Added `blk` option to initializer. NEXT: Add `tags` option to definitions, corpus.

pull/1125/head
Rick Carlino 2019-02-19 15:01:36 -06:00
parent 71e4a1675a
commit 496e1501d4
4 changed files with 135 additions and 108 deletions

View File

@ -143,7 +143,6 @@ module CeleryScript
allowed: allowed,
actual: actual
}
raise TypeCheckError, message
end
end

View File

@ -33,14 +33,14 @@ module CeleryScript
self
end
def arg(name, defn = [], &blk)
def arg(name, defn, &blk)
raise "NO!" unless defn.is_a?(Array)
@arg_def_list[name] = ArgumentSpecification.new(name, defn, blk)
self
end
def node(kind, args: [], body: [], &blk)
@node_def_list[kind] = \
NodeSpecification.new(kind, args, body, blk)
def node(kind, args: [], body: [], blk: nil)
@node_def_list[kind] = NodeSpecification.new(kind, args, body, blk)
self
end

View File

@ -86,9 +86,9 @@ module CeleryScriptSettingsBag
}.map { |(name, list)| Corpus.value(name, list) }
CORPUS_ENUM = {
every_point_type: ALLOWED_EVERY_POINT_TYPE,
axis: ALLOWED_AXIS,
channel_name: ALLOWED_CHANNEL_NAMES,
every_point_type: ALLOWED_EVERY_POINT_TYPE,
lhs: ALLOWED_LHS_STRINGS,
message_type: ALLOWED_MESSAGE_TYPES,
op: ALLOWED_OPS,
@ -100,88 +100,121 @@ module CeleryScriptSettingsBag
}.map { |(name, list)| Corpus.enum(name, list) }
CORPUS_ARGS = {
_else: {defn: [:execute, :nothing]},
_then: {defn: [:execute, :nothing]},
locals: {defn: [:scope_declaration]},
offset: {defn: [:coordinate]},
pin_number: {defn: [Integer, :named_pin]},
data_value: {defn: ANY_VARIABLE},
_else: {defn: [:execute, :nothing]},
_then: {defn: [:execute, :nothing]},
data_value: {defn: ANY_VARIABLE},
default_value: {defn: ANY_VARIABLE},
location: {defn: ANY_VARIABLE},
label: {defn: [String]},
milliseconds: {defn: [Integer]},
package: {defn: [String]},
pin_value: {defn: [Integer]},
radius: {defn: [Integer]},
rhs: {defn: [Integer]},
url: {defn: [String]},
value: {defn: [String, Integer, TrueClass, FalseClass]},
version: {defn: [Integer]},
x: {defn: [Integer, Float]},
y: {defn: [Integer, Float]},
z: {defn: [Integer, Float]},
pin_id: {defn: [Integer]},
resource_id: {defn: [Integer]},
label: {defn: [String]},
locals: {defn: [:scope_declaration]},
location: {defn: ANY_VARIABLE},
milliseconds: {defn: [Integer]},
offset: {defn: [:coordinate]},
package: {defn: [String]},
pin_id: {defn: [Integer]},
pin_number: {defn: [Integer, :named_pin]},
pin_value: {defn: [Integer]},
radius: {defn: [Integer]},
resource_id: {defn: [Integer]},
rhs: {defn: [Integer]},
url: {defn: [String]},
value: {defn: [String, Integer, TrueClass, FalseClass]},
version: {defn: [Integer]},
x: {defn: [Integer, Float]},
y: {defn: [Integer, Float]},
z: {defn: [Integer, Float]},
}.map do |(name, conf)|
Corpus.arg(name, conf.fetch(:defn))
end
CORPUS_NODES = {
_if: { args: [:lhs, :op, :rhs, :_then, :_else], body: [:pair]},
calibrate: { args: [:axis]},
change_ownership: { body: [:pair] },
channel: { args: [:channel_name]},
check_updates: { args: [:package]},
coordinate: { args: [:x, :y, :z]},
dump_info: {},
emergency_lock: {},
emergency_unlock: {},
every_point: { args: [:every_point_type]},
execute_script: { args: [:label], body: [:pair]},
execute: { args: [:sequence_id], body: [:parameter_application]},
explanation: { args: [:message]},
factory_reset: { args: [:package]},
find_home: { args: [:speed, :axis]},
home: { args: [:speed, :axis]},
identifier: { args: [:label]},
install_farmware: { args: [:url]},
install_first_party_farmware: {},
emergency_lock: {},
emergency_unlock: {},
read_status: {},
sync: {},
power_off: {},
take_photo: {},
dump_info: {},
internal_entry_point: {},
nothing: {},
set_user_env: { body: [:pair] },
scope_declaration: { body: SCOPE_DECLARATIONS },
change_ownership: { body: [:pair] },
internal_farm_event: { body: [:parameter_application] },
internal_regimen: { body: [:parameter_application] },
tool: { args: [:tool_id]},
coordinate: { args: [:x, :y, :z]},
move_relative: { args: [:x, :y, :z, :speed]},
channel: { args: [:channel_name]},
wait: { args: [:milliseconds]},
home: { args: [:speed, :axis]},
find_home: { args: [:speed, :axis]},
zero: { args: [:axis]},
check_updates: { args: [:package]},
reboot: { args: [:package]},
toggle_pin: { args: [:pin_number]},
explanation: { args: [:message]},
rpc_ok: { args: [:label]},
calibrate: { args: [:axis]},
pair: { args: [:label, :value]},
factory_reset: { args: [:package]},
point: { args: [:pointer_type, :pointer_id]},
install_farmware: { args: [:url]},
update_farmware: { args: [:package]},
remove_farmware: { args: [:package]},
identifier: { args: [:label]},
variable_declaration: { args: [:label, :data_value]},
internal_entry_point: {},
internal_farm_event: { body: [:parameter_application] },
internal_regimen: { body: [:parameter_application] },
move_relative: { args: [:x, :y, :z, :speed]},
nothing: {},
pair: { args: [:label, :value]},
parameter_application: { args: [:label, :data_value]},
parameter_declaration: { args: [:label, :default_value]},
set_servo_angle: { args: [:pin_number, :pin_value]},
every_point: { args: [:every_point_type]},
send_message: { args: [:message, :message_type], body: [:channel]},
execute: { args: [:sequence_id], body: [:parameter_application]},
_if: { args: [:lhs, :op, :rhs, :_then, :_else], body: [:pair]},
sequence: { args: [:version, :locals], body: ALLOWED_RPC_NODES },
rpc_request: { args: [:label], body: ALLOWED_RPC_NODES },
rpc_error: { args: [:label], body: [:explanation]},
execute_script: { args: [:label], body: [:pair]},
point: { args: [:pointer_type, :pointer_id]},
power_off: {},
read_status: {},
reboot: { args: [:package]},
remove_farmware: { args: [:package]},
rpc_error: { args: [:label], body: [:explanation]},
rpc_ok: { args: [:label]},
rpc_request: { args: [:label], body: ALLOWED_RPC_NODES },
scope_declaration: { body: SCOPE_DECLARATIONS },
send_message: { args: [:message, :message_type], body: [:channel]},
sequence: { args: [:version, :locals], body: ALLOWED_RPC_NODES },
set_servo_angle: { args: [:pin_number, :pin_value]},
set_user_env: { body: [:pair] },
sync: {},
take_photo: {},
toggle_pin: { args: [:pin_number]},
tool: { args: [:tool_id]},
update_farmware: { args: [:package]},
variable_declaration: { args: [:label, :data_value]},
wait: { args: [:milliseconds]},
zero: { args: [:axis]},
named_pin: {
args: [:pin_type, :pin_id],
blk: -> (node) do
args = HashWithIndifferentAccess.new(node.args)
klass = PIN_TYPE_MAP.fetch(args[:pin_type].value)
id = args[:pin_id].value
node.invalidate!(NO_PIN_ID % [klass.name]) if (id == 0)
bad_node = !klass.exists?(id)
no_resource(node, klass, id) if bad_node
end},
move_absolute: {
args: [:location, :speed, :offset],
blk: ->(n) do
loc = n.args[:location].try(:kind)
n.invalidate!(ONLY_ONE_COORD) if loc == "every_point"
end},
write_pin: {
args: [:pin_number, :pin_value, :pin_mode ],
blk: ->(n) do
no_rpi_analog(n)
end},
read_pin: {
args: [:pin_number, :label, :pin_mode],
blk: ->(n) do
no_rpi_analog(n)
end},
resource_update: {
args: RESOURCE_UPDATE_ARGS,
blk: ->(x) do
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},
}.map { |(name, list)| Corpus.node(name, **list) }
Corpus
.arg(:pin_type, [String]) do |node|
.arg(:pin_type, [String]) do |node|
enum(ALLOWED_PIN_TYPES, node, BAD_PIN_TYPE)
end
.arg(:pointer_id, [Integer]) do |node, device|
.arg(:pointer_id, [Integer]) do |node, device|
bad_node = !Point.where(id: node.value, device_id: device.id).exists?
node.invalidate!(BAD_POINTER_ID % node.value) if bad_node
end
@ -203,16 +236,16 @@ module CeleryScriptSettingsBag
x = [ALLOWED_LHS_STRINGS, node, BAD_LHS]
enum(*x) unless node.is_a?(CeleryScript::AstNode)
end
.arg(:op, [String]) do |node|
.arg(:op, [String]) do |node|
enum(ALLOWED_OPS, node, BAD_OP)
end
.arg(:channel_name, [String]) do |node|
.arg(:channel_name, [String]) do |node|
enum(ALLOWED_CHANNEL_NAMES, node, BAD_CHANNEL_NAME)
end
.arg(:message_type, [String]) do |node|
.arg(:message_type, [String]) do |node|
enum(ALLOWED_MESSAGE_TYPES, node, BAD_MESSAGE_TYPE)
end
.arg(:tool_id, [Integer]) do |node|
.arg(:tool_id, [Integer]) do |node|
node.invalidate!(BAD_TOOL_ID % node.value) if !Tool.exists?(node.value)
end
.arg(:package, [String]) do |node|
@ -236,29 +269,29 @@ module CeleryScriptSettingsBag
.arg(:every_point_type, [String]) do |node|
enum(ALLOWED_EVERY_POINT_TYPE, node, BAD_EVERY_POINT_TYPE)
end
.node(:named_pin, args: [:pin_type, :pin_id]) do |node|
args = HashWithIndifferentAccess.new(node.args)
klass = PIN_TYPE_MAP.fetch(args[:pin_type].value)
id = args[:pin_id].value
node.invalidate!(NO_PIN_ID % [klass.name]) if (id == 0)
bad_node = !klass.exists?(id)
no_resource(node, klass, id) if bad_node
end
.node(:move_absolute, args: [:location, :speed, :offset]) do |n|
loc = n.args[:location].try(:kind)
n.invalidate!(ONLY_ONE_COORD) if loc == "every_point"
end
.node(:write_pin, args: [:pin_number, :pin_value, :pin_mode ]) do |n|
no_rpi_analog(n)
end
.node(:read_pin, args: [:pin_number, :label, :pin_mode]) do |n|
no_rpi_analog(n)
end
.node(:resource_update, args: RESOURCE_UPDATE_ARGS) do |x|
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
# .node(:named_pin, args: [:pin_type, :pin_id], blk: -> (node) do
# args = HashWithIndifferentAccess.new(node.args)
# klass = PIN_TYPE_MAP.fetch(args[:pin_type].value)
# id = args[:pin_id].value
# node.invalidate!(NO_PIN_ID % [klass.name]) if (id == 0)
# bad_node = !klass.exists?(id)
# no_resource(node, klass, id) if bad_node
# end)
# .node(:move_absolute, args: [:location, :speed, :offset], blk: ->(n) do
# loc = n.args[:location].try(:kind)
# n.invalidate!(ONLY_ONE_COORD) if loc == "every_point"
# end)
# .node(:write_pin, args: [:pin_number, :pin_value, :pin_mode ], blk: ->(n) do
# no_rpi_analog(n)
# end)
# .node(:read_pin, args: [:pin_number, :label, :pin_mode], blk: ->(n) do
# no_rpi_analog(n)
# end)
# .node(:resource_update, args: RESOURCE_UPDATE_ARGS, blk: ->(x) do
# 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)
ANY_ARG_NAME = Corpus.as_json[:args].pluck("name").map(&:to_s)
ANY_NODE_NAME = Corpus.as_json[:nodes].pluck("name").map(&:to_s)

View File

@ -111,16 +111,11 @@ describe CeleryScript::Corpus do
args: {
location: {
kind: "tool",
# Invalid:
args: { tool_id: "PROBLEM!" }
args: { tool_id: "PROBLEM!" } # <= Invalid:
},
offset: {
kind: "coordinate",
args: {
"x": 0,
"y": 0,
"z": 0
}
args: { "x": 0, "y": 0, "z": 0 }
},
speed: 100
}