antlr4-native 1.0.0 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +98 -0
- data/antlr4-native.gemspec +3 -2
- data/lib/antlr4-native/context.rb +29 -17
- data/lib/antlr4-native/generator.rb +99 -61
- data/lib/antlr4-native/version.rb +1 -1
- data/lib/antlr4-native/visitor_generator.rb +12 -4
- data/vendor/antlr4-4.8-1-complete.jar +0 -0
- metadata +23 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f14d05febd863a51c3e111e7ef3493eb2fe1b72fe72b0b3d1c5c114a2947f7c7
|
4
|
+
data.tar.gz: e8f3fe771ae21c552a1074e2f0608f9c87da1e7bd9063f2f8e18363531c37e6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64cf7e6628edbaff365daf278c1e70dccd7ca083128d604efe8fcb4850c77efc621ce204fe250a7ffb91adb5d6cb4d02de9f1f68bbbb32c4c8c79d725c308a26
|
7
|
+
data.tar.gz: 1c5ba3ec3908cc1a951794d0e70f87afa0f01694ef623b38269ad5f22569fd8b587c1c6a7e820d32de273f6c87e77d15abcf604e83b0edd13f2a0636c09c5d86
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# antlr4-native
|
2
|
+
|
3
|
+
Create a Ruby native extension from (almost) any ANTLR4 grammar.
|
4
|
+
|
5
|
+
## What is this thing?
|
6
|
+
|
7
|
+
This gem generates native Ruby extensions from ANTLR grammars, enabling Ruby developers to generate parsers for numerous programming languages, file formats, etc.
|
8
|
+
|
9
|
+
## Who needs this?
|
10
|
+
|
11
|
+
If you're a Ruby programmer who wants to parse and traverse source code written in a plethora of programming languages, antlr4-native might be able to help you. A number of community-developed ANTLR grammars are available in ANTLR's [grammars-v4](https://github.com/antlr/grammars-v4) repo. Grab one, then use antlr4-native to generate a bunch of Ruby-compatible C++ code from it. The C++ code can be compiled and used as a native extension.
|
12
|
+
|
13
|
+
Rather than use antlr4-native directly, consider using its sister project, the [antlr-gemerator](https://github.com/camertron/antlr-gemerator), which can generate a complete rubygem from an ANTLR grammar.
|
14
|
+
|
15
|
+
## Code Generation
|
16
|
+
|
17
|
+
Here's how to generate a native extension for a given lexer and parser (Python in this case), defined in two .g4 files:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'antlr4-native'
|
21
|
+
|
22
|
+
generator = Antlr4Native::Generator.new(
|
23
|
+
grammar_files: ['Python3Lexer.g4', 'Python3Parser.g4'],
|
24
|
+
output_dir: 'ext',
|
25
|
+
parser_root_method: 'file_input'
|
26
|
+
)
|
27
|
+
|
28
|
+
generator.generate
|
29
|
+
```
|
30
|
+
|
31
|
+
In the example above, the output directory is set to the standard Ruby native extensions directory, 'ext'. Antlr4-native will generate code into ext/\<name\>, where \<name\> is the name of the parser as defined in the grammar file(s). In this case, PythonParser.g4 contains:
|
32
|
+
|
33
|
+
```antlr
|
34
|
+
parser grammar Python3Parser;
|
35
|
+
```
|
36
|
+
|
37
|
+
so antlr4-native will generate code into the ext/python3-parser directory.
|
38
|
+
|
39
|
+
Finally, the `parser_root_method` option tells antlr4-native which context represents the root of the parse tree. This context functions as the starting point for visitors.
|
40
|
+
|
41
|
+
## Using extensions in Ruby
|
42
|
+
|
43
|
+
Parsers contain several methods for parsing source code. Use `#parse` to parse a string and `#parse_file` to parse the contents of a file:
|
44
|
+
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
parser = Python3Parser::Parser.parse(File.read('path/to/file.py'))
|
48
|
+
|
49
|
+
# equivalent to:
|
50
|
+
parser = Python3Parser::Parser.parse_file('path/to/file.py')
|
51
|
+
```
|
52
|
+
|
53
|
+
Use the `#visit` method on an instance of `Parser` to make use of a visitor:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
visitor = MyVisitor.new
|
57
|
+
parser.visit(visitor)
|
58
|
+
```
|
59
|
+
|
60
|
+
See the next section for more info regarding creating and using visitors.
|
61
|
+
|
62
|
+
## Visitors
|
63
|
+
|
64
|
+
A visitor class is automatically created during code generation. Visitors are just classes with a bunch of special methods, each corresponding to a specific part of the source language's syntax. The methods are essentially callbacks that are triggered in-order as the parser walks over the parse tree. For example, here's a visitor with a method that will be called whenever the parser walks over a Python function definition:
|
65
|
+
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class FuncDefVisitor < Python3Parser::Visitor
|
69
|
+
def visit_func_def(ctx)
|
70
|
+
puts ctx.NAME.text # print the name of the method
|
71
|
+
visit_children(ctx)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
Make sure to always call `#visit_children` at some point in your `visit_*` methods. If you don't, the subtree under the current context won't get visited.
|
77
|
+
|
78
|
+
Finally, if you override `#initialize` in your visitor subclasses, don't forget to call `super`. If you don't, you'll get a nice big segfault.
|
79
|
+
|
80
|
+
## Caveats
|
81
|
+
|
82
|
+
1. Avoid retaining references to contexts, tokens, etc anywhere in your Ruby code. Contexts (i.e. the `ctx` variables in the examples above) and other objects that are created by ANTLR's C++ runtime are automatically cleaned up without the Ruby interpreter's knowledge. You'll almost surely see a segfault if you retain a reference to one of these objects and try to use it after the call to `Parser#visit`.
|
83
|
+
2. Due to an ANTLR limitation, parsers cannot be used in a multi-threaded environment, even if each parser instance is used entirely in the context of a single thread (i.e. parsers are not shared between threads). According to the ANTLR C++ developers, parsers should be threadsafe. Unfortunately firsthand experience has proven otherwise. Your mileage may vary.
|
84
|
+
3. The description of this gem says "(almost) any ANTLR4 grammar" because many grammars contain target-specific code. For example, the Python3 grammar referenced in the examples above contains inline Java code that the C++ compiler won't understand. You'll need to port any such code to C++ before you'll be able to compile and use the native extension.
|
85
|
+
|
86
|
+
## System Requirements
|
87
|
+
|
88
|
+
* A Java runtime (version 1.6 or higher) is required to generate parsers, since ANTLR is a Java tool. The ANTLR .jar file is distributed inside the antlr4-native gem, so there's no need to download it separately. You can download a Java runtime [here](https://www.java.com/en/download/).
|
89
|
+
* Ruby >= 2.3.
|
90
|
+
* A C compiler (like gcc or clang) that supports C++14. If Ruby is working on your machine then you likely already have this.
|
91
|
+
|
92
|
+
## License
|
93
|
+
|
94
|
+
Licensed under the MIT license. See LICENSE.txt for details.
|
95
|
+
|
96
|
+
## Authors
|
97
|
+
|
98
|
+
* Cameron C. Dutro: http://github.com/camertron
|
data/antlr4-native.gemspec
CHANGED
@@ -11,8 +11,9 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.description = s.summary = 'Create a Ruby native extension from any ANTLR4 grammar.'
|
12
12
|
|
13
13
|
s.platform = Gem::Platform::RUBY
|
14
|
-
s.has_rdoc = true
|
15
14
|
|
16
15
|
s.require_path = 'lib'
|
17
|
-
s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'README.md', 'Rakefile', 'antlr4-native.gemspec']
|
16
|
+
s.files = Dir['{lib,spec,vendor}/**/*', 'Gemfile', 'README.md', 'Rakefile', 'antlr4-native.gemspec']
|
17
|
+
|
18
|
+
s.add_runtime_dependency "rice", "~> 4.0"
|
18
19
|
end
|
@@ -51,16 +51,24 @@ module Antlr4Native
|
|
51
51
|
|
52
52
|
def conversions
|
53
53
|
@class_conversions ||= <<~END
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
namespace Rice::detail {
|
55
|
+
template <>
|
56
|
+
class To_Ruby<#{parser_ns}::#{name}*> {
|
57
|
+
public:
|
58
|
+
VALUE convert(#{parser_ns}::#{name}* const &x) {
|
59
|
+
if (!x) return Nil;
|
60
|
+
return Data_Object<#{parser_ns}::#{name}>(x, false, #{proxy_class_variable});
|
61
|
+
}
|
62
|
+
};
|
59
63
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
+
template <>
|
65
|
+
class To_Ruby<#{name}Proxy*> {
|
66
|
+
public:
|
67
|
+
VALUE convert(#{name}Proxy* const &x) {
|
68
|
+
if (!x) return Nil;
|
69
|
+
return Data_Object<#{name}Proxy>(x, false, #{proxy_class_variable});
|
70
|
+
}
|
71
|
+
};
|
64
72
|
}
|
65
73
|
END
|
66
74
|
end
|
@@ -88,7 +96,7 @@ module Antlr4Native
|
|
88
96
|
}
|
89
97
|
}
|
90
98
|
|
91
|
-
return a;
|
99
|
+
return std::move(a);
|
92
100
|
}
|
93
101
|
END
|
94
102
|
else
|
@@ -105,7 +113,7 @@ module Antlr4Native
|
|
105
113
|
}
|
106
114
|
|
107
115
|
for (auto child : getChildren()) {
|
108
|
-
if (ctx ==
|
116
|
+
if (ctx == detail::From_Ruby<ContextProxy>().convert(child.value()).getOriginal()) {
|
109
117
|
return child;
|
110
118
|
}
|
111
119
|
}
|
@@ -127,17 +135,17 @@ module Antlr4Native
|
|
127
135
|
Array a;
|
128
136
|
|
129
137
|
if (orig == nullptr) {
|
130
|
-
return a;
|
138
|
+
return std::move(a);
|
131
139
|
}
|
132
140
|
|
133
141
|
auto vec = ((#{parser_ns}::#{name}*)orig) -> #{token_mtd.name}(#{params});
|
134
142
|
|
135
143
|
for (auto it = vec.begin(); it != vec.end(); it ++) {
|
136
144
|
TerminalNodeProxy proxy(*it);
|
137
|
-
a.push(proxy);
|
145
|
+
a.push(detail::To_Ruby<TerminalNodeProxy>().convert(proxy));
|
138
146
|
}
|
139
147
|
|
140
|
-
return a;
|
148
|
+
return std::move(a);
|
141
149
|
}
|
142
150
|
END
|
143
151
|
else
|
@@ -148,8 +156,13 @@ module Antlr4Native
|
|
148
156
|
}
|
149
157
|
|
150
158
|
auto token = ((#{parser_ns}::#{name}*)orig) -> #{token_mtd.name}(#{params});
|
159
|
+
|
160
|
+
if (token == nullptr) {
|
161
|
+
return Qnil;
|
162
|
+
}
|
163
|
+
|
151
164
|
TerminalNodeProxy proxy(token);
|
152
|
-
return
|
165
|
+
return detail::To_Ruby<TerminalNodeProxy>().convert(proxy);
|
153
166
|
}
|
154
167
|
END
|
155
168
|
end
|
@@ -159,8 +172,7 @@ module Antlr4Native
|
|
159
172
|
def class_wrapper(module_var)
|
160
173
|
@class_wrapper ||= begin
|
161
174
|
lines = [
|
162
|
-
|
163
|
-
".define_class<#{name}Proxy, ContextProxy>(\"#{name}\")"
|
175
|
+
%(#{proxy_class_variable} = define_class_under<#{name}Proxy, ContextProxy>(#{module_var}, "#{name}"))
|
164
176
|
]
|
165
177
|
|
166
178
|
each_context_method do |ctx_method|
|
@@ -63,18 +63,27 @@ module Antlr4Native
|
|
63
63
|
|
64
64
|
def interop_code
|
65
65
|
<<~END
|
66
|
-
#include
|
66
|
+
#include <iostream>
|
67
67
|
|
68
|
-
#include
|
68
|
+
#include <antlr4-runtime.h>
|
69
69
|
|
70
|
-
#include "
|
71
|
-
#include "
|
72
|
-
#include "
|
70
|
+
#include "antlrgen/#{parser_ns}.h"
|
71
|
+
#include "antlrgen/#{antlr_ns}BaseVisitor.h"
|
72
|
+
#include "antlrgen/#{lexer_ns}.h"
|
73
73
|
|
74
|
-
#include
|
75
|
-
#include
|
76
|
-
|
77
|
-
#
|
74
|
+
#include <rice/rice.hpp>
|
75
|
+
#include <rice/stl.hpp>
|
76
|
+
|
77
|
+
#ifdef _WIN32
|
78
|
+
#undef OPTIONAL
|
79
|
+
#undef IN
|
80
|
+
#undef OUT
|
81
|
+
#endif
|
82
|
+
|
83
|
+
#undef FALSE
|
84
|
+
#undef TRUE
|
85
|
+
|
86
|
+
#undef TYPE
|
78
87
|
|
79
88
|
using namespace std;
|
80
89
|
using namespace Rice;
|
@@ -82,6 +91,35 @@ module Antlr4Native
|
|
82
91
|
|
83
92
|
#{proxy_class_declarations}
|
84
93
|
|
94
|
+
namespace Rice::detail {
|
95
|
+
template <>
|
96
|
+
class To_Ruby<Token*> {
|
97
|
+
public:
|
98
|
+
VALUE convert(Token* const &x) {
|
99
|
+
if (!x) return Nil;
|
100
|
+
return Data_Object<Token>(x, false, rb_cToken);
|
101
|
+
}
|
102
|
+
};
|
103
|
+
|
104
|
+
template <>
|
105
|
+
class To_Ruby<tree::ParseTree*> {
|
106
|
+
public:
|
107
|
+
VALUE convert(tree::ParseTree* const &x) {
|
108
|
+
if (!x) return Nil;
|
109
|
+
return Data_Object<tree::ParseTree>(x, false, rb_cParseTree);
|
110
|
+
}
|
111
|
+
};
|
112
|
+
|
113
|
+
template <>
|
114
|
+
class To_Ruby<tree::TerminalNode*> {
|
115
|
+
public:
|
116
|
+
VALUE convert(tree::TerminalNode* const &x) {
|
117
|
+
if (!x) return Nil;
|
118
|
+
return Data_Object<tree::TerminalNode>(x, false, rb_cTerminalNode);
|
119
|
+
}
|
120
|
+
};
|
121
|
+
}
|
122
|
+
|
85
123
|
class ContextProxy {
|
86
124
|
public:
|
87
125
|
ContextProxy(tree::ParseTree* orig) {
|
@@ -96,6 +134,18 @@ module Antlr4Native
|
|
96
134
|
return orig -> getText();
|
97
135
|
}
|
98
136
|
|
137
|
+
Object getStart() {
|
138
|
+
auto token = ((ParserRuleContext*) orig) -> getStart();
|
139
|
+
|
140
|
+
return detail::To_Ruby<Token*>().convert(token);
|
141
|
+
}
|
142
|
+
|
143
|
+
Object getStop() {
|
144
|
+
auto token = ((ParserRuleContext*) orig) -> getStop();
|
145
|
+
|
146
|
+
return detail::To_Ruby<Token*>().convert(token);
|
147
|
+
}
|
148
|
+
|
99
149
|
Array getChildren() {
|
100
150
|
if (children == nullptr) {
|
101
151
|
children = new Array();
|
@@ -134,7 +184,7 @@ module Antlr4Native
|
|
134
184
|
|
135
185
|
bool doubleEquals(Object other) {
|
136
186
|
if (other.is_a(rb_cContextProxy)) {
|
137
|
-
return
|
187
|
+
return detail::From_Ruby<ContextProxy*>().convert(other) -> getOriginal() == getOriginal();
|
138
188
|
} else {
|
139
189
|
return false;
|
140
190
|
}
|
@@ -155,6 +205,7 @@ module Antlr4Native
|
|
155
205
|
TerminalNodeProxy(tree::ParseTree* tree) : ContextProxy(tree) { }
|
156
206
|
};
|
157
207
|
|
208
|
+
|
158
209
|
#{proxy_class_headers}
|
159
210
|
|
160
211
|
#{conversions}
|
@@ -191,31 +242,7 @@ module Antlr4Native
|
|
191
242
|
end
|
192
243
|
|
193
244
|
def conversions
|
194
|
-
@conversions ||=
|
195
|
-
context_conversions = contexts.map(&:conversions).join("\n")
|
196
|
-
|
197
|
-
<<~END
|
198
|
-
template <>
|
199
|
-
Object to_ruby<Token*>(Token* const &x) {
|
200
|
-
if (!x) return Nil;
|
201
|
-
return Data_Object<Token>(x, rb_cToken, nullptr, nullptr);
|
202
|
-
}
|
203
|
-
|
204
|
-
template <>
|
205
|
-
Object to_ruby<tree::ParseTree*>(tree::ParseTree* const &x) {
|
206
|
-
if (!x) return Nil;
|
207
|
-
return Data_Object<tree::ParseTree>(x, rb_cParseTree, nullptr, nullptr);
|
208
|
-
}
|
209
|
-
|
210
|
-
template <>
|
211
|
-
Object to_ruby<tree::TerminalNode*>(tree::TerminalNode* const &x) {
|
212
|
-
if (!x) return Nil;
|
213
|
-
return Data_Object<tree::TerminalNode>(x, rb_cTerminalNode, nullptr, nullptr);
|
214
|
-
}
|
215
|
-
|
216
|
-
#{context_conversions}
|
217
|
-
END
|
218
|
-
end
|
245
|
+
@conversions ||= contexts.map(&:conversions).join("\n")
|
219
246
|
end
|
220
247
|
|
221
248
|
def proxy_class_methods
|
@@ -243,14 +270,21 @@ module Antlr4Native
|
|
243
270
|
return parser;
|
244
271
|
}
|
245
272
|
|
246
|
-
|
247
|
-
|
273
|
+
Object #{parser_root_method}() {
|
274
|
+
auto ctx = this -> parser -> #{parser_root_method}();
|
275
|
+
|
276
|
+
#{capitalize(parser_root_method)}ContextProxy proxy((#{parser_ns}::#{capitalize(parser_root_method)}Context*) ctx);
|
277
|
+
return detail::To_Ruby<#{capitalize(parser_root_method)}ContextProxy>().convert(proxy);
|
278
|
+
}
|
279
|
+
|
280
|
+
Object visit(VisitorProxy* visitor) {
|
281
|
+
auto result = visitor -> visit(this -> parser -> #{parser_root_method}());
|
248
282
|
|
249
283
|
// reset for the next visit call
|
250
284
|
this -> lexer -> reset();
|
251
285
|
this -> parser -> reset();
|
252
286
|
|
253
|
-
return
|
287
|
+
return result;
|
254
288
|
}
|
255
289
|
|
256
290
|
~ParserProxy() {
|
@@ -280,10 +314,15 @@ module Antlr4Native
|
|
280
314
|
#{parser_ns}* parser;
|
281
315
|
};
|
282
316
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
317
|
+
namespace Rice::detail {
|
318
|
+
template <>
|
319
|
+
class To_Ruby<ParserProxy*> {
|
320
|
+
public:
|
321
|
+
VALUE convert(ParserProxy* const &x) {
|
322
|
+
if (!x) return Nil;
|
323
|
+
return Data_Object<ParserProxy>(x, false, rb_cParser);
|
324
|
+
}
|
325
|
+
};
|
287
326
|
}
|
288
327
|
END
|
289
328
|
end
|
@@ -294,38 +333,37 @@ module Antlr4Native
|
|
294
333
|
void Init_#{ext_name}() {
|
295
334
|
Module rb_m#{parser_ns} = define_module("#{parser_ns}");
|
296
335
|
|
297
|
-
rb_cToken = rb_m#{parser_ns}
|
298
|
-
.
|
299
|
-
.define_method("
|
300
|
-
|
301
|
-
rb_cParser = rb_m#{parser_ns}
|
302
|
-
.define_class<ParserProxy>("Parser")
|
303
|
-
.define_singleton_method("parse", &ParserProxy::parse)
|
304
|
-
.define_singleton_method("parse_file", &ParserProxy::parseFile)
|
305
|
-
.define_method("visit", &ParserProxy::visit);
|
336
|
+
rb_cToken = define_class_under<Token>(rb_m#{parser_ns}, "Token")
|
337
|
+
.define_method("text", &Token::getText)
|
338
|
+
.define_method("channel", &Token::getChannel)
|
339
|
+
.define_method("token_index", &Token::getTokenIndex);
|
306
340
|
|
307
|
-
rb_cParseTree = rb_m#{parser_ns}
|
308
|
-
.define_class<tree::ParseTree>("ParseTree");
|
341
|
+
rb_cParseTree = define_class_under<tree::ParseTree>(rb_m#{parser_ns}, "ParseTree");
|
309
342
|
|
310
|
-
rb_cContextProxy = rb_m#{parser_ns}
|
311
|
-
.define_class<ContextProxy>("Context")
|
343
|
+
rb_cContextProxy = define_class_under<ContextProxy>(rb_m#{parser_ns}, "Context")
|
312
344
|
.define_method("children", &ContextProxy::getChildren)
|
313
345
|
.define_method("child_count", &ContextProxy::childCount)
|
314
346
|
.define_method("text", &ContextProxy::getText)
|
347
|
+
.define_method("start", &ContextProxy::getStart)
|
348
|
+
.define_method("stop", &ContextProxy::getStop)
|
315
349
|
.define_method("parent", &ContextProxy::getParent)
|
316
350
|
.define_method("==", &ContextProxy::doubleEquals);
|
317
351
|
|
318
|
-
rb_cTerminalNode =
|
319
|
-
.define_class<TerminalNodeProxy, ContextProxy>("TerminalNodeImpl");
|
352
|
+
rb_cTerminalNode = define_class_under<TerminalNodeProxy, ContextProxy>(rb_m#{parser_ns}, "TerminalNodeImpl");
|
320
353
|
|
321
|
-
rb_m#{parser_ns}
|
322
|
-
.define_class<#{visitor_generator.cpp_class_name}>("#{visitor_generator.class_name}")
|
354
|
+
define_class_under<#{antlr_ns}BaseVisitor>(rb_m#{parser_ns}, "#{visitor_generator.class_name}")
|
323
355
|
.define_director<#{visitor_generator.cpp_class_name}>()
|
324
356
|
.define_constructor(Constructor<#{visitor_generator.cpp_class_name}, Object>())
|
325
357
|
.define_method("visit", &#{visitor_generator.cpp_class_name}::ruby_visit)
|
326
358
|
.define_method("visit_children", &#{visitor_generator.cpp_class_name}::ruby_visitChildren)
|
327
359
|
#{visitor_generator.visitor_proxy_methods(' ').join("\n")};
|
328
360
|
|
361
|
+
rb_cParser = define_class_under<ParserProxy>(rb_m#{parser_ns}, "Parser")
|
362
|
+
.define_singleton_function("parse", &ParserProxy::parse)
|
363
|
+
.define_singleton_function("parse_file", &ParserProxy::parseFile)
|
364
|
+
.define_method("#{parser_root_method}", &ParserProxy::#{parser_root_method})
|
365
|
+
.define_method("visit", &ParserProxy::visit);
|
366
|
+
|
329
367
|
#{class_wrappers_str(' ')}
|
330
368
|
}
|
331
369
|
END
|
@@ -337,7 +375,7 @@ module Antlr4Native
|
|
337
375
|
[
|
338
376
|
" #{idx == 0 ? 'if' : 'else if'} (antlrcpp::is<#{parser_ns}::#{context.name}*>(node)) {",
|
339
377
|
" #{context.name}Proxy proxy((#{parser_ns}::#{context.name}*)node);",
|
340
|
-
" return
|
378
|
+
" return detail::To_Ruby<#{context.name}Proxy>().convert(proxy);",
|
341
379
|
" }"
|
342
380
|
]
|
343
381
|
end
|
@@ -347,7 +385,7 @@ module Antlr4Native
|
|
347
385
|
#{wrapper_branches.join("\n")}
|
348
386
|
else if (antlrcpp::is<tree::TerminalNodeImpl*>(node)) {
|
349
387
|
TerminalNodeProxy proxy(node);
|
350
|
-
return
|
388
|
+
return detail::To_Ruby<TerminalNodeProxy>().convert(proxy);
|
351
389
|
} else {
|
352
390
|
return Nil;
|
353
391
|
}
|
@@ -46,13 +46,21 @@ module Antlr4Native
|
|
46
46
|
#{cpp_class_name}(Object self) : Director(self) { }
|
47
47
|
|
48
48
|
Object ruby_visit(ContextProxy* proxy) {
|
49
|
-
visit(proxy -> getOriginal());
|
50
|
-
|
49
|
+
auto result = visit(proxy -> getOriginal());
|
50
|
+
try {
|
51
|
+
return result.as<Object>();
|
52
|
+
} catch(std::bad_cast) {
|
53
|
+
return Qnil;
|
54
|
+
}
|
51
55
|
}
|
52
56
|
|
53
57
|
Object ruby_visitChildren(ContextProxy* proxy) {
|
54
|
-
visitChildren(proxy -> getOriginal());
|
55
|
-
|
58
|
+
auto result = visitChildren(proxy -> getOriginal());
|
59
|
+
try {
|
60
|
+
return result.as<Object>();
|
61
|
+
} catch(std::bad_cast) {
|
62
|
+
return Qnil;
|
63
|
+
}
|
56
64
|
}
|
57
65
|
|
58
66
|
#{vms.join("\n")}
|
Binary file
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: antlr4-native
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Dutro
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2022-01-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rice
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
13
27
|
description: Create a Ruby native extension from any ANTLR4 grammar.
|
14
28
|
email:
|
15
29
|
- camertron@gmail.com
|
@@ -18,6 +32,7 @@ extensions: []
|
|
18
32
|
extra_rdoc_files: []
|
19
33
|
files:
|
20
34
|
- Gemfile
|
35
|
+
- README.md
|
21
36
|
- Rakefile
|
22
37
|
- antlr4-native.gemspec
|
23
38
|
- lib/antlr4-native.rb
|
@@ -28,10 +43,11 @@ files:
|
|
28
43
|
- lib/antlr4-native/string_helpers.rb
|
29
44
|
- lib/antlr4-native/version.rb
|
30
45
|
- lib/antlr4-native/visitor_generator.rb
|
46
|
+
- vendor/antlr4-4.8-1-complete.jar
|
31
47
|
homepage: http://github.com/camertron/antlr4-native-rb
|
32
48
|
licenses: []
|
33
49
|
metadata: {}
|
34
|
-
post_install_message:
|
50
|
+
post_install_message:
|
35
51
|
rdoc_options: []
|
36
52
|
require_paths:
|
37
53
|
- lib
|
@@ -46,9 +62,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
62
|
- !ruby/object:Gem::Version
|
47
63
|
version: '0'
|
48
64
|
requirements: []
|
49
|
-
|
50
|
-
|
51
|
-
signing_key:
|
65
|
+
rubygems_version: 3.2.22
|
66
|
+
signing_key:
|
52
67
|
specification_version: 4
|
53
68
|
summary: Create a Ruby native extension from any ANTLR4 grammar.
|
54
69
|
test_files: []
|