Skip to content

Commit

Permalink
Sequence diagram: @note. #4
Browse files Browse the repository at this point in the history
  • Loading branch information
pylover committed Jun 25, 2021
1 parent ad16bd3 commit d63298f
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 87 deletions.
18 changes: 9 additions & 9 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
+ bar -> baz: (a, b) func(a, b)
+ bar -> qux: func(a)
+ # This is comment
- @over:
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- tempor incididunt ut labore et dolore.
- @over bar: note
- @over bar~qux: note
- @over bar~: note
- @over ~bar: note
- @left of bar: note
- @right of qux: note
+ @over:
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore.
+ @over bar: note
+ @over bar~qux: note
+ @over bar~: note
+ @over ~bar: note
+ @left of bar: note
+ @right of qux: note
+ for i in list
+ qux -> quux: func(a)
+ if condition
Expand Down
14 changes: 9 additions & 5 deletions dial/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,22 @@ def __call__(self, interpreter, token, *args):


class Consume(Goto):
capture = [
limit = [
NAME,
EVERYTHING,
MULTILINE,
]

def __init__(self, callback=None, nextstate=None):
def __init__(self, callback=None, nextstate=None, alltokens=False):
if alltokens:
self.limit = None

super().__init__(callback=callback, nextstate=nextstate)

def __call__(self, interpreter, token, *args):
args = tuple(
i.string for i in interpreter.tokenstack if i.type in self.capture
i.string for i in interpreter.tokenstack if
not self.limit or i.type in self.limit
)
interpreter.tokenstack.clear()
return super().__call__(interpreter, token, *args)
Expand All @@ -106,8 +110,8 @@ def __call__(self, interpreter, token):


class FinalConsume(Consume):
def __init__(self, callback):
super().__init__(callback=callback, nextstate=None)
def __init__(self, callback, **kw):
super().__init__(callback=callback, nextstate=None, **kw)

def __call__(self, interpreter, token):
interpreter.more = False
Expand Down
168 changes: 107 additions & 61 deletions dial/sequence.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import abc

from .visible import Visible
from .interpreter import Interpreter, Consume, FinalConsume, New, Ignore, \
Goto, Switch
Expand All @@ -12,25 +10,108 @@ def __init__(self, title, type_='module'):
self.type = type_


class Item(Visible, Interpreter, metaclass=abc.ABCMeta):
class Item(Visible, Interpreter):
type_ = None
args = None
text = None
multiline = None

def __init__(self, tokenizer):
super().__init__(tokenizer, 'start')

@property
@abc.abstractmethod
def short_repr(self):
raise NotImplementedError()

def _complete(self, text=None):
def _complete(self, type_, *args, text=None, multiline=False):
self.type_ = type_
self.args = args
self.text = text.strip() if text else None
self.multiline = multiline

def _finish_multiline(self, type_, *args):
return self._finish(type_, *args, multiline=True)

def _finish(self, type_, *args, **kw):
args = list(args)
nargs = []
while args:
a = args.pop(0)
if a == ':':
break

nargs.append(a)

if args:
text = args[0]
else:
text = None
return self._complete(type_, *nargs, text=text, **kw)

@property
def _short_repr(self):
return self.type_

def __repr__(self):
result = self._short_repr

if self.text:
result += f': {self.text}'
result += ': '

if self.multiline:
result += '|\n'
for l in self.text.splitlines():
result += f' {l}\n'
else:
result += f'{self.text}'

return result

statemap = {
'start': {
NAME: Goto(nextstate='name'),
},
'name': {
NAME: Goto(nextstate='name'),
TILDA: Goto(nextstate='name'),
NEWLINE: FinalConsume(_finish, alltokens=True),
COLON: Goto(nextstate=':'),
},
':': {
MULTILINE: FinalConsume(_finish_multiline, alltokens=True),
EVERYTHING: {
NEWLINE: FinalConsume(_finish, alltokens=True)
}
},
}


class Note(Item):
multiline = False

@property
def position(self):
return self.type_

@property
def module(self):
return ' '.join(self.args)

def _complete(self, type_, *args, **kw):
args = list(args)

if args and args[0] == 'of':
args.pop(0)

super()._complete(type_, *args, **kw)

@property
def _short_repr(self):
pos = self.position

result = f'@{pos}'

if self.position != 'over':
result += ' of'

if self.module:
result += f' {self.module}'

return result

Expand Down Expand Up @@ -60,7 +141,7 @@ def _short_repr(self):
def _complete(self, caller, callee, text=None):
self.caller = caller
self.callee = callee
super()._complete(text)
super()._complete('call', text=text)

statemap = {
'start': {NAME: {RARROW: {NAME: Goto(nextstate='name -> name')}}},
Expand All @@ -76,55 +157,11 @@ def _complete(self, caller, callee, text=None):


class Loop(Container):
type_ = None

@property
def _short_repr(self):
return self.type_

def _complete(self, type_, text=None):
self.type_ = type_
super()._complete(text)

statemap = {
'start': {
NAME: Goto(nextstate='name'),
},
'name': {
NAME: Goto(nextstate='name'),
NEWLINE: FinalConsume(_complete),
COLON: Goto(nextstate=':'),
},
':': {EVERYTHING: {
NEWLINE: FinalConsume(_complete)
}}
}
pass


class Condition(Container):
type_ = None

@property
def _short_repr(self):
return self.type_

def _complete(self, type_, text=None):
self.type_ = type_
super()._complete(text)

statemap = {
'start': {
NAME: Goto(nextstate='name'),
},
'name': {
NAME: Goto(nextstate='name'),
NEWLINE: FinalConsume(_complete),
COLON: Goto(nextstate=':'),
},
':': {EVERYTHING: {
NEWLINE: FinalConsume(_complete)
}}
}
pass


class SequenceDiagram(Visible, Interpreter, list):
Expand Down Expand Up @@ -169,7 +206,6 @@ def current(self):
return self

def _indent(self):
self.tokenstack.pop(0)
if len(self.current):
self._callstack.append(self.current[-1])

Expand All @@ -182,6 +218,11 @@ def _new_call(self, call):
self._ensuremodule(call.callee)
self.current.append(call)

def _new_note(self, note):
if note.module:
self._ensuremodule(note.module)
self.current.append(note)

def _new_loop(self, loop):
self.current.append(loop)

Expand Down Expand Up @@ -217,14 +258,16 @@ def _module_attr(self, module, attr, value):
'start': {
HASH: {EVERYTHING: {NEWLINE: Ignore(nextstate='start')}},
NEWLINE: Ignore(nextstate='start'),
INDENT: Goto(callback=_indent, nextstate='indent'),
INDENT: Ignore(callback=_indent, nextstate='indent'),
DEDENT: Ignore(callback=_dedent, nextstate='start'),
EOF: Ignore(nextstate='start'),
NAME: Switch(default=Goto(nextstate='name'), **_keywords)
NAME: Switch(default=Goto(nextstate='name'), **_keywords),
AT: Ignore(nextstate='@'),
},
'indent': {
HASH: {EVERYTHING: {NEWLINE: Ignore(nextstate='start')}},
NAME: Switch(default=Goto(nextstate=' name'), **_keywords)
NAME: Switch(default=Goto(nextstate=' name'), **_keywords),
AT: Ignore(nextstate='@'),
},
'name': {
RARROW: New(Call, callback=_new_call, nextstate='start'),
Expand All @@ -240,4 +283,7 @@ def _module_attr(self, module, attr, value):
'mod.attr:': {
EVERYTHING: {NEWLINE: Consume(_module_attr, nextstate='start')}
},
'@': {
NAME: New(Note, callback=_new_note, nextstate='start'),
}
}
3 changes: 2 additions & 1 deletion dial/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
HASH = 15
MULTILINE = 16
EVERYTHING = 17

TILDA = 18

TOKEN_NAMES = {
value: name for name, value in globals().items()
Expand All @@ -45,6 +45,7 @@
('/', SLASH),
('|', PIPE),
('#', HASH),
('~', TILDA),
]
EXACT_TOKENS_DICT = {value: string for string, value in EXACT_TOKENS}

Expand Down
9 changes: 6 additions & 3 deletions dial/tokenizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,12 @@ def _tokenizeline(self, line):
)

if token in (':', '#'):
yield from self._everything(start + 1, line)
self.newline = True
return
if line[end] == ' ':
end += 1
if line[end] != '|':
yield from self._everything(start + 1, line)
self.newline = True
return

def tokenizeline(self, line):
for token in self._tokenizeline(line):
Expand Down
28 changes: 20 additions & 8 deletions tests/test_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,26 @@
from dial.interpreter import BadSyntax, BadAttribute


# def test_sequence_note():
# d = SequenceDiagram(Tokenizer())
# s = '''# Sequence
# title: note
# @note: Foo Bar baz
# '''
# d.parse(s)
# assert repr(d) == s[:-1]
def test_sequence_note():
d = SequenceDiagram(Tokenizer())
s = '''# Sequence
title: note
@over: |
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore.
@over ~: Foo Bar baz
@over foo ~ bar: Foo Bar baz
@over ~ foo: Foo Bar baz
@over foo ~: Foo Bar baz
@over: Foo Bar baz
@over foo: Foo Bar baz
@right of qux: note
@left of bar: note
'''
d.parse(s)
assert repr(d) == s[:-1]


def test_sequence_condition():
Expand Down

0 comments on commit d63298f

Please sign in to comment.