Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • anders_blomdell/labcomm
  • klaren/labcomm
  • tommyo/labcomm
  • erikj/labcomm
  • sven/labcomm
5 results
Select Git revision
Show changes
Showing
with 1512 additions and 148 deletions
package se.lth.control.labcomm2014;
import java.io.OutputStream;
import java.io.IOException;
class WriterWrapper implements Writer{
private OutputStream os;
public WriterWrapper(OutputStream os) {
this.os = os;
}
public void write(byte[] data) throws IOException {
os.write(data);
}
}
.PHONY: all
all:
.PHONY: test
test:
.PHONY: clean
clean:
find . -name '*.pyc' -exec rm {} \;
.PHONY: distclean
distclean: clean
import labcomm.LabComm
Decoder = labcomm.LabComm.Decoder
Encoder = labcomm.LabComm.Encoder
sample = labcomm.LabComm.sample
typedef = labcomm.LabComm.typedef
array = labcomm.LabComm.array
struct = labcomm.LabComm.struct
primitive = labcomm.LabComm.primitive
BOOLEAN = labcomm.LabComm.BOOLEAN
BYTE = labcomm.LabComm.BYTE
SHORT = labcomm.LabComm.SHORT
INTEGER = labcomm.LabComm.INTEGER
LONG = labcomm.LabComm.LONG
FLOAT = labcomm.LabComm.FLOAT
DOUBLE = labcomm.LabComm.DOUBLE
STRING = labcomm.LabComm.STRING
decl_from_signature = labcomm.LabComm.decl_from_signature
try:
import labcomm.TreeModel
TreeModel = labcomm.TreeModel.TreeModel
except:
pass
#!/usr/bin/python #!/usr/bin/python
# #
# All packets follows the following layout # LabComm2014 packet has the following layout
# #
# +----+----+----+----+ # +----+----+----+----+
# | id | # | id (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+ # +----+----+----+----+
# | data # | data
# | ... # | ...
# +----+-- # +----+--
# #
# Data layouts for packets # LabComm2014 SAMPLE_DEF:
# #
# TYPEDEF: # +----+----+----+----+
# | id = 0x02 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+
# | type name (UTF8)
# | ...
# +----+----+----+----+
# | signature length (packed32)
# +----+----+----+----+
# | type signature
# | ...
# +----+--
#
# LabComm2014 SAMPLE_REF:
# #
# +----+----+----+----+ # +----+----+----+----+
# | id = 0x00000001 | # | id = 0x03 (packed32)
# +----+----+----+----+ # +----+----+----+----+
# | type number | # | length (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+ # +----+----+----+----+
# | type name (UTF8) # | type name (UTF8)
# | ... # | ...
# +----+----+----+----+ # +----+----+----+----+
# | type # | signature length (packed32)
# +----+----+----+----+
# | type signature
# | ... # | ...
# +----+-- # +----+--
# #
# LabComm2014 TYPE_DEF: (as SAMPLE_DEF, but signatures are hierarchical,
# i.e., may contain references to other types
# #
# SAMPLE: # +----+----+----+----+
# | id = 0x04 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+
# | type name (UTF8)
# | ...
# +----+----+----+----+
# | signature length (packed32)
# +----+----+----+----+
# | type signature
# | ...
# +----+--
#
# LabComm2014 TYPE_BINDING
#
# +----+----+----+----+
# | id = 0x05 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | sample number (packed32)
# +----+----+----+----+
# | type number (packed32)
# +----+----+----+----+
#
# LabComm2014 User data:
#
# +----+----+----+----+
# | id >= 0x00000040 (packed32)
# +----+----+----+----+
# | length (packed32)
# +----+----+----+----+
# | user data
# | ...
# +----+--
#
#
# LabComm2006 packets has the following layout
#
# +----+----+----+----+
# | id |
# +----+----+----+----+
# | data
# | ...
# +----+--
#
# LabComm2006 SAMPLE:
# #
# +----+----+----+----+ # +----+----+----+----+
# | id = 0x00000002 | # | id = 0x00000002 |
...@@ -36,15 +109,15 @@ ...@@ -36,15 +109,15 @@
# | type name (UTF8) # | type name (UTF8)
# | ... # | ...
# +----+----+----+----+ # +----+----+----+----+
# | type # | type signature
# | ... # | ...
# +----+-- # +----+--
# #
# #
# User data: # LabComm2006 User data:
# #
# +----+----+----+----+ # +----+----+----+----+
# | id >= 0x00000060 | # | id >= 0x00000040 |
# +----+----+----+----+ # +----+----+----+----+
# | user data # | user data
# | ... # | ...
...@@ -89,18 +162,25 @@ ...@@ -89,18 +162,25 @@
#?? +----+----+----+----+ #?? +----+----+----+----+
# #
# #
# type numbers and lengths do not have a fixed lenght, but are packed into sequences # type numbers and lengths do not have a fixed lenght, but are packed into
# of 7 bit chunks, represented in bytes with the high bit meaning that more data # sequences of 7 bit chunks, represented in bytes with the high bit meaning
# is to come. # that more data is to come.
#
# The chunks are sent "little endian": each 7 bit chunk is more significant than
# the previous. See encode_packed32 and decode_packed32 in in Codec classes below.
import types
import struct as packer import struct as packer
i_TYPEDEF = 0x01 DEFAULT_VERSION = "LabComm2014"
i_SAMPLE = 0x02
# Allowed packet tags
i_VERSION = 0x01
i_SAMPLE_DEF = 0x02
i_SAMPLE_REF = 0x03
i_TYPE_DEF = 0x04
i_TYPE_BINDING= 0x05
i_PRAGMA = 0x3f
i_USER = 0x40 # ..0xffffffff
# Predefined types
i_ARRAY = 0x10 i_ARRAY = 0x10
i_STRUCT = 0x11 i_STRUCT = 0x11
...@@ -112,19 +192,55 @@ i_LONG = 0x24 ...@@ -112,19 +192,55 @@ i_LONG = 0x24
i_FLOAT = 0x25 i_FLOAT = 0x25
i_DOUBLE = 0x26 i_DOUBLE = 0x26
i_STRING = 0x27 i_STRING = 0x27
i_SAMPLE = 0x28
# Version testing
def usePacketLength(version):
return version in [ None, "LabComm2014" ]
class length_encoder:
def __init__(self, encoder):
self.encoder = encoder
self.version = encoder.version
self.data = ""
i_USER = 0x60 def write(self, data):
self.data += data
def __enter__(self):
return Encoder(writer=self, version=None, codec=self.encoder)
def __exit__(self, type, value, traceback):
if usePacketLength(self.version):
self.encoder.encode_packed32(len(self.data))
self.encoder.pack("%ds" % len(self.data), self.data)
def indent(i, s): def indent(i, s):
return ("\n%s" % (" " * i)).join(s.split("\n")) return ("\n%s" % (" " * i)).join(s.split("\n"))
#
# Base type for all decl's
#
class type_decl(object):
pass
# #
# Primitive types # Primitive types
# #
class primitive(object): class primitive(type_decl):
def decode_decl(self, decoder): def decode_decl(self, decoder):
return self return self
def __eq__(self, other):
return self.__class__ == other.__class__
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.__class__)
class BOOLEAN(primitive): class BOOLEAN(primitive):
def encode_decl(self, encoder): def encode_decl(self, encoder):
return encoder.encode_type(i_BOOLEAN) return encoder.encode_type(i_BOOLEAN)
...@@ -253,29 +369,66 @@ class STRING(primitive): ...@@ -253,29 +369,66 @@ class STRING(primitive):
def __repr__(self): def __repr__(self):
return "labcomm.STRING()" return "labcomm.STRING()"
class SAMPLE(primitive):
def encode_decl(self, encoder):
return encoder.encode_type(i_SAMPLE)
def encode(self, encoder, value):
if not isinstance(value, type_decl):
# Probably trying to encode a sample class, grab signature
value = value.signature
return encoder.encode_int(encoder.ref_to_index.get(value, 0))
def decode(self, decoder, obj=None):
return decoder.decode_ref()
def new_instance(self):
return ""
def __repr__(self):
return "labcomm.SAMPLE()"
# helper function
def dict_to_sorted_tuple(d):
tmpL = zip(d.keys(), d.values())
tmpL.sort()
return tuple(tmpL)
# #
# Aggregate types # Aggregate types
# #
class sample_or_typedef(object): class sampledef_or_sampleref_or_typedef(type_decl):
def __init__(self, name, decl): def __init__(self, intentions={}, decl=None):
self.name = name self.intentionDict = dict(intentions)
self.name = self.intentionDict.get('', None)
self.intentions = tuple(sorted(self.intentionDict.iteritems()))
self.decl = decl self.decl = decl
def encode_decl_tail(self, encoder): def encode_decl(self, encoder):
encoder.encode_type_number(self) encoder.encode_type(self.type_index)
encoder.encode_string(self.name) with length_encoder(encoder) as e1:
encoder.encode_type_number(self.decl) e1.encode_type(self.get_index(encoder))
# XXX: temporary hack for intentions
e1.encode_intentions(self.intentions)
with length_encoder(e1) as e2:
self.decl.encode_decl(e2)
def encode(self, encoder, object): def encode(self, encoder, value):
self.decl.encode(encoder, object) self.decl.encode(encoder, value)
def decode_decl(self, decoder): def decode_decl(self, decoder):
index = decoder.decode_type_number() index = decoder.decode_type_number()
name = decoder.decode_string() # XXX: temporary hack for intentions
# assume the name is the only intention
ints = decoder.decode_intentions()
if usePacketLength(decoder.version):
length = decoder.decode_packed32()
decl = decoder.decode_decl() decl = decoder.decode_decl()
result = self.__class__.__new__(self.__class__) result = self.__class__.__new__(self.__class__)
result.__init__(name, decl) result.__init__(intentions=ints, decl=decl)
decoder.add_decl(result, index) self.add_index(decoder, index, result)
return result return result
def decode(self, decoder, obj=None): def decode(self, decoder, obj=None):
...@@ -286,30 +439,81 @@ class sample_or_typedef(object): ...@@ -286,30 +439,81 @@ class sample_or_typedef(object):
def new_instance(self): def new_instance(self):
return self.decl.new_instance() return self.decl.new_instance()
def __repr__(self): def __eq__(self, other):
return "'%s', %s" % (self.name, self.decl) return (self.__class__ == other.__class__ and
self.name == other.name and
self.decl == other.decl)
class sample(sample_or_typedef): def __ne__(self, other):
def encode_decl(self, encoder): return not self.__eq__(other)
encoder.encode_type(i_SAMPLE)
self.encode_decl_tail(encoder) def __hash__(self):
return hash(self.__class__) ^ hash(self.name) ^ hash(self.decl)
def __repr__(self): def __repr__(self):
return "labcomm.sample(%s)" % super(sample, self).__repr__() return "%s('%s', %s)" % (self.type_name, self.name, self.decl)
class sample_def(sampledef_or_sampleref_or_typedef):
type_index = i_SAMPLE_DEF
type_name = 'sample'
def get_index(self, encoder):
return encoder.decl_to_index[self]
def add_index(self, decoder, index, decl):
decoder.add_decl(decl, index)
def rename(self, name):
newIntentions = dict(self.intentionDict)
newIntentions['']=name
return sample_def(newIntentions, decl=self.decl)
class sample_ref(sampledef_or_sampleref_or_typedef):
type_index = i_SAMPLE_REF
type_name = 'sample_ref'
def __init__(self, intentions={}, decl=None, sample=None):
self.intentionDict = dict(intentions)
self.name = self.intentionDict.get('', None) # XXX should we allow nameless?
self.decl = decl
self.intentions=tuple(sorted(self.intentionDict.iteritems()))
if sample == None and self.name != None and decl != None:
self.sample = sample_def(intentions, decl)
else:
self.sample = sample
def get_index(self, encoder):
return encoder.ref_to_index[self.sample]
def add_index(self, decoder, index, decl):
decoder.add_ref(decl, index)
class typedef(sampledef_or_sampleref_or_typedef):
type_index = i_TYPE_DEF
type_name = 'typedef'
class typedef(sample_or_typedef):
def encode_decl(self, encoder): def encode_decl(self, encoder):
encoder.encode_type(i_TYPEDEF) self.decl.encode_decl(encoder)
self.encode_decl_tail(encoder)
def __repr__(self): def encode(self, encoder, value):
return "labcomm.typedef(%s)" % super(typedef, self).__repr__() self.decl.encode(encoder, value)
class array(object): class array(type_decl):
def __init__(self, indices, decl): def __init__(self, indices, decl):
self.indices = indices self.indices = tuple(indices)
self.decl = decl self.decl = decl
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self.indices == other.indices and
self.decl == other.decl)
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.__class__) ^ hash(self.indices) ^ hash(self.decl)
def encode_decl(self, encoder): def encode_decl(self, encoder):
encoder.encode_type(i_ARRAY) encoder.encode_type(i_ARRAY)
encoder.encode_packed32(len(self.indices)) encoder.encode_packed32(len(self.indices))
...@@ -317,18 +521,26 @@ class array(object): ...@@ -317,18 +521,26 @@ class array(object):
encoder.encode_packed32(i) encoder.encode_packed32(i)
encoder.encode_type_number(self.decl) encoder.encode_type_number(self.decl)
def min_max_shape(self, l, depth=0, shape=[]): def min_max_shape(self, l, depth, shape):
if isinstance(l, list): if isinstance(l, types.StringTypes):
return shape
try:
length = len(l) length = len(l)
if len(shape) <= depth: if len(shape) <= depth:
shape.append((length, length)) shape.append((length, length))
pass
else: else:
(low, high) = shape[depth] (low, high) = shape[depth]
low = min(low, length) low = min(low, length)
high = max(high, length) high = max(high, length)
shape[depth] = (low, high) shape[depth] = (low, high)
pass
for e in l: for e in l:
shape = self.min_max_shape(e, depth + 1, shape) shape = self.min_max_shape(e, depth + 1, shape)
pass
pass
except TypeError:
pass
return shape return shape
def shape(self, l): def shape(self, l):
...@@ -344,7 +556,6 @@ class array(object): ...@@ -344,7 +556,6 @@ class array(object):
def encode_indices(self, encoder, value): def encode_indices(self, encoder, value):
depth = len(self.indices) depth = len(self.indices)
shape = self.shape(value) shape = self.shape(value)
#if len(shape) != len(self.indices):
if len(shape) < len(self.indices): if len(shape) < len(self.indices):
raise Exception("Actual dimension %s differs from declared %s" % raise Exception("Actual dimension %s differs from declared %s" %
(shape, self.indices)) (shape, self.indices))
...@@ -357,7 +568,7 @@ class array(object): ...@@ -357,7 +568,7 @@ class array(object):
return depth return depth
def encode_value(self, encoder, value, depth): def encode_value(self, encoder, value, depth):
if depth and isinstance(value, list): if depth:
for e in value: for e in value:
self.encode_value(encoder, e, depth - 1) self.encode_value(encoder, e, depth - 1)
else: else:
...@@ -414,104 +625,119 @@ class array(object): ...@@ -414,104 +625,119 @@ class array(object):
return "labcomm.array(%s,\n %s)" % ( return "labcomm.array(%s,\n %s)" % (
self.indices, indent(4, self.decl.__repr__())) self.indices, indent(4, self.decl.__repr__()))
class struct: class struct(type_decl):
def __init__(self, field): def __init__(self, field):
self.field = field self.field = tuple(field)
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self.field == other.field)
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.__class__) ^ hash(self.field)
def encode_decl(self, encoder): def encode_decl(self, encoder):
encoder.encode_type(i_STRUCT) encoder.encode_type(i_STRUCT)
encoder.encode_packed32(len(self.field)) encoder.encode_packed32(len(self.field))
for (name, decl) in self.field: for (intentions, decl) in self.field:
encoder.encode_string(name) encoder.encode_intentions(intentions)
encoder.encode_type_number(decl) encoder.encode_type_number(decl)
#type.encode_decl(encoder)
def encode(self, encoder, obj): def encode(self, encoder, obj):
if isinstance(obj, dict): try:
for (name, decl) in self.field: # hack to get names as keys in the obj:
decl.encode(encoder, obj[name]) tmp_foo = zip (map(lambda x:dict(x)[''],obj.keys()), obj.values())
else: tmp_obj = dict(tmp_foo)
for (name, decl) in self.field: for (intentions, decl) in self.field:
decl.encode(encoder, obj.__getattribute__(name)) tmp = dict(intentions)
name = tmp['']
decl.encode(encoder, tmp_obj[name])
except AttributeError:
print "HERE BE DRAGONS! hack to get duck-typing example to work"
for (intentions, decl) in self.field:
tmp = dict(intentions)
name = tmp['']
print "trying to encode [%s] " % (name)
decl.encode(encoder, getattr(obj, name))
def decode_decl(self, decoder): def decode_decl(self, decoder):
n_field = decoder.decode_packed32() n_field = decoder.decode_packed32()
field = [] field = []
for i in range(n_field): for i in range(n_field):
name = decoder.decode_string() ints = decoder.decode_intentions()
decl = decoder.decode_decl() decl = decoder.decode_decl()
field.append((name, decl)) field.append((ints, decl))
return struct(field) return struct(field)
def decode(self, decoder, obj=None): def decode(self, decoder, obj=None):
if obj == None: if obj == None:
obj = decoder.create_object() obj = decoder.create_object()
for (name, decl) in self.field: for (intentions, decl) in self.field:
obj.__setattr__(name, decl.decode(decoder)) #name = dict(intentions)['']
obj.__setattr__(intentions, decl.decode(decoder))
return obj return obj
def new_instance(self): def new_instance(self):
result = anonymous_object() result = anonymous_object()
for (name, decl) in self.field: for (intentions, decl) in self.field:
name = dict(intentions)['']
result.__setattr__(name, decl.new_instance()) result.__setattr__(name, decl.new_instance())
return result return result
def __repr__(self): def __repr__(self):
delim = "" delim = ""
result = "labcomm.struct([" result = "labcomm.struct(["
for (name, decl) in self.field: for (intentions, decl) in self.field:
try:
name = dict(intentions)['']
except:
name = '(no name)'
result += "%s\n ('%s', %s)" % (delim, name, decl) result += "%s\n ('%s', %s)" % (delim, name, decl)
delim = "," delim = ","
result += "\n])" result += "\n])"
return result return result
SAMPLE = sample(None, None) SAMPLE_DEF = sample_def()
TYPEDEF = typedef(None, None) SAMPLE_REF = sample_ref()
ARRAY = array(None, None)
STRUCT = struct({})
class anonymous_object(object): ARRAY = array([], None)
def __init__(self): STRUCT = struct([])
self._attr = {}
class anonymous_object(dict):
def __setattr__(self, name, value): def __setattr__(self, name, value):
if name.startswith("_"): # XXX HERE BE DRAGONS! Is this OK:
if (str(name)).startswith("_"):
super(anonymous_object, self).__setattr__(name, value) super(anonymous_object, self).__setattr__(name, value)
else: else:
self._attr[name] = value self[name] = value
def __getattr__(self, name): def __getattr__(self, name):
if name.startswith("_"): if name.startswith("_"):
return super(anonymous_object, self).__getattr__(name) return super(anonymous_object, self).__getattr__(name)
else: else:
return self._attr[name] return self[name]
def __getattribute__(self, name):
if name.startswith("_"):
return super(anonymous_object, self).__getattribute__(name)
else:
return self._attr[name]
def __iter__(self):
return self._attr.iteritems()
def __repr__(self):
return self._attr.__repr__()
class Codec(object): class Codec(object):
def __init__(self): def __init__(self, codec=None):
self.type_to_name = {} self.type_to_name = codec and codec.type_to_name or {}
self.name_to_type = {} self.name_to_type = codec and codec.name_to_type or {}
self.index_to_decl = {} self.index_to_decl = codec and codec.index_to_decl or {}
self.decl_to_index = {} self.decl_to_index = codec and codec.decl_to_index or {}
self.name_to_decl = {} self.name_to_decl = codec and codec.name_to_decl or {}
self.decl_index = i_USER self.index_to_ref = codec and codec.index_to_ref or {}
self.ref_to_index = codec and codec.ref_to_index or {}
self.name_to_ref = codec and codec.name_to_ref or {}
self.decl_index = codec and codec.decl_index or i_USER
self.ref_index = codec and codec.ref_index or i_USER
if not codec:
self.predefined_types() self.predefined_types()
def predefined_types(self): def predefined_types(self):
self.add_decl(TYPEDEF, i_TYPEDEF) self.add_decl(SAMPLE_DEF, i_SAMPLE_DEF)
self.add_decl(SAMPLE, i_SAMPLE) self.add_decl(SAMPLE_REF, i_SAMPLE_REF)
self.add_decl(ARRAY, i_ARRAY) self.add_decl(ARRAY, i_ARRAY)
self.add_decl(STRUCT, i_STRUCT) self.add_decl(STRUCT, i_STRUCT)
...@@ -524,9 +750,12 @@ class Codec(object): ...@@ -524,9 +750,12 @@ class Codec(object):
self.add_decl(FLOAT(), i_FLOAT) self.add_decl(FLOAT(), i_FLOAT)
self.add_decl(DOUBLE(), i_DOUBLE) self.add_decl(DOUBLE(), i_DOUBLE)
self.add_decl(STRING(), i_STRING) self.add_decl(STRING(), i_STRING)
self.add_decl(SAMPLE(), i_SAMPLE)
def add_decl(self, decl, index=0): def add_decl(self, decl, index=0):
if index == 0: if index == 0:
if decl in self.decl_to_index:
return False
index = self.decl_index index = self.decl_index
self.decl_index += 1 self.decl_index += 1
self.index_to_decl[index] = decl self.index_to_decl[index] = decl
...@@ -535,6 +764,24 @@ class Codec(object): ...@@ -535,6 +764,24 @@ class Codec(object):
self.name_to_decl[decl.name] = decl self.name_to_decl[decl.name] = decl
except: except:
pass pass
return True
def add_ref(self, ref, index=0):
if not isinstance(ref, type_decl):
# Probably trying to register a sample class, grab signature
ref = ref.signature
if index == 0:
if ref.sample in self.ref_to_index:
return False
index = self.ref_index
self.ref_index += 1
self.index_to_ref[index] = ref.sample
self.ref_to_index[ref.sample] = index
try:
self.name_to_ref[ref.sample.name] = ref.sample
except:
pass
return True
def add_binding(self, name, decl): def add_binding(self, name, decl):
self.type_to_name[decl] = name self.type_to_name[decl] = name
...@@ -552,26 +799,53 @@ class Codec(object): ...@@ -552,26 +799,53 @@ class Codec(object):
class Encoder(Codec): class Encoder(Codec):
def __init__(self, writer): def __init__(self, writer, version=DEFAULT_VERSION, codec=None):
super(Encoder, self).__init__() super(Encoder, self).__init__(codec)
self.writer = writer self.writer = writer
self.version = version
if self.version in [ "LabComm2014" ]:
self.encode_type(i_VERSION)
with length_encoder(self) as e:
e.encode_string(version)
elif self.version in [ None, "LabComm2006" ]:
pass
else:
raise Exception("Unsupported labcomm version %s" % self.version)
def pack(self, format, *args): def pack(self, format, *args):
self.writer.write(packer.pack(format, *args)) self.writer.write(packer.pack(format, *args))
def add_decl(self, decl, index=0): def add_decl(self, decl, index=0):
super(Encoder, self).add_decl(decl, index) if not isinstance(decl, type_decl):
decl = decl.signature
if index == 0:
self.writer.mark_begin(decl, None)
if super(Encoder, self).add_decl(decl, index):
decl.encode_decl(self)
self.writer.mark_end(decl, None)
def add_ref(self, ref, index=0):
if not isinstance(ref, type_decl):
# Trying to register a sample class
ref = ref.signature
decl = sample_ref(intentions=ref.intentions, decl=ref.decl, sample=ref)
if index == 0: if index == 0:
self.writer.mark_begin(ref, None)
if super(Encoder, self).add_ref(decl, index):
decl.encode_decl(self) decl.encode_decl(self)
self.writer.mark() self.writer.mark_end(ref, None)
def encode(self, object, decl=None): def encode(self, object, decl=None):
if decl == None: if decl == None:
name = self.type_to_name[object.__class__] name = self.type_to_name[object.__class__]
decl = self.name_to_decl[name] decl = self.name_to_decl[name]
if not isinstance(decl, type_decl):
decl = decl.signature
self.writer.mark_begin(decl, object)
self.encode_type_number(decl) self.encode_type_number(decl)
decl.encode(self, object) with length_encoder(self) as e:
self.writer.mark() decl.encode(e, object)
self.writer.mark_end(decl, object)
def encode_type_number(self, decl): def encode_type_number(self, decl):
try: try:
...@@ -580,16 +854,23 @@ class Encoder(Codec): ...@@ -580,16 +854,23 @@ class Encoder(Codec):
decl.encode_decl(self) decl.encode_decl(self)
def encode_packed32(self, v): def encode_packed32(self, v):
tmp = v & 0xffffffff; if self.version in [ None, "LabComm2014" ]:
v = v & 0xffffffff
while(tmp >= 0x80 ): tmp = [ v & 0x7f ]
self.encode_byte( (tmp & 0x7f) | 0x80 ) v = v >> 7
tmp >>= 7 while v:
self.encode_byte(tmp & 0x7f) tmp.append(v & 0x7f | 0x80)
v = v >> 7
for c in reversed(tmp):
self.encode_byte(c)
elif self.version == "LabComm2006" :
v = v & 0xffffffff
self.encode_int(v)
else :
raise Exception("Unsupported labcomm version %s" % self.version)
def encode_type(self, index): def encode_type(self, index):
self.encode_packed32(index) self.encode_packed32(index)
# self.pack("!i", index)
def encode_boolean(self, v): def encode_boolean(self, v):
if v: if v:
...@@ -598,7 +879,7 @@ class Encoder(Codec): ...@@ -598,7 +879,7 @@ class Encoder(Codec):
self.pack("!b", 0) self.pack("!b", 0)
def encode_byte(self, v): def encode_byte(self, v):
self.pack("!b", v) self.pack("!B", v)
def encode_short(self, v): def encode_short(self, v):
self.pack("!h", v) self.pack("!h", v)
...@@ -619,12 +900,25 @@ class Encoder(Codec): ...@@ -619,12 +900,25 @@ class Encoder(Codec):
s = v.encode("utf8") s = v.encode("utf8")
self.encode_packed32(len(s)); self.encode_packed32(len(s));
self.pack("%ds" % len(s),s) self.pack("%ds" % len(s),s)
# self.pack("!i%ds" % len(s), len(s), s)
def encode_intentions(self, intentions):
self.encode_packed32(len(intentions))
try:
for (k,v) in intentions:
self.encode_string(k)
self.encode_string(v)
except:
print "WARNING! encode_intentions: don't know what to do with %s" % intentions
class Decoder(Codec): class Decoder(Codec):
def __init__(self, reader): def __init__(self, reader, version=DEFAULT_VERSION):
super(Decoder, self).__init__() super(Decoder, self).__init__()
self.reader = reader self.reader = reader
self.version = version
self.handlers = {}
def register_handler(self, decl, handler):
self.handlers[decl] = handler
def unpack(self, format): def unpack(self, format):
size = packer.calcsize(format) size = packer.calcsize(format)
...@@ -639,15 +933,73 @@ class Decoder(Codec): ...@@ -639,15 +933,73 @@ class Decoder(Codec):
result = self.index_to_decl[index] result = self.index_to_decl[index]
if index < i_USER: if index < i_USER:
result = result.decode_decl(self) result = result.decode_decl(self)
else:
raise Exception('Should not be used')
return result return result
def skip(self, length):
for _ in xrange(length):
self.decode_byte()
# kludge, should really check if the index exists in self.version
def skip_or_raise(self, length, index):
if usePacketLength(self.version):
self.skip(length)
else:
raise Exception("Invalid type index %d" % index)
def runOne(self):
data,decl = self.decode()
# decode any signatures until next sample
while data == None:
data,decl = self.decode()
if decl:
if data != None:
if decl in self.handlers:
handler = self.handlers[decl]
handler(data)
else:
print ("No handler for %s" % decl.name )
for key, value in self.handlers.iteritems():
if key == decl:
print "but value %s == decl %s" % (key,decl)
print "hashes %d : %d" % (hash(key),hash(decl))
raise Exception()
def decode(self): def decode(self):
value = None while True:
index = self.decode_type_number() index = self.decode_type_number()
decl = self.index_to_decl[index] if usePacketLength(self.version):
if index == i_TYPEDEF or index == i_SAMPLE: length = self.decode_packed32()
decl = decl.decode_decl(self) if index != i_VERSION:
break
else: else:
other_version = self.decode_string()
if self.version != other_version:
raise Exception("LabComm version mismatch %s != %s" %
(version, other_version))
if index == i_SAMPLE_DEF:
decl = self.index_to_decl[index].decode_decl(self)
value = None
elif index == i_SAMPLE_REF:
decl = self.index_to_decl[index].decode_decl(self)
value = None
elif index == i_TYPE_DEF:
self.skip_or_raise(length, index)
decl = None
value = None
elif index == i_TYPE_BINDING:
self.skip_or_raise(length, index)
decl = None
value = None
elif index == i_PRAGMA:
self.skip_or_raise(length, index)
decl = None
value = None
elif index < i_USER:
raise Exception("Invalid type index %d" % index)
else:
decl = self.index_to_decl[index]
value = decl.decode(self) value = decl.decode(self)
self.reader.mark(value, decl) self.reader.mark(value, decl)
return (value, decl) return (value, decl)
...@@ -666,14 +1018,18 @@ class Decoder(Codec): ...@@ -666,14 +1018,18 @@ class Decoder(Codec):
return result return result
def decode_packed32(self): def decode_packed32(self):
res = 0 if self.version in [ "LabComm2013", "LabComm2014" ] :
i = 0 result = 0
cont = True while True:
while (cont): tmp = self.decode_byte()
c = self.decode_byte() result = (result << 7) | (tmp & 0x7f)
res |= (c & 0x7f) << 7*i if (tmp & 0x80) == 0:
cont = (c & 0x80) != 0; break
return res return result
elif self.version == "LabComm2006" :
return self.decode_int()
else :
raise Exception("Unsupported labcomm version %s" % self.version)
def decode_type_number(self): def decode_type_number(self):
return self.decode_packed32() return self.decode_packed32()
...@@ -682,7 +1038,7 @@ class Decoder(Codec): ...@@ -682,7 +1038,7 @@ class Decoder(Codec):
return self.unpack("!b") != 0 return self.unpack("!b") != 0
def decode_byte(self): def decode_byte(self):
return self.unpack("!b") return self.unpack("!B")
def decode_short(self): def decode_short(self):
return self.unpack("!h") return self.unpack("!h")
...@@ -703,6 +1059,19 @@ class Decoder(Codec): ...@@ -703,6 +1059,19 @@ class Decoder(Codec):
length = self.decode_packed32() length = self.decode_packed32()
return self.unpack("!%ds" % length).decode("utf8") return self.unpack("!%ds" % length).decode("utf8")
def decode_ref(self):
index = self.decode_int()
return self.index_to_ref.get(index, None)
def decode_intentions(self):
numIntentions = self.decode_packed32()
res = {}
for i in range(numIntentions):
key = self.decode_string()
val = self.decode_string()
res[key] = val
result = dict_to_sorted_tuple(res)
return result
class signature_reader: class signature_reader:
def __init__(self, signature): def __init__(self, signature):
......
class StreamReader:
def __init__(self, stream):
self.stream = stream
pass
def read(self, count):
result = self.stream.read(count)
if len(result) == 0:
raise EOFError()
return result
def mark(self, value, decl):
pass
pass
class StreamWriter:
def __init__(self, stream):
self.stream = stream
pass
def write(self, data):
self.stream.write(data)
pass
def mark_begin(self, decl, value):
pass
def mark_end(self, decl, value):
self.stream.flush()
pass
pass
__all__ = [ 'LabComm' ]
import LabComm
from StreamReader import StreamReader
from StreamWriter import StreamWriter
Decoder = LabComm.Decoder
Encoder = LabComm.Encoder
sample = LabComm.sample_def
sample_def = LabComm.sample_def
sample_ref = LabComm.sample_ref
typedef = LabComm.typedef
array = LabComm.array
struct = LabComm.struct
primitive = LabComm.primitive
BOOLEAN = LabComm.BOOLEAN
BYTE = LabComm.BYTE
SHORT = LabComm.SHORT
INTEGER = LabComm.INTEGER
LONG = LabComm.LONG
FLOAT = LabComm.FLOAT
DOUBLE = LabComm.DOUBLE
STRING = LabComm.STRING
SAMPLE = LabComm.SAMPLE
decl_from_signature = LabComm.decl_from_signature
labcomm2014-*.src.rpm
rpmbuild
.PHONY: all
all:
.PHONY: test
test:
.PHONY: clean
clean:
rm -rf rpmbuild
rm -f *~
.PHONY: distclean
distclean: clean
rm -f labcomm-*.src.rpm
.PHONY: srpm
srpm:
./make_srpm
#!/bin/sh
spec() {
cat << 'EOF'
Name: labcomm__SUFFIX__
Version: __VERSION__
Release: 1
Summary: LabComm communication protocol
License: GPLv3
# https://gitlab.control.lth.se/anders_blomdell/labcomm/repository/archive.tar.gz?__COMMIT__
Source0: labcomm.__DESCRIBE__.tar.gz
BuildRequires: gcc
BuildRequires: ant
BuildRequires: java
BuildRequires: mono-core
%description
LabComm communication protocol
%package devel
Summary: LabComm communication protocol
Requires: %{name} = %{version}-%{release}
%description devel
LabComm communication protocol
%
%prep
%setup -q -c -a 0
%build
pwd
make
%install
#
# C
#
install -d ${RPM_BUILD_ROOT}/%{_libdir}
install lib/c/liblabcomm2014.a ${RPM_BUILD_ROOT}/%{_libdir}/
install lib/c/liblabcomm2014.so.1 ${RPM_BUILD_ROOT}/%{_libdir}/liblabcomm2014.so.__VERSION__
ln -s liblabcomm2014.so.__VERSION__ ${RPM_BUILD_ROOT}/%{_libdir}/liblabcomm2014.so
install -d ${RPM_BUILD_ROOT}/%{_includedir}/labcomm
install lib/c/2014/*h ${RPM_BUILD_ROOT}/%{_includedir}/labcomm
#
# java
#
install -d ${RPM_BUILD_ROOT}/usr/lib
install -m u=r,g=r,o=r compiler/labcomm2014_compiler.jar ${RPM_BUILD_ROOT}/usr/lib
install -m u=r,g=r,o=r lib/java/labcomm2014.jar ${RPM_BUILD_ROOT}/usr/lib
install -d ${RPM_BUILD_ROOT}/%{_bindir}
install -m u=rx,g=rx,o=rx \
compiler/labcomm2014 ${RPM_BUILD_ROOT}/%{_bindir}/labcomm2014
ls -l ${RPM_BUILD_ROOT}/%{_bindir}
#
# C#
#
install -d ${RPM_BUILD_ROOT}/usr/lib
install -m u=r,g=r,o=r lib/csharp/labcomm2014.dll ${RPM_BUILD_ROOT}/usr/lib
#
# Python
#
install -d ${RPM_BUILD_ROOT}/%{python_sitelib}/labcomm2014
install lib/python/labcomm2014/* ${RPM_BUILD_ROOT}/%{python_sitelib}/labcomm2014
%files
%defattr (-, root, root)
%exclude /usr/lib/debug
%exclude /usr/lib/labcomm2014_compiler.jar
/usr/lib/*
%{_libdir}/*
%files devel
%defattr (-, root, root)
/usr/lib/labcomm2014_compiler.jar
%{_includedir}/labcomm/*
%{_bindir}/*
EOF
}
# Create a suitable directory for rpmbuild
rm -rf rpmbuild
mkdir -p rpmbuild/BUILD
mkdir -p rpmbuild/SPECS
mkdir -p rpmbuild/RPMS
mkdir -p rpmbuild/SRPMS
mkdir -p rpmbuild/SOURCES
rm -rf rpmbuild/SOURCES/*
# Create spec and .tar.gz
DESCRIBE=$(git describe | sed -e 's/^v\(.*\)/\1/')
SUFFIX=$(echo ${DESCRIBE} | sed -e 's/^\([^.]*\)[.].*$/\1/g')
VERSION=$(echo ${DESCRIBE} | sed -e 's/^[^.]*[.]\(.*\)/\1/g;s/-/./g')
COMMIT=$(git rev-parse HEAD)
(
spec | \
sed -e "s/__SUFFIX__/${SUFFIX}/g" | \
sed -e "s/__VERSION__/${VERSION}/g" | \
sed -e "s/__DESCRIBE__/${DESCRIBE}/g" | \
sed -e "s/__COMMIT__/${COMMIT}/g" \
) > rpmbuild/SPECS/labcomm.spec
(
cd $(git rev-parse --show-toplevel)
git archive --format tar HEAD
) > rpmbuild/SOURCES/labcomm.${DESCRIBE}.tar.gz
rpmbuild --define "_topdir $(pwd)/rpmbuild" \
-bs rpmbuild/SPECS/labcomm.spec 2>&1 | sed -e 's|rpmbuild/SRPMS/||g'
mv rpmbuild/SRPMS/* .
gen
TESTS=basic simple nested ref
LABCOMM_JAR=../compiler/labcomm2014_compiler.jar
LABCOMM=java -jar $(LABCOMM_JAR)
MONO_PATH=$(shell pwd)/../lib/csharp
PYTHONPATH=$(shell pwd)/../lib/python
include ../lib/c/os_compat.mk
all:
test: $(TESTS:%=test_%) $(TESTS:%=test_renaming_%) compiler_errors
# PYTHONPATH=../lib/python \
# ./test_encoder_decoder.py --labcomm="$(LABCOMM)" basic.lc
.PHONY: clean distclean
clean distclean:
rm -rf gen
.PHONY: test_%
test_%: gen/%/signatures.py \
gen/%/c_relay \
gen/%/cs_relay.exe \
gen/%/java_relay.class \
gen/%/java_code
PYTHONPATH=$(PYTHONPATH) MONO_PATH=$(MONO_PATH) \
./test_encoder_decoder.py \
--signatures=gen/$*/signatures.py \
--test tee gen/$*/testdata \
--test $(shell echo $(VALGRIND) | sed -e 's/[-][-]/\\\\--/g') \
gen/$*/c_relay /dev/stdin /dev/stdout \
--test mono gen/$*/cs_relay.exe /dev/stdin /dev/stdout \
--test java \\-cp gen/$*:../lib/java/labcomm2014.jar \
java_relay /dev/stdin /dev/stdout
.PHONY: test_renaming_%
test_renaming_%: gen/%/signatures.py \
gen/%/c_renaming_relay \
gen/%/cs_renaming_relay.exe \
gen/%/java_relay.class \
gen/%/java_code
PYTHONPATH=$(PYTHONPATH) MONO_PATH=$(MONO_PATH) \
./test_renaming_encoder_decoder.py \
--signatures=gen/$*/signatures.py \
--test tee gen/$*/testdata.renamed \
--test $(shell echo $(VALGRIND) | sed -e 's/[-][-]/\\\\--/g') \
gen/$*/c_renaming_relay /dev/stdin /dev/stdout \
--test mono gen/$*/cs_renaming_relay.exe \
/dev/stdin /dev/stdout
echo \
--test java \\-cp gen/$*:../lib/java/labcomm2014.jar \
java_relay /dev/stdin /dev/stdout
# test cases for compiler error checking
.PHONY: compiler_errors testErrorsOK testErrorsNOK
compiler_errors: testErrorsOK testErrorsNOK
# tests that should succeed
testErrorsOK: $(wildcard errors/correct/*.lc)
./test_errors.py --labcomm="$(LABCOMM)" --testOK $^
# tests that should fail
testErrorsNOK: $(wildcard errors/incorrect/*.lc)
./test_errors.py --labcomm="$(LABCOMM)" --testNOK $^
.PRECIOUS: gen/%/.dir
gen/%/.dir:
mkdir -p gen/$*
touch $@
.PRECIOUS: gen/%/typeinfo
gen/%/typeinfo: %.lc Makefile | gen/%/.dir
$(LABCOMM) --typeinfo=$@ $<
.PRECIOUS: gen/%/signatures.py
gen/%/signatures.py: %.lc Makefile | gen/%/.dir
$(LABCOMM) --python=$@ $<
# C relay test rules
.PRECIOUS: gen/%/c_code.h gen/%/c_code.c
gen/%/c_code.h gen/%/c_code.c: %.lc Makefile | gen/%/.dir
$(LABCOMM) --c=gen/$*/c_code.c --h=gen/$*/c_code.h $<
.PRECIOUS: gen/%/c_relay.c
gen/%/c_relay.c: gen/%/typeinfo relay_gen_c.py Makefile
./relay_gen_c.py $< > $@
.PRECIOUS: gen/%/c_relay
gen/%/c_relay: gen/%/c_relay.c gen/%/c_code.c Makefile
$(CC) $(CFLAGS) -o $@ $< -I../lib/c/2014 -I. -L../lib/c \
gen/$*/c_code.c -llabcomm2014
.PRECIOUS: gen/%/c_renaming_relay.c
gen/%/c_renaming_relay.c: gen/%/typeinfo relay_gen_c.py Makefile
./relay_gen_c.py --renaming $< > $@
.PRECIOUS: gen/%/c_renaming_relay
gen/%/c_renaming_relay: gen/%/c_renaming_relay.c gen/%/c_code.c Makefile
$(CC) $(CFLAGS) -o $@ $< -I../lib/c/2014 -I. -L../lib/c \
gen/$*/c_code.c -llabcomm2014
# C# relay test rules
.PRECIOUS: gen/%/cs_code.cs
gen/%/cs_code.cs: %.lc Makefile | gen/%/.dir
$(LABCOMM) --cs=$@ $<
.PRECIOUS: gen/%/cs_relay.cs
gen/%/cs_relay.cs: gen/%/typeinfo relay_gen_cs.py Makefile
./relay_gen_cs.py $< > $@
.PRECIOUS: gen/%/cs_relay.exe
gen/%/cs_relay.exe: gen/%/cs_relay.cs gen/%/cs_code.cs Makefile
mcs -out:$@ $(filter %.cs, $^) -lib:../lib/csharp/ -r:labcomm2014
.PRECIOUS: gen/%/cs_renaming_relay.cs
gen/%/cs_renaming_relay.cs: gen/%/typeinfo relay_gen_cs.py Makefile
./relay_gen_cs.py --renaming $< > $@
.PRECIOUS: gen/%/cs_renaming_relay.exe
gen/%/cs_renaming_relay.exe: gen/%/cs_renaming_relay.cs \
gen/%/cs_code.cs Makefile
mcs -out:$@ $(filter %.cs, $^) -lib:../lib/csharp/ -r:labcomm2014
# Java relay test rules
.PRECIOUS: gen/%/java_code
gen/%/java_code: %.lc | gen/%/.dir
mkdir -p $@
$(LABCOMM) --java=$@ $<
.PRECIOUS: gen/%/java_relay.java
gen/%/java_relay.java: gen/%/typeinfo relay_gen_java.py Makefile
./relay_gen_java.py $< > $@
.PRECIOUS: gen/%/java_relay.class
gen/%/java_relay.class: gen/%/java_relay.java gen/%/java_code Makefile
javac -d gen/$* -cp ../lib/java/labcomm2014.jar:gen/$*/java_code $<
sample void s_void;
sample byte s_byte;
sample short s_short;
sample int s_int;
sample long s_long;
sample float s_float;
sample double s_double;
sample boolean s_boolean;
sample string s_string;
def gen(f, signatures):
print """
#include <labcomm.h>
#include <labcomm_fd_reader_writer.h>
#include "%(f)s.h"
""" % { 'f': f }
for s in [s.name for s in signatures]:
t = "%s_%s" % (f, s)
print """
void handle_%(t)s(%(t)s *v, void *context)
{
struct labcomm_encoder *e = context;
labcomm_encode_%(t)s(e, v);
}
""" % {'t':t}
print """
int main(int argc, char *argv[]) {
struct labcomm_decoder *d;
struct labcomm_encoder *e;
"""
#!/usr/bin/python
import os
import re
import subprocess
import sys
def gen(classname, namespace, signatures):
yield 'using System;'
yield 'using System.IO;'
yield 'using se.lth.control.labcomm;'
yield ''
yield 'class %s :' % classname
for s in signatures[0:-1]:
yield '%s%s.Handler,' % (namespace, s.name)
yield '%s%s.Handler' % (namespace, signatures[-1].name)
yield '{'
yield ''
yield ' LabCommEncoderChannel encoder;'
for s in signatures:
yield ''
if s.type == 'void':
yield ' void %s%s.Handler.handle() {' % ( namespace, s.name)
else:
yield ' void %s%s.Handler.handle(%s data) {' % (
namespace, s.name, s.type)
yield ' Console.Error.WriteLine("%s%s");' % (namespace, s.name)
if s.type == 'void':
yield ' %s%s.encode(encoder);' % (namespace, s.name)
else:
yield ' %s%s.encode(encoder, data);' % (namespace, s.name)
yield ' }'
yield ''
yield ' public %s(String InName, String OutName) {' % (classname)
yield ' FileStream InFile = new FileStream(InName,'
yield ' FileMode.Open, '
yield ' FileAccess.Read);'
yield ' LabCommDecoderChannel d = new LabCommDecoderChannel(InFile);'
yield ' FileStream OutFile = new FileStream(OutName, '
yield ' FileMode.OpenOrCreate, '
yield ' FileAccess.Write);'
yield ' encoder = new LabCommEncoderChannel(OutFile);'
yield ''
for s in signatures:
yield ' %s%s.register(d, this);' % (namespace, s.name)
yield ''
for s in signatures:
yield ' %s%s.register(encoder);' % (namespace, s.name)
yield ''
yield ' try {'
yield ' d.run();'
yield ' } catch (EndOfStreamException) {'
yield ' }'
yield ''
yield ' }'
yield ''
yield ' static void Main(String[] arg) {'
yield ' new %s(arg[0], arg[1]);' % (classname)
yield ' }'
yield ''
yield '}'
class Signature:
def __init__(self, name, type):
self.name = name
self.type = type
def test_program(target, typeinfo):
f = open(typeinfo)
signature = []
for l in f:
m = re.match('C#,sample,([^,]+),(.*)', l)
if m:
signature.append(Signature(m.group(1), m.group(2)))
f.close()
f = open(target, "w")
for l in gen("x", "", signature):
f.write(l + "\n")
f.close()
if __name__ == "__main__":
#os.system("labcomm --typeinfo=/dev/stdout %s" % sys.argv[1])
typeinfo = subprocess.Popen(["labcomm",
"--typeinfo=/dev/stdout %s" % sys.argv[1]],
stdout=subprocess.PIPE)
signature = []
for l in typeinfo.stdout:
m = re.match('C#,sample,([^,]+),(.*)', l)
if m:
signature.append(Signature(m.group(1), m.group(2)))
for l in gen("x", "", signature):
print l
typedef struct {
string topic;
} pubsub;
sample pubsub subscribe;
sample pubsub unsubscribe;
sample pubsub publish;
sample pubsub unpublish;
typedef void avoid;
sample avoid doavoid;
// examples of errors: void may not be used
// in structs or arrays
//
// sample struct {
// int a;
// avoid error;
//} foo;
//
//sample void error2[2] ;
//sample avoid error3[_];
typedef void avoid;
// examples of errors: void may not be used
// in structs or arrays
//
sample struct {
int a;
avoid error_1;
} foo;
sample void error_2[2] ;
sample avoid error_3[_];
typedef int int_array_ss[1][_, 3, _][5]; sample int s_array_array_array[1][1, 1][1, 1, 1];
sample struct { int aa; boolean bb; int_array_ss ias; } struct_array_ss[1][_][_]; sample struct {
int b[1][1, 1];
int c[1][_, 1, _][_,_];
} struct_array_ss[1];
typedef int int_t; typedef int int_t;
typedef int int_array_t[1][2][3,4]; typedef int int_array_t[1][2][3,4];
typedef struct { int a; } struct_t; typedef struct { int a; } struct_t;
...@@ -18,3 +20,6 @@ sample int_array_t int_array_t_s; ...@@ -18,3 +20,6 @@ sample int_array_t int_array_t_s;
sample struct_t struct_t_s; sample struct_t struct_t_s;
sample struct_array_t struct_array_t_s; sample struct_array_t struct_array_t_s;
sample struct_struct_t struct_struct_t_s; sample struct_struct_t struct_struct_t_s;
sample string string_array[_];
sample struct { string s[_]; } string_struct_array;
sample sample s1;
sample sample s2;
sample sample s3;
sample sample sample_list[4];