abstract flags, implement comments as words, fix some bugs
This commit is contained in:
parent
7c76bc49af
commit
1a229d5ddb
43
builtins.go
43
builtins.go
@ -9,9 +9,9 @@ type Builtins struct{}
|
|||||||
var ErrExit = fmt.Errorf("exit requested")
|
var ErrExit = fmt.Errorf("exit requested")
|
||||||
|
|
||||||
// Colon sets the COMPILE/IMMEDIATE flag to COMPILE
|
// Colon sets the COMPILE/IMMEDIATE flag to COMPILE
|
||||||
func (b *Builtins) Colon(f *bool) func() error {
|
func (b *Builtins) Colon(c *Context) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
*f = false
|
c.Flags.SetFlag("Immediate", false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -20,7 +20,26 @@ func (b *Builtins) Colon(f *bool) func() error {
|
|||||||
func (b *Builtins) Semicolon(c *Context) func() error {
|
func (b *Builtins) Semicolon(c *Context) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
c.Dictionary.AddWord(c.Words[0], nil, c.Words[1:], false)
|
c.Dictionary.AddWord(c.Words[0], nil, c.Words[1:], false)
|
||||||
c.Immediate = true
|
c.Words = []string{}
|
||||||
|
c.Flags.SetFlag("Immediate", true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenComment puts the parser into an "ignore" mode
|
||||||
|
func (b *Builtins) OpenComment(c *Context) func() error {
|
||||||
|
return func() error {
|
||||||
|
c.Flags.SetFlag("Comment", true)
|
||||||
|
c.Flags.SetFlag("Immediate", false)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseComment resumes parsing
|
||||||
|
func (b *Builtins) CloseComment(c *Context) func() error {
|
||||||
|
return func() error {
|
||||||
|
c.Flags.SetFlag("Comment", false)
|
||||||
|
c.Flags.SetFlag("Immediate", false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,6 +322,16 @@ func (b *Builtins) Words(d Dictionary) func() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flags outputs a list of all flags
|
||||||
|
func (b *Builtins) Flags(c Context) func() error {
|
||||||
|
return func() error {
|
||||||
|
for n := range c.Flags {
|
||||||
|
fmt.Printf("%s %v\n", n, c.Flags.GetFlag(n))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Emit outputs the UTF-8 rune for the int on the top of the stack
|
// Emit outputs the UTF-8 rune for the int on the top of the stack
|
||||||
func (b *Builtins) Emit(s *Stack) func() error {
|
func (b *Builtins) Emit(s *Stack) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
@ -443,14 +472,6 @@ func (b *Builtins) I(s *Stack, r *Stack) func() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Quit exits the repl
|
||||||
func (b *Builtins) Quit() func() error {
|
func (b *Builtins) Quit() func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
|
41
eval.go
41
eval.go
@ -6,12 +6,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context is a set of Dictionary + Stacks representing a runtime environment
|
// Context is a set of Dictionary + Stacks + Flags representing a runtime environment
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Dictionary Dictionary
|
Dictionary Dictionary
|
||||||
Stack *Stack
|
Stack *Stack
|
||||||
RStack *Stack
|
RStack *Stack
|
||||||
Immediate bool
|
Flags Flags
|
||||||
Words []string
|
Words []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,38 +19,29 @@ type Context struct {
|
|||||||
func (c *Context) Eval(line string) error {
|
func (c *Context) Eval(line string) error {
|
||||||
// state
|
// state
|
||||||
var word []byte
|
var word []byte
|
||||||
var comment bool
|
|
||||||
|
|
||||||
for i := 0; i < len(line); i = i + 1 {
|
for i := 0; i < len(line); i = i + 1 {
|
||||||
switch line[i] {
|
switch line[i] {
|
||||||
case '(', ')': // comments
|
|
||||||
if len(word) == 0 {
|
|
||||||
if line[i] == '(' {
|
|
||||||
comment = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
comment = false
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
word = append(word, line[i])
|
|
||||||
}
|
|
||||||
case ' ':
|
case ' ':
|
||||||
sword := strings.TrimSpace(string(word))
|
sword := strings.TrimSpace(string(word))
|
||||||
if !c.Immediate { // continue building our subroutine if we're not in immediate mode...
|
if len(word) == 0 {
|
||||||
if len(word) != 0 { // don't add empty words to our list
|
// empty space, just continue...
|
||||||
// Was that a word we know?
|
continue
|
||||||
|
}
|
||||||
|
// Is this a word we know?
|
||||||
w, _ := c.Dictionary.GetWord(sword)
|
w, _ := c.Dictionary.GetWord(sword)
|
||||||
// check if it's an IMMEDIATE mode toggle word
|
// check if it's an IMMEDIATE mode toggle word
|
||||||
c.Immediate = w.Immediate
|
if !c.Flags.GetFlag("Immediate") {
|
||||||
if !c.Immediate {
|
c.Flags.SetFlag("Immediate", w.Immediate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Flags.GetFlag("Immediate") && !c.Flags.GetFlag("Comment") {
|
||||||
c.Words = append(c.Words, sword)
|
c.Words = append(c.Words, sword)
|
||||||
word = []byte{}
|
word = []byte{}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
if !c.Flags.GetFlag("Immediate") && c.Flags.GetFlag("Comment") {
|
||||||
}
|
word = []byte{}
|
||||||
if len(word) == 0 || comment {
|
|
||||||
// empty space, just continue...
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +54,7 @@ func (c *Context) Eval(line string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// it wasn't a number. Is it a word we know?
|
// it wasn't a number. Is it a word we know?
|
||||||
w, err := c.Dictionary.GetWord(sword)
|
w, err = c.Dictionary.GetWord(sword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not parse %s; %v", w.Name, err)
|
return fmt.Errorf("could not parse %s; %v", w.Name, err)
|
||||||
}
|
}
|
||||||
@ -78,11 +69,9 @@ func (c *Context) Eval(line string) error {
|
|||||||
}
|
}
|
||||||
word = []byte{}
|
word = []byte{}
|
||||||
default:
|
default:
|
||||||
if !comment {
|
|
||||||
word = append(word, line[i])
|
word = append(word, line[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
12
flags.go
Normal file
12
flags.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// Flags is a simple map of strings to boolean flag fields
|
||||||
|
type Flags map[string]bool
|
||||||
|
|
||||||
|
func (f Flags) GetFlag(s string) bool {
|
||||||
|
return f[s]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Flags) SetFlag(s string, b bool) {
|
||||||
|
f[s] = b
|
||||||
|
}
|
27
main.go
27
main.go
@ -18,14 +18,20 @@ func main() {
|
|||||||
Dictionary: dict,
|
Dictionary: dict,
|
||||||
Stack: &stack,
|
Stack: &stack,
|
||||||
RStack: &rstack,
|
RStack: &rstack,
|
||||||
Immediate: true,
|
Flags: Flags{
|
||||||
|
"Immediate": true,
|
||||||
|
"Comment": false,
|
||||||
|
},
|
||||||
Words: []string{},
|
Words: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
b := &Builtins{}
|
b := &Builtins{}
|
||||||
// word definitions
|
// word definitions
|
||||||
dict.AddWord(":", b.Colon(&c.Immediate), nil, false)
|
dict.AddWord(":", b.Colon(&c), nil, false)
|
||||||
dict.AddWord(";", b.Semicolon(&c), nil, true)
|
dict.AddWord(";", b.Semicolon(&c), nil, true)
|
||||||
|
// comments
|
||||||
|
dict.AddWord("(", b.OpenComment(&c), nil, true)
|
||||||
|
dict.AddWord(")", b.CloseComment(&c), nil, true)
|
||||||
// math
|
// math
|
||||||
dict.AddWord("+", b.Add(&stack), nil, false)
|
dict.AddWord("+", b.Add(&stack), nil, false)
|
||||||
dict.AddWord("-", b.Sub(&stack), nil, false)
|
dict.AddWord("-", b.Sub(&stack), nil, false)
|
||||||
@ -34,7 +40,7 @@ func main() {
|
|||||||
// output
|
// output
|
||||||
dict.AddWord(".", b.Print(&stack), nil, false)
|
dict.AddWord(".", b.Print(&stack), nil, false)
|
||||||
dict.AddWord("EMIT", b.Emit(&stack), nil, false)
|
dict.AddWord("EMIT", b.Emit(&stack), nil, false)
|
||||||
dict.AddWord("CR", b.CR(), nil, false)
|
dict.AddWord("CR", nil, []string{"10", "EMIT"}, false) // emit a newline
|
||||||
// logic
|
// logic
|
||||||
dict.AddWord("=", b.Eq(&stack), nil, false)
|
dict.AddWord("=", b.Eq(&stack), nil, false)
|
||||||
dict.AddWord("0=", nil, []string{"0", "="}, false)
|
dict.AddWord("0=", nil, []string{"0", "="}, false)
|
||||||
@ -53,6 +59,7 @@ func main() {
|
|||||||
dict.AddWord("ROT", b.Rot(&stack), nil, false)
|
dict.AddWord("ROT", b.Rot(&stack), nil, false)
|
||||||
// debugging
|
// debugging
|
||||||
dict.AddWord("WORDS", b.Words(dict), nil, false)
|
dict.AddWord("WORDS", b.Words(dict), nil, false)
|
||||||
|
dict.AddWord("FLAGS", b.Flags(c), nil, false)
|
||||||
dict.AddWord(".S", b.Debug(&stack), nil, false)
|
dict.AddWord(".S", b.Debug(&stack), nil, false)
|
||||||
dict.AddWord(".R", b.Debug(&rstack), nil, false)
|
dict.AddWord(".R", b.Debug(&rstack), nil, false)
|
||||||
dict.AddWord("R>", b.RFrom(&stack, &rstack), nil, false)
|
dict.AddWord("R>", b.RFrom(&stack, &rstack), nil, false)
|
||||||
@ -66,11 +73,15 @@ func main() {
|
|||||||
dict.AddWord("BYE", b.Quit(), nil, false)
|
dict.AddWord("BYE", b.Quit(), nil, false)
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
fmt.Print("prosper")
|
fmt.Print("prosper\n")
|
||||||
|
|
||||||
// read loop
|
// read loop
|
||||||
for {
|
for {
|
||||||
fmt.Print("\n> ")
|
if c.Flags["Immediate"] {
|
||||||
|
fmt.Print("> ")
|
||||||
|
} else {
|
||||||
|
fmt.Print(" ")
|
||||||
|
}
|
||||||
|
|
||||||
line, err := reader.ReadString('\n')
|
line, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -83,9 +94,9 @@ func main() {
|
|||||||
fmt.Printf("bye\n")
|
fmt.Printf("bye\n")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
fmt.Printf("error in evaluation: %v", err)
|
fmt.Printf("error in evaluation: %v\n", err)
|
||||||
} else {
|
} else if c.Flags["Immediate"] {
|
||||||
fmt.Print("ok")
|
fmt.Print("ok\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user