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
|
@property
|
||||||
def file_info(self) -> FileInfo: return self._file_info
|
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:
|
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
||||||
s: str = f"{pre} Animation ({self._identifier.value})\n"
|
s: str = f"{pre} Animation ({self._identifier.value})\n"
|
||||||
s += f"{pre_cont}├─ Range Start \
|
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:
|
class ContextExpression:
|
||||||
|
|
||||||
_file_info: FileInfo
|
_file_info: FileInfo
|
||||||
|
@ -1865,7 +1911,7 @@ class ContextExpression:
|
||||||
@property
|
@property
|
||||||
def file_info(self) -> FileInfo: return self._file_info
|
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
|
raise RuntimeError
|
||||||
|
|
||||||
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
||||||
|
@ -1886,7 +1932,7 @@ class ContextLiteral(ContextExpression):
|
||||||
self._file_info = file_info
|
self._file_info = file_info
|
||||||
self._value = value
|
self._value = value
|
||||||
|
|
||||||
def value(self, context: "Context") -> int | float:
|
def value(self, context: ContextNamespace) -> int | float:
|
||||||
if self._value == 'π': return math.pi
|
if self._value == 'π': return math.pi
|
||||||
elif '.' in self._value: return float(self._value)
|
elif '.' in self._value: return float(self._value)
|
||||||
else: return int(self._value)
|
else: return int(self._value)
|
||||||
|
@ -1912,7 +1958,7 @@ class ContextVariable(ContextExpression):
|
||||||
@property
|
@property
|
||||||
def name(self) -> str: return self._name
|
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)
|
return context.lookup_var(self)
|
||||||
|
|
||||||
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
|
||||||
|
@ -1942,7 +1988,7 @@ class ContextUnaryExpression(ContextExpression):
|
||||||
@property
|
@property
|
||||||
def operator(self) -> UnaryOperator: return self._operator
|
def operator(self) -> UnaryOperator: return self._operator
|
||||||
|
|
||||||
def value(self, context: "Context") -> int | float:
|
def value(self, context: ContextNamespace) -> int | float:
|
||||||
match self.operator:
|
match self.operator:
|
||||||
case UnaryOperator.Negate:
|
case UnaryOperator.Negate:
|
||||||
return - self.expression.value(context)
|
return - self.expression.value(context)
|
||||||
|
@ -1984,7 +2030,7 @@ class ContextBinaryExpression(ContextExpression):
|
||||||
@property
|
@property
|
||||||
def operator(self) -> BinaryOperator: return self._operator
|
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)
|
a, b = self.expression1.value(context), self.expression2.value(context)
|
||||||
match self.operator:
|
match self.operator:
|
||||||
case BinaryOperator.Exponential:
|
case BinaryOperator.Exponential:
|
||||||
|
@ -2111,7 +2157,7 @@ class ContextFunctionCall(ContextExpression):
|
||||||
@property
|
@property
|
||||||
def arguments(self) -> list[ContextExpression]: return self._arguments[:]
|
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]
|
args = [a.value(context) for a in self._arguments]
|
||||||
func = context.lookup_func(self)
|
func = context.lookup_func(self)
|
||||||
if len(args) > func.parameters:
|
if len(args) > func.parameters:
|
||||||
|
@ -2158,16 +2204,9 @@ class ContextFunction:
|
||||||
_context: "Context"
|
_context: "Context"
|
||||||
_values: "dict[str, ContextAnimation | ContextExpression]"
|
_values: "dict[str, ContextAnimation | ContextExpression]"
|
||||||
|
|
||||||
@property
|
|
||||||
def value(self) -> int | float: pass
|
|
||||||
|
|
||||||
def lookup(self, value: str) -> int | float:
|
def value(self, context: ContextNamespace) -> int | float:
|
||||||
if value in self._values:
|
pass
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class ContextAnimation:
|
class ContextAnimation:
|
||||||
|
@ -2181,7 +2220,26 @@ class ContextAnimation:
|
||||||
_direction: AnimationDirection
|
_direction: AnimationDirection
|
||||||
_reversed: bool
|
_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 (
|
if self._direction == AnimationDirection.Increase or (
|
||||||
self._direction == AnimationDirection.Bounce and not self._reversed
|
self._direction == AnimationDirection.Bounce and not self._reversed
|
||||||
):
|
):
|
||||||
|
@ -2218,10 +2276,10 @@ class ContextAnimation:
|
||||||
self._reversed = False
|
self._reversed = False
|
||||||
if not self._range_end_inclusive:
|
if not self._range_end_inclusive:
|
||||||
self._current -= self._step.value(context)
|
self._current -= self._step.value(context)
|
||||||
return self.value
|
return self.value(context)
|
||||||
|
|
||||||
@property
|
def value(self, context: ContextNamespace) -> int | float:
|
||||||
def value(self) -> int | float: return self._current
|
return self._current
|
||||||
|
|
||||||
|
|
||||||
class GraphType(Enum):
|
class GraphType(Enum):
|
||||||
|
@ -2253,9 +2311,7 @@ class ContextGraph:
|
||||||
_color_saturation: None | ContextFunction
|
_color_saturation: None | ContextFunction
|
||||||
_color_luminosity: None | ContextFunction
|
_color_luminosity: None | ContextFunction
|
||||||
|
|
||||||
def __iter__(self): return self
|
def step(self, context: ContextNamespace) -> tuple[
|
||||||
|
|
||||||
def step(self, context: "Context") -> tuple[
|
|
||||||
int | float,
|
int | float,
|
||||||
int | float,
|
int | float,
|
||||||
int | float,
|
int | float,
|
||||||
|
@ -2264,31 +2320,31 @@ class ContextGraph:
|
||||||
]:
|
]:
|
||||||
match self.graph_type:
|
match self.graph_type:
|
||||||
case GraphType.X_Independent:
|
case GraphType.X_Independent:
|
||||||
x_last = self._x.value # type: ignore
|
x_last = self._x.value(context) # type: ignore
|
||||||
y_last = self._y.value # type: ignore
|
y_last = self._y.value(context) # type: ignore
|
||||||
x = next(self._x) # type: ignore
|
x = self._x.step(context) # type: ignore
|
||||||
y = self._y.value # type: ignore
|
y = self._y.value(context) # type: ignore
|
||||||
case GraphType.Y_Independent:
|
case GraphType.Y_Independent:
|
||||||
y_last = self._y.value # type: ignore
|
y_last = self._y.value(context) # type: ignore
|
||||||
x_last = self._x.value # type: ignore
|
x_last = self._x.value(context) # type: ignore
|
||||||
y = next(self._y) # type: ignore
|
y = self._y.step(context) # type: ignore
|
||||||
x = self._x.value # type: ignore
|
x = self._x.value(context) # type: ignore
|
||||||
case GraphType.Parametric:
|
case GraphType.Parametric:
|
||||||
x_last = self._x.value # type: ignore
|
x_last = self._x.value(context) # type: ignore
|
||||||
y_last = self._y.value # type: ignore
|
y_last = self._y.value(context) # type: ignore
|
||||||
next(self._t) # type: ignore
|
self._t.step(context) # type: ignore
|
||||||
x = self._x.value # type: ignore
|
x = self._x.value(context) # type: ignore
|
||||||
y = self._y.value # type: ignore
|
y = self._y.value(context) # type: ignore
|
||||||
case GraphType.Polar:
|
case GraphType.Polar:
|
||||||
theta_last = self._theta.value # type: ignore
|
theta_last = self._theta.value(context) # type: ignore
|
||||||
r_last = self._r.value # type: ignore
|
r_last = self._r.value(context) # type: ignore
|
||||||
theta = next(self._theta) # type: ignore
|
theta = self._theta.step(context) # type: ignore
|
||||||
r = self._r.value # type: ignore
|
r = self._r.value(context) # type: ignore
|
||||||
x_last = r_last * math.cos(theta_last)
|
x_last = r_last * math.cos(theta_last)
|
||||||
y_last = r_last * math.sin(theta_last)
|
y_last = r_last * math.sin(theta_last)
|
||||||
x = r * math.cos(theta)
|
x = r * math.cos(theta)
|
||||||
y = r * math.sin(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
|
@property
|
||||||
def graph_type(self) -> GraphType:
|
def graph_type(self) -> GraphType:
|
||||||
|
@ -2320,54 +2376,41 @@ class ContextGraph:
|
||||||
else:
|
else:
|
||||||
return ColorSpace.Grey
|
return ColorSpace.Grey
|
||||||
|
|
||||||
@property
|
def color(
|
||||||
def color(self) -> tuple[float,float,float,float,]:
|
self, context: ContextNamespace) -> tuple[float,float,float,float,]:
|
||||||
if self._color_alpha is not None:
|
if self._color_alpha is not None:
|
||||||
a = self._color_alpha.value
|
a = self._color_alpha.value(context)
|
||||||
else: a = 1
|
else: a = 1
|
||||||
match self.color_space:
|
match self.color_space:
|
||||||
case ColorSpace.Grey:
|
case ColorSpace.Grey:
|
||||||
if self._color_grey is not None:
|
if self._color_grey is not None:
|
||||||
c = self._color_grey.value
|
c = self._color_grey.value(context)
|
||||||
else: c = 1
|
else: c = 1
|
||||||
r, g, b = c, c, c
|
r, g, b = c, c, c
|
||||||
case ColorSpace.RGB:
|
case ColorSpace.RGB:
|
||||||
if self._color_red is not None:
|
if self._color_red is not None:
|
||||||
r = self._color_red.value
|
r = self._color_red.value(context)
|
||||||
else: r = 1
|
else: r = 1
|
||||||
if self._color_green is not None:
|
if self._color_green is not None:
|
||||||
g = self._color_green.value
|
g = self._color_green.value(context)
|
||||||
else: g = 1
|
else: g = 1
|
||||||
if self._color_blue is not None:
|
if self._color_blue is not None:
|
||||||
b = self._color_blue.value
|
b = self._color_blue.value(context)
|
||||||
else: b = 1
|
else: b = 1
|
||||||
case ColorSpace.HSL:
|
case ColorSpace.HSL:
|
||||||
r,g,b = 1,1,1
|
r,g,b = 1,1,1
|
||||||
return r, g, b, a
|
return r, g, b, a
|
||||||
|
|
||||||
@property
|
def value(self, context: ContextNamespace) -> int | float:
|
||||||
def value(self) -> int | float:
|
|
||||||
match self.graph_type:
|
match self.graph_type:
|
||||||
case GraphType.X_Independent:
|
case GraphType.X_Independent:
|
||||||
return self._x.value # type: ignore
|
return self._x.value(context) # type: ignore
|
||||||
case GraphType.Y_Independent:
|
case GraphType.Y_Independent:
|
||||||
return self._y.value # type: ignore
|
return self._y.value(context) # type: ignore
|
||||||
case GraphType.Parametric:
|
case GraphType.Parametric:
|
||||||
return self._t.value # type: ignore
|
return self._t.value(context) # type: ignore
|
||||||
case GraphType.Polar:
|
case GraphType.Polar:
|
||||||
return self._theta.value # type: ignore
|
return self._theta.value(context) # 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
|
@ -2379,15 +2422,18 @@ class Context:
|
||||||
|
|
||||||
def step(self):
|
def step(self):
|
||||||
for anim in self._animations.values():
|
for anim in self._animations.values():
|
||||||
next(anim)
|
anim.step(ContextNamespace(self))
|
||||||
|
|
||||||
def lookup_var(self, variable: ContextVariable) -> int | float:
|
def lookup_var(self, variable: ContextVariable) -> int | float:
|
||||||
if variable.name not in self._constants:
|
if variable.name in self._animations:
|
||||||
raise UndefinedVariableIdentifierRuntime(
|
return self._animations[variable.name].value(ContextNamespace(self))
|
||||||
variable.name, variable.file_info)
|
elif variable.name in self._constants:
|
||||||
return self._constants[variable.name]
|
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:
|
if function.identifier not in self._functions:
|
||||||
raise UndefinedFunctionIdentifierRuntime(
|
raise UndefinedFunctionIdentifierRuntime(
|
||||||
function.identifier, function.file_info)
|
function.identifier, function.file_info)
|
||||||
|
@ -2588,7 +2634,43 @@ def semantics_analyzer(file: File) -> Context:
|
||||||
raise UnderDefinedConstantDefinition(child.file_info, None)
|
raise UnderDefinedConstantDefinition(child.file_info, None)
|
||||||
constants[child.identifier.value] = value
|
constants[child.identifier.value] = value
|
||||||
elif isinstance(child, Animation):
|
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):
|
elif isinstance(child, Graph):
|
||||||
pass
|
pass
|
||||||
if screen is None:
|
if screen is None:
|
||||||
|
|
Loading…
Reference in New Issue