diff --git a/builtins.go b/builtins.go index f6d7759..050a12b 100644 --- a/builtins.go +++ b/builtins.go @@ -5,6 +5,9 @@ import "fmt" // Builtins is a handy holder for our various default words type Builtins struct{} +// ErrExit is a special sentinel value to cease computation and quit +var ErrExit = fmt.Errorf("exit requested") + // Add sums the top two numbers on the stack and pushes the result func (b *Builtins) Add(s *Stack) func() error { return func() error { @@ -169,6 +172,18 @@ func (b *Builtins) Words(d Dictionary) func() error { } } +// Emit outputs the UTF-8 rune for the int on the top of the stack +func (b *Builtins) Emit(s *Stack) func() error { + return func() error { + i, err := s.Pop() + if err != nil { + return err + } + fmt.Print(string(rune(i)) + " ") + return nil + } +} + // CR prints a newline to standard out func (b *Builtins) CR() func() error { return func() error { @@ -177,6 +192,13 @@ func (b *Builtins) CR() func() error { } } +// Quit exits the repl +func (b *Builtins) Quit() func() error { + return func() error { + return ErrExit + } +} + // Debug prints the stack without modifying it func (b *Builtins) Debug(s *Stack) func() error { return func() error { diff --git a/main.go b/main.go index bfa8270..ee97b85 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "errors" "fmt" "os" "strings" @@ -24,7 +25,9 @@ func main() { dict.AddWord("ROT", b.Rot(&stack), "") dict.AddWord("WORDS", b.Words(dict), "") dict.AddWord(".S", b.Debug(&stack), "") + dict.AddWord("EMIT", b.Emit(&stack), "") dict.AddWord("CR", b.CR(), "") + dict.AddWord("QUIT", b.Quit(), "") c := Context{ Dictionary: dict, @@ -45,7 +48,10 @@ func main() { } line = strings.TrimSpace(line) err = c.Eval(line + " ") // append a space to make sure we always close out our parse loop - if err != nil { + if errors.Is(err, ErrExit) { + fmt.Printf("bye\n") + os.Exit(0) + } else if err != nil { fmt.Printf("error in evaluation: %v\n", err) } fmt.Print("ok")