Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6f2dcce

Browse files
authored
Merge pull request #224 from ruby-syntax-tree/more-compilations
Assembler
2 parents 9136254 + 9d57b6a commit 6f2dcce

File tree

8 files changed

+694
-438
lines changed

8 files changed

+694
-438
lines changed

lib/syntax_tree.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
require_relative "syntax_tree/yarv"
3131
require_relative "syntax_tree/yarv/bf"
3232
require_relative "syntax_tree/yarv/compiler"
33-
require_relative "syntax_tree/yarv/disasm_formatter"
33+
require_relative "syntax_tree/yarv/assembler"
34+
require_relative "syntax_tree/yarv/decompiler"
3435
require_relative "syntax_tree/yarv/disassembler"
3536
require_relative "syntax_tree/yarv/instruction_sequence"
3637
require_relative "syntax_tree/yarv/instructions"

lib/syntax_tree/yarv/assembler.rb

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# frozen_string_literal: true
2+
3+
module SyntaxTree
4+
module YARV
5+
class Assembler
6+
class ObjectVisitor < Compiler::RubyVisitor
7+
def visit_dyna_symbol(node)
8+
if node.parts.empty?
9+
:""
10+
else
11+
raise CompilationError
12+
end
13+
end
14+
15+
def visit_string_literal(node)
16+
case node.parts.length
17+
when 0
18+
""
19+
when 1
20+
raise CompilationError unless node.parts.first.is_a?(TStringContent)
21+
node.parts.first.value
22+
else
23+
raise CompilationError
24+
end
25+
end
26+
end
27+
28+
attr_reader :filepath
29+
30+
def initialize(filepath)
31+
@filepath = filepath
32+
end
33+
34+
def assemble
35+
iseq = InstructionSequence.new(:top, "<main>", nil, Location.default)
36+
labels = {}
37+
38+
File.foreach(filepath, chomp: true) do |line|
39+
case line.strip
40+
when ""
41+
# skip over blank lines
42+
next
43+
when /^;/
44+
# skip over comments
45+
next
46+
when /^(\w+):$/
47+
# create labels
48+
iseq.push(labels[$1] = iseq.label)
49+
next
50+
end
51+
52+
insn, operands = line.split(" ", 2)
53+
54+
case insn
55+
when "adjuststack"
56+
iseq.adjuststack(parse_number(operands))
57+
when "anytostring"
58+
iseq.anytostring
59+
when "checkmatch"
60+
iseq.checkmatch(parse_number(operands))
61+
when "checktype"
62+
iseq.checktype(parse_number(operands))
63+
when "concatarray"
64+
iseq.concatarray
65+
when "concatstrings"
66+
iseq.concatstrings(parse_number(operands))
67+
when "dup"
68+
iseq.dup
69+
when "dupn"
70+
iseq.dupn(parse_number(operands))
71+
when "duparray"
72+
object = parse(operands)
73+
raise unless object.is_a?(Array)
74+
75+
iseq.duparray(object)
76+
when "duphash"
77+
object = parse(operands)
78+
raise unless object.is_a?(Hash)
79+
80+
iseq.duphash(object)
81+
when "getinstancevariable"
82+
object = parse(operands)
83+
raise unless object.is_a?(Symbol)
84+
85+
iseq.getinstancevariable(object)
86+
when "intern"
87+
iseq.intern
88+
when "leave"
89+
iseq.leave
90+
when "newarray"
91+
iseq.newarray(parse_number(operands))
92+
when "newrange"
93+
object = parse(operands)
94+
raise if object != 0 && object != 1
95+
96+
iseq.newrange(operands.to_i)
97+
when "nop"
98+
iseq.nop
99+
when "objtostring"
100+
iseq.objtostring(
101+
YARV.calldata(
102+
:to_s,
103+
0,
104+
CallData::CALL_ARGS_SIMPLE | CallData::CALL_FCALL
105+
)
106+
)
107+
when "opt_and"
108+
iseq.send(YARV.calldata(:&, 1))
109+
when "opt_aref"
110+
iseq.send(YARV.calldata(:[], 1))
111+
when "opt_aref_with"
112+
object = parse(operands)
113+
raise unless object.is_a?(String)
114+
115+
iseq.opt_aref_with(object, YARV.calldata(:[], 1))
116+
when "opt_div"
117+
iseq.send(YARV.calldata(:/, 1))
118+
when "opt_empty_p"
119+
iseq.send(
120+
YARV.calldata(
121+
:empty?,
122+
0,
123+
CallData::CALL_ARGS_SIMPLE | CallData::CALL_FCALL
124+
)
125+
)
126+
when "opt_eqeq"
127+
iseq.send(YARV.calldata(:==, 1))
128+
when "opt_ge"
129+
iseq.send(YARV.calldata(:>=, 1))
130+
when "opt_getconstant_path"
131+
object = parse(operands)
132+
raise unless object.is_a?(Array)
133+
134+
iseq.opt_getconstant_path(object)
135+
when "opt_ltlt"
136+
iseq.send(YARV.calldata(:<<, 1))
137+
when "opt_minus"
138+
iseq.send(YARV.calldata(:-, 1))
139+
when "opt_mult"
140+
iseq.send(YARV.calldata(:*, 1))
141+
when "opt_or"
142+
iseq.send(YARV.calldata(:|, 1))
143+
when "opt_plus"
144+
iseq.send(YARV.calldata(:+, 1))
145+
when "pop"
146+
iseq.pop
147+
when "putnil"
148+
iseq.putnil
149+
when "putobject"
150+
iseq.putobject(parse(operands))
151+
when "putself"
152+
iseq.putself
153+
when "putstring"
154+
object = parse(operands)
155+
raise unless object.is_a?(String)
156+
157+
iseq.putstring(object)
158+
when "send"
159+
iseq.send(calldata(operands))
160+
when "setinstancevariable"
161+
object = parse(operands)
162+
raise unless object.is_a?(Symbol)
163+
164+
iseq.setinstancevariable(object)
165+
when "swap"
166+
iseq.swap
167+
when "toregexp"
168+
options, length = operands.split(", ")
169+
iseq.toregexp(parse_number(options), parse_number(length))
170+
else
171+
raise "Could not understand: #{line}"
172+
end
173+
end
174+
175+
iseq.compile!
176+
iseq
177+
end
178+
179+
def self.assemble(filepath)
180+
new(filepath).assemble
181+
end
182+
183+
private
184+
185+
def parse(value)
186+
program = SyntaxTree.parse(value)
187+
raise if program.statements.body.length != 1
188+
189+
program.statements.body.first.accept(ObjectVisitor.new)
190+
end
191+
192+
def parse_number(value)
193+
object = parse(value)
194+
raise unless object.is_a?(Integer)
195+
196+
object
197+
end
198+
199+
def calldata(value)
200+
message, argc_value, flags_value = value.split
201+
flags =
202+
if flags_value
203+
flags_value
204+
.split("|")
205+
.map do |flag|
206+
case flag
207+
when "ARGS_SPLAT"
208+
CallData::CALL_ARGS_SPLAT
209+
when "ARGS_BLOCKARG"
210+
CallData::CALL_ARGS_BLOCKARG
211+
when "FCALL"
212+
CallData::CALL_FCALL
213+
when "VCALL"
214+
CallData::CALL_VCALL
215+
when "ARGS_SIMPLE"
216+
CallData::CALL_ARGS_SIMPLE
217+
when "BLOCKISEQ"
218+
CallData::CALL_BLOCKISEQ
219+
when "KWARG"
220+
CallData::CALL_KWARG
221+
when "KW_SPLAT"
222+
CallData::CALL_KW_SPLAT
223+
when "TAILCALL"
224+
CallData::CALL_TAILCALL
225+
when "SUPER"
226+
CallData::CALL_SUPER
227+
when "ZSUPER"
228+
CallData::CALL_ZSUPER
229+
when "OPT_SEND"
230+
CallData::CALL_OPT_SEND
231+
when "KW_SPLAT_MUT"
232+
CallData::CALL_KW_SPLAT_MUT
233+
end
234+
end
235+
.inject(:|)
236+
else
237+
CallData::CALL_ARGS_SIMPLE
238+
end
239+
240+
YARV.calldata(message.to_sym, argc_value&.to_i || 0, flags)
241+
end
242+
end
243+
end
244+
end

lib/syntax_tree/yarv/compiler.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,18 @@ def visit_imaginary(node)
148148
end
149149

150150
def visit_int(node)
151-
node.value.to_i
151+
case (value = node.value)
152+
when /^0b/
153+
value[2..].to_i(2)
154+
when /^0o/
155+
value[2..].to_i(8)
156+
when /^0d/
157+
value[2..].to_i
158+
when /^0x/
159+
value[2..].to_i(16)
160+
else
161+
value.to_i
162+
end
152163
end
153164

154165
def visit_label(node)

0 commit comments

Comments
 (0)