Commit 9162d67f authored by dbarbera's avatar dbarbera
Browse files

Merge remote-tracking branch 'upstream/master' into llvm

Conflicts:
	.gitignore
	LlvmGenerator.py
	tests/regression/test13/Makefile
	tests/regression/test13/basic.pr
	tests/regression/test13/dataview-uniq.asn
	tests/regression/test13/expected
	tests/regression/test6/Makefile
	tests/regression/test8/Makefile
	tests/test.py
parents 7408b7b2 90ee507e
*.pyc
*.autosave
tests/**/*.ads
tests/**/*.adb
tests/**/*.ali
tests/**/*.ll
tests/**/*.s
tests/**/*.o
tests/**/*.idx
tests/**/*.wrn
tests/**/*.gpr
tests/**/*.sh
tests/**/*.cfg
tests/**/result
tests/**/testcase
antlr-3.1.3.tar.bz2
antlr-3.1.3/
tests/**/python.stg
tests/**/*.stg
......@@ -1183,17 +1183,21 @@ def _mantissa_base_exp(primary):
return [], u'', []
@expression.register(ogAST.PrimIfThenElse)
def _if_then_else(ifThenElse):
''' Return string and statements for ternary operator '''
resType = ifThenElse.exprType
@expression.register(ogAST.PrimConditional)
def _conditional(cond):
''' Return string and statements for conditional expressions '''
resType = cond.exprType
stmts = []
if resType.kind.startswith('Integer'):
if resType.kind in ('IntegerType', 'Integer32Type'):
tmp_type = 'Asn1Int'
elif resType.kind == 'StandardStringType':
print ifThenElse.value['then'].value
then_str = ifThenElse.value['then'].value.replace("'", '"')
else_str = ifThenElse.value['else'].value.replace("'", '"')
elif resType.kind == 'RealType':
tmp_type = 'Asn1Real'
elif resType.kind == 'BooleanType':
tmp_type = 'Boolean'
elif resType.kind == 'StringType':
then_str = cond.value['then'].value.replace("'", '"')
else_str = cond.value['else'].value.replace("'", '"')
lens = [len(then_str), len(else_str)]
tmp_type = 'String(1 .. {})'.format(max(lens) - 2)
# Ada require fixed-length strings, adjust with spaces
......@@ -1203,29 +1207,30 @@ def _if_then_else(ifThenElse):
else_str = else_str[0:-1] + ' ' * (lens[0] - lens[1]) + '"'
else:
tmp_type = 'asn1Scc' + resType.ReferencedTypeName.replace('-', '_')
local_decl = ['tmp{idx} : {tmpType};'.format(
idx=ifThenElse.value['tmpVar'],
idx=cond.value['tmpVar'],
tmpType=tmp_type)]
if_stmts, if_str, if_local = expression(ifThenElse.value['if'])
if_stmts, if_str, if_local = expression(cond.value['if'])
stmts.extend(if_stmts)
local_decl.extend(if_local)
if resType.kind != 'StandardStringType':
then_stmts, then_str, then_local = expression(ifThenElse.value['then'])
else_stmts, else_str, else_local = expression(ifThenElse.value['else'])
if resType.kind != 'StringType':
then_stmts, then_str, then_local = expression(cond.value['then'])
else_stmts, else_str, else_local = expression(cond.value['else'])
stmts.extend(then_stmts)
stmts.extend(else_stmts)
local_decl.extend(then_local)
local_decl.extend(else_local)
stmts.append(u'if {if_str} then'.format(if_str=if_str))
stmts.append(u'tmp{idx} := {then_str};'.format(
idx=ifThenElse.value['tmpVar'],
idx=cond.value['tmpVar'],
then_str=then_str))
stmts.append('else')
stmts.append(u'tmp{idx} := {else_str};'.format(
idx=ifThenElse.value['tmpVar'],
idx=cond.value['tmpVar'],
else_str=else_str))
stmts.append('end if;')
ada_string = u'tmp{idx}'.format(idx=ifThenElse.value['tmpVar'])
ada_string = u'tmp{idx}'.format(idx=cond.value['tmpVar'])
return stmts, unicode(ada_string), local_decl
......
......@@ -387,9 +387,9 @@ def _rename_path(ast, from_name, to_name):
ast.value[0] = to_name
@rename_everything.register(ogAST.PrimIfThenElse)
@rename_everything.register(ogAST.PrimConditional)
def _rename_ifhthenelse(ast, from_name, to_name):
''' Rename expressions in If-Then-Else-Fi construct '''
''' Rename expressions in Conditional expression construct '''
for expr in ('if', 'then', 'else'):
rename_everything(ast.value[expr], from_name, to_name)
......
......@@ -1430,7 +1430,7 @@ def _mantissa_base_exp(primary):
raise NotImplementedError
@expression.register(ogAST.PrimIfThenElse)
@expression.register(ogAST.PrimConditional)
def _if_then_else(ifthen):
''' Generate the code for ternary operator '''
func = ctx.builder.basic_block.function
......
......@@ -30,5 +30,6 @@ publish: install
python setup.py sdist upload
clean:
make -C tests/regression clean
find . -name '*~' | xargs rm -f
find . -name '*.o' | xargs rm -f
......@@ -232,7 +232,7 @@ class PrimOctetStringLiteral(Primary):
pass
class PrimIfThenElse(Primary):
class PrimConditional(Primary):
''' value is a dictionnary:
{ 'if': Expression, 'then': Expression,
'else': Expression, 'tmpVar': integer}
......
......@@ -28,12 +28,10 @@ __author__ = 'Maxime Perrotin'
import sys
import os
import re
import fnmatch
import logging
import traceback
from itertools import chain, permutations, combinations
from collections import defaultdict
from collections import defaultdict, Counter
import antlr3
import antlr3.tree
......@@ -68,7 +66,6 @@ EXPR_NODE = {
lexer.NOT: ogAST.ExprNot,
lexer.NEG: ogAST.ExprNeg,
lexer.PRIMARY: ogAST.Primary,
lexer.IFTHENELSE: ogAST.PrimIfThenElse,
}
# Insert current path in the search list for importing modules
......@@ -394,11 +391,7 @@ def fix_special_operators(op_name, expr_list, context):
for each in (INTEGER, REAL, BOOLEAN, RAWSTRING, OCTETSTRING):
try:
check_type_compatibility(param, each, context)
if each is OCTETSTRING and isinstance(param,
ogAST.PrimIfThenElse):
param.exprType = param.value['then'].exprType
else:
param.exprType = each
param.exprType = each
break
except TypeError:
continue
......@@ -551,28 +544,15 @@ def check_type_compatibility(primary, typeRef, context):
'" not in this enumeration: ' +
str(actual_type.EnumValues.keys()))
raise TypeError(err)
elif isinstance(primary, ogAST.PrimIfThenElse):
# check that IF expr returns BOOL, and that Then and Else expressions
# are compatible with actual_type
if_expr = primary.value['if']
elif isinstance(primary, ogAST.PrimConditional):
then_expr = primary.value['then']
else_expr = primary.value['else']
if if_expr.exprType.kind != 'BooleanType':
raise TypeError('IF expression does not return a boolean')
else:
for expr in (then_expr, else_expr):
if expr.is_raw:
check_type_compatibility(expr, typeRef, context)
# compare the types for semantic equivalence:
else:
if expr.exprType is UNKNOWN_TYPE:
# If it was not resolved before, it must be a variable
# this can happen in the context of a special operator
# (write), where at no point before where the type
# could be compared to another type
expr.exprType = find_variable(expr.value[0], context)
compare_types(expr.exprType, typeRef)
for expr in (then_expr, else_expr):
if expr.is_raw:
check_type_compatibility(expr, typeRef, context)
return
elif isinstance(primary, ogAST.PrimVariable):
try:
compare_types(primary.exprType, typeRef)
......@@ -634,7 +614,7 @@ def check_type_compatibility(primary, typeRef, context):
# Compare the types for semantic equivalence
try:
compare_types(
primary.value[ufield].exprType, fd_data.type)
primary.value[ufield].exprType, fd_data.type)
except TypeError as err:
raise TypeError('Field ' + ufield +
' is not of the proper type, i.e. ' +
......@@ -871,7 +851,7 @@ def fix_expression_types(expr, context):
raise TypeError('Cannot resolve type of "{}"'
.format(unknown[0].inputString))
# In Sequence, Choice, SEQUENCE OF, and IfThenElse expressions,
# In Sequence, Choice and SEQUENCE OF expressions,
# we must fix missing inner types
# (due to similarities, the following should be refactored FIXME)
if isinstance(expr.right, ogAST.PrimSequence):
......@@ -913,7 +893,7 @@ def fix_expression_types(expr, context):
check_expr.right = expr.right.value['value']
fix_expression_types(check_expr, context)
expr.right.value['value'] = check_expr.right
elif isinstance(expr.right, ogAST.PrimIfThenElse):
elif isinstance(expr.right, ogAST.PrimConditional):
for det in ('then', 'else'):
# Recursively fix possibly missing types in the expression
check_expr = ogAST.ExprAssign()
......@@ -1040,8 +1020,8 @@ def expression(root, context):
return neg_expression(root, context)
elif root.type == lexer.PAREN:
return expression(root.children[0], context)
elif root.type == lexer.IFTHENELSE:
return if_then_else_expression(root, context)
elif root.type == lexer.CONDITIONAL:
return conditional_expression(root, context)
elif root.type == lexer.PRIMARY:
return primary(root.children[0], context)
elif root.type == lexer.CALL:
......@@ -1076,13 +1056,16 @@ def logic_expression(root, context):
errors.append(error(root, msg))
break
if bty.kind in ('BooleanType', 'BitStringType'):
if bty.kind == 'BooleanType':
continue
elif bty.kind == 'SequenceOfType' and bty.type.kind == 'BooleanType':
elif bty.kind == 'BitStringType' and bty.Min == bty.Max:
continue
elif bty.kind == 'SequenceOfType' and bty.type.kind == 'BooleanType'\
and bty.Min == bty.Max:
continue
else:
msg = 'Bitwise operators only work with Booleans, ' \
'SequenceOf Booleans or BitStrings'
'fixed size SequenceOf Booleans or fixed size BitStrings'
errors.append(error(root, msg))
break
......@@ -1260,11 +1243,11 @@ def neg_expression(root, context):
return expr, errors, warnings
def if_then_else_expression(root, context):
''' If Then Else expression analysis '''
def conditional_expression(root, context):
''' Conditional expression analysis '''
errors, warnings = [], []
expr = ogAST.PrimIfThenElse(
expr = ogAST.PrimConditional(
get_input_string(root),
root.getLine(),
root.getCharPositionInLine()
......@@ -1286,7 +1269,20 @@ def if_then_else_expression(root, context):
errors.extend(err)
warnings.extend(warn)
if find_basic_type(if_expr.exprType).kind != 'BooleanType':
msg = 'Conditions in conditional expressions must be of type Boolean'
errors.append(error(root, msg))
# TODO: Refactor this
try:
expr.left = then_expr
expr.right = else_expr
fix_expression_types(expr, context)
expr.exprType = then_expr.exprType
except (AttributeError, TypeError) as err:
if UNKNOWN_TYPE not in (then_expr.exprType, else_expr.exprType):
errors.append(error(root, str(err)))
expr.value = {
'if': if_expr,
'then': then_expr,
......@@ -1410,7 +1406,6 @@ def primary_call(root, context):
'Max': str(max(enum_values))
})
except AttributeError:
msg = 'Type Error, check the parameter'
errors.append(error(root, '"Num" parameter error'))
return node, errors, warnings
......@@ -1620,7 +1615,7 @@ def primary(root, context):
elif root.type == lexer.OCTSTR:
prim = ogAST.PrimOctetStringLiteral()
warnings.append(
warning(root, 'Octet string literal not supported yet'))
warning(root, 'Octet string literal not supported yet'))
else:
# TODO: return error message
raise NotImplementedError
......@@ -1680,8 +1675,13 @@ def variables(root, ta_ast, context):
str(child.type))
for variable in var:
# Add to the context and text area AST entries
context.variables[variable] = (asn1_sort, def_value)
ta_ast.variables[variable] = (asn1_sort, def_value)
if variable.lower() in context.variables \
or variable.lower() in ta_ast.variables:
errors.append('Variable "{}" is declared more than once'
.format(variable))
else:
context.variables[variable.lower()] = (asn1_sort, def_value)
ta_ast.variables[variable.lower()] = (asn1_sort, def_value)
if not DV:
errors.append('Cannot do semantic checks on variable declarations')
return errors, warnings
......@@ -2543,7 +2543,7 @@ def state(root, parent, context):
state_def.charPositionInLine = child.getCharPositionInLine()
exceptions = [c.toString() for c in child.getChildren()]
for st in context.mapping:
if st not in (exceptions, 'START'):
if st not in exceptions + ['START']:
state_def.statelist.append(st)
elif child.type == lexer.INPUT:
# A transition triggered by an INPUT
......@@ -2553,6 +2553,19 @@ def state(root, parent, context):
warnings.extend(warn)
try:
for statename in state_def.statelist:
# check that input is not already defined
existing = context.mapping.get(statename.lower(), [])
dupl = set()
for each in inp.inputlist:
for ex_input in (name for i in existing
for name in i.inputlist):
if unicode(each) == unicode(ex_input):
dupl.add(each)
for each in dupl:
errors.append('Input "{}" is defined more '
'than once for state "{}"'
.format(each, statename.lower()))
# then update the mapping state-input
context.mapping[statename.lower()].append(inp)
except KeyError:
warnings.append('State definition missing')
......@@ -2564,9 +2577,9 @@ def state(root, parent, context):
else:
asterisk_input = inp
elif child.type == lexer.CONNECT:
comp_states = (comp.statename for comp in context.composite_states)
if asterisk_state or len(state_def.statelist) != 1 \
or (state_def.statelist[0].lower()
not in (comp.statename for comp in context.composite_states)):
or state_def.statelist[0].lower() not in comp_states:
errors.append('State {} is not a composite state and cannot '
'be followed by a connect statement'
.format(state_def.statelist[0]))
......@@ -2960,6 +2973,7 @@ def decision(root, parent, context):
covered_ranges = defaultdict(list)
qmin, qmax = 0, 0
need_else = False
is_enum = False
for ans in dec.answers:
if ans.kind in ('constant', 'open_range'):
expr = ans.openRangeOp()
......@@ -2972,6 +2986,13 @@ def decision(root, parent, context):
ans.constant = expr.right
q_basic = find_basic_type(dec.question.exprType)
a_basic = find_basic_type(ans.constant.exprType)
if q_basic.kind.endswith('EnumeratedType'):
if not ans.constant.is_raw:
# Ref to a variable -> can't guarantee coverage
need_else = True
continue
covered_ranges[ans].append(ans.inputString)
is_enum = True
if not q_basic.kind.startswith('Integer'):
continue
# numeric type -> find the range covered by this answer
......@@ -3065,7 +3086,7 @@ def decision(root, parent, context):
qmin, qmax = int(float(q_basic.Min)), int(float(q_basic.Max))
a0_val = int(float(a0_basic.Min))
a1_val = int(float(a1_basic.Max))
if a0_val < qmin:
if a0_val < qmin:
warnings.append('Decision "{dec}": '
'Range [{a0} .. {qmin}] is unreachable'
.format(a0=a0_val, qmin=qmin - 1,
......@@ -3082,14 +3103,17 @@ def decision(root, parent, context):
l=a0_val, h=a1_val))
covered_ranges[ans].append((int(float(a0_basic.Min)),
int(float(a1_basic.Max))))
# Check the following:
# Check the following
# (1) no overlap between covered ranges in decision answers
# (2) no gap in the coverage of the decision possible values
# (3) ELSE branch, if present, can be reached
# (4) if an answer uses a non-ground expression an ELSE is there
# (5) present() operator and enumerated question are fully covered
q_ranges = [(qmin, qmax)] if is_numeric(dec.question.exprType) else []
for each in combinations(covered_ranges.viewitems(), 2):
if not q_ranges:
continue
for comb in combinations(
chain.from_iterable(val[1] for val in each), 2):
comb_overlap = (max(comb[0][0], comb[1][0]),
......@@ -3104,9 +3128,10 @@ def decision(root, parent, context):
o1=comb_overlap[0],
o2=comb_overlap[1]))
new_q_ranges = []
# for minq, maxq in q_ranges:
# (2) Check that decision range is fully covered
for ans_ref, ranges in covered_ranges.viewitems():
if is_enum:
continue
for mina, maxa in ranges:
for minq, maxq in q_ranges:
left = (minq, min(maxq, mina - 1))
......@@ -3134,6 +3159,21 @@ def decision(root, parent, context):
warnings.append('Decision "{}": Missing ELSE branch'
.format(dec.inputString))
# (5) check coverage of enumerated types
if is_enum:
# check duplicate answers
answers = list(chain.from_iterable(covered_ranges.viewvalues()))
dupl = [a for a, v in Counter(answers).items() if v > 1]
if dupl:
errors.append('Decision "{}": duplicate answers "{}"'
.format(dec.inputString, '", "'.join(dupl)))
enumerants = [en.replace('-', '_') for en in q_basic.EnumValues.keys()]
# check for missing answers
if set(answers) != set(enumerants) and not has_else:
errors.append('Decision "{}": Missing branches for answer(s) "{}"'
.format(dec.inputString,
'", "'.join(set(enumerants) - set(answers))))
return dec, errors, warnings
......
......@@ -95,7 +95,8 @@ try:
import LlvmGenerator
except ImportError:
# not sure if LLVM is available on the Windows platform
pass
LlvmGenerator = None
print 'LLVM is not available'
__all__ = ['opengeode']
__version__ = '0.994'
......@@ -1799,9 +1800,9 @@ def init_logging(options):
for module in modules:
module.LOG.addHandler(handler_console)
module.LOG.setLevel(level)
except NameError:
except (NameError, AttributeError) as err:
# Some modules may not be loaded (like llvm on Windows)
pass;
LOG.info(str(err))
def parse(files):
......
......@@ -33,6 +33,7 @@ tokens {
CLOSED_RANGE;
COMMENT;
COMPOSITE_STATE;
CONDITIONAL;
CONNECT;
CONNECTION;
CONSTANT;
......@@ -836,7 +837,7 @@ postfix_expression
primary_expression
: primary -> ^(PRIMARY primary)
| '(' expression ')' -> ^(PAREN expression)
| conditional_ground_expression
| conditional_expression
;
......@@ -966,31 +967,19 @@ operator_application
active_expression_list
: active_expression (',' expression_list)?;/* |
ground_expression ',' active_expression_list;*/ // Will not work (recursion)
/*
conditional_expression
: IF boolean_active_expression THEN consequence_expression ELSE alternative_expression FI |
IF boolean_expression THEN active_consequence_expression ELSE alternative_expression FI |
IF boolean_expression THEN consequence_expression ELSE active_alternative_expression FI;
*/
// Simpler version, the rest will is checked by semantic analysis
conditional_expression
: IF expression THEN expression ELSE expression FI;
//synonym : ID; // synonym_id | external_synonym;
external_synonym
: external_synonym_id;
conditional_ground_expression
conditional_expression
: IF ifexpr=expression
THEN thenexpr=expression
ELSE elseexpr=expression FI
-> ^(IFTHENELSE $ifexpr $thenexpr $elseexpr);
-> ^(CONDITIONAL $ifexpr $thenexpr $elseexpr);
expression_list
......
# $ANTLR 3.1.3 Mar 17, 2009 19:23:44 sdl92.g 2014-07-22 16:47:59
# $ANTLR 3.1.3 Mar 17, 2009 19:23:44 sdl92.g 2014-07-29 14:08:49
import sys
from antlr3 import *
......@@ -9,222 +9,223 @@ from antlr3.compat import set, frozenset
HIDDEN = BaseRecognizer.HIDDEN
# token types
NUMBER_OF_INSTANCES=59
COMMENT2=209
MANTISSA=166
ROUTE=78
MOD=158
GROUND=43
PARAM=64
NOT=160
SEQOF=81
TEXTAREA_CONTENT=102
NUMBER_OF_INSTANCES=60
COMMENT2=210
MANTISSA=167
ROUTE=79
MOD=159
GROUND=44
PARAM=65
NOT=161
SEQOF=82
TEXTAREA_CONTENT=103
EOF=-1
ACTION=4
IMPORT=170
CREATE=147
FPAR=42
NEXTSTATE=58
RETURN=77
THIS=148
IMPORT=171
CREATE=148
FPAR=43
NEXTSTATE=59
RETURN=78
THIS=149
CHANNEL=13
VIAPATH=112
ENDCONNECTION=125
EXPORT=31
EQ=141
INFORMAL_TEXT=48
GEODE=174
D=183
E=186
F=193
GE=146
G=194
A=180
IMPLIES=151
B=202
C=184
L=185
M=190
N=181
O=195
TERMINATOR=99
H=196
I=192
ELSE=26
J=203
K=187
U=199
T=197
W=201
STOP=90
V=200
INT=123
Q=210
P=188
S=191
VALUE=108
R=189
Y=182
X=198
FI=34
Z=211
MINUS_INFINITY=165
WS=208
OUT=131
NONE=132
INPUT_NONE=51
CONSTANT=21
GT=143
CALL=137
END=176
FLOATING_LABEL=40
VIAPATH=113
ENDCONNECTION=126
EXPORT=32