init reader for lists
This commit is contained in:
parent
f279d7c90a
commit
5200dfde00
10
list/list.go
10
list/list.go
@ -29,6 +29,9 @@ func (this *List) Conj(val any) *List {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Conj(this *List, val any) *List {
|
func Conj(this *List, val any) *List {
|
||||||
|
if this == nil {
|
||||||
|
return New(val)
|
||||||
|
}
|
||||||
new_head := New(val)
|
new_head := New(val)
|
||||||
new_head.next = this
|
new_head.next = this
|
||||||
return new_head
|
return new_head
|
||||||
@ -46,6 +49,9 @@ func (this *List) Rest() *List {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func First(this *List) any {
|
func First(this *List) any {
|
||||||
|
if this == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return this.Value
|
return this.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +59,10 @@ func (this *List) First() any {
|
|||||||
return First(this)
|
return First(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsEmpty(this *List) bool {
|
||||||
|
return this == nil
|
||||||
|
}
|
||||||
|
|
||||||
func String(this *List) string {
|
func String(this *List) string {
|
||||||
if this == nil {
|
if this == nil {
|
||||||
return "{}"
|
return "{}"
|
||||||
|
|||||||
89
read/read.go
89
read/read.go
@ -1,39 +1,96 @@
|
|||||||
package read
|
package read
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mal-go/list"
|
"mal-go/hash_map"
|
||||||
"mal-go/symbol"
|
"mal-go/symbol"
|
||||||
|
"mal-go/vector"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReadString(s string) (any, any) {
|
func ReadString(s string) (any, any) {
|
||||||
res, err, _ := readInternal(s, 0, nil, "user")
|
res, err, _ := readForm(s, 0, "user")
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSymbolChar(c byte) bool {
|
func isDigitChar(c byte) bool {
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-' || c == '/' || c == '\''
|
return c >= '0' && c <= '9'
|
||||||
}
|
}
|
||||||
|
|
||||||
func readInternal(s string, pos int, ctx *list.List, ns string) (any, any, int) {
|
func isSpaceChar(c byte) bool {
|
||||||
|
return c == ' ' || c == '\n' || c == ','
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSymbolChar(c byte) bool {
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-' || c == '/' || c == '\'' || c == '+' || c == '-' || c == '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
func readForm(s string, pos int, ns string) (any, any, int) {
|
||||||
if pos >= len(s) {
|
if pos >= len(s) {
|
||||||
return ctx, nil, pos
|
return nil, "unterminated input", pos
|
||||||
}
|
}
|
||||||
c := s[pos]
|
c := s[pos]
|
||||||
|
|
||||||
var res, err any
|
var res, err any
|
||||||
|
|
||||||
if isSymbolChar(c) {
|
if isSpaceChar(c) {
|
||||||
res, err, pos2 := readSymbol(s, pos, ns)
|
res, err, pos = readForm(s, pos+1, ns)
|
||||||
return res, err, pos2
|
} else if isDigitChar(c) {
|
||||||
|
res, err, pos = readInt(s, pos, ns)
|
||||||
|
} else if isSymbolChar(c) {
|
||||||
|
res, err, pos = readSymbol(s, pos, ns)
|
||||||
|
} else {
|
||||||
|
switch c {
|
||||||
|
case '{':
|
||||||
|
res, err, pos = readMap(s, pos, ns)
|
||||||
|
case '[':
|
||||||
|
res, err, pos = readVector(s, pos, ns)
|
||||||
|
case '(':
|
||||||
|
res, err, pos = readList(s, pos, ns)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// switch c {
|
return res, err, pos
|
||||||
// case '{':
|
}
|
||||||
// res, err, _ = readInternal(s, pos+1, list.Conj(ctx, hash_map.New()), ns)
|
|
||||||
// case '[':
|
func readMap(s string, pos int, ns string) (any, any, int) {
|
||||||
// case '(':
|
m := hash_map.New()
|
||||||
// }
|
return m, "unimplemented", pos
|
||||||
return res, err, 0
|
}
|
||||||
|
|
||||||
|
func readList(s string, pos int, ns string) (any, any, int) {
|
||||||
|
pos += 1
|
||||||
|
forms := vector.New()
|
||||||
|
for rune(s[pos]) != ')' {
|
||||||
|
res, _, pos2 := readForm(s, pos, ns)
|
||||||
|
forms = forms.Conj(res)
|
||||||
|
pos = pos2
|
||||||
|
}
|
||||||
|
return forms.ToList(), nil, pos + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func readVector(s string, pos int, ns string) (any, any, int) {
|
||||||
|
pos += 1
|
||||||
|
forms := vector.New()
|
||||||
|
for rune(s[pos]) != ']' {
|
||||||
|
res, _, pos2 := readForm(s, pos, ns)
|
||||||
|
forms = forms.Conj(res)
|
||||||
|
pos = pos2
|
||||||
|
}
|
||||||
|
return forms, nil, pos + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func readInt(s string, pos int, ns string) (any, any, int) {
|
||||||
|
startingPos := pos
|
||||||
|
c := s[pos]
|
||||||
|
for isDigitChar(c) {
|
||||||
|
pos += 1
|
||||||
|
if pos >= len(s) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c = s[pos]
|
||||||
|
}
|
||||||
|
res, _ := strconv.Atoi(s[startingPos:pos])
|
||||||
|
return res, nil, pos
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSymbol(s string, pos int, ns string) (any, any, int) {
|
func readSymbol(s string, pos int, ns string) (any, any, int) {
|
||||||
|
|||||||
@ -2,10 +2,19 @@ package read
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"mal-go/list"
|
||||||
"mal-go/symbol"
|
"mal-go/symbol"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestReadInt(t *testing.T) {
|
||||||
|
input := "2"
|
||||||
|
sym, err, end_pos := readInt(input, 0, "user")
|
||||||
|
assert.Equal(t, 2, sym, "should read ")
|
||||||
|
assert.Equal(t, nil, err, "should read without error")
|
||||||
|
assert.Equal(t, len(input), end_pos, "should read the whole string")
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadSymbol(t *testing.T) {
|
func TestReadSymbol(t *testing.T) {
|
||||||
input := "foo"
|
input := "foo"
|
||||||
sym, err, end_pos := readSymbol(input, 0, "user")
|
sym, err, end_pos := readSymbol(input, 0, "user")
|
||||||
@ -21,3 +30,20 @@ func TestReadSymbolWithNamespace(t *testing.T) {
|
|||||||
assert.Equal(t, err, nil, "should read without error")
|
assert.Equal(t, err, nil, "should read without error")
|
||||||
assert.Equal(t, end_pos, len(input), "should read the whole string")
|
assert.Equal(t, end_pos, len(input), "should read the whole string")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadListElem(t *testing.T) {
|
||||||
|
input := "(1223)"
|
||||||
|
f, err, pos := readForm(input, 1, "user")
|
||||||
|
assert.Equal(t, f, 1223, "should num list")
|
||||||
|
assert.Equal(t, err, nil, "should read without error")
|
||||||
|
assert.Equal(t, pos, len(input)-1, "should read the whole number")
|
||||||
|
assert.Equal(t, rune(input[pos]), ')', "should end pointing to ending list char")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadList(t *testing.T) {
|
||||||
|
input := "(1 2 3)"
|
||||||
|
l, err, pos := readList(input, 0, "user")
|
||||||
|
assert.Equal(t, list.New(3).Conj(2).Conj(1), l, "should read list")
|
||||||
|
assert.Equal(t, nil, err, "should read without error")
|
||||||
|
assert.Equal(t, len(input), pos, "should read the whole string")
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package vector
|
package vector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"mal-go/list"
|
||||||
"mal-go/utils"
|
"mal-go/utils"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -49,3 +50,16 @@ func String(this *Vector) string {
|
|||||||
func (this *Vector) String() string {
|
func (this *Vector) String() string {
|
||||||
return String(this)
|
return String(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ToList(this *Vector) *list.List {
|
||||||
|
var l *list.List
|
||||||
|
l = nil
|
||||||
|
for i := len(this._slice) - 1; i >= 0; i-- {
|
||||||
|
l = list.Conj(l, this._slice[i])
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Vector) ToList() *list.List {
|
||||||
|
return ToList(this)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user