metal 0.0.2 → 0.0.3

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,16 @@
1
+ require 'mkmf'
2
+
3
+ begin
4
+ CXX_EXT << 'mm' unless CXX_EXT.include?('mm')
5
+ rescue
6
+ end
7
+
8
+ dir_config('metal')
9
+
10
+ $CFLAGS << " -I. -I../../../include/ -Wall -g"
11
+ $libs << " -lobjc"
12
+
13
+ $objs = %w[metal_boot.o metal_boot_rb.o]
14
+ $srcs = %w[metal_boot.mm metal_boot_rb.mm]
15
+
16
+ create_makefile('metal_boot')
@@ -0,0 +1,20 @@
1
+ #import "ruby.h"
2
+ #import "metal/rbcode.h"
3
+ #import "metal_boot.h"
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+ void Init_metal_boot() {
8
+ VALUE mMetal = rb_define_module("Metal");
9
+ VALUE cBase = rb_define_class_under(mMetal, "ParserBase", rb_cObject);
10
+ VALUE code;
11
+ {
12
+ VALUE cMetalParser = rb_define_class("MetalParser", cBase);
13
+ rb_define_method(cMetalParser, "parse", (VALUE (*)(ANYARGS))(VALUE (*)(VALUE,VALUE))&Metal::parse_method_template<MetalParser>, 1);
14
+ code = rb_str_new(" include Metal::Generator ",26);
15
+ rb_mod_module_eval(1,&code,cMetalParser);
16
+ }
17
+ }
18
+ #ifdef __cplusplus
19
+ }
20
+ #endif
@@ -0,0 +1,35 @@
1
+ require 'mkmf'
2
+
3
+ begin
4
+ CXX_EXT << 'mm' unless CXX_EXT.include?('mm')
5
+ rescue
6
+ end
7
+
8
+ dir_config('oniguruma')
9
+ dir_config('metal')
10
+
11
+ $CFLAGS << " -I. -I../../../include -Wall -g"
12
+
13
+ if have_library('objc', 'objc_msgSend')
14
+ $CFLAGS << " -DOBJC_APPLE"
15
+ elsif have_library('objc', 'objc_msg_lookup')
16
+ $CFLAGS << " -DOBJC_GNU"
17
+ else
18
+ raise "Objective-C library is needed."
19
+ end
20
+
21
+ unless have_library('stdc++')
22
+ raise "Standard C++ library is needed."
23
+ end
24
+
25
+ if RUBY_VERSION < "1.9.0"
26
+ unless have_library('onig')
27
+ raise "Oniguruma library is needed."
28
+ end
29
+ end
30
+
31
+ $objs = %w[input.o runtime.o rbinit.o]
32
+ $srcs = %w[input.mm runtime.mm rbinit.mm]
33
+
34
+ create_makefile('metal_runtime')
35
+
@@ -0,0 +1,99 @@
1
+ /*
2
+ * Metal Buffered Input
3
+ *
4
+ * Copyright (C) 2008 FURUHASHI Sadayuki
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #import "metal/input.h"
20
+ #import "metal/runtime.h"
21
+ #import <stdexcept>
22
+
23
+ namespace Metal {
24
+
25
+
26
+ static const unsigned UTF8_CHARLEN_TABLE[] = {
27
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
28
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
29
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
30
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
31
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
32
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
33
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
34
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
35
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
36
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0
40
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
41
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0
42
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 // 0xf0
43
+ };
44
+
45
+
46
+ BufferedInput::BufferedInput(const char* src, size_t len) :
47
+ m_cur(0), m_pos(src), m_endpos(m_pos+len)
48
+ { }
49
+
50
+ BufferedInput::~BufferedInput() {}
51
+
52
+ BufferedInput::at_t BufferedInput::at(size_t pos)
53
+ {
54
+ ssize_t dist = pos - m_cur;
55
+ if(dist == 0) {
56
+ // do nothing
57
+ return at_t(m_pos, charlen());
58
+ // } else if(dist == 1) {
59
+ // while(true) {
60
+ // ++m_pos;
61
+ // if(m_pos == m_endpos) { prev(); return at_t(NULL, 0); }
62
+ // if(charlen() != 0) { break; }
63
+ // }
64
+ // ++m_cur;
65
+ // return at_t(m_pos, charlen());
66
+ } else if(dist > 0) {
67
+ for(size_t i=0; i < (size_t)dist; ++i) {
68
+ while(true) {
69
+ ++m_pos;
70
+ if(m_pos == m_endpos) { prev(); return at_t(NULL, 0); }
71
+ if(charlen() != 0) { break; }
72
+ }
73
+ }
74
+ m_cur += dist;
75
+ return at_t(m_pos, charlen());
76
+ } else { // dist < 0
77
+ for(size_t i=-dist; i > 0; --i) {
78
+ prev();
79
+ }
80
+ m_cur += dist;
81
+ return at_t(m_pos, charlen());
82
+ }
83
+ }
84
+
85
+ void BufferedInput::prev()
86
+ {
87
+ do {
88
+ --m_pos;
89
+ } while(charlen() == 0);
90
+ }
91
+
92
+ unsigned BufferedInput::charlen()
93
+ {
94
+ return UTF8_CHARLEN_TABLE[(unsigned char)*m_pos];
95
+ }
96
+
97
+
98
+ } // namespace Metal
99
+
@@ -0,0 +1,17 @@
1
+ #import "ruby.h"
2
+ #import "metal.h"
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ void Init_metal_runtime()
9
+ {
10
+ VALUE mMetal = rb_define_module("Metal");
11
+ rb_define_class_under(mMetal, "ParserBase", rb_cObject);
12
+ }
13
+
14
+ #ifdef __cplusplus
15
+ }
16
+ #endif
17
+
@@ -0,0 +1,660 @@
1
+ /*
2
+ * Metal Runtime
3
+ *
4
+ * Copyright (C) 2008 FURUHASHI Sadayuki
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #import "metal.h"
20
+ #import <iostream>
21
+ #import <sstream>
22
+ #import <vector>
23
+ #import <string.h>
24
+ #import <oniguruma.h>
25
+
26
+ #ifdef OBJC_APPLE
27
+ #else
28
+ #import <objc/objc-api.h>
29
+ #endif
30
+
31
+ namespace Metal {
32
+
33
+
34
+ class ContextIMPL {
35
+ public:
36
+ ContextIMPL(id instance, VALUE rb_instance, Input& input);
37
+ ~ContextIMPL();
38
+
39
+ public:
40
+ inline VALUE apply(SEL method, Context* ctx);
41
+
42
+ inline VALUE act_or(Lambda** blocks);
43
+ inline VALUE act_many(Lambda* block);
44
+ inline VALUE act_many1(Lambda* block);
45
+ inline VALUE act_may(Lambda* block);
46
+ inline VALUE act_not(Lambda* block);
47
+ inline VALUE act_lookahead(Lambda* block);
48
+ inline VALUE act_char(const char* c, unsigned clen);
49
+ inline VALUE act_token(const char* s, unsigned slen);
50
+ inline VALUE act_any();
51
+ inline VALUE act_charclass(const char* s, unsigned slen);
52
+
53
+ inline VALUE act_run(Env& env, const char* code, unsigned code_len);
54
+ inline VALUE act_where(Env& env, const char* code, unsigned code_len);
55
+
56
+ inline VALUE act_end();
57
+
58
+ private:
59
+ void next_char();
60
+
61
+ private:
62
+ typedef size_t index_t;
63
+ index_t m_index;
64
+ Input& m_input;
65
+
66
+ id m_instance;
67
+ VALUE m_rb_instance;
68
+ std::string m_env_tmp_name;
69
+
70
+ // current character
71
+ const char* m_ccur;
72
+ unsigned m_ccur_len;
73
+
74
+ public:
75
+ class Backtrack;
76
+
77
+ private:
78
+ class ErrorMessage;
79
+ #ifdef __GNUC__
80
+ void backtrack(const std::string& msg) __attribute__((noreturn));
81
+ #else
82
+ void backtrack(const std::string& msg);
83
+ #endif
84
+ friend class ErrorMessage;
85
+
86
+ static inline ContextIMPL& impl(Context& ctx)
87
+ { return *ctx.m_impl; }
88
+
89
+ typedef std::vector<SEL> call_stack_t;
90
+ call_stack_t m_call_stack;
91
+
92
+ typedef std::vector<ErrorMessage*> error_history_t;
93
+ error_history_t m_error_history;
94
+
95
+ void clear_history();
96
+
97
+ private:
98
+ ContextIMPL(const ContextIMPL&);
99
+ ContextIMPL();
100
+ };
101
+
102
+
103
+ class ContextIMPL::ErrorMessage {
104
+ public:
105
+ ErrorMessage(const std::string& msg,
106
+ size_t index, call_stack_t& call_stack) :
107
+ m_message(msg),
108
+ m_index(index),
109
+ m_call_stack(call_stack)
110
+ { }
111
+ ~ErrorMessage() {}
112
+ public:
113
+ void message(std::ostream& stream, Context& ctx)
114
+ {
115
+ ContextIMPL& ctx_impl( ContextIMPL::impl(ctx) );
116
+ for(error_history_t::iterator it(ctx_impl.m_error_history.begin()),
117
+ it_end(ctx_impl.m_error_history.end());
118
+ it != it_end; ++it) {
119
+ (*it)->format(stream, ctx_impl);
120
+ }
121
+ }
122
+ private:
123
+ void format(std::ostream& stream, ContextIMPL& ctx_impl)
124
+ {
125
+ stream << "\n ";
126
+ for(call_stack_t::iterator it(m_call_stack.begin()),
127
+ it_end(m_call_stack.end());
128
+ it != it_end; ++it) {
129
+ #ifdef OBJC_APPLE
130
+ const char* name = sel_getName(*it) + strlen("rule_");
131
+ #else
132
+ const char* name = sel_get_name(*it) + strlen("rule_");
133
+ #endif
134
+ size_t len = strlen(name);
135
+ stream.write(name, len-1); // rule_end:
136
+ stream << "> ";
137
+ }
138
+ stream << "\n at index " << m_index << " " << m_message;
139
+ }
140
+
141
+ private:
142
+ const std::string m_message;
143
+ size_t m_index;
144
+ call_stack_t m_call_stack;
145
+ private:
146
+ ErrorMessage();
147
+ ErrorMessage(const ErrorMessage&);
148
+ };
149
+
150
+
151
+ class ContextIMPL::Backtrack {
152
+ public:
153
+ Backtrack(ErrorMessage* message) :
154
+ m_message(message) { }
155
+ public:
156
+ inline std::string message(Context& ctx)
157
+ {
158
+ std::ostringstream stream;
159
+ stream << "parse error:";
160
+ m_message->message(stream, ctx);
161
+ return stream.str();
162
+ }
163
+ private:
164
+ ErrorMessage* m_message;
165
+ private:
166
+ Backtrack();
167
+ };
168
+
169
+
170
+
171
+ class EnvIMPL {
172
+ public:
173
+ EnvIMPL() {}
174
+ ~EnvIMPL() {}
175
+ public:
176
+ inline VALUE& operator[](param_t key);
177
+ inline size_t size() const { return m_table.size(); }
178
+ inline bool empty() const { return m_table.empty(); }
179
+ private:
180
+ typedef std::vector< std::pair<param_t,VALUE> > table_t;
181
+ table_t m_table;
182
+ public:
183
+ typedef table_t::iterator iterator;
184
+ inline iterator begin() { return m_table.begin(); }
185
+ inline iterator end() { return m_table.end(); }
186
+ private:
187
+ static inline EnvIMPL& impl(Env& env)
188
+ { return *env.m_impl; }
189
+ friend class ContextIMPL;
190
+ private:
191
+ static void gc_mark(EnvIMPL* impl);
192
+ friend class Env;
193
+ };
194
+
195
+ Env::Env() :
196
+ m_impl( new EnvIMPL() )
197
+ {
198
+ m_gc_marker = Data_Wrap_Struct(
199
+ 0, (void (*)(void*))&EnvIMPL::gc_mark,
200
+ NULL, m_impl
201
+ );
202
+ }
203
+
204
+ Env::~Env() {
205
+ RDATA(m_gc_marker)->dmark = 0;
206
+ delete m_impl;
207
+ }
208
+
209
+ VALUE& Env::operator[](param_t key)
210
+ { return m_impl->operator[](key); }
211
+ VALUE& EnvIMPL::operator[](param_t key)
212
+ {
213
+ for(table_t::iterator it(m_table.begin()),
214
+ it_end(m_table.end());
215
+ it != it_end; ++it) {
216
+ if(it->first == key) {
217
+ return it->second;
218
+ }
219
+ }
220
+ m_table.push_back( table_t::value_type(key,Qnil) );
221
+ return m_table.back().second;
222
+ }
223
+
224
+ void EnvIMPL::gc_mark(EnvIMPL* impl)
225
+ {
226
+ for(table_t::iterator it(impl->m_table.begin()),
227
+ it_end(impl->m_table.end());
228
+ it != it_end; ++it) {
229
+ rb_gc_mark(it->second);
230
+ }
231
+ }
232
+
233
+
234
+
235
+ Context::Context(id instance, VALUE rb_instance, Input& input) :
236
+ m_impl( new ContextIMPL(instance, rb_instance, input) )
237
+ { }
238
+
239
+ Context::~Context()
240
+ {
241
+ delete m_impl;
242
+ }
243
+
244
+ static const char* ENV_TMP_NAME_PREFIX = "@metal_env";
245
+
246
+ ContextIMPL::ContextIMPL(id instance, VALUE rb_instance, Input& input) :
247
+ m_index(0),
248
+ m_input(input),
249
+ m_instance(instance),
250
+ m_rb_instance(rb_instance)
251
+ {
252
+ // FIXME
253
+ std::ostringstream stream;
254
+ stream << ENV_TMP_NAME_PREFIX;
255
+ stream << (unsigned long)FIX2ULONG( rb_obj_id(rb_instance) );
256
+ m_env_tmp_name = stream.str();
257
+ }
258
+
259
+ ContextIMPL::~ContextIMPL()
260
+ {
261
+ clear_history();
262
+ }
263
+
264
+
265
+ VALUE Context::apply(SEL method)
266
+ { return m_impl->apply(method, this); }
267
+ VALUE ContextIMPL::apply(SEL method, Context* ctx)
268
+ {
269
+ m_call_stack.push_back(method);
270
+ VALUE ret;
271
+ try {
272
+ #ifdef OBJC_APPLE
273
+ ret = (VALUE)objc_msgSend(m_instance, method, ctx);
274
+ #else
275
+ IMP imp = objc_msg_lookup(m_instance, method);
276
+ ret = (VALUE)(*imp)(m_instance, method, ctx);
277
+ #endif
278
+ } catch (...) {
279
+ m_call_stack.pop_back();
280
+ throw;
281
+ }
282
+ m_call_stack.pop_back();
283
+ return ret;
284
+ }
285
+
286
+
287
+ VALUE Context::act_or(Lambda** blocks)
288
+ { return m_impl->act_or(blocks); }
289
+ VALUE ContextIMPL::act_or(Lambda** blocks)
290
+ {
291
+ index_t pos = m_index;
292
+ do {
293
+ try {
294
+ VALUE ret = (*blocks)->call();
295
+ return ret;
296
+ } catch (Backtrack& e) {
297
+ m_index = pos;
298
+ }
299
+ ++blocks;
300
+ } while(*blocks != NULL);
301
+ backtrack("or failed");
302
+ }
303
+
304
+ VALUE Context::act_many(Lambda* block)
305
+ { return m_impl->act_many(block); }
306
+ VALUE ContextIMPL::act_many(Lambda* block)
307
+ {
308
+ VALUE ret = rb_ary_new();
309
+ while(true) {
310
+ index_t pos = m_index;
311
+ try {
312
+ rb_ary_push(ret, block->call());
313
+ if(pos == m_index) { return ret; } // XXX many in many avoidance
314
+ } catch (Backtrack& e) {
315
+ m_index = pos;
316
+ return ret;
317
+ }
318
+ }
319
+ }
320
+
321
+ VALUE Context::act_many1(Lambda* block)
322
+ { return m_impl->act_many1(block); }
323
+ VALUE ContextIMPL::act_many1(Lambda* block)
324
+ {
325
+ VALUE ret = rb_ary_new();
326
+ while(true) {
327
+ index_t pos = m_index;
328
+ try {
329
+ rb_ary_push(ret, block->call());
330
+ if(pos == m_index) { return ret; } // XXX many in many avoidance
331
+ } catch(Backtrack& e) {
332
+ m_index = pos;
333
+ if(RARRAY_LEN(ret) == 0) { throw; }
334
+ return ret;
335
+ }
336
+ }
337
+ }
338
+
339
+ VALUE Context::act_may(Lambda* block)
340
+ { return m_impl->act_may(block); }
341
+ VALUE ContextIMPL::act_may(Lambda* block)
342
+ {
343
+ index_t pos = m_index;
344
+ try {
345
+ return block->call();
346
+ } catch(Backtrack& e) {
347
+ m_index = pos;
348
+ return Qnil;
349
+ }
350
+ }
351
+
352
+ VALUE Context::act_not(Lambda* block)
353
+ { return m_impl->act_not(block); }
354
+ VALUE ContextIMPL::act_not(Lambda* block)
355
+ {
356
+ index_t pos = m_index;
357
+ bool ok;
358
+ try {
359
+ block->call();
360
+ ok = false;
361
+ } catch(Backtrack& e) {
362
+ ok = true;
363
+ }
364
+ m_index = pos;
365
+ if(!ok) {
366
+ backtrack("not prediction failed");
367
+ }
368
+ return Qnil;
369
+ }
370
+
371
+ VALUE Context::act_lookahead(Lambda* block)
372
+ { return m_impl->act_lookahead(block); }
373
+ VALUE ContextIMPL::act_lookahead(Lambda* block)
374
+ {
375
+ index_t pos = m_index;
376
+ try {
377
+ VALUE ret = block->call();
378
+ m_index = pos;
379
+ return ret;
380
+ } catch(Backtrack& e) {
381
+ m_index = pos;
382
+ throw;
383
+ }
384
+ }
385
+
386
+
387
+ VALUE Context::act_char(const char* c, unsigned clen)
388
+ { return m_impl->act_char(c, clen); }
389
+ VALUE ContextIMPL::act_char(const char* c, unsigned clen)
390
+ {
391
+ index_t pos = m_index;
392
+ next_char();
393
+ if(!( m_ccur_len==clen && memcmp(m_ccur,c,clen)==0 )) {
394
+ m_index = pos;
395
+ backtrack("act_char failed");
396
+ }
397
+ return rb_str_new(c, clen);
398
+ }
399
+
400
+ VALUE Context::act_token(const char* s, unsigned slen)
401
+ { return m_impl->act_token(s, slen); }
402
+ VALUE ContextIMPL::act_token(const char* s, unsigned slen)
403
+ {
404
+ index_t pos = m_index;
405
+ const char* c = s;
406
+ unsigned left = slen;
407
+ while(true) {
408
+ try {
409
+ next_char();
410
+ } catch(Backtrack& e) {
411
+ break;
412
+ }
413
+ if(!( m_ccur_len <= left && memcmp(m_ccur,c,m_ccur_len)==0 )) {
414
+ break;
415
+ }
416
+ left -= m_ccur_len;
417
+ if(left == 0) { return rb_str_new(s, slen); }
418
+ c += m_ccur_len;
419
+ }
420
+ m_index = pos;
421
+ backtrack("act_token failed");
422
+ }
423
+
424
+ VALUE Context::act_any()
425
+ { return m_impl->act_any(); }
426
+ VALUE ContextIMPL::act_any()
427
+ {
428
+ next_char();
429
+ return rb_str_new(m_ccur, m_ccur_len);
430
+ }
431
+
432
+
433
+ VALUE Context::act_charclass(const char* s, unsigned slen)
434
+ { return m_impl->act_charclass(s, slen); }
435
+ VALUE ContextIMPL::act_charclass(const char* s, unsigned slen)
436
+ {
437
+ // FIXME regexp precompile
438
+ index_t pos = m_index;
439
+
440
+ next_char();
441
+
442
+ regex_t* reg;
443
+ onig_new(&reg,
444
+ (const OnigUChar*)s, (const OnigUChar*)s+slen,
445
+ ONIG_OPTION_MULTILINE, ONIG_ENCODING_UTF8,
446
+ ONIG_SYNTAX_RUBY, NULL);
447
+ int ret = onig_match(reg,
448
+ (const OnigUChar*)m_ccur,
449
+ (const OnigUChar*)m_ccur+m_ccur_len,
450
+ (const OnigUChar*)m_ccur,
451
+ NULL, 0);
452
+ onig_free(reg);
453
+
454
+ if(ret < 0) {
455
+ m_index = pos;
456
+ backtrack("act_charclass failed");
457
+ } else {
458
+ return rb_str_new(m_ccur, m_ccur_len);
459
+ }
460
+ }
461
+
462
+ static VALUE act_run_eval(VALUE ary)
463
+ {
464
+ VALUE rbcode = rb_ary_entry(ary, 0);
465
+ VALUE klass = rb_ary_entry(ary, 1);
466
+ return rb_mod_module_eval(1, &rbcode, klass);
467
+ }
468
+
469
+ static VALUE act_run_rescue(VALUE rbcode) {
470
+ // FIXME
471
+ throw std::runtime_error( STR2CSTR(rb_eval_string("$!")) );
472
+ }
473
+
474
+ VALUE Context::act_run(Env& env, const char* code, unsigned code_len)
475
+ { return m_impl->act_run(env, code, code_len); }
476
+ VALUE ContextIMPL::act_run(Env& env, const char* code, unsigned code_len)
477
+ {
478
+ // instance variable -> local variable
479
+ EnvIMPL& env_impl( EnvIMPL::impl(env) );
480
+
481
+ VALUE rbcode;
482
+ VALUE klass = CLASS_OF(m_rb_instance);
483
+
484
+ if(env_impl.empty()) {
485
+ rbcode = rb_str_new(code, code_len);
486
+
487
+ } else {
488
+ // args = [a_value, b_value]
489
+ // ParserClass.instance_variable_set(env_name, args)
490
+ // begin
491
+ // ParserClass.instance_eval("a,b,=#{env_name}; #{code}")
492
+ // ensure
493
+ // ParserClass.instance_variable_set(env_name, Qnil)
494
+ // end
495
+
496
+ VALUE args = rb_ary_new2(env_impl.size());
497
+ rbcode = rb_str_buf_new(
498
+ env_impl.size()*4 + m_env_tmp_name.length() + code_len
499
+ ); // FIXME
500
+
501
+ for(EnvIMPL::iterator it(env_impl.begin()),
502
+ it_end(env_impl.end());
503
+ it != it_end; ++it) {
504
+ long itlen = strlen(it->first);
505
+ rb_ary_push(args, it->second);
506
+ rb_str_buf_cat(rbcode, it->first, itlen);
507
+ rb_str_buf_cat(rbcode, ",", 1);
508
+ }
509
+ rb_str_buf_cat(rbcode, "=", 1);
510
+ rb_str_buf_cat(rbcode, m_env_tmp_name.c_str(), m_env_tmp_name.length());
511
+ rb_str_buf_cat(rbcode, ";", 1);
512
+ rb_str_buf_cat(rbcode, code, code_len);
513
+
514
+ rb_iv_set(klass, m_env_tmp_name.c_str(), args);
515
+ }
516
+
517
+ VALUE ary = rb_ary_new2(2);
518
+ rb_ary_push(ary, rbcode);
519
+ rb_ary_push(ary, klass);
520
+
521
+ VALUE ret;
522
+ try {
523
+ ret = rb_rescue((VALUE(*)(ANYARGS))act_run_eval, ary,
524
+ (VALUE(*)(ANYARGS))act_run_rescue, rbcode);
525
+ } catch (...) {
526
+ rb_iv_set(klass, m_env_tmp_name.c_str(), Qnil);
527
+ throw;
528
+ }
529
+ rb_iv_set(klass, m_env_tmp_name.c_str(), Qnil);
530
+
531
+ return ret;
532
+ }
533
+
534
+ VALUE Context::act_where(Env& env, const char* code, unsigned code_len)
535
+ { return m_impl->act_where(env, code, code_len); }
536
+ VALUE ContextIMPL::act_where(Env& env, const char* code, unsigned code_len)
537
+ {
538
+ VALUE ret = act_run(env, code, code_len);
539
+ if(ret == Qfalse || ret == Qnil) {
540
+ backtrack("where prediction failed");
541
+ }
542
+ return ret;
543
+ }
544
+
545
+
546
+ VALUE Context::act_end()
547
+ { return m_impl->act_end(); }
548
+ VALUE ContextIMPL::act_end()
549
+ {
550
+ size_t pos = m_index;
551
+ bool ok;
552
+ try {
553
+ next_char();
554
+ ok = false;
555
+ } catch(Backtrack& e) {
556
+ ok = true;
557
+ }
558
+ m_index = pos;
559
+ if(!ok) {
560
+ backtrack("unexpected character 'NOT IMPLEMENTED', EOF expected");
561
+ }
562
+ return Qnil;
563
+ }
564
+
565
+
566
+ void ContextIMPL::next_char()
567
+ {
568
+ Input::at_t c( m_input.at(m_index) );
569
+ if(c.pos == NULL) {
570
+ backtrack("unexpected end of input");
571
+ }
572
+ m_ccur = c.pos;
573
+ m_ccur_len = c.charlen;
574
+ ++m_index;
575
+ }
576
+
577
+
578
+ void ContextIMPL::backtrack(const std::string& msg)
579
+ {
580
+ ErrorMessage* err = new ErrorMessage(msg, m_index, m_call_stack);
581
+ m_error_history.push_back(err);
582
+ throw Backtrack(err);
583
+ }
584
+
585
+ void ContextIMPL::clear_history()
586
+ {
587
+ for(error_history_t::iterator it(m_error_history.begin()),
588
+ it_end(m_error_history.end());
589
+ it != it_end; ++it) {
590
+ delete *it;
591
+ }
592
+ }
593
+
594
+
595
+ class ParameterMap {
596
+ public:
597
+ param_t operator[](const char* at_name);
598
+ private:
599
+ typedef std::vector< std::pair<const char*,param_t> > table_t;
600
+ table_t m_table;
601
+ private:
602
+ void clear_table();
603
+ };
604
+
605
+ param_t ParameterMap::operator[](const char* name)
606
+ {
607
+ for(table_t::iterator it(m_table.begin()),
608
+ it_end(m_table.end());
609
+ it != it_end; ++it) {
610
+ if(strcmp(it->first,name) == 0) {
611
+ return it->second;
612
+ }
613
+ }
614
+ m_table.push_back( table_t::value_type(name,name) );
615
+ return name;
616
+ }
617
+
618
+ void ParameterMap::clear_table()
619
+ {
620
+ for(table_t::iterator it(m_table.begin()),
621
+ it_end(m_table.end());
622
+ it != it_end; ++it) {
623
+ free((void*)it->second);
624
+ }
625
+ }
626
+
627
+ param_t param_lookup(const char* name)
628
+ {
629
+ static ParameterMap map;
630
+ return map[name];
631
+ }
632
+
633
+
634
+ } // namespace Metal
635
+
636
+
637
+ @implementation MetalParserBase
638
+ -(id)init:(VALUE)rb_instance
639
+ {
640
+ self = [super init];
641
+ if(self != nil) {
642
+ instance = rb_instance;
643
+ }
644
+ return self;
645
+ }
646
+ -(VALUE)parse:(Metal::Input&)input withRule:(SEL)name
647
+ {
648
+ Metal::Context ctx((id)self, instance, input);
649
+ try {
650
+ return ctx.apply(name); // FIXME
651
+ } catch (Metal::ContextIMPL::Backtrack& e) {
652
+ throw Metal::ParseError(e.message(ctx));
653
+ }
654
+ }
655
+ -(VALUE)parse:(Metal::Input&)input
656
+ {
657
+ return [self parse:input withRule:@selector(rule_main:)];
658
+ }
659
+ @end
660
+