Franck Pommereau

improved parsing, added meta (+aspic) parsers

1 -import argparse, io, pkgutil, ast, types, importlib 1 +import argparse, io, pkgutil, ast, importlib
2 import zinc, zinc.compil, zinc.io.zn 2 import zinc, zinc.compil, zinc.io.zn
3 3
4 class ListBackends (argparse.Action) : 4 class ListBackends (argparse.Action) :
......
1 # coding: utf-8 1 # coding: utf-8
2 2
3 import io, re 3 import io, re
4 +from .. import ParseError
4 5
5 ## 6 ##
6 ## insert INDENT/DEDENT 7 ## insert INDENT/DEDENT
...@@ -30,3 +31,35 @@ def indedent (text, indent="↦", dedent="↤") : ...@@ -30,3 +31,35 @@ def indedent (text, indent="↦", dedent="↤") :
30 out.write(dedent) 31 out.write(dedent)
31 stack.pop() 32 stack.pop()
32 return out.getvalue() 33 return out.getvalue()
34 +
35 +##
36 +## base parser
37 +##
38 +
39 +_errre = re.compile(r"^.*?error at line ([0-9]+), col ([0-9]+):[ \t]*"
40 + "((.|\n)*)$", re.I|re.A)
41 +
42 +class BaseParser (object) :
43 + def init (self, parser) :
44 + pass
45 + def parse (self, source, path) :
46 + parser = self.__parser__(indedent(source))
47 + self.init(parser)
48 + try :
49 + do_parse = getattr(parser, parser.__default__, "INPUT")
50 + result = do_parse()
51 + if result is parser.NoMatch or parser.p_peek() is not None:
52 + parser.p_raise()
53 + return result
54 + except parser.ParserError as err :
55 + self._raise(err, path)
56 + def _raise (self, error, path=None) :
57 + message = str(error)
58 + match = _errre.match(message)
59 + if match :
60 + raise ParseError(match.group(3),
61 + lno=int(match.group(1)),
62 + cno=int(match.group(2)),
63 + path=path)
64 + else :
65 + raise ParseError(message, path=path)
......
1 +from . import metaparse, BaseParser
2 +
3 +class Parser (BaseParser) :
4 + class __parser__ (metaparse.MetaParser) :
5 + __compound__ = [["if", "*elif", "?else"],
6 + ["choose", "+either"],
7 + ["parallel", "+besides"],
8 + ["race", "+against"],
9 + ["retry"],
10 + ["negate"],
11 + ["task"]]
12 +
13 +def parse (source) :
14 + if isinstance(source, str) :
15 + return Parser().parse(source, "<string>")
16 + else :
17 + return Parser().parse(source.read(), getattr(source, "name", "<string>"))
1 +from . import BaseParser
2 +from . import metaparse
3 +
4 +class Parser (BaseParser) :
5 + def __init__ (self, spec) :
6 + class MP (metaparse.MetaParser) :
7 + __compound__ = spec
8 + self.__parser__ = MP
9 +
10 +def parse (source, spec) :
11 + if isinstance(source, str) :
12 + return Parser(spec).parse(source, "<string>")
13 + else :
14 + return Parser(spec).parse(source.read(), getattr(source, "name", "<string>"))
1 +# coding: utf-8
2 +
3 +import ast
4 +import fastidious
5 +
6 +class node (object) :
7 + def __init__ (self, tag, **children) :
8 + self.__dict__.update(tag=tag, **children)
9 + self._fields = list(children)
10 + def __setitem__ (self, key, val) :
11 + setattr(self, key, val)
12 + if key not in self._fields :
13 + self._fields.append(key)
14 + def __getitem__ (self, key) :
15 + return getattr(self, key)
16 + def __iter__ (self) :
17 + for name in self._fields :
18 + yield name, self[name]
19 + def __repr__ (self) :
20 + return "\n".join(self._repr())
21 + def _repr (self, indent=0) :
22 + TAB = " | " * indent
23 + if not self._fields :
24 + yield TAB + self.tag
25 + else :
26 + yield TAB + "%s :" % self.tag
27 + for name, child in self :
28 + if name.startswith("_") :
29 + pass
30 + elif isinstance(child, node) :
31 + for i, line in enumerate(child._repr(indent + 1)) :
32 + if i == 0 :
33 + yield TAB + " + %s = %s" % (name, line.lstrip(" |"))
34 + else :
35 + yield line
36 + elif isinstance(child, list) and child and isinstance(child[0], node) :
37 + for n, c in enumerate(child) :
38 + for i, line in enumerate(c._repr(1)) :
39 + if i == 0 :
40 + l = line.lstrip("| ")
41 + yield TAB + " + %s[%s] = %s" % (name, n, l)
42 + else :
43 + yield TAB + line
44 + else :
45 + yield TAB + " + %s = %r" % (name, child)
46 +
47 +class Nest (object) :
48 + def __init__ (self, blocks) :
49 + self.pred = {}
50 + self.succ = {}
51 + self.rep = {}
52 + self.opt = {}
53 + self.first = {}
54 + self.last = {}
55 + for spec in blocks :
56 + _spec = []
57 + first = True
58 + for name in spec :
59 + _name = name.lstrip("*?")
60 + self.rep[_name] = name.startswith("*") or name.startswith("+")
61 + self.opt[_name] = name.startswith("?") or name.startswith("*")
62 + self.succ[_name] = set()
63 + self.pred[_name] = set()
64 + _spec.append(_name)
65 + self.first[_name] = first
66 + first = first and self.opt[_name]
67 + last = True
68 + for name in reversed(_spec) :
69 + self.last[name] = last
70 + last = last and self.opt[name]
71 + for one, two in zip(_spec, _spec[1:]) :
72 + if self.rep[two] :
73 + self.pred[two].update({one, two} | self.pred[one])
74 + elif self.opt[two] :
75 + self.pred[two].update({one} | self.pred[one])
76 + else :
77 + self.pred[two].add(one)
78 + for two, preds in self.pred.items() :
79 + for one in preds :
80 + self.succ[one].add(two)
81 +
82 +class MetaParser (fastidious.Parser) :
83 + __compound__ = []
84 + __default__ = "INPUT"
85 + __grammar__ = r"""
86 + INPUT <- NL? :model {@model}
87 + NL <- ~"([\t ]*(#.*)?\n)+" {_drop}
88 + _ <- ~"[\t ]+"? {_drop}
89 + COLON <- _ ":" _ {_drop}
90 + COMMA <- _ "," _ {p_flatten}
91 + AT <- _ "@" _ {p_flatten}
92 + EQ <- _ "=" _ {p_flatten}
93 + LP <- _ "(" _ {p_flatten}
94 + RP <- _ ")" _ {p_flatten}
95 + LSB <- _ "[" _ {p_flatten}
96 + RSB <- _ "]" _ {p_flatten}
97 + LCB <- _ "{" _ {p_flatten}
98 + RCB <- _ "}" _ {p_flatten}
99 + INDENT <- _ "↦" NL? _ {_drop}
100 + DEDENT <- _ "↤" NL? _ {_drop}
101 + NUMBER <- _ ~"[+-]?[0-9]+" {_number}
102 + NAME <- _ ~"[a-z][a-z0-9_]*"i _ {p_flatten}
103 + atom <- :name / num:NUMBER / :code / :string {_first}
104 + name <- name:NAME {_name}
105 + code <- codec / codeb {_code}
106 + codec <- LCB (~"([^{}\\\\]|[{}])+" / codec)* RCB {p_flatten}
107 + codeb <- LSB (~"([^\\[\\]\\\\]|[\\[\\]])+" / codeb)* RSB {p_flatten}
108 + string <- _ ( ~"'{3}.*?'{3}"s
109 + / ~'"{3}.*?"{3}'s
110 + / ~"'([^'\\\\]|\\.)*'"
111 + / ~'"([^"\\\\]|\\.)*"' ) _ {_string}
112 + """
113 + def _drop (self, match) :
114 + return ""
115 + def _number (self, match) :
116 + return node("const", value=int(self.p_flatten(match)), type="int")
117 + def _name (self, match, name) :
118 + return node("const", value=name, type="name")
119 + def _code (self, match) :
120 + return node("const", value=self.p_flatten(match).strip()[1:-1], type="code")
121 + def _string (self, match) :
122 + return node("const", value=ast.literal_eval(self.p_flatten(match).strip()),
123 + type="str")
124 + def _tuple (self, match) :
125 + lst = []
126 + for m in match :
127 + if isinstance(m, list) :
128 + lst.extend(i[1] for i in m)
129 + else :
130 + lst.append(m)
131 + return tuple(lst)
132 + def _first (self, match, **args) :
133 + for k, v in args.items() :
134 + if v is not self.NoMatch :
135 + if isinstance(v, node) :
136 + return v
137 + else :
138 + return node(k, value=v)
139 + return self.NoMatch
140 + __grammar__ += r"""
141 + model <- stmt:stmt+
142 + stmt <- :call / :block {_first}
143 + call <- name:NAME :args NL
144 + args <- LP ( pos:posargs
145 + / kw:kwargs
146 + / pos:posargs COMMA kw:kwargs )? RP
147 + posargs <- atom (COMMA atom)* {_tuple}
148 + kwargs <- kwa (COMMA kwa) {_tuple}
149 + kwa <- name:NAME "EQ" :atom
150 + block <- deco:deco? name:NAME args:args? COLON NL INDENT stmt:stmt+ DEDENT
151 + deco <- AT name:NAME args:args? NL
152 + """
153 + def _glue (self, stmt) :
154 + n = self.nest
155 + s = []
156 + l = None
157 + for child in stmt :
158 + if child.tag == "call" :
159 + s.append(child)
160 + l = None
161 + elif n.pred[child.tag] :
162 + if l in n.pred[child.tag] :
163 + s[-1][child.tag] = child
164 + elif l and n.last[l] and n.first[child.tag] :
165 + l = child.tag
166 + s.append(child)
167 + elif l :
168 + self.p_parse_error("invalid block %r after %r" % (child.tag, l),
169 + child._pos)
170 + else :
171 + self.p_parse_error("unexpected block %r" % child.tag,
172 + child._pos)
173 + else :
174 + if l and not n.last[l] :
175 + self.p_parse_error("invalid block %r after %r" % (child.tag, l),
176 + child._pos)
177 + if not n.first[child.tag] :
178 + self.p_parse_error("unexpected block %r" % child.tag,
179 + child._pos)
180 + l = child.tag
181 + s.append(child)
182 + return s
183 + def on_model (self, match, stmt) :
184 + return node("model", body=self._glue(stmt), _pos=self.pos)
185 + def on_call (self, match, name, args) :
186 + return node("call", name=name, largs=args.l, kargs=args.k, _pos=self.pos)
187 + def on_args (self, match, pos=None, kw=None) :
188 + if pos is self.NoMatch or not pos :
189 + pos = []
190 + if kw is self.NoMatch or not kw :
191 + kw = {}
192 + return node("args", l=list(pos), k=dict(kw))
193 + def on_kwa (self, name, atom) :
194 + return name, atom
195 + def on_block (self, match, name, stmt, args=None, deco=None) :
196 + if args is self.NoMatch or not args :
197 + args = None
198 + if deco is self.NoMatch or not deco :
199 + deco = None
200 + return node(name, body=self._glue(stmt), args=args, deco=deco, _pos=self.pos)
201 + def on_deco (self, match, name, args=[]) :
202 + return node("deco", name=name, args=args)
203 + def __INIT__ (self) :
204 + self.nest = Nest(self.__compound__)
This diff could not be displayed because it is too large.
1 -import ast, functools 1 +from .. import nets
2 +from . import znparse, BaseParser
2 3
3 -from .. import nets, ParseError, ZINCError 4 +class Parser (BaseParser) :
4 -from . import znparse, indedent 5 + __parser__ = znparse.ZnParser
5 -from ..data import flatten
6 -
7 -class _TupleParser (object) :
8 - def __init__ (self) :
9 - self.p = znparse.znParser()
10 - def parse (self, source) :
11 - return self.p.parse(source, "tailtuple", semantics=self)
12 - def tuple (self, st) :
13 - def _tuple (l) :
14 - if isinstance(l, list) :
15 - return tuple(_tuple(x) for x in l)
16 - else :
17 - return l
18 - return _tuple(st[1][::2])
19 - def tailtuple (self, st) :
20 - return st
21 - def code (self, st) :
22 - return "".join(flatten(st))[1:-1].strip()
23 - def string (self, st) :
24 - return "".join(flatten(st))
25 - def text (self, st) :
26 - if st.name :
27 - return st.name
28 - elif st.string :
29 - return ast.literal_eval(st.string)
30 - elif st.code :
31 - return st.code
32 -
33 -class _Parser (_TupleParser) :
34 - def spec (self, st) :
35 - try :
36 - net = self.n.PetriNet(st.net, st.lang)
37 - except ZINCError as err :
38 - raise ParseError(str(err), None, None, self._p)
39 - for lvl, decl in st.declare :
40 - net.declare(decl, lvl)
41 - for node, *rest in st.nodes :
42 - if isinstance(node, self.n.Place) :
43 - try :
44 - net.add_place(node)
45 - except ZINCError as err :
46 - raise ParseError(err, rest[0], None, self._p)
47 - else :
48 - lineno, inputs, outputs = rest
49 - try :
50 - net.add_transition(node)
51 - except ZINCError as err :
52 - raise ParseError(err, lineno, None, self._p)
53 - for place, label in inputs.items() :
54 - try :
55 - if len(label) == 1 :
56 - net.add_input(place, node.name, label[0])
57 - else :
58 - net.add_input(place, node.name, self.n.MultiArc(*label))
59 - except ZINCError as err :
60 - raise ParseError(err, self._l[place, node.name], None, self._p)
61 - for place, label in outputs.items() :
62 - try :
63 - if len(label) == 1 :
64 - net.add_output(place, node.name, label[0])
65 - else :
66 - net.add_output(place, node.name, self.n.MultiArc(*label))
67 - except ZINCError as err :
68 - raise ParseError(err, self._l[node.name, place], None, self._p)
69 - return net
70 - def _mkarc (self, st) :
71 - _arc = {"val" : self.n.Value,
72 - "var" : self.n.Variable,
73 - "expr" : self.n.Expression,
74 - "flush" : self.n.Flush,
75 - "flush+" : functools.partial(self.n.Flush, notempty=True),
76 - "fill" : self.n.Fill}
77 - def mktuple (kind, label) :
78 - if isinstance(kind, tuple) :
79 - if not (isinstance(label, tuple) and len(kind) == len(label)) :
80 - raise ParseError("unmatched tuples %r and %r" % (kind, label),
81 - st.parseinfo.line+1, None, self._p)
82 - return self.n.Tuple(*(mktuple(k, l) for k, l in zip(kind, label)))
83 - else :
84 - return _arc[kind](label)
85 - if isinstance(st.kind, tuple) :
86 - try :
87 - lbl = self.t.parse(st.label)
88 - except Exception as err :
89 - raise ParseError(str(err), st.parseinfo.line+1, None, self._p)
90 - label = mktuple(st.kind, lbl)
91 - elif st.kind in _arc :
92 - label = _arc[st.kind](st.label.strip())
93 - if st.mod :
94 - if st.mod.kind == "?" :
95 - label = self.n.Test(label)
96 - elif st.mod.kind == "!" :
97 - label = self.n.Inhibitor(label, st.mod.guard)
98 - return st.way == "<", st.place, label, st.parseinfo.line+1
99 - def arc (self, st) :
100 - try :
101 - return self._mkarc(st)
102 - except ZINCError as err :
103 - raise ParseError(str(err), st.parseinfo.line+1, None, self._p)
104 -
105 -class Parser (object) :
106 def __init__ (self, module=nets) : 6 def __init__ (self, module=nets) :
107 self.n = module 7 self.n = module
108 - def parse (self, source, path) : 8 + def init (self, parser) :
109 - parser = znparse.ZnParser(indedent(source))
110 parser.n = self.n 9 parser.n = self.n
111 - try :
112 - result = parser.INPUT()
113 - if result is parser.NoMatch or parser.p_peek() is not None:
114 - parser.p_raise()
115 - return result
116 - except parser.ParserError as err :
117 - raise
118 - except :
119 - raise
120 10
121 def loads (source, module=nets) : 11 def loads (source, module=nets) :
122 return Parser(module).parse(source, "<string>") 12 return Parser(module).parse(source, "<string>")
......