Commit 0be24fee authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Work on append expressions

parent 41e8b290
......@@ -1181,6 +1181,7 @@ def _call_external_function(output, **kwargs):
# Add the traceability information
code.extend(traceability(output))
#code.extend(debug_trace())
for out in output.output:
signal_name = out['outputName']
......@@ -1275,6 +1276,7 @@ def _call_external_function(output, **kwargs):
and p_id.startswith(LPREFIX)) # NO FIXME WITH CTXT
or isinstance(param, ogAST.PrimFPAR)):
tmp_id = 'tmp{}'.format(out['tmpVars'][idx])
local_decl.extend(debug_trace())
local_decl.append(u'{tmp} : aliased {sort};'
.format(tmp=tmp_id,
sort=typename))
......@@ -1286,7 +1288,23 @@ def _call_external_function(output, **kwargs):
(ogAST.PrimSequenceOf, ogAST.PrimStringLiteral)):
p_id = array_content(param, p_id,
find_basic_type(param_type))
code.append(u'{} := {};'.format(tmp_id, p_id))
if isinstance(param, ogAST.ExprAppend):
# Process Append constructs properly when they are
# used as raw params (e.g. callme(a//b//c))
# TODO: ogAST.PrimSubstring seem to be missing
# Check the template in def _conditional
app_len = append_size(param)
code.extend(debug_trace())
code.append(u'{tmp}.Data (1 .. {app_len}) := {val};'
.format(tmp=tmp_id, app_len=app_len, val=p_id))
if basic_param.Min != basic_param.Max:
# Append should only apply to this case, i.e.
# types of varying length...
code.append(u'{tmp}.Length := {app_len};'
.format(tmp=tmp_id, app_len=app_len))
else:
code.append(u'{} := {};'.format(tmp_id, p_id))
list_of_params.append(u"{}'Access{}"
.format(tmp_id,
u", {}'Size".format(tmp_id)
......@@ -2999,17 +3017,28 @@ def path_type(path):
def traceability(symbol):
''' Return a string with code-to-model traceability '''
trace = [u'-- {line}'.format(line=l) for l in
trace = [u'-- {line}'.format(line=l) for l in
symbol.trace().split('\n')]
if hasattr(symbol, 'comment') and symbol.comment:
trace.extend(traceability(symbol.comment))
return trace
def debug_trace(limit=2):
''' Return a list of comments containing traceability to the code
generator, needed to know the origin of a statement in the code '''
result = []
for each in traceback.format_stack (limit=limit)[:-1]:
formatted = each.replace('\n', ' ').split(',')
function = formatted[2].strip().split(' ')[1]
line_nb = formatted[1].strip()
added = [u'-- !! stack: {} {}'.format(function, line_nb)]
result.extend(added)
return result
def format_ada_code(stmts):
''' Indent properly the Ada code '''
indent = 0
indent_pattern = ' '
indent_pattern = ' '
for line in stmts[:-1]:
elems = line.strip().split()
if elems and elems[0].startswith(('when', 'end', 'elsif', 'else')):
......
......@@ -497,7 +497,8 @@ def signature(name, context):
def check_call(name, params, context):
''' Check the parameter types of a procedure/output/operator call,
returning the type of its result '''
returning the type of its result (value-returning functions only,
i.e not signal sending '''
# Special case for write/writeln functions
if name.lower() in ('write', 'writeln'):
......@@ -666,6 +667,26 @@ def check_range(typeref, type_to_check):
raise TypeError('Missing range')
def fix_append_expression_type(expr, expected_type):
''' In an Append expression, all components must be of the same type,
which is the type expected by the user of the append, for example
the left part of an assign expression.
We must recursively fix the Append type, in case we have a//b//c
that is handled as (a//b)//c
Inputs:
expr: the append expression (possibly recursive)
expected_type : the type to assign to the expression
'''
def rec_append(inner_expr, set_type):
for each in (inner_expr.left, inner_expr.right):
if isinstance(each, ogAST.ExprAppend):
rec_append(each, set_type)
each.expected_type = set_type
rec_append(expr, expected_type)
expr.exprType = expected_type
expr.expected_type = expected_type
def check_type_compatibility(primary, type_ref, context): # type: -> [warnings]
'''
Check if an ogAST.Primary (raw value, enumerated, ASN.1 Value...)
......@@ -862,7 +883,7 @@ def check_type_compatibility(primary, type_ref, context): # type: -> [warnings]
return warnings
else:
raise TypeError('Invalid string literal'
' - check that length is'
' - check that length is '
'within the bound limits {Min}..{Max}'
.format(Min=str(basic_type.Min),
Max=str(basic_type.Max)))
......@@ -1072,21 +1093,20 @@ def fix_expression_types(expr, context): # type: -> [warnings]
if asn_type.kind != 'SequenceType':
raise TypeError('left side must be a SEQUENCE type')
for field, fd_expr in expr.right.value.viewitems():
# if fd_expr.exprType == UNKNOWN_TYPE:
try:
for spelling in asn_type.Children:
if field.lower().replace('_', '-') == spelling.lower():
break
expected_type = asn_type.Children[spelling].type
except AttributeError:
raise TypeError('Field not found: ' + field)
check_expr = ogAST.ExprAssign()
check_expr.left = ogAST.PrimVariable()
check_expr.left.exprType = expected_type
check_expr.right = fd_expr
warnings.extend(fix_expression_types(check_expr, context))
# Id of fd_expr may have changed (enumerated, choice)
expr.right.value[field] = check_expr.right
try:
for spelling in asn_type.Children:
if field.lower().replace('_', '-') == spelling.lower():
break
expected_type = asn_type.Children[spelling].type
except AttributeError:
raise TypeError('Field not found: ' + field)
check_expr = ogAST.ExprAssign()
check_expr.left = ogAST.PrimVariable()
check_expr.left.exprType = expected_type
check_expr.right = fd_expr
warnings.extend(fix_expression_types(check_expr, context))
# Id of fd_expr may have changed (enumerated, choice)
expr.right.value[field] = check_expr.right
elif isinstance(expr.right, ogAST.PrimChoiceItem):
asn_type = find_basic_type(expr.left.exprType)
field = expr.right.value['choice'].replace('_', '-')
......@@ -1108,6 +1128,9 @@ def fix_expression_types(expr, context): # type: -> [warnings]
warnings.extend(fix_expression_types(check_expr, context))
expr.right.value['value'] = check_expr.right
elif isinstance(expr.right, ogAST.PrimConditional):
# in principle it could also be the left side that is a ternary
# in which case, its type would be unknown and would need to be
# set according to the right type.
#print "[Parser] [Conditional] ", expr.right.inputString
for det in ('then', 'else'):
# Recursively fix possibly missing types in the expression
......@@ -1121,6 +1144,8 @@ def fix_expression_types(expr, context): # type: -> [warnings]
expr.right.value[det].exprType = expr.left.exprType
# We must also set the type of the overal expression to the same
expr.right.exprType = expr.left.exprType
elif isinstance(expr.right, ogAST.ExprAppend):
fix_append_expression_type(expr.right, expr.left.exprType)
if expr.right.is_raw != expr.left.is_raw:
warnings.extend(check_type_compatibility(raw_expr, ref_type, context))
......@@ -1584,13 +1609,12 @@ def conditional_expression(root, context):
msg = 'Conditions in conditional expressions must be of type Boolean'
errors.append(error(root, msg))
# TODO: Refactor this
# The type of the expression is set to the type of the "then" part,
# but this is not always right, in the case of raw numbers ("then" part
# may be unsigned, while the real expected type is signed)
try:
expr.left = then_expr
expr.right = else_expr
# The type of the expression was set to the type of the "then" part,
# but this is not always right, in the case of raw numbers ("then" part
# may be unsigned, while the real expected type is signed)
warnings.extend(fix_expression_types(expr, context))
expr.exprType = then_expr.exprType
except (AttributeError, TypeError) as err:
......@@ -1604,6 +1628,10 @@ def conditional_expression(root, context):
'else' : else_expr,
'tmpVar': expr.tmpVar
}
# at the end, expr.exprType is still UNKNOWN TYPE
# it can only be resolved by from the context
# print traceback.print_stack()
#print traceback.format_stack (limit=2)
return expr, errors, warnings
......@@ -3491,8 +3519,7 @@ def outputbody(root, context):
errors.append('"' + child.text +
'" is not defined in the current scope')
elif child.type == lexer.PARAMS:
body['params'], err, warn = expression_list(
child, context)
body['params'], err, warn = expression_list(child, context)
errors.extend(err)
warnings.extend(warn)
elif child.type == lexer.TO:
......@@ -4209,20 +4236,21 @@ def assign(root, context):
# to the same value as left in case of ExprAppend
# Setting it - I did not see any place in the Ada backend where
# this could cause a bug (and regression is OK)
if isinstance(expr.right, ogAST.ExprAppend):
# all append components must be of the same type, which is the
# type of the left part of the expression. we must recursively
# fix the right type, in case we have the for a//b//c
# that is handled as (a//b)//c
def rec_append(inner_expr, set_type):
for each in (inner_expr.left, inner_expr.right):
if isinstance(each, ogAST.ExprAppend):
rec_append(each, set_type)
each.expected_type = set_type
rec_append(expr.right, expr.left.exprType)
expr.right.exprType = expr.left.exprType
expr.right.expected_type = expr.left.exprType
#print 'here in assign', expr.right.inputString
# if isinstance(expr.right, ogAST.ExprAppend):
# fix_append_expression_type(expr.right, expr.left.exprType)
# # all append components must be of the same type, which is the
# # type of the left part of the expression. we must recursively
# # fix the right type, in case we have the for a//b//c
# # that is handled as (a//b)//c
# def rec_append(inner_expr, set_type):
# for each in (inner_expr.left, inner_expr.right):
# if isinstance(each, ogAST.ExprAppend):
# rec_append(each, set_type)
# each.expected_type = set_type
# rec_append(expr.right, expr.left.exprType)
# expr.right.exprType = expr.left.exprType
# expr.right.expected_type = expr.left.exprType
# #print 'here in assign', expr.right.inputString
if isinstance(expr.right, (ogAST.PrimSequenceOf,
ogAST.PrimStringLiteral)):
# Set the expected type on the right, this is needed to know
......
......@@ -4,4 +4,6 @@ BEGIN
SeqOf ::= SEQUENCE (SIZE(0..10)) OF BoolType
BoolType ::= BOOLEAN
MyStr ::= OCTET STRING (SIZE (3..1000))
END
SYSTEM og;
system og;
/* CIF TEXT (159, 221), (289, 188) */
-- Text area for declarations and comments
use dv comment 'dataview.asn';
signal run;
signal saved_signal(BoolType);
signal we;
use dv comment 'dataview.asn';
signal run;
signal saved_signal(BoolType);
signal we (MyStr);
/* CIF ENDTEXT */
CHANNEL c
FROM ENV TO og WITH run,
channel c
from env to og with run,
saved_signal;
FROM og TO ENV WITH we;
ENDCHANNEL;
BLOCK og;
SIGNALROUTE r
FROM ENV TO og WITH run,
from og to env with we;
endchannel;
block og;
signalroute r
from env to og with run,
saved_signal;
FROM og TO ENV WITH we;
CONNECT c AND r;
from og to env with we;
connect c and r;
/* CIF PROCESS (225, 50), (150, 75) */
PROCESS og;
/* CIF TEXT (335, 58), (396, 136) */
process og;
/* CIF TEXT (532, 58), (396, 136) */
-- Various tests of the ternary operator
-- (PrimConditional)
dcl save_buffer SeqOf;
dcl param BoolType;
-- (PrimConditional)
dcl save_buffer SeqOf;
dcl param BoolType;
dcl msg MyStr := 'hello';
/* CIF ENDTEXT */
/* CIF START (0, 226), (70, 35) */
START;
/* CIF NEXTSTATE (0, 276), (70, 35) */
NEXTSTATE wait;
/* CIF STATE (291, 227), (70, 35) */
STATE wait;
/* CIF INPUT (296, 282), (162, 35) */
INPUT saved_signal(param);
/* CIF DECISION (296, 332), (161, 50) */
DECISION length(save_buffer);
/* CIF ANSWER (253, 402), (60, 34) */
(<10):
/* CIF TASK (194, 451), (177, 50) */
TASK save_buffer :=
save_buffer // {param};
/* CIF ANSWER (457, 402), (53, 34) */
(10):
/* CIF PROCEDURECALL (382, 451), (202, 38) */
CALL writeln('Buffer Overflow!');
ENDDECISION;
/* CIF NEXTSTATE (342, 516), (70, 35) */
NEXTSTATE wait;
/* CIF INPUT (91, 282), (84, 35) */
INPUT run;
/* CIF NEXTSTATE (79, 332), (107, 35) */
NEXTSTATE Running;
ENDSTATE;
/* CIF STATE (929, 221), (88, 35) */
STATE Running;
/* CIF PROVIDED (718, 276), (181, 35) */
PROVIDED length(save_buffer) > 0;
/* CIF TASK (714, 326), (188, 35) */
TASK param := save_buffer(0);
/* CIF TASK (633, 376), (350, 34) */
TASK save_buffer := save_buffer(1, length(save_buffer));
/* CIF TASK (647, 425), (323, 56) */
TASK save_buffer := if length(save_buffer) > 1
/* CIF state (1126, 221), (88, 35) */
state Running;
/* CIF input (1017, 276), (70, 35) */
input Run;
/* CIF PROCEDURECALL (955, 326), (194, 35) */
call writeln('Already running');
/* CIF NEXTSTATE (1017, 376), (70, 35) */
NEXTSTATE -;
/* CIF provided (679, 276), (181, 35) */
provided length(save_buffer) > 0;
/* CIF task (675, 326), (188, 35) */
task param := save_buffer(0);
/* CIF task (594, 376), (350, 34) */
task save_buffer := save_buffer(1, length(save_buffer));
/* CIF task (608, 425), (323, 56) */
task save_buffer := if length(save_buffer) > 1
then {true} else save_buffer // {false } fi;
/* CIF TASK (650, 496), (316, 56) */
TASK save_buffer := if length(save_buffer) > 1
/* CIF task (611, 496), (316, 56) */
task save_buffer := if length(save_buffer) > 1
then save_buffer(1, length(save_buffer))
else {} fi;
/* CIF PROCEDURECALL (708, 567), (200, 35) */
CALL writeln('Running: ', param);
/* CIF NEXTSTATE (764, 617), (88, 35) */
/* CIF PROCEDURECALL (669, 567), (200, 35) */
call writeln('Running: ', param);
/* CIF NEXTSTATE (725, 617), (88, 35) */
NEXTSTATE Running;
/* CIF INPUT (1053, 276), (70, 35) */
INPUT Run;
/* CIF PROCEDURECALL (990, 326), (194, 35) */
CALL writeln('Already running');
/* CIF NEXTSTATE (1053, 376), (70, 35) */
/* CIF provided (1262, 276), (135, 35) */
provided length (msg) < 100;
/* CIF task (1255, 331), (149, 35) */
task msg := msg // ' world';
/* CIF task (1159, 386), (341, 35) */
task msg := if false then 'helo' else msg // 'world' // '!!' fi;
/* CIF output (1291, 441), (76, 35) */
output we (msg);
/* CIF output (1275, 496), (109, 35) */
output we (msg // '!');
/* CIF output (1253, 551), (152, 35) */
output we ('hello' // ' world!');
/* CIF NEXTSTATE (1294, 601), (70, 35) */
NEXTSTATE -;
ENDSTATE;
ENDPROCESS og;
ENDBLOCK;
ENDSYSTEM;
\ No newline at end of file
endstate;
/* CIF state (291, 227), (70, 35) */
state wait;
/* CIF input (296, 282), (162, 35) */
input saved_signal(param);
/* CIF decision (296, 332), (161, 50) */
decision length(save_buffer);
/* CIF ANSWER (253, 402), (60, 34) */
(<10):
/* CIF task (194, 451), (177, 50) */
task save_buffer :=
save_buffer // {param};
/* CIF ANSWER (457, 402), (53, 34) */
(10):
/* CIF PROCEDURECALL (382, 451), (202, 38) */
call writeln('Buffer Overflow!');
enddecision;
/* CIF NEXTSTATE (342, 516), (70, 35) */
NEXTSTATE wait;
/* CIF input (91, 282), (84, 35) */
input run;
/* CIF NEXTSTATE (79, 332), (107, 35) */
NEXTSTATE Running;
endstate;
endprocess og;
endblock;
endsystem;
\ No newline at end of file
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