Worked on semantics for top level animations
This commit is contained in:
parent
230b4d1080
commit
a30be96bf2
226
compiler.py
226
compiler.py
|
@ -795,6 +795,27 @@ class Animation:
|
|||
@property
|
||||
def file_info(self) -> FileInfo: return self._file_info
|
||||
|
||||
@property
|
||||
def identifier(self) -> Identifier: return self._identifier
|
||||
|
||||
@property
|
||||
def range_start(self) -> Expression: return self._range_start
|
||||
|
||||
@property
|
||||
def range_start_inclusive(self) -> bool: return self._range_start_inclusive
|
||||
|
||||
@property
|
||||
def range_end(self) -> Expression: return self._range_end
|
||||
|
||||
@property
|
||||
def range_end_inclusive(self) -> bool: return self._range_end_inclusive
|
||||
|
||||
@property
|
||||
def step(self) -> Expression: return self._step
|
||||
|
||||
@property
|
||||
def direction(self) -> AnimationDirection: return self._direction
|
||||
|
||||
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
||||
s: str = f"{pre} Animation ({self._identifier.value})\n"
|
||||
s += f"{pre_cont}├─ Range Start \
|
||||
|
@ -1858,6 +1879,31 @@ class FunctionDomainErrorRuntime(GraphRuntimeError):
|
|||
)
|
||||
|
||||
|
||||
class ContextNamespace:
|
||||
|
||||
_parent: "Context | ContextNamespace"
|
||||
_values: "dict[str, int | float | ContextExpression | ContextAnimation]"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: "Context | ContextNamespace",
|
||||
values: "dict[str, int | float | ContextExpression | ContextAnimation] | None" = None,
|
||||
):
|
||||
self._parent = parent
|
||||
self._values = values or {}
|
||||
|
||||
def lookup_var(self, variable: "ContextVariable") -> int | float:
|
||||
if variable.name in self._values:
|
||||
value = self._values[variable.name]
|
||||
if isinstance(value, (int , float)): return value
|
||||
else: return value.value(self)
|
||||
else: return self._parent.lookup_var(variable)
|
||||
|
||||
def lookup_func(
|
||||
self, function: "ContextFunctionCall") -> "ContextFunctionCallable":
|
||||
return self._parent.lookup_func(function)
|
||||
|
||||
|
||||
class ContextExpression:
|
||||
|
||||
_file_info: FileInfo
|
||||
|
@ -1865,7 +1911,7 @@ class ContextExpression:
|
|||
@property
|
||||
def file_info(self) -> FileInfo: return self._file_info
|
||||
|
||||
def value(self, context: "Context") -> int | float:
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
raise RuntimeError
|
||||
|
||||
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
||||
|
@ -1886,7 +1932,7 @@ class ContextLiteral(ContextExpression):
|
|||
self._file_info = file_info
|
||||
self._value = value
|
||||
|
||||
def value(self, context: "Context") -> int | float:
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
if self._value == 'π': return math.pi
|
||||
elif '.' in self._value: return float(self._value)
|
||||
else: return int(self._value)
|
||||
|
@ -1912,7 +1958,7 @@ class ContextVariable(ContextExpression):
|
|||
@property
|
||||
def name(self) -> str: return self._name
|
||||
|
||||
def value(self, context: "Context") -> int | float:
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
return context.lookup_var(self)
|
||||
|
||||
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
||||
|
@ -1942,7 +1988,7 @@ class ContextUnaryExpression(ContextExpression):
|
|||
@property
|
||||
def operator(self) -> UnaryOperator: return self._operator
|
||||
|
||||
def value(self, context: "Context") -> int | float:
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
match self.operator:
|
||||
case UnaryOperator.Negate:
|
||||
return - self.expression.value(context)
|
||||
|
@ -1984,7 +2030,7 @@ class ContextBinaryExpression(ContextExpression):
|
|||
@property
|
||||
def operator(self) -> BinaryOperator: return self._operator
|
||||
|
||||
def value(self, context: "Context") -> int | float:
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
a, b = self.expression1.value(context), self.expression2.value(context)
|
||||
match self.operator:
|
||||
case BinaryOperator.Exponential:
|
||||
|
@ -2111,7 +2157,7 @@ class ContextFunctionCall(ContextExpression):
|
|||
@property
|
||||
def arguments(self) -> list[ContextExpression]: return self._arguments[:]
|
||||
|
||||
def value(self, context: "Context") -> int | float:
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
args = [a.value(context) for a in self._arguments]
|
||||
func = context.lookup_func(self)
|
||||
if len(args) > func.parameters:
|
||||
|
@ -2158,16 +2204,9 @@ class ContextFunction:
|
|||
_context: "Context"
|
||||
_values: "dict[str, ContextAnimation | ContextExpression]"
|
||||
|
||||
@property
|
||||
def value(self) -> int | float: pass
|
||||
|
||||
def lookup(self, value: str) -> int | float:
|
||||
if value in self._values:
|
||||
return self._values[value].value(context)
|
||||
else: return self._context.lookup_var(value)
|
||||
|
||||
def call(self, value: str, args: list[ContextExpression]) -> int | float:
|
||||
return self._context.call(value, args)
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
pass
|
||||
|
||||
|
||||
class ContextAnimation:
|
||||
|
@ -2181,7 +2220,26 @@ class ContextAnimation:
|
|||
_direction: AnimationDirection
|
||||
_reversed: bool
|
||||
|
||||
def step(self, context: "Context"):
|
||||
def __init__(
|
||||
self,
|
||||
start_value: int | float,
|
||||
range_start: ContextExpression,
|
||||
range_start_inclusive: bool,
|
||||
range_end: ContextExpression,
|
||||
range_end_inclusive: bool,
|
||||
step: ContextExpression,
|
||||
direction: AnimationDirection,
|
||||
):
|
||||
self._current = start_value
|
||||
self._range_start = range_start
|
||||
self._range_start_inclusive = range_start_inclusive
|
||||
self._range_end = range_end
|
||||
self._range_end_inclusive = range_end_inclusive
|
||||
self._step = step
|
||||
self._direction = direction
|
||||
self._reversed = direction == AnimationDirection.Decrease
|
||||
|
||||
def step(self, context: ContextNamespace) -> int | float:
|
||||
if self._direction == AnimationDirection.Increase or (
|
||||
self._direction == AnimationDirection.Bounce and not self._reversed
|
||||
):
|
||||
|
@ -2218,10 +2276,10 @@ class ContextAnimation:
|
|||
self._reversed = False
|
||||
if not self._range_end_inclusive:
|
||||
self._current -= self._step.value(context)
|
||||
return self.value
|
||||
return self.value(context)
|
||||
|
||||
@property
|
||||
def value(self) -> int | float: return self._current
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
return self._current
|
||||
|
||||
|
||||
class GraphType(Enum):
|
||||
|
@ -2253,9 +2311,7 @@ class ContextGraph:
|
|||
_color_saturation: None | ContextFunction
|
||||
_color_luminosity: None | ContextFunction
|
||||
|
||||
def __iter__(self): return self
|
||||
|
||||
def step(self, context: "Context") -> tuple[
|
||||
def step(self, context: ContextNamespace) -> tuple[
|
||||
int | float,
|
||||
int | float,
|
||||
int | float,
|
||||
|
@ -2264,31 +2320,31 @@ class ContextGraph:
|
|||
]:
|
||||
match self.graph_type:
|
||||
case GraphType.X_Independent:
|
||||
x_last = self._x.value # type: ignore
|
||||
y_last = self._y.value # type: ignore
|
||||
x = next(self._x) # type: ignore
|
||||
y = self._y.value # type: ignore
|
||||
x_last = self._x.value(context) # type: ignore
|
||||
y_last = self._y.value(context) # type: ignore
|
||||
x = self._x.step(context) # type: ignore
|
||||
y = self._y.value(context) # type: ignore
|
||||
case GraphType.Y_Independent:
|
||||
y_last = self._y.value # type: ignore
|
||||
x_last = self._x.value # type: ignore
|
||||
y = next(self._y) # type: ignore
|
||||
x = self._x.value # type: ignore
|
||||
y_last = self._y.value(context) # type: ignore
|
||||
x_last = self._x.value(context) # type: ignore
|
||||
y = self._y.step(context) # type: ignore
|
||||
x = self._x.value(context) # type: ignore
|
||||
case GraphType.Parametric:
|
||||
x_last = self._x.value # type: ignore
|
||||
y_last = self._y.value # type: ignore
|
||||
next(self._t) # type: ignore
|
||||
x = self._x.value # type: ignore
|
||||
y = self._y.value # type: ignore
|
||||
x_last = self._x.value(context) # type: ignore
|
||||
y_last = self._y.value(context) # type: ignore
|
||||
self._t.step(context) # type: ignore
|
||||
x = self._x.value(context) # type: ignore
|
||||
y = self._y.value(context) # type: ignore
|
||||
case GraphType.Polar:
|
||||
theta_last = self._theta.value # type: ignore
|
||||
r_last = self._r.value # type: ignore
|
||||
theta = next(self._theta) # type: ignore
|
||||
r = self._r.value # type: ignore
|
||||
theta_last = self._theta.value(context) # type: ignore
|
||||
r_last = self._r.value(context) # type: ignore
|
||||
theta = self._theta.step(context) # type: ignore
|
||||
r = self._r.value(context) # type: ignore
|
||||
x_last = r_last * math.cos(theta_last)
|
||||
y_last = r_last * math.sin(theta_last)
|
||||
x = r * math.cos(theta)
|
||||
y = r * math.sin(theta)
|
||||
return x_last, y_last, x, y, self.color
|
||||
return x_last, y_last, x, y, self.color(context)
|
||||
|
||||
@property
|
||||
def graph_type(self) -> GraphType:
|
||||
|
@ -2320,54 +2376,41 @@ class ContextGraph:
|
|||
else:
|
||||
return ColorSpace.Grey
|
||||
|
||||
@property
|
||||
def color(self) -> tuple[float,float,float,float,]:
|
||||
def color(
|
||||
self, context: ContextNamespace) -> tuple[float,float,float,float,]:
|
||||
if self._color_alpha is not None:
|
||||
a = self._color_alpha.value
|
||||
a = self._color_alpha.value(context)
|
||||
else: a = 1
|
||||
match self.color_space:
|
||||
case ColorSpace.Grey:
|
||||
if self._color_grey is not None:
|
||||
c = self._color_grey.value
|
||||
c = self._color_grey.value(context)
|
||||
else: c = 1
|
||||
r, g, b = c, c, c
|
||||
case ColorSpace.RGB:
|
||||
if self._color_red is not None:
|
||||
r = self._color_red.value
|
||||
r = self._color_red.value(context)
|
||||
else: r = 1
|
||||
if self._color_green is not None:
|
||||
g = self._color_green.value
|
||||
g = self._color_green.value(context)
|
||||
else: g = 1
|
||||
if self._color_blue is not None:
|
||||
b = self._color_blue.value
|
||||
b = self._color_blue.value(context)
|
||||
else: b = 1
|
||||
case ColorSpace.HSL:
|
||||
r,g,b = 1,1,1
|
||||
return r, g, b, a
|
||||
|
||||
@property
|
||||
def value(self) -> int | float:
|
||||
def value(self, context: ContextNamespace) -> int | float:
|
||||
match self.graph_type:
|
||||
case GraphType.X_Independent:
|
||||
return self._x.value # type: ignore
|
||||
return self._x.value(context) # type: ignore
|
||||
case GraphType.Y_Independent:
|
||||
return self._y.value # type: ignore
|
||||
return self._y.value(context) # type: ignore
|
||||
case GraphType.Parametric:
|
||||
return self._t.value # type: ignore
|
||||
return self._t.value(context) # type: ignore
|
||||
case GraphType.Polar:
|
||||
return self._theta.value # type: ignore
|
||||
|
||||
|
||||
funcs_1 = {
|
||||
"sin": math.sin,
|
||||
"asin": math.asin,
|
||||
"cos": math.cos,
|
||||
"acos": math.acos,
|
||||
"tan": math.tan,
|
||||
"atan": math.atan,
|
||||
"ln": math.log,
|
||||
"log": math.log10,
|
||||
}
|
||||
return self._theta.value(context) # type: ignore
|
||||
|
||||
|
||||
class Context:
|
||||
|
@ -2379,15 +2422,18 @@ class Context:
|
|||
|
||||
def step(self):
|
||||
for anim in self._animations.values():
|
||||
next(anim)
|
||||
anim.step(ContextNamespace(self))
|
||||
|
||||
def lookup_var(self, variable: ContextVariable) -> int | float:
|
||||
if variable.name not in self._constants:
|
||||
raise UndefinedVariableIdentifierRuntime(
|
||||
variable.name, variable.file_info)
|
||||
return self._constants[variable.name]
|
||||
if variable.name in self._animations:
|
||||
return self._animations[variable.name].value(ContextNamespace(self))
|
||||
elif variable.name in self._constants:
|
||||
return self._constants[variable.name]
|
||||
raise UndefinedVariableIdentifierRuntime(
|
||||
variable.name, variable.file_info)
|
||||
|
||||
def lookup_func(self, function: ContextFunctionCall) -> ContextFunctionCallable:
|
||||
def lookup_func(
|
||||
self, function: ContextFunctionCall) -> ContextFunctionCallable:
|
||||
if function.identifier not in self._functions:
|
||||
raise UndefinedFunctionIdentifierRuntime(
|
||||
function.identifier, function.file_info)
|
||||
|
@ -2588,7 +2634,43 @@ def semantics_analyzer(file: File) -> Context:
|
|||
raise UnderDefinedConstantDefinition(child.file_info, None)
|
||||
constants[child.identifier.value] = value
|
||||
elif isinstance(child, Animation):
|
||||
pass
|
||||
range_start = _simplify_expression(
|
||||
child.range_start,
|
||||
constants,
|
||||
functions,
|
||||
True,
|
||||
)
|
||||
if not isinstance(range_start, ContextLiteral):
|
||||
raise UnderDefinedConstantDefinition(
|
||||
child.range_start.file_info, None)
|
||||
start_value = float(range_start._value)
|
||||
range_end = _simplify_expression(
|
||||
child.range_end,
|
||||
constants,
|
||||
functions,
|
||||
True,
|
||||
)
|
||||
if not isinstance(range_end, ContextLiteral):
|
||||
raise UnderDefinedConstantDefinition(
|
||||
child.range_end.file_info, None)
|
||||
step = _simplify_expression(
|
||||
child.step,
|
||||
constants,
|
||||
functions,
|
||||
True,
|
||||
)
|
||||
if not isinstance(step, ContextLiteral):
|
||||
raise UnderDefinedConstantDefinition(
|
||||
child.step.file_info, None)
|
||||
animations[child.identifier.value] = ContextAnimation(
|
||||
start_value,
|
||||
range_start,
|
||||
child.range_start_inclusive,
|
||||
range_end,
|
||||
child.range_end_inclusive,
|
||||
step,
|
||||
child.direction,
|
||||
)
|
||||
elif isinstance(child, Graph):
|
||||
pass
|
||||
if screen is None:
|
||||
|
|
Loading…
Reference in New Issue