added support for structures in q syntax.
diff --git a/aos/build/queues/compiler.rb b/aos/build/queues/compiler.rb
index 28e206b..ffee5d3 100644
--- a/aos/build/queues/compiler.rb
+++ b/aos/build/queues/compiler.rb
@@ -1,12 +1,13 @@
+$LOAD_PATH.unshift(".")
["tokenizer.rb","q_file.rb","queue_group.rb","queue.rb","namespaces.rb",
-"interface.rb","errors.rb"].each do |name|
+"interface.rb","errors.rb", "q_struct.rb"].each do |name|
require File.dirname(__FILE__) + "/objects/" + name
end
["standard_types.rb","auto_gen.rb","file_pair_types.rb",
"dep_file_pair.rb","swig.rb"].each do |name|
require File.dirname(__FILE__) + "/cpp_pretty_print/" + name
end
-["q_file.rb","message_dec.rb","queue_dec.rb"].each do |name|
+["q_file.rb","message_dec.rb","queue_dec.rb", "q_struct.rb"].each do |name|
require File.dirname(__FILE__) + "/output/" + name
end
require "fileutils"
diff --git a/aos/build/queues/objects/namespaces.rb b/aos/build/queues/objects/namespaces.rb
index b799d36..74f7197 100644
--- a/aos/build/queues/objects/namespaces.rb
+++ b/aos/build/queues/objects/namespaces.rb
@@ -43,7 +43,7 @@
end
class BoundSituation < LocalSituation
def initialize(locals,bind_to)
- @globals = globals
+ @globals = locals.globals
@local = bind_to
end
end
diff --git a/aos/build/queues/objects/q_file.rb b/aos/build/queues/objects/q_file.rb
index f683dda..beaf8f0 100644
--- a/aos/build/queues/objects/q_file.rb
+++ b/aos/build/queues/objects/q_file.rb
@@ -134,6 +134,8 @@
suite << QueueStmt.parse(tokens)
when "interface"
suite << InterfaceStmt.parse(tokens)
+ when "struct"
+ suite << StructStmt.parse(tokens)
else
tokens.qError(<<ERROR_MSG)
expected a "package","import","queue","queue_group", or "message" statement rather
diff --git a/aos/build/queues/objects/q_struct.rb b/aos/build/queues/objects/q_struct.rb
new file mode 100644
index 0000000..cd47fe6
--- /dev/null
+++ b/aos/build/queues/objects/q_struct.rb
@@ -0,0 +1,37 @@
+
+class StructStmt
+ def initialize(name,suite)
+ @name = name
+ @suite = suite
+ end
+ def q_eval(locals)
+ group = Target::StructDec.new(@name)
+ locals.register(group)
+ @suite.each do |stmt|
+ stmt.q_eval(locals.bind(group))
+ end
+ return group
+ end
+ def self.parse(tokens)
+ name = tokens.expect(:tWord).data
+ values = []
+ tokens.expect(:tOpenB)
+ while(tokens.peak != :tCloseB)
+ values << MessageElementStmt.parse(tokens)
+ end
+ names = {}
+ values.each do |val|
+ if(names[val.name])
+ raise QSyntaxError.new(<<ERROR_MSG)
+Hey! duplicate name #{val.name.inspect} in your message declaration statement (message #{name}).
+\tI found them at: #{names[val.name].q_stack_name()} and #{val.q_stack_name()}.
+\tWot. Wot.
+ERROR_MSG
+ end
+ names[val.name] = val
+ end
+ tokens.expect(:tCloseB)
+ tokens.expect(:tSemi)
+ self.new(name,values)
+ end
+end
diff --git a/aos/build/queues/objects/queue.rb b/aos/build/queues/objects/queue.rb
index e993eb9..1199cc2 100644
--- a/aos/build/queues/objects/queue.rb
+++ b/aos/build/queues/objects/queue.rb
@@ -1,12 +1,13 @@
class MessageElementStmt < QStmt
attr_accessor :name
- def initialize(type,name,length = nil) #lengths are for arrays
- @type = type
+ def initialize(type_name,name,length = nil) #lengths are for arrays
+ @type_name = type_name
+ @type = type_name.to_s
@name = name
@length = length
end
CommonMistakes = {"short" => "int16_t","int" => "int32_t","long" => "int64_t"}
- def check_type_error()
+ def check_type_error(locals)
if(!(Sizes[@type] || (@length != nil && @type == "char")) )
if(correction = CommonMistakes[@type])
raise QError.new(<<ERROR_MSG)
@@ -23,11 +24,13 @@
\tWot. Wot.
ERROR_MSG
else
+ @is_struct_type = true
+ return if(lookup_type(locals))
raise QError.new(<<ERROR_MSG)
Hey! you have a \"#{@type}\" in your message statement.
\tThat is not in the list of supported types.
\there is the list of supported types:
-\tint{8,16,32,64}_t,uint{8,16,32,64}_t,bool,float,double#{len_comment}
+\tint{8,16,32,64}_t,uint{8,16,32,64}_t,bool,float,double
\tWot. Wot.
ERROR_MSG
end
@@ -72,21 +75,30 @@
\tWot. Wot.
ERROR_MSG
end
+ def lookup_type(locals)
+ return @type_name.lookup(locals)
+ end
def q_eval(locals)
- check_type_error()
- if(@length == nil)
- member = Target::MessageElement.new(@type,@name)
+ check_type_error(locals)
+ if(@is_struct_type)
+ tval = lookup_type(locals)
+ member = Target::MessageStructElement.new(tval, name)
else
- member = Target::MessageArrayElement.new(@type,@name,@length)
+ if(@length == nil)
+ member = Target::MessageElement.new(@type,@name)
+ else
+ member = Target::MessageArrayElement.new(@type,@name,@length)
+ end
+ member.size = size()
+ member.zero = Zero[@type] || "0";
+ member.printformat = toPrintFormat()
end
- member.size = size()
- member.zero = Zero[@type] || "0";
- member.printformat = toPrintFormat()
locals.local.add_member(member)
end
def self.parse(tokens)
line = tokens.pos
- type = tokens.expect(:tWord).data
+ #type = tokens.expect(:tWord).data
+ type_name = QualifiedName.parse(tokens)
len = nil
if(tokens.peak == :tOpenB)
tokens.expect(:tOpenB)
@@ -95,7 +107,7 @@
end
name = tokens.expect(:tWord).data
tokens.expect(:tSemi)
- return self.new(type,name,len).set_line(line)
+ return self.new(type_name,name,len).set_line(line)
end
end
class MessageStmt < QStmt
diff --git a/aos/build/queues/output/message_dec.rb b/aos/build/queues/output/message_dec.rb
index 3b89149..579ce0c 100644
--- a/aos/build/queues/output/message_dec.rb
+++ b/aos/build/queues/output/message_dec.rb
@@ -34,17 +34,13 @@
@members.each do |elem|
format += ", "
format += elem.toPrintFormat()
- if (elem.type == 'bool')
- args.push("#{elem.name} ? 'T' : 'f'")
- else
- args.push(elem.name)
- end
+ elem.fetchPrintArgs(args)
end
- format += "\""
- member_func.suite << "size_t super_size = ::aos::Message::Print(buffer, length)"
- member_func.suite << "buffer += super_size"
- member_func.suite << "length -= super_size"
- member_func.suite << "return super_size + snprintf(buffer, length, " + ([format] + args).join(", ") + ")";
+ format += "\""
+ member_func.suite << "size_t super_size = ::aos::Message::Print(buffer, length)"
+ member_func.suite << "buffer += super_size"
+ member_func.suite << "length -= super_size"
+ member_func.suite << "return super_size + snprintf(buffer, length, " + ([format] + args).join(", ") + ")";
end
def create_Serialize(type_class,cpp_tree)
member_func = CPP::MemberFunc.new(type_class,"size_t","Serialize")
@@ -221,26 +217,33 @@
def create_usage(cpp_tree)
"#{@type} #{@name}"
end
- def toNetwork(offset,suite)
+ def toNetwork(offset,suite, parent = "")
offset = (offset == 0) ? "" : "#{offset} + "
suite << f_call = CPP::FuncCall.build("to_network",
- "&#{@name}",
+ "&#{parent}#{@name}",
"&buffer[#{offset}::aos::Message::Size()]")
f_call.args.dont_wrap = true
end
- def toHost(offset,suite)
+ def toHost(offset,suite, parent = "")
offset = (offset == 0) ? "" : "#{offset} + "
suite << f_call = CPP::FuncCall.build("to_host",
"&buffer[#{offset}::aos::Message::Size()]",
- "&#{@name}")
+ "&#{parent}#{@name}")
f_call.args.dont_wrap = true
end
def set_message_builder(suite)
suite << "msg_ptr_->#{@name} = #{@name}"
end
- def zeroCall(suite)
- suite << CPP::Assign.new(@name,@zero)
+ def zeroCall(suite, parent = "")
+ suite << CPP::Assign.new(parent + @name,@zero)
+ end
+ def fetchPrintArgs(args, parent = "")
+ if (self.type == 'bool')
+ args.push("#{parent}#{self.name} ? 'T' : 'f'")
+ else
+ args.push("#{parent}#{self.name}")
+ end
end
end
class Target::MessageArrayElement < Target::Node
diff --git a/aos/build/queues/output/q_file.rb b/aos/build/queues/output/q_file.rb
index 5e016c0..1ef47a4 100644
--- a/aos/build/queues/output/q_file.rb
+++ b/aos/build/queues/output/q_file.rb
@@ -8,6 +8,13 @@
end
class Target::Node
attr_accessor :created_by
+ def get_name()
+ if(@parent)
+ return "#{@parent.get_name}.#{@name}"
+ else
+ return "#{@name}"
+ end
+ end
end
class Target::QFile < Target::Node
def initialize() #needs to know repo_path,
diff --git a/aos/build/queues/output/q_struct.rb b/aos/build/queues/output/q_struct.rb
new file mode 100644
index 0000000..12276ad
--- /dev/null
+++ b/aos/build/queues/output/q_struct.rb
@@ -0,0 +1,104 @@
+class Target::StructDec < Target::Node
+ attr_accessor :name,:loc,:parent, :extern
+ def initialize(name)
+ @name = name
+ @members = []
+ end
+ def [](key)
+ return nil
+ end
+ def add_member(member)
+ @members << member
+ end
+ def create(cpp_tree)
+ return self if(@extern)
+ orig_namespace = namespace = cpp_tree.get(@loc)
+ name = ""
+ if(namespace.class < Types::Type) #is nested
+ name = namespace.name + "_" + name
+ namespace = namespace.space
+ end
+ type_class = namespace.add_struct(name + @name)
+
+ @members.each do |elem|
+ type_class.add_member(elem.create_usage(cpp_tree))
+ end
+ return type_class
+ end
+ def size()
+ return @size if(@size)
+ @size = 0
+ @members.each do |elem|
+ @size += elem.size
+ end
+ return @size
+ end
+ def getPrintFormat()
+ return "{" + @members.collect { |elem| elem.toPrintFormat() }.join(", ") + "}"
+ end
+ def fetchPrintArgs(args, parent = "")
+ @members.each do |elem|
+ elem.fetchPrintArgs(args, parent)
+ end
+ end
+ def toHost(offset, suite, parent)
+ @members.each do |elem|
+ elem.toHost(offset, suite, parent)
+ offset += elem.size()
+ end
+ end
+ def toNetwork(offset, suite, parent)
+ @members.each do |elem|
+ elem.toNetwork(offset, suite, parent)
+ offset += elem.size()
+ end
+ end
+ def zeroCall(suite, parent)
+ @members.each do |elem|
+ elem.zeroCall(suite, parent)
+ end
+ end
+end
+class Target::MessageStructElement < Target::Node
+ attr_accessor :name,:loc
+ def initialize(type,name)
+ @type, @name = type, name
+ end
+ def type()
+ return @type.get_name
+ end
+ def type_name(cpp_tree)
+ type = cpp_tree.get(@type)
+ if(@type.loc == @loc) #use relative name
+ return type.name
+ else #use full name
+ return @type.loc.to_cpp_id(type.name)
+ end
+ end
+ def size()
+ return @type.size()
+ end
+ def toPrintFormat()
+ @type.getPrintFormat()
+ end
+ def create_usage(cpp_tree)
+ return "#{type_name(cpp_tree)} #{@name}"
+ end
+ def fetchPrintArgs(args, parent = "")
+ @type.fetchPrintArgs(args, parent + "#{@name}.")
+ end
+ def toNetwork(offset,suite, parent = "")
+ @type.toNetwork(offset, suite, parent + "#{@name}.")
+ end
+ def toHost(offset,suite, parent = "")
+ @type.toHost(offset, suite, parent + "#{@name}.")
+ end
+ def set_message_builder(suite)
+ suite << "msg_ptr_->#{@name} = #{@name}"
+ end
+
+ def zeroCall(suite, parent = "")
+ @type.zeroCall(suite, parent + "#{@name}.")
+ end
+
+end
diff --git a/aos/build/queues/q_specs/nested_structs.q b/aos/build/queues/q_specs/nested_structs.q
new file mode 100644
index 0000000..7162620
--- /dev/null
+++ b/aos/build/queues/q_specs/nested_structs.q
@@ -0,0 +1,12 @@
+package aos.test;
+
+import "q_specs/struct_test.q";
+
+
+message Position {
+ int32_t a;
+ int32_t[2] b;
+ .aos.test2.ClawHalfPosition top;
+ .aos.test2.ClawHalfPosition bottom;
+ bool c;
+};
diff --git a/aos/build/queues/q_specs/struct_test.q b/aos/build/queues/q_specs/struct_test.q
new file mode 100644
index 0000000..afb22ac
--- /dev/null
+++ b/aos/build/queues/q_specs/struct_test.q
@@ -0,0 +1,12 @@
+package aos.test2;
+
+struct SubStruct {
+ int32_t g;
+};
+
+struct ClawHalfPosition {
+ double position;
+ bool hall_effect;
+ SubStruct clampy;
+};
+