|
@@ -9,18 +9,12 @@ from sccd.syntax.scope import *
|
|
|
class StaticTypeError(ModelError):
|
|
|
pass
|
|
|
|
|
|
-# to inspect types in Python 3.6 and 3.7, we rely on a backporting package
|
|
|
-# Python 3.8 already has this in its 'typing' module
|
|
|
-import sys
|
|
|
-if sys.version_info.minor < 8:
|
|
|
- from typing_inspect import get_args
|
|
|
-
|
|
|
class Expression(ABC):
|
|
|
# Must be called exactly once on each expression, before any call to eval is made.
|
|
|
# Determines the static type of the expression. May throw if there is a type error.
|
|
|
# Returns static type of expression.
|
|
|
@abstractmethod
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
pass
|
|
|
|
|
|
# Evaluation should NOT have side effects.
|
|
@@ -35,7 +29,7 @@ class Expression(ABC):
|
|
|
class LValue(Expression):
|
|
|
# Initialize the LValue as an LValue.
|
|
|
@abstractmethod
|
|
|
- def init_lvalue(self, scope: Scope, expected_type: type):
|
|
|
+ def init_lvalue(self, scope: Scope, expected_type: SCCDType):
|
|
|
pass
|
|
|
|
|
|
@abstractmethod
|
|
@@ -52,7 +46,7 @@ class Identifier(LValue):
|
|
|
name: str
|
|
|
variable: Optional[Variable] = None
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
# assert self.variable is None
|
|
|
self.variable = scope.get(self.name)
|
|
|
# print("init rvalue", self.name, "as", self.variable)
|
|
@@ -76,22 +70,23 @@ class FunctionCall(Expression):
|
|
|
|
|
|
type: Optional[type] = None
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
function_type = self.function.init_rvalue(scope)
|
|
|
- if not isinstance(function_type, Callable):
|
|
|
- raise StaticTypeError("Function call: Expression '%s' is not callable" % self.function.render())
|
|
|
- formal_types, return_type = get_args(function_type)
|
|
|
- self.type = return_type
|
|
|
+ if not isinstance(function_type, SCCDFunction):
|
|
|
+ raise StaticTypeError("Function call: Expression '%s' is not a function" % self.function.render())
|
|
|
+
|
|
|
+ formal_types = function_type.param_types
|
|
|
+ return_type = function_type.return_type
|
|
|
|
|
|
# We always secretly pass an EvalContext object with every function call
|
|
|
# Not visible to the user.
|
|
|
- assert formal_types[0] == EvalContext
|
|
|
+ # assert formal_types[0] == EvalContext
|
|
|
|
|
|
actual_types = [p.init_rvalue(scope) for p in self.params]
|
|
|
- for i, (formal, actual) in enumerate(zip(formal_types[1:], actual_types)):
|
|
|
+ for i, (formal, actual) in enumerate(zip(formal_types, actual_types)):
|
|
|
if formal != actual:
|
|
|
raise StaticTypeError("Function call, argument %d: %s is not expected type %s, instead is %s" % (i, self.params[i].render(), str(formal), str(actual)))
|
|
|
- return self.type
|
|
|
+ return return_type
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
|
f = self.function.eval(ctx)
|
|
@@ -118,14 +113,14 @@ class FunctionDeclaration(Expression):
|
|
|
body: 'Statement'
|
|
|
scope: Optional[Scope] = None
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
self.scope = Scope("function", scope)
|
|
|
# Reserve space for arguments on stack
|
|
|
for p in self.params_decl:
|
|
|
p.init_param(self.scope)
|
|
|
ret = self.body.init_stmt(self.scope)
|
|
|
return_type = ret.get_return_type()
|
|
|
- return Callable[[EvalContext,*[p.type for p in self.params_decl]], return_type]
|
|
|
+ return SCCDFunction([p.type for p in self.params_decl], return_type)
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
|
def FUNCTION(ctx: EvalContext, *params):
|
|
@@ -146,8 +141,8 @@ class FunctionDeclaration(Expression):
|
|
|
class StringLiteral(Expression):
|
|
|
string: str
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
- return str
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
+ return SCCDString
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
|
return self.string
|
|
@@ -160,8 +155,8 @@ class StringLiteral(Expression):
|
|
|
class IntLiteral(Expression):
|
|
|
i: int
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
- return int
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
+ return SCCDInt
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
|
return self.i
|
|
@@ -173,8 +168,8 @@ class IntLiteral(Expression):
|
|
|
class BoolLiteral(Expression):
|
|
|
b: bool
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
- return bool
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
+ return SCCDBool
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
|
return self.b
|
|
@@ -186,8 +181,8 @@ class BoolLiteral(Expression):
|
|
|
class DurationLiteral(Expression):
|
|
|
d: Duration
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
- return Duration
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
+ return SCCDDuration
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
|
return self.d
|
|
@@ -199,16 +194,16 @@ class DurationLiteral(Expression):
|
|
|
class Array(Expression):
|
|
|
elements: List[Any]
|
|
|
|
|
|
- type: Optional[type] = None
|
|
|
+ element_type: Optional[SCCDType] = None
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
for e in self.elements:
|
|
|
t = e.init_rvalue(scope)
|
|
|
- if self.type and self.type != t:
|
|
|
- raise StaticTypeError("Mixed element types in Array expression: %s and %s" % (str(self.type), str(t)))
|
|
|
- self.type = t
|
|
|
+ if self.element_type and self.element_type != t:
|
|
|
+ raise StaticTypeError("Mixed element types in Array expression: %s and %s" % (str(self.element_type), str(t)))
|
|
|
+ self.element_type = t
|
|
|
|
|
|
- return List[self.type]
|
|
|
+ return SCCDArray(self.element_type)
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
|
return [e.eval(ctx) for e in self.elements]
|
|
@@ -222,7 +217,7 @@ class Array(Expression):
|
|
|
class Group(Expression):
|
|
|
subexpr: Expression
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
return self.subexpr.init_rvalue(scope)
|
|
|
|
|
|
def eval(self, ctx: EvalContext):
|
|
@@ -237,13 +232,13 @@ class BinaryExpression(Expression):
|
|
|
operator: str # token name from the grammar.
|
|
|
rhs: Expression
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
lhs_t = self.lhs.init_rvalue(scope)
|
|
|
rhs_t = self.rhs.init_rvalue(scope)
|
|
|
|
|
|
def comparison_type():
|
|
|
same_type()
|
|
|
- return bool
|
|
|
+ return SCCDBool
|
|
|
|
|
|
def same_type():
|
|
|
if lhs_t != rhs_t:
|
|
@@ -255,15 +250,15 @@ class BinaryExpression(Expression):
|
|
|
if lhs_t == Duration:
|
|
|
raise StaticTypeError("Cannot multiply 'Duration' and 'Duration'")
|
|
|
return lhs_t
|
|
|
- key = lambda x: {int: 1, float: 2, Duration: 3}[x]
|
|
|
+ key = lambda x: {SCCDInt: 1, SCCDFloat: 2, SCCDDuration: 3}[x]
|
|
|
[smallest_type, largest_type] = sorted([lhs_t, rhs_t], key=key)
|
|
|
- if largest_type == Duration and smallest_type == float:
|
|
|
+ if largest_type == SCCDDuration and smallest_type == SCCDFloat:
|
|
|
raise StaticTypeError("Cannot multiply 'float' and 'Duration'")
|
|
|
return largest_type
|
|
|
|
|
|
return {
|
|
|
- "and": bool,
|
|
|
- "or": bool,
|
|
|
+ "and": SCCDBool,
|
|
|
+ "or": SCCDBool,
|
|
|
"==": comparison_type(),
|
|
|
"!=": comparison_type(),
|
|
|
">": comparison_type(),
|
|
@@ -273,7 +268,7 @@ class BinaryExpression(Expression):
|
|
|
"+": same_type(),
|
|
|
"-": same_type(),
|
|
|
"*": mult_type(),
|
|
|
- "/": float,
|
|
|
+ "/": SCCDFloat,
|
|
|
"//": same_type(),
|
|
|
"%": same_type(),
|
|
|
"**": same_type(),
|
|
@@ -307,10 +302,10 @@ class UnaryExpression(Expression):
|
|
|
operator: str # token value from the grammar.
|
|
|
expr: Expression
|
|
|
|
|
|
- def init_rvalue(self, scope: Scope) -> type:
|
|
|
+ def init_rvalue(self, scope: Scope) -> SCCDType:
|
|
|
expr_type = self.expr.init_rvalue(scope)
|
|
|
return {
|
|
|
- "not": bool,
|
|
|
+ "not": SCCDBool,
|
|
|
"-": expr_type,
|
|
|
}[self.operator]
|
|
|
|