loxxy 0.0.4 → 0.0.9
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +54 -0
- data/README.md +43 -15
- data/lib/loxxy.rb +1 -0
- data/lib/loxxy/ast/ast_builder.rb +157 -0
- data/lib/loxxy/ast/ast_visitor.rb +125 -0
- data/lib/loxxy/ast/lox_binary_expr.rb +22 -0
- data/lib/loxxy/ast/lox_compound_expr.rb +25 -0
- data/lib/loxxy/ast/lox_literal_expr.rb +25 -0
- data/lib/loxxy/ast/lox_node.rb +22 -0
- data/lib/loxxy/datatype/builtin_datatype.rb +3 -4
- data/lib/loxxy/datatype/false.rb +3 -3
- data/lib/loxxy/datatype/lx_string.rb +4 -9
- data/lib/loxxy/datatype/nil.rb +3 -3
- data/lib/loxxy/datatype/number.rb +2 -10
- data/lib/loxxy/datatype/true.rb +4 -4
- data/lib/loxxy/front_end/grammar.rb +45 -35
- data/lib/loxxy/front_end/literal.rb +1 -1
- data/lib/loxxy/front_end/parser.rb +56 -0
- data/lib/loxxy/front_end/raw_parser.rb +2 -3
- data/lib/loxxy/front_end/scanner.rb +4 -6
- data/lib/loxxy/version.rb +1 -1
- data/loxxy.gemspec +2 -2
- data/spec/datatype/lx_string_spec.rb +35 -35
- data/spec/front_end/parser_spec.rb +275 -0
- data/spec/front_end/raw_parser_spec.rb +6 -7
- data/spec/front_end/scanner_spec.rb +14 -2
- data/spec/loxxy_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -3
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74cd4aa3bd58cad64cad8ac452535052c761f166da883b06b593590310edd97d
|
4
|
+
data.tar.gz: 15af4b4a4c86c7b8e6a14bda16433a9d1663ab581eae78331d29adeed02313d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0dbd9244c36913eed955b1ff92bdc63fd77cc6f7cda3d6b037f3ee87cdcc8d4450673f852426a7395d968711aaf9a3a539efeeaf5e2a0d46865f4f4fa7276c74
|
7
|
+
data.tar.gz: c8c65b58fa53d0cce81a3e7508317dfbeb5d8e10f883a0a011d278ca33ee647967bfd34e79fc4703ad7a5b4a3a88aece8d17ca0d0db107f0ec0fcb9ac12e4280
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
AllCops:
|
2
2
|
Exclude:
|
3
3
|
- 'exp/**/*'
|
4
|
+
- 'demo/**/*'
|
4
5
|
|
5
6
|
Layout/ArgumentAlignment:
|
6
7
|
Enabled: false
|
@@ -55,6 +56,9 @@ Layout/MultilineMethodCallBraceLayout:
|
|
55
56
|
|
56
57
|
Layout/SpaceAroundOperators:
|
57
58
|
Enabled: true
|
59
|
+
|
60
|
+
Layout/SpaceBeforeBrackets:
|
61
|
+
Enabled: true
|
58
62
|
|
59
63
|
Layout/SpaceInsideParens:
|
60
64
|
Enabled: true
|
@@ -70,6 +74,9 @@ Layout/TrailingEmptyLines:
|
|
70
74
|
|
71
75
|
Layout/TrailingWhitespace:
|
72
76
|
Enabled: true
|
77
|
+
|
78
|
+
Lint/AmbiguousAssignment:
|
79
|
+
Enabled: true
|
73
80
|
|
74
81
|
Lint/DuplicateBranch:
|
75
82
|
Enabled: true
|
@@ -163,6 +170,9 @@ Naming/BlockParameterName:
|
|
163
170
|
|
164
171
|
Naming/MethodParameterName:
|
165
172
|
Enabled: false
|
173
|
+
|
174
|
+
Naming/MethodName:
|
175
|
+
Enabled: false
|
166
176
|
|
167
177
|
Naming/VariableName:
|
168
178
|
Enabled: false
|
@@ -226,6 +236,9 @@ Style/GuardClause:
|
|
226
236
|
|
227
237
|
Style/HashEachMethods:
|
228
238
|
Enabled: true
|
239
|
+
|
240
|
+
Style/HashExcept:
|
241
|
+
Enabled: true
|
229
242
|
|
230
243
|
Style/HashTransformKeys:
|
231
244
|
Enabled: true
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,57 @@
|
|
1
|
+
## [0.0.9] - 2021-01-07
|
2
|
+
- AST node generation for comparison expression.
|
3
|
+
|
4
|
+
## Changed
|
5
|
+
- Class `AST::ASTBuilder` added `reduce_` methods for comparison operations.
|
6
|
+
- File `grammar.rb`added name to comparison rules
|
7
|
+
|
8
|
+
## [0.0.8] - 2021-01-07
|
9
|
+
- AST node generation for arithmetic operations of number literals.
|
10
|
+
|
11
|
+
## Changed
|
12
|
+
- Class `AST::ASTBuilder` added `reduce_` methods for arithmetic operations.
|
13
|
+
- File `grammar.rb`added name to arithmetic rules
|
14
|
+
|
15
|
+
## Fixed
|
16
|
+
- File `grammar.rb`: second rule for `factor` had a missing member in rhs.
|
17
|
+
|
18
|
+
## [0.0.7] - 2021-01-06
|
19
|
+
- Lox grammar reworked, initial AST classes created.
|
20
|
+
|
21
|
+
## Added
|
22
|
+
- Class `Parser` this one generates AST's (Abstract Syntax Tree)
|
23
|
+
- Class `AST::ASTVisitor` draft initial implementation.
|
24
|
+
- Class `AST::BinaryExpr` draft initial implementation.
|
25
|
+
- Class `AST::LoxCompoundExpr` draft initial implementation.
|
26
|
+
- Class `AST::LiteralExpr` draft initial implementation.
|
27
|
+
- Class `AST::LoxNode` draft initial implementation.
|
28
|
+
|
29
|
+
## Changed
|
30
|
+
- File `spec_helper.rb`: removed Bundler dependency
|
31
|
+
- Class `AST::ASTBuilder` added initial `reduce_` methods.
|
32
|
+
- File `README.md` Removed example with AST generation since this is in flux.
|
33
|
+
|
34
|
+
## [0.0.6] - 2021-01-03
|
35
|
+
- First iteration of a parser with AST generation.
|
36
|
+
|
37
|
+
## Added
|
38
|
+
- Class `Parser` this one generates AST's (Abstract Syntax Tree)
|
39
|
+
- Class `AST::ASTBuilder` default code to generate an AST.
|
40
|
+
|
41
|
+
## Changed
|
42
|
+
- File `spec_helper.rb`: removed Bundler dependency
|
43
|
+
- File `README.md` Added example with AST visualization.
|
44
|
+
|
45
|
+
## Fixed
|
46
|
+
- File `grammar.rb` ensure that the constant `Grammar` is created once only.
|
47
|
+
|
48
|
+
## [0.0.5] - 2021-01-02
|
49
|
+
- Improved example in `README.md`, code re-styling to please `Rubocop` 1.7
|
50
|
+
|
51
|
+
## Changed
|
52
|
+
- Code re-styling to please `Rubocop` 1.7
|
53
|
+
- File `README.md` Improved example with better parse tree visualization.
|
54
|
+
|
1
55
|
## [0.0.4] - 2021-01-01
|
2
56
|
- A first parser implementation able to parse Lox source code.
|
3
57
|
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Loxxy
|
2
2
|
|
3
|
-
A Ruby implementation of the [Lox programming language](https://craftinginterpreters.com/the-lox-language.html),
|
4
|
-
a simple language used in Bob Nystrom's online book [Crafting Interpreters](https://craftinginterpreters.com/).
|
3
|
+
A Ruby implementation of the [Lox programming language](https://craftinginterpreters.com/the-lox-language.html ),
|
4
|
+
a simple language used in Bob Nystrom's online book [Crafting Interpreters](https://craftinginterpreters.com/ ).
|
5
5
|
|
6
6
|
## Purpose of this project:
|
7
7
|
- To deliver an open source example of a programming language fully implemented in Ruby
|
@@ -9,17 +9,23 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
|
|
9
9
|
- The implementation should be mature enough to run (LoxLox)[https://github.com/benhoyt/loxlox],
|
10
10
|
a Lox interpreter written in Lox.
|
11
11
|
|
12
|
+
## Current status
|
13
|
+
The __loxxy__ gem hosts two distinct parsers classes (`RawParser` and `Parser`).
|
14
|
+
- A `RawParser` instance is able to recognize valid Lox input and to generate
|
15
|
+
a concrete parse tree from it.
|
16
|
+
- A `Parser` instance can also parse Lox source code but will generate an AST
|
17
|
+
(Abstract Syntax Tree) that will be used by the future tree-walking interpreter.
|
18
|
+
Currently it generates AST for arithmetic expressions with literal numbers only.
|
19
|
+
|
12
20
|
## Roadmap
|
13
21
|
- [DONE] Scanner (tokenizer)
|
14
22
|
- [DONE] Raw parser. It parses Lox programs and generates a parse tree.
|
15
|
-
- [
|
23
|
+
- [DONE] Tailored parser for generating AST (Abstract Syntax Tree)
|
24
|
+
- [STARTED] Custom AST builder class
|
25
|
+
- [STARTED] Hierarchy classes for representing Lox expressions in AST
|
16
26
|
- [TODO] Interpreter or transpiler
|
17
27
|
|
18
|
-
|
19
|
-
## Example
|
20
|
-
At this, stage, the raw parser is able to recognize Lox input and to generate
|
21
|
-
a concrete parse tree from it.
|
22
|
-
|
28
|
+
## Example using RawParser class
|
23
29
|
```ruby
|
24
30
|
require 'loxxy'
|
25
31
|
|
@@ -34,13 +40,35 @@ base_parser = Loxxy::FrontEnd::RawParser.new
|
|
34
40
|
# Now parse the input into a concrete parse tree...
|
35
41
|
ptree = base_parser.parse(lox_input)
|
36
42
|
|
37
|
-
#
|
38
|
-
|
43
|
+
# Display the parse tree thanks to Rley formatters...
|
44
|
+
visitor = Rley::ParseTreeVisitor.new(ptree)
|
45
|
+
tree_formatter = Rley::Formatter::Asciitree.new($stdout)
|
46
|
+
tree_formatter.render(visitor)
|
39
47
|
```
|
40
48
|
|
41
|
-
|
42
|
-
|
43
|
-
|
49
|
+
This is the output produced by the above example:
|
50
|
+
```
|
51
|
+
program
|
52
|
+
+-- declaration_plus
|
53
|
+
| +-- declaration
|
54
|
+
| +-- statement
|
55
|
+
| +-- printStmt
|
56
|
+
| +-- PRINT: 'print'
|
57
|
+
| +-- expression
|
58
|
+
| | +-- assignment
|
59
|
+
| | +-- logic_or
|
60
|
+
| | +-- logic_and
|
61
|
+
| | +-- equality
|
62
|
+
| | +-- comparison
|
63
|
+
| | +-- term
|
64
|
+
| | +-- factor
|
65
|
+
| | +-- unary
|
66
|
+
| | +-- call
|
67
|
+
| | +-- primary
|
68
|
+
| | +-- STRING: '"Hello, world!"'
|
69
|
+
| +-- SEMICOLON: ';'
|
70
|
+
+-- EOF: ''
|
71
|
+
```
|
44
72
|
|
45
73
|
## Installation
|
46
74
|
|
@@ -63,9 +91,9 @@ Or install it yourself as:
|
|
63
91
|
TODO: Write usage instructions here
|
64
92
|
|
65
93
|
## Other Lox implementations in Ruby
|
66
|
-
An impressive list of Lox implementations can be found [here](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations
|
94
|
+
An impressive list of Lox implementations can be found [here](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations)
|
67
95
|
|
68
|
-
For Ruby,
|
96
|
+
For Ruby, there is the [lox](https://github.com/rdodson41/ruby-lox) gem.
|
69
97
|
There are other Ruby-based projects as well:
|
70
98
|
- [SlowLox](https://github.com/ArminKleinert/SlowLox), described as a "1-to-1 conversion of JLox to Ruby"
|
71
99
|
- [rulox](https://github.com/LevitatingBusinessMan/rulox)
|
data/lib/loxxy.rb
CHANGED
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../datatype/all_datatypes'
|
4
|
+
require_relative 'lox_literal_expr'
|
5
|
+
require_relative 'lox_binary_expr'
|
6
|
+
|
7
|
+
module Loxxy
|
8
|
+
module Ast
|
9
|
+
# The purpose of ASTBuilder is to build piece by piece an AST
|
10
|
+
# (Abstract Syntax Tree) from a sequence of input tokens and
|
11
|
+
# visit events produced by walking over a GFGParsing object.
|
12
|
+
class ASTBuilder < Rley::ParseRep::ASTBaseBuilder
|
13
|
+
# Terminal2NodeClass = {
|
14
|
+
# 'FALSE' => Datatype::False,
|
15
|
+
# 'NIL' => Datatype::Nil,
|
16
|
+
# 'NUMBER' => Datatype::Number,
|
17
|
+
# 'STRING' => Datatype::LXString,
|
18
|
+
# 'TRUE' => Datatype::True
|
19
|
+
# }.freeze
|
20
|
+
|
21
|
+
attr_reader :strict
|
22
|
+
|
23
|
+
# Create a new AST builder instance.
|
24
|
+
# @param theTokens [Array<Rley::Lexical::Token>] The sequence of input tokens.
|
25
|
+
def initialize(theTokens)
|
26
|
+
super(theTokens)
|
27
|
+
@strict = false
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def terminal2node
|
33
|
+
Terminal2NodeClass
|
34
|
+
end
|
35
|
+
|
36
|
+
# Method override
|
37
|
+
def new_leaf_node(_production, _terminal, aTokenPosition, aToken)
|
38
|
+
Rley::PTree::TerminalNode.new(aToken, aTokenPosition)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Factory method for creating a parent node object.
|
42
|
+
# @param aProduction [Production] Production rule
|
43
|
+
# @param aRange [Range] Range of tokens matched by the rule
|
44
|
+
# @param theTokens [Array] The input tokens
|
45
|
+
# @param theChildren [Array] Children nodes (one per rhs symbol)
|
46
|
+
def new_parent_node(aProduction, aRange, theTokens, theChildren)
|
47
|
+
mth_name = method_name(aProduction.name)
|
48
|
+
if respond_to?(mth_name, true)
|
49
|
+
node = send(mth_name, aProduction, aRange, theTokens, theChildren)
|
50
|
+
else
|
51
|
+
# Default action...
|
52
|
+
node = case aProduction.rhs.size
|
53
|
+
when 0
|
54
|
+
return_epsilon(aRange, theTokens, theChildren)
|
55
|
+
when 1
|
56
|
+
return_first_child(aRange, theTokens, theChildren)
|
57
|
+
else
|
58
|
+
if strict
|
59
|
+
msg = "Don't know production '#{aProduction.name}'"
|
60
|
+
raise StandardError, msg
|
61
|
+
else
|
62
|
+
node = Rley::PTree::NonTerminalNode.new(aProduction.lhs, aRange)
|
63
|
+
theChildren&.reverse_each do |child|
|
64
|
+
node.add_subnode(child) if child
|
65
|
+
end
|
66
|
+
|
67
|
+
node
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
node
|
73
|
+
end
|
74
|
+
|
75
|
+
# rule('lhs' => 'nonterm_i nonterm_k_plus')
|
76
|
+
def reduce_binary_operator(_production, _range, tokens, theChildren)
|
77
|
+
operand1 = theChildren[0]
|
78
|
+
|
79
|
+
# Second child is anray with couples [operator, operand2]
|
80
|
+
theChildren[1].each do |(operator, operand2)|
|
81
|
+
operand1 = LoxBinaryExpr.new(tokens[0].position, operator, operand1, operand2)
|
82
|
+
end
|
83
|
+
|
84
|
+
operand1
|
85
|
+
end
|
86
|
+
|
87
|
+
# rule('comparison' => 'term comparisonTest_plus')
|
88
|
+
def reduce_comparison_plus(production, range, tokens, theChildren)
|
89
|
+
reduce_binary_operator(production, range, tokens, theChildren)
|
90
|
+
end
|
91
|
+
|
92
|
+
# rule('comparisonTest_plus' => 'comparisonTest_plus comparisonTest term').as 'comparison_t_plus_more'
|
93
|
+
# TODO: is it meaningful to implement this rule?
|
94
|
+
|
95
|
+
# rule('comparisonTest_plus' => 'comparisonTest term')
|
96
|
+
def reduce_comparison_t_plus_end(_production, _range, _tokens, theChildren)
|
97
|
+
name2operators = {
|
98
|
+
'GREATER' => '>',
|
99
|
+
'GREATER_EQUAL' => '>=',
|
100
|
+
'LESS' => '<',
|
101
|
+
'LESS_EQUAL' => '<='
|
102
|
+
}
|
103
|
+
operator = name2operators[theChildren[0].symbol.name].to_sym
|
104
|
+
operand2 = theChildren[1]
|
105
|
+
[[operator, operand2]]
|
106
|
+
end
|
107
|
+
|
108
|
+
# rule('term' => 'factor additive_plus')
|
109
|
+
def reduce_term_additive(production, range, tokens, theChildren)
|
110
|
+
reduce_binary_operator(production, range, tokens, theChildren)
|
111
|
+
end
|
112
|
+
|
113
|
+
# rule('additive_star' => 'additive_star additionOp factor').as 'additionOp_expr'
|
114
|
+
def reduce_additive_plus_more(_production, _range, _tokens, theChildren)
|
115
|
+
result = theChildren[0]
|
116
|
+
operator = theChildren[1].symbol.name == 'MINUS' ? :- : :+
|
117
|
+
operand2 = theChildren[2]
|
118
|
+
result << [operator, operand2]
|
119
|
+
end
|
120
|
+
|
121
|
+
# rule('additive_plus' => 'additionOp factor')
|
122
|
+
def reduce_additive_plus_end(_production, _range, _tokens, theChildren)
|
123
|
+
operator = theChildren[0].symbol.name == 'MINUS' ? :- : :+
|
124
|
+
operand2 = theChildren[1]
|
125
|
+
[[operator, operand2]]
|
126
|
+
end
|
127
|
+
|
128
|
+
# rule('factor' => 'multiplicative_plus')
|
129
|
+
def reduce_factor_multiplicative(production, range, tokens, theChildren)
|
130
|
+
reduce_binary_operator(production, range, tokens, theChildren)
|
131
|
+
end
|
132
|
+
|
133
|
+
# rule('multiplicative_plus' => 'multiplicative_plus multOp unary')
|
134
|
+
def reduce_multiplicative_plus_more(_production, _range, _tokens, theChildren)
|
135
|
+
result = theChildren[0]
|
136
|
+
operator = theChildren[1].symbol.name == 'SLASH' ? :/ : :*
|
137
|
+
operand2 = theChildren[2]
|
138
|
+
result << [operator, operand2]
|
139
|
+
end
|
140
|
+
|
141
|
+
# rule('multiplicative_plus' => 'multOp unary')
|
142
|
+
def reduce_multiplicative_plus_end(_production, _range, _tokens, theChildren)
|
143
|
+
operator = theChildren[0].symbol.name == 'SLASH' ? :/ : :*
|
144
|
+
operand2 = theChildren[1]
|
145
|
+
[[operator, operand2]]
|
146
|
+
end
|
147
|
+
|
148
|
+
# rule('primary' => 'FALSE' | TRUE').as 'literal_expr'
|
149
|
+
def reduce_literal_expr(_production, _range, _tokens, theChildren)
|
150
|
+
first_child = theChildren.first
|
151
|
+
pos = first_child.token.position
|
152
|
+
literal = first_child.token.value
|
153
|
+
LoxLiteralExpr.new(pos, literal)
|
154
|
+
end
|
155
|
+
end # class
|
156
|
+
end # module
|
157
|
+
end # module
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Loxxy
|
4
|
+
module Ast
|
5
|
+
class ASTVisitor
|
6
|
+
# Link to the top node to visit
|
7
|
+
attr_reader(:top)
|
8
|
+
|
9
|
+
# List of objects that subscribed to the visit event notification.
|
10
|
+
attr_reader(:subscribers)
|
11
|
+
|
12
|
+
# attr_reader(:runtime)
|
13
|
+
|
14
|
+
# Build a visitor for the given top.
|
15
|
+
# @param aRoot [AST::LoxNode] the parse tree to visit.
|
16
|
+
def initialize(aTop)
|
17
|
+
raise StandardError if aTop.nil?
|
18
|
+
|
19
|
+
@top = aTop
|
20
|
+
@subscribers = []
|
21
|
+
end
|
22
|
+
|
23
|
+
# Add a subscriber for the visit event notifications.
|
24
|
+
# @param aSubscriber [Object]
|
25
|
+
def subscribe(aSubscriber)
|
26
|
+
subscribers << aSubscriber
|
27
|
+
end
|
28
|
+
|
29
|
+
# Remove the given object from the subscription list.
|
30
|
+
# The object won't be notified of visit events.
|
31
|
+
# @param aSubscriber [Object]
|
32
|
+
def unsubscribe(aSubscriber)
|
33
|
+
subscribers.delete_if { |entry| entry == aSubscriber }
|
34
|
+
end
|
35
|
+
|
36
|
+
# The signal to begin the visit of the top.
|
37
|
+
def start # (aRuntime)
|
38
|
+
# @runtime = aRuntime
|
39
|
+
top.accept(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Visit event. The visitor is visiting the
|
43
|
+
# given terminal node containing a datatype object.
|
44
|
+
# @param aLiteralExpr [AST::LoxLiteralExpr] the leaf node to visit.
|
45
|
+
def visit_literal_expr(aLiteralExpr)
|
46
|
+
broadcast(:before_literal_expr, aLiteralExpr)
|
47
|
+
broadcast(:after_literal_expr, aLiteralExpr)
|
48
|
+
end
|
49
|
+
|
50
|
+
=begin
|
51
|
+
|
52
|
+
|
53
|
+
def visit_compound_datum(aCompoundDatum)
|
54
|
+
broadcast(:before_compound_datum, aCompoundDatum)
|
55
|
+
traverse_children(aCompoundDatum)
|
56
|
+
broadcast(:after_compound_datum, aCompoundDatum)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Visit event. The visitor is visiting the
|
60
|
+
# given empty list object.
|
61
|
+
# @param anEmptyList [SkmEmptyList] the empty list object to visit.
|
62
|
+
def visit_empty_list(anEmptyList)
|
63
|
+
broadcast(:before_empty_list, anEmptyList)
|
64
|
+
broadcast(:after_empty_list, anEmptyList)
|
65
|
+
end
|
66
|
+
|
67
|
+
def visit_pair(aPair)
|
68
|
+
broadcast(:before_pair, aPair)
|
69
|
+
traverse_car_cdr(aPair)
|
70
|
+
broadcast(:after_pair, aPair)
|
71
|
+
end
|
72
|
+
=end
|
73
|
+
=begin
|
74
|
+
# Visit event. The visitor is about to visit the given non terminal node.
|
75
|
+
# @param aNonTerminalNode [NonTerminalNode] the node to visit.
|
76
|
+
def visit_nonterminal(aNonTerminalNode)
|
77
|
+
if @traversal == :post_order
|
78
|
+
broadcast(:before_non_terminal, aNonTerminalNode)
|
79
|
+
traverse_subnodes(aNonTerminalNode)
|
80
|
+
else
|
81
|
+
traverse_subnodes(aNonTerminalNode)
|
82
|
+
broadcast(:before_non_terminal, aNonTerminalNode)
|
83
|
+
end
|
84
|
+
broadcast(:after_non_terminal, aNonTerminalNode)
|
85
|
+
end
|
86
|
+
=end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def traverse_children(aParent)
|
91
|
+
children = aParent.children
|
92
|
+
broadcast(:before_children, aParent, children)
|
93
|
+
|
94
|
+
# Let's proceed with the visit of children
|
95
|
+
children.each { |a_child| a_child.accept(self) }
|
96
|
+
|
97
|
+
broadcast(:after_children, aParent, children)
|
98
|
+
end
|
99
|
+
|
100
|
+
def traverse_car_cdr(aPair)
|
101
|
+
if aPair.car
|
102
|
+
broadcast(:before_car, aPair, aPair.car)
|
103
|
+
aPair.car.accept(self)
|
104
|
+
broadcast(:after_car, aPair, aPair.car)
|
105
|
+
end
|
106
|
+
if aPair.cdr
|
107
|
+
broadcast(:before_cdr, aPair, aPair.cdr)
|
108
|
+
aPair.cdr.accept(self)
|
109
|
+
broadcast(:after_cdr, aPair, aPair.cdr)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Send a notification to all subscribers.
|
114
|
+
# @param msg [Symbol] event to notify
|
115
|
+
# @param args [Array] arguments of the notification.
|
116
|
+
def broadcast(msg, *args)
|
117
|
+
subscribers.each do |subscr|
|
118
|
+
next unless subscr.respond_to?(msg) || subscr.respond_to?(:accept_all)
|
119
|
+
|
120
|
+
subscr.send(msg, runtime, *args)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end # class
|
124
|
+
end # module
|
125
|
+
end # module
|