Commit 635d40cd authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Fixed handling of substrings in Ada backend

parent 364cc82f
......@@ -442,15 +442,15 @@ def write_statement(param, newline):
u"{tmp}(i) := Character'Val({st}.Data(i));"
.format(tmp=localstr, st=string, sep=sep),
u"end loop;"])
if basic_type.Min != basic_type.Max:
code.extend(["if {string}.Length < {to} then"
.format(string=string, to=basic_type.Max),
u"{tmp}({string}.Length + 1 .. {to}) "
u":= (others=>Character'Val(0));"
.format(tmp=localstr,
string=string,
to=basic_type.Max),
"end if;"])
# if basic_type.Min != basic_type.Max:
# code.extend(["if {string}.Length < {to} then"
# .format(string=string, to=basic_type.Max),
# u"{tmp}({string}.Length + 1 .. {to}) "
# u":= (others=>Character'Val(0));"
# .format(tmp=localstr,
# string=string,
# to=basic_type.Max),
# "end if;"])
string = u'{}({})'.format(localstr, range_len)
elif type_kind in ('IntegerType', 'RealType',
'BooleanType', 'Integer32Type'):
......@@ -603,9 +603,10 @@ def _task_assign(task):
code.extend(traceability(task.comment))
for expr in task.elems:
code.extend(traceability(expr))
code_assign, ada_string, decl_assign = expression(expr)
# ExprAssign only returns code statements, no string
code_assign, _, decl_assign = expression(expr)
code.extend(code_assign)
code.append(ada_string[1:-1] + ';')
# code.append(ada_string[1:-1] + ';')
local_decl.extend(decl_assign)
return code, local_decl
......@@ -667,7 +668,8 @@ def _task_forloop(task):
elem_type = loop['type'].ReferencedTypeName.replace('-', '_')
list_stmt, list_str, list_local = expression(loop['list'])
basic_type = find_basic_type(loop['list'].exprType)
range_cond = "{}.Data'Range".format(list_str)\
list_payload = list_str + string_payload(loop['list'], list_str)
range_cond = "{}'Range".format(list_payload)\
if basic_type.Min == basic_type.Max\
else "1..{}.Length".format(list_str)
stmt.extend(list_stmt)
......@@ -679,8 +681,8 @@ def _task_forloop(task):
'begin',
'for {it}_idx in {rc} loop'.format(it=loop['var'],
rc=range_cond),
'{it} := {var}.Data({it}_idx);'.format(it=loop['var'],
var=list_str)])
'{it} := {var}({it}_idx);'.format(it=loop['var'],
var=list_payload)])
try:
code_trans, local_trans = generate(loop['transition'])
if local_trans:
......@@ -842,30 +844,46 @@ def _prim_substring(prim):
r1_stmts, r1_string, r1_local = expression(prim.value[1]['substring'][0])
r2_stmts, r2_string, r2_local = expression(prim.value[1]['substring'][1])
# should we add 1 in case of numerical values? (see index)
# Adding 1 because SDL starts indexes at 0, ASN1 Ada types at 1
if unicode.isnumeric(r1_string):
r1_string = unicode(int(r1_string) + 1)
else:
r1_string += ' + 1'
if unicode.isnumeric(r2_string):
r2_string = unicode(int(r2_string) + 1)
else:
r2_string += ' + 1'
ada_string += '.Data({r1}..{r2})'.format(r1=r1_string, r2=r2_string)
stmts.extend(r1_stmts)
stmts.extend(r2_stmts)
local_decl.extend(r1_local)
local_decl.extend(r2_local)
local_decl.append('tmp{idx} : aliased asn1Scc{parent_type};'.format(
idx=prim.value[1]['tmpVar'], parent_type=receiver_ty_name))
# XXX types with fixed length: substrings will not work
if unicode.isnumeric(r1_string) and unicode.isnumeric(r2_string):
length = int(r2_string) - int(r1_string) + 1
else:
length = ('{r2} - {r1} + 1'.format(r2=r2_string, r1=r1_string))
prim_basic = find_basic_type(prim.exprType)
if int(prim_basic.Min) != int(prim_basic.Max):
stmts.append('tmp{idx}.Length := {length};'.format(
idx=prim.value[1]['tmpVar'], length=length))
stmts.append('tmp{idx}.Data(1..{length}) := {data};'.format(
idx=prim.value[1]['tmpVar'], length=length, data=ada_string))
ada_string = 'tmp{idx}'.format(idx=prim.value[1]['tmpVar'])
# # should we add 1 in case of numerical values? (see index)
# ada_string += '.Data({r1}..{r2})'.format(r1=r1_string, r2=r2_string)
# stmts.extend(r1_stmts)
# stmts.extend(r2_stmts)
# local_decl.extend(r1_local)
# local_decl.extend(r2_local)
#
# local_decl.append('tmp{idx} : aliased asn1Scc{parent_type};'.format(
# idx=prim.value[1]['tmpVar'], parent_type=receiver_ty_name))
#
# # XXX types with fixed length: substrings will not work
# if unicode.isnumeric(r1_string) and unicode.isnumeric(r2_string):
# length = int(r2_string) - int(r1_string) + 1
# else:
# length = ('{r2} - {r1} + 1'.format(r2=r2_string, r1=r1_string))
#
# prim_basic = find_basic_type(prim.exprType)
# if int(prim_basic.Min) != int(prim_basic.Max):
# stmts.append('tmp{idx}.Length := {length};'.format(
# idx=prim.value[1]['tmpVar'], length=length))
#
# stmts.append('tmp{idx}.Data(1..{length}) := {data};'.format(
# idx=prim.value[1]['tmpVar'], length=length, data=ada_string))
# ada_string = 'tmp{idx}'.format(idx=prim.value[1]['tmpVar'])
return stmts, unicode(ada_string), local_decl
......@@ -906,7 +924,6 @@ def _prim_selector(prim):
@expression.register(ogAST.ExprDiv)
@expression.register(ogAST.ExprMod)
@expression.register(ogAST.ExprRem)
@expression.register(ogAST.ExprAssign)
def _basic_operators(expr):
''' Expressions with two sides '''
code, local_decl = [], []
......@@ -920,6 +937,31 @@ def _basic_operators(expr):
local_decl.extend(right_local)
return code, unicode(ada_string), local_decl
@expression.register(ogAST.ExprAssign)
def _assign_expression(expr):
''' Assignment: almost the same a basic operators, except for strings '''
code, local_decl = [], []
strings = []
left_stmts, left_str, left_local = expression(expr.left)
right_stmts, right_str, right_local = expression(expr.right)
# If left side is a string/seqOf and right side is a substring, we must
# assign the .Data and .Length parts properly
basic_left = find_basic_type(expr.left.exprType)
if basic_left.kind in ('SequenceOfType', 'OctetStringType') \
and isinstance(expr.right, ogAST.PrimSubstring):
strings.append(u"{lvar}.Data(1..{rvar}'Length) := {rvar};"
.format(lvar=left_str, rvar=right_str))
if basic_left.Min != basic_left.Max:
strings.append(u"{lvar}.Length := {rvar}'Length;"
.format(lvar=left_str, rvar=right_str))
else:
strings.append(u"{} := {};".format(left_str, right_str))
code.extend(left_stmts)
code.extend(right_stmts)
code.extend(strings)
local_decl.extend(left_local)
local_decl.extend(right_local)
return code, '', local_decl
@expression.register(ogAST.ExprOr)
@expression.register(ogAST.ExprAnd)
......@@ -942,8 +984,12 @@ def _bitwise_operators(expr):
code.append(u'{tmp} := {right};'.format(tmp=tmp_string,
right=right_str))
right_str = tmp_string
ada_string = u'(Data => ({left}.Data {op} {right}.Data)'.format(
left=left_str, op=expr.operand, right=right_str)
right_payload = right_str + '.Data'
else:
right_payload = right_str + string_payload(expr.right, right_str)
left_payload = left_str + string_payload(expr.left, left_str)
ada_string = u'(Data => ({left} {op} {right})'.format(
left=left_payload, op=expr.operand, right=right_payload)
if basic_type.Min != basic_type.Max:
ada_string += u", Length => {left}.Length".format(left=left_str)
ada_string += u')'
......@@ -976,20 +1022,6 @@ def _unary_operator(expr):
def _append(expr):
''' Generate code for the APPEND construct: a // b '''
stmts, ada_string, local_decl = [], '', []
# basic_type_expr = find_basic_type(expr.exprType)
# We can do a length check if both strings are literals
# XXX should be already done by the parser
# if(expr.right.kind == 'primary'
# and expr.right.var.kind == 'stringLiteral'
# and expr.left.kind == 'primary'
# and expr.left.var.kind == 'stringLiteral'
# and len(expr.right.var.stringLiteral[1:-1]) +
# len(expr.left.var.stringLiteral[1:-1]) > basic_type_expr.Max):
# raise ValueError('String concatenation exceeds container length: '
# 'length(' + expr.left.var.stringLiteral[1:-1] +
# expr.right.var.stringLiteral[1:-1] + ') > ' +
# str(basic_type_expr.Max))
left_stmts, left_str, left_local = expression(expr.left)
right_stmts, right_str, right_local = expression(expr.right)
stmts.extend(left_stmts)
......@@ -1030,14 +1062,26 @@ def _append(expr):
sexp.slen = basic.Max
else:
# Variable-size types have a Length field
sexp.slen = '{}.Length'.format(sexp.sid)
stmts.append('{res}.Data(1..{l1}) := {lid}.Data(1..{l1});'.format(
res=ada_string, l1=expr.left.slen, lid=expr.left.sid))
stmts.append('{res}.Data({l1}+1..{l1}+{l2}) := {rid}.Data(1..{l2});'
.format(res=ada_string, l1=expr.left.slen,
rid=expr.right.sid, l2=expr.right.slen))
stmts.append('{res}.Length := {l1} + {l2};'.format(
res=ada_string, l1=expr.left.slen, l2=expr.right.slen))
if isinstance(sexp, ogAST.PrimSubstring):
sexp.slen = u"{}'Length".format(sexp.sid)
else:
sexp.slen = u'{}.Length'.format(sexp.sid)
left_payload = expr.left.sid + string_payload(expr.left, expr.left.sid)
right_payload = expr.right.sid + string_payload(expr.right, expr.right.sid)
if unicode.isnumeric(expr.left.slen) \
and unicode.isnumeric(expr.right.slen):
length = unicode(int(expr.left.slen) + int(expr.right.slen))
else:
length = '{} + {}'.format(expr.left.slen, expr.right.slen)
stmts.append('{res}.Data(1..{length}) := {lid} & {rid};'
.format(length=length,
res=ada_string,
lid=left_payload,
rid=right_payload))
basic_tmp = find_basic_type(expr.exprType)
if basic_tmp.Min != basic_tmp.Max:
# Update lenght field of resulting variable (if variable size)
stmts.append('{}.Length := {};'.format(ada_string, length))
return stmts, unicode(ada_string), local_decl
......@@ -1520,6 +1564,23 @@ def _inner_procedure(proc):
return code, local_decl
def string_payload(prim, ada_string):
''' Return the .Data part of a string, including range computed according
to the length, if the string has a variable size '''
if isinstance(prim, ogAST.PrimSubstring):
return ''
prim_basic = find_basic_type(prim.exprType)
payload = ''
if prim_basic.kind in ('SequenceOfType', 'OctetStringType'):
range_string = ''
if int(prim_basic.Min) != int(prim_basic.Max):
payload = u'.Data(1..{}.Length)'.format(ada_string)
else:
payload = u'.Data'
return payload
def find_basic_type(a_type):
''' Return the ASN.1 basic type of a_type '''
basic_type = a_type
......
......@@ -26,6 +26,9 @@ Type1 ::= INTEGER(0..1)
Type2 ::= BOOLEAN
Toto ::= SEQUENCE { elem-1 Type1, elem-2 Type2 }
SeqBool ::= SEQUENCE(SIZE(1..5)) OF BOOLEAN
default-seqof SeqOf ::= {4,7,9}
default-str My-OctStr ::= 'DEADBEEF'H
......
......@@ -16,67 +16,71 @@ dcl foo MyInteger := 3;
dcl alwaysTrue Type2 := 3 in {1,2,3};
dcl alwaysFalse Type2 := 0 in {1,2,3};
dcl seqofbool seqBool := { true, true};
/* CIF ENDTEXT */
/* CIF START (427, 26), (100, 50) */
START;
/* CIF TASK (393, 91), (168, 83) */
/* CIF TASK (370, 91), (214, 83) */
TASK test := 5,
test := power(test, 1),
test := abs(-4+1),
test := abs(test)
/* CIF COMMENT (581, 114), (183, 35) */
/* CIF COMMENT (603, 114), (183, 35) */
COMMENT 'Task with unicode: voilà!';
/* CIF TASK (375, 189), (204, 50) */
TASK first_msg := 'Say hello first!'
/* CIF COMMENT (599, 189), (148, 50) */
COMMENT 'String assignment';
/* CIF PROCEDURECALL (402, 254), (149, 35) */
CALL writeln(first_msg);
/* CIF TASK (394, 304), (165, 50) */
/* CIF PROCEDURECALL (390, 254), (173, 35) */
CALL writeln( first_msg);
/* CIF PROCEDURECALL (373, 304), (207, 35) */
CALL writeln( not (not not true));
/* CIF TASK (394, 354), (165, 50) */
TASK seq := default_seqof,
seq := {1,2,3}
/* CIF COMMENT (579, 304), (204, 50) */
/* CIF COMMENT (579, 354), (204, 50) */
COMMENT 'default_seqof is a constant
defined in the ASN.1 model';
/* CIF TASK (345, 369), (263, 50) */
/* CIF TASK (345, 419), (263, 50) */
TASK seq := seq // {4, test} // default_seqof
/* CIF COMMENT (629, 369), (156, 50) */
/* CIF COMMENT (629, 419), (156, 50) */
COMMENT 'Concatenate
two SEQUENCE OF';
/* CIF TASK (408, 434), (137, 50) */
/* CIF TASK (408, 484), (137, 50) */
TASK 'seq(1) := seq(2)';
/* CIF TASK (380, 499), (193, 50) */
/* CIF TASK (380, 549), (193, 50) */
TASK seq := seq(1,2) // seq(4,5)
/* CIF COMMENT (593, 499), (166, 50) */
/* CIF COMMENT (593, 549), (166, 50) */
COMMENT 'Remove 3rd element';
/* CIF DECISION (425, 564), (104, 70) */
/* CIF DECISION (425, 614), (104, 70) */
DECISION test in seq
/* CIF COMMENT (549, 579), (170, 39) */
/* CIF COMMENT (549, 629), (170, 39) */
COMMENT 'Test the "in" operator
Unicode test: Ï';
/* CIF ANSWER (335, 654), (100, 35) */
/* CIF ANSWER (335, 704), (100, 35) */
(TRUE):
/* CIF PROCEDURECALL (308, 704), (154, 50) */
/* CIF PROCEDURECALL (308, 754), (154, 50) */
CALL writeln('All OK (1)');
/* CIF ANSWER (498, 654), (100, 35) */
/* CIF ANSWER (498, 704), (100, 35) */
(FALSE):
/* CIF PROCEDURECALL (466, 704), (164, 50) */
/* CIF PROCEDURECALL (466, 754), (164, 50) */
CALL writeln('NOT OK (1)')
/* CIF COMMENT (650, 711), (117, 35) */
/* CIF COMMENT (650, 761), (117, 35) */
COMMENT 'Call UnicÔDË';
ENDDECISION;
/* CIF DECISION (427, 769), (100, 70) */
/* CIF DECISION (427, 819), (100, 70) */
DECISION 3 in seq;
/* CIF ANSWER (341, 859), (100, 35) */
/* CIF ANSWER (341, 909), (100, 35) */
(TRUE):
/* CIF PROCEDURECALL (309, 909), (164, 50) */
/* CIF PROCEDURECALL (309, 959), (164, 50) */
CALL writeln('NOT OK (2)');
/* CIF ANSWER (513, 859), (100, 35) */
/* CIF ANSWER (513, 909), (100, 35) */
(FALSE):
/* CIF PROCEDURECALL (482, 909), (161, 50) */
/* CIF PROCEDURECALL (482, 959), (161, 50) */
CALL writeln('All OK (2)');
ENDDECISION;
/* CIF NEXTSTATE (427, 974), (100, 50) */
/* CIF NEXTSTATE (427, 1024), (100, 50) */
NEXTSTATE Wait;
/* CIF STATE (1204, 151), (100, 50) */
STATE Running;
......@@ -136,47 +140,47 @@ against current Length';
NEXTSTATE Running;
ENDDECISION;
ENDSTATE;
/* CIF STATE (427, 974), (100, 50) */
/* CIF STATE (427, 1024), (100, 50) */
STATE Wait;
/* CIF INPUT (427, 1044), (100, 50) */
/* CIF INPUT (427, 1094), (100, 50) */
INPUT go(msg)
/* CIF COMMENT (547, 1051), (120, 35) */
/* CIF COMMENT (547, 1101), (120, 35) */
COMMENT 'Ïñpût unicode';
/* CIF DECISION (420, 1109), (114, 70) */
/* CIF DECISION (420, 1159), (114, 70) */
DECISION msg = 'hello'
/* CIF COMMENT (554, 1119), (128, 50) */
/* CIF COMMENT (554, 1169), (128, 50) */
COMMENT 'Boolean test
on string value';
/* CIF ANSWER (638, 1199), (100, 35) */
/* CIF ANSWER (638, 1249), (100, 35) */
(FALSE):
/* CIF OUTPUT (618, 1249), (139, 50) */
/* CIF OUTPUT (618, 1299), (139, 50) */
OUTPUT rezult(first_msg)
/* CIF COMMENT (777, 1256), (85, 35) */
/* CIF COMMENT (777, 1306), (85, 35) */
COMMENT 'OûtpUT';
/* CIF NEXTSTATE (638, 1314), (100, 50) */
/* CIF NEXTSTATE (638, 1364), (100, 50) */
NEXTSTATE Wait;
/* CIF ANSWER (367, 1199), (100, 35) */
/* CIF ANSWER (367, 1249), (100, 35) */
(TRUE):
/* CIF OUTPUT (344, 1249), (145, 50) */
/* CIF OUTPUT (344, 1299), (145, 50) */
OUTPUT rezult('Welcome')
/* CIF COMMENT (509, 1249), (95, 50) */
/* CIF COMMENT (509, 1299), (95, 50) */
COMMENT 'Send raw
string';
/* CIF DECISION (368, 1314), (98, 50) */
/* CIF DECISION (368, 1364), (98, 50) */
DECISION 3 in {1,2,3};
/* CIF ANSWER (328, 1384), (88, 23) */
/* CIF ANSWER (328, 1434), (88, 23) */
(1 in {1,2}):
/* CIF ANSWER (418, 1384), (88, 23) */
/* CIF ANSWER (418, 1434), (88, 23) */
(0 in {1,2}):
ENDDECISION;
/* CIF DECISION (368, 1462), (98, 50) */
/* CIF DECISION (368, 1472), (98, 50) */
DECISION 4 in {1,2,3};
/* CIF ANSWER (337, 1532), (70, 23) */
/* CIF ANSWER (337, 1542), (70, 23) */
(true):
/* CIF ANSWER (427, 1532), (70, 23) */
/* CIF ANSWER (427, 1542), (70, 23) */
(false):
ENDDECISION;
/* CIF NEXTSTATE (367, 1585), (100, 50) */
/* CIF NEXTSTATE (367, 1580), (100, 50) */
NEXTSTATE Running;
ENDDECISION;
ENDSTATE;
......
......@@ -6,10 +6,15 @@ test-parse:
test-ada:
../../../opengeode.py --toAda orchestrator.pr system_structure.pr
asn1.exe -Ada dataview-uniq.asn -typePrefix asn1Scc -equal
gnatmake -c orchestrator.adb
asn1.exe -c dataview-uniq.asn -typePrefix asn1Scc
gnatmake -c *.adb
gcc -c test.c
gnatbind -n orchestrator.ali
gnatlink -o testcase test.o orchestrator.ali -lgnat
./testcase | diff expected -
coverage:
coverage run -p ../../../opengeode.py orchestrator.pr system_structure.pr --toAda
clean:
rm -rf *.adb *.ads *.pyc runSpark.sh spark.idx *.o *.ali gnat.cfg examiner bin *.wrn *.gpr
rm -rf *.adb *.ads *.pyc runSpark.sh spark.idx *.o *.ali gnat.cfg examiner bin *.wrn *.gpr datav*.? ber.c xer.c asn1crt.? acn.c real.c
[C Code] Running test
[SDL] Startup
Hello 2.00000000000000E+00
1 2.00000000000000E+00
1.00000000000000E+00
[C Code] Received T_GNC_LV_SIM_INPUTS
2.00000000000000E+00
[C Code] Received T_GNC_LV_SIM_INPUTS
3.00000000000000E+00
[C Code] Received T_GNC_LV_SIM_INPUTS
4.00000000000000E+00
[C Code] Received T_GNC_LV_SIM_INPUTS
1.00000000000000E+00
2.00000000000000E+00
3.00000000000000E+00
4.00000000000000E+00
2.00000000000000E+00
3.00000000000000E+00
/* CIF PROCESS (250, 150), (150, 75) */
PROCESS orchestrator;
/* CIF TEXT (-957, 11), (297, 233) */
-- Test case covering FOR loops
/* CIF TEXT (0, 11), (297, 233) */
-- Test case covering FOR loops
dcl foo t_quAT_FLOAT32 := {1.0, 2.0, 3.0, 4.0};
dcl gnc_out T_GNC_LV_SIM_INPUTS;
dcl toto T_UInt8 := 2;
/* CIF ENDTEXT */
/* CIF START (-564, 36), (81, 37) */
START;
/* CIF PROCEDURECALL (-590, 88), (133, 44) */
CALL writeln
/* CIF ENDTEXT */
/* CIF START (393, 36), (81, 37) */
START;
/* CIF PROCEDURECALL (367, 88), (133, 44) */
CALL writeln
('[SDL] Startup');
/* CIF TASK (-630, 147), (214, 68) */
TASK for x in range(1,3,2):
/* CIF TASK (326, 147), (214, 68) */
TASK for x in range(1,3,2):
call writeln('Hello ',foo(x));
call writeln(x, foo(1));
endfor;
/* CIF TASK (-650, 230), (254, 68) */
TASK for x in range(length(foo)):
endfor
/* CIF COMMENT (575, 141), (256, 78) */
COMMENT 'this range should iterate only ONCE
expected output:
Hello 2.0 (array index start at 0)
1 2.0';
/* CIF TASK (306, 230), (254, 68) */
TASK for x in range(length(foo)):
call writeln(foo(x));
output vesat_one_step(gnc_out);
endfor;
/* CIF TASK (-593, 313), (140, 53) */
TASK for x in foo:
endfor
/* CIF COMMENT (584, 221), (412, 98) */
COMMENT 'length(foo) = 4 -> should iterate 4 times
expected output (in addition to the printf in vesat_one_step):
1.0
2.0
3.0
4.0';
/* CIF TASK (363, 379), (140, 53) */
TASK for x in foo:
call writeln(x);
endfor;
/* CIF TASK (-593, 381), (140, 53) */
TASK for x in foo(1,2):
endfor
/* CIF COMMENT (534, 359), (146, 93) */
COMMENT 'expected output:
1.0
2.0
3.0
4.0';
/* CIF TASK (363, 516), (140, 53) */
TASK for x in foo(1,2):
call writeln(x);
endfor;
/* CIF TASK (-582, 449), (118, 35) */
TASK toto := (toto);
/* CIF NEXTSTATE (-569, 499), (91, 39) */
NEXTSTATE Stopped;
/* CIF STATE (-340, 38), (91, 35) */
STATE Stopped;
ENDSTATE;
endfor
/* CIF COMMENT (525, 503), (146, 63) */
COMMENT 'expected output:
2.0
3.0';
/* CIF TASK (374, 584), (118, 35) */
TASK toto := (toto);
/* CIF NEXTSTATE (388, 634), (91, 39) */
NEXTSTATE Stopped;
/* CIF STATE (617, 38), (91, 35) */
STATE Stopped;
ENDSTATE;
ENDPROCESS orchestrator;
\ No newline at end of file
#include <math.h>
#include <stdio.h>
#include "dataview-uniq.h"
extern void adainit();
void orchestrator_RI_VESAT_one_step(asn1SccT_GNC_LV_SIM_INPUTS *inp)
{
printf("[C Code] Received T_GNC_LV_SIM_INPUTS\n");
}
int main()
{
printf("[C Code] Running test\n");
adainit();
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment