aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-10-04 20:06:42 -0500
committerJoel Martin <github@martintribe.org>2014-10-04 20:06:42 -0500
commit45e1db6afbb0c63b1cd5d17e0996d7929803f37b (patch)
tree57aad492414d013e4d2b5b6eb81bc563244df02f
parent1ac751b20c8c6efe924737b0f88b9de6805bd5b4 (diff)
downloadmal-45e1db6afbb0c63b1cd5d17e0996d7929803f37b.tar.gz
mal-45e1db6afbb0c63b1cd5d17e0996d7929803f37b.zip
go: reading of atoms and lists.
-rw-r--r--go/Makefile13
-rw-r--r--go/src/reader/reader.go110
-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.go60
-rw-r--r--go/src/types/types.go17
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
+}
+