Commit 7abbb982 authored by Maxime Perrotin's avatar Maxime Perrotin

Use Helper module in backends

parent 58bf16f3
This diff is collapsed.
This diff is collapsed.
......@@ -63,16 +63,16 @@ def _process(process):
# Set up the optimizer pipeline.
# Start with registering info about how the
# target lays out data structures.
LLVM['pass_manager'].add(LLVM['executor'].target_data)
# Do simple "peephole" optimizations and bit-twiddling optzns.
LLVM['pass_manager'].add(passes.PASS_INSTRUCTION_COMBINING)
# Reassociate expressions.
LLVM['pass_manager'].add(passes.PASS_REASSOCIATE)
# Eliminate Common SubExpressions.
LLVM['pass_manager'].add(passes.PASS_GVN)
# Simplify the control flow graph (deleting unreachable blocks, etc).
LLVM['pass_manager'].add(passes.PASS_CFG_SIMPLIFICATION)
LLVM['pass_manager'].initialize()
# LLVM['pass_manager'].add(LLVM['executor'].target_data)
# # Do simple "peephole" optimizations and bit-twiddling optzns.
# LLVM['pass_manager'].add(passes.PASS_INSTRUCTION_COMBINING)
# # Reassociate expressions.
# LLVM['pass_manager'].add(passes.PASS_REASSOCIATE)
# # Eliminate Common SubExpressions.
# LLVM['pass_manager'].add(passes.PASS_GVN)
# # Simplify the control flow graph (deleting unreachable blocks, etc).
# LLVM['pass_manager'].add(passes.PASS_CFG_SIMPLIFICATION)
# LLVM['pass_manager'].initialize()
# Create the runTransition function
run_funct_name = 'run_transition'
......
......@@ -51,9 +51,19 @@ def render(ast, scene, parent, states, terminators=None):
raise TypeError('[Renderer] Unsupported symbol in branch: ' + repr(ast))
@render.register(ogAST.Block)
def _block(ast, scene):
''' Render a block, containing a set of process symbols '''
# TODO = Add text areas with signal lists, external procedures defs...
top_level = []
for each in ast.processes:
top_level.append(render(each, scene))
return top_level
@render.register(ogAST.Process)
def _process(ast, scene):
''' Render the symbols inside a process or procedure '''
''' Render a Process symbol (in a BLOCK diagram) '''
# Set autocompletion lists for input, output, state, types, variables:
try:
sdlSymbols.TextSymbol.completion_list = {
......@@ -71,7 +81,9 @@ def _process(ast, scene):
sdlSymbols.ProcedureCall.completion_list = {
proc.inputString for proc in ast.procedures}
return render(ast.content, scene)
symbol = sdlSymbols.Process(ast, ast)
scene.addItem(symbol)
return symbol
@render.register(ogAST.Automaton)
......
This diff is collapsed.
......@@ -712,6 +712,15 @@ class Process(object):
self.variables = {}
# global variables can be used to inherit variables
self.global_variables = {}
# Set default coordinates and width/height
self.pos_x = self.pos_y = 150
self.width = 150
self.height = 75
# Optional hyperlink
self.hyperlink = None
# Optional comment
self.comment = None
# dataview: complete AST of the ASN.1 types
self.asn1Modules = None
......@@ -734,7 +743,6 @@ class Process(object):
# list of Procedure (external procedures)
self.procedures = []
# The Mapping structure should be used for code generation backends
# dictionnary: {'stateName': [class Input1, Input2,...], ...}
# then Input contains the inputs list and corresponding transition
......
......@@ -100,7 +100,7 @@ SPECIAL_OPERATORS = {'length': [LIST],
# Container to keep a list of types mapped from ANTLR Tokens
# (Used with singledispatch/visitor pattern)
ANTLR_TOKEN_TYPES = {a: type(a, (antlr3.tree.CommonTree,), {})
for a,b in lexer.__dict__.viewitems() if type(b)==int}
for a, b in lexer.__dict__.viewitems() if type(b) == int}
# Shortcut to create a new referenced ASN.1 type
......@@ -726,7 +726,6 @@ def find_type(path, context):
raise TypeError('Field ' + elem
+ ' not found in expression '
+ '!'.join(path))
result = UNKNOWN_TYPE
break
# Sequence of
elif basic.kind == 'SequenceOfType':
......@@ -857,7 +856,7 @@ def fix_expression_types(expr, context):
if asn_type.kind != 'ChoiceType' \
or field.lower() not in [key.lower()
for key in asn_type.Children.viewkeys()]:
raise TypeError('Field is not valid in CHOICE:' + field)
raise TypeError('Field is not valid in CHOICE:' + field)
key, = [key for key in asn_type.Children.viewkeys()
if key.lower() == field.lower()]
if expr.right.value['value'].exprType == UNKNOWN_TYPE:
......@@ -1069,7 +1068,7 @@ def primary_value(root, context=None):
# If there were parameters or index, try to determine the type of
# the expression
if isinstance(prim, ogAST.PrimPath) and len(prim.value)>1:
if isinstance(prim, ogAST.PrimPath) and len(prim.value) > 1:
try:
prim.exprType = find_type(prim.value, context)
except TypeError as err:
......@@ -1313,7 +1312,7 @@ def fpar(root):
param_names = []
sort = ''
direction = 'in'
assert(param.type == lexer.PARAM)
assert param.type == lexer.PARAM
for child in param.getChildren():
if child.type == lexer.INOUT:
direction = 'out'
......@@ -1743,10 +1742,16 @@ def process_definition(root, parent=None):
process.filename = node_filename(root)
process.parent = parent
parent.processes.append(process)
coord = False
# Prepare the transition/state mapping
process.mapping = {name: [] for name in get_state_list(root)}
for child in root.getChildren():
if child.type == lexer.ID:
if child.type == lexer.CIF:
# Get symbol coordinates
process.pos_x, process.pos_y, process.width, process.height =\
cif(child)
coord = True
elif child.type == lexer.ID:
# Get process (taste function) name
process.processName = child.text
try:
......@@ -1763,6 +1768,10 @@ def process_definition(root, parent=None):
except TypeError as error:
LOG.debug(str(error))
errors.append(str(error))
if coord:
errors = [[e, [process.pos_x, process.pos_y]] for e in errors]
warnings = [[w, [process.pos_x, process.pos_y]]
for w in warnings]
elif child.type == lexer.TEXTAREA:
# Text zone where variables and operators are declared
textarea, err, warn = text_area(child, context=process)
......@@ -1807,8 +1816,9 @@ def process_definition(root, parent=None):
elif child.type == lexer.REFERENCED:
process.referenced = True
else:
warnings.append('Unsupported process definition child type: ' +
str(child.type) + '- line ' + str(child.getLine()))
warnings.append('Unsupported process definition child: ' +
sdl92Parser.tokenNames[child.type] +
' - line ' + str(child.getLine()))
return process, errors, warnings
def input_part(root, parent, context):
......@@ -1901,7 +1911,7 @@ def input_part(root, parent, context):
context.transitions.append(trans)
i.transition_id = len(context.transitions) - 1
elif child.type == lexer.COMMENT:
i.comment, _, ___ = end(child)
i.comment, _, _ = end(child)
elif child.type == lexer.HYPERLINK:
i.hyperlink = child.getChild(0).toString()[1:-1]
else:
......@@ -2045,7 +2055,7 @@ def connect_part(root, parent, context):
elif child.type == lexer.HYPERLINK:
conn.hyperlink = child.getChild(0).toString()[1:-1]
elif child.type == lexer.COMMENT:
conn.comment, _, ___ = end(child)
conn.comment, _, _ = end(child)
else:
warnings.append('Unsupported CONNECT PART child type: ' +
sdl92Parser.tokenNames[child.type])
......@@ -2819,7 +2829,7 @@ def pr_file(root):
def find_processes(block):
''' Recursively find processes in a system '''
try:
result = [proc for proc in block.processes
result = [proc for proc in block.processes
if not proc.referenced]
except AttributeError:
result = []
......@@ -2857,14 +2867,14 @@ def add_to_ast(ast, filename=None, string=None):
# Root of the AST is of type antlr3.tree.CommonTree
# Add it as a child of the common tree
subtree = tree_rule_return_scope.tree
token_stream = parser.getTokenStream()
token_str = parser.getTokenStream()
children_before = set(ast.children)
# addChild does not simply add the subtree - it flattens it if necessary
# this means that possibly SEVERAL subtrees can be added. We must set
# the token_stream reference to all of them.
ast.addChild(subtree)
for tree in set(ast.children) - children_before:
tree.token_stream = token_stream
tree.token_stream = token_str
return errors, warnings
......@@ -2879,11 +2889,12 @@ def parse_pr(files=None, string=None):
sys.path.insert(0, os.path.dirname(filename))
for filename in files:
err, warn = add_to_ast(common_tree, filename=filename)
errors.extend(err)
warnings.extend(warn)
if string:
err, warn = add_to_ast(common_tree, string=string)
errors.extend(err)
warnings.extend(warn)
errors.extend(err)
warnings.extend(warn)
# At the end when common tree is complete, perform the parsing
og_ast, err, warn = pr_file(common_tree)
......@@ -2917,7 +2928,7 @@ def parseSingleElement(elem='', string=''):
LOG.debug('Parsing string: ' + string + ' with elem ' + elem)
parser = parser_init(string=string)
parser_ptr = getattr(parser, elem)
assert(parser_ptr is not None)
assert parser_ptr is not None
syntax_errors = []
semantic_errors = []
warnings = []
......
......@@ -56,7 +56,7 @@ from genericSymbols import(Symbol, Comment, EditableText, Cornergrabber,
Connection, Completer)
from sdlSymbols import(Input, Output, Decision, DecisionAnswer, Task,
ProcedureCall, TextSymbol, State, Start, Join, Label, Procedure,
ProcedureStart, ProcedureStop, StateStart, Connect)
ProcedureStart, ProcedureStop, StateStart, Connect, Process)
# Icons and png files generated from the resource file:
import icons # NOQA
......@@ -125,6 +125,7 @@ G_SYMBOLS = set()
# Lookup table used to configure the context-dependent toolbars
ACTIONS = {
'block': [Process],
'process': [Start, State, Input, Connect, Task, Decision, DecisionAnswer,
Output, ProcedureCall, TextSymbol, Comment, Label,
Join, Procedure],
......@@ -237,7 +238,7 @@ class Sdl_toolbar(QtGui.QToolBar, object):
try:
for item in scene.visible_symb:
try:
if item.is_singleton: # and item.isVisible():
if item.is_singleton:
self.actions[
item.__class__.__name__].setEnabled(False)
except (AttributeError, KeyError) as error:
......@@ -286,6 +287,7 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
QtGui.QImage(':icons/texture.png')))
self.messages_window = None
self.click_coordinates = None
self.orig_pos = None
self.process_name = 'opengeode'
# Scene name is used to update the tab window name when scene changes
self.name = ''
......@@ -310,6 +312,12 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
''' Return the top level floating items of a scene '''
return (it for it in self.visible_symb if not it.hasParent)
@property
def processes(self):
''' Return visible processes components of the scene '''
return (it for it in self.visible_symb if isinstance(it, Process) and
not isinstance(it, Procedure))
@property
def states(self):
''' Return visible state components of the scene '''
......@@ -359,6 +367,7 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
@composite_states.setter
def composite_states(self, value):
''' Attribute setter '''
self._composite_states = value
@property
......@@ -376,11 +385,13 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
pass
def render_process(self, process):
def render_everything(self, ast):
''' Render a process and its children scenes, recursively '''
self.process_name = process.processName or 'opengeode'
def recursive_render(content, dest_scene):
items_with_nested_scene = []
''' Process the rendering in scenes and nested scenes '''
if isinstance(content, ogAST.Process):
# XXX - should be set when entering the process
self.process_name = ast.processName
# Render top-level items and their children:
for each in Renderer.render(content, dest_scene):
......@@ -402,7 +413,7 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
each.nested_scene = dest_scene.composite_states[
str(each).lower()]
recursive_render(process, self)
recursive_render(ast, self)
def refresh(self):
......@@ -662,6 +673,8 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
def get_pr_string(self):
''' Parse the graphical items and returns a PR string '''
pr_data = deque()
for each in self.processes:
pr_data.append(each.parse_gr())
for item in chain(self.texts, self.procs, self.start):
pr_data.append(repr(item))
......@@ -677,8 +690,6 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
pass
pr_data.append(item.parse_gr())
pr_data.appendleft('PROCESS {};'.format(self.process_name))
pr_data.append('ENDPROCESS {};'.format(self.process_name))
return list(pr_data)
def sdl_to_statechart(self):
......@@ -686,8 +697,12 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
graph = dot.AGraph(strict=False, directed=True)
pr_raw = self.get_pr_string()
pr_data = str('\n'.join(pr_raw))
ast, _, ___ = ogParser.parse_pr(string=pr_data)
process_ast, = ast.processes
ast, _, _ = ogParser.parse_pr(string=pr_data)
try:
process_ast, = ast.processes
except ValueError:
LOG.error('No statechart to render')
return
diamond = 0
for state, inputs in process_ast.mapping.viewitems():
# create a new node for each state
......@@ -1214,7 +1229,7 @@ class SDL_View(QtGui.QGraphicsView, object):
self.scale(1.1, 1.1)
self.setTransformationAnchor(QtGui.QGraphicsView.AnchorViewCenter)
else:
return(super(SDL_View, self).wheelEvent(wheelEvent))
return super(SDL_View, self).wheelEvent(wheelEvent)
# pylint: disable=C0103
def mousePressEvent(self, evt):
......@@ -1384,12 +1399,23 @@ class SDL_View(QtGui.QGraphicsView, object):
except ValueError:
LOG.error('Cannot load more than one process at a time')
return
try:
syst, = ast.systems
block, = syst.blocks
if block.processes[0].referenced:
LOG.debug('Process is referenced, fixing')
block.processes = [process]
except ValueError:
# No System/Block hierarchy, creating single block
block = ogAST.Block()
block.processes = [process]
LOG.debug('Parsing complete. Summary, found ' + str(len(warnings)) +
' warnings and ' + str(len(errors)) + ' errors')
self.log_errors(errors, warnings)
self.scene().render_process(process)
self.wrapping_window.setWindowTitle('process ' +
self.scene().process_name + '[*]')
self.scene().render_everything(block)
self.toolbar.update_menu(self.scene())
self.wrapping_window.setWindowTitle('block ' +
process.processName + '[*]')
self.refresh()
self.centerOn(self.sceneRect().topLeft())
self.scene().undo_stack.clear()
......@@ -1522,11 +1548,15 @@ class OG_MainWindow(QtGui.QMainWindow, object):
self.statechart_view = None
self.statechart_scene = None
self.vi_bar = Vi_bar()
# Docking areas
self.datatypes_view = None
self.datatypes_scene = None
self.asn1_area = None
def start(self, file_name):
''' Initializes all objects to start the application '''
# Create a graphic scene: the main canvas
self.scene = SDL_Scene(context='process')
self.scene = SDL_Scene(context='block')
# Find SDL_View widget
self.view = self.findChild(SDL_View, 'graphicsView')
self.view.setScene(self.scene)
......@@ -1605,7 +1635,7 @@ class OG_MainWindow(QtGui.QMainWindow, object):
statechart_dock.hide()
# Set up the dock area to display the ASN.1 Data model
asn1_dock = self.findChild(QtGui.QDockWidget, 'datatypes_dock' )
#asn1_dock = self.findChild(QtGui.QDockWidget, 'datatypes_dock')
self.datatypes_view = self.findChild(SDL_View, 'datatypes_view')
self.datatypes_scene = SDL_Scene(context='process')
self.datatypes_view.setScene(self.datatypes_scene)
......@@ -1659,7 +1689,7 @@ class OG_MainWindow(QtGui.QMainWindow, object):
# Match vi-like search and replace pattern (e.g. :%s,a,b,g)
search = re.compile(r':%s(.)(.*)\1(.*)\1(.)')
try:
_, pattern, new, ___ = search.match(command).groups()
_, pattern, new, _ = search.match(command).groups()
LOG.debug('Replacing {this} with {that}'
.format(this=pattern, that=new))
self.scene.search(pattern, replace_with=new)
......@@ -1786,12 +1816,12 @@ def opengeode():
ast, warnings, errors = ogParser.parse_pr(files=options.files)
except IOError:
LOG.error('Aborting due to parsing error (check input file)')
return(-1)
return -1
try:
process, = ast.processes
except ValueError:
LOG.error('Only one process at a time is supported')
return(-1)
return -1
LOG.info('Parsing complete. Summary, found ' +
str(len(warnings)) +
' warnings and ' +
......@@ -1815,7 +1845,7 @@ def opengeode():
LlvmGenerator.generate(process)
except (TypeError, ValueError, NameError) as err:
LOG.error(str(err))
print(str(traceback.format_exc()))
#print(str(traceback.format_exc()))
LOG.error('Code generation failed')
export_fmt = []
if options.png:
......@@ -1826,7 +1856,7 @@ def opengeode():
export_fmt.append('svg')
if export_fmt:
scene = SDL_Scene(context='process')
scene.render_process(process)
scene.render_everything(process)
# Update connections, placements:
scene.refresh()
for doc_fmt in export_fmt:
......@@ -1848,7 +1878,7 @@ def opengeode():
ui_file.close()
my_widget.start(options.files)
ret = app.exec_()
return(ret)
return ret
if __name__ == '__main__':
sys.exit(opengeode())
......@@ -11,6 +11,7 @@
<file>icons/procedurestart.png</file>
<file>icons/procedurestop.png</file>
<file>icons/procedure.png</file>
<file>icons/process.png</file>
<file>icons/start.png</file>
<file>icons/connect.png</file>
<file>icons/statestart.png</file>
......
......@@ -203,11 +203,11 @@ connection
process_definition
: PROCESS process_id number_of_instances? REFERENCED end
-> ^(PROCESS process_id number_of_instances? REFERENCED)
| PROCESS process_id number_of_instances? end
| cif? PROCESS process_id number_of_instances? end
(text_area | procedure | composite_state)*
processBody? ENDPROCESS process_id?
end
-> ^(PROCESS process_id number_of_instances?
-> ^(PROCESS cif? process_id number_of_instances?
text_area* procedure* composite_state* processBody?);
......@@ -1023,6 +1023,7 @@ symbolname
| OUTPUT
| STATE
| PROCEDURE
| PROCESS
| PROCEDURE_CALL
| STOP
| RETURN
......
This diff is collapsed.
This diff is collapsed.
......@@ -20,20 +20,23 @@
__all__ = ['Input', 'Output', 'State', 'Task', 'ProcedureCall', 'Label',
'Decision', 'DecisionAnswer', 'Join', 'Start', 'TextSymbol',
'Procedure', 'ProcedureStart', 'ProcedureStop', 'ASN1Viewer',
'StateStart']
'StateStart', 'Process']
from genericSymbols import(
HorizontalSymbol, VerticalSymbol, Connection, Comment)
import traceback
import logging
from itertools import chain
from collections import deque
from PySide.QtCore import Qt, QPoint, QRect, QRectF
from PySide.QtGui import(QPainterPath, QBrush, QColor, QPolygon,
QRadialGradient, QPainter, QPolygonF, QPen)
from genericSymbols import(
HorizontalSymbol, VerticalSymbol, Connection, Comment)
import ogParser
import ogAST
import traceback
import logging
LOG = logging.getLogger('sdlSymbols')
......@@ -955,7 +958,7 @@ class State(VerticalSymbol):
result.append('in ({});'.format(','.join(entry_points)))
if exit_points:
result.append('out ({});'.format(','.join(exit_points)))
result.extend(self.nested_scene.get_pr_string()[1:-1])
result.extend(self.nested_scene.get_pr_string())
result.append('ENDSUBSTRUCTURE;')
return '\n'.join(result)
......@@ -1000,8 +1003,93 @@ class State(VerticalSymbol):
return '\n'.join(result)
class Procedure(HorizontalSymbol):
''' Procedure declaration symbol '''
class Process(HorizontalSymbol):
''' Process symbol '''
_unique_followers = ['Comment']
_allow_nesting = True
common_name = 'process_definition'
needs_parent = False
# Define reserved keywords for the syntax highlighter
blackbold = SDL_BLACKBOLD
redbold = SDL_REDBOLD
completion_list = set()
is_singleton = True
def __init__(self, ast=None, subscene=None):
ast = ast or ogAST.Process()
super(Process, self).__init__(parent=None,
text=ast.processName,
x=ast.pos_x,
y=ast.pos_y,
hyperlink=ast.hyperlink)
self.set_shape(ast.width, ast.height)
self.setBrush(QBrush(QColor(255, 255, 202)))
self.parser = ogParser
if ast.comment:
Comment(parent=self, ast=ast.comment)
self.nested_scene = subscene
def set_shape(self, width, height):
''' Compute the polygon to fit in width, height '''
path = QPainterPath()
path.moveTo(7, 0)
path.lineTo(0, 7)
path.lineTo(0, height - 7)
path.lineTo(7, height)
path.lineTo(width - 7, height)
path.lineTo(width, height - 7)
path.lineTo(width, 7)
path.lineTo(width - 7, 0)
path.lineTo(7, 0)
self.setPath(path)
super(Process, self).set_shape(width, height)
def recursive_parser(self):
''' Return the full content of the process as PR string '''
pr_data = deque()
scene = self.nested_scene
if not scene:
return []
for item in chain(scene.texts, scene.procs, scene.start):
pr_data.append(repr(item))
for item in scene.floating_labels:
pr_data.append(item.parse_gr())
composite = set(scene.composite_states.keys())
for item in scene.states:
if item.is_composite():
try:
composite.remove(str(item).lower())
pr_data.appendleft(item.parse_composite_state())
except KeyError:
pass
pr_data.append(item.parse_gr())
return list(pr_data)
def parse_gr(self, recursive=True):
''' Generate PR for a process '''
comment = repr(self.comment) if self.comment else ';'
pos = self.scenePos()
result =['/* CIF PROCESS ({x}, {y}), ({w}, {h}) */\n'
'{hlink}'
'PROCESS {process}{comment}'.format(
process=str(self),
hlink=repr(self.text),
x=int(pos.x()), y=int(pos.y()),
w=int(self.boundingRect().width()),
h=int(self.boundingRect().height()), comment=comment)]
if recursive:
result.append('\n'.join(self.recursive_parser()))
result.append('ENDPROCESS {};'.format(str(self)))
return '\n'.join(result)
def __repr__(self):
''' Return the complete process content '''
return self.parse_gr(recursive=True)
class Procedure(Process):
''' Procedure declaration symbol - Very similar to Process '''
_unique_followers = ['Comment']
_allow_nesting = True
common_name = 'procedure'
......@@ -1010,10 +1098,11 @@ class Procedure(HorizontalSymbol):
blackbold = SDL_BLACKBOLD
redbold = SDL_REDBOLD
completion_list = set()
is_singleton = False
def __init__(self, ast=None, subscene=None):
ast = ast or ogAST.Procedure()
super(Procedure, self).__init__(parent=None,
super(Process, self).__init__(parent=None,
text=ast.inputString,
x=ast.pos_x, y=ast.pos_y, hyperlink=ast.hyperlink)
self.set_shape(ast.width, ast.height)
......@@ -1048,17 +1137,14 @@ class Procedure(HorizontalSymbol):
pos = self.scenePos()
result = ['/* CIF PROCEDURE ({x}, {y}), ({w}, {h}) */\n'
'{hlink}'
'PROCEDURE {state}{comment}'.format(
state=str(self),
'PROCEDURE {proc}{comment}'.format(
proc=str(self),
hlink=repr(self.text),
x=int(pos.x()), y=int(pos.y()),
w=int(self.boundingRect().width()),