diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa3d5f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tmp +.air.toml diff --git a/go.mod b/go.mod index f311a25..7b7fcac 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,10 @@ module mal-go go 1.24.2 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cc8b3f4 --- /dev/null +++ b/go.sum @@ -0,0 +1,9 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index b9f85b6..ebdb770 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,7 @@ func main() { if input == "exit" { return } - ast := read.ReadString(input) + ast, _ := read.ReadString(input) result := eval.Eval(ast) print.Print(result) } diff --git a/read/read.go b/read/read.go index a43acbc..be42e7f 100644 --- a/read/read.go +++ b/read/read.go @@ -1,5 +1,57 @@ package read -func ReadString(s string) any { - return s +import ( + "mal-go/list" + "mal-go/symbol" + "strings" +) + +func ReadString(s string) (any, any) { + res, err, _ := readInternal(s, 0, nil, "user") + return res, err +} + +func isSymbolChar(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-' || c == '/' || c == '\'' +} + +func readInternal(s string, pos int, ctx *list.List, ns string) (any, any, int) { + if pos >= len(s) { + return ctx, nil, pos + } + c := s[pos] + + var res, err any + + if isSymbolChar(c) { + res, err, pos2 := readSymbol(s, pos, ns) + return res, err, pos2 + } + // switch c { + // case '{': + // res, err, _ = readInternal(s, pos+1, list.Conj(ctx, hash_map.New()), ns) + // case '[': + // case '(': + // } + return res, err, 0 +} + +func readSymbol(s string, pos int, ns string) (any, any, int) { + startingPos := pos + c := s[pos] + for isSymbolChar(c) { + pos += 1 + if pos >= len(s) { + break + } + c = s[pos] + } + sym := s[startingPos:pos] + symNs := ns + if strings.Contains(sym, "/") { + splitIdx := strings.Index(s, "/") + symNs = s[startingPos:splitIdx] + sym = s[splitIdx+1 : pos] + } + return symbol.Intern(symNs, sym), nil, pos } diff --git a/read/read_test.go b/read/read_test.go new file mode 100644 index 0000000..69bfcdb --- /dev/null +++ b/read/read_test.go @@ -0,0 +1,23 @@ +package read + +import ( + "github.com/stretchr/testify/assert" + "mal-go/symbol" + "testing" +) + +func TestReadSymbol(t *testing.T) { + input := "foo" + sym, err, end_pos := readSymbol(input, 0, "user") + assert.Equal(t, sym, symbol.Intern("user", "foo"), "should read user/foo symbol") + assert.Equal(t, err, nil, "should read without error") + assert.Equal(t, end_pos, len(input), "should read the whole string") +} + +func TestReadSymbolWithNamespace(t *testing.T) { + input := "foo/bar" + sym, err, end_pos := readSymbol(input, 0, "user") + assert.Equal(t, sym, symbol.Intern("foo", "bar"), "should read user/foo symbol") + assert.Equal(t, err, nil, "should read without error") + assert.Equal(t, end_pos, len(input), "should read the whole string") +}