package main import ( "fmt" "strconv" "strings" ) // Context is a set of Dictionary + Stacks + Flags representing a runtime environment type Context struct { Dictionary Dictionary Stack *Stack RStack *Stack Flags Flags Words []string } // Eval evaulates a given line, recursively descending into given words as needed func (c *Context) Eval(line string) error { // state var word []byte for i := 0; i < len(line); i = i + 1 { switch line[i] { case ' ': sword := strings.TrimSpace(string(word)) if len(word) == 0 { // empty space, just continue... continue } // Is this a word we know? w, _ := c.Dictionary.GetWord(sword) // check if it's an IMMEDIATE mode toggle word if !c.Flags.GetFlag("Immediate") { c.Flags.SetFlag("Immediate", w.Immediate) } if !c.Flags.GetFlag("Immediate") { if !c.Flags.GetFlag("Comment") { c.Words = append(c.Words, sword) } word = []byte{} continue } int, err := strconv.Atoi(sword) if err == nil { // it was a number! put it on the stack. c.Stack.Push(int) word = []byte{} continue } // it wasn't a number. Is it a word we know? w, err = c.Dictionary.GetWord(sword) if err != nil { return fmt.Errorf("could not parse %s; %v", w.Name, err) } // run word c.RStack.Push(i) if err = c.Exec(w); err != nil { return err } i, err = c.RStack.Pop() if err != nil { return fmt.Errorf("error while popping from return stack: %v", err) } word = []byte{} default: word = append(word, line[i]) } } return nil } // Exec wraps the branched execution of words (either built-in or user-defined) func (c *Context) Exec(w Word) error { if w.Impl != nil { // we have an implementation for that word. Run it. err := w.Impl() if err != nil { return err } } else if len(w.Source) != 0 { // user-defined word; let's descend... err := c.Eval(strings.Join(w.Source, " ") + " ") if err != nil { return err } } return nil }