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

Setup the grounds to support PROCESS TYPE construct and instances

parent bd071849
......@@ -97,6 +97,39 @@ SHARED_LIB = False
UNICODE_SEP = u'\u00dc'
LPREFIX = u'ctxt'
def external_ri_list(process):
''' Helper function: create a list of RI with proper signature
Used for the formal parameters of generic packages when using process type
'''
result = []
for signal in process.output_signals:
param_name = signal.get('param_name') \
or u'{}_param'.format(signal['name'])
param_spec = ''
if 'type' in signal:
typename = type_name(signal['type'])
param_spec = u'({pName}: access {sort})'.format(pName=param_name,
sort=typename)
result.append(u"procedure RI{sep}{name}{param}".format(sep=UNICODE_SEP,
name=signal['name'],
param=param_spec))
for proc in (proc for proc in process.procedures if proc.external):
ri_header = u'procedure RI{sep}{sig_name}'.format(
sep=UNICODE_SEP,
sig_name=proc.inputString)
params = []
params_spec = ''
for param in proc.fpar:
typename = type_name(param['type'])
params.append(u'{par[name]}: access {sort}'.format(par=param,
sort=typename))
if params:
params_spec = u"({})".format("; ".join(params))
ri_header += params_spec
result.append(ri_header)
return result
@singledispatch
def generate(*args, **kwargs):
''' Generate the code for an item of the AST '''
......@@ -108,7 +141,12 @@ def generate(*args, **kwargs):
@generate.register(ogAST.Process)
def _process(process, simu=False, **kwargs):
''' Generate the code for a complete process (AST Top level) '''
process_name = process.processName
# support generation of code of a process type
process_name = process.instance_of_name or process.processName
generic = process.instance_of_name # shortcut
process_instance = process
process = process.instance_of_ref or process
global TYPES
TYPES = process.dataview
del OUT_SIGNALS[:]
......@@ -373,19 +411,25 @@ package body {process_name} is'''.format(process_name=process_name,
'use Interfaces.C.Strings;'
if simu else '')]
generic_spec = ""
if generic:
generic_spec = u"generic\n"
ri_list = external_ri_list(process)
if ri_list:
generic_spec += u" with " + u";\n with ".join(ri_list) + ';'
# Generate the source file (.ads) header
ads_template = ['''\
ads_template = [u'''\
-- This file was generated automatically: DO NOT MODIFY IT !
{dataview}
{C}
package {process_name} is'''.format(process_name=process_name,
{generic}
package {process_name} is'''.format(generic=generic_spec if generic else "",
process_name=process_name,
dataview=asn1_modules,
C='with Interfaces.C.Strings;\n'
'use Interfaces.C.Strings;'
if simu else '')]
dll_api = []
if simu:
ads_template.extend(context_decl)
......@@ -473,7 +517,7 @@ package {process_name} is'''.format(process_name=process_name,
# Exported procedures must be declared in the .ads
pi_header = procedure_header(proc)
ads_template.append(u'{};'.format(pi_header))
if not proc.external:
if not proc.external and not generic:
ads_template.append(u'pragma Export'
u'(C, p{sep}{proc_name}, "_{proc_name}");'
.format(sep=UNICODE_SEP,
......@@ -510,8 +554,9 @@ package {process_name} is'''.format(process_name=process_name,
# Add declaration of the provided interface in the .ads file
ads_template.append(u'-- Provided interface "{}"'.format(signame))
ads_template.append(pi_header + ';')
ads_template.append(u'pragma Export(C, {name}, "{proc}_{name}");'
.format(name=signame, proc=process_name))
if not generic:
ads_template.append(u'pragma Export(C, {name}, "{proc}_{name}");'
.format(name=signame, proc=process_name))
if simu:
# Generate code for the mini-cv template
......@@ -631,9 +676,10 @@ package {process_name} is'''.format(process_name=process_name,
sort=typename,
shared=u'; Size: Integer'
if SHARED_LIB else '')
ads_template.append(u'-- {}equired interface "{}"'
.format("Paramless r" if not 'type' in signal
else "R", signal['name']))
if not generic:
ads_template.append(u'-- {}equired interface "{}"'
.format("Paramless r" if not 'type' in signal
else "R", signal['name']))
if simu:
# When generating a shared library, we need a callback mechanism
ads_template.append(u'type {}_T is access procedure{};'
......@@ -661,7 +707,7 @@ package {process_name} is'''.format(process_name=process_name,
.format(sep=UNICODE_SEP, sig=signal['name']))
taste_template.append(u'end Register_{};'.format(signal['name']))
taste_template.append(u'')
else:
elif not generic:
ads_template.append(u'procedure RI{}{}{};'
.format(UNICODE_SEP,
signal['name'],
......@@ -718,7 +764,7 @@ package {process_name} is'''.format(process_name=process_name,
taste_template.append(u'end Register_{};'.format(proc.inputString))
taste_template.append(u'')
else:
elif not generic:
ads_template.append(ri_header + u';')
ads_template.append(u'pragma import(C, RI{sep}{sig},'
u' "{proc}_RI_{sig}");'
......@@ -764,13 +810,15 @@ package {process_name} is'''.format(process_name=process_name,
else:
ads_template.append(u'procedure SET_{}(val: access asn1SccT_UInt32);'
.format(timer))
ads_template.append(
u'pragma import(C, SET_{timer}, "{proc}_RI_set_{timer}");'
.format(timer=timer, proc=process_name))
if not generic:
ads_template.append(
u'pragma import(C, SET_{timer}, "{proc}_RI_set_{timer}");'
.format(timer=timer, proc=process_name))
ads_template.append(u'procedure RESET_{};'.format(timer))
ads_template.append(
u'pragma import(C, RESET_{timer}, "{proc}_RI_reset_{timer}");'
.format(timer=timer, proc=process_name))
if not generic:
ads_template.append(
u'pragma import(C, RESET_{timer}, "{proc}_RI_reset_{timer}");'
.format(timer=timer, proc=process_name))
if simu and process.cs_mapping:
# Callback registration for Check_Queue
......@@ -861,9 +909,10 @@ package {process_name} is'''.format(process_name=process_name,
taste_template.append('end if;')
ads_template.append(
u'procedure Check_Queue(res: access Asn1Boolean);')
ads_template.append(
u'pragma import(C, Check_Queue, "{proc}_check_queue");'
.format(proc=process_name))
if not generic:
ads_template.append(
u'pragma import(C, Check_Queue, "{proc}_check_queue");'
.format(proc=process_name))
elif process.cs_mapping and simu:
taste_template.append('if {}.initDone then'.format(LPREFIX))
taste_template.append("Check_Queue(msgPending'access);")
......
......@@ -2,7 +2,7 @@
 
# Resource object code
#
# Created: Sun Feb 19 22:16:09 2017
# Created: Sun Mar 19 12:13:43 2017
# by: The Resource Compiler for PySide (Qt v4.8.6)
#
# WARNING! All changes made in this file will be lost!
......@@ -834,6 +834,11 @@ class Process(object):
self.processName = None
# Optional filename containing this process (PR file)
self.filename = None
# Optional type of this process instance (name = string, ref = Process)
self.instance_of_name = None
self.instance_of_ref = None
# A process may be a process type (boolean)
self.process_type = False
# Process parent context (Block or AST if defined at root level)
self.parent = None
# A process can be referenced (externally defined)
......
......@@ -320,7 +320,9 @@ def find_process_declaration(ast, process_name):
return result
try:
for process in ast.processes:
if process.processName == process_name:
if process.processName.lower() == process_name.lower():
return process
elif process.instance_of_name.lower() == process_name.lower():
return process
except AttributeError:
return None
......@@ -345,13 +347,15 @@ def get_interfaces(ast, process_name):
'''
Search for the list of input and output signals (async PI/RI)
and procedures (sync RI) of a process in a given top-level AST
process_name can be the name of a process type, in which case the
interfaces can only be found by looking at an instance of the type
that is actually connected in the system
'''
all_signals, async_signals, errors = [], [], set()
system = None
system = ast
# Move up to the system level, in case process is nested in a block
# and not defined at root level as it is the case when it is referenced
system = ast
while hasattr(system, 'parent'):
system = system.parent
......@@ -361,7 +365,10 @@ def get_interfaces(ast, process_name):
for system in iterator:
all_signals.extend(signals_in_system(system))
process_ref = find_process_declaration(system, process_name)
# Update process name with the name of the instance if we are parsing
# a process type.
if process_ref:
process_name = process_ref.processName
# Go to the block where the process is defined
process_parent = process_ref.parent
break
......@@ -2763,12 +2770,6 @@ def system_definition(root, parent):
else:
warnings.append('Unsupported construct in system: ' +
str(child.type))
# if asn1_files:
# # parse ASN.1 files before parsing the rest of the system
# try:
# set_global_DV(asn1_files)
# except TypeError as err:
# errors.append(str(err))
if asn1_files:
system.ast.asn1Modules = DV.asn1Modules
system.ast.asn1_filenames = asn1_files
......@@ -2886,9 +2887,11 @@ def process_definition(root, parent=None, context=None):
process.composite_states.append(comp)
elif child.type == lexer.REFERENCED:
process.referenced = True
elif child.type == lexer.TYPE:
process.process_type = True
elif child.type == lexer.TYPE_INSTANCE:
# PROCESS Toto:ParentType; Not supported
pass
# PROCESS Toto:ParentType;
process.instance_of_name = child.children[0].text
elif child.type == lexer.COMMENT:
process.comment, _, _ = end(child)
else:
......@@ -2900,7 +2903,8 @@ def process_definition(root, parent=None, context=None):
err, warn = procedure_post(proc, content, context=process)
errors.extend(err)
warnings.extend(warn)
if not process.referenced and (not process.content.start or
if not process.referenced and not process.instance_of_name \
and (not process.content.start or
not process.content.start.terminators):
# detect missing START transition
errors.append(['Mandatory START transition is missing in process',
......@@ -4431,7 +4435,7 @@ def pr_file(root):
ast.systems.append(system)
def find_processes(block):
''' Recursively find processes in a system '''
''' Recursively find non-referenced processes in a system '''
try:
result = [proc for proc in block.processes
if not proc.referenced]
......@@ -4442,7 +4446,7 @@ def pr_file(root):
return result
ast.processes.extend(find_processes(system))
for child in processes:
# process definition at root level (must be referenced in a system)
# process definition at root level (can be a process type)
process, err, warn = process_definition(child, parent=ast)
ast.processes.append(process)
process.dataview = types()
......@@ -4450,6 +4454,34 @@ def pr_file(root):
process.dv = DV
errors.extend(err)
warnings.extend(warn)
# Check that process instance/types match
process_instances = []
process_types = []
to_be_deleted = []
for each in ast.processes:
if each.instance_of_name is not None or not each.process_type:
# standalone process or instance of a process type
process_instances.append(each)
elif each.process_type:
process_types.append(each)
for each in process_instances:
if each.instance_of_name is not None:
# Find corresponding process type definition
for p_type in process_types:
if p_type.processName == each.instance_of_name:
each.instance_of_ref = p_type
to_be_deleted.append(p_type)
break
else:
warnings.append('"{}" PROCESS TYPE definition not found'
.format(each.instance_of_name))
for each in to_be_deleted:
ast.processes.remove(each)
process_types.remove(each)
for each in process_types:
ast.processes.remove(each)
warnings.append('No instance of PROCESS TYPE "{}" found'
.format(each.processName))
# Since SDL type declarations are injected in ASN.1 ast,
# The ASN.1 ASTs needs to be copied at the end of PR parsing process
......
......@@ -1736,7 +1736,12 @@ class SDL_View(QtGui.QGraphicsView, object):
''' Enter a nested diagram (procedure, composite state) '''
# Save context history
self.context_history.append(sdlSymbols.CONTEXT)
subtype, subname = name.split()
try:
subtype, subname = name.split()
except ValueError as err:
LOG.debug("[go_down] name split fail (PROCESS TYPE?)" + str(err))
LOG.info("Can't refine content of a type instance")
return
# Get AST of the element that is entered
if subtype == 'procedure':
for each in sdlSymbols.CONTEXT.procedures:
......@@ -1802,7 +1807,7 @@ class SDL_View(QtGui.QGraphicsView, object):
item.nested_scene = \
self.scene().create_subscene(ctx, self.scene())
self.go_down(item.nested_scene,
name=ctx + u' ' + unicode(item))
name=u"{} {}".format(ctx, unicode(item)))
else:
# Otherwise, double-click edits the item text
item.edit_text(self.mapToScene(evt.pos()))
......@@ -1944,19 +1949,23 @@ class SDL_View(QtGui.QGraphicsView, object):
LOG.error('Aborting: could not open or parse input file')
sdlSymbols.CONTEXT = ogAST.Block()
return
try:
process, = ast.processes
self.filename = process.filename
self.readonly_pr = ast.pr_files - {self.filename}
except ValueError:
LOG.error('Cannot load process')
if not ast.processes:
LOG.error("No PROCESS was parsed in the input file(s)")
process = ogAST.Process()
process.processName = "SyntaxError"
process.processName = "Syntax_Error"
elif len(ast.processes) == 1:
process, = ast.processes
self.filename = process.filename
self.readonly_pr = ast.pr_files - {self.filename}
else:
# More than one process
LOG.error("More than one process is not supported")
return
try:
syst, = ast.systems
block, = syst.blocks
if block.processes[0].referenced:
LOG.debug('Process is referenced, fixing')
LOG.debug('[Load file] Process is referenced')
block.processes = [process]
except ValueError:
# No System/Block hierarchy, creating single block
......@@ -2761,8 +2770,7 @@ def gui(options):
# Set all encodings to utf-8 in Qt
QtCore.QTextCodec.setCodecForCStrings(
QtCore.QTextCodec.codecForName('UTF-8')
)
QtCore.QTextCodec.codecForName('UTF-8'))
# Bypass system-default font, to harmonize size on all platforms
font_database = QtGui.QFontDatabase()
......
This diff is collapsed.
This diff is collapsed.
......@@ -1014,8 +1014,10 @@ class Process(HorizontalSymbol):
def __init__(self, ast=None, subscene=None):
ast = ast or ogAST.Process()
self.ast = ast
label = ast.processName + (': {}'.format(ast.instance_of_name) \
if ast.instance_of_name else '')
super(Process, self).__init__(parent=None,
text=ast.processName,
text=label,
x=ast.pos_x,
y=ast.pos_y,
hyperlink=ast.hyperlink)
......
......@@ -254,14 +254,14 @@ connection
*/
process_definition
: cif?
PROCESS process_id
PROCESS TYPE? process_id
number_of_instances? (':' type_inst)? REFERENCED? a=end
pfpar?
(text_area | procedure | (composite_state_preamble) =>composite_state)*
processBody? ENDPROCESS? process_id?
end?
-> ^(PROCESS cif? process_id number_of_instances? type_inst?
REFERENCED? $a? pfpar? text_area* procedure*
TYPE? REFERENCED? $a? pfpar? text_area* procedure*
composite_state* processBody?)
;
......@@ -1460,6 +1460,7 @@ RETURN : R E T U R N;
RETURNS : R E T U R N S;
TIMER : T I M E R;
PROCESS : P R O C E S S;
TYPE : T Y P E;
ENDPROCESS : E N D P R O C E S S;
START : S T A R T;
STATE : S T A T E;
......
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