Commit 04581b9e authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Add support for the "exist" operator in the parser

This operator returns True if an OPTIONAL field is actually present in a
record.
parent 35cf67aa
......@@ -121,6 +121,7 @@ SPECIAL_OPERATORS = {
{'type': NUMERICAL, 'direction': 'in'}
],
'present' : [{'type': CHOICE, 'direction': 'in'}],
'exist' : [{'type': ANY_TYPE, 'direction': 'in'}],
'reset_timer': [{'type': TIMER, 'direction': 'in'}],
'round' : [{'type': REAL, 'direction': 'in'}],
'set_timer' : [
......@@ -522,7 +523,7 @@ def check_call(name, params, context):
else:
for each in (p.value['then'], p.value['else']):
check_one_param(each, name)
# check that both "then" and "else" are both of a similar type
# check that both "then" and "else" are of a similar type
# (string, int, or enumerated), this is necessary for the
# backends
if (is_numeric(p.value['then'].exprType) ==
......@@ -539,6 +540,47 @@ def check_call(name, params, context):
.format(name))
return UNKNOWN_TYPE
# Special case for "exist" function
elif name == 'exist':
# "exist" shall return true if an optional SEQUENCE field is present
# We have to check that the parameter is actually an optional field
# So we check first that there is only one param
# then that this is a PrimSelector (at least "a.b")
# Then we analyse from the variable to the last field if that is
# actually an optional field, using the ASN.1 data model
if len(params) != 1:
raise TypeError ('"exist" operator takes only one parameter')
param, = params
if not isinstance(param, ogAST.PrimSelector):
raise TypeError ('"exist" operator only works on optional fields')
left = param.value[0] # Can be a variable or another PrimSelector
field_list = [param.value[1]] # string of the field name
while isinstance(left, ogAST.PrimSelector):
field_list.append(left.value[1])
left = left.value[0]
sort = find_basic_type(left.exprType) # must have Children
if sort.kind == 'UnknownType':
raise TypeError('Variable not found in call to "exist" operator')
# At this point we know that the expression is correct, so we will
# not miss any child in the dataview. We can follow the children
# in the ASN.1 model until we reach the last one, which shall be
# optional
while field_list:
child_name = field_list.pop().replace('_', '-').lower()
for child in sort.Children.viewkeys():
if child.lower() == child_name:
break
optional = sort.Children[child].Optional
sort = sort.Children[child].type
if sort.kind == 'ReferenceType':
sort = find_basic_type (sort)
# At this point we should have found the last type
if optional != "True":
raise TypeError('Field is not optional in call to "exist"')
return type('Exist', (object,), {
'kind': 'BooleanType'
})
# (1) Find the signature of the function
# signature will hold the list of parameters for the function
sign = signature(name, context)
......@@ -2030,6 +2072,8 @@ def selector_expression(root, context, pos="right"):
except AttributeError:
# When parsing for syntax or copy-paste, receiver_bty may
# not be found
# CHECKME: but then we don't detect nonexistent variable in a function
# call?!?!
pass
node.value = [receiver, field_name.replace('-', '_').lower()]
......
......@@ -8,7 +8,7 @@ edit:
$(OPENGEODE) og.pr
test-parse:
$(OPENGEODE) og.pr --check
$(OPENGEODE) og.pr -g --check
test-qgen-parse:
$(TESTQGEN_PARSE) $(ROOT_MODEL)
......
......@@ -10,6 +10,10 @@ Seq ::= SEQUENCE {
b-C BOOLEAN OPTIONAL
} OPTIONAL
}
ChoiceWithInnerSeq ::= CHOICE {
ch1 Seq,
ch2 SEQUENCE { opt-field BOOLEAN OPTIONAL }
}
-- Type with DEFAULT values (similar to OPTIONAL in many ways)
SeqDef ::= SEQUENCE {
......
SYSTEM og;
system og;
/* CIF TEXT (159, 221), (289, 188) */
-- Text area for declarations and comments
......@@ -8,17 +8,17 @@ SYSTEM og;
signal we;
/* CIF ENDTEXT */
CHANNEL c
FROM ENV TO og WITH run;
FROM og TO ENV WITH we;
ENDCHANNEL;
BLOCK og;
SIGNALROUTE r
FROM ENV TO og WITH run;
FROM og TO ENV WITH we;
CONNECT c AND r;
channel c
from env to og with run;
from og to env with we;
endchannel;
block og;
signalroute r
from env to og with run;
from og to env with we;
connect c and r;
/* CIF PROCESS (225, 50), (150, 75) */
PROCESS og;
process og;
/* CIF TEXT (531, 266), (448, 158) */
dcl s1 Seq := { a TRUE };
......@@ -33,37 +33,54 @@ SYSTEM og;
/* CIF ENDTEXT */
/* CIF START (269, 259), (70, 35) */
START;
/* CIF TASK (239, 309), (130, 35) */
TASK s2 := { a FALSE};
/* CIF TASK (247, 359), (114, 35) */
TASK s2.a := TRUE;
/* CIF TASK (234, 409), (139, 35) */
TASK s2.b.b_c := TRUE;
/* CIF TASK (224, 459), (159, 35) */
TASK s2 :={ b { b_c TRUE }};
/* CIF PROCEDURECALL (244, 514), (119, 35) */
CALL writeln (def.b)
/* CIF COMMENT (383, 514), (201, 35) */
COMMENT 'Uninitialized, expect garbage';
/* CIF PROCEDURECALL (244, 569), (120, 35) */
CALL writeln (def2.b)
/* CIF COMMENT (384, 569), (145, 35) */
COMMENT 'Should display 19';
/* CIF TASK (258, 624), (92, 35) */
TASK def2.b := 16;
/* CIF PROCEDURECALL (244, 674), (120, 35) */
CALL writeln (def2.b)
/* CIF COMMENT (384, 674), (145, 35) */
COMMENT 'Should display 16';
/* CIF NEXTSTATE (269, 724), (70, 35) */
/* CIF task (239, 309), (130, 35) */
task s2 := { a FALSE};
/* CIF decision (261, 364), (85, 48) */
decision exist (s2.a)
/* CIF comment (366, 370), (122, 38) */
comment 'test presence of
optional field';
/* CIF ANSWER (224, 432), (70, 23) */
(true):
/* CIF ANSWER (314, 432), (70, 23) */
(false):
enddecision;
/* CIF decision (249, 470), (110, 50) */
decision exist (s2.b.b_c);
/* CIF ANSWER (224, 540), (70, 23) */
(true):
/* CIF ANSWER (314, 540), (70, 23) */
(false):
enddecision;
/* CIF task (247, 578), (114, 35) */
task s2.a := TRUE;
/* CIF task (234, 628), (139, 35) */
task s2.b.b_c := TRUE;
/* CIF task (224, 678), (159, 35) */
task s2 :={ b { b_c TRUE }};
/* CIF PROCEDURECALL (244, 733), (119, 35) */
call writeln (def.b)
/* CIF comment (383, 733), (201, 35) */
comment 'Uninitialized, expect garbage';
/* CIF PROCEDURECALL (244, 788), (120, 35) */
call writeln (def2.b)
/* CIF comment (384, 788), (145, 35) */
comment 'Should display 19';
/* CIF task (258, 843), (92, 35) */
task def2.b := 16;
/* CIF PROCEDURECALL (244, 893), (120, 35) */
call writeln (def2.b)
/* CIF comment (384, 893), (145, 35) */
comment 'Should display 16';
/* CIF NEXTSTATE (269, 943), (70, 35) */
NEXTSTATE wait;
/* CIF STATE (269, 724), (70, 35) */
STATE wait;
/* CIF INPUT (261, 779), (84, 35) */
INPUT run;
/* CIF NEXTSTATE (259, 829), (88, 35) */
/* CIF state (269, 943), (70, 35) */
state wait;
/* CIF input (261, 998), (84, 35) */
input run;
/* CIF NEXTSTATE (259, 1048), (88, 35) */
NEXTSTATE wait;
ENDSTATE;
ENDPROCESS og;
ENDBLOCK;
ENDSYSTEM;
\ No newline at end of file
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