diff options
Diffstat (limited to 'abdl/_parser.py')
-rw-r--r-- | abdl/_parser.py | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/abdl/_parser.py b/abdl/_parser.py new file mode 100644 index 0000000..3e179a2 --- /dev/null +++ b/abdl/_parser.py @@ -0,0 +1,75 @@ +# 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 + +from abdl import 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="") + + escape_char = Literal("%") + str_token = Literal("'") + re_token = Literal("/") + + unexpected_token = CharsNotIn("", exact=1).setParseAction(exceptions.PatternError._unexpected_tok) + unexpected_end = StringEnd().setParseAction(exceptions.PatternError._unexpected_tok) + + str_literal = (Combine(Suppress(str_token) + + (Suppress(escape_char) + (str_token | escape_char) | escape_char + CharsNotIn("", exact=1).setParseAction(exceptions.PatternError._str_escape) | CharsNotIn("%'"))[...] + + (Suppress(str_token) | StringEnd().setParseAction(exceptions.PatternError._str_end))) + skippable) + str_literal.setParseAction(lambda toks: [_vm.StringKey(toks)]) + + re_literal = (Combine(Suppress(re_token) + + (Suppress(escape_char) + (re_token | escape_char) | escape_char + CharsNotIn("", exact=1).setParseAction(exceptions.PatternError._re_escape) | CharsNotIn("%/"))[...] + + (Suppress(re_token) | StringEnd().setParseAction(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 + Suppress("$") + identifier) + type_.setParseAction(lambda toks: [_vm.ApplyPredicate(toks)]) + + # support for objects-as-keys + keysubtree = (Suppress("[") + Group(type_[...] + subtree) + (Suppress("]") | unexpected_token | unexpected_end) + 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(")") | unexpected_token | unexpected_end) + 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 | unexpected_token) + StringEnd()).parseWithTabs() + +BUILT_SYNTAX = _build_syntax() |