VERY UNSTABLE. WIP

pull/1125/head
Rick Carlino 2019-02-20 17:13:23 -06:00
parent 4176ba234b
commit 3439ae6c9e
4 changed files with 144 additions and 47 deletions

View File

@ -3,6 +3,19 @@
# parser generators (but not exactly). # parser generators (but not exactly).
module CeleryScript module CeleryScript
class Corpus class Corpus
class ArgAtom
attr_reader :value
def initialize(value)
raise "USE SYMBOLS!" unless value.is_a?(Symbol)
@value = value
end
end
class Enum < ArgAtom; end
class Value < ArgAtom; end
class Node < ArgAtom; end
ATOMS = [Enum, Value, Node]
BAD_NODE_NAME = "Can't find validation rules for node " BAD_NODE_NAME = "Can't find validation rules for node "
NO_ARG_SPEC = "CANT FIND ARG SPEC" NO_ARG_SPEC = "CANT FIND ARG SPEC"
NO_NODE_SPEC = "NO_NODE_SPEC" NO_NODE_SPEC = "NO_NODE_SPEC"
@ -34,7 +47,11 @@ module CeleryScript
end end
def arg(name, defn, &blk) def arg(name, defn, &blk)
raise "NO!" unless defn.is_a?(Array) defn.map do |x|
binding.pry if x.is_a?(Symbol)
binding.pry if x.is_a?(Class)
puts x.class.inspect
end
@arg_def_list[name] = ArgumentSpecification.new(name, defn, blk) @arg_def_list[name] = ArgumentSpecification.new(name, defn, blk)
self self
end end

View File

@ -38,10 +38,9 @@ module CeleryScriptSettingsBag
factory_reset find_home home install_farmware factory_reset find_home home install_farmware
install_first_party_farmware _if move_absolute install_first_party_farmware _if move_absolute
move_relative power_off read_pin read_status reboot move_relative power_off read_pin read_status reboot
register_gpio remove_farmware resource_update remove_farmware resource_update send_message
send_message set_servo_angle set_user_env sync set_servo_angle set_user_env sync take_photo
take_photo toggle_pin update_farmware wait write_pin toggle_pin update_farmware wait write_pin zero )
zero )
ALLOWED_SPEC_ACTION = %w(dump_info emergency_lock emergency_unlock power_off ALLOWED_SPEC_ACTION = %w(dump_info emergency_lock emergency_unlock power_off
read_status reboot sync take_photo) read_status reboot sync take_photo)
ANY_VARIABLE = %i(tool coordinate point identifier every_point) ANY_VARIABLE = %i(tool coordinate point identifier every_point)
@ -99,55 +98,108 @@ module CeleryScriptSettingsBag
resource_type: ALLOWED_RESOURCE_TYPE, resource_type: ALLOWED_RESOURCE_TYPE,
}.map { |(name, list)| Corpus.enum(name, list) } }.map { |(name, list)| Corpus.enum(name, list) }
def self.e(symbol)
CeleryScript::Corpus::Enum.new(symbol)
end
def self.n(symbol)
CeleryScript::Corpus::Node.new(symbol)
end
def self.v(symbol)
CeleryScript::Corpus::Value.new(symbol)
end
ANY_VAR_TOKENIZED = ANY_VARIABLE.map { |x| n(x) }
CORPUS_ARGS = { CORPUS_ARGS = {
_else: {defn: [:execute, :nothing]}, _else: {
_then: {defn: [:execute, :nothing]}, defn: [
data_value: {defn: ANY_VARIABLE}, n(:execute),
default_value: {defn: ANY_VARIABLE}, n(:nothing)
label: {defn: [String]}, ]
locals: {defn: [:scope_declaration]}, },
location: {defn: ANY_VARIABLE}, _then: {
milliseconds: {defn: [Integer]}, defn: [
offset: {defn: [:coordinate]}, n(:execute),
pin_id: {defn: [Integer]}, n(:nothing)
pin_number: {defn: [Integer, :named_pin]}, ]
pin_value: {defn: [Integer]}, },
radius: {defn: [Integer]}, data_value: {
resource_id: {defn: [Integer]}, defn: ANY_VAR_TOKENIZED
rhs: {defn: [Integer]}, },
url: {defn: [String]}, default_value: {
value: {defn: [String, Integer, TrueClass, FalseClass]}, defn: ANY_VAR_TOKENIZED
version: {defn: [Integer]}, },
x: {defn: [Integer, Float]}, label: {
y: {defn: [Integer, Float]}, defn: [v(:string)]
z: {defn: [Integer, Float]}, },
locals: {
defn: [n(:scope_declaration)]
},
location: {
defn: ANY_VAR_TOKENIZED
},
milliseconds: {
defn: [v(:integer)]
},
offset: {
defn: [n(:coordinate)]
},
pin_id: {
defn: [v(:integer)]
},
pin_number: {
defn: [
v(:integer),
n(:named_pin)
]
},
pin_value: {
defn: [ v(:integer) ]
},
radius: {
defn: [ v(:integer) ]
},
resource_id: {
defn: [ v(:integer) ]
},
rhs: { defn: [ v(:integer) ] },
url: { defn: [ v(:string) ] },
value: {
defn: [v(:string), v(:integer), v(:boolean)]
},
version: {defn: [v(:integer)]},
x: {defn: [v(:integer), v(:float)]},
y: {defn: [v(:integer), v(:float)]},
z: {defn: [v(:integer), v(:float)]},
pin_type: { pin_type: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_PIN_TYPES, node, BAD_PIN_TYPE) enum(ALLOWED_PIN_TYPES, node, BAD_PIN_TYPE)
end end
}, },
pointer_id: { pointer_id: {
defn: [Integer], defn: [v(:integer)],
blk: -> (node, device) do blk: -> (node, device) do
bad_node = !Point.where(id: node.value, device_id: device.id).exists? bad_node = !Point.where(id: node.value, device_id: device.id).exists?
node.invalidate!(BAD_POINTER_ID % node.value) if bad_node node.invalidate!(BAD_POINTER_ID % node.value) if bad_node
end end
}, },
pointer_type: { pointer_type: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_POINTER_TYPE, node, BAD_POINTER_TYPE) enum(ALLOWED_POINTER_TYPE, node, BAD_POINTER_TYPE)
end end
}, },
pin_mode: { pin_mode: {
defn: [Integer], defn: [v(:integer)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_PIN_MODES, node, BAD_ALLOWED_PIN_MODES) enum(ALLOWED_PIN_MODES, node, BAD_ALLOWED_PIN_MODES)
end end
}, },
sequence_id: { sequence_id: {
defn: [Integer], defn: [v(:integer)],
blk: -> (node) do blk: -> (node) do
if (node.value == 0) if (node.value == 0)
node.invalidate!(NO_SUB_SEQ) node.invalidate!(NO_SUB_SEQ)
@ -165,43 +217,43 @@ module CeleryScriptSettingsBag
end end
}, },
op: { op: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_OPS, node, BAD_OP) enum(ALLOWED_OPS, node, BAD_OP)
end end
}, },
channel_name: { channel_name: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_CHANNEL_NAMES, node, BAD_CHANNEL_NAME) enum(ALLOWED_CHANNEL_NAMES, node, BAD_CHANNEL_NAME)
end end
}, },
message_type: { message_type: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_MESSAGE_TYPES, node, BAD_MESSAGE_TYPE) enum(ALLOWED_MESSAGE_TYPES, node, BAD_MESSAGE_TYPE)
end end
}, },
tool_id: { tool_id: {
defn: [Integer], defn: [v(:integer)],
blk: -> (node) do blk: -> (node) do
node.invalidate!(BAD_TOOL_ID % node.value) if !Tool.exists?(node.value) node.invalidate!(BAD_TOOL_ID % node.value) if !Tool.exists?(node.value)
end end
}, },
package: { package: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_PACKAGES, node, BAD_PACKAGE) enum(ALLOWED_PACKAGES, node, BAD_PACKAGE)
end end
}, },
axis: { axis: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_AXIS, node, BAD_AXIS) enum(ALLOWED_AXIS, node, BAD_AXIS)
end end
}, },
message: { message: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
notString = !node.value.is_a?(String) notString = !node.value.is_a?(String)
tooShort = notString || node.value.length == 0 tooShort = notString || node.value.length == 0
@ -210,19 +262,19 @@ module CeleryScriptSettingsBag
end end
}, },
speed: { speed: {
defn: [Integer], defn: [v(:integer)],
blk: -> (node) do blk: -> (node) do
node.invalidate!(BAD_SPEED) unless node.value.between?(1, 100) node.invalidate!(BAD_SPEED) unless node.value.between?(1, 100)
end end
}, },
resource_type: { resource_type: {
defn: [String], defn: [v(:string)],
blk: -> (n) do blk: -> (n) do
enum(ALLOWED_RESOURCE_TYPE, n, BAD_RESOURCE_TYPE) enum(ALLOWED_RESOURCE_TYPE, n, BAD_RESOURCE_TYPE)
end end
}, },
every_point_type: { every_point_type: {
defn: [String], defn: [v(:string)],
blk: -> (node) do blk: -> (node) do
enum(ALLOWED_EVERY_POINT_TYPE, node, BAD_EVERY_POINT_TYPE) enum(ALLOWED_EVERY_POINT_TYPE, node, BAD_EVERY_POINT_TYPE)
end end
@ -294,7 +346,7 @@ module CeleryScriptSettingsBag
body: [:parameter_application] body: [:parameter_application]
}, },
internal_regimen: { internal_regimen: {
body: [:parameter_application] body: %i(parameter_application parameter_declaration variable_declaration)
}, },
move_relative: { move_relative: {
args: [:x, :y, :z, :speed] args: [:x, :y, :z, :speed]
@ -381,26 +433,26 @@ module CeleryScriptSettingsBag
}, },
move_absolute: { move_absolute: {
args: [:location, :speed, :offset], args: [:location, :speed, :offset],
blk: ->(n) do blk: -> (n) do
loc = n.args[:location].try(:kind) loc = n.args[:location].try(:kind)
n.invalidate!(ONLY_ONE_COORD) if loc == "every_point" n.invalidate!(ONLY_ONE_COORD) if loc == "every_point"
end end
}, },
write_pin: { write_pin: {
args: [:pin_number, :pin_value, :pin_mode ], args: [:pin_number, :pin_value, :pin_mode ],
blk: ->(n) do blk: -> (n) do
no_rpi_analog(n) no_rpi_analog(n)
end end
}, },
read_pin: { read_pin: {
args: [:pin_number, :label, :pin_mode], args: [:pin_number, :label, :pin_mode],
blk: ->(n) do blk: -> (n) do
no_rpi_analog(n) no_rpi_analog(n)
end end
}, },
resource_update: { resource_update: {
args: RESOURCE_UPDATE_ARGS, args: RESOURCE_UPDATE_ARGS,
blk: ->(x) do blk: -> (x) do
resource_type = x.args.fetch(:resource_type).value resource_type = x.args.fetch(:resource_type).value
resource_id = x.args.fetch(:resource_id).value resource_id = x.args.fetch(:resource_id).value
check_resource_type(x, resource_type, resource_id) check_resource_type(x, resource_type, resource_id)

View File

@ -36,7 +36,7 @@ class CorpusEmitter
attr_reader :name, :allowed_args, :allowed_body_types attr_reader :name, :allowed_args, :allowed_body_types
def initialize(name:, allowed_args:, allowed_body_types: []) def initialize(name:, allowed_args:, allowed_body_types: [], tags:)
@name, @name,
@allowed_args, @allowed_args,
@allowed_body_types = name, allowed_args, allowed_body_types @allowed_body_types = name, allowed_args, allowed_body_types

View File

@ -60,6 +60,34 @@ describe Api::RegimensController do
expect(json[:color]).to eq(color) expect(json[:color]).to eq(color)
end end
it "creates a regimen that uses unbound variables" do
pending("TODO: Help Gabe with this.")
sign_in user
s = FakeSequence.with_parameters
payload = { device: s.device,
name: "specs",
color: "red",
body: [
{
kind: "parameter_application",
args: {
label: "parent",
data_value: {
kind: "identifier", args: { label: "parent" }
}
}
}
],
regimen_items: [ { time_offset: 100, sequence_id: s.id } ] }
post :create, body: payload.to_json, format: :json
expect(response.status).to eq(200)
declr = json.fetch(:body).first
expect(declr).to be
expect(declr.fetch(:kind)).to eq("parameter_application")
path = [:args, :data_value, :args, :label]
expect(declr.dig(*path)).to eq("parent")
end
it "handles CeleryScript::TypeCheckError" do it "handles CeleryScript::TypeCheckError" do
sign_in user sign_in user
s = FakeSequence.with_parameters s = FakeSequence.with_parameters