Coverage for kye/parser/kye_ast.py: 61%
94 statements
« prev ^ index » next coverage.py v7.3.2, created at 2024-01-04 16:29 -0700
« prev ^ index » next coverage.py v7.3.2, created at 2024-01-04 16:29 -0700
1from __future__ import annotations
2from pydantic import BaseModel, model_validator, constr
3from typing import Optional, Literal, Union, Any
5TYPE = constr(pattern=r'[A-Z][a-z][a-zA-Z]*')
6EDGE = constr(pattern=r'[a-z][a-z_]*')
8class TokenPosition(BaseModel):
9 line: int
10 column: int
11 end_line: int
12 end_column: int
13 start_pos: int
14 end_pos: int
15 text: str
17 def __repr__(self):
18 end_line = f"{self.end_line}:" if self.end_line != self.line else ''
19 return f"{self.line}:{self.column}-{end_line}{self.end_column}"
21class AST(BaseModel):
22 children: list[AST] = []
23 meta: TokenPosition
25 def __repr__(self):
26 end_line = f"-{self.meta.end_line}" if self.meta.end_line != self.meta.line else ''
27 return f"{self.__class__.__name__}<{self.__repr_value__()}>:{self.meta.line}{end_line}"
29 def __repr_value__(self):
30 raise Exception('Not implemented __repr_value__')
32class Definition(AST):
33 """ Abstract class for all AST nodes that define a name """
34 name: Union[TYPE, EDGE]
36class TypeDefinition(Definition):
37 """ Abstract class for all AST nodes that define a type """
38 name: TYPE
40class ExpressionDefinition(Definition):
41 """ Abstract class for all AST nodes who's type is an expression """
42 type: Expression
44class ContainedDefinitions(AST):
45 """ Abstract class for all AST nodes that have child definitions """
46 children: list[Definition]
48class ModuleDefinitions(ContainedDefinitions):
49 children: list[TypeDefinition]
51 @model_validator(mode='after')
52 def validate_definitions(self):
53 type_names = set()
54 for child in self.children:
55 # raise error if definition name is duplicated
56 if child.name in type_names:
57 raise ValueError(f'Type name {child.name} is duplicated in model {self.name}')
58 type_names.add(child.name)
59 return self
61 def __repr_value__(self):
62 return f"{','.join(child.name for child in self.children)}"
64class AliasDefinition(TypeDefinition, ExpressionDefinition):
66 @model_validator(mode='after')
67 def set_children(self):
68 self.children = [self.type]
69 return self
71 def __repr_value__(self):
72 return f"{self.name}"
74class ModelDefinition(TypeDefinition, ContainedDefinitions):
75 indexes: list[list[EDGE]]
76 subtypes: list[TypeDefinition]
77 edges: list[EdgeDefinition]
79 @model_validator(mode='after')
80 def validate_indexes(self):
81 self.children = self.subtypes + self.edges
83 subtype_names = set()
84 for subtype in self.subtypes:
85 # raise error if subtype name is duplicated
86 if subtype.name in subtype_names:
87 raise ValueError(f'Subtype {subtype.name} is duplicated in model {self.name}')
88 subtype_names.add(subtype.name)
90 edge_names = set()
91 for edge in self.edges:
92 # raise error if edge name is duplicated
93 if edge.name in edge_names:
94 raise ValueError(f'Edge name {edge.name} is duplicated in model {self.name}')
95 edge_names.add(edge.name)
97 idx_names = set()
98 for idx in self.indexes:
99 for name in idx:
100 # raise error if index name is not an edge name
101 if name not in edge_names:
102 raise ValueError(f'Index {name} is not an edge name in model {self.name}')
103 if name in idx_names:
104 raise ValueError(f'Index Edge {name} is in multiple indexes in model {self.name}')
105 idx_names.add(name)
106 return self
108 def __repr_value__(self):
109 def format_index(idx):
110 return "(" + ','.join(idx) + ")"
112 return self.name + \
113 ''.join(format_index(idx) for idx in self.indexes) + \
114 "{" + ','.join(edge.name for edge in self.children) + "}"
116class EdgeDefinition(ExpressionDefinition):
117 name: EDGE
118 cardinality: Optional[Literal['*','?','+','!']]
119 _ref: Optional[str]
121 @model_validator(mode='after')
122 def set_children(self):
123 self.children = [self.type]
124 return self
126 def __repr_value__(self):
127 return f"{self.name}{self.cardinality or ''}"
129class Expression(AST):
130 """ Abstract class for all AST nodes that are expressions """
131 pass
133class Identifier(Expression):
134 name: str
136 @property
137 def kind(self):
138 if self.name[0].isupper():
139 if any(letter.islower() for letter in self.name):
140 return 'type'
141 return 'const'
142 if self.name[0].islower():
143 return 'edge'
145 def __repr_value__(self):
146 return self.name
148class LiteralExpression(Expression):
149 value: Union[str, float, bool]
151 def __repr_value__(self):
152 return repr(self.value)
154class Operation(Expression):
155 _OP_NAMES = {
156 '!': 'not', '~': 'invert',
157 '!=': 'ne', '==': 'eq',
158 '>=': 'gte', '<=': 'lte',
159 '>': 'gt', '<': 'lt',
160 '+': 'add', '-': 'sub',
161 '*': 'mul', '/': 'div', '%': 'mod',
162 '|': 'or', '&': 'and', '^': 'xor',
163 '[]': 'filter', '.': 'dot', 'is': 'is',
164 }
166 op: Literal[
167 '!','~',
168 '!=','==','>=','<=','>','<',
169 '+','-','*','/','%',
170 '|','&','^',
171 '[]','.','is',
172 ]
173 children: list[Expression]
175 @property
176 def name(self):
177 return self._OP_NAMES[self.op]
179 def __repr_value__(self):
180 return self.name