15 type Reader
interface {
20 type TokenReader
struct {
25 func (tr
*TokenReader
) next() *string {
26 if tr
.position
>= len(tr
.tokens
) { return nil }
27 token
:= tr
.tokens
[tr
.position
]
28 tr
.position
= tr
.position
+ 1
32 func (tr
*TokenReader
) peek() *string {
33 if tr
.position
>= len(tr
.tokens
) { return nil }
34 return &tr
.tokens
[tr
.position
]
39 func tokenize (str
string) []string {
40 results
:= make([]string, 0, 1)
41 // Work around lack of quoting in backtick
42 re
:= regexp
.MustCompile(`[\s,]*(~@|[\[\]{}()'` + "`" +
43 `~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"` + "`" +
45 for _
, group
:= range re
.FindAllStringSubmatch(str
, -1) {
46 if (group
[1] == "") ||
(group
[1][0] == ';') { continue }
47 results
= append(results
, group
[1])
52 func read_atom(rdr Reader
) (MalType
, error
) {
54 if token
== nil { return nil, errors
.New("read_atom underflow") }
55 if match
, _
:= regexp
.MatchString(`^-?[0-9]+$`, *token
); match
{
58 if i
, e
= strconv
.Atoi(*token
); e
!= nil {
59 return nil, errors
.New("number parse error")
62 } else if (*token
)[0] == '"' {
63 str
:= (*token
)[1:len(*token
)-1]
64 return strings
.Replace(
65 strings
.Replace(str
, `\"`, `"`, -1),
67 } else if *token
== "nil" {
69 } else if *token
== "true" {
71 } else if *token
== "false" {
74 return Symbol
{*token
}, nil
79 func read_list(rdr Reader
, start
string, end
string) (MalType
, error
) {
81 if token
== nil { return nil, errors
.New("read_list underflow") }
83 ast_list
:= []MalType
{}
85 return nil, errors
.New("expected '" + start
+ "'")
88 for ; true ; token
= rdr
.peek() {
89 if token
== nil { return nil, errors
.New("exepected '" + end
+ "', got EOF") }
90 if *token
== end
{ break }
91 f
, e
:= read_form(rdr
)
92 if e
!= nil { return nil, e
}
93 ast_list
= append(ast_list
, f
)
96 return List
{ast_list
}, nil
99 func read_vector(rdr Reader
) (MalType
, error
) {
100 lst
, e
:= read_list(rdr
, "[", "]")
101 if e
!= nil { return nil, e
}
102 vec
:= Vector
{lst
.(List
).Val
}
106 func read_hash_map(rdr Reader
) (MalType
, error
) {
107 mal_lst
, e
:= read_list(rdr
, "{", "}")
108 lst
:= mal_lst
.(List
).Val
109 if e
!= nil { return nil, e
}
110 if len(lst
) % 2 == 1 {
111 return nil, errors
.New("Odd number of hash map arguments")
113 m
:= map[string]MalType
{}
114 for i
:= 0; i
< len(lst
); i
+=2 {
115 str
, ok
:= lst
[i
].(string)
117 return nil, errors
.New("expected hash-map key string")
124 func read_form(rdr Reader
) (MalType
, error
) {
126 if token
== nil { return nil, errors
.New("read_form underflow") }
129 case `'`: rdr
.next();
130 form
, e
:= read_form(rdr
); if e
!= nil { return nil, e
}
131 return List
{[]MalType
{Symbol
{"quote"}, form
}}, nil
132 case "`": rdr
.next();
133 form
, e
:= read_form(rdr
); if e
!= nil { return nil, e
}
134 return List
{[]MalType
{Symbol
{"quasiquote"}, form
}}, nil
135 case `~`: rdr
.next();
136 form
, e
:= read_form(rdr
); if e
!= nil { return nil, e
}
137 return List
{[]MalType
{Symbol
{"unquote"}, form
}}, nil
138 case `~@`: rdr
.next();
139 form
, e
:= read_form(rdr
); if e
!= nil { return nil, e
}
140 return List
{[]MalType
{Symbol
{"splice-unquote"}, form
}}, nil
143 case ")": return nil, errors
.New("unexpected ')'")
144 case "(": return read_list(rdr
, "(", ")")
147 case "]": return nil, errors
.New("unexpected ']'")
148 case "[": return read_vector(rdr
)
151 case "}": return nil, errors
.New("unexpected '}'")
152 case "{": return read_hash_map(rdr
)
153 default: return read_atom(rdr
)
155 return read_atom(rdr
)
158 func Read_str(str
string) (MalType
, error
) {
159 var tokens
= tokenize(str
);
160 if len(tokens
) == 0 {
161 return nil, errors
.New("<empty line>")
164 return read_form(&TokenReader
{tokens
: tokens
, position
: 0})