loxxy 0.2.02 → 0.3.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +59 -0
- data/README.md +19 -2
- data/lib/loxxy/ast/all_lox_nodes.rb +0 -1
- data/lib/loxxy/ast/ast_builder.rb +27 -4
- data/lib/loxxy/ast/ast_visitee.rb +53 -0
- data/lib/loxxy/ast/ast_visitor.rb +2 -10
- data/lib/loxxy/ast/lox_assign_expr.rb +1 -5
- data/lib/loxxy/ast/lox_binary_expr.rb +1 -6
- data/lib/loxxy/ast/lox_block_stmt.rb +1 -5
- data/lib/loxxy/ast/lox_call_expr.rb +1 -5
- data/lib/loxxy/ast/lox_class_stmt.rb +1 -5
- data/lib/loxxy/ast/lox_fun_stmt.rb +1 -5
- data/lib/loxxy/ast/lox_get_expr.rb +1 -6
- data/lib/loxxy/ast/lox_grouping_expr.rb +1 -5
- data/lib/loxxy/ast/lox_if_stmt.rb +2 -6
- data/lib/loxxy/ast/lox_literal_expr.rb +1 -5
- data/lib/loxxy/ast/lox_logical_expr.rb +1 -6
- data/lib/loxxy/ast/lox_node.rb +9 -1
- data/lib/loxxy/ast/lox_print_stmt.rb +1 -5
- data/lib/loxxy/ast/lox_return_stmt.rb +1 -5
- data/lib/loxxy/ast/lox_seq_decl.rb +1 -5
- data/lib/loxxy/ast/lox_set_expr.rb +1 -5
- data/lib/loxxy/ast/lox_super_expr.rb +2 -6
- data/lib/loxxy/ast/lox_this_expr.rb +1 -5
- data/lib/loxxy/ast/lox_unary_expr.rb +1 -6
- data/lib/loxxy/ast/lox_var_stmt.rb +1 -5
- data/lib/loxxy/ast/lox_variable_expr.rb +1 -5
- data/lib/loxxy/ast/lox_while_stmt.rb +2 -6
- data/lib/loxxy/back_end/engine.rb +28 -26
- data/lib/loxxy/back_end/lox_instance.rb +1 -1
- data/lib/loxxy/back_end/resolver.rb +17 -21
- data/lib/loxxy/datatype/number.rb +19 -4
- data/lib/loxxy/front_end/parser.rb +1 -1
- data/lib/loxxy/front_end/scanner.rb +11 -10
- data/lib/loxxy/version.rb +1 -1
- data/spec/back_end/environment_spec.rb +0 -14
- data/spec/back_end/symbol_table_spec.rb +0 -19
- data/spec/back_end/variable_spec.rb +0 -35
- data/spec/front_end/scanner_spec.rb +35 -7
- data/spec/interpreter_spec.rb +36 -0
- metadata +3 -3
- data/lib/loxxy/ast/lox_for_stmt.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 231fc227cc66ebd0b4f47a00f9fe7260146d70e64cea3581df6cfc5c71937bef
|
4
|
+
data.tar.gz: cd8117dc8ae9b631ad0d7bef34ee972bdcaa8c758045637bae2f3ea0ed25bb79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca714bbd5fa4fcbae67548cdae0d8c43236b02f30adc45e939c0e1dcd3e6694471ea429f902d5e1a7335d4a4cf9779d167a9387b0f4f0732325bd31237630e8d
|
7
|
+
data.tar.gz: '008526b6d9a2e9f5cf27a68f796e53aa5312d67523a53d8c8682cf944ee6cd990adf3928a3af7fb66e056bca4fc6e45fc11119ffcab1dda4d41fb2ca1c1207be'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,62 @@
|
|
1
|
+
## [0.3.00] - 2021-05-07
|
2
|
+
- Milestone: `Loxxy` passes all reference test suite.
|
3
|
+
|
4
|
+
### Fixed
|
5
|
+
- Method `BackEdn::Resolver#before_variable_expr`: Standard `Lox` allows re-declaration of a variable at top-level scope
|
6
|
+
|
7
|
+
|
8
|
+
## [0.2.06] - 2021-05-04
|
9
|
+
- Nearly passing the 'official' test suite, fixing non-compliant behavior, specialized exceptions for errors
|
10
|
+
|
11
|
+
### New
|
12
|
+
- Module `LoxFileTester` module that hosts methods that simplify the tests of `Lox` source file.
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
- Folder `test_suite` vastly reorganized. Sub-folder `baseline` contains spec files testing the `Lox` files from official implementation
|
16
|
+
- Class `BackEnd::Engine` replaced most `StandardError` by `Loxxy::RuntimeError` exception.
|
17
|
+
- Class `BackEnd::Resolver` replaced most `StandardError` by `Loxxy::RuntimeError` exception.
|
18
|
+
- Method `Datatype::Number#/` now handles correctly expression like `0/0` (integer divide)
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
- `0/0` expression results in a ZeroDivisionError exception, in Lox this result to a NaN (Not a Number). Now, `Loxxy` is aligned to standard `Lox`
|
22
|
+
- `FrontEnd::Scanner` now always treats expression like `-123` as the unary or binary minus operator applied to a positive number.
|
23
|
+
|
24
|
+
## [0.2.05] - 2021-04-26
|
25
|
+
- `Loxxy` now transforms for loops into while loops (desugaring), fix in Scanner class
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
- Method `Ast::ASTBuilder#reduce_for_stmt` converts 'for' loops into 'while' loops
|
29
|
+
- Method `Ast::ASTBuilder#reduce_for_control takes care of case for(expr1;;expr2) now test expression is set to true
|
30
|
+
|
31
|
+
### Fixed
|
32
|
+
- Method `FrontEnd::Scanner#next_token` keyword recognition was case insensitive
|
33
|
+
|
34
|
+
### Removed
|
35
|
+
- Method `Ast::Visitor#visitor_for_stmt`
|
36
|
+
- Method `BackEnd::Engine#after_for_stmt`
|
37
|
+
- Method `BackEnd::Resolver#before_for_stmt`
|
38
|
+
- Method `BackEnd::Resolver#after_for_stmt`
|
39
|
+
|
40
|
+
|
41
|
+
## [0.2.04] - 2021-04-25
|
42
|
+
- `Loxxy` passes the test suite for `for` statements
|
43
|
+
|
44
|
+
### Fixed
|
45
|
+
- Method `BackEnd::Engine#after_for_stmt` now a for(;;) executes the body once; a for without test will execute forever
|
46
|
+
- Method `BackEnd::Resolver#after_for_stmt now accepts nil test expression
|
47
|
+
|
48
|
+
## [0.2.03] - 2021-04-24
|
49
|
+
- Fixes for the set (field) expressions, `accept` methods for AST nodes are meta-programmed
|
50
|
+
|
51
|
+
### New
|
52
|
+
- Module `Ast::Visitee` provides the `define_accept` method that generate `accept` method with meta-programming
|
53
|
+
|
54
|
+
### Fixed
|
55
|
+
- Method `BackEnd::Engine#before_set_expr` methos method that ensure that the receiver is evaluated first, then the assigned value
|
56
|
+
- Method `BackEnd::Engine#after_set_expr` now pushes the value assigned to the field also onto the stack
|
57
|
+
- Class `BackEnd::Engine` a number of StnadardError exceptions are replaced by Loxxy::RuntimeError
|
58
|
+
|
59
|
+
|
1
60
|
## [0.2.02] - 2021-04-21
|
2
61
|
- Improvements in the scanner class (escape sequence for quotes and newlines), error messages closer to jlox.
|
3
62
|
|
data/README.md
CHANGED
@@ -19,20 +19,37 @@ Although __Lox__ is fairly simple, it is far from being a toy language:
|
|
19
19
|
### Loxxy gem features
|
20
20
|
- Complete tree-walking interpreter including lexer, parser and resolver
|
21
21
|
- 100% pure Ruby with clean design (not a port from some other language)
|
22
|
+
- Passes the `jox` (THE reference `Lox` implementation) test suite
|
22
23
|
- Minimal runtime dependency (Rley gem). Won't drag a bunch of gems...
|
23
24
|
- Ruby API for integrating a Lox interpreter with your code.
|
24
25
|
- A command-line interpreter `loxxy`
|
25
|
-
- Open for your language extensions
|
26
|
+
- Open for your language extensions...
|
27
|
+
|
28
|
+
### Why `Loxxy` ?
|
29
|
+
- If programming languages are one of your subject interest...
|
30
|
+
- ... and you wanted learn how to implement one in Ruby...
|
31
|
+
- ... then `Loxxy` can help to understand and experiment in this rewarding craft.
|
26
32
|
|
27
33
|
## How to start in 1, 2, 3...?
|
28
34
|
... in less than 3 minutes...
|
29
35
|
|
30
36
|
### 1. Installing
|
31
|
-
|
37
|
+
__Loxxy__'s installation is pretty standard:
|
32
38
|
|
33
39
|
|
34
40
|
$ gem install loxxy
|
35
41
|
|
42
|
+
Alternatively, you can install `loxxy` with Bundler.
|
43
|
+
Add this line to your application's Gemfile:
|
44
|
+
|
45
|
+
gem 'loxxy'
|
46
|
+
|
47
|
+
And then execute:
|
48
|
+
|
49
|
+
$ bundle
|
50
|
+
|
51
|
+
|
52
|
+
|
36
53
|
### 2. Your first `Lox` program
|
37
54
|
Create a text file and enter the following lines:
|
38
55
|
```javascript
|
@@ -19,7 +19,6 @@ require_relative 'lox_while_stmt'
|
|
19
19
|
require_relative 'lox_return_stmt'
|
20
20
|
require_relative 'lox_print_stmt'
|
21
21
|
require_relative 'lox_if_stmt'
|
22
|
-
require_relative 'lox_for_stmt'
|
23
22
|
require_relative 'lox_var_stmt'
|
24
23
|
require_relative 'lox_class_stmt'
|
25
24
|
require_relative 'lox_seq_decl'
|
@@ -225,16 +225,39 @@ module Loxxy
|
|
225
225
|
end
|
226
226
|
|
227
227
|
# rule('forStmt' => 'FOR LEFT_PAREN forControl RIGHT_PAREN statement')
|
228
|
-
def reduce_for_stmt(_production, _range,
|
229
|
-
|
230
|
-
|
228
|
+
def reduce_for_stmt(_production, _range, tokens, theChildren)
|
229
|
+
# Following 'Crafting Interpreters', we replace the for statement by a while loop
|
230
|
+
return theChildren[4] if theChildren[2].compact.empty? # for(;;) => execute body once
|
231
|
+
|
232
|
+
(init, test, update) = theChildren[2]
|
233
|
+
if update
|
234
|
+
new_body = LoxSeqDecl.new(tokens[0].position, [theChildren[4], update])
|
235
|
+
stmt = Ast::LoxBlockStmt.new(tokens[1].position, new_body)
|
236
|
+
else
|
237
|
+
stmt = theChildren[4]
|
238
|
+
end
|
239
|
+
while_stmt = Ast::LoxWhileStmt.new(tokens[0].position, test, stmt)
|
240
|
+
|
241
|
+
if init
|
242
|
+
block_body = LoxSeqDecl.new(tokens[0].position, [init, while_stmt])
|
243
|
+
for_stmt = Ast::LoxBlockStmt.new(tokens[1].position, block_body)
|
244
|
+
else
|
245
|
+
for_stmt = while_stmt
|
246
|
+
end
|
247
|
+
|
231
248
|
for_stmt
|
232
249
|
end
|
233
250
|
|
234
251
|
# rule('forControl' => 'forInitialization forTest forUpdate')
|
235
252
|
def reduce_for_control(_production, _range, tokens, theChildren)
|
236
253
|
(init, test, update) = theChildren
|
237
|
-
|
254
|
+
if test.nil? && update
|
255
|
+
# when test expr is nil but update expr is not, then force test to be true
|
256
|
+
test = LoxLiteralExpr.new(tokens[0].position, Datatype::True.instance)
|
257
|
+
[init, test, update]
|
258
|
+
else
|
259
|
+
theChildren
|
260
|
+
end
|
238
261
|
end
|
239
262
|
|
240
263
|
# rule('forInitialization' => 'SEMICOLON')
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Loxxy
|
4
|
+
module Ast
|
5
|
+
# Mix-in module that relies on meta-programming to add a method
|
6
|
+
# called `accept` to the host class (an AST node).
|
7
|
+
# That method fulfills the expected behavior of the `visitee` in
|
8
|
+
# the Visitor design pattern.
|
9
|
+
module ASTVisitee
|
10
|
+
# Convert the input string into a snake case string.
|
11
|
+
# Example: ClassExpr => class_expr
|
12
|
+
# @param aName [String] input name to convert
|
13
|
+
# @return [String] the name converted into snake case
|
14
|
+
def snake_case(aName)
|
15
|
+
converted = +''
|
16
|
+
down = false
|
17
|
+
aName.each_char do |ch|
|
18
|
+
lower = ch.downcase
|
19
|
+
if lower == ch
|
20
|
+
converted << ch
|
21
|
+
down = true
|
22
|
+
else
|
23
|
+
converted << '_' if down && converted[-1] != '_'
|
24
|
+
converted << lower
|
25
|
+
down = false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
converted
|
30
|
+
end
|
31
|
+
|
32
|
+
# This method adds a method named `accept` that takes a visitor
|
33
|
+
# The visitor is expected to implement a method named:
|
34
|
+
# visit + class name (without the Lox prefix) in snake case
|
35
|
+
# Example: class name = LoxClassStmt => visit method = visit_class_stmt
|
36
|
+
def define_accept
|
37
|
+
return if instance_methods(false).include?(:accept)
|
38
|
+
|
39
|
+
base_name = name.split('::').last
|
40
|
+
name_suffix = snake_case(base_name).sub(/^lox/, '')
|
41
|
+
accept_body = <<-MTH_END
|
42
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
43
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
44
|
+
def accept(aVisitor)
|
45
|
+
aVisitor.visit#{name_suffix}(self)
|
46
|
+
end
|
47
|
+
MTH_END
|
48
|
+
|
49
|
+
class_eval(accept_body)
|
50
|
+
end
|
51
|
+
end # module
|
52
|
+
end # module
|
53
|
+
end # module
|
@@ -75,14 +75,6 @@ module Loxxy
|
|
75
75
|
broadcast(:after_class_stmt, aClassStmt, self)
|
76
76
|
end
|
77
77
|
|
78
|
-
# Visit event. The visitor is about to visit a for statement.
|
79
|
-
# @param aForStmt [AST::LOXForStmt] the for statement node to visit
|
80
|
-
def visit_for_stmt(aForStmt)
|
81
|
-
broadcast(:before_for_stmt, aForStmt)
|
82
|
-
traverse_subnodes(aForStmt) # The condition is visited/evaluated here...
|
83
|
-
broadcast(:after_for_stmt, aForStmt, self)
|
84
|
-
end
|
85
|
-
|
86
78
|
# Visit event. The visitor is about to visit a if statement.
|
87
79
|
# @param anIfStmt [AST::LOXIfStmt] the if statement node to visit
|
88
80
|
def visit_if_stmt(anIfStmt)
|
@@ -111,7 +103,7 @@ module Loxxy
|
|
111
103
|
# @param aWhileStmt [AST::LOXWhileStmt] the while statement node to visit
|
112
104
|
def visit_while_stmt(aWhileStmt)
|
113
105
|
broadcast(:before_while_stmt, aWhileStmt)
|
114
|
-
traverse_subnodes(aWhileStmt) # The condition is visited/evaluated here...
|
106
|
+
traverse_subnodes(aWhileStmt) if aWhileStmt.condition # The condition is visited/evaluated here...
|
115
107
|
broadcast(:after_while_stmt, aWhileStmt, self)
|
116
108
|
end
|
117
109
|
|
@@ -133,7 +125,7 @@ module Loxxy
|
|
133
125
|
|
134
126
|
# @param aSetExpr [AST::LOXGetExpr] the get expression node to visit
|
135
127
|
def visit_set_expr(aSetExpr)
|
136
|
-
broadcast(:before_set_expr, aSetExpr)
|
128
|
+
broadcast(:before_set_expr, aSetExpr, self)
|
137
129
|
traverse_subnodes(aSetExpr)
|
138
130
|
broadcast(:after_set_expr, aSetExpr, self)
|
139
131
|
end
|
@@ -17,11 +17,7 @@ module Loxxy
|
|
17
17
|
@name = aName
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
21
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
22
|
-
def accept(visitor)
|
23
|
-
visitor.visit_assign_expr(self)
|
24
|
-
end
|
20
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
25
21
|
end # class
|
26
22
|
end # module
|
27
23
|
end # module
|
@@ -16,12 +16,7 @@ module Loxxy
|
|
16
16
|
@operator = anOperator
|
17
17
|
end
|
18
18
|
|
19
|
-
#
|
20
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
21
|
-
def accept(visitor)
|
22
|
-
visitor.visit_binary_expr(self)
|
23
|
-
end
|
24
|
-
|
19
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
25
20
|
alias operands subnodes
|
26
21
|
end # class
|
27
22
|
end # module
|
@@ -15,11 +15,7 @@ module Loxxy
|
|
15
15
|
subnodes.size == 1 && subnodes[0].nil?
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
20
|
-
def accept(visitor)
|
21
|
-
visitor.visit_block_stmt(self)
|
22
|
-
end
|
18
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
23
19
|
end # class
|
24
20
|
end # module
|
25
21
|
end # module
|
@@ -15,11 +15,7 @@ module Loxxy
|
|
15
15
|
@arguments = argList
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
20
|
-
def accept(visitor)
|
21
|
-
visitor.visit_call_expr(self)
|
22
|
-
end
|
18
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
23
19
|
end # class
|
24
20
|
end # module
|
25
21
|
end # module
|
@@ -24,11 +24,7 @@ module Loxxy
|
|
24
24
|
@body = theMethods
|
25
25
|
end
|
26
26
|
|
27
|
-
#
|
28
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
29
|
-
def accept(visitor)
|
30
|
-
visitor.visit_class_stmt(self)
|
31
|
-
end
|
27
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
32
28
|
end # class
|
33
29
|
end # module
|
34
30
|
end # module
|
@@ -23,11 +23,7 @@ module Loxxy
|
|
23
23
|
@is_method = false
|
24
24
|
end
|
25
25
|
|
26
|
-
#
|
27
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
28
|
-
def accept(visitor)
|
29
|
-
visitor.visit_fun_stmt(self)
|
30
|
-
end
|
26
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
31
27
|
end # class
|
32
28
|
# rubocop: enable Style/AccessorGrouping
|
33
29
|
end # module
|
@@ -18,12 +18,7 @@ module Loxxy
|
|
18
18
|
@property = aPropertyName
|
19
19
|
end
|
20
20
|
|
21
|
-
#
|
22
|
-
# @param visitor [ASTVisitor] the visitor
|
23
|
-
def accept(visitor)
|
24
|
-
visitor.visit_get_expr(self)
|
25
|
-
end
|
26
|
-
|
21
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
27
22
|
alias callee= object=
|
28
23
|
end # class
|
29
24
|
end # module
|
@@ -11,11 +11,7 @@ module Loxxy
|
|
11
11
|
super(aPosition, [subExpr])
|
12
12
|
end
|
13
13
|
|
14
|
-
#
|
15
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
16
|
-
def accept(visitor)
|
17
|
-
visitor.visit_grouping_expr(self)
|
18
|
-
end
|
14
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
19
15
|
end # class
|
20
16
|
end # module
|
21
17
|
end # module
|
@@ -21,17 +21,13 @@ module Loxxy
|
|
21
21
|
@else_stmt = elseStmt
|
22
22
|
end
|
23
23
|
|
24
|
-
# Part of the 'visitee' role in Visitor design pattern.
|
25
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
26
|
-
def accept(visitor)
|
27
|
-
visitor.visit_if_stmt(self)
|
28
|
-
end
|
29
|
-
|
30
24
|
# Accessor to the condition expression
|
31
25
|
# @return [LoxNode]
|
32
26
|
def condition
|
33
27
|
subnodes[0]
|
34
28
|
end
|
29
|
+
|
30
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
35
31
|
end # class
|
36
32
|
end # module
|
37
33
|
end # module
|
@@ -15,11 +15,7 @@ module Loxxy
|
|
15
15
|
@literal = aLiteral
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
# @param visitor [ASTVisitor] the visitor
|
20
|
-
def accept(visitor)
|
21
|
-
visitor.visit_literal_expr(self)
|
22
|
-
end
|
18
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
23
19
|
end # class
|
24
20
|
end # module
|
25
21
|
end # module
|
@@ -16,12 +16,7 @@ module Loxxy
|
|
16
16
|
@operator = anOperator
|
17
17
|
end
|
18
18
|
|
19
|
-
#
|
20
|
-
# @param visitor [Ast::ASTVisitor] the visitor
|
21
|
-
def accept(visitor)
|
22
|
-
visitor.visit_logical_expr(self)
|
23
|
-
end
|
24
|
-
|
19
|
+
define_accept # Add `accept` method as found in Visitor design pattern
|
25
20
|
alias operands subnodes
|
26
21
|
end # class
|
27
22
|
end # module
|
data/lib/loxxy/ast/lox_node.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'ast_visitee'
|
4
|
+
|
3
5
|
module Loxxy
|
4
6
|
module Ast
|
7
|
+
# Abstract class.
|
8
|
+
# Instances of its subclasses represent nodes of an abstract syntax tree
|
9
|
+
# that is the product of the parse of an input text.
|
5
10
|
class LoxNode
|
11
|
+
# Let nodes take `visitee` role as defined in the Visitor design pattern
|
12
|
+
extend ASTVisitee
|
13
|
+
|
6
14
|
# return [Rley::Lexical::Position] Position of the entry in the input stream.
|
7
15
|
attr_reader :position
|
8
16
|
|
@@ -16,7 +24,7 @@ module Loxxy
|
|
16
24
|
# Default: do nothing ...
|
17
25
|
end
|
18
26
|
|
19
|
-
# Abstract method.
|
27
|
+
# Abstract method (must be overriden in subclasses).
|
20
28
|
# Part of the 'visitee' role in Visitor design pattern.
|
21
29
|
# @param _visitor [LoxxyTreeVisitor] the visitor
|
22
30
|
def accept(_visitor)
|