package main import ( "bufio" "errors" "fmt" "os" "strings" ) func main() { stack := Stack{values: []int{}} rstack := Stack{values: []int{}} ifstack := Stack{values: []int{}} dict := Dictionary{} c := Context{ Dictionary: dict, Stack: &stack, RStack: &rstack, IfStack: &ifstack, Flags: Flags{ "Immediate": true, }, Words: []string{}, } b := &Builtins{} // word definitions dict.AddWord(":", Word{Name: ":", Impl: b.Colon(&c)}) dict.AddWord(";", Word{Name: ";", Impl: b.Semicolon(&c), Immediate: true}) // comments dict.AddWord("(", Word{Name: "(", Impl: b.OpenComment(&c), Immediate: true}) dict.AddWord(")", Word{Name: ")", Impl: b.CloseComment(&c), Immediate: true}) // math dict.AddWord("+", Word{Name: "+", Impl: b.Add(&stack)}) dict.AddWord("-", Word{Name: "-", Impl: b.Sub(&stack)}) dict.AddWord("*", Word{Name: "*", Impl: b.Mul(&stack)}) dict.AddWord("/", Word{Name: "/", Impl: b.Div(&stack)}) dict.AddWord("MOD", Word{Name: "MOD", Impl: b.Mod(&stack)}) dict.AddWord("/MOD", Word{Name: "/MOD", Source: []string{"2DUP", "MOD", "ROT", "ROT", "/"}}) dict.AddWord("1+", Word{Name: "1+", Source: []string{"1", "+"}}) dict.AddWord("1-", Word{Name: "1-", Source: []string{"1", "-"}}) dict.AddWord("ABS", Word{Name: "ABS", Source: []string{"DUP", "0<", "IF", "NEGATE", "THEN"}}) dict.AddWord("NEGATE", Word{Name: "NEGATE", Source: []string{"-1", "*"}}) dict.AddWord("MAX", Word{Name: "MAX", Source: []string{"2DUP", "<", "IF", "SWAP", "THEN", "DROP"}}) dict.AddWord("MIN", Word{Name: "MIN", Source: []string{"2DUP", ">", "IF", "SWAP", "THEN", "DROP"}}) // output dict.AddWord(".", Word{Name: ".", Impl: b.Print(os.Stdout, &stack)}) dict.AddWord("EMIT", Word{Name: "EMIT", Impl: b.Emit(os.Stdout, &stack)}) dict.AddWord("CR", Word{Name: "CR", Source: []string{"10", "EMIT"}}) // emit a newline // logic dict.AddWord("=", Word{Name: "=", Impl: b.Eq(&stack)}) dict.AddWord("0=", Word{Name: "0=", Source: []string{"0", "="}}) dict.AddWord("<>", Word{Name: "<>", Impl: b.NEq(&stack)}) dict.AddWord("0<>", Word{Name: "0<>", Source: []string{"0=", "0="}}) dict.AddWord(">", Word{Name: ">", Impl: b.Gt(&stack)}) dict.AddWord("<", Word{Name: "<", Impl: b.Lt(&stack)}) dict.AddWord(">=", Word{Name: ">=", Impl: b.GtEq(&stack)}) dict.AddWord("<=", Word{Name: "<=", Impl: b.LtEq(&stack)}) dict.AddWord("0<", Word{Name: "0<", Source: []string{"0", "<"}}) dict.AddWord("0>", Word{Name: "0>", Source: []string{"0", ">"}}) // stack manipulation dict.AddWord("DUP", Word{Name: "DUP", Impl: b.Dup(&stack)}) dict.AddWord("?DUP", Word{Name: "?DUP", Source: []string{"DUP", "0<>", "IF", "DUP", "THEN"}}) dict.AddWord("SWAP", Word{Name: "SWAP", Impl: b.Swap(&stack)}) dict.AddWord("OVER", Word{Name: "OVER", Impl: b.Over(&stack)}) dict.AddWord("DROP", Word{Name: "DROP", Impl: b.Drop(&stack)}) dict.AddWord("ROT", Word{Name: "ROT", Impl: b.Rot(&stack)}) dict.AddWord("PICK", Word{Name: "PICK", Impl: b.Pick(&stack)}) dict.AddWord("NIP", Word{Name: "NIP", Source: []string{"SWAP", "DROP"}}) dict.AddWord("TUCK", Word{Name: "TUCK", Source: []string{"SWAP", "OVER"}}) // paired stack manipulation dict.AddWord("2DROP", Word{Name: "2DROP", Source: []string{"DROP", "DROP"}}) dict.AddWord("2DUP", Word{Name: "2DUP", Source: []string{"OVER", "OVER"}}) dict.AddWord("2OVER", Word{Name: "2OVER", Source: []string{"3", "PICK", "3", "PICK"}}) // debugging dict.AddWord("WORDS", Word{Name: "WORDS", Impl: b.Words(os.Stdout, dict)}) dict.AddWord("SEE", Word{Name: "SEE", Impl: b.See(os.Stdout, &rstack, dict)}) dict.AddWord("FLAGS", Word{Name: "FLAGS", Impl: b.Flags(os.Stdout, c)}) dict.AddWord(".S", Word{Name: ".S", Impl: b.Debug(os.Stdout, &stack)}) dict.AddWord(".R", Word{Name: ".R", Impl: b.Debug(os.Stdout, &rstack)}) dict.AddWord(".I", Word{Name: ".I", Impl: b.Debug(os.Stdout, &ifstack)}) dict.AddWord("DEPTH", Word{Name: "DEPTH", Impl: b.Depth(&stack)}) dict.AddWord("R>", Word{Name: "R>", Impl: b.RFrom(&stack, &rstack)}) dict.AddWord(">R", Word{Name: ">R", Impl: b.ToR(&stack, &rstack)}) dict.AddWord("R@", Word{Name: "R@", Impl: b.RFetch(&stack, &rstack)}) // branching dict.AddWord("IF", Word{Name: "IF", Impl: b.If(&stack, &ifstack), BranchCheck: true}) dict.AddWord("ELSE", Word{Name: "ELSE", Impl: b.Else(&ifstack), BranchCheck: true}) dict.AddWord("THEN", Word{Name: "THEN", Impl: b.Then(&ifstack), BranchCheck: true}) dict.AddWord("DO", Word{Name: "DO", Impl: b.Do(&stack, &rstack)}) dict.AddWord("LOOP", Word{Name: "LOOP", Impl: b.Loop(&stack, &rstack)}) dict.AddWord("I", Word{Name: "I", Impl: b.I(&stack, &rstack)}) // exit dict.AddWord("BYE", Word{Name: "BYE", Impl: b.Quit()}) reader := bufio.NewReader(os.Stdin) fmt.Print("prosper\n") // read loop for { if c.Flags["Immediate"] { fmt.Print("> ") } else { fmt.Print(" ") } line, err := reader.ReadString('\n') if err != nil { fmt.Println(err.Error()) os.Exit(1) } line = strings.TrimSpace(line) err = c.Eval(line + " ") // append a space to make sure we always close out our parse loop if errors.Is(err, ErrExit) { fmt.Printf("bye\n") os.Exit(0) } else if err != nil { fmt.Printf("error in evaluation: %v\n", err) } else if c.Flags["Immediate"] { fmt.Print("ok\n") } } }