def visitVarDef(self, node): # variables must be primitive type if node._type.is_array(): raise NodeError(node, 'Error: missing size for array definition') # cannot define void variables if node._type == self.tvoid: raise NodeError(node, 'Error: variable must be non-void') # Variable initialization must match variable type self.visit_children(node) self.check_type(node.value, node._type)
def visitAssignment(self, node): self.visit_children(node) # functions cannot be re-assigned if isinstance(node.ref.ty, FunType): raise NodeError(node, 'Error: cannot reassign function') # array pointers cannot be re-assigned if node.ref.ty.is_array(): raise NodeError(node, 'Error: cannot reassign array variable') # assigned value must match variable type self.check_type(node.value, node.ref.ty)
def visitReturn(self, node): # returned type must match function type self.visit_children(node) retty = self.curfn._type.return_type is_void = str(retty) == 'void' if node.value and is_void: raise NodeError(node.value, 'Error: void function must not return a value') elif node.value: self.check_type(node.value, retty) elif not is_void: raise NodeError(node, 'Error: non-void function must not return void')
def visitFunDef(self, node): # functions can only return basic types if node._type.return_type.is_array(): raise NodeError( node, 'Error: functions can only return basic type or void') self.curfn = node self.visit_children(node) self.curfn = None # a non-void function must return a value if node._type.return_type != self.tvoid: stat = node.body.statements if not len(stat) or not isinstance(stat[-1], Return): raise NodeError( node, 'Error: non-void function must end with return')
def visitFunCall(self, node): self.visit_children(node) funty = node.definition._type if not isinstance(funty, FunType): raise NodeError(node, 'Error: %s is not a function' % node.name) typed_args = node.args nargs = len(node.args) nparams = len(funty.params) defargs = (node.definition.location, 'Note: function is defined here') # number of arguments must match number of parameters in definition if funty.varargs: if nargs < nparams: raise BackrefError( node.location, 'Not enough arguments for varargs function', *defargs) typed_args = node.args[:len(funty.params)] elif nargs != nparams: errnode = node.args[nparams] if nargs > nparams else node raise BackrefError( errnode.location, 'Expected %d arguments, got %d' % (nparams, nargs), *defargs) # argument types must match defined parameter types for arg, param in zip(typed_args, funty.params): self.check_type(arg, param._type) # resulting expression has return type of function node.ty = funty.return_type
def visitGlobalDef(self, node): self.visit_children(node) # global definitions cannot be arrays or void if node._type.is_array(): raise NodeError(node, 'Error: global must have basic type') if node._type == self.tvoid: raise NodeError(node, 'Error: global must be non-void') # initializer must match global type self.check_type(node.value, node._type) # initializer must be constant if not isinstance(node.value, Const): raise NodeError(node.value, 'Error: global initializer must be constant')
def visitIndex(self, node): # array index must have int type, base must have array type self.visit_children(node) if not node.base.ty.is_array(): raise NodeError(node.base, 'Expected array type, got %s', node.base.ty) self.check_type(node.index, self.tint) node.ty = node.base.ty.base
def find_in_scope(self, node): for scope in reversed(self.scopes): if node.name in scope: #print('%s -> %s' % (node.name, repr(scope[node.name]))) node.definition = scope[node.name] return raise NodeError(node, 'Error: %s is undefined' % node.name)
def visitParam(self, node): # cannot define void parameters if str(node._type).startswith('void'): raise NodeError(node, 'Error: parameter must be non-void')
def visitGlobalDec(self, node): # cannot define void globals if str(node._type).startswith('void'): raise NodeError(node, 'Error: global must be non-void')
def check_type(self, node, *expected): if node.ty not in expected: raise NodeError(node, 'Type mismatch: expected %s, got %s', '/'.join(map(str, expected)), node.ty)
def visitContinue(self, node): #! added visitBreak if (self.loop_count <= 0): raise NodeError(node, 'Error: continue not in loop')
def visitBreak(self, node): #! added visitBreak if (self.loop_count <= 0): raise NodeError(node, 'Error: break not in loop')
def visitArrayDef(self, node): # cannot define void arrays if node._type.base == self.tvoid: raise NodeError(node, 'Error: array must be non-void') self.visit_children(node)
def visitContinue(self, node): if not self.in_loop: raise NodeError(node, 'Error: continue must be inside loop')
def visitBreak(self, node): if not self.in_loop: raise NodeError(node, 'Error: break must be inside loop')