Commit 2881a9a6 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Strong syntax check when saving

parent dca011c9
...@@ -170,6 +170,38 @@ ACTIONS = { ...@@ -170,6 +170,38 @@ ACTIONS = {
} }
def log_errors(window, errors, warnings, clearfirst=True):
''' Report Error and Warnings on the console and in the log window '''
if window and clearfirst:
window.clear()
for error in errors:
if type(error[0]) == list:
# should be fixed now, CHECKME - NO, NOT FULLY FIXED
# problem is in decision answers branches
error[0] = 'Internal error - ' + str(error[0])
LOG.error(error[0])
item = QtGui.QListWidgetItem(u'[ERROR] ' + error[0])
if len(error) == 3:
item.setData(Qt.UserRole, error[1])
#found = self.scene().symbol_near(QPoint(*error[1]), 1)
# Pyside bug: setData cannot store 'found' directly
#item.setData(Qt.UserRole + 1, id(found))
item.setData(Qt.UserRole + 1, error[2])
if window:
window.addItem(item)
for warning in warnings:
LOG.warning(warning[0])
item = QtGui.QListWidgetItem(u'[WARNING] ' + str(warning[0]))
if len(warning) == 3:
item.setData(Qt.UserRole, warning[1])
item.setData(Qt.UserRole + 1, warning[2])
if window:
window.addItem(item)
if not errors and not warnings and window:
window.addItem('No errors, no warnings!')
class Vi_bar(QtGui.QLineEdit, object): class Vi_bar(QtGui.QLineEdit, object):
''' Line editor for the Vi-like command mode ''' ''' Line editor for the Vi-like command mode '''
def __init__(self): def __init__(self):
...@@ -434,6 +466,17 @@ class SDL_Scene(QtGui.QGraphicsScene, object): ...@@ -434,6 +466,17 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
yield sub yield sub
@property
def path(self):
''' Get the path to the current scene as a list
e.g. ['BLOCK a', 'PROCESS b', ...]
'''
if not self.parent_scene:
return [self.name[0:-3]]
return self.parent_scene.path + [self.name[0:-3]]
def quit_scene(self): def quit_scene(self):
''' Called in case of scene switch (e.g. UP button) ''' ''' Called in case of scene switch (e.g. UP button) '''
pass pass
...@@ -508,7 +551,8 @@ class SDL_Scene(QtGui.QGraphicsScene, object): ...@@ -508,7 +551,8 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
# Ignore nested state scenes that already exist # Ignore nested state scenes that already exist
continue continue
subscene = \ subscene = \
self.create_subscene(each.__class__.__name__.lower()) self.create_subscene(each.__class__.__name__.lower(),
dest_scene)
already_created.append(each.nested_scene) already_created.append(each.nested_scene)
subscene.name = unicode(each) subscene.name = unicode(each)
LOG.debug('Created scene: {}'.format(subscene.name)) LOG.debug('Created scene: {}'.format(subscene.name))
...@@ -654,13 +698,29 @@ class SDL_Scene(QtGui.QGraphicsScene, object): ...@@ -654,13 +698,29 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
def global_syntax_check(self): def global_syntax_check(self):
''' Parse each visible symbol in the current scene and its children ''' Parse each visible symbol in the current scene and its children
and check syntax using the parser ''' and check syntax using the parser '''
errors = [] res = True
for each in self.visible_symb: for each in self.visible_symb:
err = self.syntax_errors(each) errors = self.syntax_errors(each)
errors.extend(err) if errors:
if errors: res = False
return False for err in errors:
return True split = err.split()
if split[0] == 'line' and len(split) > 1:
line_col = split[1].split(':')
if len(line_col) == 2:
# get line and col. line must be decremented because
# line 1 is the CIF comment which is not visible
line_nb, col = line_col
line_nb = int(line_nb) - 1
split[1] = '{}:{}'.format(line_nb, col)
fmt = [[' '.join(split), [each.pos_x, each.pos_y], self.path]]
log_errors(self.messages_window, fmt, [], clearfirst=False)
for each in self.all_nested_scenes:
err = each.global_syntax_check()
if not err:
res = False
return res
def update_completion_list(self, symbol): def update_completion_list(self, symbol):
...@@ -1116,11 +1176,11 @@ class SDL_Scene(QtGui.QGraphicsScene, object): ...@@ -1116,11 +1176,11 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
code.interact('type your command:', local=locals()) code.interact('type your command:', local=locals())
def create_subscene(self, context): def create_subscene(self, context, parent=None):
''' Create a new SDL scene, e.g. for nested symbols ''' ''' Create a new SDL scene, e.g. for nested symbols '''
subscene = SDL_Scene(context=context) subscene = SDL_Scene(context=context)
subscene.messages_window = self.messages_window subscene.messages_window = self.messages_window
subscene.parent_scene = self subscene.parent_scene = parent
return subscene return subscene
...@@ -1144,7 +1204,7 @@ class SDL_Scene(QtGui.QGraphicsScene, object): ...@@ -1144,7 +1204,7 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
elif item_type in (Procedure, State, Process): elif item_type in (Procedure, State, Process):
# Create a sub-scene for clickable symbols # Create a sub-scene for clickable symbols
item.nested_scene = \ item.nested_scene = \
self.create_subscene(item_type.__name__.lower()) self.create_subscene(item_type.__name__.lower(), self)
self.clearSelection() self.clearSelection()
self.clear_focus() self.clear_focus()
...@@ -1430,7 +1490,7 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1430,7 +1490,7 @@ class SDL_View(QtGui.QGraphicsView, object):
ctx = unicode(item.__class__.__name__.lower()) ctx = unicode(item.__class__.__name__.lower())
if not isinstance(item.nested_scene, SDL_Scene): if not isinstance(item.nested_scene, SDL_Scene):
item.nested_scene = \ item.nested_scene = \
self.scene().create_subscene(context=ctx) self.scene().create_subscene(ctx, self.scene())
self.go_down(item.nested_scene, self.go_down(item.nested_scene,
name=ctx + u' ' + unicode(item)) name=ctx + u' ' + unicode(item))
else: else:
...@@ -1493,7 +1553,8 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1493,7 +1553,8 @@ class SDL_View(QtGui.QGraphicsView, object):
return False return False
# check syntax and raise a big warning before saving # check syntax and raise a big warning before saving
if not scene.global_syntax_check(): self.messages_window.clear()
if not autosave and not scene.global_syntax_check():
LOG.error('Syntax errors must be fixed NOW ' LOG.error('Syntax errors must be fixed NOW '
'or you may not be able to reload the model') 'or you may not be able to reload the model')
msg_box = QtGui.QMessageBox(self) msg_box = QtGui.QMessageBox(self)
...@@ -1591,14 +1652,14 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1591,14 +1652,14 @@ class SDL_View(QtGui.QGraphicsView, object):
block.processes = [process] block.processes = [process]
LOG.debug('Parsing complete. Summary, found ' + str(len(warnings)) + LOG.debug('Parsing complete. Summary, found ' + str(len(warnings)) +
' warnings and ' + str(len(errors)) + ' errors') ' warnings and ' + str(len(errors)) + ' errors')
self.log_errors(errors, warnings) log_errors(self.messages_window, errors, warnings)
try: try:
self.scene().render_everything(block) self.scene().render_everything(block)
except AttributeError: except AttributeError:
pass pass
self.toolbar.update_menu(self.scene()) self.toolbar.update_menu(self.scene())
self.wrapping_window.setWindowTitle('block ' + self.scene().name = 'block {}[*]'.format(process.processName)
process.processName + '[*]') self.wrapping_window.setWindowTitle(self.scene().name)
self.refresh() self.refresh()
self.centerOn(self.sceneRect().topLeft()) self.centerOn(self.sceneRect().topLeft())
self.scene().undo_stack.clear() self.scene().undo_stack.clear()
...@@ -1668,37 +1729,6 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1668,37 +1729,6 @@ class SDL_View(QtGui.QGraphicsView, object):
return True return True
def log_errors(self, errors, warnings):
''' Report Error and Warnings on the console and in the log window '''
if self.messages_window:
self.messages_window.clear()
for error in errors:
if type(error[0]) == list:
# should be fixed now, CHECKME - NO, NOT FULLY FIXED
# problem is in decision answers branches
error[0] = 'Internal error - ' + str(error[0])
LOG.error(error[0])
item = QtGui.QListWidgetItem(u'[ERROR] ' + error[0])
if len(error) == 3:
item.setData(Qt.UserRole, error[1])
#found = self.scene().symbol_near(QPoint(*error[1]), 1)
# Pyside bug: setData cannot store 'found' directly
#item.setData(Qt.UserRole + 1, id(found))
item.setData(Qt.UserRole + 1, error[2])
if self.messages_window:
self.messages_window.addItem(item)
for warning in warnings:
LOG.warning(warning[0])
item = QtGui.QListWidgetItem(u'[WARNING] ' + str(warning[0]))
if len(warning) == 3:
item.setData(Qt.UserRole, warning[1])
item.setData(Qt.UserRole + 1, warning[2])
#found = self.scene().symbol_near(QPoint(*warning[1]), 1)
if self.messages_window:
self.messages_window.addItem(item)
if not errors and not warnings and self.messages_window:
self.messages_window.addItem('No errors, no warnings!')
def check_model(self): def check_model(self):
''' Parse the model and check for warnings and errors ''' ''' Parse the model and check for warnings and errors '''
# If the current scene is a nested one, save the top parent # If the current scene is a nested one, save the top parent
...@@ -1707,6 +1737,13 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1707,6 +1737,13 @@ class SDL_View(QtGui.QGraphicsView, object):
else: else:
scene = self.scene() scene = self.scene()
self.messages_window.clear()
self.messages_window.addItem("Checking syntax")
if not scene.global_syntax_check():
self.messages_window.addItem("Aborted. Fix syntax errors first")
return
self.messages_window.addItem("Checking semantics")
if scene.context not in ('process', 'state', 'procedure', 'block'): if scene.context not in ('process', 'state', 'procedure', 'block'):
# check can only be done on SDL diagrams # check can only be done on SDL diagrams
return return
...@@ -1716,7 +1753,8 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1716,7 +1753,8 @@ class SDL_View(QtGui.QGraphicsView, object):
if pr_data: if pr_data:
ast, warnings, errors = ogParser.parse_pr(files=self.readonly_pr, ast, warnings, errors = ogParser.parse_pr(files=self.readonly_pr,
string=pr_data) string=pr_data)
self.log_errors(errors, warnings) log_errors(self.messages_window, errors, warnings,
clearfirst=False)
self.update_asn1_dock.emit(ast) self.update_asn1_dock.emit(ast)
def show_item(self, item): def show_item(self, item):
...@@ -1737,7 +1775,7 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1737,7 +1775,7 @@ class SDL_View(QtGui.QGraphicsView, object):
for each in path: for each in path:
kind, name = each.split() kind, name = each.split()
name = unicode(name).lower() name = unicode(name).lower()
if kind == 'PROCESS': if kind.lower() == 'process':
for process in self.scene().processes: for process in self.scene().processes:
if unicode(process).lower() == name: if unicode(process).lower() == name:
self.go_down(process.nested_scene, self.go_down(process.nested_scene,
...@@ -1745,7 +1783,7 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1745,7 +1783,7 @@ class SDL_View(QtGui.QGraphicsView, object):
break break
else: else:
LOG.error('Process {} not found'.format(name)) LOG.error('Process {} not found'.format(name))
elif kind == 'STATE': elif kind.lower() == 'state':
for state in self.scene().states: for state in self.scene().states:
if unicode(state).lower() == name: if unicode(state).lower() == name:
self.go_down(state.nested_scene, self.go_down(state.nested_scene,
...@@ -1753,7 +1791,7 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1753,7 +1791,7 @@ class SDL_View(QtGui.QGraphicsView, object):
break break
else: else:
LOG.error('Composite state {} not found'.format(name)) LOG.error('Composite state {} not found'.format(name))
elif kind == 'PROCEDURE': elif kind.lower() == 'procedure':
for proc in self.scene().procedures: for proc in self.scene().procedures:
if unicode(proc).lower() == name: if unicode(proc).lower() == name:
self.go_down(proc.nested_scene, self.go_down(proc.nested_scene,
...@@ -1786,7 +1824,7 @@ class SDL_View(QtGui.QGraphicsView, object): ...@@ -1786,7 +1824,7 @@ class SDL_View(QtGui.QGraphicsView, object):
ast, warnings, errors = ogParser.parse_pr(files=self.readonly_pr, ast, warnings, errors = ogParser.parse_pr(files=self.readonly_pr,
string=pr_data) string=pr_data)
process, = ast.processes process, = ast.processes
self.log_errors(errors, warnings) log_errors(self.messages_window, errors, warnings)
if len(errors) > 0: if len(errors) > 0:
self.messages_window.addItem( self.messages_window.addItem(
'Aborting: too many errors to generate code') 'Aborting: too many errors to generate code')
...@@ -2221,7 +2259,7 @@ def export(ast, options): ...@@ -2221,7 +2259,7 @@ def export(ast, options):
.format(ext=doc_fmt, name=name)) .format(ext=doc_fmt, name=name))
diagram.export_img(name, doc_format=doc_fmt, split=options.split) diagram.export_img(name, doc_format=doc_fmt, split=options.split)
if diagram.context == 'block' and graphviz: if diagram.context == 'block' and graphviz:
# Also save the statechart viewa of the current scene # Also save the statechart view of the current scene
LOG.info('Saving statechart sc_{}.png'.format(process.processName)) LOG.info('Saving statechart sc_{}.png'.format(process.processName))
sc_scene = SDL_Scene(context='statechart') sc_scene = SDL_Scene(context='statechart')
graph = diagram.sdl_to_statechart() graph = diagram.sdl_to_statechart()
......
Supports Markdown
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