2 using System
.Collections
;
3 using System
.Collections
.Generic
;
4 using System
.Text
.RegularExpressions
;
6 using MalVal
= Mal
.types
.MalVal
;
7 using MalSymbol
= Mal
.types
.MalSymbol
;
8 using MalList
= Mal
.types
.MalList
;
9 using MalVector
= Mal
.types
.MalVector
;
10 using MalHashMap
= Mal
.types
.MalHashMap
;
11 using MalThrowable
= Mal
.types
.MalThrowable
;
12 using MalContinue
= Mal
.types
.MalContinue
;
16 public class ParseError
: MalThrowable
{
17 public ParseError(string msg
) : base(msg
) { }
23 public Reader(List
<string> t
) {
28 public string peek() {
29 if (position
>= tokens
.Count
) {
32 return tokens
[position
];
35 public string next() {
36 return tokens
[position
++];
40 public static List
<string> tokenize(string str
) {
41 List
<string> tokens
= new List
<string>();
42 string pattern
= @"[\s ,]*(~@|[\[\]{}()'`~@]|""(?:[\\].|[^\\""])*""|;.*|[^\s \[\]{}()'""`~@,;]*)";
43 Regex regex
= new Regex(pattern
);
44 foreach (Match match
in regex
.Matches(str
)) {
45 string token
= match
.Groups
[1].Value
;
46 if ((token
!= null) && !(token
== "") && !(token
[0] == ';')) {
47 //Console.WriteLine("match: ^" + match.Groups[1] + "$");
54 public static MalVal
read_atom(Reader rdr
) {
55 string token
= rdr
.next();
56 string pattern
= @"(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|^("".*"")$|:(.*)|(^[^""]*$)";
57 Regex regex
= new Regex(pattern
);
58 Match match
= regex
.Match(token
);
59 //Console.WriteLine("token: ^" + token + "$");
61 throw new ParseError("unrecognized token '" + token
+ "'");
63 if (match
.Groups
[1].Value
!= String
.Empty
) {
64 return new Mal
.types
.MalInt(int.Parse(match
.Groups
[1].Value
));
65 } else if (match
.Groups
[3].Value
!= String
.Empty
) {
67 } else if (match
.Groups
[4].Value
!= String
.Empty
) {
68 return Mal
.types
.True
;
69 } else if (match
.Groups
[5].Value
!= String
.Empty
) {
70 return Mal
.types
.False
;
71 } else if (match
.Groups
[6].Value
!= String
.Empty
) {
72 string str
= match
.Groups
[6].Value
;
73 str
= str
.Substring(1, str
.Length
-2)
74 .Replace("\\\"", "\"")
76 .Replace("\\\\", "\\");
77 return new Mal
.types
.MalString(str
);
78 } else if (match
.Groups
[7].Value
!= String
.Empty
) {
79 return new Mal
.types
.MalString("\u029e" + match
.Groups
[7].Value
);
80 } else if (match
.Groups
[8].Value
!= String
.Empty
) {
81 return new Mal
.types
.MalSymbol(match
.Groups
[8].Value
);
83 throw new ParseError("unrecognized '" + match
.Groups
[0] + "'");
87 public static MalVal
read_list(Reader rdr
, MalList lst
, char start
, char end
) {
88 string token
= rdr
.next();
89 if (token
[0] != start
) {
90 throw new ParseError("expected '" + start
+ "'");
93 while ((token
= rdr
.peek()) != null && token
[0] != end
) {
94 lst
.conj_BANG(read_form(rdr
));
98 throw new ParseError("expected '" + end
+ "', got EOF");
105 public static MalVal
read_hash_map(Reader rdr
) {
106 MalList lst
= (MalList
)read_list(rdr
, new MalList(), '{', '}');
107 return new MalHashMap(lst
);
111 public static MalVal
read_form(Reader rdr
) {
112 string token
= rdr
.peek();
113 if (token
== null) { throw new MalContinue(); }
117 case "'": rdr
.next();
118 return new MalList(new MalSymbol("quote"),
120 case "`": rdr
.next();
121 return new MalList(new MalSymbol("quasiquote"),
125 return new MalList(new MalSymbol("unquote"),
129 return new MalList(new MalSymbol("splice-unquote"),
131 case "^": rdr
.next();
132 MalVal meta
= read_form(rdr
);
133 return new MalList(new MalSymbol("with-meta"),
136 case "@": rdr
.next();
137 return new MalList(new MalSymbol("deref"),
140 case "(": form
= read_list(rdr
, new MalList(), '(' , ')'); break;
141 case ")": throw new ParseError("unexpected ')'");
142 case "[": form
= read_list(rdr
, new MalVector(), '[' , ']'); break;
143 case "]": throw new ParseError("unexpected ']'");
144 case "{": form
= read_hash_map(rdr
); break;
145 case "}": throw new ParseError("unexpected '}'");
146 default: form
= read_atom(rdr
); break;
152 public static MalVal
read_str(string str
) {
153 return read_form(new Reader(tokenize(str
)));