-
Notifications
You must be signed in to change notification settings - Fork 1
/
ocelot.rb
135 lines (115 loc) · 2.38 KB
/
ocelot.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
require 'redparse'
class RedParse::Node
def toplevel_ocelot_compile(env)
return ocelot_compile(env)
end
def ocelot_compile_funcall(env, recv, name, *params)
return env.scope {
s = ''
if recv then
s << recv.ocelot_compile(env)
s << "VALUE recv = result;\n"
else
s << "VALUE recv = self;\n"
end
s << %Q{ID name = rb_intern("#{name}");\n}
argc = params.size
s << "VALUE argv[#{argc}];\n"
params.each_with_index { |param, idx|
s << param.ocelot_compile(env)
s << "argv[#{idx}] = result;\n"
}
s << %Q{result = rb_funcall2(recv, name, #{argc}, argv);\n}
s
}
end
end
class RedParse::SequenceNode
def toplevel_ocelot_compile(env)
s = ''
self.each do |child|
s << child.ocelot_compile(env) << ";\n"
end
return s
end
end
class RedParse::LiteralNode
def ocelot_compile(env)
return %Q{result = rb_eval_string("#{val}");\n}
end
end
class RedParse::CallSiteNode
def ocelot_compile(env)
fail if block
return self.ocelot_compile_funcall(
env,
receiver,
name,
*params)
end
end
module RedParse::OpNode
def ocelot_compile(env)
return self.ocelot_compile_funcall(
env,
left,
op,
right)
end
end
module Ocelot
class CompileEnvironment
attr_reader :indent_level
def indent_block(&block)
t = yield
t.gsub!(/^/, " ")
return t
end
def scope(&block)
s = "{\n"
s << indent_block(&block)
s << "}\n"
return s
end
end
PROGRAM_TEMPLATE = <<END
#include <ruby.h>
VALUE run_program()
{
VALUE result;
VALUE self = rb_cObject; /* TODO: should be toplevel object */
%{statement_list}
return result;
}
int main(int argc, char * argv[])
{
char * dummy_argv[] = { argv[0], "-e", "" };
RUBY_INIT_STACK;
ruby_init();
ruby_options(3, dummy_argv);
ruby_script("ocelot");
run_program();
return 0;
}
END
class Compiler
def compile(tree)
env = Ocelot::CompileEnvironment.new
statement_list = env.indent_block {
tree.toplevel_ocelot_compile(env)
}
PROGRAM_TEMPLATE.sub("%{statement_list}", statement_list)
end
end
end
if $0 == __FILE__ then
s = "puts 42; puts 1+1"
# s = "puts 42"
p = RedParse.new(s)
tree = p.parse()
require 'pp'
# pp tree
compiler = Ocelot::Compiler.new
output = compiler.compile(tree)
puts output
end