ruby-ll 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,90 @@
1
+ /* The MIT License
2
+
3
+ Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
24
+ */
25
+
26
+ /*
27
+ An example:
28
+
29
+ #include "kvec.h"
30
+ int main() {
31
+ kvec_t(int) array;
32
+ kv_init(array);
33
+ kv_push(int, array, 10); // append
34
+ kv_a(int, array, 20) = 5; // dynamic
35
+ kv_A(array, 20) = 4; // static
36
+ kv_destroy(array);
37
+ return 0;
38
+ }
39
+ */
40
+
41
+ /*
42
+ 2008-09-22 (0.1.0):
43
+
44
+ * The initial version.
45
+
46
+ */
47
+
48
+ #ifndef AC_KVEC_H
49
+ #define AC_KVEC_H
50
+
51
+ #include <stdlib.h>
52
+
53
+ #define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
54
+
55
+ #define kvec_t(type) struct { size_t n, m; type *a; }
56
+ #define kv_init(v) ((v).n = (v).m = 0, (v).a = 0)
57
+ #define kv_destroy(v) free((v).a)
58
+ #define kv_A(v, i) ((v).a[(i)])
59
+ #define kv_pop(v) ((v).a[--(v).n])
60
+ #define kv_size(v) ((v).n)
61
+ #define kv_max(v) ((v).m)
62
+
63
+ #define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
64
+
65
+ #define kv_copy(type, v1, v0) do { \
66
+ if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n); \
67
+ (v1).n = (v0).n; \
68
+ memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
69
+ } while (0) \
70
+
71
+ #define kv_push(type, v, x) do { \
72
+ if ((v).n == (v).m) { \
73
+ (v).m = (v).m? (v).m<<1 : 2; \
74
+ (v).a = (type*)realloc((v).a, sizeof(type) * (v).m); \
75
+ } \
76
+ (v).a[(v).n++] = (x); \
77
+ } while (0)
78
+
79
+ #define kv_pushp(type, v) (((v).n == (v).m)? \
80
+ ((v).m = ((v).m? (v).m<<1 : 2), \
81
+ (v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
82
+ : 0), ((v).a + ((v).n++))
83
+
84
+ #define kv_a(type, v, i) (((v).m <= (size_t)(i)? \
85
+ ((v).m = (v).n = (i) + 1, kv_roundup32((v).m), \
86
+ (v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
87
+ : (v).n <= (size_t)(i)? (v).n = (i) + 1 \
88
+ : 0), (v).a[(i)])
89
+
90
+ #endif
@@ -0,0 +1,7 @@
1
+ #include "libll.h"
2
+
3
+ void Init_libll()
4
+ {
5
+ Init_ll_driver_config();
6
+ Init_ll_driver();
7
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef LIBLL_H
2
+ #define LIBLL_H
3
+
4
+ #include <ruby.h>
5
+ #include "driver.h"
6
+
7
+ void Init_libll();
8
+
9
+ #endif
@@ -0,0 +1,6 @@
1
+ #ifndef LIBLL_MACROS_H
2
+ #define LIBLL_MACROS_H
3
+
4
+ #define FOR(index, max) for ( index = 0; index < max; index++ )
5
+
6
+ #endif
@@ -0,0 +1,12 @@
1
+ package org.libll;
2
+
3
+ import org.jruby.Ruby;
4
+
5
+ public class Libll
6
+ {
7
+ public static void load(final Ruby runtime)
8
+ {
9
+ org.libll.DriverConfig.load(runtime);
10
+ org.libll.Driver.load(runtime);
11
+ }
12
+ }
@@ -0,0 +1,247 @@
1
+ package org.libll;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.ArrayDeque;
5
+
6
+ import org.libll.DriverConfig;
7
+
8
+ import org.jruby.Ruby;
9
+ import org.jruby.RubyModule;
10
+ import org.jruby.RubyClass;
11
+ import org.jruby.RubyObject;
12
+ import org.jruby.RubyArray;
13
+ import org.jruby.RubySymbol;
14
+ import org.jruby.RubyFixnum;
15
+
16
+ import org.jruby.anno.JRubyClass;
17
+ import org.jruby.anno.JRubyMethod;
18
+ import org.jruby.runtime.Arity;
19
+ import org.jruby.runtime.Helpers;
20
+ import org.jruby.runtime.ThreadContext;
21
+ import org.jruby.runtime.ObjectAllocator;
22
+ import org.jruby.runtime.BlockCallback;
23
+ import org.jruby.runtime.Block;
24
+ import org.jruby.runtime.CallBlock19;
25
+ import org.jruby.runtime.builtin.IRubyObject;
26
+
27
+ @JRubyClass(name="LL::Driver", parent="Object")
28
+ public class Driver extends RubyObject
29
+ {
30
+ private static long T_EOF = -1;
31
+ private static long T_RULE = 0;
32
+ private static long T_TERMINAL = 1;
33
+ private static long T_EPSILON = 2;
34
+ private static long T_ACTION = 3;
35
+
36
+ /**
37
+ * The current Ruby runtime.
38
+ */
39
+ private Ruby runtime;
40
+
41
+ /**
42
+ * The driver configuration.
43
+ */
44
+ private DriverConfig config;
45
+
46
+ /**
47
+ * Sets up the class in the Ruby runtime.
48
+ */
49
+ public static void load(Ruby runtime)
50
+ {
51
+ RubyModule ll = (RubyModule) runtime.getModule("LL");
52
+
53
+ RubyClass driver = ll.defineClassUnder(
54
+ "Driver",
55
+ runtime.getObject(),
56
+ ALLOCATOR
57
+ );
58
+
59
+ driver.defineAnnotatedMethods(Driver.class);
60
+ }
61
+
62
+ private static final ObjectAllocator ALLOCATOR = new ObjectAllocator()
63
+ {
64
+ public IRubyObject allocate(Ruby runtime, RubyClass klass)
65
+ {
66
+ return new org.libll.Driver(runtime, klass);
67
+ }
68
+ };
69
+
70
+ /**
71
+ * @param runtime The current Ruby runtime.
72
+ * @param klass The Driver class.
73
+ */
74
+ public Driver(Ruby runtime, RubyClass klass)
75
+ {
76
+ super(runtime, klass);
77
+
78
+ this.runtime = runtime;
79
+ this.config = (DriverConfig) klass.getConstant("CONFIG");
80
+ }
81
+
82
+ /**
83
+ * The main parsing loop of the driver.
84
+ */
85
+ @JRubyMethod
86
+ public IRubyObject parse(ThreadContext context)
87
+ {
88
+ final ArrayDeque<Long> stack = new ArrayDeque<Long>();
89
+ final ArrayDeque<IRubyObject> value_stack = new ArrayDeque<IRubyObject>();
90
+ final Driver self = this;
91
+
92
+ // EOF
93
+ stack.push(this.T_EOF);
94
+ stack.push(this.T_EOF);
95
+
96
+ // Start rule
97
+ ArrayList<Long> start_row = self.config.rules.get(0);
98
+
99
+ for ( int index = 0; index < start_row.size(); index++ )
100
+ {
101
+ stack.push(start_row.get(index));
102
+ }
103
+
104
+ BlockCallback callback = new BlockCallback()
105
+ {
106
+ public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block)
107
+ {
108
+ RubyArray token = (RubyArray) args[0];
109
+ IRubyObject type = token.entry(0);
110
+ IRubyObject value = token.entry(1);
111
+
112
+ while ( true )
113
+ {
114
+ if ( stack.size() == 0 )
115
+ {
116
+ self.callMethod(
117
+ context,
118
+ "unexpected_input_error",
119
+ token
120
+ );
121
+ }
122
+
123
+ Long stack_value = stack.pop();
124
+ Long stack_type = stack.pop();
125
+ Long token_id = (long) 0;
126
+
127
+ if ( self.config.terminals.containsKey(type) )
128
+ {
129
+ token_id = self.config.terminals.get(type);
130
+ }
131
+
132
+ // Rule
133
+ if ( stack_type == self.T_RULE )
134
+ {
135
+ Long production_i = self.config.table
136
+ .get(stack_value.intValue())
137
+ .get(token_id.intValue());
138
+
139
+ if ( production_i == self.T_EOF )
140
+ {
141
+ IRubyObject[] stack_input_error_args = {
142
+ RubyFixnum.newFixnum(self.runtime, stack_value),
143
+ token
144
+ };
145
+
146
+ self.callMethod(
147
+ context,
148
+ "stack_input_error",
149
+ stack_input_error_args
150
+ );
151
+ }
152
+ else
153
+ {
154
+ ArrayList<Long> row = self.config.rules
155
+ .get(production_i.intValue());
156
+
157
+ for ( int index = 0; index < row.size(); index++ )
158
+ {
159
+ stack.push(row.get(index));
160
+ }
161
+ }
162
+ }
163
+ // Terminal
164
+ else if ( stack_type == self.T_TERMINAL )
165
+ {
166
+ if ( stack_value == token_id )
167
+ {
168
+ value_stack.push(value);
169
+
170
+ break;
171
+ }
172
+ else
173
+ {
174
+ IRubyObject[] invalid_terminal_args = {
175
+ RubyFixnum.newFixnum(self.runtime, token_id),
176
+ RubyFixnum.newFixnum(self.runtime, stack_value)
177
+ };
178
+
179
+ self.callMethod(
180
+ context,
181
+ "invalid_terminal_error",
182
+ invalid_terminal_args
183
+ );
184
+ }
185
+ }
186
+ // Action
187
+ else if ( stack_type == self.T_ACTION )
188
+ {
189
+ String method = self.config.action_names
190
+ .get(stack_value.intValue())
191
+ .toString();
192
+
193
+ long num_args = (long) self.config.action_arg_amounts
194
+ .get(stack_value.intValue());
195
+
196
+ RubyArray action_args = self.runtime.newArray();
197
+
198
+ if ( num_args > (long) value_stack.size() )
199
+ {
200
+ num_args = (long) value_stack.size();
201
+ }
202
+
203
+ while ( (num_args--) > 0 )
204
+ {
205
+ if ( value_stack.size() > 0 )
206
+ {
207
+ action_args.store(num_args, value_stack.pop());
208
+ }
209
+ }
210
+
211
+ value_stack.push(
212
+ self.callMethod(context, method, action_args)
213
+ );
214
+ }
215
+ else if ( stack_type == self.T_EOF )
216
+ {
217
+ break;
218
+ }
219
+ }
220
+
221
+ return context.nil;
222
+ }
223
+ };
224
+
225
+ Helpers.invoke(
226
+ context,
227
+ this,
228
+ "each_token",
229
+ CallBlock19.newCallClosure(
230
+ this,
231
+ this.metaClass,
232
+ Arity.NO_ARGUMENTS,
233
+ callback,
234
+ context
235
+ )
236
+ );
237
+
238
+ if ( value_stack.isEmpty() )
239
+ {
240
+ return context.nil;
241
+ }
242
+ else
243
+ {
244
+ return value_stack.pop();
245
+ }
246
+ }
247
+ }
@@ -0,0 +1,193 @@
1
+ package org.libll;
2
+
3
+ import java.util.HashMap;
4
+ import java.util.ArrayList;
5
+
6
+ import org.jruby.Ruby;
7
+ import org.jruby.RubyModule;
8
+ import org.jruby.RubyClass;
9
+ import org.jruby.RubyObject;
10
+ import org.jruby.RubySymbol;
11
+ import org.jruby.RubyArray;
12
+ import org.jruby.RubyFixnum;
13
+
14
+ import org.jruby.anno.JRubyClass;
15
+ import org.jruby.anno.JRubyMethod;
16
+ import org.jruby.runtime.ThreadContext;
17
+ import org.jruby.runtime.ObjectAllocator;
18
+ import org.jruby.runtime.builtin.IRubyObject;
19
+
20
+ /**
21
+ * Class used for storing the configuration (e.g. the rules and the lookup
22
+ * table) of a parser driver. This class mimics its C equivalent (also called
23
+ * "DriverConfig").
24
+ */
25
+ @JRubyClass(name="LL::DriverConfig", parent="Object")
26
+ public class DriverConfig extends RubyObject
27
+ {
28
+ /**
29
+ * The current Ruby runtime.
30
+ */
31
+ private Ruby runtime;
32
+
33
+ /**
34
+ * Hash mapping Ruby Symbols with their indexes.
35
+ */
36
+ public HashMap<RubySymbol, Long> terminals = new HashMap<RubySymbol, Long>();
37
+
38
+ /**
39
+ * 2-dimensional array containing the rules and their steps.
40
+ */
41
+ public ArrayList<ArrayList<Long>> rules = new ArrayList<ArrayList<Long>>();
42
+
43
+ /**
44
+ * 2-dimensional array used as the lookup table.
45
+ */
46
+ public ArrayList<ArrayList<Long>> table = new ArrayList<ArrayList<Long>>();
47
+
48
+ /**
49
+ * Array containing the callback names.
50
+ */
51
+ public ArrayList<RubySymbol> action_names = new ArrayList<RubySymbol>();
52
+
53
+ /**
54
+ * Array containing the arities of every callback.
55
+ */
56
+ public ArrayList<Integer> action_arg_amounts = new ArrayList<Integer>();
57
+
58
+ /**
59
+ * Sets up the class in the Ruby runtime.
60
+ */
61
+ public static void load(Ruby runtime)
62
+ {
63
+ RubyModule ll = (RubyModule) runtime.getModule("LL");
64
+
65
+ RubyClass config = ll.defineClassUnder(
66
+ "DriverConfig",
67
+ runtime.getObject(),
68
+ ALLOCATOR
69
+ );
70
+
71
+ config.defineAnnotatedMethods(DriverConfig.class);
72
+ }
73
+
74
+ private static final ObjectAllocator ALLOCATOR = new ObjectAllocator()
75
+ {
76
+ public IRubyObject allocate(Ruby runtime, RubyClass klass)
77
+ {
78
+ return new org.libll.DriverConfig(runtime, klass);
79
+ }
80
+ };
81
+
82
+ /**
83
+ * @param runtime The current Ruby runtime.
84
+ * @param klass The DriverConfig class.
85
+ */
86
+ public DriverConfig(Ruby runtime, RubyClass klass)
87
+ {
88
+ super(runtime, klass);
89
+
90
+ this.runtime = runtime;
91
+ }
92
+
93
+ /**
94
+ * Stores the terminals of the parser in the current DriverConfig instance.
95
+ *
96
+ * @param arg Array of terminals to store.
97
+ */
98
+ @JRubyMethod(name="terminals_native=")
99
+ public IRubyObject set_terminals_native(ThreadContext context, IRubyObject arg)
100
+ {
101
+ RubyArray array = arg.convertToArray();
102
+
103
+ for ( long index = 0; index < array.size(); index++ )
104
+ {
105
+ RubySymbol sym = (RubySymbol) array.entry(index);
106
+
107
+ this.terminals.put(sym, index);
108
+ }
109
+
110
+ return context.nil;
111
+ }
112
+
113
+ /**
114
+ * Stores the rules in the current DriverConfig instance.
115
+ *
116
+ * @param arg Array of rules to store.
117
+ */
118
+ @JRubyMethod(name="rules_native=")
119
+ public IRubyObject set_rules_native(ThreadContext context, IRubyObject arg)
120
+ {
121
+ RubyArray array = arg.convertToArray();
122
+
123
+ for ( long rindex = 0; rindex < array.size(); rindex++ )
124
+ {
125
+ RubyArray ruby_row = (RubyArray) array.entry(rindex);
126
+ ArrayList<Long> row = new ArrayList<Long>();
127
+
128
+ for ( long cindex = 0; cindex < ruby_row.size(); cindex++ )
129
+ {
130
+ RubyFixnum column = (RubyFixnum) ruby_row.entry(cindex);
131
+
132
+ row.add(column.getLongValue());
133
+ }
134
+
135
+ this.rules.add(row);
136
+ }
137
+
138
+ return context.nil;
139
+ }
140
+
141
+ /**
142
+ * Stores the lookup table in the current DriverConfig instance.
143
+ *
144
+ * @param arg Array containing the rows/columns of the lookup table.
145
+ */
146
+ @JRubyMethod(name="table_native=")
147
+ public IRubyObject set_table_native(ThreadContext context, IRubyObject arg)
148
+ {
149
+ RubyArray array = arg.convertToArray();
150
+
151
+ for ( long rindex = 0; rindex < array.size(); rindex++ )
152
+ {
153
+ RubyArray ruby_row = (RubyArray) array.entry(rindex);
154
+ ArrayList<Long> row = new ArrayList<Long>();
155
+
156
+ for ( long cindex = 0; cindex < ruby_row.size(); cindex++ )
157
+ {
158
+ RubyFixnum column = (RubyFixnum) ruby_row.entry(cindex);
159
+
160
+ row.add(column.getLongValue());
161
+ }
162
+
163
+ this.table.add(row);
164
+ }
165
+
166
+ return context.nil;
167
+ }
168
+
169
+ /**
170
+ * Stores the callback actions and their arities in the current DriverConfig
171
+ * instance.
172
+ *
173
+ * @param arg Array containing the callback names and their arguments.
174
+ */
175
+ @JRubyMethod(name="actions_native=")
176
+ public IRubyObject set_actions_native(ThreadContext context, IRubyObject arg)
177
+ {
178
+ RubyArray array = arg.convertToArray();
179
+
180
+ for ( long rindex = 0; rindex < array.size(); rindex++ )
181
+ {
182
+ RubyArray row = (RubyArray) array.entry(rindex);
183
+
184
+ RubySymbol name = (RubySymbol) row.entry(0);
185
+ RubyFixnum arity = (RubyFixnum) row.entry(1);
186
+
187
+ this.action_names.add(name);
188
+ this.action_arg_amounts.add((int) arity.getLongValue());
189
+ }
190
+
191
+ return context.nil;
192
+ }
193
+ }