2 Imports System
.Collections
3 Imports System
.Collections
.Generic
4 Imports System
.Text
.RegularExpressions
6 Imports MalVal
= Mal
.types
.MalVal
7 Imports MalSymbol
= Mal
.types
.MalSymbol
8 Imports MalList
= Mal
.types
.MalList
9 Imports MalVector
= Mal
.types
.MalVector
10 Imports MalHashMap
= Mal
.types
.MalHashMap
11 Imports MalThrowable
= Mal
.types
.MalThrowable
12 Imports MalContinue
= Mal
.types
.MalContinue
16 Public Class ParseError
18 Public Sub New(msg
As String)
24 Private tokens
As New List(Of
String)
25 Private position
As Int32
= 0
26 Sub New(t
As List(Of
String))
31 Public Function peek() As String
32 If position
>= tokens
.Count
Then
35 return tokens(position
)
39 Public Function get_next() As String
40 If position
>= tokens
.Count
Then
44 return tokens(position
-1)
49 Shared
Function tokenize(str
As String) As List(Of
String)
50 Dim tokens
As New List(Of
String)
51 Dim pattern
As String = "[\s ,]*(~@|[\[\]{}()'`~@]|""(?:[\\].|[^\\""])*""|;.*|[^\s \[\]{}()'""`~@,;]*)"
52 Dim regex
As New Regex(pattern
)
53 For Each match
As Match
In regex
.Matches(str
)
54 Dim token
As String = match
.Groups(1).Value
55 If Not token Is
Nothing _
56 AndAlso
Not token
= "" _
57 AndAlso
Not token(0) = ";" Then
58 'Console.WriteLine("match: ^" & match.Groups[1] & "$")
65 Shared
Function read_atom(rdr
As Reader
) As MalVal
66 Dim token
As String = rdr
.get_next()
67 Dim pattern
As String = "(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|^("".*"")$|^:(.*)|(^[^""]*$)"
68 Dim regex As Regex = New Regex(pattern)
69 Dim match As Match = regex.Match(token)
70 'Console.WriteLine("token
: ^
" + token + "$")
71 If not match
.Success
Then
72 throw
New ParseError("unrecognized token '" & token
& "'")
74 If match
.Groups(1).Value
<> String.Empty
Then
75 return New Mal
.types
.MalInt(Integer.Parse(match
.Groups(1).Value
))
76 Else If match
.Groups(3).Value
<> String.Empty
Then
78 Else If match
.Groups(4).Value
<> String.Empty
Then
79 return Mal
.types
.MalTrue
80 Else If match
.Groups(5).Value
<> String.Empty
Then
81 return Mal
.types
.MalFalse
82 Else If match
.Groups(6).Value
<> String.Empty
Then
83 Dim str
As String = match
.Groups(6).Value
84 return New Mal
.types
.MalString(
85 str
.Substring(1, str
.Length
-2) _
86 .Replace("\""", """") _
87 .Replace("\n", Environment
.NewLine
) _
89 Else If match
.Groups(7).Value
<> String.Empty
Then
90 return New Mal
.types
.MalString(ChrW(&H029e
) & match
.Groups(7).Value
)
91 Else If match
.Groups(8).Value
<> String.Empty
Then
92 return New Mal
.types
.MalSymbol(match
.Groups(8).Value
)
94 throw
New ParseError("unrecognized '" & match
.Groups(0).Value
& "'")
98 Shared
Function read_list(rdr
As Reader
, lst
As MalList
,
99 start
As String, last
As String) As MalVal
100 Dim token
As String = rdr
.get_next()
101 If token(0) <> start
Then
102 throw
New ParseError("expected '" & start
& "'")
106 While token IsNot
Nothing AndAlso
token(0) <> last
107 lst
.conj_BANG(read_form(rdr
))
111 If token Is
Nothing Then
112 throw
New ParseError("expected '" & last
& "', got EOF")
119 Shared
Function read_hash_map(rdr
As Reader
) As MalVal
120 Dim lst
As MalList
= DirectCast(read_list(rdr
, new MalList(),
122 return New MalHashMap(lst
)
126 Shared
Function read_form(rdr
As Reader
) As MalVal
127 Dim token
As String = rdr
.peek()
128 If token Is
Nothing Then
129 throw
New MalContinue()
131 Dim form
As MalVal
= Nothing
136 return New MalList(New MalSymbol("quote"),
140 return New MalList(New MalSymbol("quasiquote"),
144 return New MalList(New MalSymbol("unquote"),
148 return new MalList(New MalSymbol("splice-unquote"),
152 Dim meta
As MalVal
= read_form(rdr
)
153 return new MalList(New MalSymbol("with-meta"),
158 return new MalList(New MalSymbol("deref"),
162 form
= read_list(rdr
, New MalList(), "(" , ")")
164 throw
New ParseError("unexpected ')'")
166 form
= read_list(rdr
, New MalVector(), "[" , "]")
168 throw
New ParseError("unexpected ']'")
170 form
= read_hash_map(rdr
)
172 throw
New ParseError("unexpected '}'")
174 form
= read_atom(rdr
)
180 Shared
Function read_str(str
As string) As MalVal
181 return read_form(New Reader(tokenize(str
)))