Mercurial > repos > tabletprog
comparison modules/parser.tp @ 212:32080f96c3a0
Implement matchOne matching macro. Support more AST node types in zeroPlus matching macro.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 30 Nov 2013 15:05:24 -0800 |
parents | 4b3b57f39f10 |
children | e00a8bc6361b |
comparison
equal
deleted
inserted
replaced
211:53cd9c3bcf96 | 212:32080f96c3a0 |
---|---|
1 #{ | 1 #{ |
2 _applyMatch <- :fun tomatch { | 2 _applyMatch <- :fun tomatch { |
3 fun: tomatch | 3 fun: tomatch |
4 } | |
5 _matchString <- :str tomatch { | |
6 if: (tomatch isString?) { | |
7 if: (tomatch length) < (str length) { | |
8 #{ | |
9 matched? <- { false } | |
10 } | |
11 } else: { | |
12 if: (tomatch length) > (str length) { | |
13 tomatch <- tomatch from: 0 withLength: (str length) | |
14 } | |
15 if: str = tomatch { | |
16 #{ | |
17 matched? <- { true } | |
18 matchlen <- { str length } | |
19 } | |
20 } else: { | |
21 #{ | |
22 matched? <- { false } | |
23 } | |
24 } | |
25 } | |
26 } else: { | |
27 #{ | |
28 matched? <- { false } | |
29 } | |
30 } | |
31 } | |
32 ifmatch:else <- :matchres :elseblock { | |
33 if: (matchres matched?) { | |
34 matchres | |
35 } else: { | |
36 elseblock: | |
37 } | |
38 } | |
39 _makeMatchCall <- :matchexpr { | |
40 if: (matchexpr nodeType) = "lambda" { | |
41 #{ | |
42 valid? <- { true } | |
43 matchcall <- quote: (_applyMatch: matchexpr tomatch) | |
44 } | |
45 } else: { | |
46 if: (matchexpr nodeType) = "symbol" { | |
47 #{ | |
48 valid? <- { true } | |
49 matchcall <- quote: (matchexpr: tomatch) | |
50 } | |
51 } else: { | |
52 if: (matchexpr nodeType) = "strlit" { | |
53 #{ | |
54 valid? <- { true } | |
55 matchcall <- quote: (_matchString: matchexpr tomatch) | |
56 } | |
57 } else: { | |
58 if: (matchexpr nodeType) = "op" { | |
59 if: (matchexpr opName) = "." { | |
60 left <- (_makeMatchCall: (matchexpr left)) matchcall | |
61 right <- (_makeMatchCall: (matchexpr right)) matchcall | |
62 #{ | |
63 valid? <- { true } | |
64 matchcall <- quote: (_applyMatch: :tomatch { | |
65 lm <- left | |
66 if: (lm matched?) { | |
67 tomatch <- tomatch from: (lm matchlen) | |
68 rm <- right | |
69 if: (rm matched?) { | |
70 total <- (rm matchlen) + (lm matchlen) | |
71 #{ | |
72 matched? <- { true } | |
73 matchlen <- { total } | |
74 } | |
75 } else: { | |
76 rm | |
77 } | |
78 } else: { | |
79 lm | |
80 } | |
81 } tomatch) | |
82 } | |
83 } else: { | |
84 #{ | |
85 valid? <- { false } | |
86 message <- "Unsupported operator " . (matchexpr opName) | |
87 } | |
88 } | |
89 } else: { | |
90 #{ | |
91 valid? <- { false } | |
92 message <- "Unsupported AST node type " . (matchexpr nodeType) | |
93 } | |
94 } | |
95 } | |
96 } | |
97 } | |
4 } | 98 } |
5 expandClass <- :chars { | 99 expandClass <- :chars { |
6 if: (chars length) > 0 { | 100 if: (chars length) > 0 { |
7 pos <- 0 | 101 pos <- 0 |
8 inverted <- false | 102 inverted <- false |
47 if: inverted { | 141 if: inverted { |
48 old <- out | 142 old <- out |
49 out <- "" | 143 out <- "" |
50 cur <- 0 | 144 cur <- 0 |
51 while: { cur < 256 } do: { | 145 while: { cur < 256 } do: { |
52 out <- out . (cur asStringChar) | 146 notfound <- true |
147 idx <- 0 | |
148 len <- (old length) | |
149 while: { notfound && idx < len } do: { | |
150 if: cur = (old byte: idx) { | |
151 notfound <- false | |
152 } else: { | |
153 idx <- idx + 1 | |
154 } | |
155 } | |
156 if: notfound { | |
157 out <- out . (cur asStringChar) | |
158 } | |
53 cur <- cur + 1 | 159 cur <- cur + 1 |
54 } | 160 } |
55 } | 161 } |
56 out | 162 out |
57 } else: { | 163 } else: { |
58 "" | 164 "" |
59 } | 165 } |
60 } | 166 } |
61 charClass <- macro: :rawchars { | 167 charClass <- macro: :rawchars { |
62 eval: rawchars :chars { | 168 eval: rawchars :chars { |
169 orig <- chars | |
63 chars <- expandClass: chars | 170 chars <- expandClass: chars |
64 //TODO: Use a more sophisticated approach for large classes | 171 //TODO: Use a more sophisticated approach for large classes |
65 quote: :tomatch { | 172 quote: :tomatch { |
66 if: (tomatch isString?) { | 173 if: (tomatch isString?) { |
67 check <- 0 | 174 check <- 0 |
88 matched? <- { false } | 195 matched? <- { false } |
89 } | 196 } |
90 } | 197 } |
91 } | 198 } |
92 } else: { | 199 } else: { |
93 print: "uh oh" | 200 print: "#error Argument to charClass macro must be a compile-time constant\n" |
94 } | 201 } |
95 } | 202 } |
96 | 203 |
97 zeroPlus <- macro: :matchexpr { | 204 zeroPlus <- macro: :matchexpr { |
98 funexpr <- false | 205 funexpr <- false |
99 valid <- false | 206 valid <- false |
100 matchcall <- if: (matchexpr nodeType) = "lambda" { | 207 mc <- _makeMatchCall: matchexpr |
101 valid <- true | 208 if: (mc valid?) { |
102 quote: (_applyMatch: matchexpr tomatch) | 209 mcall <- mc matchcall |
103 } else: { | |
104 if: (matchexpr nodeType) = "symbol" { | |
105 valid <- true | |
106 quote: (matchexpr: tomatch) | |
107 } | |
108 } | |
109 if: valid { | |
110 quote: :tomatch { | 210 quote: :tomatch { |
111 cur <- 0 | 211 cur <- 0 |
112 n <- tomatch byte_length | 212 n <- tomatch byte_length |
113 orig <- tomatch | 213 orig <- tomatch |
114 match <- true | 214 match <- true |
115 while: { match && cur < n } do: { | 215 while: { match && cur < n } do: { |
116 res <- matchcall | 216 res <- mcall |
117 match <- res matched? | 217 match <- res matched? |
118 if: match { | 218 if: match { |
119 //TODO: Use some kind of lightweight substring wrapper here | 219 //TODO: Use some kind of lightweight substring wrapper here |
120 tomatch <- tomatch from: (res matchlen) | 220 tomatch <- tomatch from: (res matchlen) |
121 cur <- cur + (res matchlen) | 221 cur <- cur + (res matchlen) |
131 matched? <- { false } | 231 matched? <- { false } |
132 } | 232 } |
133 } | 233 } |
134 } | 234 } |
135 } else: { | 235 } else: { |
136 print: "#error Invalid zeroPlus macro call\n" | 236 print: "#error Invalid zeroPlus macro call: " . (mc message) . "\n" |
237 } | |
238 } | |
239 | |
240 matchOne <- macro: :options { | |
241 options <- (options value) map: :option { | |
242 _makeMatchCall: option | |
243 } | |
244 body <- options foldr: (quote: #{ | |
245 matched? <- { false } | |
246 }) with: :acc el { | |
247 if: (el valid?) { | |
248 mcall <- el matchcall | |
249 quote: (ifmatch: mcall else: { acc }) | |
250 } else: { | |
251 print: "#error Invalid matchOne macro call: " . (el message) . "\n" | |
252 acc | |
253 } | |
254 } | |
255 quote: :tomatch { | |
256 body | |
137 } | 257 } |
138 } | 258 } |
139 | 259 |
140 | 260 |
141 _alpha <- charClass: "a-zA-Z" | 261 _alpha <- charClass: "a-zA-Z" |
142 alpha <- zeroPlus: _alpha | 262 alpha <- zeroPlus: _alpha |
143 alphaNum <- zeroPlus: (charClass: "a-zA-Z0-9") | 263 alphaNum <- zeroPlus: (charClass: "a-zA-Z0-9") |
264 hws <- zeroPlus: (matchOne: [ | |
265 (charClass: " \t") | |
266 "/*" . (zeroPlus: (matchOne: [(charClass: "^*") "*" . (charClass: "^/")])) . "*/" | |
267 ]) | |
268 | |
144 | 269 |
145 main <- { | 270 main <- { |
146 cmatch <- alpha: "czx0123" | 271 cmatch <- alpha: "czx0123" |
147 zeromatch <- alpha: "01234" | 272 zeromatch <- alpha: "01234" |
148 if: (cmatch matched?) { | 273 if: (cmatch matched?) { |
159 if: (zeromatchanum matched?) { | 284 if: (zeromatchanum matched?) { |
160 print: "01234 matched with length " . (zeromatchanum matchlen) . "\n" | 285 print: "01234 matched with length " . (zeromatchanum matchlen) . "\n" |
161 } else: { | 286 } else: { |
162 print: "01234 didn't match\n" | 287 print: "01234 didn't match\n" |
163 } | 288 } |
289 stuff <- " \t/* blah blah blah * blah */ foo" | |
290 hwsmatch <- hws: stuff | |
291 if: (hwsmatch matched?) { | |
292 print: "'" . (stuff from: (hwsmatch matchlen)) . "' found after hws\n" | |
293 } else: { | |
294 print: stuff . " did not match hws rule\n" | |
295 } | |
164 } | 296 } |
165 } | 297 } |