diff options
Diffstat (limited to 'abdl/_parser.py')
-rw-r--r-- | abdl/_parser.py | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/abdl/_parser.py b/abdl/_parser.py new file mode 100644 index 0000000..c39a45e --- /dev/null +++ b/abdl/_parser.py @@ -0,0 +1,70 @@ +# This file is part of A Boneless Datastructure Language +# Copyright (C) 2020 Soni L. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +import pyparsing + +import abdl.exceptions +from abdl import _vm + +def _build_syntax(): + # pylint: disable=protected-access + from pyparsing import Suppress, Literal, Forward, CharsNotIn, StringEnd, Combine, Optional, Group, Word, srange, Empty + + subtree = Forward() + + skippable = Optional("?", default="") + + str_literal = (Combine(Suppress("'") + + (Suppress("%") + ("'" | "%") | Literal("%") + (CharsNotIn("") | StringEnd()).setParseAction(abdl.exceptions.PatternError._str_escape) | CharsNotIn("%'"))[...] + + (Suppress("'") | StringEnd().setParseAction(abdl.exceptions.PatternError._str_end))) + skippable) + str_literal.setParseAction(lambda toks: [_vm.StringKey(toks)]) + + re_literal = (Combine(Suppress("/") + + (Suppress("%") + ("/" | "%") | Literal("%") + (CharsNotIn("") | StringEnd()).setParseAction(abdl.exceptions.PatternError._re_escape) | CharsNotIn("%/"))[...] + + (Suppress("/") | StringEnd().setParseAction(abdl.exceptions.PatternError._re_end))) + skippable) + re_literal.setParseAction(lambda toks: [_vm.RegexKey(toks)]) + + arrow = Literal("->") + arrow.setParseAction(lambda: [_vm.Arrow()]) + + identifier = Word(srange("[A-Za-z_]"), srange("[A-Za-z0-9_]")) + identifier.setParseAction(lambda toks: [_vm.Ident(toks)]) + + parameter = (Suppress("$") + skippable + identifier) + parameter.setParseAction(lambda toks: [_vm.Param(toks)]) + + type_ = (Suppress(":") + skippable + Optional(Suppress("$")) + identifier) + type_.setParseAction(lambda toks: [_vm.ApplyPredicate(toks)]) + + # support for objects-as-keys + keysubtree = (Suppress("[") + + Group(type_[...] + subtree) + + (Suppress("]") | (CharsNotIn("") | StringEnd()).setParseAction(abdl.exceptions.PatternError._unexpected_tok)) + skippable) + keysubtree.setParseAction(lambda toks: [_vm.KeySubtree(toks)]) + + # represents key matching - switches from "key" to "value" + tag = (identifier + Optional(parameter | str_literal | re_literal | keysubtree) | parameter | str_literal | re_literal | keysubtree) + type_[...] + Empty().setParseAction(lambda: [_vm.End()]) + + # multiple value matching + valuesubtree = (Suppress("(") + Group(subtree) + (Suppress(")") | CharsNotIn("").setParseAction(abdl.exceptions.PatternError._unexpected_tok) | StringEnd().setParseAction(abdl.exceptions.PatternError._unexpected_tok)) + Optional("?", default="")) + valuesubtree.setParseAction(lambda toks: [_vm.ValueSubtree(toks)]) + + # arrow and tag, value subtree + subtree <<= (arrow + tag)[...] + (valuesubtree + Empty().setParseAction(lambda: [_vm.End()]))[...] + + return ((subtree | CharsNotIn("").setParseAction(abdl.exceptions.PatternError._unexpected_tok)) + StringEnd()).parseWithTabs() + +BUILT_SYNTAX = _build_syntax() |