expression.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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. # Returns static type of expression.
  39. @abstractmethod
  40. def get_type(self) -> SCCDType:
  41. pass
  42. # Evaluate the expression.
  43. # Evaluation may have side effects.
  44. @abstractmethod
  45. def eval(self, memory: MemoryInterface):
  46. pass
  47. @abstractmethod
  48. def render(self) -> str:
  49. pass
  50. # The LValue type is any type that can serve as an expression OR an LValue (left hand of assignment)
  51. # Either 'init_expr' or 'init_lvalue' is called to initialize the LValue.
  52. # Then either 'eval' or 'eval_lvalue' can be called any number of times.
  53. class LValue(Expression):
  54. # Initialize the LValue as an LValue.
  55. # Returns whether LValue was initialized, or just re-assigned another value.
  56. @abstractmethod
  57. def init_lvalue(self, scope: Scope, rhs_t: SCCDType, rhs: Expression) -> bool:
  58. pass
  59. # Should return offset relative to current context stack frame.
  60. # offset ∈ [0, +∞[ : variable's memory address is within current scope
  61. # offset ∈ ]-∞, 0[ : variable's memory address is in a parent scope (or better: 'context scope')
  62. @abstractmethod
  63. def assign(self, memory: MemoryInterface, value: Any):
  64. pass
  65. @dataclass
  66. class Identifier(LValue):
  67. name: str
  68. offset: Optional[int] = None
  69. type: Optional[SCCDType] = None
  70. is_lvalue: Optional[bool] = None
  71. is_init: Optional[bool] = None
  72. def init_expr(self, scope: Scope) -> SCCDType:
  73. self.offset, self.type = scope.get_rvalue(self.name)
  74. self.is_init = False
  75. self.is_lvalue = False
  76. return self.type
  77. def get_type(self) -> SCCDType:
  78. return self.type
  79. def init_lvalue(self, scope: Scope, rhs_t: SCCDType, rhs: Expression) -> bool:
  80. self.is_lvalue = True
  81. self.offset, self.is_init = scope.put_lvalue(self.name, rhs_t, rhs)
  82. return self.is_init
  83. def assign(self, memory: MemoryInterface, value: Any):
  84. memory.store(self.offset, value)
  85. def eval(self, memory: MemoryInterface):
  86. return memory.load(self.offset)
  87. def render(self):
  88. return self.name
  89. @dataclass
  90. class FunctionCall(Expression):
  91. function: Expression # an identifier, or another function call
  92. params: List[Expression]
  93. return_type: Optional[SCCDType] = None
  94. function_being_called: Optional['FunctionDeclaration'] = None
  95. def init_expr(self, scope: Scope) -> SCCDType:
  96. function_type = self.function.init_expr(scope)
  97. # A FunctionCall can be a call on a regular function, or a closure object
  98. if isinstance(function_type, SCCDClosureObject):
  99. # For static analysis, we treat calls on closure objects just like calls on regular functions.
  100. function_type = function_type.function_type
  101. if not isinstance(function_type, SCCDFunction):
  102. raise StaticTypeError("Function call: Expression '%s' is not a function" % self.function.render())
  103. self.function_being_called = function_type.function
  104. formal_types = function_type.param_types
  105. self.return_type = function_type.return_type
  106. actual_types = [p.init_expr(scope) for p in self.params]
  107. if len(formal_types) != len(actual_types):
  108. raise StaticTypeError("Function call, expected %d arguments, but %d were given." % (len(formal_types), len(actual_types)))
  109. for i, (formal, actual) in enumerate(zip(formal_types, actual_types)):
  110. if formal != actual:
  111. raise StaticTypeError("Function call, argument %d: %s is not expected type %s, instead is %s" % (i, self.params[i].render(), str(formal), str(actual)))
  112. # The type of a function call is the return type of the function called
  113. return self.return_type
  114. def get_type(self) -> SCCDType:
  115. return self.return_type
  116. def eval(self, memory: MemoryInterface):
  117. f = self.function.eval(memory)
  118. p = [p.eval(memory) for p in self.params]
  119. return f(memory, *p)
  120. def render(self):
  121. return self.function.render()+'('+','.join([p.render() for p in self.params])+')'
  122. # Used in EventDecl and FunctionDeclaration
  123. @dataclass
  124. class ParamDecl(Visitable):
  125. name: str
  126. formal_type: SCCDType
  127. offset: Optional[int] = None
  128. def init_param(self, scope: Scope):
  129. self.offset = scope.declare(self.name, self.formal_type)
  130. def render(self):
  131. return self.name + ":" + str(self.formal_type)
  132. @dataclass(eq=False) # eq=False: make it hashable (plus, we don't need auto eq)
  133. class FunctionDeclaration(Expression):
  134. params_decl: List[ParamDecl]
  135. body: 'Statement'
  136. scope: Optional[Scope] = None
  137. return_type: Optional[SCCDType] = None
  138. type: Optional[SCCDFunction] = None
  139. def init_expr(self, scope: Scope) -> SCCDType:
  140. self.scope = Scope("function", scope)
  141. # Reserve space for arguments on stack
  142. for p in self.params_decl:
  143. p.init_param(self.scope)
  144. ret = self.body.init_stmt(self.scope)
  145. self.return_type = ret.get_return_type()
  146. if isinstance(self.return_type, SCCDFunction) and self.return_type.function.scope.parent is self.scope:
  147. # Called function returns a closure object
  148. self.return_type = SCCDClosureObject(self.scope, function_type=self.return_type)
  149. self.type = SCCDFunction([p.formal_type for p in self.params_decl], self.return_type, function=self)
  150. return self.type
  151. def get_type(self) -> SCCDType:
  152. return self.type
  153. def eval(self, memory: MemoryInterface):
  154. context: 'StackFrame' = memory.current_frame()
  155. def FUNCTION(memory: MemoryInterface, *params):
  156. memory.push_frame_w_context(self.scope, context)
  157. # Copy arguments to stack
  158. for val, p in zip(params, self.params_decl):
  159. memory.store(p.offset, val)
  160. ret = self.body.exec(memory)
  161. memory.pop_frame()
  162. return ret.val
  163. return FUNCTION
  164. def render(self) -> str:
  165. return "func(%s) [...]" % ", ".join(p.render() for p in self.params_decl) # todo
  166. @dataclass
  167. class ArrayIndexed(LValue):
  168. array: Expression
  169. index: Expression
  170. def init_expr(self, scope: Scope) -> SCCDType:
  171. array_type = self.array.init_expr(scope)
  172. if not isinstance(array_type, SCCDArray):
  173. raise StaticTypeError("Array indexation: Expression '%s' is not an array" % self.array.render())
  174. index_type = self.index.init_expr(scope)
  175. if index_type is not SCCDInt:
  176. raise StaticTypeError("Array indexation: Expression '%s' is not an integer" % self.index_type.render())
  177. return array_type.element_type
  178. def get_type(self) -> SCCDType:
  179. return self.array.get_type().element_type
  180. def init_lvalue(self, scope: Scope, rhs_t: SCCDType, rhs: Expression) -> bool:
  181. if not isinstance(self.array, LValue):
  182. raise StaticTypeError("Array indexation as LValue: Expression '%s' must be an LValue" % self.array.render())
  183. return self.array.init_lvalue(scope, SCCDArray(element_type=type), rhs)
  184. def assign(self, memory: MemoryInterface, value):
  185. self.array.eval(memory)[self.index.eval(memory)] = value
  186. def render(self):
  187. return self.name
  188. def eval(self, memory: MemoryInterface):
  189. index = self.index.eval()
  190. return array.eval(memory)[index]
  191. def render(self):
  192. return self.array.render() + '[' + self.index.render() + ']'
  193. @dataclass
  194. class StringLiteral(Expression):
  195. string: str
  196. def init_expr(self, scope: Scope) -> SCCDType:
  197. return SCCDString
  198. def get_type(self) -> SCCDType:
  199. return SCCDString
  200. def eval(self, memory: MemoryInterface):
  201. return self.string
  202. def render(self):
  203. return '"'+self.string+'"'
  204. @dataclass
  205. class IntLiteral(Expression):
  206. i: int
  207. def init_expr(self, scope: Scope) -> SCCDType:
  208. return SCCDInt
  209. def get_type(self) -> SCCDType:
  210. return SCCDInt
  211. def eval(self, memory: MemoryInterface):
  212. return self.i
  213. def render(self):
  214. return str(self.i)
  215. @dataclass
  216. class FloatLiteral(Expression):
  217. f: float
  218. def init_expr(self, scope: Scope) -> SCCDType:
  219. return SCCDFloat
  220. def get_type(self) -> SCCDType:
  221. return SCCDFloat
  222. def eval(self, memory: MemoryInterface):
  223. return self.f
  224. def render(self):
  225. return str(self.f)
  226. @dataclass
  227. class BoolLiteral(Expression):
  228. b: bool
  229. def init_expr(self, scope: Scope) -> SCCDType:
  230. return SCCDBool
  231. def get_type(self) -> SCCDType:
  232. return SCCDBool
  233. def eval(self, memory: MemoryInterface):
  234. return self.b
  235. def render(self):
  236. return "true" if self.b else "false"
  237. @dataclass
  238. class DurationLiteral(Expression):
  239. d: Duration
  240. def init_expr(self, scope: Scope) -> SCCDType:
  241. return SCCDDuration
  242. def get_type(self) -> SCCDType:
  243. return SCCDDuration
  244. def eval(self, memory: MemoryInterface):
  245. return self.d
  246. def render(self):
  247. return str(self.d)
  248. @dataclass
  249. class Array(Expression):
  250. elements: List[Any]
  251. element_type: Optional[SCCDType] = None
  252. def init_expr(self, scope: Scope) -> SCCDType:
  253. for e in self.elements:
  254. t = e.init_expr(scope)
  255. if self.element_type and self.element_type != t:
  256. raise StaticTypeError("Mixed element types in Array expression: %s and %s" % (str(self.element_type), str(t)))
  257. self.element_type = t
  258. return SCCDArray(self.element_type)
  259. def get_type(self) -> SCCDType:
  260. return SCCDArray(self.element_type)
  261. def eval(self, memory: MemoryInterface):
  262. return [e.eval(memory) for e in self.elements]
  263. def render(self):
  264. return '['+','.join([e.render() for e in self.elements])+']'
  265. # A group of parentheses in the concrete syntax.
  266. # Does not add anything semantically, but allows us to go back from abstract to concrete textual syntax without weird rules
  267. @dataclass
  268. class Group(Expression):
  269. subexpr: Expression
  270. def init_expr(self, scope: Scope) -> SCCDType:
  271. return self.subexpr.init_expr(scope)
  272. def get_type(self) -> SCCDType:
  273. return self.subexpr.get_type()
  274. def eval(self, memory: MemoryInterface):
  275. return self.subexpr.eval(memory)
  276. def render(self):
  277. return '('+self.subexpr.render()+')'
  278. @dataclass
  279. class BinaryExpression(Expression):
  280. lhs: Expression
  281. operator: str # token name from the grammar.
  282. rhs: Expression
  283. type: Optional[SCCDType] = None
  284. def init_expr(self, scope: Scope) -> SCCDType:
  285. lhs_t = self.lhs.init_expr(scope)
  286. rhs_t = self.rhs.init_expr(scope)
  287. def logical():
  288. if lhs_t.is_bool_castable() and rhs_t.is_bool_castable():
  289. return SCCDBool
  290. def eq():
  291. if lhs_t.is_eq(rhs_t):
  292. return SCCDBool
  293. def ord():
  294. if lhs_t.is_ord(rhs_t):
  295. return SCCDBool
  296. def sum():
  297. if lhs_t.is_summable(rhs_t):
  298. return lhs_t
  299. def mult():
  300. return lhs_t.mult(rhs_t)
  301. def div():
  302. return lhs_t.div(rhs_t)
  303. def floordiv():
  304. return lhs_t.floordiv(rhs_t)
  305. def exp():
  306. return lhs_t.exp(rhs_t)
  307. self.type = {
  308. "and": logical,
  309. "or": logical,
  310. "==": eq,
  311. "!=": eq,
  312. ">": ord,
  313. ">=": ord,
  314. "<": ord,
  315. "<=": ord,
  316. "+": sum,
  317. "-": sum,
  318. "*": mult,
  319. "/": div,
  320. "//": floordiv,
  321. "%": floordiv,
  322. "**": exp,
  323. }[self.operator]()
  324. if self.type is None:
  325. raise StaticTypeError("Illegal types for '%s'-operation: %s and %s" % (self.operator, lhs_t, rhs_t))
  326. return self.type
  327. def get_type(self) -> SCCDType:
  328. return self.type
  329. def eval(self, memory: MemoryInterface):
  330. return {
  331. "and": lambda x,y: x and y.eval(memory),
  332. "or": lambda x,y: x or y.eval(memory),
  333. "==": lambda x,y: x == y.eval(memory),
  334. "!=": lambda x,y: x != y.eval(memory),
  335. ">": lambda x,y: x > y.eval(memory),
  336. ">=": lambda x,y: x >= y.eval(memory),
  337. "<": lambda x,y: x < y.eval(memory),
  338. "<=": lambda x,y: x <= y.eval(memory),
  339. "+": lambda x,y: x + y.eval(memory),
  340. "-": lambda x,y: x - y.eval(memory),
  341. "*": lambda x,y: x * y.eval(memory),
  342. "/": lambda x,y: x / y.eval(memory),
  343. "//": lambda x,y: x // y.eval(memory),
  344. "%": lambda x,y: x % y.eval(memory),
  345. "**": lambda x,y: x ** y.eval(memory),
  346. }[self.operator](self.lhs.eval(memory), self.rhs) # Borrow Python's lazy evaluation
  347. def render(self):
  348. return self.lhs.render() + ' ' + self.operator + ' ' + self.rhs.render()
  349. @dataclass
  350. class UnaryExpression(Expression):
  351. operator: str # token value from the grammar.
  352. expr: Expression
  353. type: Optional[SCCDType] = None
  354. def init_expr(self, scope: Scope) -> SCCDType:
  355. expr_type = self.expr.init_expr(scope)
  356. def logical():
  357. if expr_type.is_bool_castable():
  358. return SCCDBool
  359. def neg():
  360. if expr_type.is_neg():
  361. return expr_type
  362. self.type = {
  363. "not": logical,
  364. "-": neg,
  365. }[self.operator]()
  366. if self.type is None:
  367. raise StaticTypeError("Illegal type for unary '%s'-expression: %s" % (self.operator, expr_type))
  368. return self.type
  369. def get_type(self) -> SCCDType:
  370. return self.type
  371. def eval(self, memory: MemoryInterface):
  372. return {
  373. "not": lambda x: not x.eval(memory),
  374. "-": lambda x: - x.eval(memory),
  375. }[self.operator](self.expr)
  376. def render(self):
  377. return self.operator + ' ' + self.expr.render()