wip genmsg_lisp

This commit is contained in:
Bhaskara Marthi 2010-10-10 05:08:20 +00:00
parent 2544bd8416
commit a459e5c24c
3 changed files with 175 additions and 41 deletions

6
.gitignore vendored
View File

@ -143,3 +143,9 @@ tutorials/rospy_tutorials/srv/lisp
util/rosthread/build
.build_version
.rosgcov_files
3rdparty/gtest/gtest
/core/genmsg_cpp/genmsg_java
/core/genmsg_cpp/genmsg_oct
/core/genmsg_cpp/gensrv_java
/core/genmsg_cpp/gensrv_oct
/core/roslib/src/roslib

View File

@ -48,18 +48,57 @@ import roslib.gentools
from cStringIO import StringIO
MSG_TYPE_TO_CPP = {'byte': 'int8_t', 'char': 'uint8_t',
'bool': 'uint8_t',
'uint8': 'uint8_t', 'int8': 'int8_t',
'uint16': 'uint16_t', 'int16': 'int16_t',
'uint32': 'uint32_t', 'int32': 'int32_t',
'uint64': 'uint64_t', 'int64': 'int64_t',
'float32': 'float',
'float64': 'double',
'string': 'std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other > ',
'time': 'ros::Time',
'duration': 'ros::Duration'}
############################################################
# Built in types
############################################################
def is_fixnum(t):
return t in ['char', 'byte', 'int8', 'uint8', 'int16', 'uint16']
def is_integer(t):
return is_fixnum(t) or t in ['int32', 'uint32', 'int64', 'uint64']
def is_bool(t):
return t == 'bool'
def is_string(t):
return t == 'string'
def is_float(t):
return t in ['float16', 'float32', 'float64']
def is_time(t):
return t in ['time', 'duration']
def lisp_type(t):
if is_fixnum(t):
return 'fixnum'
elif is_integer(t):
return 'integer'
elif is_bool(t):
return 'boolean'
elif is_float(t):
return 'float'
elif is_time(t):
return 'real'
elif is_string(t):
return 'string'
else:
raise ValueError('%s is not a recognized primitive type'%t)
def lisp_initform(t):
if is_integer(t):
return '0'
elif is_bool(t):
return 'nil'
elif is_float(t):
return '0.0'
elif is_time(t):
return 0
elif is_string(t):
return '\"\"'
# todo remove
def msg_type_to_cpp(type):
"""
Converts a message type (e.g. uint32, std_msgs/String, etc.) into the C++ declaration
@ -92,24 +131,6 @@ def msg_type_to_cpp(type):
else:
return cpp_type
def cpp_message_declarations(name_prefix, msg):
"""
Returns the different possible C++ declarations for a message given the message itself.
@param name_prefix: The C++ prefix to be prepended to the name, e.g. "std_msgs::"
@type name_prefix: str
@param msg: The message type
@type msg: str
@return: A tuple of 3 different names. cpp_message_decelarations("std_msgs::", "String") returns the tuple
("std_msgs::String_", "std_msgs::String_<ContainerAllocator>", "std_msgs::String")
@rtype: str
"""
pkg, basetype = roslib.names.package_resource_name(msg)
cpp_name = '%s%s'%(name_prefix, msg)
if (pkg):
cpp_name = '%s::%s'%(pkg, basetype)
return ('%s_'%(cpp_name), '%s_<ContainerAllocator> '%(cpp_name), '%s'%(cpp_name))
def write_begin(s, spec, path):
"""
Writes the beginning of the file: a comment saying it's auto-generated and the in-package form
@ -121,8 +142,20 @@ def write_begin(s, spec, path):
@param path: The file this message is being generated for
@type path: str
"""
s.write(';; Auto-generated by genmsg_lisp for file %s\n'%path)
s.write('(in-package %s-msg)\n\n'%spec.package)
s.write('; Auto-generated. Do not edit!\n\n\n')
s.write('(in-package %s-msg)\n\n\n'%spec.package)
s.write(';//! \\htmlinclude %s.msg.html\n\n'%spec.short_name) # Can get rid of this
def write_slot_definition(s, field):
"""
Write the definition of a slot corresponding to a single message field
"""
s.write('(%s\n '%field.name)
s.write(':reader %s-val\n '%field.name)
s.write(':initarg :%s\n '%field.name)
s.write(':type %s\n '%lisp_type(field.type))
s.write(':initform %s)'%lisp_initform(field.type))
def write_defclass(s, spec):
"""
@ -134,6 +167,14 @@ def write_defclass(s, spec):
@type spec: roslib.msgs.MsgSpec
"""
s.write('(defclass %s (ros-message)\n ('%message_class(spec))
first_field = True
for field in spec.parsed_fields():
# Can get rid of this first_field stuff
if not first_field:
s.write('\n ')
first_field = False
write_slot_definition(s, field)
s.write(')\n)\n')
def message_class(spec):
@ -691,6 +732,87 @@ def write_ostream_operator(s, spec, cpp_name_prefix):
s.write('template<typename ContainerAllocator>\nstd::ostream& operator<<(std::ostream& s, const %s& v)\n{\n'%(cpp_msg_with_alloc))
s.write(' ros::message_operations::Printer<%s>::stream(s, "", v);\n return s;}\n\n'%(cpp_msg_with_alloc))
def write_serialize_length(s, v):
s.write(' (let ((__ros_str_len (length %s)))'%v)
for x in range(0, 32, 8):
s.write('\n (write-byte (ldb (byte 8 %s) __ros_str_len) ostream)'%x)
s.write(')\n')
def write_serialize_builtin(s, f):
if f.type == 'string':
v = '(slot-value msg \'%s)'%f.name
write_serialize_length(s, v)
s.write(' (map nil #\'(lambda (c) (write-byte (char-code c) ostream)) %s)\n'%v)
def write_serialize(s, spec):
"""
Write the serialize method
"""
s.write('(defmethod serialize ((msg %s) ostream)\n'%message_class(spec))
s.write(' "Serializes a message object of type \'%s"\n'%message_class(spec))
for field in spec.parsed_fields():
if field.is_array:
pass # todo
else:
if field.is_builtin:
write_serialize_builtin(s, field)
else:
pass # todo
def write_deserialize_length(s):
s.write(' (let ((__ros_str_len 0))')
for x in range(0, 32, 8):
s.write('\n (setf (ldb (byte 8 %s) __ros_str_len) (read-byte istream))'%x)
def write_deserialize_builtin(s, f):
if f.type == 'string':
v = '(slot-value msg \'%s)'%f.name
write_deserialize_length(s)
s.write('\n (setf %s (make-string __ros_str_len))'%v)
s.write('\n (dotimes (__ros_str_idx __ros_str_len msg)')
s.write('\n (setf (char %s __ros_str_idx) (code-char (read-byte istream)))))\n'%v)
def write_deserialize(s, spec):
"""
Write the deserialize method
"""
s.write('(defmethod deserialize ((msg %s) istream)\n'%message_class(spec))
s.write(' "Deserializes a message object of type \'%s"\n'%message_class(spec))
for field in spec.parsed_fields():
if field.is_array:
pass # todo
else:
if field.is_builtin:
write_deserialize_builtin(s, field)
else:
pass # todo
s.write(' msg\n)\n')
def write_ros_datatype(s, spec):
c = message_class(spec)
s.write('(defmethod ros-datatype ((msg (eql \'%s)))\n'%c)
s.write(' "Returns string type for a message object of type \'%s"\n'%c)
s.write(' "%s")\n'%spec.full_name)
def write_md5sum(s, spec):
gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package,
compute_files=False)
md5sum = roslib.gentools.compute_md5(gendeps_dict)
c = message_class(spec)
s.write('(defmethod md5sum ((type (eql \'%s)))\n'%c)
s.write(' "Returns md5sum for a message object of type \'%s"\n'%c)
s.write(' "%s")\n'%md5sum)
def write_message_definition(s, spec):
c = message_class(spec)
s.write('(defmethod message-definition ((type (eql \'%s)))\n'%c)
s.write(' "Returns full string definition for a message object of type \'%s"\n'%c)
def generate(msg_path):
"""
Generate a message
@ -703,12 +825,12 @@ def generate(msg_path):
s = StringIO()
write_begin(s, spec, msg_path)
write_defclass(s, spec)
write_constant_definitions(s, spec)
s.write('} // namespace %s\n\n'%(package))
write_serialize(s, spec)
write_deserialize(s, spec)
write_ros_datatype(s, spec)
write_md5sum(s, spec)
write_message_definition(s, spec)
output_dir = '%s/msg_gen/lisp'%package_dir
if (not os.path.exists(output_dir)):
@ -724,11 +846,7 @@ def generate(msg_path):
s.close()
def generate_messages(argv):
for arg in argv[1:]:
generate(arg)
if __name__ == "__main__":
roslib.msgs.set_verbose(True)
generate_messages(sys.argv)
generate(sys.argv[1])

View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
PKG=`rospack find $1`
FILENAME=$PKG/msg/$2.msg
echo "Running original genmsg_lisp on $FILENAME"
rosrun genmsg_cpp genmsg_lisp $FILENAME
echo "Running new genmsg_lisp.py"
rosrun roslisp genmsg_lisp.py $FILENAME
echo "Checking diffs"
diff $PKG/msg/lisp/$1/$2.lisp $PKG/msg_gen/lisp/$2.lisp | head -n 10