package main 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 { r1, err := s.Pop() if err != nil { return err } r2, err := s.Pop() if err != nil { return err } s.Push(r1 + r2) return nil } } // Sub performs NOS - TOS and pushes the result func (b *Builtins) Sub(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } r2, err := s.Pop() if err != nil { return err } s.Push(r2 - r1) return nil } } // Mul multiplies the two numbers on the top of the stack and pushes the result func (b *Builtins) Mul(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } r2, err := s.Pop() if err != nil { return err } s.Push(r2 * r1) return nil } } // Div performs NOS/TOS and pushes the (integer!) result func (b *Builtins) Div(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } r2, err := s.Pop() if err != nil { return err } s.Push(r2 / r1) return nil } } // Print pops the stack and outputs it to stdout func (b *Builtins) Print(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } fmt.Print(r1, " ") return nil } } // Dup pops the stack, then pushes two copies onto the stack func (b *Builtins) Dup(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } s.Push(r1) s.Push(r1) return nil } } // Swap inverts the order of TOS and NOS func (b *Builtins) Swap(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } r2, err := s.Pop() if err != nil { return err } s.Push(r1) s.Push(r2) return nil } } // Over duplicates NOS to TOS, resulting in NOS TOS NOS func (b *Builtins) Over(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } r2, err := s.Pop() if err != nil { return err } s.Push(r2) s.Push(r1) s.Push(r2) return nil } } // Drop simply discards TOS func (b *Builtins) Drop(s *Stack) func() error { return func() error { _, err := s.Pop() return err } } // Rot cycles the first three items on the stack: TOS 1 2 3 -> TOS 3 1 2 func (b *Builtins) Rot(s *Stack) func() error { return func() error { r1, err := s.Pop() if err != nil { return err } r2, err := s.Pop() if err != nil { return err } r3, err := s.Pop() if err != nil { return err } s.Push(r2) s.Push(r1) s.Push(r3) return err } } // Words outputs a list of all known words in the dictionary func (b *Builtins) Words(d Dictionary) func() error { return func() error { for n := range d { fmt.Printf("%s ", n) } return nil } } // 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 { fmt.Print("\n") return nil } } // 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 { fmt.Print(s.values, " ") return nil } }