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.
- data/Manifest.txt +14 -1
- data/bin/metal +63 -16
- data/bin/metal-run +16 -13
- data/config/hoe.rb +4 -2
- data/ext/metal/boot/metal_boot.h +32 -0
- data/{lib/metal/boot.metal → ext/metal/boot/metal_boot.metal} +40 -53
- data/ext/metal/boot/metal_boot.mm +1294 -0
- data/ext/metal/boot/metal_boot_extconf.rb +16 -0
- data/ext/metal/boot/metal_boot_rb.mm +20 -0
- data/ext/metal/runtime/extconf.rb +35 -0
- data/ext/metal/runtime/input.mm +99 -0
- data/ext/metal/runtime/rbinit.mm +17 -0
- data/ext/metal/runtime/runtime.mm +660 -0
- data/include/metal.h +4 -0
- data/include/metal/exception.h +15 -0
- data/include/metal/input.h +42 -0
- data/include/metal/rbcode.h +24 -0
- data/include/metal/runtime.h +97 -0
- data/lib/metal/boot.rb +1 -353
- data/lib/metal/generator.rb +313 -203
- data/lib/metal/runtime.rb +1 -386
- data/lib/metal/version.rb +1 -1
- metadata +32 -8
|
@@ -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(®,
|
|
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
|
+
|