Commit c2762c46 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Parser bugfix (type resolution)

parent 24924186
......@@ -295,13 +295,14 @@ def is_constant(var):
def fix_special_operators(op_name, expr_list, context):
''' Verify/fix type of special operators parameters '''
if op_name.lower() in ('length', 'present'):
if op_name.lower() in ('length', 'present', 'abs'):
if len(expr_list) != 1:
raise AttributeError('Only one parameter for the {} operator'
.format(op_name))
expr = expr_list[0]
if expr.exprType is UNKNOWN_TYPE:
expr.exprType = find_variable(expr.inputString, context)
# XXX don't use inputString, there can be brackets
# XXX should change type to PrimVariable
basic = find_basic_type(expr.exprType)
if op_name.lower() == 'length' and basic.kind != 'SequenceOfType' \
......@@ -634,13 +635,10 @@ def find_type(path, context):
it is context-dependent (the name of a variable may conflict with the
name of a enumeration item or a choice determinant)
'''
errors = []
warnings = []
result = UNKNOWN_TYPE
assert len(path) > 1, str(path)
if not DV:
errors.append('Dataview is required to process types')
return result, errors, warnings
raise AttributeError('Dataview is required to process types')
LOG.debug('[find_type] ' + str(path))
# First, find the type of the main element
main = path[0]
......@@ -665,18 +663,15 @@ def find_type(path, context):
# with elements being the choice options
param, = path[1].get('procParams') or [None]
if not param:
errors.append('Missing parameter in PRESENT clause')
raise TypeError('Missing parameter in PRESENT clause')
else:
check_type = find_variable(param.inputString, context)\
if param.exprType == UNKNOWN_TYPE else \
param.exprType
try:
param_type = find_basic_type(check_type)
except TypeError as err:
errors.append('[find_type]' + str(err))
param_type = find_basic_type(check_type)
if param_type.kind != 'ChoiceType':
errors.append('PRESENT parameter'
' must be a CHOICE type:' + str(path))
raise TypeError('PRESENT parameter'
' must be a CHOICE type:' + str(path))
else:
result.EnumValues = param_type.Children
elif main.lower() in ('length', 'abs'):
......@@ -689,28 +684,24 @@ def find_type(path, context):
# We have more than one element and the first one is of type 'result'
# Iterate over the path to get the type of the last element
for elem in path[1:]:
try:
basic = find_basic_type(result)
except TypeError as err:
errors.append(str(err))
return result, errors, warnings
basic = find_basic_type(result)
if 'procParams' in elem:
# Discard operator parameters: they do not change the type
continue
# Sequence, Choice (case insensitive)
if basic.kind in ('SequenceType', 'ChoiceType'):
if 'index' in elem:
errors.append('Element {} cannot have an index'.format(
path[0]))
return result, errors, warnings
raise TypeError('Element {} cannot have an index'
.format(path[0]))
elem_asn1 = elem.replace('_', '-').lower()
type_idx = [c for c in basic.Children
if c.lower() == elem_asn1]
if type_idx:
result = basic.Children[type_idx[0]].type
else:
errors.append('Field ' + elem + ' not found in expression '
+ '!'.join(path))
raise TypeError('Field ' + elem
+ ' not found in expression '
+ '!'.join(path))
result = UNKNOWN_TYPE
break
# Sequence of
......@@ -728,18 +719,14 @@ def find_type(path, context):
elif basic.kind.endswith('StringType'):
# Can be an index or a substring
if 'index' in elem:
errors.append('Index on a string is not supported')
raise TypeError('Index on a string is not supported')
elif 'substring' in elem:
# don't change type, returns a string
# XXX Size may differ
pass
else:
errors.append('Expression ' + '!'.join(path) +
' does not resolve - check field "' +
str(elem) + '"')
result = UNKNOWN_TYPE
break
return result, errors, warnings
raise TypeError('Incorrect field or index')
return result
def expression_list(root, context):
......@@ -899,15 +886,21 @@ def primary_value(root, context=None):
# If there were parameters or index, try to determine the type of
# the expression
if isinstance(prim, ogAST.PrimPath) and len(prim.value)>1:
prim.exprType, err, warn = find_type(prim.value, context)
errors.extend(err)
warnings.extend(warn)
try:
prim.exprType = find_type(prim.value, context)
except TypeError as err:
errors.append('Type of expression "'
+ get_input_string(root)
+ '" not found: ' +str(err))
except AttributeError as err:
LOG.debug('[find_types] ' + str(err))
if prim:
prim.inputString = get_input_string(root)
else:
prim = ogAST.PrimPath()
return prim, errors, warnings
def primary(root, context):
''' Process a primary (-/NOT value) '''
warnings = []
......@@ -1020,13 +1013,14 @@ def expression(root, context):
lexer.AND,
lexer.IN):
expr.exprType = BOOLEAN
elif root.type == lexer.PLUS:
# elif root.type == lexer.PLUS:
# Adjust type constraint upper range with sum of expressions
# Create a new type to store the new constraint
expr.exprType = type('Plus_Type',
(find_basic_type(expr.left.exprType),), {})
expr.exprType.Max = str(int(expr.exprType.Max) +
int(find_basic_type(expr.right.exprType).Max))
# INCORRECT TO DO IT HERE - we must check right and left types FIRST
# expr.exprType = type('Plus_Type',
# (find_basic_type(expr.left.exprType),), {})
# expr.exprType.Max = str(int(find_basic_type(expr.left.exprType).Max) +
# int(find_basic_type(expr.right.exprType).Max))
elif root.type in (lexer.PLUS,
lexer.ASTERISK,
lexer.DASH,
......@@ -1827,7 +1821,7 @@ def procedure_call(root, parent, context):
''' Parse a PROCEDURE CALL (synchronous required interface) '''
# Same as OUTPUT for external procedures
out_ast = ogAST.ProcedureCall()
err, warn = output(root, parent, out_ast, context)
_, err, warn = output(root, parent, out_ast, context)
return out_ast, err, warn
......@@ -1871,11 +1865,12 @@ def outputbody(root, context):
return body, errors, warnings
def output(root, parent, out_ast, context):
def output(root, parent, out_ast=None, context=None):
''' Parse an OUTPUT : set of asynchronous required interface(s) '''
errors = []
warnings = []
coord = False
out_ast = out_ast or ogAST.Output() # syntax checker passes no ast
for child in root.getChildren():
if child.type == lexer.CIF:
# Get symbol coordinates
......@@ -1901,7 +1896,7 @@ def output(root, parent, out_ast, context):
if coord:
errors = [[e, [out_ast.pos_x, out_ast.pos_y]] for e in errors]
warnings = [[w, [out_ast.pos_x, out_ast.pos_y]] for w in warnings]
return errors, warnings
return out_ast, errors, warnings
def alternative_part(root, parent, context):
......@@ -2134,7 +2129,7 @@ def transition(root, parent, context):
parent = t
elif child.type == lexer.OUTPUT:
out_ast = ogAST.Output()
err, warn = output(child,
_, err, warn = output(child,
parent=parent,
out_ast=out_ast,
context=context)
......@@ -2176,9 +2171,12 @@ def fix_expression_types(expr, context):
for side in ('left', 'right'):
# Determine if the expression is a variable
uk_expr = getattr(expr, side)
if uk_expr.exprType == UNKNOWN_TYPE and not uk_expr.is_raw:
if uk_expr.exprType == UNKNOWN_TYPE \
and isinstance(uk_expr, ogAST.PrimPath) \
and len(uk_expr.value) == 1:
try:
exprType = find_variable(uk_expr.inputString, context)
#exprType = find_variable(uk_expr.inputString, context)
exprType = find_variable(uk_expr.value[0], context)
setattr(expr, side, ogAST.PrimVariable(primary=uk_expr))
getattr(expr, side).exprType = exprType
except AttributeError:
......@@ -2260,11 +2258,14 @@ def fix_expression_types(expr, context):
asn_type = find_basic_type(expr.left.exprType)
field = expr.right.value['choice'].replace('_', '-')
if asn_type.kind != 'ChoiceType' \
or field not in asn_type.Children.keys():
raise TypeError('left side must be a valid CHOICE type')
or field.lower() not in [key.lower()
for key in asn_type.Children.viewkeys()]:
raise TypeError('Field is not valid in CHOICE:' + field)
key, = [key for key in asn_type.Children.viewkeys()
if key.lower() == field.lower()]
if expr.right.value['value'].exprType == UNKNOWN_TYPE:
try:
expected_type = asn_type.Children.get(field).type
expected_type = asn_type.Children.get(key).type
except AttributeError:
raise TypeError('Field not found in CHOICE: ' + field)
check_expr = ogAST.ExprAssign()
......@@ -2613,8 +2614,13 @@ def parseSingleElement(elem='', string=''):
backend_ptr = eval(elem)
# Create a dummy process, needed to place context data
context = ogAST.Process()
t, semantic_errors, warnings = backend_ptr(
try:
t, semantic_errors, warnings = backend_ptr(
root=root, parent=None, context=context)
except AttributeError:
# Syntax checker has no visibility on variables and types
# so we have to discard exceptions sent by e.g. find_variable
pass
return(t, syntax_errors, semantic_errors, warnings,
context.terminators)
......
......@@ -1496,8 +1496,10 @@ class OG_MainWindow(QtGui.QMainWindow, object):
if types:
self.asn1_area.text.setPlainText('\n'.join(types))
self.asn1_area.text.try_resize()
except IOError:
LOG.warning('ASN.1 file(s) could not be loaded')
except IOError as err:
LOG.warning('ASN.1 file(s) could not be loaded : ' + str(err))
except AttributeError:
LOG.warning('No AST, check input files')
def vi_command(self):
'''
......
......@@ -12,54 +12,56 @@ DCL test Some_Thing;
/* CIF ENDTEXT */
/* CIF START (-252, -114), (100, 50) */
START;
/* CIF TASK (-257, -49), (110, 50) */
TASK test := 5;
/* CIF TASK (-304, 16), (204, 50) */
/* CIF TASK (-284, -49), (164, 53) */
TASK test := 5,
test := abs(-4+1),
test := abs(test);
/* CIF TASK (-304, 19), (204, 50) */
TASK first_msg := 'Say hello first!'
/* CIF COMMENT (-80, 16), (148, 50) */
/* CIF COMMENT (-80, 19), (148, 50) */
COMMENT 'String assignment';
/* CIF TASK (-284, 81), (165, 50) */
/* CIF TASK (-284, 84), (165, 50) */
TASK seq := default_seqof,
seq := {1,2,3}
/* CIF COMMENT (-100, 81), (204, 50) */
/* CIF COMMENT (-100, 84), (204, 50) */
COMMENT 'default_seqof is a constant
defined in the ASN.1 model';
/* CIF TASK (-333, 146), (263, 50) */
/* CIF TASK (-333, 149), (263, 50) */
TASK seq := seq // {4, test} // default_seqof
/* CIF COMMENT (-50, 146), (156, 50) */
/* CIF COMMENT (-50, 149), (156, 50) */
COMMENT 'Concatenate
two SEQUENCE OF';
/* CIF TASK (-270, 211), (137, 50) */
/* CIF TASK (-270, 214), (137, 50) */
TASK 'seq(1) := seq(2)';
/* CIF TASK (-298, 276), (193, 50) */
/* CIF TASK (-298, 279), (193, 50) */
TASK seq := seq(1,2) // seq(4,5)
/* CIF COMMENT (-86, 276), (166, 50) */
/* CIF COMMENT (-86, 279), (166, 50) */
COMMENT 'Remove 3rd element';
/* CIF DECISION (-254, 341), (104, 70) */
/* CIF DECISION (-254, 344), (104, 70) */
DECISION test in seq
/* CIF COMMENT (-130, 356), (170, 39) */
/* CIF COMMENT (-130, 359), (170, 39) */
COMMENT 'Test the "in" operator';
/* CIF ANSWER (-344, 431), (100, 35) */
/* CIF ANSWER (-344, 434), (100, 35) */
(TRUE):
/* CIF PROCEDURECALL (-371, 481), (154, 50) */
/* CIF PROCEDURECALL (-371, 484), (154, 50) */
CALL writeln('All OK (1)');
/* CIF ANSWER (-181, 431), (100, 35) */
/* CIF ANSWER (-181, 434), (100, 35) */
(FALSE):
/* CIF PROCEDURECALL (-213, 481), (164, 50) */
/* CIF PROCEDURECALL (-213, 484), (164, 50) */
CALL writeln('NOT OK (1)');
ENDDECISION;
/* CIF DECISION (-252, 546), (100, 70) */
/* CIF DECISION (-252, 549), (100, 70) */
DECISION 3 in seq;
/* CIF ANSWER (-338, 636), (100, 35) */
/* CIF ANSWER (-338, 639), (100, 35) */
(TRUE):
/* CIF PROCEDURECALL (-370, 686), (164, 50) */
/* CIF PROCEDURECALL (-370, 689), (164, 50) */
CALL writeln('NOT OK (2)');
/* CIF ANSWER (-166, 636), (100, 35) */
/* CIF ANSWER (-166, 639), (100, 35) */
(FALSE):
/* CIF PROCEDURECALL (-196, 686), (161, 50) */
/* CIF PROCEDURECALL (-196, 689), (161, 50) */
CALL writeln('All OK (2)');
ENDDECISION;
/* CIF NEXTSTATE (-252, 751), (100, 50) */
/* CIF NEXTSTATE (-252, 754), (100, 50) */
NEXTSTATE Wait;
......@@ -122,29 +124,29 @@ ENDDECISION;
ENDSTATE;
/* CIF STATE (-252, 751), (100, 50) */
/* CIF STATE (-252, 754), (100, 50) */
STATE Wait;
/* CIF INPUT (-252, 821), (100, 50) */
/* CIF INPUT (-252, 824), (100, 50) */
INPUT go(msg);
/* CIF DECISION (-259, 886), (114, 70) */
/* CIF DECISION (-259, 889), (114, 70) */
DECISION msg = 'hello'
/* CIF COMMENT (-125, 896), (128, 50) */
/* CIF COMMENT (-125, 899), (128, 50) */
COMMENT 'Boolean test
on string value';
/* CIF ANSWER (-41, 976), (100, 35) */
/* CIF ANSWER (-41, 979), (100, 35) */
(FALSE):
/* CIF OUTPUT (-60, 1026), (139, 50) */
/* CIF OUTPUT (-60, 1029), (139, 50) */
OUTPUT rezult(first_msg);
/* CIF NEXTSTATE (-41, 1091), (100, 50) */
/* CIF NEXTSTATE (-41, 1094), (100, 50) */
NEXTSTATE Wait;
/* CIF ANSWER (-312, 976), (100, 35) */
/* CIF ANSWER (-312, 979), (100, 35) */
(TRUE):
/* CIF OUTPUT (-334, 1026), (145, 50) */
/* CIF OUTPUT (-334, 1029), (145, 50) */
OUTPUT rezult('Welcome')
/* CIF COMMENT (-170, 1026), (95, 50) */
/* CIF COMMENT (-170, 1029), (95, 50) */
COMMENT 'Send raw
string';
/* CIF NEXTSTATE (-312, 1091), (100, 50) */
/* CIF NEXTSTATE (-312, 1094), (100, 50) */
NEXTSTATE Running;
ENDDECISION;
ENDSTATE;
......
......@@ -14,23 +14,45 @@ DCL major_cycle, sub_cycle T_UInt32;
/* CIF ENDTEXT */
/* CIF START (-209, 208), (100, 50) */
START;
/* CIF PROCEDURECALL (-254, 273), (189, 50) */
/* CIF PROCEDURECALL (-253, 273), (189, 50) */
CALL writeln
('[Orchestrator] Startup');
/* CIF TASK (-231, 338), (143, 50) */
/* CIF TASK (-230, 338), (143, 50) */
TASK intr := obt_pulse4;
/* CIF TASK (-231, 403), (144, 50) */
/* CIF OUTPUT (-224, 403), (130, 35) */
OUTPUT telemetry;
/* CIF TASK (-231, 453), (144, 50) */
TASK major_cycle := 1,
sub_cycle := 0;
/* CIF NEXTSTATE (-217, 468), (116, 50) */
/* CIF NEXTSTATE (-217, 518), (116, 50) */
NEXTSTATE Wait_for_GUI;
/* CIF STATE (-18, 53), (116, 50) */
STATE Wait_for_GUI;
/* CIF INPUT (-28, 123), (136, 50) */
INPUT start_simulation
(gnc_input);
/* CIF PROCEDURECALL (-55, 188), (190, 50) */
CALL writeln
('[Orchestrator] Running');
/* CIF NEXTSTATE (-10, 253), (100, 50) */
NEXTSTATE Running;
ENDSTATE;
/* CIF STATE (502, 32), (100, 50) */
STATE Running;
/* CIF INPUT (314, 102), (100, 50) */
/* CIF INPUT (757, 102), (136, 50) */
INPUT start_simulation
(gnc_input)
/* CIF COMMENT (913, 102), (169, 50) */
COMMENT 'Input from gui
stops the simulation';
/* CIF NEXTSTATE (767, 167), (116, 50) */
NEXTSTATE Wait_for_GUI;
/* CIF INPUT (311, 102), (105, 50) */
INPUT pulse
/* CIF COMMENT (434, 102), (114, 50) */
/* CIF COMMENT (436, 102), (114, 50) */
COMMENT 'Periodic call';
/* CIF PROCEDURECALL (175, 167), (377, 50) */
CALL S_SET_GNC_LV_SIM_CONTEXT_FOR_NEXT_MAJOR_CYCLE
......@@ -63,8 +85,6 @@ sub_cycle = 0
/* CIF COMMENT (477, 459), (250, 50) */
COMMENT 'Plot only every 50 major cycles
(otherwise performance is too low)';
/* CIF ANSWER (449, 562), (100, 35) */
(false):
/* CIF ANSWER (254, 562), (100, 35) */
(true):
/* CIF TASK (169, 612), (270, 68) */
......@@ -72,17 +92,15 @@ TASK plot_data!major_cycle := major_cycle,
plot_data!subcycle := sub_cycle,
plot_data!gnc_inputs := gnc_input,
plot_data!gnc_outputs := gnc_output;
/* CIF OUTPUT (238, 695), (132, 50) */
/* CIF OUTPUT (224, 695), (159, 50) */
OUTPUT plot(plot_data);
/* CIF ANSWER (449, 562), (100, 35) */
(false):
ENDDECISION;
/* CIF DECISION (305, 760), (118, 70) */
DECISION sub_cycle = 7
/* CIF COMMENT (443, 770), (199, 50) */
COMMENT 'Compute next major cycle';
/* CIF ANSWER (424, 850), (100, 35) */
(false):
/* CIF TASK (377, 900), (194, 50) */
TASK sub_cycle := sub_cycle + 1;
/* CIF ANSWER (197, 850), (100, 35) */
(true):
/* CIF TASK (137, 900), (220, 53) */
......@@ -90,29 +108,13 @@ TASK sub_cycle := 0,
major_cycle := major_cycle + 1;
/* CIF PROCEDURECALL (127, 968), (240, 50) */
CALL S_JUMP_TO_NEXT_MAJOR_CYCLE;
/* CIF ANSWER (424, 850), (100, 35) */
(false):
/* CIF TASK (377, 900), (194, 50) */
TASK sub_cycle := sub_cycle + 1;
ENDDECISION;
/* CIF NEXTSTATE (314, 1033), (100, 50) */
NEXTSTATE Running;
/* CIF INPUT (757, 102), (136, 50) */
INPUT start_simulation
(gnc_input)
/* CIF COMMENT (913, 102), (169, 50) */
COMMENT 'Input from gui
stops the simulation';
/* CIF NEXTSTATE (767, 167), (116, 50) */
NEXTSTATE Wait_for_GUI;
ENDSTATE;
/* CIF STATE (-18, 53), (116, 50) */
STATE Wait_for_GUI;
/* CIF INPUT (-28, 123), (136, 50) */
INPUT start_simulation
(gnc_input);
/* CIF PROCEDURECALL (-55, 188), (190, 50) */
CALL writeln
('[Orchestrator] Running');
/* CIF NEXTSTATE (-10, 253), (100, 50) */
NEXTSTATE Running;
ENDSTATE;
ENDPROCESS orchestrator;
\ No newline at end of file
......@@ -31,7 +31,9 @@ endfor;
TASK for x in foo(1,2):
call writeln(x);
endfor;
/* CIF NEXTSTATE (-569, 449), (91, 39) */
/* 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;
......
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