expr: add const-ness attribute and const()/infer() markers
This commit is contained in:
parent
a6eb428411
commit
11c556d7d6
|
@ -2,7 +2,7 @@ from .core import parse, dump, sizeof, offsetof, default, to_type, context
|
|||
from .core.base import Params, Context, Type, Error
|
||||
from .core.io import Stream, Segment
|
||||
from .core.meta import Wrapper, Generic
|
||||
from .core.expr import BaseExpr, Expr
|
||||
from .core.expr import BaseExpr, Expr, const, infer
|
||||
|
||||
from .types.data import Nothing, Static, Ignored, Data, data
|
||||
from .types.num import *
|
||||
|
@ -14,7 +14,7 @@ from .types.control import Switch, If
|
|||
from .types.io import AlignTo, AlignedTo
|
||||
|
||||
__all__ = [x.__name__ for x in {
|
||||
parse, dump, sizeof, offsetof, default, to_type,
|
||||
parse, dump, sizeof, offsetof, default, to_type, const, infer,
|
||||
Params, Context, Type, Error, Stream, Segment, BaseExpr, Expr,
|
||||
|
||||
Wrapper, Default, Sized, Ref, Transform, Mapped, Enum, Check, Fixed,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import math
|
||||
import operator
|
||||
import functools
|
||||
from typing import Any, Optional as O, Sequence, Mapping, Callable, Generic as G, TypeVar, List
|
||||
from typing import Any, Optional as O, Union as U, Sequence, Mapping, Callable, Generic as G, TypeVar, List
|
||||
|
||||
|
||||
symbols = {
|
||||
|
@ -63,6 +63,9 @@ class BaseExpr(G[T]):
|
|||
def _sx_put_(self, value: T, pop: bool = True) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
class Expr(G[T], BaseExpr[T]):
|
||||
def __getattr__(self, name: str) -> 'AttrExpr':
|
||||
return AttrExpr(self, name)
|
||||
|
@ -101,6 +104,9 @@ class AttrExpr(G[T], Expr[T]):
|
|||
setattr(parent, get(self.__attr, pop=pop), value)
|
||||
put(self.__parent, parent, pop=pop)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return is_const(self.__parent) and is_const(self.__attr)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'{self.__parent}.{self.__attr}'
|
||||
|
||||
|
@ -123,6 +129,9 @@ class ItemExpr(G[T], Expr[T]):
|
|||
parent[get(self.__item, pop=pop)] = value
|
||||
put(self.__parent, parent, pop=pop)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return is_const(self.__parent) and is_const(self.__item)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'{self.__parent}[{self.__item}]'
|
||||
|
||||
|
@ -144,6 +153,9 @@ class CallExpr(G[T], Expr[T]):
|
|||
def _sx_put_(self, value: T, pop: bool = True) -> None:
|
||||
raise NotImplementedError(f'{self.__class__.__name__} is not invertible')
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return False
|
||||
|
||||
def __str__(self) -> str:
|
||||
args = [repr(a) for a in self.__args]
|
||||
args += [f'{k}: {v}' for k, v in self.__kwargs.items()]
|
||||
|
@ -173,6 +185,9 @@ class UnaryExpr(G[T], Expr[T]):
|
|||
raise NotImplementedError(f'{self.__class__.__name__} {symbols[self.__op]!r} is not invertible')
|
||||
put(self.__value, reverse[self.__op](value), pop=pop)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return is_const(self.__value)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'({symbols[self.__op]}{self.__value})'
|
||||
|
||||
|
@ -192,22 +207,25 @@ class BinExpr(G[T], Expr[T]):
|
|||
return self.__op(peek(self.__left, pop=pop), peek(self.__right, pop=pop))
|
||||
|
||||
def _sx_put_(self, value: T, pop: bool = True) -> None:
|
||||
if not isinstance(self.__left, BaseExpr):
|
||||
if is_const(self.__left):
|
||||
operand = self.__left
|
||||
target = self.__right
|
||||
i = 0
|
||||
elif not isinstance(self.__right, BaseExpr):
|
||||
elif is_const(self.__right):
|
||||
operand = self.__right
|
||||
target = self.__left
|
||||
i = 1
|
||||
else:
|
||||
raise NotImplementedError(f'{self.__class__.__name__} has two expression operands and is not invertible')
|
||||
raise NotImplementedError(f'{self.__class__.__name__} has two non-const expression operands and is not invertible')
|
||||
if self.__op not in reverse:
|
||||
raise NotImplementedError(f'{self.__class__.__name__} {symbols[self.__op]!r} is not invertible')
|
||||
rev = reverse[self.__op]
|
||||
if isinstance(rev, tuple):
|
||||
rev = rev[i]
|
||||
put(target, rev(value, operand), pop=pop)
|
||||
put(target, rev(value, get(operand, pop=pop)), pop=pop)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return is_const(self.__left) and is_const(self.__right)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'({self.__left} {symbols[self.__op]} {self.__right})'
|
||||
|
@ -245,6 +263,9 @@ class CompExpr(Expr[bool]):
|
|||
raise NotImplementedError(f'{self.__class__.__name__} {symbols[self.__op]!r} is not invertible')
|
||||
put(target, value, pop=pop)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return is_const(self.__left) and is_const(self.__right)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'({self.__left} {symbols[self.__op]} {self.__right})'
|
||||
|
||||
|
@ -271,23 +292,60 @@ class ProxyExpr(G[T], Expr[T]):
|
|||
def _sx_put_(self, value: T, pop: bool = True) -> None:
|
||||
return put(self.__stack[-1], value, pop=pop)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return is_const(self.__stack[-1])
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'${self.__name}'
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'${self.__name}(=> {self.__stack!r})'
|
||||
|
||||
class ConstChangeExpr(G[T], Expr[T]):
|
||||
def __init__(self, child: BaseExpr[T], const: bool = True) -> None:
|
||||
self.__child = child
|
||||
self.__const = const
|
||||
|
||||
def get(expr: Any, pop: bool = True) -> Any:
|
||||
def _sx_get_(self, pop: bool = True) -> T:
|
||||
return get(self.__child, pop=pop)
|
||||
|
||||
def _sx_peek_(self, pop: bool = True) -> T:
|
||||
return peek(self.__child, pop=pop)
|
||||
|
||||
def _sx_put_(self, value: T, pop: bool = True) -> None:
|
||||
return put(self.__child, value, pop=pop)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return self.__const
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self.__const:
|
||||
return f'const({self.__child})'
|
||||
else:
|
||||
return f'infer({self.__child})'
|
||||
|
||||
|
||||
def get(expr: U[T, BaseExpr[T]], pop: bool = True) -> T:
|
||||
if isinstance(expr, BaseExpr):
|
||||
return expr._sx_get_(pop=pop)
|
||||
return expr
|
||||
|
||||
def peek(expr: Any, pop: bool = True) -> Any:
|
||||
def peek(expr: U[T, BaseExpr[T]], pop: bool = True) -> T:
|
||||
if isinstance(expr, BaseExpr):
|
||||
return expr._sx_peek_(pop=pop)
|
||||
return expr
|
||||
|
||||
def put(expr: Any, value: Any, pop: bool = True) -> None:
|
||||
def put(expr: U[T, BaseExpr[T]], value: T, pop: bool = True) -> None:
|
||||
if isinstance(expr, BaseExpr):
|
||||
expr._sx_put_(value, pop=pop)
|
||||
|
||||
def is_const(expr: U[T, BaseExpr[T]]) -> bool:
|
||||
if isinstance(expr, BaseExpr):
|
||||
return expr._sx_is_const_()
|
||||
return True
|
||||
|
||||
def const(expr: U[T, BaseExpr[T]]) -> ConstChangeExpr[T]:
|
||||
return ConstChangeExpr(expr, const=True)
|
||||
|
||||
def infer(expr: U[T, BaseExpr[T]]) -> ConstChangeExpr[T]:
|
||||
return ConstChangeExpr(expr, const=False)
|
||||
|
|
|
@ -55,6 +55,9 @@ class Generic(G[T], Type[T], BaseExpr[T]):
|
|||
def _sx_peek_(self, pop: bool = False) -> T:
|
||||
return self.stack[-1]
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return False
|
||||
|
||||
def _get_sx_type_(self, ident: Any) -> Type:
|
||||
return to_type(self.stack[-1])
|
||||
|
||||
|
@ -142,3 +145,6 @@ class TypeSource(G[T], Wrapper[T], BaseExpr[T]):
|
|||
context, segment, stream, pos, _ = self.stack.pop() if pop else self.stack[-1]
|
||||
with context.enter_segment(segment, stream, pos, os.SEEK_SET) as f:
|
||||
context.dump(to_type(self.child), f, value)
|
||||
|
||||
def _sx_is_const_(self) -> bool:
|
||||
return False
|
||||
|
|
Loading…
Reference in New Issue