add TDD for read symbols
This commit is contained in:
parent
fa8e4bc8e1
commit
f279d7c90a
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
tmp
|
||||||
|
.air.toml
|
||||||
7
go.mod
7
go.mod
@ -1,3 +1,10 @@
|
|||||||
module mal-go
|
module mal-go
|
||||||
|
|
||||||
go 1.24.2
|
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
|
||||||
|
)
|
||||||
|
|||||||
9
go.sum
Normal file
9
go.sum
Normal file
@ -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=
|
||||||
2
main.go
2
main.go
@ -22,7 +22,7 @@ func main() {
|
|||||||
if input == "exit" {
|
if input == "exit" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ast := read.ReadString(input)
|
ast, _ := read.ReadString(input)
|
||||||
result := eval.Eval(ast)
|
result := eval.Eval(ast)
|
||||||
print.Print(result)
|
print.Print(result)
|
||||||
}
|
}
|
||||||
|
|||||||
56
read/read.go
56
read/read.go
@ -1,5 +1,57 @@
|
|||||||
package read
|
package read
|
||||||
|
|
||||||
func ReadString(s string) any {
|
import (
|
||||||
return s
|
"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
|
||||||
}
|
}
|
||||||
|
|||||||
23
read/read_test.go
Normal file
23
read/read_test.go
Normal file
@ -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")
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user