M compiler.rb => compiler.rb +8 -7
@@ 276,13 276,14 @@ class Compiler
end
{
- '>' => VM::CMP_GT,
- '>=' => VM::CMP_GTE,
- '<' => VM::CMP_LT,
- '<=' => VM::CMP_LTE,
- '=' => VM::CMP_EQ,
- '+' => VM::ADD,
- '-' => VM::SUB
+ '+' => VM::ADD,
+ '-' => VM::SUB,
+ '>' => VM::CMP_GT,
+ '>=' => VM::CMP_GTE,
+ '<' => VM::CMP_LT,
+ '<=' => VM::CMP_LTE,
+ '=' => VM::CMP_EQ_NUM,
+ 'eq?' => VM::CMP_EQ
}.each do |name, instruction|
define_method(name) do |args, options|
compare(instruction, args, options)
M spec/compiler_spec.rb => spec/compiler_spec.rb +22 -9
@@ 644,6 644,23 @@ describe Compiler do
end
end
+ context 'eq?' do
+ before do
+ @result = subject.compile([
+ ['eq?', '1', '1']
+ ])
+ end
+
+ it 'compiles into vm instructions' do
+ expect(d(@result)).to eq([
+ 'VM::PUSH_NUM', '1',
+ 'VM::PUSH_NUM', '1',
+ 'VM::CMP_EQ',
+ 'VM::HALT'
+ ])
+ end
+ end
+
context '=' do
before do
@result = subject.compile([
@@ 655,7 672,7 @@ describe Compiler do
expect(d(@result)).to eq([
'VM::PUSH_NUM', '1',
'VM::PUSH_NUM', '1',
- 'VM::CMP_EQ',
+ 'VM::CMP_EQ_NUM',
'VM::HALT'
])
end
@@ 665,16 682,14 @@ describe Compiler do
context 'given value is not used' do
before do
@result = subject.compile([
- ['if', ['=', '1', '1'], '2', '3'],
+ ['if', '#t', '2', '3'],
'0'
])
end
it 'compiles into vm instructions' do
expect(d(@result)).to eq([
- 'VM::PUSH_NUM', '1',
- 'VM::PUSH_NUM', '1',
- 'VM::CMP_EQ',
+ 'VM::PUSH_TRUE',
'VM::JUMP_IF_FALSE', 5,
'VM::PUSH_NUM', '2',
'VM::JUMP', 3,
@@ 689,15 704,13 @@ describe Compiler do
context 'given value is used' do
before do
@result = subject.compile([
- ['print', ['if', ['=', '1', '1'], '2', '3']]
+ ['print', ['if', '#t', '2', '3']]
])
end
it 'compiles into vm instructions' do
expect(d(@result)).to eq([
- 'VM::PUSH_NUM', '1',
- 'VM::PUSH_NUM', '1',
- 'VM::CMP_EQ',
+ 'VM::PUSH_TRUE',
'VM::JUMP_IF_FALSE', 5,
'VM::PUSH_NUM', '2',
'VM::JUMP', 3,
M spec/vm_spec.rb => spec/vm_spec.rb +37 -0
@@ 641,6 641,41 @@ describe VM do
VM::PUSH_NUM, '1',
VM::PUSH_NUM, '2',
VM::CMP_EQ,
+ VM::PUSH_TRUE,
+ VM::PUSH_TRUE,
+ VM::CMP_EQ,
+ VM::PUSH_TRUE,
+ VM::PUSH_FALSE,
+ VM::CMP_EQ,
+ VM::HALT
+ ])
+ end
+
+ it 'removes both values and puts a #t or #f on the stack' do
+ expect(subject.stack_values).to eq([
+ VM::BoolTrue.instance,
+ VM::BoolFalse.instance,
+ VM::BoolTrue.instance,
+ VM::BoolFalse.instance
+ ])
+ end
+ end
+
+ describe 'CMP_EQ_NUM' do
+ before do
+ subject.execute([
+ VM::PUSH_NUM, '1',
+ VM::PUSH_NUM, '1',
+ VM::CMP_EQ_NUM,
+ VM::PUSH_NUM, '1',
+ VM::PUSH_NUM, '2',
+ VM::CMP_EQ_NUM,
+ VM::PUSH_TRUE,
+ VM::PUSH_TRUE,
+ VM::CMP_EQ_NUM,
+ VM::PUSH_TRUE,
+ VM::PUSH_FALSE,
+ VM::CMP_EQ_NUM,
VM::HALT
])
end
@@ 648,6 683,8 @@ describe VM do
it 'removes both values and puts a #t or #f on the stack' do
expect(subject.stack_values).to eq([
VM::BoolTrue.instance,
+ VM::BoolFalse.instance,
+ VM::BoolFalse.instance,
VM::BoolFalse.instance
])
end
M vm.rb => vm.rb +5 -0
@@ 38,6 38,7 @@ class VM
['CMP_LT', 0],
['CMP_LTE', 0],
['CMP_EQ', 0],
+ ['CMP_EQ_NUM', 0],
['CMP_NULL', 0],
['DUP', 0],
['ENDF', 0],
@@ 174,6 175,10 @@ class VM
num2 = pop_val
num1 = pop_val
num1 == num2 ? push_true : push_false
+ when CMP_EQ_NUM
+ num2 = pop_val
+ num1 = pop_val
+ num1.is_a?(Int) && num2.is_a?(Int) && num1 == num2 ? push_true : push_false
when CMP_NULL
val = pop_val
val == EmptyList.instance ? push_true : push_false