Finally fix the symbol vs. string issues in CeleryScript type checker

pull/1066/head
Rick Carlino 2018-12-07 09:33:33 -06:00
parent 904c98eff8
commit befbdc4f0a
6 changed files with 37 additions and 16 deletions

View File

@ -7,6 +7,8 @@ module CeleryScript
BODY_HAS_NON_NODES = "The `body` of a node can only contain nodes- " \
"no leaves here."
LEAVES_NEED_KEYS = "Tried to initialize a leaf without a key."
NEVER = :__NEVER__
def initialize(parent = nil,
args:,
body: nil,
@ -16,7 +18,7 @@ module CeleryScript
@comment, @kind, @parent = comment, kind, parent
@args = args.map do |key, value|
[key, maybe_initialize(self, value, key)]
[key.to_sym, maybe_initialize(self, value, key)]
end.to_h if args
@body = body.map do |e|
@ -25,11 +27,11 @@ module CeleryScript
end if body
end
def maybe_initialize(parent, leaf_or_node, key = "__NEVER__")
def maybe_initialize(parent, leaf_or_node, key = NEVER)
if is_node?(leaf_or_node)
AstNode.new(parent, leaf_or_node)
else
raise TypeCheckError, LEAVES_NEED_KEYS if key == "__NEVER__"
raise TypeCheckError, LEAVES_NEED_KEYS if key == NEVER
AstLeaf.new(parent, leaf_or_node, key)
end
end

View File

@ -184,12 +184,12 @@ module CeleryScript
# Calling this method with only one paramter
# indicates a starting condition 🏁
def resolve_variable!(node, origin = node)
locals = (node.args["locals"] || node.args[:locals])
locals = node.args[:locals]
if locals&.kind === "scope_declaration"
label = (origin.args["label"] || origin.args[:label])&.value
label = origin.args[:label]&.value
result = (locals.body || []).select do |x|
(x.args[:label] || x.args["label"])&.value == label
x.args[:label]&.value == label
end.first
return result if result
end
@ -200,7 +200,7 @@ module CeleryScript
# Keep recursing if we can't find a scope on this node.
resolve_variable!(node.parent, origin)
when nil # We've got an unbound variable.
origin.invalidate!(UNBOUND_VAR % origin.args["label"].value)
origin.invalidate!(UNBOUND_VAR % origin.args[:label].value)
end
end
end

View File

@ -74,8 +74,6 @@ module CeleryScriptSettingsBag
"BoxLed4" => BoxLed }
CANT_ANALOG = "Analog modes are not supported for Box LEDs"
ALLOWED_PIN_TYPES = PIN_TYPE_MAP.keys
# KLASS_LOOKUP =
# Point::POINTER_KINDS.reduce({}) { |a, v| (a[v] = Kernel.const_get(v)) && a }
RESOURCE_UPDATE_ARGS = [:resource_type, :resource_id, :label, :value]
Corpus = CeleryScript::Corpus
@ -254,8 +252,8 @@ module CeleryScriptSettingsBag
.node(:install_first_party_farmware, [])
.node(:farm_event, [], [:variable_declaration]) # NEVER SAVE THIS NODE ITS PRIVATE
.node(:resource_update, RESOURCE_UPDATE_ARGS) do |x|
resource_type = x.args.fetch("resource_type").value
resource_id = x.args.fetch("resource_id").value
resource_type = x.args.fetch(:resource_type).value
resource_id = x.args.fetch(:resource_id).value
check_resource_type(x, resource_type, resource_id)
end
@ -272,7 +270,7 @@ module CeleryScriptSettingsBag
# When "resource_type" is "Device", resource_id always refers to
# the current_device.
# For convinience, we try to set it here, defaulting to 0
node.args["resource_id"].instance_variable_set("@value", 0)
node.args[:resource_id].instance_variable_set("@value", 0)
when *RESOURCE_NAME.without("Device")
klass = Kernel.const_get(resource_type)
resource_ok = klass.exists?(resource_id)

View File

@ -37,7 +37,7 @@ describe CeleryScript::Checker do
end
it "handles unknown args" do
tree.body.first.args["foo"] = "bar"
tree.body.first.args[:foo] = "bar"
expect(checker.valid?).to be(false)
msg = checker.error.message
expect(msg).to include("unexpected arguments: [:foo].")

View File

@ -164,7 +164,7 @@ describe CeleryScript::Corpus do
"value" => 1 } }
checker = CeleryScript::Checker.new(CeleryScript::AstNode.new(ast), corpus, device)
expect(checker.valid?).to be(true)
expect(checker.tree.args["resource_id"].value).to eq(0)
expect(checker.tree.args[:resource_id].value).to eq(0)
end
it "rejects bogus resource_updates" do
@ -176,7 +176,7 @@ describe CeleryScript::Corpus do
"label" => "foo",
"value" => "Should Fail" } }
hmm = CeleryScript::AstNode.new(ast)
expect(hmm.args.fetch("resource_id").value).to eq(fake_id)
expect(hmm.args.fetch(:resource_id).value).to eq(fake_id)
checker = CeleryScript::Checker.new(hmm, corpus, device)
expect(checker.valid?).to be(false)
expect(checker.error.message)

View File

@ -6,7 +6,28 @@ describe CeleryScript::Checker do
let(:point) { FactoryBot.create(:generic_pointer, device: device) }
let(:corpus) { Sequence::Corpus }
it "disallows the use of `identifier` nodes"
it "disallows the use of `identifier` nodes" do
tree = \
CeleryScript::AstNode.new(kind: "farm_event",
args: {},
body: [
{
kind: "variable_declaration",
args: {
label: "foo",
data_value: {
kind: "identifier",
args: {
label: "makes no sense",
data_type: "coordinate"
}
}
}
}
])
checker = CeleryScript::Checker.new(tree, corpus, device)
expect { checker.run! }.to raise_error(CeleryScript::TypeCheckError)
end
it "runs through a syntactically valid program" do
body = [