Skip to content

Commit

Permalink
Sequence diagram interpreter: recursive calls. #4.
Browse files Browse the repository at this point in the history
  • Loading branch information
pylover committed Jun 20, 2021
1 parent aa05499 commit 8c95f80
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 16 deletions.
73 changes: 63 additions & 10 deletions dial/sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,53 @@ def __init__(self, name):
self.name = name


class Call(Visible):
def __init__(self, caller, callee):
class Call(list, Visible):
def __init__(self, caller, callee, children=None):
self.caller = caller
self.callee = callee
if children:
super(Call, self).__init__(children)

super(list, self).__init__()

def __ne__(self, other):
if isinstance(other, Call):
if len(self) != len(other):
return True

for i, c in enumerate(self):
if c != other[i]:
return True

return self.caller != other.caller or \
self.callee != other.callee

return super().__ne__(other)

def __eq__(self, other):
if isinstance(other, Call):
return self.caller == other.caller and \
self.callee == other.callee
return not self.__ne__(other)

return super().__eq__(other)

def __repr__(self):
result = f'{self.caller} -> {self.callee}'
if self:
result += ':\n'
for c in self:
r = repr(c)
for l in r.splitlines():
result += ' ' + l + '\n'

return result


class SequenceDiagram(list, Visible, Interpreter):
def __init__(self, tokenizer, name):
super(Visible, self).__init__(tokenizer)
self.name = name
self.modules = {}
self.callerstack = []
self.callstack = []

def _ensuremodule(self, module):
Expand All @@ -38,17 +69,34 @@ def _simplecall(self, caller, callee):

def _indent(self, caller):
self._ensuremodule(caller)
self.callstack.append(caller)
self.callerstack.append(caller)
return 'caller'

def _callercallee(self, callee):
def _dedent(self):
self.callerstack.pop()
if self.callstack:
self.callstack.pop()
return 'caller' if self.callerstack else 'root'

def _newcall(self, callee):
self._ensuremodule(callee)
self.append(Call(self.callstack[-1], callee))
call = Call(self.callerstack[-1], callee)

if self.callstack:
self.callstack[-1].append(call)
else:
self.append(call)

return call

def _callercallee(self, callee):
self._newcall(callee)
return 'caller'

def _dedent(self):
self.callstack.pop()
return 'caller' if self.callstack else 'root'
def _callercalleecaller(self, callee):
call = self._newcall(callee)
self.callstack.append(call)
return self._indent(callee)

states = {
'root': {
Expand All @@ -68,6 +116,11 @@ def _dedent(self):
'caller': {
NAME: {
NEWLINE: _callercallee,
COLON: {
NEWLINE: {
INDENT: _callercalleecaller,
}
}
},
DEDENT: _dedent,
}
Expand Down
32 changes: 32 additions & 0 deletions tests/test_call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from dial.sequence import Call


def test_call():
assert repr(Call('foo', 'bar')) == 'foo -> bar'
bar = Call('bar', 'baz', [
Call('baz', 'quux', [
Call('quux', 'fred')
]),
Call('baz', 'thud')
])

assert repr(bar) == '''\
bar -> baz:
baz -> quux:
quux -> fred
baz -> thud
'''

assert bar != Call('bar', 'baz', [
Call('bad', 'quux', [
Call('quux', 'fred')
]),
Call('baz', 'thud')
])

assert bar != Call('bar', 'baz', [
Call('baz', 'thud')
])

assert bar != []
assert not bar == []
29 changes: 23 additions & 6 deletions tests/test_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,35 @@ def test_interpreter_sequencediagram_parse():
d = SequenceDiagram(Tokenizer(), 'foo')

d.parse('''
foo: bar
bar:
baz
qux
foo: bar
bar:
alfred
baz:
quux:
fred
thud
qux:
bar
baz
foo: bar
''')
assert 'foo' in d.modules
assert 'bar' in d.modules
assert 'baz' in d.modules
assert 'qux' in d.modules
assert d[0] == Call('foo', 'bar')
assert d[1] == Call('bar', 'baz')
assert d[2] == Call('bar', 'qux')
assert d[1] == Call('bar', 'alfred')
assert d[2] == Call('bar', 'baz', [
Call('baz', 'quux', [
Call('quux', 'fred')
]),
Call('baz', 'thud')
])
assert d[3] == Call('bar', 'qux', [
Call('qux', 'bar'),
Call('qux', 'baz')
])
assert d[4] == Call('foo', 'bar')


def test_interpreter_sequencediagram_parseline():
Expand Down

0 comments on commit 8c95f80

Please sign in to comment.