diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-04 20:06:42 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-10-04 20:06:42 -0500 |
| commit | 45e1db6afbb0c63b1cd5d17e0996d7929803f37b (patch) | |
| tree | 57aad492414d013e4d2b5b6eb81bc563244df02f | |
| parent | 1ac751b20c8c6efe924737b0f88b9de6805bd5b4 (diff) | |
| download | mal-45e1db6afbb0c63b1cd5d17e0996d7929803f37b.tar.gz mal-45e1db6afbb0c63b1cd5d17e0996d7929803f37b.zip | |
go: reading of atoms and lists.
| -rw-r--r-- | go/Makefile | 13 | ||||
| -rw-r--r-- | go/src/reader/reader.go | 110 | ||||
| -rw-r--r-- | go/src/step0_repl/step0_repl.go (renamed from go/step0_repl.go) | 1 | ||||
| -rw-r--r-- | go/src/step1_read_print/step1_read_print.go | 60 | ||||
| -rw-r--r-- | go/src/types/types.go | 17 |
5 files changed, 194 insertions, 7 deletions
diff --git a/go/Makefile b/go/Makefile index 85719bf..076a7aa 100644 --- a/go/Makefile +++ b/go/Makefile @@ -1,13 +1,14 @@ +export GOPATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) + ##################### -SOURCES_BASE = -SOURCES_LISP = step0_repl.go +SOURCES_BASE = src/types/types.go src/reader/reader.go +SOURCES_LISP = src/step1_read_print/step1_read_print.go SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) - ##################### -SRCS = step0_repl.go +SRCS = step0_repl.go step1_read_print.go BINS = $(SRCS:%.go=%) ##################### @@ -17,8 +18,8 @@ all: $(BINS) mal mal: $(word $(words $(BINS)),$(BINS)) cp $< $@ -$(BINS): %: %.go - go build -o $@ $+ +$(BINS): $(SOURCES_BASE) $(SOURCES_LISP) + go build $@ clean: rm -f $(BINS) mal diff --git a/go/src/reader/reader.go b/go/src/reader/reader.go new file mode 100644 index 0000000..3222d6f --- /dev/null +++ b/go/src/reader/reader.go @@ -0,0 +1,110 @@ +package reader + +import ( + "errors" + "regexp" + "strconv" + //"fmt" +) + +import ( + "types" +) + +type Reader interface { + next() *string + peek() *string +} + +type TokenReader struct { + tokens []string + position int +} + +func (tr *TokenReader) next() *string { + if tr.position >= len(tr.tokens) { return nil } + token := tr.tokens[tr.position] + tr.position = tr.position + 1 + return &token +} + +func (tr *TokenReader) peek() *string { + if tr.position > len(tr.tokens) { return nil } + return &tr.tokens[tr.position] +} + + + +func tokenize (str string) []string { + results := make([]string, 0, 1) + re := regexp.MustCompile(`[\s,]*(~@|[\[\]{}()'~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('",;)]*)`) + for _, group := range re.FindAllStringSubmatch(str, -1) { + if group[1] == "" { continue } + results = append(results, group[1]) + } + return results +} + +func read_atom(rdr Reader) (types.MalType, error) { + token := rdr.next() + if token == nil { return nil, errors.New("read_atom underflow") } + if match, _ := regexp.MatchString(`^-?[0-9]+$`, *token); match { + var i int + var e error + if i, e = strconv.Atoi(*token); e != nil { + return nil, errors.New("number parse error") + } + return i, nil + } else if (*token)[0] == '"' { + // TODO: unquote newline and quotes + return (*token)[1:len(*token)-1], nil + } else if *token == "nil" { + return nil, nil + } else if *token == "true" { + return true, nil + } else if *token == "false" { + return false, nil + } else { + return types.Symbol{*token}, nil + } + return token, nil +} + +func read_list(rdr Reader) (types.MalType, error) { + token := rdr.next() + if token == nil { return nil, errors.New("read_list underflow") } + + ast_list := []types.MalType{} + if *token != "(" { + return nil, errors.New("expected '('") + } + token = rdr.peek() + for ; token != nil && *token != ")" ; token = rdr.peek() { + if token == nil { return nil, errors.New("exepected ')', got EOF") } + f, e := read_form(rdr) + if e != nil { return nil, e } + ast_list = append(ast_list, f) + } + rdr.next() + return types.List{ast_list}, nil +} + +func read_form(rdr Reader) (types.MalType, error) { + token := rdr.peek() + if token == nil { return nil, errors.New("read_form underflow") } + switch (*token) { + case ")": return nil, errors.New("unexpected ')'") + case "(": return read_list(rdr) + default: return read_atom(rdr) + } + return read_atom(rdr) +} + +func Read_str(str string) (types.MalType, error) { + var tokens = tokenize(str); + if len(tokens) == 0 { + return nil, errors.New("<empty line>") + } + + return read_form(&TokenReader{tokens: tokens, position: 0}) +} diff --git a/go/step0_repl.go b/go/src/step0_repl/step0_repl.go index 601ef64..1203213 100644 --- a/go/step0_repl.go +++ b/go/src/step0_repl/step0_repl.go @@ -2,7 +2,6 @@ package main import ( "bufio" - //"io" "fmt" "os" "strings" diff --git a/go/src/step1_read_print/step1_read_print.go b/go/src/step1_read_print/step1_read_print.go new file mode 100644 index 0000000..60a06cb --- /dev/null +++ b/go/src/step1_read_print/step1_read_print.go @@ -0,0 +1,60 @@ +package main + +import ( + "bufio" + //"io" + "fmt" + "os" + "strings" +) + +import ( + "types" + "reader" +) + +// read +func READ(str string) (types.MalType, error) { + return reader.Read_str(str) +} + +// eval +func EVAL(ast types.MalType, env string) (types.MalType, error) { + return ast, nil +} + +// print +func PRINT(exp types.MalType) (types.MalType, error) { + return exp, nil +} + +// repl +func rep(str string) (types.MalType, error) { + var exp types.MalType + var e error + if exp, e = READ(str); e != nil { return nil, e } + if exp, e = EVAL(exp, ""); e != nil { return nil, e } + if exp, e = PRINT(exp); e != nil { return nil, e } + return exp, nil +} + +func main() { + rdr := bufio.NewReader(os.Stdin); + // repl loop + for { + fmt.Print("user> "); + text, err := rdr.ReadString('\n'); + text = strings.TrimRight(text, "\n"); + if (err != nil) { + return + } + var out types.MalType + var e error + if out, e = rep(text); e != nil { + if e.Error() == "<empty line>" { continue } + fmt.Printf("Error: %v\n", e) + continue + } + fmt.Printf("%#v\n", out) + } +} diff --git a/go/src/types/types.go b/go/src/types/types.go new file mode 100644 index 0000000..3f1c652 --- /dev/null +++ b/go/src/types/types.go @@ -0,0 +1,17 @@ +package types + +//type Error interface { +// error +//} + +type MalType interface { +} + +type Symbol struct { + Val string +} + +type List struct { + Val []MalType +} + |
