spec/interpreter/interpreter_spec.rb in nudge-0.0.2 vs spec/interpreter/interpreter_spec.rb in nudge-0.1.0

- old
+ new

@@ -1,25 +1,21 @@ +#encoding: utf-8 require File.join(File.dirname(__FILE__), "/../spec_helper") - include Nudge describe "initialization" do before(:each) do @ii = Interpreter.new() @ii.clear_stacks end - it "should have a #parser, which defaults to a new NudgeLanguageParser" do - @ii.parser.should be_a_kind_of(NudgeLanguageParser) - end - - it "should have an empty stacks Hash, empty initially" do + it "should have a #stacks Hash" do @ii.stacks.should == {} end - it "should keep have an empty instructions attribute, a Hash" do - @ii.instructions_library.should == Hash.new + it "should keep have (by default) a complete #instructions Hash" do + @ii.instructions_library.should_not == {} end it "should automatically create an entry if an unmentioned stack is referenced by a method" do lambda{@ii.stacks[:pirate].peek}.should_not raise_error @ii.stacks.should include(:pirate) @@ -31,54 +27,54 @@ @ii.stacks.should_not include(:robot) lambda{@ii.stacks[:robot].pop}.should_not raise_error @ii.stacks.should include(:robot) end - it "should respond to #reset(listing) by parsing the listing and pushing it onto its exec stack" do - checker = NudgeLanguageParser.new() + it "should respond to #reset(blueprint) by parsing the blueprint and pushing it onto its exec stack" do myCode = "ref x" @ii.reset(myCode) @ii.stacks.should include(:exec) @ii.stacks[:exec].should be_a_kind_of(Stack) @ii.stacks[:exec].depth.should == 1 - @ii.stacks[:exec].peek.should be_a_kind_of(ChannelPoint) - @ii.stacks[:exec].peek.name.should == checker.parse(myCode).to_points.name + @ii.stacks[:exec].peek.should be_a_kind_of(ReferencePoint) + @ii.stacks[:exec].peek.name.should == "x" end it "#reset should reset the #steps counter, too" do @ii.steps = 100 @ii.reset("channel x") @ii.steps.should == 0 end it "should load a complex CodeBlock as a single item on the exec stack" do - checker = NudgeLanguageParser.new() myCode = "block {\ndo foo\n do bar\n block {\ndo baz}}" @ii.reset(myCode) @ii.stacks.should include(:exec) @ii.stacks[:exec].depth.should == 1 whatGotPushed = @ii.stacks[:exec].peek - whatGotPushed.should be_a_kind_of(CodeBlock) - whatGotPushed.contents.length.should == checker.parse(myCode).to_points.contents.length + whatGotPushed.should be_a_kind_of(CodeblockPoint) + whatGotPushed.contents.length.should == 3 whatGotPushed.contents[1].name.should == "bar" whatGotPushed.contents[2].contents[0].name.should == "baz" end - it "should accept a listing, which should default to an empty string" do - ij = Interpreter.new(program:"literal int(7)") - ij.stacks[:exec].peek.should be_a_kind_of(LiteralPoint) + it "should accept a blueprint, which should default to an empty string" do + Interpreter.new(program:"value «int» \n«int» 7").program.should == "value «int» \n«int» 7" + # Interpreter.new().program.should == "" end it "should have an #enable method that works for Instructions, adding them to the #instructions hash" do + @ii.disable_all_instructions @ii.instructions_library.should == {} @ii.enable(IntAddInstruction) @ii.instructions_library[IntAddInstruction].should_not== nil @ii.instructions_library[IntAddInstruction].should be_a_kind_of(IntAddInstruction) @ii.instructions_library[IntAddInstruction].context.should == @ii end it "should have an #enable_all_instructions method" do + @ii.disable_all_instructions @ii.instructions_library.should == {} @ii.enable_all_instructions @ii.instructions_library.keys.should == Instruction.all_instructions end @@ -100,31 +96,36 @@ it "should be an empty hash initially (by deafult)" do @ii.variables.should == {} end it "should create a new entry when #bind_variable is called" do - @ii.bind_variable("x",LiteralPoint.new(:int,88)) - @ii.variables["x"].should be_a_kind_of(LiteralPoint) + @ii.bind_variable("x",ValuePoint.new(:int,"88")) + @ii.variables["x"].should be_a_kind_of(ValuePoint) @ii.variables["x"].type.should == :int - @ii.variables["x"].value.should == 88 + @ii.variables["x"].raw.should == "88" end - it "should raise an exception if the bound value is anything but a LiteralPoint" do + it "should raise an exception if the bound value is anything but a ProgramPoint" do lambda {@ii.bind_variable("x", 88)}.should raise_error(ArgumentError) lambda {@ii.bind_variable("x", [1,2])}.should raise_error(ArgumentError) lambda {@ii.bind_variable("x", nil)}.should raise_error(ArgumentError) + + lambda {@ii.bind_variable("x", ValuePoint.new("int", 88))}.should_not raise_error(ArgumentError) + lambda {@ii.bind_variable("x", ReferencePoint.new("x2"))}.should_not raise_error(ArgumentError) + lambda {@ii.bind_variable("x", InstructionPoint.new("matrix_a"))}.should_not raise_error(ArgumentError) + lambda {@ii.bind_variable("x", CodeblockPoint.new([]))}.should_not raise_error(ArgumentError) end it "should remove an new entry when #unbind_variable is called" do - @ii.bind_variable("x",LiteralPoint.new(:int,88)) - @ii.variables["x"].value.should == 88 + @ii.bind_variable("x",ValuePoint.new(:int,"99")) + @ii.variables["x"].raw.should == "99" @ii.unbind_variable("x") @ii.variables["x"].should == nil end it "should be resettable" do - @ii.bind_variable("x",LiteralPoint.new(:int,88)) + @ii.bind_variable("x",ValuePoint.new(:int,"77")) @ii.reset_variables @ii.variables.should_not include("x") end end @@ -132,41 +133,41 @@ it "should be an empty hash initially" do @ii.names.should == {} end it "should create a new entry when #bind_name is called" do - @ii.bind_name("x",LiteralPoint.new(:bool,false)) - @ii.names["x"].should be_a_kind_of(LiteralPoint) + @ii.bind_name("x",ValuePoint.new(:bool,"false")) + @ii.names["x"].should be_a_kind_of(ValuePoint) @ii.names["x"].type.should == :bool - @ii.names["x"].value.should == false + @ii.names["x"].raw.should == "false" end - it "should raise an exception if the bound value is anything but a LiteralPoint" do + it "should raise an exception if the bound value is anything but a ValuePoint" do lambda {@ii.bind_name("x", 88)}.should raise_error(ArgumentError) lambda {@ii.bind_name("x", [1,2])}.should raise_error(ArgumentError) lambda {@ii.bind_name("x", nil)}.should raise_error(ArgumentError) end it "should remove an new entry when #unbind_name is called" do - @ii.bind_name("x",LiteralPoint.new(:int,88)) - @ii.names["x"].value.should == 88 + @ii.bind_name("x",ValuePoint.new(:int,"55")) + @ii.names["x"].raw.should == "55" @ii.unbind_name("x") @ii.names["x"].should == nil end it "should be resettable" do - @ii.bind_name("x",LiteralPoint.new(:int,88)) + @ii.bind_name("x",ValuePoint.new(:int,"44")) @ii.reset_names @ii.names.should_not include("x") end end describe "references" do it "should return an Array of keys obtained by mergine variables into names (not vice versa)" do - @ii.bind_name("x",LiteralPoint.new(:int,88)) - @ii.bind_variable("y",LiteralPoint.new(:int,88)) - @ii.bind_name("y",LiteralPoint.new(:bool,false)) + @ii.bind_name("x",ValuePoint.new(:foo,"bar")) + @ii.bind_variable("y",ValuePoint.new(:baz,"qux")) + @ii.bind_name("y",ValuePoint.new(:bool,"false")) @ii.references.should == @ii.names.merge(@ii.variables).keys @ii.references.should_not == @ii.variables.merge(@ii.names).keys end end @@ -200,13 +201,168 @@ @ii.enable(IntType) @ii.enable(IntType) @ii.types.length.should == 1 end end +end + + +describe "Interpreter#peek" do + before(:each) do + @ii = Interpreter.new() + @ii.clear_stacks + end + it "should invoke a particular stack's #peek method" do + @ii.stacks[:donut].push(ValuePoint.new("donut", "0")) + lambda{@ii.peek(:donut)}.should_not raise_error + @ii.peek(:donut).value.should == "0" + end + + it "should return nil if the stack doesn't exist" do + lambda{@ii.peek(:nonexistent)}.should_not raise_error + @ii.peek(:nonexistent).should == nil + end + + it "should validate the stackname as a symbol" do + lambda{@ii.peek("not there")}.should raise_error(ArgumentError) + lambda{@ii.peek(99)}.should raise_error(ArgumentError) + end end + + +describe "Interpreter#peek_value" do + before(:each) do + @ii = Interpreter.new() + @ii.clear_stacks + end + + it "should invoke a particular stack's #peek method" do + @ii.stacks[:donut].push(ValuePoint.new("donut", "0")) + lambda{@ii.peek_value(:donut)}.should_not raise_error + @ii.stacks[:donut].push(ValuePoint.new("donut", "O")) + @ii.peek_value(:donut).should == "O" + end + + it "should return the value, not the entire ValuePoint" do + @ii.stacks[:int].push(ValuePoint.new("int", "8817")) + @ii.peek_value(:int).should == 8817 + end + + + it "should return nil if the stack doesn't exist" do + lambda{@ii.peek_value(:nonexistent)}.should_not raise_error + @ii.peek_value(:nonexistent).should == nil + end + + it "should validate the stackname as a symbol" do + lambda{@ii.peek_value("not there")}.should raise_error(ArgumentError) + lambda{@ii.peek_value(99)}.should raise_error(ArgumentError) + end +end + + +describe "Interpreter#pop" do + before(:each) do + @ii = Interpreter.new() + @ii.clear_stacks + end + + it "should invoke a particular stack's #pop method" do + @ii.stacks[:crown].push(ValuePoint.new("crown", "WWW")) + lambda{@ii.pop(:crown)}.should_not raise_error + + @ii.stacks[:crown].push(ValuePoint.new("crown", "WWW")) + got_crown = @ii.pop(:crown) + got_crown.should be_a_kind_of(ValuePoint) + got_crown.value.should == "WWW" + end + + it "should return nil if the stack doesn't exist" do + lambda{@ii.pop(:nonexistent)}.should_not raise_error + @ii.pop(:nonexistent).should == nil + end + + it "should validate the stackname as a symbol" do + lambda{@ii.pop("not there")}.should raise_error(ArgumentError) + lambda{@ii.pop(99)}.should raise_error(ArgumentError) + end +end + + +describe "Interpreter#pop_value" do + before(:each) do + @ii = Interpreter.new() + @ii.clear_stacks + end + + it "should invoke a particular stack's #pop method" do + @ii.stacks[:box].push(ValuePoint.new("box", "[_]")) + lambda{@ii.pop_value(:box)}.should_not raise_error + + @ii.stacks[:box].push(ValuePoint.new("box", "[_]")) + holder = @ii.pop_value(:box) + holder.should be_a_kind_of(String) + holder.should == "[_]" + end + + it "should return nil if the stack doesn't exist" do + lambda{@ii.pop_value(:nonexistent)}.should_not raise_error + @ii.pop_value(:nonexistent).should == nil + end + + it "should validate the stackname as a symbol" do + lambda{@ii.pop_value("not there")}.should raise_error(ArgumentError) + lambda{@ii.pop_value(99)}.should raise_error(ArgumentError) + end +end + + +describe "Interpreter#push" do + before(:each) do + @ii = Interpreter.new() + @ii.clear_stacks + end + + it "should invoke a particular stack's #push method" do + lambda{@ii.push(:int,"9")}.should_not raise_error + + @ii.push(:foo,"bar") + @ii.pop_value(:foo).should == "bar" + + @ii.push(:baz,"qux") + @ii.peek(:baz).should be_a_kind_of(ValuePoint) + @ii.peek(:baz).value.should == "qux" + end + + it "should allow passing in valid non-string values for that type" do + @ii.push(:int,9182) + @ii.pop_value(:int).should == 9182 + + @ii.push(:float,8.765) + @ii.pop_value(:float).should == 8.765 + + @ii.push(:bool,true) + @ii.pop_value(:bool).should == true + + @ii.push(:bool,false) + @ii.peek(:bool).raw.should == "false" + end + + it "should have a default value of an empty string" do + @ii.push(:matrix) + @ii.pop(:matrix).raw.should == "" + end + + it "should validate the stackname as a symbol" do + lambda{@ii.push("backwards", :int)}.should raise_error(ArgumentError) + lambda{@ii.push("int")}.should raise_error(ArgumentError) + end +end + + describe "stepping" do before(:each) do @ii = Interpreter.new() @ii.clear_stacks end @@ -254,13 +410,51 @@ @ii.steps.should == 20 end it "should do nothing if the :exec stack starts empty" do @ii.reset() + puts @ii.stacks[:exec].depth @ii.run @ii.steps.should == 0 end end -describe "channel setup" do + +describe "resetting" do + it "should clear the steps" do + ii = Interpreter.new(program:"block {ref a ref b}") + ii.run + ii.steps.should == 3 + ii.reset + ii.steps.should == 0 + end + + it "should clear all names" do + ii = Interpreter.new + ii.bind_name("a", ValuePoint.new("int",3)) + ii.names.keys.should == ["a"] + ii.reset + ii.names.keys.should == [] + end + + it "should clear all stacks, except the program" do + ii = Interpreter.new + ii.stacks[:foo].push(ValuePoint.new("foo", "100101")) + ii.reset + ii.stacks[:foo].depth.should == 0 + end + + it "should clear the program, if none is given" do + ii = Interpreter.new(program:"block {}") + ii.reset + ii.program.should == nil + end + + it "should not affect variable bindings" do + ii = Interpreter.new + ii.bind_variable("a", ValuePoint.new("int",3)) + ii.variables.keys.should == ["a"] + ii.reset + ii.variables.keys.should == ["a"] + end end