kompiler 0.3.0.pre.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,693 @@
1
+
2
+ #
3
+ # Implements logic to parse math-like expressions into an ASTs.
4
+ #
5
+ # Main functions:
6
+ # str_to_ast - converts a raw string into an AST.
7
+ # run_ast - runs the AST created by str_to_ast.
8
+ #
9
+ # Config options are available in Kompiler::Parsers::SymAST::Config :
10
+ # word_begin_chars - a list of characters that a word can begin with
11
+ # word_chars - a list of characters that a word can contain
12
+ # number_begin_chars - a list of characters that a number can begin with
13
+ # number_chars - a list of characters that a number can contain
14
+ # whitespace_chars - a list of whitespace / separator characters
15
+ # parse_functions - a boolean specifying whether functions with syntax func(x + 2) should be parsed or throw an error
16
+ # sign_types - a list of available signs, their names and character sequences that qualify as the sign.
17
+ # Entries appearing earlier in the list are prioritized.
18
+ # one_element_ast_operations - a list of one element operations, their names, sign types, and checking direction (1 for left to right, -1 for right to left).
19
+ # For example, the negation "-x" is a one element operation, with the sign type "sub", and check_direction -1 (checks from right to left) because it is on the left of the 'x'
20
+ # Entries appearing earlier in the list are prioritized.
21
+ # two_element_ast_operations - a list of two element operation 'groups'. Groups are implemented to list operations on the same priority level with the same check direction.
22
+ # Each group has a check_direction (1 for left to right, -1 for opposite), and a list of operations in this group, their names and sign types, similar to one element operations.
23
+ # Entries appearing earlier in the list are prioritized.
24
+ # An example group could be multiplication and division. The check_direction will be 1, and there will be two operations (mul and div). This group will be below the power (a ** b) group.
25
+ # functions - a list of available functions in expressions in Kompiler programs
26
+ #
27
+
28
+
29
+ module Kompiler
30
+
31
+ module Parsers
32
+
33
+
34
+ module SymAST
35
+
36
+ module Config
37
+
38
+ # Word begin characters are characters from which a word can begin (right now, everything except numbers)
39
+ @word_begin_chars = ("a".."z").to_a + ("A".."Z").to_a + ["_"]
40
+ # Word characters are characters that the word can contain (excluding the first character)
41
+ @word_chars = @word_begin_chars + ("0".."9").to_a
42
+
43
+ # Number begin characters. Same as word_begin_chars but for numbers
44
+ @number_begin_chars = ("0".."9").to_a
45
+ # Number characters. Same as word_chars but for numbers
46
+ @number_chars = ("0".."9").to_a + ["."]
47
+
48
+ # Whitespace characters
49
+ @whitespace_chars = [" ", "\t"]
50
+
51
+ class <<self
52
+ attr_accessor :word_begin_chars, :word_chars, :number_begin_chars, :number_chars, :whitespace_chars
53
+ end
54
+
55
+
56
+
57
+ # Include function operations parsing (e.g., func(x + 2) )
58
+ @parse_functions = true
59
+
60
+ class <<self
61
+ attr_accessor :parse_functions
62
+ end
63
+
64
+
65
+ @sign_types = [
66
+ {name: "open_bracket", chars: ["("]},
67
+ {name: "close_bracket", chars: [")"]},
68
+ {name: "power", chars: ["**"]},
69
+ {name: "div", chars: ["/"]},
70
+ {name: "mul", chars: ["*"]},
71
+ {name: "add", chars: ["+"]},
72
+ {name: "sub", chars: ["-"]},
73
+ {name: "shift_left", chars: ["<<"]},
74
+ {name: "shift_right", chars: [">>"]},
75
+ {name: "or", chars: ["|"]},
76
+ {name: "and", chars: ["&"]},
77
+ {name: "modulo_sign", chars: ["%"]},
78
+ {name: "equal_sign", chars: ["=="]},
79
+ {name: "not_equal_sign", chars: ["!="]},
80
+ {name: "less_or_eq_sign", chars: ["<="]},
81
+ {name: "greater_or_eq_sign", chars: [">="]},
82
+ {name: "less_than_sign", chars: ["<"]},
83
+ {name: "greater_than_sign", chars: [">"]},
84
+
85
+ {name: "exclamation_mark", chars: ["!"]},
86
+ ]
87
+
88
+ # One element operations (e.g., negate operation as "-x" or factorial as "x!"). Elements earlier have higher priority
89
+ # check_direction means whether parsing should start from the left (-1) or from the right (1)
90
+ @one_element_ast_operations = [
91
+ {name: "negate", sign_type: "sub", check_direction: -1},
92
+ {name: "factorial", sign_type: "exclamation_mark", check_direction: 1},
93
+ ]
94
+
95
+ # # Two element operations (e.g., division as "a / b"). Elements earlier have higher priority
96
+ # # check_direction means whether parsing should start from the left (-1) or from the right (1)
97
+ # @two_element_ast_operations = [
98
+ # {name: "power", sign_type: "power", check_direction: -1},
99
+ # {name: "div", sign_type: "div", check_direction: 1},
100
+ # {name: "mul", sign_type: "mul", check_direction: 1},
101
+ # {name: "add", sign_type: "add", check_direction: 1},
102
+ # {name: "sub", sign_type: "sub", check_direction: 1},
103
+ # {name: "bitshift_left", sign_type: "shift_left", check_direction: 1},
104
+ # {name: "bitshift_right", sign_type: "shift_right", check_direction: 1},
105
+ # {name: "bit_or", sign_type: "or", check_direction: 1},
106
+ # {name: "bit_and", sign_type: "and", check_direction: 1},
107
+ # ]
108
+
109
+ # Two element operations (e.g., division as "a / b"). Elements earlier have higher priority
110
+ # check_direction means whether parsing should start from the left (-1) or from the right (1)
111
+ @two_element_ast_operations = [
112
+ {
113
+ group_check_direction: -1,
114
+ group_operations: [
115
+ {name: "power", sign_type: "power"},
116
+ ]
117
+ },
118
+ {
119
+ group_check_direction: 1,
120
+ group_operations: [
121
+ {name: "modulo", sign_type: "modulo_sign"},
122
+ ]
123
+ },
124
+ {
125
+ group_check_direction: 1,
126
+ group_operations: [
127
+ {name: "div", sign_type: "div"},
128
+ {name: "mul", sign_type: "mul"},
129
+ ]
130
+ },
131
+ {
132
+ group_check_direction: 1,
133
+ group_operations: [
134
+ {name: "bitshift_left", sign_type: "shift_left"},
135
+ {name: "bitshift_right", sign_type: "shift_right"},
136
+ {name: "bit_or", sign_type: "or"},
137
+ {name: "bit_and", sign_type: "and"},
138
+ ]
139
+ },
140
+ {
141
+ group_check_direction: 1,
142
+ group_operations: [
143
+ {name: "add", sign_type: "add"},
144
+ {name: "sub", sign_type: "sub"},
145
+ ]
146
+ },
147
+ {
148
+ group_check_direction: 1,
149
+ group_operations: [
150
+ {name: "equal", sign_type: "equal_sign"},
151
+ {name: "not_equal", sign_type: "not_equal_sign"},
152
+ {name: "less_than", sign_type: "less_than_sign"},
153
+ {name: "greater_than", sign_type: "less_than_sign"},
154
+ {name: "less_or_eq", sign_type: "less_or_eq_sign"},
155
+ {name: "greater_or_eq", sign_type: "greater_or_eq_sign"},
156
+ ]
157
+ },
158
+ ]
159
+
160
+
161
+ @functions = {
162
+ "len" => lambda do |arg|
163
+ if !arg.is_a?(String) then raise "Math AST len() error 1" end
164
+ return arg.size
165
+ end,
166
+ "floor" => lambda do |arg|
167
+ if !arg.is_a?(Numeric) then raise "Math AST floor() error 1" end
168
+ return arg.floor
169
+ end
170
+ }
171
+
172
+ class <<self
173
+ attr_accessor :sign_types, :one_element_ast_operations, :two_element_ast_operations, :functions
174
+ end
175
+ end
176
+
177
+
178
+ def self.str_to_tokens str
179
+
180
+ tokens = []
181
+
182
+ char_i = 0
183
+
184
+ # Types of available signs (the first one is prioritized)
185
+ sign_types = Config.sign_types
186
+
187
+
188
+ full_word = ""
189
+
190
+ while char_i < str.size
191
+
192
+
193
+ # Check if the character is a whitespace
194
+ if Config.whitespace_chars.include?(str[char_i])
195
+ char_i += 1 # Move to the next character
196
+ next # Skip
197
+ end
198
+
199
+ cut_str = str[char_i..]
200
+
201
+ # Check if the current position is a math sign
202
+
203
+ sign_found = false
204
+ str_found = false
205
+
206
+ sign_types.each do |sign|
207
+ sign[:chars].each do |seq|
208
+ if cut_str.start_with? seq
209
+ # Here when the sign matched
210
+ tokens << {type: "sign", sign_type: sign[:name], match_seq: seq}
211
+ char_i += seq.size
212
+ sign_found = true
213
+ end
214
+ break if sign_found
215
+ end
216
+ break if sign_found
217
+ end
218
+
219
+
220
+ if !sign_found && Kompiler::Config.string_delimiters.include?(str[char_i])
221
+ str_content, len_parsed = Kompiler::Parsers.parse_str(cut_str)
222
+
223
+
224
+ case str[char_i]
225
+ when '"'
226
+ tokens << {type: "string", str_content: str_content}
227
+ when "'"
228
+ if str_content.size != 1 then raise "Math AST parse error - a character definition cannot be longer than 1" end
229
+ full_str = str[char_i...(char_i + len_parsed)]
230
+ tokens << {type: "number", number_content: full_str}
231
+ end
232
+
233
+ str_found = true
234
+ char_i += len_parsed
235
+ end
236
+
237
+
238
+ if sign_found || str_found
239
+ next if full_word.size == 0
240
+
241
+ is_imm, imm_value = Kompiler::Parsers.check_immediate_operand(full_word)
242
+ if is_imm
243
+ tokens.insert -2, {type: "number", number_content: full_word, number_value: imm_value[:value]}
244
+ full_word = ""
245
+ next
246
+ end
247
+
248
+ if Config.word_begin_chars.include?(full_word[0]) && !(full_word[1..].each_char.map{|c| Config.word_chars.include?(c)}.include?(false))
249
+ tokens.insert -2, {type: "word", word_content: full_word}
250
+ full_word = ""
251
+ next
252
+ end
253
+
254
+ raise "Math AST Error 1"
255
+ else
256
+ full_word << str[char_i]
257
+ char_i += 1
258
+ end
259
+
260
+ next
261
+
262
+
263
+
264
+ next_word = ""
265
+ word_char_i = char_i.dup
266
+
267
+ while word_char_i < str.size && !Config.whitespace_chars.include?(str[word_char_i])
268
+ next_word += str[word_char_i]
269
+ word_char_i += 1
270
+ end
271
+
272
+ is_imm, imm_value = Kompiler::Parsers.check_immediate_operand(next_word)
273
+
274
+ if is_imm
275
+ tokens << {type: "number", number_content: next_word, number_value: imm_value[:value]}
276
+ char_i = word_char_i
277
+ next
278
+ end
279
+
280
+ # if Config.number_begin_chars.include?(str[char_i])
281
+ # full_number = str[char_i]
282
+ # char_i += 1
283
+ #
284
+ # while char_i < str.size && Config.number_chars.include?(str[char_i])
285
+ # full_number << str[char_i]
286
+ # char_i += 1
287
+ # end
288
+ #
289
+ # tokens << {type: "number", number_content: full_number}
290
+ #
291
+ # next
292
+ # end
293
+
294
+
295
+ if Config.word_begin_chars.include?(str[char_i])
296
+ full_word = str[char_i]
297
+ char_i += 1
298
+
299
+ while char_i < str.size && Config.word_chars.include?(str[char_i])
300
+ full_word << str[char_i]
301
+ char_i += 1
302
+ end
303
+
304
+ tokens << {type: "word", word_content: full_word}
305
+
306
+ next
307
+ end
308
+
309
+
310
+ # Here when non of the checks worked
311
+ raise "\"#{str}\" - unrecognized syntax at position #{char_i}"
312
+ end
313
+
314
+ a = 0
315
+ while a != 1
316
+ a = 1
317
+ if full_word.size > 0
318
+ is_imm, imm_value = Kompiler::Parsers.check_immediate_operand(full_word)
319
+ if is_imm
320
+ tokens.insert -1, {type: "number", number_content: full_word, number_value: imm_value[:value]}
321
+ full_word = ""
322
+ next
323
+ end
324
+
325
+ if Config.word_begin_chars.include?(full_word[0]) && !(full_word[1..].each_char.map{|c| Config.word_chars.include?(c)}.include?(false))
326
+ tokens.insert -1, {type: "word", word_content: full_word}
327
+ full_word = ""
328
+ next
329
+ end
330
+
331
+ raise "Math AST Error 2"
332
+ end
333
+ end
334
+
335
+
336
+ tokens
337
+ end
338
+
339
+
340
+ # A recursive function that makes blocks (bracket enclosed) into single tokens
341
+ def self.parse_blocks_from_tokens tokens
342
+
343
+ final_tokens = []
344
+
345
+ token_i = 0
346
+
347
+ while token_i < tokens.size
348
+
349
+ token = tokens[token_i]
350
+
351
+ if !(token[:type] == "sign" && ["open_bracket", "close_bracket"].include?(token[:sign_type]))
352
+ final_tokens << token
353
+ token_i += 1
354
+ next
355
+ end
356
+
357
+ if token[:sign_type] == "close_bracket"
358
+ raise "Parsing error - unexpected close bracket at token #{token_i}"
359
+ end
360
+
361
+ # Set up a bracket count that counts the bracket level (zero means 'absolute' / ground level)
362
+ bracket_count = 1
363
+ block_end_i = token_i + 1
364
+
365
+ while block_end_i < tokens.size && bracket_count != 0
366
+ if tokens[block_end_i][:type] != "sign"
367
+ block_end_i += 1
368
+ next
369
+ end
370
+
371
+ case tokens[block_end_i][:sign_type]
372
+ when "open_bracket"
373
+ bracket_count += 1
374
+ when "close_bracket"
375
+ bracket_count -= 1
376
+ end
377
+
378
+ block_end_i += 1
379
+ end
380
+
381
+ raise "Parsing error - Bracket amount does not match" if bracket_count != 0
382
+
383
+ block_tokens = tokens[(token_i + 1)...(block_end_i - 1)]
384
+
385
+ parsed_block_tokens = parse_blocks_from_tokens(block_tokens)
386
+ parsed_block_tokens = parse_functions_from_tokens(parsed_block_tokens)
387
+
388
+ final_tokens << {type: "block", content: parsed_block_tokens}
389
+
390
+ token_i = block_end_i
391
+ end
392
+
393
+ final_tokens
394
+
395
+ end
396
+
397
+
398
+ def self.parse_functions_from_tokens tokens
399
+
400
+ final_tokens = []
401
+
402
+ token_i = 0
403
+
404
+ while token_i < (tokens.size - 1)
405
+ token = tokens[token_i]
406
+
407
+ if !(token[:type] == "word" && tokens[token_i + 1][:type] == "block")
408
+ token_i += 1
409
+ final_tokens << token
410
+ next
411
+ end
412
+
413
+ final_tokens << {type: "func", func_name: token[:word_content], func_arg_block: tokens[token_i + 1]}
414
+ token_i += 2
415
+ end
416
+
417
+ final_tokens << tokens.last
418
+
419
+ final_tokens
420
+ end
421
+
422
+
423
+ def self.tokens_to_ast tokens
424
+
425
+
426
+ # Swap words and numbers for operations of type word and number
427
+ token_i = 0
428
+
429
+ while token_i < tokens.size
430
+ token = tokens[token_i]
431
+
432
+ if !["word", "number", "block", "string", "func"].include?(token[:type])
433
+ token_i += 1
434
+ next
435
+ end
436
+
437
+ case token[:type]
438
+ when "word"
439
+ tokens[token_i] = {type: "operation", op_type: "word", elements: [token[:word_content]]}
440
+ when "number"
441
+ tokens[token_i] = {type: "operation", op_type: "number", elements: [token[:number_content]]}
442
+ when "string"
443
+ tokens[token_i] = {type: "operation", op_type: "string", elements: [token[:str_content]]}
444
+ when "block"
445
+ tokens[token_i] = tokens_to_ast(token[:content])
446
+ when "func"
447
+ tokens[token_i] = {type: "operation", op_type: "func", elements: [token[:func_name], tokens_to_ast(token[:func_arg_block][:content])]}
448
+ end
449
+
450
+ token_i += 1
451
+ end
452
+
453
+ # Check for negation operations of type "-x"
454
+
455
+ one_element_ast_ops = Config.one_element_ast_operations
456
+
457
+ one_element_ast_ops.each do |operation|
458
+
459
+ if operation[:check_direction] == -1
460
+ token_i = tokens.size - 1
461
+ token_i_change = -1
462
+ check_condition = -> {token_i >= 0}
463
+ check_boundary = 0
464
+ elsif operation[:check_direction] == 1
465
+ token_i = 0
466
+ token_i_change = 1
467
+ check_condition = -> {token_i < tokens.size}
468
+ check_boundary = tokens.size - 1
469
+ end
470
+
471
+ while check_condition.call
472
+ token = tokens[token_i]
473
+
474
+ if token[:type] != "sign"
475
+ token_i += token_i_change
476
+ next
477
+ end
478
+
479
+ if token[:sign_type] != operation[:sign_type]
480
+ token_i += token_i_change
481
+ next
482
+ end
483
+
484
+ # Check if this is the first token (and a minus sign), which means "[-]x"
485
+ # Or check if this token is preceded by another sign, e.g. "+[-]x"
486
+ if token_i == check_boundary || ["sign"].include?(tokens[token_i + token_i_change][:type])
487
+ ast_node = {type: "operation", op_type: operation[:name], elements: [tokens[token_i - token_i_change]]}
488
+ if token_i_change == -1
489
+ tokens = tokens[...token_i] + [ast_node] + tokens[(token_i + 1 + 1)..]
490
+ elsif token_i_change == 1
491
+ tokens = tokens[...(token_i - 1)] + [ast_node] + tokens[(token_i + 1)..]
492
+ end
493
+ check_boundary -= token_i_change
494
+ next
495
+ end
496
+
497
+ token_i += token_i_change
498
+ end
499
+
500
+ end
501
+
502
+
503
+ # Math AST operations sorted in priority order
504
+ two_element_ast_ops = Config.two_element_ast_operations
505
+
506
+ two_element_ast_ops.each do |operations_group|
507
+
508
+ if operations_group[:group_check_direction] == -1
509
+ token_i = tokens.size - 1
510
+ token_i_change = -1
511
+ check_condition = -> {token_i >= 0}
512
+ elsif operations_group[:group_check_direction] == 1
513
+ token_i = 0
514
+ token_i_change = 1
515
+ check_condition = -> {token_i < tokens.size}
516
+ end
517
+
518
+ while check_condition.call
519
+ token = tokens[token_i]
520
+
521
+ if token[:type] != "sign"
522
+ token_i += token_i_change
523
+ next
524
+ end
525
+
526
+ operation_found = false
527
+
528
+ operations_group[:group_operations].each do |operation|
529
+ if token[:sign_type] != operation[:sign_type]
530
+ next
531
+ end
532
+
533
+ elements = [tokens[token_i - 1], tokens[token_i + 1]]
534
+
535
+ # Check if there are some non-operation elements, which shouldn't happen
536
+ raise "Parsing error - something went wrong, compute elements were not operations" if elements.filter{|e| e[:type] != "operation"}.size > 0
537
+
538
+ operation_found = true
539
+
540
+ ast_node = {type: "operation", op_type: operation[:name], elements: }
541
+
542
+ tokens = tokens[...(token_i - 1)] + [ast_node] + tokens[(token_i + 1 + 1)..]
543
+
544
+ # token_i += token_i_change
545
+
546
+ break
547
+ end
548
+
549
+ if !operation_found
550
+ token_i += token_i_change
551
+ next
552
+ end
553
+
554
+ # if token[:sign_type] != operation[:sign_type]
555
+ # token_i += token_i_change
556
+ # next
557
+ # end
558
+ #
559
+ # elements = [tokens[token_i - 1], tokens[token_i + 1]]
560
+ #
561
+ # # Check if there are some non-operation elements, which shouldn't happen
562
+ # raise "Parsing error - something went wrong, compute elements were not operations" if elements.filter{|e| e[:type] != "operation"}.size > 0
563
+ #
564
+ # ast_node = {type: "operation", op_type: operation[:name], elements: }
565
+ #
566
+ # tokens = tokens[...(token_i - 1)] + [ast_node] + tokens[(token_i + 1 + 1)..]
567
+ #
568
+ # token_i += token_i_change
569
+ end
570
+
571
+ end
572
+
573
+
574
+ raise "Parsing error - something went wrong, tokens should've collapsed into a single AST, but didn't :(" if tokens.size != 1
575
+
576
+ tokens[0]
577
+ end
578
+
579
+ def self.token_ast_to_ast(token_ast)
580
+ final_ast = Hash.new
581
+
582
+ final_ast[:type] = token_ast[:op_type]
583
+
584
+ elements = token_ast[:elements]
585
+
586
+ elements.map! do |el|
587
+ if el.is_a?(Hash) && el.keys.include?(:type) && el[:type] == "operation"
588
+ el = token_ast_to_ast(el)
589
+ end
590
+ el
591
+ end
592
+
593
+ final_ast[:elements] = elements
594
+
595
+ final_ast
596
+ end
597
+
598
+
599
+ def self.str_to_ast str
600
+ tokens = str_to_tokens(str)
601
+
602
+ tokens = parse_blocks_from_tokens(tokens)
603
+
604
+ tokens = parse_functions_from_tokens(tokens) if Config.parse_functions
605
+
606
+ token_ast = tokens_to_ast(tokens)
607
+
608
+ ast = token_ast_to_ast(token_ast)
609
+
610
+ ast
611
+ end
612
+
613
+ # Strange looking thing to create an alias for str_to_ast
614
+ class <<self
615
+ alias_method :parse, :str_to_ast
616
+ end
617
+
618
+
619
+ def self.run_ast ast, words=Hash.new, functions=Hash.new
620
+
621
+ # p ast
622
+
623
+ case ast[:type]
624
+ when "word"
625
+ return words[ast[:elements][0]]
626
+ when "number"
627
+ # if ast[:elements][0].include?(".")
628
+ # return ast[:elements][0].to_f
629
+ # else
630
+ # return ast[:elements][0].to_i
631
+ # end
632
+ is_num, imm_value = Kompiler::Parsers.check_immediate_operand(ast[:elements][0])
633
+ raise "AST recognition error - \"#{ast[:elements][0]}\" is not a number" if !is_num
634
+
635
+ return imm_value[:value]
636
+ when "string"
637
+ return ast[:elements][0]
638
+ when "func"
639
+ func_name = ast[:elements][0]
640
+ return Config.functions[func_name].call(run_ast(ast[:elements][1]))
641
+ when "add"
642
+ return run_ast(ast[:elements][0], words, functions) + run_ast(ast[:elements][1], words, functions)
643
+ when "sub"
644
+ return run_ast(ast[:elements][0], words, functions) - run_ast(ast[:elements][1], words, functions)
645
+ when "mul"
646
+ return run_ast(ast[:elements][0], words, functions) * run_ast(ast[:elements][1], words, functions)
647
+ when "div"
648
+ return run_ast(ast[:elements][0], words, functions) / run_ast(ast[:elements][1], words, functions)
649
+ when "power"
650
+ return run_ast(ast[:elements][0], words, functions) ** run_ast(ast[:elements][1], words, functions)
651
+ when "negate"
652
+ return -run_ast(ast[:elements][0], words, functions)
653
+ when "bitshift_left"
654
+ return run_ast(ast[:elements][0], words, functions) << run_ast(ast[:elements][1], words, functions)
655
+ when "bitshift_right"
656
+ return run_ast(ast[:elements][0], words, functions) >> run_ast(ast[:elements][1], words, functions)
657
+ when "bit_or"
658
+ return run_ast(ast[:elements][0], words, functions) | run_ast(ast[:elements][1], words, functions)
659
+ when "bit_and"
660
+ return run_ast(ast[:elements][0], words, functions) & run_ast(ast[:elements][1], words, functions)
661
+ when "factorial"
662
+ res = 1
663
+ lim = run_ast(ast[:elements][0], words, functions)
664
+ (1..lim).each do |n|
665
+ res *= n
666
+ end
667
+ return res
668
+ when "modulo"
669
+ return run_ast(ast[:elements][0], words, functions) % run_ast(ast[:elements][1], words, functions)
670
+
671
+ when "equal"
672
+ return (run_ast(ast[:elements][0], words, functions) == run_ast(ast[:elements][1], words, functions)) ? 1 : 0
673
+ when "not_equal"
674
+ return (run_ast(ast[:elements][0], words, functions) != run_ast(ast[:elements][1], words, functions)) ? 1 : 0
675
+ when "less_than"
676
+ return (run_ast(ast[:elements][0], words, functions) < run_ast(ast[:elements][1], words, functions)) ? 1 : 0
677
+ when "greater_than"
678
+ return (run_ast(ast[:elements][0], words, functions) > run_ast(ast[:elements][1], words, functions)) ? 1 : 0
679
+ when "less_or_eq"
680
+ return (run_ast(ast[:elements][0], words, functions) <= run_ast(ast[:elements][1], words, functions)) ? 1 : 0
681
+ when "greater_or_eq"
682
+ return (run_ast(ast[:elements][0], words, functions) >= run_ast(ast[:elements][1], words, functions)) ? 1 : 0
683
+ end
684
+
685
+
686
+ end
687
+
688
+
689
+ end # Kompiler::Parsers::SymAST
690
+
691
+ end # Kompiler::Parsers
692
+
693
+ end # Kompiler