Finally fix the symbol vs. string issues in CeleryScript type checker
parent
904c98eff8
commit
befbdc4f0a
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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].")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = [
|
||||
|
|
Loading…
Reference in New Issue