]> git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/ast.rb
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / offlineasm / ast.rb
1 # Copyright (C) 2011 Apple Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1. Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22 # THE POSSIBILITY OF SUCH DAMAGE.
23
24 require "config"
25
26 #
27 # Base utility types for the AST.
28 #
29
30 # Valid methods for Node:
31 #
32 # node.children -> Returns an array of immediate children.
33 #
34 # node.descendents -> Returns an array of all strict descendants (children
35 # and children of children, transitively).
36 #
37 # node.flatten -> Returns an array containing the strict descendants and
38 # the node itself.
39 #
40 # node.filter(type) -> Returns an array containing those elements in
41 # node.flatten that are of the given type (is_a? type returns true).
42 #
43 # node.mapChildren{|v| ...} -> Returns a new node with all children
44 # replaced according to the given block.
45 #
46 # Examples:
47 #
48 # node.filter(Setting).uniq -> Returns all of the settings that the AST's
49 # IfThenElse blocks depend on.
50 #
51 # node.filter(StructOffset).uniq -> Returns all of the structure offsets
52 # that the AST depends on.
53
54 class Node
55 attr_reader :codeOrigin
56
57 def initialize(codeOrigin)
58 @codeOrigin = codeOrigin
59 end
60
61 def codeOriginString
62 @codeOrigin.to_s
63 end
64
65 def descendants
66 children.collect{|v| v.flatten}.flatten
67 end
68
69 def flatten
70 [self] + descendants
71 end
72
73 def filter(type)
74 flatten.select{|v| v.is_a? type}
75 end
76 end
77
78 class NoChildren < Node
79 def initialize(codeOrigin)
80 super(codeOrigin)
81 end
82
83 def children
84 []
85 end
86
87 def mapChildren
88 self
89 end
90 end
91
92 class StructOffsetKey
93 attr_reader :struct, :field
94
95 def initialize(struct, field)
96 @struct = struct
97 @field = field
98 end
99
100 def hash
101 @struct.hash + @field.hash * 3
102 end
103
104 def eql?(other)
105 @struct == other.struct and @field == other.field
106 end
107 end
108
109 #
110 # AST nodes.
111 #
112
113 class StructOffset < NoChildren
114 attr_reader :struct, :field
115
116 def initialize(codeOrigin, struct, field)
117 super(codeOrigin)
118 @struct = struct
119 @field = field
120 end
121
122 @@mapping = {}
123
124 def self.forField(codeOrigin, struct, field)
125 key = StructOffsetKey.new(struct, field)
126
127 unless @@mapping[key]
128 @@mapping[key] = StructOffset.new(codeOrigin, struct, field)
129 end
130 @@mapping[key]
131 end
132
133 def dump
134 "#{struct}::#{field}"
135 end
136
137 def <=>(other)
138 if @struct != other.struct
139 return @struct <=> other.struct
140 end
141 @field <=> other.field
142 end
143
144 def address?
145 false
146 end
147
148 def label?
149 false
150 end
151
152 def immediate?
153 true
154 end
155
156 def register?
157 false
158 end
159 end
160
161 class Sizeof < NoChildren
162 attr_reader :struct
163
164 def initialize(codeOrigin, struct)
165 super(codeOrigin)
166 @struct = struct
167 end
168
169 @@mapping = {}
170
171 def self.forName(codeOrigin, struct)
172 unless @@mapping[struct]
173 @@mapping[struct] = Sizeof.new(codeOrigin, struct)
174 end
175 @@mapping[struct]
176 end
177
178 def dump
179 "sizeof #{@struct}"
180 end
181
182 def <=>(other)
183 @struct <=> other.struct
184 end
185
186 def address?
187 false
188 end
189
190 def label?
191 false
192 end
193
194 def immediate?
195 true
196 end
197
198 def register?
199 false
200 end
201 end
202
203 class Immediate < NoChildren
204 attr_reader :value
205
206 def initialize(codeOrigin, value)
207 super(codeOrigin)
208 @value = value
209 raise "Bad immediate value #{value.inspect} at #{codeOriginString}" unless value.is_a? Integer
210 end
211
212 def dump
213 "#{value}"
214 end
215
216 def ==(other)
217 other.is_a? Immediate and other.value == @value
218 end
219
220 def address?
221 false
222 end
223
224 def label?
225 false
226 end
227
228 def immediate?
229 true
230 end
231
232 def immediateOperand?
233 true
234 end
235
236 def register?
237 false
238 end
239 end
240
241 class AddImmediates < Node
242 attr_reader :left, :right
243
244 def initialize(codeOrigin, left, right)
245 super(codeOrigin)
246 @left = left
247 @right = right
248 end
249
250 def children
251 [@left, @right]
252 end
253
254 def mapChildren
255 AddImmediates.new(codeOrigin, (yield @left), (yield @right))
256 end
257
258 def dump
259 "(#{left.dump} + #{right.dump})"
260 end
261
262 def value
263 "#{left.value} + #{right.value}"
264 end
265
266 def address?
267 false
268 end
269
270 def label?
271 false
272 end
273
274 def immediate?
275 true
276 end
277
278 def immediateOperand?
279 true
280 end
281
282 def register?
283 false
284 end
285 end
286
287 class SubImmediates < Node
288 attr_reader :left, :right
289
290 def initialize(codeOrigin, left, right)
291 super(codeOrigin)
292 @left = left
293 @right = right
294 end
295
296 def children
297 [@left, @right]
298 end
299
300 def mapChildren
301 SubImmediates.new(codeOrigin, (yield @left), (yield @right))
302 end
303
304 def dump
305 "(#{left.dump} - #{right.dump})"
306 end
307
308 def value
309 "#{left.value} - #{right.value}"
310 end
311
312 def address?
313 false
314 end
315
316 def label?
317 false
318 end
319
320 def immediate?
321 true
322 end
323
324 def immediateOperand?
325 true
326 end
327
328 def register?
329 false
330 end
331 end
332
333 class MulImmediates < Node
334 attr_reader :left, :right
335
336 def initialize(codeOrigin, left, right)
337 super(codeOrigin)
338 @left = left
339 @right = right
340 end
341
342 def children
343 [@left, @right]
344 end
345
346 def mapChildren
347 MulImmediates.new(codeOrigin, (yield @left), (yield @right))
348 end
349
350 def dump
351 "(#{left.dump} * #{right.dump})"
352 end
353
354 def address?
355 false
356 end
357
358 def label?
359 false
360 end
361
362 def immediate?
363 true
364 end
365
366 def immediateOperand?
367 false
368 end
369
370 def register?
371 false
372 end
373 end
374
375 class NegImmediate < Node
376 attr_reader :child
377
378 def initialize(codeOrigin, child)
379 super(codeOrigin)
380 @child = child
381 end
382
383 def children
384 [@child]
385 end
386
387 def mapChildren
388 NegImmediate.new(codeOrigin, (yield @child))
389 end
390
391 def dump
392 "(-#{@child.dump})"
393 end
394
395 def address?
396 false
397 end
398
399 def label?
400 false
401 end
402
403 def immediate?
404 true
405 end
406
407 def immediateOperand?
408 false
409 end
410
411 def register?
412 false
413 end
414 end
415
416 class OrImmediates < Node
417 attr_reader :left, :right
418
419 def initialize(codeOrigin, left, right)
420 super(codeOrigin)
421 @left = left
422 @right = right
423 end
424
425 def children
426 [@left, @right]
427 end
428
429 def mapChildren
430 OrImmediates.new(codeOrigin, (yield @left), (yield @right))
431 end
432
433 def dump
434 "(#{left.dump} | #{right.dump})"
435 end
436
437 def address?
438 false
439 end
440
441 def label?
442 false
443 end
444
445 def immediate?
446 true
447 end
448
449 def immediateOperand?
450 false
451 end
452
453 def register?
454 false
455 end
456 end
457
458 class AndImmediates < Node
459 attr_reader :left, :right
460
461 def initialize(codeOrigin, left, right)
462 super(codeOrigin)
463 @left = left
464 @right = right
465 end
466
467 def children
468 [@left, @right]
469 end
470
471 def mapChildren
472 AndImmediates.new(codeOrigin, (yield @left), (yield @right))
473 end
474
475 def dump
476 "(#{left.dump} & #{right.dump})"
477 end
478
479 def address?
480 false
481 end
482
483 def label?
484 false
485 end
486
487 def immediate?
488 true
489 end
490
491 def immediateOperand?
492 false
493 end
494
495 def register?
496 false
497 end
498 end
499
500 class XorImmediates < Node
501 attr_reader :left, :right
502
503 def initialize(codeOrigin, left, right)
504 super(codeOrigin)
505 @left = left
506 @right = right
507 end
508
509 def children
510 [@left, @right]
511 end
512
513 def mapChildren
514 XorImmediates.new(codeOrigin, (yield @left), (yield @right))
515 end
516
517 def dump
518 "(#{left.dump} ^ #{right.dump})"
519 end
520
521 def address?
522 false
523 end
524
525 def label?
526 false
527 end
528
529 def immediate?
530 true
531 end
532
533 def immediateOperand?
534 false
535 end
536
537 def register?
538 false
539 end
540 end
541
542 class BitnotImmediate < Node
543 attr_reader :child
544
545 def initialize(codeOrigin, child)
546 super(codeOrigin)
547 @child = child
548 end
549
550 def children
551 [@child]
552 end
553
554 def mapChildren
555 BitnotImmediate.new(codeOrigin, (yield @child))
556 end
557
558 def dump
559 "(~#{@child.dump})"
560 end
561
562 def address?
563 false
564 end
565
566 def label?
567 false
568 end
569
570 def immediate?
571 true
572 end
573
574 def immediateOperand?
575 false
576 end
577
578 def register?
579 false
580 end
581 end
582
583 class RegisterID < NoChildren
584 attr_reader :name
585
586 def initialize(codeOrigin, name)
587 super(codeOrigin)
588 @name = name
589 end
590
591 @@mapping = {}
592
593 def self.forName(codeOrigin, name)
594 unless @@mapping[name]
595 @@mapping[name] = RegisterID.new(codeOrigin, name)
596 end
597 @@mapping[name]
598 end
599
600 def dump
601 name
602 end
603
604 def address?
605 false
606 end
607
608 def label?
609 false
610 end
611
612 def immediate?
613 false
614 end
615
616 def register?
617 true
618 end
619 end
620
621 class FPRegisterID < NoChildren
622 attr_reader :name
623
624 def initialize(codeOrigin, name)
625 super(codeOrigin)
626 @name = name
627 end
628
629 @@mapping = {}
630
631 def self.forName(codeOrigin, name)
632 unless @@mapping[name]
633 @@mapping[name] = FPRegisterID.new(codeOrigin, name)
634 end
635 @@mapping[name]
636 end
637
638 def dump
639 name
640 end
641
642 def address?
643 false
644 end
645
646 def label?
647 false
648 end
649
650 def immediate?
651 false
652 end
653
654 def immediateOperand?
655 false
656 end
657
658 def register?
659 true
660 end
661 end
662
663 class SpecialRegister < NoChildren
664 def initialize(name)
665 @name = name
666 end
667
668 def address?
669 false
670 end
671
672 def label?
673 false
674 end
675
676 def immediate?
677 false
678 end
679
680 def immediateOperand?
681 false
682 end
683
684 def register?
685 true
686 end
687 end
688
689 class Variable < NoChildren
690 attr_reader :name
691
692 def initialize(codeOrigin, name)
693 super(codeOrigin)
694 @name = name
695 end
696
697 @@mapping = {}
698
699 def self.forName(codeOrigin, name)
700 unless @@mapping[name]
701 @@mapping[name] = Variable.new(codeOrigin, name)
702 end
703 @@mapping[name]
704 end
705
706 def dump
707 name
708 end
709
710 def inspect
711 "<variable #{name} at #{codeOriginString}>"
712 end
713 end
714
715 class Address < Node
716 attr_reader :base, :offset
717
718 def initialize(codeOrigin, base, offset)
719 super(codeOrigin)
720 @base = base
721 @offset = offset
722 raise "Bad base for address #{base.inspect} at #{codeOriginString}" unless base.is_a? Variable or base.register?
723 raise "Bad offset for address #{offset.inspect} at #{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
724 end
725
726 def withOffset(extraOffset)
727 Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset))
728 end
729
730 def children
731 [@base, @offset]
732 end
733
734 def mapChildren
735 Address.new(codeOrigin, (yield @base), (yield @offset))
736 end
737
738 def dump
739 "#{offset.dump}[#{base.dump}]"
740 end
741
742 def address?
743 true
744 end
745
746 def label?
747 false
748 end
749
750 def immediate?
751 false
752 end
753
754 def immediateOperand?
755 true
756 end
757
758 def register?
759 false
760 end
761 end
762
763 class BaseIndex < Node
764 attr_reader :base, :index, :scale, :offset
765
766 def initialize(codeOrigin, base, index, scale, offset)
767 super(codeOrigin)
768 @base = base
769 @index = index
770 @scale = scale
771 raise unless [1, 2, 4, 8].member? @scale
772 @offset = offset
773 end
774
775 def scaleShift
776 case scale
777 when 1
778 0
779 when 2
780 1
781 when 4
782 2
783 when 8
784 3
785 else
786 raise "Bad scale at #{codeOriginString}"
787 end
788 end
789
790 def withOffset(extraOffset)
791 BaseIndex.new(codeOrigin, @base, @index, @scale, Immediate.new(codeOrigin, @offset.value + extraOffset))
792 end
793
794 def children
795 [@base, @index, @offset]
796 end
797
798 def mapChildren
799 BaseIndex.new(codeOrigin, (yield @base), (yield @index), @scale, (yield @offset))
800 end
801
802 def dump
803 "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
804 end
805
806 def address?
807 true
808 end
809
810 def label?
811 false
812 end
813
814 def immediate?
815 false
816 end
817
818 def immediateOperand?
819 false
820 end
821
822 def register?
823 false
824 end
825 end
826
827 class AbsoluteAddress < NoChildren
828 attr_reader :address
829
830 def initialize(codeOrigin, address)
831 super(codeOrigin)
832 @address = address
833 end
834
835 def withOffset(extraOffset)
836 AbsoluteAddress.new(codeOrigin, Immediate.new(codeOrigin, @address.value + extraOffset))
837 end
838
839 def dump
840 "#{address.dump}[]"
841 end
842
843 def address?
844 true
845 end
846
847 def label?
848 false
849 end
850
851 def immediate?
852 false
853 end
854
855 def immediateOperand?
856 true
857 end
858
859 def register?
860 false
861 end
862 end
863
864 class Instruction < Node
865 attr_reader :opcode, :operands, :annotation
866
867 def initialize(codeOrigin, opcode, operands, annotation=nil)
868 super(codeOrigin)
869 @opcode = opcode
870 @operands = operands
871 @annotation = annotation
872 end
873
874 def children
875 operands
876 end
877
878 def mapChildren(&proc)
879 Instruction.new(codeOrigin, @opcode, @operands.map(&proc), @annotation)
880 end
881
882 def dump
883 "\t" + opcode.to_s + " " + operands.collect{|v| v.dump}.join(", ")
884 end
885
886 def lowerDefault
887 case opcode
888 when "localAnnotation"
889 $asm.putLocalAnnotation
890 when "globalAnnotation"
891 $asm.putGlobalAnnotation
892 else
893 raise "Unhandled opcode #{opcode} at #{codeOriginString}"
894 end
895 end
896 end
897
898 class Error < NoChildren
899 def initialize(codeOrigin)
900 super(codeOrigin)
901 end
902
903 def dump
904 "\terror"
905 end
906 end
907
908 class ConstDecl < Node
909 attr_reader :variable, :value
910
911 def initialize(codeOrigin, variable, value)
912 super(codeOrigin)
913 @variable = variable
914 @value = value
915 end
916
917 def children
918 [@variable, @value]
919 end
920
921 def mapChildren
922 ConstDecl.new(codeOrigin, (yield @variable), (yield @value))
923 end
924
925 def dump
926 "const #{@variable.dump} = #{@value.dump}"
927 end
928 end
929
930 $labelMapping = {}
931 $referencedExternLabels = Array.new
932
933 class Label < NoChildren
934 attr_reader :name
935
936 def initialize(codeOrigin, name)
937 super(codeOrigin)
938 @name = name
939 @extern = true
940 @global = false
941 end
942
943 def self.forName(codeOrigin, name, definedInFile = false)
944 if $labelMapping[name]
945 raise "Label name collision: #{name}" unless $labelMapping[name].is_a? Label
946 else
947 $labelMapping[name] = Label.new(codeOrigin, name)
948 end
949 if definedInFile
950 $labelMapping[name].clearExtern()
951 end
952 $labelMapping[name]
953 end
954
955 def self.setAsGlobal(codeOrigin, name)
956 if $labelMapping[name]
957 label = $labelMapping[name]
958 raise "Label: #{name} declared global multiple times" unless not label.global?
959 label.setGlobal()
960 else
961 newLabel = Label.new(codeOrigin, name)
962 newLabel.setGlobal()
963 $labelMapping[name] = newLabel
964 end
965 end
966
967 def self.resetReferenced
968 $referencedExternLabels = Array.new
969 end
970
971 def self.forReferencedExtern()
972 $referencedExternLabels.each {
973 | label |
974 yield "#{label.name}"
975 }
976 end
977
978 def clearExtern
979 @extern = false
980 end
981
982 def extern?
983 @extern
984 end
985
986 def setGlobal
987 @global = true
988 end
989
990 def global?
991 @global
992 end
993
994 def dump
995 "#{name}:"
996 end
997 end
998
999 class LocalLabel < NoChildren
1000 attr_reader :name
1001
1002 def initialize(codeOrigin, name)
1003 super(codeOrigin)
1004 @name = name
1005 end
1006
1007 @@uniqueNameCounter = 0
1008
1009 def self.forName(codeOrigin, name)
1010 if $labelMapping[name]
1011 raise "Label name collision: #{name}" unless $labelMapping[name].is_a? LocalLabel
1012 else
1013 $labelMapping[name] = LocalLabel.new(codeOrigin, name)
1014 end
1015 $labelMapping[name]
1016 end
1017
1018 def self.unique(comment)
1019 newName = "_#{comment}"
1020 if $labelMapping[newName]
1021 while $labelMapping[newName = "_#{@@uniqueNameCounter}_#{comment}"]
1022 @@uniqueNameCounter += 1
1023 end
1024 end
1025 forName(nil, newName)
1026 end
1027
1028 def cleanName
1029 if name =~ /^\./
1030 "_" + name[1..-1]
1031 else
1032 name
1033 end
1034 end
1035
1036 def dump
1037 "#{name}:"
1038 end
1039 end
1040
1041 class LabelReference < Node
1042 attr_reader :label
1043
1044 def initialize(codeOrigin, label)
1045 super(codeOrigin)
1046 @label = label
1047 end
1048
1049 def children
1050 [@label]
1051 end
1052
1053 def mapChildren
1054 LabelReference.new(codeOrigin, (yield @label))
1055 end
1056
1057 def name
1058 label.name
1059 end
1060
1061 def extern?
1062 $labelMapping[name].is_a? Label and $labelMapping[name].extern?
1063 end
1064
1065 def used
1066 if !$referencedExternLabels.include?(@label) and extern?
1067 $referencedExternLabels.push(@label)
1068 end
1069 end
1070
1071 def dump
1072 label.name
1073 end
1074
1075 def value
1076 asmLabel()
1077 end
1078
1079 def address?
1080 false
1081 end
1082
1083 def label?
1084 true
1085 end
1086
1087 def immediate?
1088 false
1089 end
1090
1091 def immediateOperand?
1092 true
1093 end
1094 end
1095
1096 class LocalLabelReference < NoChildren
1097 attr_reader :label
1098
1099 def initialize(codeOrigin, label)
1100 super(codeOrigin)
1101 @label = label
1102 end
1103
1104 def children
1105 [@label]
1106 end
1107
1108 def mapChildren
1109 LocalLabelReference.new(codeOrigin, (yield @label))
1110 end
1111
1112 def name
1113 label.name
1114 end
1115
1116 def dump
1117 label.name
1118 end
1119
1120 def value
1121 asmLabel()
1122 end
1123
1124 def address?
1125 false
1126 end
1127
1128 def label?
1129 true
1130 end
1131
1132 def immediate?
1133 false
1134 end
1135
1136 def immediateOperand?
1137 true
1138 end
1139 end
1140
1141 class Sequence < Node
1142 attr_reader :list
1143
1144 def initialize(codeOrigin, list)
1145 super(codeOrigin)
1146 @list = list
1147 end
1148
1149 def children
1150 list
1151 end
1152
1153 def mapChildren(&proc)
1154 Sequence.new(codeOrigin, @list.map(&proc))
1155 end
1156
1157 def dump
1158 list.collect{|v| v.dump}.join("\n")
1159 end
1160 end
1161
1162 class True < NoChildren
1163 def initialize
1164 super(nil)
1165 end
1166
1167 @@instance = True.new
1168
1169 def self.instance
1170 @@instance
1171 end
1172
1173 def value
1174 true
1175 end
1176
1177 def dump
1178 "true"
1179 end
1180 end
1181
1182 class False < NoChildren
1183 def initialize
1184 super(nil)
1185 end
1186
1187 @@instance = False.new
1188
1189 def self.instance
1190 @@instance
1191 end
1192
1193 def value
1194 false
1195 end
1196
1197 def dump
1198 "false"
1199 end
1200 end
1201
1202 class TrueClass
1203 def asNode
1204 True.instance
1205 end
1206 end
1207
1208 class FalseClass
1209 def asNode
1210 False.instance
1211 end
1212 end
1213
1214 class Setting < NoChildren
1215 attr_reader :name
1216
1217 def initialize(codeOrigin, name)
1218 super(codeOrigin)
1219 @name = name
1220 end
1221
1222 @@mapping = {}
1223
1224 def self.forName(codeOrigin, name)
1225 unless @@mapping[name]
1226 @@mapping[name] = Setting.new(codeOrigin, name)
1227 end
1228 @@mapping[name]
1229 end
1230
1231 def dump
1232 name
1233 end
1234 end
1235
1236 class And < Node
1237 attr_reader :left, :right
1238
1239 def initialize(codeOrigin, left, right)
1240 super(codeOrigin)
1241 @left = left
1242 @right = right
1243 end
1244
1245 def children
1246 [@left, @right]
1247 end
1248
1249 def mapChildren
1250 And.new(codeOrigin, (yield @left), (yield @right))
1251 end
1252
1253 def dump
1254 "(#{left.dump} and #{right.dump})"
1255 end
1256 end
1257
1258 class Or < Node
1259 attr_reader :left, :right
1260
1261 def initialize(codeOrigin, left, right)
1262 super(codeOrigin)
1263 @left = left
1264 @right = right
1265 end
1266
1267 def children
1268 [@left, @right]
1269 end
1270
1271 def mapChildren
1272 Or.new(codeOrigin, (yield @left), (yield @right))
1273 end
1274
1275 def dump
1276 "(#{left.dump} or #{right.dump})"
1277 end
1278 end
1279
1280 class Not < Node
1281 attr_reader :child
1282
1283 def initialize(codeOrigin, child)
1284 super(codeOrigin)
1285 @child = child
1286 end
1287
1288 def children
1289 [@child]
1290 end
1291
1292 def mapChildren
1293 Not.new(codeOrigin, (yield @child))
1294 end
1295
1296 def dump
1297 "(not #{child.dump})"
1298 end
1299 end
1300
1301 class Skip < NoChildren
1302 def initialize(codeOrigin)
1303 super(codeOrigin)
1304 end
1305
1306 def dump
1307 "\tskip"
1308 end
1309 end
1310
1311 class IfThenElse < Node
1312 attr_reader :predicate, :thenCase
1313 attr_accessor :elseCase
1314
1315 def initialize(codeOrigin, predicate, thenCase)
1316 super(codeOrigin)
1317 @predicate = predicate
1318 @thenCase = thenCase
1319 @elseCase = Skip.new(codeOrigin)
1320 end
1321
1322 def children
1323 if @elseCase
1324 [@predicate, @thenCase, @elseCase]
1325 else
1326 [@predicate, @thenCase]
1327 end
1328 end
1329
1330 def mapChildren
1331 IfThenElse.new(codeOrigin, (yield @predicate), (yield @thenCase), (yield @elseCase))
1332 end
1333
1334 def dump
1335 "if #{predicate.dump}\n" + thenCase.dump + "\nelse\n" + elseCase.dump + "\nend"
1336 end
1337 end
1338
1339 class Macro < Node
1340 attr_reader :name, :variables, :body
1341
1342 def initialize(codeOrigin, name, variables, body)
1343 super(codeOrigin)
1344 @name = name
1345 @variables = variables
1346 @body = body
1347 end
1348
1349 def children
1350 @variables + [@body]
1351 end
1352
1353 def mapChildren
1354 Macro.new(codeOrigin, @name, @variables.map{|v| yield v}, (yield @body))
1355 end
1356
1357 def dump
1358 "macro #{name}(" + variables.collect{|v| v.dump}.join(", ") + ")\n" + body.dump + "\nend"
1359 end
1360 end
1361
1362 class MacroCall < Node
1363 attr_reader :name, :operands, :annotation
1364
1365 def initialize(codeOrigin, name, operands, annotation)
1366 super(codeOrigin)
1367 @name = name
1368 @operands = operands
1369 raise unless @operands
1370 @operands.each{|v| raise unless v}
1371 @annotation = annotation
1372 end
1373
1374 def children
1375 @operands
1376 end
1377
1378 def mapChildren(&proc)
1379 MacroCall.new(codeOrigin, @name, @operands.map(&proc), @annotation)
1380 end
1381
1382 def dump
1383 "\t#{name}(" + operands.collect{|v| v.dump}.join(", ") + ")"
1384 end
1385 end
1386