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 }