Commit 77140fd9 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Merge branch 'feature_stateType'

parents a493a3df 52ae9e35
......@@ -175,8 +175,13 @@ The background pattern was downloaded from www.subtlepatterns.com
Changelog
=========
**3.1.3 (07/2020)**
- Fix issue finding ASN.1 files when model loaded from another folder
**3.2.1 (07/2020)**
- Fix issue with the "present" operator
- Move the context declaration to the .ads
- Always expose the Get_State function (returns char * to C)
**3.2.0 (07/2020)**
- Add basic support for state type/instance
**3.1.2 (07/2020)**
- Reinforce syntax error checking and reporting
......
......@@ -424,8 +424,9 @@ LD_LIBRARY_PATH=./lib:. opengeode-simulator
context_decl.append(u'{ctxt}_bk: {ctxt}_Ty;'
.format(ctxt=LPREFIX))
if not simu and not instance:
process_level_decl.extend(context_decl)
# Don't declare the context in the adb - declare it in the ads
#if not simu and not instance:
# process_level_decl.extend(context_decl)
aggreg_start_proc = []
start_transition = []
......@@ -490,7 +491,7 @@ LD_LIBRARY_PATH=./lib:. opengeode-simulator
use {process_name}_newtypes;'''.format(process_name=process_name) \
if process.user_defined_types else u''
taste_template = [u'''\
taste_template = [f'''\
-- This file was generated automatically by OpenGEODE: DO NOT MODIFY IT !
with System.IO;
......@@ -499,22 +500,7 @@ use System.IO;
with Ada.Unchecked_Conversion;
with Ada.Numerics.Generic_Elementary_Functions;
{dataview}
{custom_data_types}
with Interfaces;
use Interfaces;
{C}
{Context}
package body {process_name} is'''.format(
process_name=process_name,
dataview=asn1_modules,
custom_data_types=include_custom_types,
C='with Interfaces.C.Strings;\n'
'use Interfaces.C.Strings;'
if simu else '',
Context=f"with {import_context}; use {import_context};"
if import_context else '')
package body {process_name} is'''
if not instance else u"package body {} is".format(process_name)]
generic_spec, instance_decl = "", ""
......@@ -530,43 +516,51 @@ package body {process_name} is'''.format(
# FPAR could be set for Context Parameters. They are available here
# Generate the source file (.ads) header
ads_template = [u'''\
# Stop conditions must import the SDL model they observe
imp_str = f"with {import_context}; use {import_context};" \
if import_context else ''
ads_template = [f'''\
-- This file was generated automatically by OpenGEODE: DO NOT MODIFY IT !
{dataview}
{C}
{instance}
{generic}
package {process_name} is'''.format(generic=generic_spec,
instance=instance_decl,
process_name=process_name,
dataview=asn1_modules,
C='with Interfaces.C.Strings,\n'
' Ada.Characters.Handling;\n'
'use Interfaces.C.Strings,\n'
' Ada.Characters.Handling;'
if simu else '')]
with Interfaces,
Interfaces.C.Strings,
Ada.Characters.Handling;
use Interfaces,
Interfaces.C.Strings,
Ada.Characters.Handling;
{asn1_modules}
{include_custom_types}
{imp_str}
{instance_decl}
{generic_spec}'''.strip() + f'''
package {process_name} with Elaborate_Body is''']
dll_api = []
if simu:
if not instance:
ads_template.extend(context_decl)
if not generic and not instance:
# Add function allowing to trace current state as a string
ads_template.append(
f"function Get_State return chars_ptr "
f"is (New_String (States'Image ({LPREFIX}.State)))"
f" with Export, Convention => C, "
f'Link_Name => "{process_name.lower()}_state";')
if simu:
ads_template.append('-- API for simulation via DLL')
dll_api.append('-- API to remotely change internal data')
# Add function allowing to trace current state as a string
process_level_decl.append("function Get_State return chars_ptr "
"is (New_String(states'Image({ctxt}.state)))"
" with Export, Convention => C, "
'Link_Name => "{name}_state";'
.format(name=process_name, ctxt=LPREFIX))
set_state_decl = "procedure Set_State(New_State : chars_ptr)"
ads_template.append("{};".format(set_state_decl))
ads_template.append('pragma Export(C, Set_State, "_set_state");')
dll_api.append("{} is".format(set_state_decl))
set_state_decl = "procedure Set_State (New_State : chars_ptr)"
ads_template.append(f'{set_state_decl} with Export, Convention => C, '
f' Link_Name => "_set_state";')
dll_api.append(f"{set_state_decl} is")
dll_api.append("begin")
dll_api.append("for S in States loop")
dll_api.append("if To_Upper (Value (New_State))"
" = States'Image (S) then")
dll_api.append("{}.state := S;"
.format(LPREFIX))
dll_api.append(f"{LPREFIX}.State := S;")
dll_api.append("end if;")
dll_api.append("end loop;")
dll_api.append("end Set_State;")
......@@ -993,6 +987,11 @@ package {process_name} is'''.format(generic=generic_spec,
if ri_inst:
pkg_decl += u" ({})".format(u", ".join(ri_inst))
ads_template.append(pkg_decl + u";")
ads_template.append(
f"function Get_State return chars_ptr "
f"is (New_String ({process_name}_Instance.{LPREFIX}.State'Img))"
f" with Export, Convention => C, "
f'Link_Name => "{process_name.lower()}_state";')
has_cs = any(process.cs_mapping.values())
......
This diff is collapsed.
......@@ -703,6 +703,9 @@ def check_call(name, params, context):
# check that the list of enumerants are identical. unfortunately we
# cannot check the ordering, as it is an unordered dict
if name == 'to_selector':
# if the sort is a subtype, it may not have a -selection suffix
# and an exception may be raised. FIXME : check "present" operator
# as the issue is already fixed there
return_type = types()[sort + '-selection'].type
else:
return_type = types()[sort].type
......@@ -828,8 +831,21 @@ def check_call(name, params, context):
elif name == 'present':
p, = params
sort = type_name (p.exprType) + "-selection"
return types()[sort].type
# When we get there, the parameter has been checked already and we
# know it is a CHOICE type.
# However it may be a subtype, and in the AST the choices are defined
# in the supertype, so we must find it and and the -selection suffix
# This suffix is added by the Asn1scc module.
sort = p.exprType
sort_name = type_name (sort)
try:
while sort.kind == "ReferenceType":
sort_name = sort.ReferencedTypeName
sort = types()[sort.ReferencedTypeName].type
except AttributeError:
# Native choice types don't have the kind field here
pass
return types()[sort_name + "-selection"].type
# choice_to_int: returns an integer corresponding to either the currently
# selected choice value (e.g. foo in CHOICE { foo INTEGER (..), ... } when
......@@ -3857,13 +3873,13 @@ def state(root, parent, context):
state_def.charPositionInLine = child.getCharPositionInLine()
state_def.statelist = [state_def.inputString]
inst_stop = child.getTokenStopIndex()
via_stop = inst_stop # in case there is also a via clause
elif child.type == lexer.TYPE_INSTANCE:
# Extract the complete string "state: instance"
start = inst_stop
stop = child.getTokenStopIndex()
full_string = token_stream(root).toString(start, stop)
state_def.inputString, state_def.instance_of = \
full_string, state_def.instance_of
state_def.inputString = token_stream(root).toString(start, stop)
state_def.instance_of = child.getChild(0).toString()
elif child.type == lexer.STATELIST:
# State name(state_def)
state_def.inputString = get_input_string(child)
......@@ -3911,7 +3927,12 @@ def state(root, parent, context):
'in substate "{}"'
.format(each, comp.statename.lower()))
try:
for statename in state_def.statelist:
# Use the statelist unless the state is an instance
if not state_def.instance_of:
statelist = state_def.statelist
else:
statelist = [state_def.instance_of]
for statename in statelist:
# check that input is not already defined
existing = context.mapping.get(statename.lower(), [])
dupl = set()
......@@ -3926,8 +3947,11 @@ def state(root, parent, context):
.format(each, statename.lower()))
# then update the mapping state-input
context.mapping[statename.lower()].append(inp)
except KeyError:
stwarn.append('State definition missing')
except KeyError as err:
# missing state definition is caught at other places, no
# need to report here
pass
#stwarn.append(f'State definition missing - {str(err)}')
state_def.inputs.append(inp)
if inp.inputString.strip() == '*':
if asterisk_input:
......@@ -4675,7 +4699,7 @@ def decision(root, parent, context):
def nextstate(root, context):
''' Parse a NEXTSTATE [: type] [VIA State_Entry_Point]
''' Parse a NEXTSTATE [: type] [VIA State_Entry_Point]
detect various kinds of errors when trying to enter a nested state '''
next_state_id, via, entrypoint, instance_of = '', None, None, None
errors = []
......@@ -4689,24 +4713,6 @@ def nextstate(root, context):
via = get_input_string(root).replace(
'NEXTSTATE', '', 1).strip()
entrypoint = child.getChild(0).text
try:
composite, = (comp for comp in context.composite_states
if comp.statename.lower()
== next_state_id.lower())
except ValueError:
errors.append('State {} is not a composite state'
.format(next_state_id))
else:
if entrypoint.lower() not in composite.state_entrypoints:
errors.append('State {s} has no "{p}" entrypoint'
.format(s=next_state_id, p=entrypoint))
for each in composite.content.named_start:
if each.inputString == entrypoint.lower() + '_START':
break
else:
errors.append('Entrypoint {p} in state {s} is '
'declared but not defined'.format
(s=next_state_id, p=entrypoint))
else:
errors.append('"History" NEXTSTATE cannot have a "via" clause')
elif child.type == lexer.TYPE_INSTANCE:
......@@ -4716,17 +4722,40 @@ def nextstate(root, context):
else:
errors.append('NEXTSTATE undefined construct: ' +
sdl92Parser.tokenNamesMap[child.type])
if not via:
# check that if the nextstate is nested, it has a START symbol
try:
composite, = (comp for comp in context.composite_states
if comp.statename.lower() == next_state_id.lower())
if not isinstance(composite, ogAST.StateAggregation) \
and not composite.content.start:
errors.append('Composite state "{}" has no unnamed '
'START symbol'.format(composite.statename))
except ValueError:
# Checks on the NEXTSTATE
if via: # instance and/or via clause
state_id = instance_of or next_state_id
try:
composite, = (comp for comp in context.composite_states
if comp.statename.lower() == state_id.lower())
except ValueError:
errors.append(f'State {state_id} is not a composite state')
else:
if entrypoint is None:
pass
elif entrypoint.lower() not in composite.state_entrypoints:
errors.append(
f'State {state_id} has no "{entrypoint}" entrypoint')
# The test below seems identical to the one just done
# for each in composite.content.named_start:
# if not entrypoint or \
# each.inputString == entrypoint.lower() + '_START':
# break
# else:
# errors.append(f'Entrypoint {entrypoint} in state'
# f' {state_id} is declared but not defined')
else: # not via and/or instance
# check that if the nextstate is nested, it has a START symbol
try:
composite, = (comp for comp in context.composite_states
if comp.statename.lower() == next_state_id.lower())
if not isinstance(composite, ogAST.StateAggregation) \
and not composite.content.start:
errors.append('Composite state "{}" has no unnamed '
'START symbol'.format(composite.statename))
except ValueError:
pass
return next_state_id, via, entrypoint, instance_of, errors
......@@ -5447,6 +5476,18 @@ def parse_pr(files=None, string=None):
[t_x, t_y],
['PROCESS {}'.format(process.processName)]])
# TODO: do the same with JOIN/LABEL
# Check that all floating state instances (foo:bar) have a correspoding
# nested state defined.
state_types = set(st.instance_of.lower()
for st in process.content.states if st.instance_of)
comp_states = set(comp.statename.lower()
for comp in process.composite_states)
for missing in state_types - comp_states:
errors.append([f'Nested state definition missing : {missing}',
[0, 0],
['PROCESS {}'.format(process.processName)]])
return og_ast, warnings, errors
......
......@@ -140,7 +140,7 @@ except ImportError:
__all__ = ['opengeode', 'SDL_Scene', 'SDL_View', 'parse']
__version__ = '3.1.3'
__version__ = '3.2.1'
if hasattr(sys, 'frozen'):
# Detect if we are running on Windows (py2exe-generated)
......@@ -2323,14 +2323,21 @@ clean:
pr_raw = Pr.parse_scene(scene, full_model=True
if not self.readonly_pr else False)
pr_data = str('\n'.join(pr_raw))
if pr_data:
ast, warnings, errors = ogParser.parse_pr(files=self.readonly_pr,
string=pr_data)
scene.semantic_errors = True if errors else False
log_errors(self.messages_window, errors, warnings,
clearfirst=False)
self.update_asn1_dock.emit(ast)
return "Done"
try:
if pr_data:
ast, warnings, errors = ogParser.parse_pr(
files=self.readonly_pr,
string=pr_data)
scene.semantic_errors = True if errors else False
log_errors(self.messages_window, errors, warnings,
clearfirst=False)
self.update_asn1_dock.emit(ast)
return "Done"
except Exception as err:
self.messages_window.addItem("Opengeode bug, PLEASE REPORT: "
+ str(err))
LOG.debug(str(traceback.format_exc()))
return "Syntax Errors"
def show_item(self, item):
'''
......
This diff is collapsed.
This diff is collapsed.
......@@ -981,8 +981,9 @@ class State(VerticalSymbol):
@property
def allow_nesting(self):
''' Redefinition - must be checked according to context '''
# nesting permitted only if single plain state
result = not any(elem in str(self).lower().strip()
for elem in ('-', ',', '*'))
for elem in ('-', ',', '*', ':', 'via'))
return result
@property
......
......@@ -478,16 +478,17 @@ floating_label
-> ^(FLOATING_LABEL cif? hyperlink? connector_name transition?)
;
// state is either a full state definition, or a declaration of an instance
// state is either a full state definition, or a state instance
state
: state_definition
| state_instance
;
// the "via" part is needed to allow the graphical merge with a nextstate
state_definition
: cif?
hyperlink?
STATE statelist via? (e=end | SEMI) // "via" part may be in NEXTSTATE
STATE statelist via? (e=end | SEMI)
(state_part)*
ENDSTATE statename? f=end
-> ^(STATE cif? hyperlink? $e? statelist via? state_part*)
......@@ -497,9 +498,10 @@ state_definition
state_instance
: cif?
hyperlink?
STATE statename ':' type_inst e=end
STATE statename ':' type_inst via? (e=end | SEMI)
(state_part)*
ENDSTATE statename? f=end
-> ^(STATE cif? hyperlink? $e? statename type_inst)
-> ^(STATE cif? hyperlink? $e? statename via? type_inst state_part*)
;
......
......@@ -3,6 +3,10 @@
#include "dataview-uniq.h"
extern void adainit();
extern void orchestrator_startup();
extern void orchestrator_PI_other();
extern void orchestrator_PI_Paramless_TC();
extern char *orchestrator_state();
void orchestrator_RI_peek_list(void *_) {}
void orchestrator_RI_peek_fixed(void *_) {}
void orchestrator_RI_telemetry(void *_){}
......@@ -15,7 +19,13 @@ int main()
int i;
printf("[C Code] Running test\n");
adainit();
orchestrator_startup();
toto = fixed_value();
printf("%s\n", orchestrator_state());
orchestrator_PI_other();
printf("%s\n", orchestrator_state());
orchestrator_PI_other();
printf("%s\n", orchestrator_state());
// size = fixed_size();
// printf("Size=%d\n", size);
// for (i = 0; i<size; i++) printf("%d", toto[i]);
......
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