Source code for concepts.dm.crow.parsers.cdl_literal_parser
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# File : cdl_literal_parser.py
# Author : Jiayuan Mao
# Email : maojiayuan@gmail.com
# Date : 08/15/2024
#
# This file is part of Project Concepts.
# Distributed under terms of the MIT license.
from dataclasses import dataclass
from typing import Any, Union, Tuple, Set, Dict
from lark import Tree
from lark.visitors import Transformer, v_args
from concepts.dm.crow.crow_domain import CrowDomain
from concepts.dsl.dsl_types import BatchedListType, ListType, TypeBase, Variable, VectorValueType
inline_args = v_args(inline=True)
__all__ = ['LiteralValue', 'LiteralList', 'LiteralSet', 'InTypedArgument', 'ArgumentsDef', 'CSList', 'CDLLiteralTransformer']
[docs]
@dataclass
class LiteralValue(object):
"""A literal value."""
value: Union[bool, int, float, complex, str]
[docs]
@dataclass
class LiteralList(object):
"""A list of literals."""
items: Tuple[Union[bool, int, float, complex, str, 'LiteralList', 'LiteralSet'], ...]
[docs]
@dataclass
class LiteralSet(object):
"""A set of literals."""
items: Set[Union[bool, int, float, complex, str, 'LiteralList', 'LiteralSet']]
[docs]
@dataclass
class InTypedArgument(object):
"""A typed argument defined as `name in value`. This is used in forall/exists statements."""
name: str
value: Any
[docs]
@dataclass
class CSList(object):
"""A comma-separated list of something."""
items: Tuple[Any, ...]
def __str__(self):
return f'CSList({", ".join(str(item) for item in self.items)})'
def __repr__(self):
return self.__str__()
[docs]
class CDLLiteralTransformer(Transformer):
"""The transformer for literal types. Including:
- VARNAME, CONSTNAME, BASIC_TYPENAME
- number, DEC_NUMBER, HEX_NUMBER, BIN_NUMBER, OCT_NUMBER, FLOAT_NUMBER, IMAG_NUMBER
- boolean, TRUE, FALSE
- string
- literal_list
- literal_set
- decorator_k, decorator_kwarg, decorator_kwargs
"""
domain: CrowDomain
[docs]
@inline_args
def typename(self, name: Union[str, TypeBase]) -> TypeBase:
"""Captures typenames including basic types and vector types."""
return name
[docs]
@inline_args
def sized_vector_typename(self, name: Union[str, TypeBase], size: int) -> VectorValueType:
"""Captures sized vector typenames defined as `vector[typename, size]`."""
return VectorValueType(self.domain.get_type(name), size)
[docs]
@inline_args
def unsized_vector_typename(self, name: Union[str, TypeBase]) -> VectorValueType:
"""Captures unsized vector typenames defined as `vector[typename]`."""
return VectorValueType(self.domain.get_type(name))
[docs]
@inline_args
def batched_typename(self, element_dtype: Union[str, TypeBase], indices: Tree) -> BatchedListType:
"""Captures batched typenames defined as `typename[indices]`."""
element_dtype = self.domain.get_type(element_dtype)
return BatchedListType(element_dtype, [self.domain.get_type(name) for name in indices.children])
[docs]
@inline_args
def list_typename(self, element_dtype: Union[str, TypeBase]) -> ListType:
"""Captures list typenames defined as `list[typename]`."""
return ListType(self.domain.get_type(element_dtype))
[docs]
@inline_args
def typed_argument(self, name: str, typename: Union[str, TypeBase]) -> Variable:
"""Captures typed arguments defined as `name: typename`."""
if isinstance(typename, str):
typename = self.domain.get_type(typename)
return Variable(name, typename)
[docs]
@inline_args
def multi_typed_arguments(self, name: Tree, typename: Union[str, TypeBase]) -> 'CSList':
"""Captures multiple typed arguments defined as `name1, name2: typename`."""
if isinstance(typename, str):
typename = self.domain.get_type(typename)
return CSList(tuple(Variable(n, typename) for n in name.children))
[docs]
@inline_args
def is_typed_argument(self, name: str, typename: Union[str, TypeBase]) -> Variable:
"""Captures typed arguments defined as `name is typename`. This is used in forall/exists statements."""
if isinstance(typename, str):
typename = self.domain.get_type(typename)
return Variable(name, typename)
[docs]
@inline_args
def in_typed_argument(self, name: str, value: Any) -> InTypedArgument:
"""Captures typed arguments defined as `name in value`. This is used in forall/exists statements."""
return InTypedArgument(name, value)
[docs]
def arguments_def(self, args):
"""Captures the arguments definition. This is used in function definitions."""
return ArgumentsDef(tuple(args))
[docs]
def VARNAME(self, token):
"""Captures variable names, such as `var_name`."""
return token.value
[docs]
def CONSTNAME(self, token):
"""Captures constant names, such as `CONST_NAME`."""
return token.value
[docs]
def BASIC_TYPENAME(self, token):
"""Captures basic type names (non-vector types), such as `int`, `float`, `bool`, `object`, etc."""
return token.value
[docs]
@inline_args
def number(self, value: Union[int, float, complex]) -> Union[int, float, complex]:
"""Captures number literals, including integers, floats, and complex numbers."""
return value
[docs]
@inline_args
def BIN_NUMBER(self, value: str) -> int:
"""Captures binary number literals."""
return int(value, 2)
[docs]
@inline_args
def OCT_NUMBER(self, value: str) -> int:
"""Captures octal number literals."""
return int(value, 8)
[docs]
@inline_args
def DEC_NUMBER(self, value: str) -> int:
"""Captures decimal number literals."""
return int(value)
[docs]
@inline_args
def HEX_NUMBER(self, value: str) -> int:
"""Captures hexadecimal number literals."""
return int(value, 16)
[docs]
@inline_args
def FLOAT_NUMBER(self, value: str) -> float:
"""Captures floating point number literals."""
return float(value)
[docs]
@inline_args
def IMAG_NUMBER(self, value: str) -> complex:
"""Captures complex number literals."""
return complex(value)
[docs]
@inline_args
def boolean(self, value: bool) -> bool:
"""Captures boolean literals."""
return value
[docs]
@inline_args
def string(self, value: str) -> str:
"""Captures string literals."""
if value[0] == value[-1] and value[0] in ('"', "'"):
value = value[1:-1]
return str(value)
[docs]
@inline_args
def literal_list(self, *items: Any) -> LiteralList:
"""Captures literal lists, such as `[1, 2, 3, 4]`."""
return LiteralList(tuple(items))
[docs]
@inline_args
def literal_set(self, *items: Any) -> LiteralSet:
"""Captures literal sets, such as `{1, 2, 3, 4}`."""
return LiteralSet(set(items))
[docs]
@inline_args
def literal(self, value: Union[bool, int, float, complex, str, LiteralList, LiteralSet]) -> Union[LiteralValue, LiteralList, LiteralSet]:
"""Captures literal values."""
if isinstance(value, (bool, int, float, complex, str)):
return LiteralValue(value)
elif isinstance(value, (LiteralList, LiteralSet)):
return value
else:
raise ValueError(f'Invalid literal value: {value}')
[docs]
@inline_args
def decorator_kwarg(self, k, v: Union[LiteralValue, LiteralList, LiteralSet] = True) -> Tuple[str, Union[bool, int, float, complex, str, LiteralList, LiteralSet]]:
"""Captures the key-value pair of a decorator. This is used in the decorator syntax, such as [[k=True]]."""
return k, v.value if isinstance(v, LiteralValue) else v
[docs]
def decorator_kwargs(self, args) -> Dict[str, Union[bool, int, float, complex, str, LiteralList, LiteralSet]]:
"""Captures the key-value pairs of a decorator. This is used in the decorator syntax, such as [[k=True, k2=123, k3=[1, 2, 3]]]."""
return {k: v for k, v in args}