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

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