Commits (2)
...@@ -124,6 +124,10 @@ The background pattern was downloaded from www.subtlepatterns.com ...@@ -124,6 +124,10 @@ The background pattern was downloaded from www.subtlepatterns.com
Changelog Changelog
========= =========
**3.5.5 (04/2021)**
- Fix support for single input/output expressions (with no message name)
- Fix graphical location of errors for undefined states
**3.5.4 (04/2021)** **3.5.4 (04/2021)**
- Fix code generation when no signals are defined (only exported procedures) - Fix code generation when no signals are defined (only exported procedures)
- Add renames clause (aliases) for input/output expressions - Add renames clause (aliases) for input/output expressions
......
...@@ -1640,6 +1640,8 @@ def io_expression(root, context): ...@@ -1640,6 +1640,8 @@ def io_expression(root, context):
regular form based on the known structure of events: Observable_Event regular form based on the known structure of events: Observable_Event
type that is generated by kazoo. type that is generated by kazoo.
''' '''
errors, warnings = [], []
inputString = get_input_string(root) inputString = get_input_string(root)
event_kind = "{kind}_event" event_kind = "{kind}_event"
target_option = " and then event.{kind}_event.{target} = {function}" target_option = " and then event.{kind}_event.{target} = {function}"
...@@ -1658,6 +1660,7 @@ def io_expression(root, context): ...@@ -1658,6 +1660,7 @@ def io_expression(root, context):
string += event_kind.format(kind=kind) string += event_kind.format(kind=kind)
param_name = "" param_name = ""
from_f, to_f = "", ""
for child in root.getChildren(): for child in root.getChildren():
if child.type == lexer.ID: if child.type == lexer.ID:
...@@ -1687,7 +1690,14 @@ def io_expression(root, context): ...@@ -1687,7 +1690,14 @@ def io_expression(root, context):
func = from_f if direction == "out" else to_f func = from_f if direction == "out" else to_f
if msg: if msg and not func:
# When input or output specify a message there must be a source or destination
if direction == "out":
errors.append(f"FROM clause is missing in output expression '{inputString}'")
else:
errors.append(f"TO clause is missing in input expression '{inputString}'")
elif msg:
string += msg_name.format(kind=kind, string += msg_name.format(kind=kind,
function=func, function=func,
direction=direction, direction=direction,
...@@ -1698,7 +1708,9 @@ def io_expression(root, context): ...@@ -1698,7 +1708,9 @@ def io_expression(root, context):
tree = new_root.tree tree = new_root.tree
tree.token_stream = parser.getTokenStream() tree.token_stream = parser.getTokenStream()
expr, errors, warnings = expression(tree, context) expr, errs, warns = expression(tree, context)
errors.extend(errs)
warnings.extend(warns)
expr.inputString = inputString expr.inputString = inputString
# Now address the optional parameter: if set, we will create an implicit # Now address the optional parameter: if set, we will create an implicit
...@@ -3061,14 +3073,17 @@ def composite_state(root, parent=None, context=None): ...@@ -3061,14 +3073,17 @@ def composite_state(root, parent=None, context=None):
warnings.extend(warn) warnings.extend(warn)
comp.content.states.append(newstate) comp.content.states.append(newstate)
# Post-processing: check that all NEXTSTATEs have a corresponding STATE # Post-processing: check that all NEXTSTATEs have a corresponding STATE
for ns in [t.inputString.lower() for t in comp.terminators for t in comp.terminators:
if t.kind == 'next_state']: if t.kind != "next_state":
if not ns in [s.lower() for s in continue
comp.mapping.keys()] + ['-']: ns = t.inputString.lower()
#for ns in [t.inputString.lower() for t in comp.terminators
# if t.kind == 'next_state']:
if not ns in [s.lower() for s in comp.mapping.keys()] + ['-']:
errors.append(['In composite state "{}": missing definition ' errors.append(['In composite state "{}": missing definition '
'of substate "{}"' 'of substate "{}"'
.format(comp.statename, ns.upper()), .format(comp.statename, ns.upper()),
[0, 0], []]) [t.pos_x or 0, t.pos_y or 0], []])
for each in chain(errors, warnings): for each in chain(errors, warnings):
each[2].insert(0, 'STATE {}'.format(comp.statename)) each[2].insert(0, 'STATE {}'.format(comp.statename))
return comp, errors, warnings return comp, errors, warnings
......
...@@ -141,7 +141,7 @@ except ImportError: ...@@ -141,7 +141,7 @@ except ImportError:
__all__ = ['opengeode', 'SDL_Scene', 'SDL_View', 'parse'] __all__ = ['opengeode', 'SDL_Scene', 'SDL_View', 'parse']
__version__ = '3.5.4' __version__ = '3.5.5'
if hasattr(sys, 'frozen'): if hasattr(sys, 'frozen'):
# Detect if we are running on Windows (py2exe-generated) # Detect if we are running on Windows (py2exe-generated)
...@@ -2379,8 +2379,11 @@ clean: ...@@ -2379,8 +2379,11 @@ clean:
continue continue
pos = QPoint(*coord) pos = QPoint(*coord)
symbol = self.scene().symbol_near(pos=pos, dist=1) symbol = self.scene().symbol_near(pos=pos, dist=1)
G_ERRORS.append(symbol) if symbol is not None:
line.setData(Qt.UserRole + 2, len(G_ERRORS) - 1) G_ERRORS.append(symbol)
line.setData(Qt.UserRole + 2, len(G_ERRORS) - 1)
else:
print("No symbol at coord", coord, "in scene", path)
_ = self.go_to_scene_path(current_scene) _ = self.go_to_scene_path(current_scene)
......