tagged release 0.6.4
[parrot.git] / languages / tcl / src / grammar / expr / pge2past.tg
blob8e14db47199c2b5136f33177e2b4794c6b9f2ce8
1 grammar TclExpr::PAST::Grammar is TGE::Grammar;
3 transform past (ROOT) {
4     $P0 = node['expr']
5     unless null $P0 goto expression
6     .return tree.get('dispatch', node, 'TclExpr::Grammar')
8 expression:
9     .return tree.get('expression', node)
10
12 transform expression (TclExpr::Grammar) {
13     .local pmc past
14     past = new 'PAST::Expr'
15     
16     node = node['expr']
17     past['node'] = node
19     $P0 = tree.get('dispatch', node, 'TclExpr::Grammar')
20     past['value'] = $P0
22     .return(past)
25 # Handle generic dispatch (needed at ROOT, and for things with kids.)
27 transform dispatch (TclExpr::Grammar) {
28     .local pmc child
30     # Ask the child node for its past.
31 dispatch:
32     $P0 = node['expand']
33     unless null $P0 goto expand
34     $P0 = node['backslash_substitution']
35     unless null $P0 goto constant
36     $P0 = node['empty']
37     unless null $P0 goto empty
38     $P0 = node['chunk']
39     unless null $P0 goto chunks
40     $P0 = node['substitution']
41     unless null $P0 goto substitution
42     $P0 = node['boolean']
43     unless null $P0 goto boolean
44     $P0 = node['braced_word']
45     unless null $P0 goto braced_word
46     $P0 = node['integer']
47     unless null $P0 goto integer
48     $P0 = node['float']
49     unless null $P0 goto has_float
50     $P0 = node['scientific']
51     unless null $P0 goto scientific
52     $P0 = node['number']
53     unless null $P0 goto number
54     $P0 = node['quoted_word']
55     unless null $P0 goto quoted_word
56     $P0 = node['mathfunc']
57     unless null $P0 goto mathfunc
58     $P0 = node['command']
59     unless null $P0 goto program
60     $P0 = node['subcommand']
61     unless null $P0 goto program
62     $P0 = node['variable_substitution']
63     unless null $P0 goto variable_substitution
64     $P0 = node['command_substitution']
65     unless null $P0 goto command_substitution
66     $P0 = node['nested']
67     unless null $P0 goto nested
68     $P0 = node['type']
69     unless null $P0 goto operator
71     say "Didn't know how to handle node:"
72     .dumper(node)
73     end
75 program:
76     .return tree.get('past', $P0, 'program')
78 empty:
79     $P0 = new 'PAST::Val'
80     $P0['value'] = ''
81     $P0['class'] = 'TclString'
82     .return($P0)
84 expand:
85     .return tree.get('past', node, 'expand')
87 chunks:
88     .return tree.get('past', $P0, 'array')
90 operator:
91     .return tree.get('past', node, 'operator')
93 mathfunc:
94     .return tree.get('past', $P0, 'mathfunc')
96 quoted_word:
97     .return tree.get('past', $P0, 'quoted_word')
99 braced_word:
100     .return tree.get('past', $P0, 'braced_word')
102 number:
103     .return tree.get('past', $P0, 'number')
105 boolean:
106     .return tree.get('past', $P0, 'boolean')
108 constant:
109     .return tree.get('past', $P0, 'constant')
111 integer:
112     .return tree.get('past', $P0, 'integer')
114 has_float:
115     .return tree.get('past', $P0, 'float')
117 scientific:
118     .return tree.get('past', $P0, 'scientific')
120 substitution:
121     node = $P0
122     goto dispatch
124 variable_substitution:
125     .return tree.get('past', $P0, 'variable_substitution')
127 command_substitution:
128     node = $P0
129     $P0 = node['subcommand']
130     unless null $P0 goto program
132     # we have an empty command substitution []
133     $P0 = new 'PAST::Val'
134     $P0['class'] = 'TclString'
135     $P0['value'] = ''
136     .return($P0)
138 nested:
139     .return tree.get('past', $P0, 'nested')
142 # Go through all the children of an operator and transform them.
144 transform past (operator) {
145     # for each child of this operator, dispatch to get the past,
146     # use those as our children.
147     .local pmc children, iter, past
148     .local string name
150     name = node['type']
151     if name == 'ternary:? :' goto is_ternary
152     if name == 'infix:&&' goto is_and
153     if name == 'infix:||' goto is_or
155     past = new 'PAST::Op'
157     past['opfunc'] = name
158     $P0 = node.'get_array'()
159     if null $P0 goto iter_end
160     iter = new 'Iterator', $P0
161   iter_loop:
162     unless iter goto iter_end
163     $P0 = shift iter
164     $S0 = $P0
165     $P1 = tree.'get'('dispatch', $P0, 'TclExpr::Grammar')
166     past.'add_child'($P1)
167     goto iter_loop
168   iter_end:
169     past['children'] = 1
170     .return (past)
172   is_ternary:
173     .return tree.get('ternary', node, 'PAST::Op')
174   is_and:
175     .return tree.get('logical_and', node, 'PAST::Op')
176   is_or:
177     .return tree.get('logical_or', node, 'PAST::Op')
180 transform past (expand) {
181     .local pmc past
182     past = new 'PAST::Expand'
184     delete node['expand']
185     $P0 = tree.'get'('dispatch', node, 'TclExpr::Grammar')
186     past['value'] = $P0
188     .return(past)
191 transform past (program) {
192     .local pmc past
193     past = new 'PAST::Program'
195     .local pmc iter
196     iter = new 'Iterator', node
197 loop:
198     unless iter goto end
199     $P0 = shift iter
200     $P0 = tree.'get'('past', $P0, 'command')
201     if null $P0 goto loop
202     past.'add_child'($P0)
203     goto loop
204 end:
206     $P0 = past.'get_children'()
207     $I0 = elements $P0
208     if $I0 == 0 goto empty
210     .return(past)
212 empty:
213     past = new 'PAST::Val'
214     past['value'] = ''
215     past['class'] = 'TclString'
216     .return(past)
219 transform past (mathfunc) {
220     .local string function_name
221     .local pmc args
222     .local int argc
223     args = node['expression']
224     argc = 0
225     unless args goto has_argc
226     argc = elements args
228 has_argc:
229     .local pmc past
230     past = new 'PAST::MathFunc'
231     $P0  = node['unary_function']
232     unless null $P0 goto unary
233     $P0  = node['nullary_function']
234     unless null $P0 goto nullary
235     $P0  = node['binary_function']
236     unless null $P0 goto binary
237     $P0  = node['nary_function']
238     unless null $P0 goto nary
240   # never get here
242   nullary:
243     if argc > 0 goto too_many
244     function_name = node['nullary_function']
245     goto arguments
247   unary:
248     if argc == 0 goto too_few
249     if argc > 1  goto too_many
250     function_name = node['unary_function']
251     $P0 = args[0]
252     $P1 = tree.'get'('expression', $P0)
253     past.'add_child'($P1)
254     goto arguments
256   binary:
257     if argc < 2 goto too_few
258     if argc > 2 goto too_many
259     function_name = node['binary_function']
261     $P1 = args[0]
262     $P2 = tree.'get'('expression', $P1)
263     past.'add_child'($P2)
265     $P1 = args[1]
266     $P2 = tree.'get'('expression', $P1)
267     past.'add_child'($P2)
268     goto arguments
270   nary:
271     if argc < 1 goto too_few
272     function_name = node['nary_function']
274     .local pmc iter
275     iter = new 'Iterator', args
276   nary_loop:
277     unless iter goto arguments
278     $P0 = shift iter
279     $P0 = tree.'get'('expression', $P0)
280     past.'add_child'($P0)
281     goto nary_loop
283   arguments:
284     past['mathfunc'] = function_name
285     past['children'] = 1
286     .return (past)
288 too_few:
289     tcl_error 'too few arguments for math function'
291 too_many:
292     tcl_error 'too many arguments for math function'
295 transform past (boolean) {
296     .local pmc past
297     past = new 'PAST::Val'
298     past.set_node(node)
299     
300     $S0 = node
301     $P0 = new 'TclConst'
302     $P0 = $S0
303     $S0 = $P0
304     past['value'] = $S0
305     past['class'] = "TclString"
306     .return(past)
309 transform past (constant) {
310     .local pmc past
311     past = new 'PAST::Val'
312     past.set_node(node)
313     
314     $S0 = node
315     $P0 = new 'TclConst'
316     $P0 = $S0
317     $S0 = $P0
318     past['value'] = $S0
319     past['class'] = "TclString"
320     .return(past)
323 transform past (braced_word) {
324     .local pmc past
325     past = new 'PAST::Val'
326     past.set_node(node)
328     $P0 = node['PGE::Text::bracketed']
329     $S0 = $P0[0]
330     past['value'] = $S0
331     past['class'] = "TclString"
332     .return(past)
335 transform past (number) {
336     $P0 = node['integer']
337     unless null $P0 goto integer
338     $P0 = node['float']
339     unless null $P0 goto have_float
340     $P0 = node['scientific']
341     unless null $P0 goto scientific
342     tcl_error 'invalid number type'
344 integer:
345     .return tree.get('past', $P0, 'integer')
347 have_float:
348     .return tree.get('past', $P0, 'float')
350 scientific:
351     .return tree.get('past', $P0, 'scientific')
355 transform past (nested) :language('PIR') {
356     .local pmc past
357     $P0  = node['expression'; 'expr']
358     past = tree.'get'('dispatch', $P0, 'TclExpr::Grammar')
359     .return(past)
363 transform past (scientific) {
364     .local pmc past
365     past = new 'PAST::Val'
366     past.set_node(node)
367     
368     $S0 = node[0]
369     $N0 = $S0
370     $S0 = node[1]
371     $N1 = $S0
372     $N1 = 10**$N1
373     $N0 *= $N1
374     
375     $S0 = $N0
376     past['value'] = $S0
377     past['class'] = "TclFloat"
379     .return(past)
382 transform past (integer) {
383     .local pmc past
384     past = new 'PAST::Val'
385     past.set_node(node)
387     $P0 = node['binary']
388     unless null $P0 goto binary
389     $P0 = node['octal']
390     unless null $P0 goto octal
391     $P0 = node['hex']
392     unless null $P0 goto hex
394     # XXX (40863): This is a bad hack to make bignums compile
395     $S0 = node['decimal']
396     $I0 = length $S0
397     if $I0 < 10 goto decimal
398     if $I0 > 10 goto bignum_hack
400     if $S0 >= "2147483647" goto bignum_hack
402   decimal:
403     $S0 = node
404     past['value'] = $S0
405     past['class'] = "TclInt"
406     .return (past)
408   bignum_hack:
409     past['value'] = 0
410     past['class'] = "TclInt"
411     .return(past)
413   binary:
414     .local int bvalue
415     bvalue = 0
416     $S0 = $P0[0]
417     $I0 = 0
418     $I1 = length $S0
419   binary_loop:
420     if $I0 >= $I1 goto binary_done
421     shl bvalue, 1
422     $S2 = substr $S0, $I0, 1
423     inc $I0
424     if $S2 == '0' goto binary_loop
425     bvalue += 1
426     goto binary_loop
427   binary_done:
428     past['value'] = bvalue
429     past['class'] = "TclInt"
430     .return(past)
432   octal: 
433      $S0 = $P0[0]
435     .local int octal_value, octal_digit, octal_counter, octal_length
436     octal_length  = length $S0
437     octal_counter = 0
438     octal_value   = 0
439     # at this point, string should consist only of digits 0-7
440   octal_loop:
441     if octal_counter == octal_length goto octal_done # skip first 0
442     octal_digit = ord $S0, octal_counter
443     octal_digit -= 48 # ascii value of 0
444     octal_value *= 8
445     octal_value += octal_digit
446     inc octal_counter
447     goto octal_loop
448   
449   octal_done:
450     past['value'] = octal_value
451     past['class'] = "TclInt"
452     .return (past)
454   hex:
455     $S0 = node
456     .local int len, digit, hex_value
457     len = length $S0
458     $I0 = 2 # skip 0x
459     hex_value = 0
460   hex_loop:
461     if $I0 == len goto hex_done
462     digit = ord $S0, $I0
463     # higher than Z - must be lowercase letter
464     if digit > 90 goto hex_lower
465     # higher than 9 - must be uppercase letter
466     if digit > 57 goto hex_upper
467     digit -= 48 # value of 0
468     goto hex_next
469   hex_lower:
470     digit -= 97 # value of a
471     digit += 10
472     goto hex_next
473   hex_upper:
474     digit -= 65 # value of A
475     digit += 10
476     # goto hex_next
477   hex_next:
478     hex_value *= 16
479     hex_value += digit
480     inc $I0
481     goto hex_loop
483   hex_done:
484     past['value'] = hex_value
485     past['class'] = "TclInt"
486     .return(past)
490 transform past (float) {
491     .local pmc past
492     past = new 'PAST::Val'
493     past.set_node(node)
495     $S0 = node
496     past['value'] = $S0
497     past['class'] = "TclFloat"
498     .return (past)
501 transform past (quoted_word) {
502     .local pmc past
503     $P0 = node['chunk']
504     if null $P0 goto empty_string
506     .return tree.get('past', $P0, 'array')
508 empty_string:
509     past = new 'PAST::Val'
510     past['node']  = node
511     past['class'] = 'TclString'
512     past['value'] = ''
514     .return(past)
517 transform past (array) {
518     .local pmc past
519     .local pmc iter
520     iter = new 'Iterator', node
521     null past
522   iter_loop:
523     unless iter goto iter_end
524     .local pmc cnode, cpast
525     cnode = shift iter
526     $I0 = exists cnode['substitution']
527     unless $I0 goto cpast_str
528     cnode = cnode['substitution']
529     cpast = tree.'get'('dispatch', cnode, 'TclExpr::Grammar')
530     goto cpast_add
531   cpast_str:
532     $S0 = cnode
533     $P0 = new 'TclConst'
534     $P0 = $S0
535     $S0 = $P0
536     cpast = new 'PAST::Val'
537     cpast['node'] = node
538     cpast['class'] = 'TclString'
539     cpast['value'] = $S0
540   cpast_add:
541     unless null past goto cpast_concat
542     past = cpast
543     goto iter_loop
544   cpast_concat:
545     $P0 = new 'PAST::Op'
546     $P0.add_child(past)
547     $P0.add_child(cpast)
548     $P0['node'] = node
549     $P0['opfunc'] = 'infix:concat'
550     past = $P0
551     goto iter_loop
552   iter_end:
553     .return(past)
556 transform past (command) {
557     .local pmc past, words, iter
558     .local string node_type
560     words = node['word']
561     if null words goto empty
563     .local pmc command
564     command = shift words
565     command = tree.'get'('dispatch', command, 'TclExpr::Grammar')
567     node_type = typeof command
568     if node_type == 'PAST::Val' goto static
570     node_type = 'PAST::DynamicCommand'
571     goto create_node
573 static:
574     node_type = 'PAST::StaticCommand'
575 create_node:
576     past = new node_type
577     past.set_node(node)
578     past.'add_child'(command)
580     iter = new 'Iterator', words
581 loop2:
582     unless iter goto end2
583     $P0 = shift iter
584     $P1 = tree.'get'('dispatch', $P0, 'TclExpr::Grammar')
585     past.'add_child'($P1)
586     goto loop2
587 end2:
588     .return(past)
590 empty:
591     null past
592     .return(past)
595 transform past (variable_substitution) {
596     .local pmc past
597     past = new 'PAST::Var'
598     past.set_node(node)
599     
600     $S0 = node[0]
601     past['name']  = $S0
603     $I0 = exists node['index']
604     if $I0 goto array
605     .return(past)
607 array:
608     $P0 = node['index']
609     $P0 = tree.'get'('past', $P0, 'array')
610     past['index'] = $P0
611     .return(past)
614 transform ternary (PAST::Op) {
615     .local pmc past
617     past = new 'PAST::Cond'
618     past.set_node(node)
620     $P1 = node[0]
621     $P2 = tree.'get'('dispatch', $P1, 'TclExpr::Grammar')
622     past.'add_child'($P2)
623     $P1 = node[1]
624     $P2 = tree.'get'('dispatch', $P1, 'TclExpr::Grammar')
625     past.'add_child'($P2)
626     $P1 = node[2]
627     $P2 = tree.'get'('dispatch', $P1, 'TclExpr::Grammar')
628     past.'add_child'($P2)
630     past['conditional'] = 1
632     .return(past)
635 transform logical_and (PAST::Op) {
636     .local pmc past, true, false, A, B
637     .local pmc inner
639     # Transform A && B into:
640     # A ? ( B ? 1 : 0) : 0
642     true = new 'PAST::Val'
643     true['value'] = 1
644     true['class'] = "TclInt"
646     false = new 'PAST::Val'
647     false['value'] = 0
648     false['class'] = "TclInt"
650     # Get our A & B trees..
651     $P1 = node[0]
652     A = tree.'get'('dispatch', $P1, 'TclExpr::Grammar')
653     $P1 = node[1]
654     B = tree.'get'('dispatch', $P1, 'TclExpr::Grammar')
656     # Generate (B ? 1 : 0)
657     inner = new 'PAST::Cond'
658     inner.'add_child'(B)
660     inner.'add_child'(true)
661     inner.'add_child'(false)
662     inner['conditional'] = 1
664     # Generate (A ? (...) : 0)
665     past = new 'PAST::Cond'
666     past.set_node(node)
668     past.'add_child' (A)
670     past.'add_child' (inner)
671     past.'add_child' (false)
673     past['conditional'] = 1
675     .return(past)
678 transform logical_or (PAST::Op) {
679     .local pmc past, true, false, A, B
680     .local pmc inner
682     # Transform A || B into:
683     # A ? 1 : ( B ? 1 : 0)
685     true = new 'PAST::Val'
686     true['value'] = 1
687     true['class'] = "TclInt"
689     false = new 'PAST::Val'
690     false['value'] = 0
691     false['class'] = "TclInt"
693     # Get our A & B trees..
694     $P1 = node[0]
695     A = tree.'get'('dispatch', $P1, 'TclExpr::Grammar')
696     $P1 = node[1]
697     B = tree.'get'('dispatch', $P1, 'TclExpr::Grammar')
699     # Generate (B ? 1 : 0)
700     inner = new 'PAST::Cond'
701     inner.'add_child'(B)
703     inner.'add_child'(true)
704     inner.'add_child'(false)
705     inner['conditional'] = 1
707     # Generate (A ? 1 : (...))
708     past = new 'PAST::Cond'
709     past.set_node(node)
711     past.'add_child' (A)
713     past.'add_child' (true)
714     past.'add_child' (inner)
716     past['conditional'] = 1
718     .return(past)