From: Michael D. Lowis Date: Sat, 4 Jul 2020 03:09:33 +0000 (-0400) Subject: added specs for symtable X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=097d1afffe2c085b6855a71dcd137599ca121aa0;p=proto%2Fsclpl-rb.git added specs for symtable --- diff --git a/lib/dyn.rb b/lib/dyn.rb index 356fc6b..70ebc5d 100755 --- a/lib/dyn.rb +++ b/lib/dyn.rb @@ -14,6 +14,8 @@ def error(loc, msg) end class SymTable < Hash + attr_accessor :is_func + def initialize(parent = nil) @parent = (parent || {}) end @@ -34,20 +36,30 @@ class SymTable < Hash super(key,value) end - def local?(key) + def block_local?(key) (not method(:[]).super_method.call(key).nil?) end def global?(key) if @parent.class == Hash - local?(key) - elsif local? key + block_local?(key) + elsif block_local? key false else @parent.global? key end end + def local?(key) + if @parent.class == Hash + false + elsif is_func + block_local? key + else + @parent.local? key + end + end + def merge!(env) env.each {|k,v| self[k] = v } end diff --git a/spec/symtable_spec.rb b/spec/symtable_spec.rb index 45f6c55..c4073c0 100644 --- a/spec/symtable_spec.rb +++ b/spec/symtable_spec.rb @@ -1,16 +1,68 @@ require "dyn" describe SymTable do -# subject { -# symtab = SymTable.new -# symtab[:a] = {} -# symtab -# } - -# context ".clone" do -# if "keeps a reference to the parent environment when cloned" do -# symtab = SymTable.new("foo") -# expect(symtab.instance_variable_get(:@parent)).to eq "foo" -# end -# end + subject { + symtab1 = SymTable.new + symtab1[:a] = {} + symtab1[:d] = {} + symtab2 = symtab1.clone + symtab2.is_func = true + symtab2[:b] = {} + symtab3 = symtab2.clone + symtab3[:c] = {} + symtab3[:d] = {} + symtab3 + } + + it "keeps a reference to the parent environment when cloned" do + symtab = SymTable.new("foo") + expect(symtab.instance_variable_get(:@parent)).to eq "foo" + end + + context "lookup/store" do + it "will find the symbol in the inner most context" do + expect(subject[:c]).to eq({}) + end + + it "will find the symbol in global context" do + expect(subject[:a]).to eq({}) + end + + it "will find the symbol in the middle context" do + expect(subject[:b]).to eq({}) + end + + it "will return nil if no symbol defined with the given name" do + expect(subject[:z]).to eq(nil) + end + end + + context "global?" do + it "returns true if the symbol is defined in global context" do + expect(subject.global? :a).to eq true + end + + it "returns false if the symbol is defined in non-global context" do + expect(subject.global? :b).to eq false + end + end + + context "local?" do + it "returns true if the symbol is defined in local function context" do + expect(subject.local? :b).to eq true + end + it "returns false if the symbol is defined outside of the current function context" do + expect(subject.local? :a).to eq false + end + end + + context "block_local?" do + it "returns true if the symbol is defined in context of the inner most block" do + expect(subject.block_local? :d).to eq true + end + + it "returns false if the symbol is defined outside the context of the inner most block" do + expect(subject.block_local? :b).to eq false + end + end end \ No newline at end of file