o debugger

- commands
    - removed RECORD command. the functionality is now part of the
    SCRIPT command

o commandline
    - bugfixes
This commit is contained in:
steve 2019-04-21 22:26:49 +01:00
parent 47b59fedad
commit 102f9813d7
7 changed files with 97 additions and 54 deletions

View file

@ -151,6 +151,7 @@ func TestParser(t *testing.T) {
template = []string{
"DISPLAY (OFF|DEBUG|SCALE [%V]|DEBUGCOLORS)",
"SCRIPT [%F|RECORD [%F]|END]",
"DROP [BREAK|TRAP|WATCH] [%S]",
"GREP %V",
"TEST [FOO [%S]|BAR] (EGG [%S]|FOG|NOG NUG) (TUG)",
@ -159,6 +160,6 @@ func TestParser(t *testing.T) {
cmds, err = commandline.ParseCommandTemplate(template)
if expectSuccess(t, err) {
expectEquality(t, template, cmds)
//memvizOutput(t, "1", cmds)
// memvizOutput(t, "1", cmds)
}
}

View file

@ -59,8 +59,6 @@ func (tc *TabCompletion) Complete(input string) string {
}
// new tabcompletion session
// reinitialise matches array
tc.Reset()
// no need to to anything if input ends with a space
@ -134,11 +132,18 @@ func (tc *TabCompletion) buildMatches(n *node, tokens *Tokens) {
match = err == nil
case "%S":
// accept anything
// against expectations, string placeholders do not cause a match. if
// they did then they would be acting in the same way as the %*
// placeholder and any subsequent branches will not be considered at
// all.
match = false
case "%F":
// TODO: filename completion
// see commentary for %S above
match = false
case "%*":
// this placeholder indicates that the rest of the tokens can be
// ignored.

View file

@ -190,3 +190,26 @@ func TestTabCompletion_complex(t *testing.T) {
t.Errorf("expecting '%s' got '%s'", expected, completion)
}
}
func TestTabCompletion_filenameFirstOption(t *testing.T) {
var cmds *commandline.Commands
var tc *commandline.TabCompletion
var completion, expected string
var err error
cmds, err = commandline.ParseCommandTemplate([]string{
"TEST [%F|foo|bar]",
})
if err != nil {
t.Fatalf("%s", err)
}
tc = commandline.NewTabCompletion(cmds)
completion = "TEST f"
expected = "TEST FOO "
completion = tc.Complete(completion)
if completion != expected {
t.Errorf("expecting '%s' got '%s'", expected, completion)
}
}

View file

@ -59,7 +59,7 @@ func placeHolderText(text string) string {
// branches creates a readable string, listing all the branches of the node
func branches(n *node) string {
s := strings.Builder{}
s.WriteString(n.tag)
s.WriteString(placeHolderText(n.tag))
for bi := range n.branch {
s.WriteString(" or ")
s.WriteString(placeHolderText(n.branch[bi].tag))
@ -112,11 +112,18 @@ func (n *node) validate(tokens *Tokens) error {
}
case "%S":
// accept anything
// string placeholders do not cause a match if the node has branches.
// if they did then they would be acting in the same way as the %*
// placeholder and any subsequent branches will not be considered at
// all.
match = n.branch == nil
case "%F":
// accept anything (note: filename is distinct from %S when we use it
// for tab-completion)
// TODO: check for file existance
// see commentary for %S above
match = n.branch == nil
case "%*":
// this placeholder indicates that the rest of the tokens can be

View file

@ -228,3 +228,18 @@ func TestValidation_doubleArgs(t *testing.T) {
t.Errorf("doesn't match but should: %s", err)
}
}
func TestValidation_filenameFirstArg(t *testing.T) {
var cmds *commandline.Commands
var err error
cmds, err = commandline.ParseCommandTemplate([]string{"TEST [%F|foo [wibble]|bar]"})
if err != nil {
t.Fatalf("%s", err)
}
err = cmds.Validate("TEST foo wibble")
if err != nil {
t.Errorf("doesn't match but should: %s", err)
}
}

View file

@ -46,7 +46,6 @@ const (
cmdPoke = "POKE"
cmdQuit = "QUIT"
cmdRAM = "RAM"
cmdRecord = "RECORD"
cmdRIOT = "RIOT"
cmdReset = "RESET"
cmdRun = "RUN"
@ -90,11 +89,10 @@ var expCommandTemplate = []string{
cmdPoke + " %V %*",
cmdQuit,
cmdRAM,
cmdRecord + " [END|%F]",
cmdRIOT,
cmdReset,
cmdRun,
cmdScript + " %F",
cmdScript + " [RECORD [%S]|END|%F]",
cmdStep + " (CPU|VIDEO|SCANLINE)", // see notes
cmdStepMode + " (CPU|VIDEO)",
cmdStick + "[0|1] [LEFT|RIGHT|UP|DOWN|FIRE|CENTRE|NOFIRE]",
@ -162,13 +160,14 @@ func (dbg *Debugger) parseCommand(userInput *string) (parseCommandResult, error)
// much about the success of tokens.Get() in the command implementations
// below:
//
// tok, _ := tokens.Get()
// arg, _ := tokens.Get()
//
// is an acceptable pattern. default values can be handled thus:
// is an acceptable pattern when an argument is required. default values
// can be handled thus:
//
// tok, ok := tokens.Get()
// arg, ok := tokens.Get()
// if ok {
// switch tok {
// switch arg {
// ...
// }
// } else {
@ -222,17 +221,31 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens) (parseCommandResul
dbg.print(console.Feedback, "machine reset with new cartridge (%s)", cart)
case cmdScript:
script, _ := tokens.Get()
spt, err := dbg.loadScript(script)
if err != nil {
dbg.print(console.Error, "error running debugger initialisation script: %s\n", err)
return doNothing, err
}
err = dbg.inputLoop(spt, false)
if err != nil {
return doNothing, err
option, _ := tokens.Get()
switch strings.ToUpper(option) {
case "RECORD":
var err error
script, _ := tokens.Get()
dbg.scriptRec, err = dbg.startScriptRecording(script)
return scriptRecordStarted, err
case "END":
if dbg.scriptRec == nil {
return doNothing, fmt.Errorf("no script recording currently taking place")
}
err := dbg.scriptRec.end()
dbg.scriptRec = nil
dbg.print(console.Feedback, "script recording completed\n")
return scriptRecordEnded, err
default:
// run a script
spt, err := dbg.loadScript(option)
if err != nil {
return doNothing, err
}
err = dbg.inputLoop(spt, false)
if err != nil {
return doNothing, err
}
}
case cmdDisassembly:
@ -542,9 +555,9 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens) (parseCommandResul
}
case cmdCartridge:
tok, ok := tokens.Get()
arg, ok := tokens.Get()
if ok {
switch tok {
switch arg {
case "ANALYSIS":
dbg.print(console.Feedback, dbg.disasm.String())
}
@ -707,8 +720,8 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens) (parseCommandResul
case cmdPlayer:
plyr := -1
tok, _ := tokens.Get()
switch tok {
arg, _ := tokens.Get()
switch arg {
case "0":
plyr = 0
case "1":
@ -766,8 +779,8 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens) (parseCommandResul
case cmdMissile:
mssl := -1
tok, _ := tokens.Get()
switch tok {
arg, _ := tokens.Get()
switch arg {
case "0":
mssl = 0
case "1":
@ -913,26 +926,6 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens) (parseCommandResul
if err != nil {
return doNothing, err
}
case cmdRecord:
// record can refer to recording of a script or recording of user
// input. in this context, it currently only refers to script recording
tok, _ := tokens.Get()
if strings.ToUpper(tok) == "END" {
if dbg.scriptRec == nil {
return doNothing, fmt.Errorf("no script recording currently taking place")
}
err := dbg.scriptRec.end()
dbg.scriptRec = nil
return scriptRecordEnded, err
}
var err error
dbg.scriptRec, err = dbg.startScriptRecording(tok)
return scriptRecordStarted, err
}
return doNothing, nil

View file

@ -27,11 +27,10 @@ var Help = map[string]string{
cmdPoke: "Modify an individual memory address",
cmdQuit: "Exits the emulator",
cmdRAM: "Display the current contents of PIA RAM",
cmdRecord: "Start recording entered commands to an external script",
cmdRIOT: "Display the current state of the RIOT",
cmdReset: "Reset the emulation to its initial state",
cmdRun: "Run emulator until next halt state",
cmdScript: "Run commands from specified file",
cmdScript: "Run commands from specified file or record commands to a file",
cmdStep: "Step forward emulator one step (see STEPMODE command)",
cmdStepMode: "Change method of stepping: CPU or VIDEO",
cmdStick: "Emulate a joystick input for Player 0 or Player 1",