expression.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. from abc import *
  2. from typing import *
  3. from dataclasses import *
  4. from sccd.util.duration import *
  5. from sccd.util.visitable import *
  6. from sccd.action_lang.static.scope import *
  7. class MemoryInterface(ABC):
  8. @abstractmethod
  9. def current_frame(self) -> 'StackFrame':
  10. pass
  11. @abstractmethod
  12. def push_frame(self, scope: Scope):
  13. pass
  14. @abstractmethod
  15. def push_frame_w_context(self, scope: Scope, context: 'StackFrame'):
  16. pass
  17. @abstractmethod
  18. def pop_frame(self):
  19. pass
  20. @abstractmethod
  21. def load(self, offset: int) -> Any:
  22. pass
  23. @abstractmethod
  24. def store(self, offset: int, value: Any):
  25. pass
  26. # Thrown if the type checker encountered something illegal.
  27. # Not to be confused with Python's TypeError exception.
  28. class StaticTypeError(ModelStaticError):
  29. pass
  30. class Expression(ABC, Visitable):
  31. # Run static analysis on the expression.
  32. # Must be called exactly once on each expression, before any call to eval is made.
  33. # Determines the static type of the expression. May throw if there is a type error.
  34. # Returns static type of expression.
  35. @abstractmethod
  36. def init_expr(self, scope: Scope) -> SCCDType:
  37. pass
  38. # Evaluate the expression.
  39. # Evaluation may have side effects.
  40. @abstractmethod
  41. def eval(self, memory: MemoryInterface):
  42. pass
  43. @abstractmethod
  44. def render(self) -> str:
  45. pass
  46. # The LValue type is any type that can serve as an expression OR an LValue (left hand of assignment)
  47. # Either 'init_expr' or 'init_lvalue' is called to initialize the LValue.
  48. # Then either 'eval' or 'eval_lvalue' can be called any number of times.
  49. class LValue(Expression):
  50. # Initialize the LValue as an LValue.
  51. # Returns whether LValue was initialized, or just re-assigned another value.
  52. @abstractmethod
  53. def init_lvalue(self, scope: Scope, rhs_t: SCCDType, rhs: Expression) -> bool:
  54. pass
  55. # Should return offset relative to current context stack frame.
  56. # offset ∈ [0, +∞[ : variable's memory address is within current scope
  57. # offset ∈ ]-∞, 0[ : variable's memory address is in a parent scope (or better: 'context scope')
  58. @abstractmethod
  59. def assign(self, memory: MemoryInterface, value: Any):
  60. pass
  61. @dataclass
  62. class Identifier(LValue):
  63. name: str
  64. offset: Optional[int] = None
  65. def init_expr(self, scope: Scope) -> SCCDType:
  66. self.offset, type = scope.get_rvalue(self.name)
  67. return type
  68. def init_lvalue(self, scope: Scope, rhs_t: SCCDType, rhs: Expression) -> bool:
  69. self.offset, is_init = scope.put_lvalue(self.name, rhs_t, rhs)
  70. return is_init
  71. def assign(self, memory: MemoryInterface, value: Any):
  72. memory.store(self.offset, value)
  73. def eval(self, memory: MemoryInterface):
  74. return memory.load(self.offset)
  75. def render(self):
  76. return self.name
  77. @dataclass
  78. class FunctionCall(Expression):
  79. function: Expression
  80. params: List[Expression]
  81. def init_expr(self, scope: Scope) -> SCCDType:
  82. function_type = self.function.init_expr(scope)
  83. if not isinstance(function_type, SCCDFunction):
  84. raise StaticTypeError("Function call: Expression '%s' is not a function" % self.function.render())
  85. formal_types = function_type.param_types
  86. return_type = function_type.return_type
  87. actual_types = [p.init_expr(scope) for p in self.params]
  88. if len(formal_types) != len(actual_types):
  89. raise StaticTypeError("Function call, expected %d arguments, but %d were given." % (len(formal_types), len(actual_types)))
  90. for i, (formal, actual) in enumerate(zip(formal_types, actual_types)):
  91. if formal != actual:
  92. raise StaticTypeError("Function call, argument %d: %s is not expected type %s, instead is %s" % (i, self.params[i].render(), str(formal), str(actual)))
  93. return return_type
  94. def eval(self, memory: MemoryInterface):
  95. f = self.function.eval(memory)
  96. p = [p.eval(memory) for p in self.params]
  97. return f(memory, *p)
  98. def render(self):
  99. return self.function.render()+'('+','.join([p.render() for p in self.params])+')'
  100. # Used in EventDecl and FunctionDeclaration
  101. @dataclass
  102. class ParamDecl(Visitable):
  103. name: str
  104. formal_type: SCCDType
  105. offset: Optional[int] = None
  106. def init_param(self, scope: Scope):
  107. self.offset = scope.declare(self.name, self.formal_type)
  108. def render(self):
  109. return self.name + ":" + str(self.formal_type)
  110. @dataclass
  111. class FunctionDeclaration(Expression):
  112. params_decl: List[ParamDecl]
  113. body: 'Statement'
  114. scope: Optional[Scope] = None
  115. def init_expr(self, scope: Scope) -> SCCDType:
  116. self.scope = Scope("function", scope)
  117. # Reserve space for arguments on stack
  118. for p in self.params_decl:
  119. p.init_param(self.scope)
  120. ret = self.body.init_stmt(self.scope)
  121. return_type = ret.get_return_type()
  122. return SCCDFunction([p.formal_type for p in self.params_decl], return_type)
  123. def eval(self, memory: MemoryInterface):
  124. context: 'StackFrame' = memory.current_frame()
  125. def FUNCTION(memory: MemoryInterface, *params):
  126. memory.push_frame_w_context(self.scope, context)
  127. # Copy arguments to stack
  128. for val, p in zip(params, self.params_decl):
  129. memory.store(p.offset, val)
  130. ret = self.body.exec(memory)
  131. memory.pop_frame()
  132. return ret.val
  133. return FUNCTION
  134. def render(self) -> str:
  135. return "func(%s) [...]" % ", ".join(p.render() for p in self.params_decl) # todo
  136. @dataclass
  137. class ArrayIndexed(LValue):
  138. array: Expression
  139. index: Expression
  140. def init_expr(self, scope: Scope) -> SCCDType:
  141. array_type = self.array.init_expr(scope)
  142. if not isinstance(array_type, SCCDArray):
  143. raise StaticTypeError("Array indexation: Expression '%s' is not an array" % self.array.render())
  144. index_type = self.index.init_expr(scope)
  145. if index_type is not SCCDInt:
  146. raise StaticTypeError("Array indexation: Expression '%s' is not an integer" % self.index_type.render())
  147. return array_type.element_type
  148. def init_lvalue(self, scope: Scope, rhs_t: SCCDType, rhs: Expression) -> bool:
  149. if not isinstance(self.array, LValue):
  150. raise StaticTypeError("Array indexation as LValue: Expression '%s' must be an LValue" % self.array.render())
  151. return self.array.init_lvalue(scope, SCCDArray(element_type=type), rhs)
  152. def assign(self, memory: MemoryInterface, value):
  153. self.array.eval(memory)[self.index.eval(memory)] = value
  154. def render(self):
  155. return self.name
  156. def eval(self, memory: MemoryInterface):
  157. index = self.index.eval()
  158. return array.eval(memory)[index]
  159. def render(self):
  160. return self.array.render() + '[' + self.index.render() + ']'
  161. @dataclass
  162. class StringLiteral(Expression):
  163. string: str
  164. def init_expr(self, scope: Scope) -> SCCDType:
  165. return SCCDString
  166. def eval(self, memory: MemoryInterface):
  167. return self.string
  168. def render(self):
  169. return '"'+self.string+'"'
  170. @dataclass
  171. class IntLiteral(Expression):
  172. i: int
  173. def init_expr(self, scope: Scope) -> SCCDType:
  174. return SCCDInt
  175. def eval(self, memory: MemoryInterface):
  176. return self.i
  177. def render(self):
  178. return str(self.i)
  179. @dataclass
  180. class FloatLiteral(Expression):
  181. f: float
  182. def init_expr(self, scope: Scope) -> SCCDType:
  183. return SCCDFloat
  184. def eval(self, memory: MemoryInterface):
  185. return self.f
  186. def render(self):
  187. return str(self.f)
  188. @dataclass
  189. class BoolLiteral(Expression):
  190. b: bool
  191. def init_expr(self, scope: Scope) -> SCCDType:
  192. return SCCDBool
  193. def eval(self, memory: MemoryInterface):
  194. return self.b
  195. def render(self):
  196. return "true" if self.b else "false"
  197. @dataclass
  198. class DurationLiteral(Expression):
  199. d: Duration
  200. def init_expr(self, scope: Scope) -> SCCDType:
  201. return SCCDDuration
  202. def eval(self, memory: MemoryInterface):
  203. return self.d
  204. def render(self):
  205. return str(self.d)
  206. @dataclass
  207. class Array(Expression):
  208. elements: List[Any]
  209. element_type: Optional[SCCDType] = None
  210. def init_expr(self, scope: Scope) -> SCCDType:
  211. for e in self.elements:
  212. t = e.init_expr(scope)
  213. if self.element_type and self.element_type != t:
  214. raise StaticTypeError("Mixed element types in Array expression: %s and %s" % (str(self.element_type), str(t)))
  215. self.element_type = t
  216. return SCCDArray(self.element_type)
  217. def eval(self, memory: MemoryInterface):
  218. return [e.eval(memory) for e in self.elements]
  219. def render(self):
  220. return '['+','.join([e.render() for e in self.elements])+']'
  221. # Does not add anything semantically, but ensures that when rendering an expression,
  222. # the parenthesis are not lost
  223. @dataclass
  224. class Group(Expression):
  225. subexpr: Expression
  226. def init_expr(self, scope: Scope) -> SCCDType:
  227. return self.subexpr.init_expr(scope)
  228. def eval(self, memory: MemoryInterface):
  229. return self.subexpr.eval(memory)
  230. def render(self):
  231. return '('+self.subexpr.render()+')'
  232. @dataclass
  233. class BinaryExpression(Expression):
  234. lhs: Expression
  235. operator: str # token name from the grammar.
  236. rhs: Expression
  237. def init_expr(self, scope: Scope) -> SCCDType:
  238. lhs_t = self.lhs.init_expr(scope)
  239. rhs_t = self.rhs.init_expr(scope)
  240. def logical():
  241. if lhs_t.is_bool_castable() and rhs_t.is_bool_castable():
  242. return SCCDBool
  243. def eq():
  244. if lhs_t.is_eq(rhs_t):
  245. return SCCDBool
  246. def ord():
  247. if lhs_t.is_ord(rhs_t):
  248. return SCCDBool
  249. def sum():
  250. if lhs_t.is_summable(rhs_t):
  251. return lhs_t
  252. def mult():
  253. return lhs_t.mult(rhs_t)
  254. def div():
  255. return lhs_t.div(rhs_t)
  256. def floordiv():
  257. return lhs_t.floordiv(rhs_t)
  258. def exp():
  259. return lhs_t.exp(rhs_t)
  260. t = {
  261. "and": logical,
  262. "or": logical,
  263. "==": eq,
  264. "!=": eq,
  265. ">": ord,
  266. ">=": ord,
  267. "<": ord,
  268. "<=": ord,
  269. "+": sum,
  270. "-": sum,
  271. "*": mult,
  272. "/": div,
  273. "//": floordiv,
  274. "%": floordiv,
  275. "**": exp,
  276. }[self.operator]()
  277. if t is None:
  278. raise StaticTypeError("Illegal types for '%s'-operation: %s and %s" % (self.operator, lhs_t, rhs_t))
  279. return t
  280. def eval(self, memory: MemoryInterface):
  281. return {
  282. "and": lambda x,y: x and y.eval(memory),
  283. "or": lambda x,y: x or y.eval(memory),
  284. "==": lambda x,y: x == y.eval(memory),
  285. "!=": lambda x,y: x != y.eval(memory),
  286. ">": lambda x,y: x > y.eval(memory),
  287. ">=": lambda x,y: x >= y.eval(memory),
  288. "<": lambda x,y: x < y.eval(memory),
  289. "<=": lambda x,y: x <= y.eval(memory),
  290. "+": lambda x,y: x + y.eval(memory),
  291. "-": lambda x,y: x - y.eval(memory),
  292. "*": lambda x,y: x * y.eval(memory),
  293. "/": lambda x,y: x / y.eval(memory),
  294. "//": lambda x,y: x // y.eval(memory),
  295. "%": lambda x,y: x % y.eval(memory),
  296. "**": lambda x,y: x ** y.eval(memory),
  297. }[self.operator](self.lhs.eval(memory), self.rhs) # Borrow Python's lazy evaluation
  298. def render(self):
  299. return self.lhs.render() + ' ' + self.operator + ' ' + self.rhs.render()
  300. @dataclass
  301. class UnaryExpression(Expression):
  302. operator: str # token value from the grammar.
  303. expr: Expression
  304. def init_expr(self, scope: Scope) -> SCCDType:
  305. expr_type = self.expr.init_expr(scope)
  306. def logical():
  307. if expr_type.is_bool_castable():
  308. return SCCDBool
  309. def neg():
  310. if expr_type.is_neg():
  311. return expr_type
  312. t = {
  313. "not": logical,
  314. "-": neg,
  315. }[self.operator]()
  316. if t is None:
  317. raise StaticTypeError("Illegal type for unary '%s'-expression: %s" % (self.operator, expr_type))
  318. return t
  319. def eval(self, memory: MemoryInterface):
  320. return {
  321. "not": lambda x: not x.eval(memory),
  322. "-": lambda x: - x.eval(memory),
  323. }[self.operator](self.expr)
  324. def render(self):
  325. return self.operator + ' ' + self.expr.render()