Source code for concepts.dsl.parsers.function_expression_parser
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# File : function_expression_parser.py
# Author : Jiayuan Mao
# Email : maojiayuan@gmail.com
# Date : 10/25/2022
#
# This file is part of Project Concepts.
# Distributed under terms of the MIT license.
"""The parser for simple function expressions."""
import lark
import json
from dataclasses import dataclass
from concepts.dsl.dsl_types import ObjectType, Variable, ObjectConstant
from concepts.dsl.function_domain import FunctionDomain
from concepts.dsl.value import Value
from concepts.dsl.expression import Expression, ConstantExpression, VariableExpression, ObjectConstantExpression, FunctionApplicationExpression
from concepts.dsl.parsers.parser_base import ParserBase
# lark.v_args
inline_args = lark.v_args(inline=True)
__all__ = ['FunctionExpressionTransformer', 'FunctionExpressionParser']
@dataclass
class _Placeholder(object):
name: str
placeholder_type: str
[docs]
class FunctionExpressionParser(ParserBase):
"""The simple function expression parser.
This parser works for simple function expressions, for example: ``f(x, y)``.
Each function name is a string composed of letters, digits, and _, and each argument is an expression or a string.
When ``escape_string`` is set to ``True``, the string should be escaped with double quotes.
>>> from concepts.dsl.function_domain import FunctionDomain
>>> from concepts.dsl.parsers.function_expression_parser import FunctionExpressionParser
>>> domain = FunctionDomain()
>>> parser = FunctionExpressionParser(domain)
>>> parser.parse_expression('f(g(), "string")')
"""
GRAMMAR = r"""
start: function_application
function_application: function_name "(" (argument ("," argument)*)? ")"
function_name: STRING
%import common.WS
%ignore WS
%import common.LETTER
%import common.DIGIT
STRING: LETTER ("_"|"-"|LETTER|DIGIT)*
%import common.ESCAPED_STRING
"""
[docs]
def __init__(self, domain: FunctionDomain, allow_variable: bool = False, escape_string: bool = True):
"""Initialize the parser.
Args:
domain: the domain to use.
allow_variable: whether to allow variable.
escape_string: whether to escape the string.
"""
self.allow_variable = allow_variable
self.escape_string = escape_string if escape_string is not None else allow_variable
if self.allow_variable:
assert self.escape_string, 'If allow_variable is True, escape_string must be True.'
self.parser = lark.Lark(
self.GRAMMAR +
('constant: ESCAPED_STRING\n' if escape_string else 'constant: STRING\n') +
('variable: STRING\nargument: function_application | constant | variable' if allow_variable else 'argument: function_application | constant'),
parser='lalr', start='start'
)
self.transformer = FunctionExpressionTransformer(domain)
[docs]
def parse_expression(self, string: str) -> Expression:
"""Parse an expression from a string.
Args:
string: The string to parse.
Returns:
The parsed expression.
"""
tree = self.parser.parse(string)
return self.transformer.transform(tree)