def check_range(self): # These violations of the Law of Demeter make me queasy. lower_bound = self.ast().range().lower() upper_bound = self.ast().range().upper() if not lower_bound < upper_bound: msg = 'lower bound {} must < upper bound {}' raise SemanticError(msg.format(lower_bound, upper_bound)) return True
def __init__(self, modifs, ret_type, name, params, body, ts, localts=None): super(mjMethod, self).__init__() self.modifs = modifs self.ret_type = ret_type self.name = name self.params = params self.processed_params = [] self.body = body # hack self._modifiable = mjModifiable() self._modifiable.modifs = self.modifs self.isStatic = self._modifiable.isStatic self.isPublic = self._modifiable.isPublic self.isProtected = self._modifiable.isProtected self.ts = localts if localts is None: self.ts = mjTS(ts) self.ts.set_owner(self) if not ts is None: if not ts.addMethod(self): raise SemanticError(self.name.get_line(), self.name.get_col(), "Redefinicion de metodo.") param_offset = 3 if not self.isStatic(): param_offset = 4 param_offset = len(self.params) + param_offset for (t, v) in self.params: param_offset -= 1 var = mjVariable(t, v, ts=self.ts) var.offset = param_offset self.processed_params.append(var) if not self.ts.addVar(var): raise SemanticError( v.get_line(), v.get_col(), "%s ya esta definido como parametro" % v.get_lexeme()) self.create_block_ts() self.body.set_owning_method(self)
def check_type(self, t): if t.get_type() in FIRST_primitive_type: return if t.get_type() == VOID_TYPE: return if not self.ts.parent().parent().typeExists(t.get_lexeme()): raise SemanticError( t.get_line(), t.get_col(), "No existe ninguna clase llamada %s" % t.get_lexeme())
def solve_extends(self): if not self.ext_name is None: (valid, ref) = self.ts.parent().validExtend(self.ext_name) # copiamos para mantener los offsets de esta clase en particular self.ext_class = ref if not valid: raise SemanticError(self.ext_name.get_line(), self.ext_name.get_col(), "No existe la clase padre")
def check(self): self.check_type() self.check_modifs() for v, i in self.list_ids: if not i is None: i.check() if not i.compatibleWith(self.type): raise SemanticError(v.get_line(), v.get_col(), "Inicializacion de tipo incompatible") return ""
def resolve_names(self, scope): if not self.decls: raise SemanticError('no "main" function in a program', *self.eof.get_char_info()) for decl in self.decls: scope.add(decl.name, decl) if 'main' not in scope.members.keys(): # todo is it correct to show token pos of last decl name? semantic_error3('no "main" function in a program', decl.name) for decl in self.decls: decl.resolve_names(scope)
def hasMain(self): mains = [] for clstr in self._sections["classes"]: cl = self.getType(clstr) if "main" in cl.ts._sections["methods"].keys(): ms = cl.ts._sections["methods"]["main"] for m in ms: if len(m.params) == 0 and \ m.isStatic() and \ m.isPublic(): mains.append(m) if len(mains) == 0: raise SemanticError(0,0, "No existe ningun metodo static void main()") if len(mains) > 1: raise SemanticError(0,0, "Existen mas de un metodo static void main()") return mains[0].label
def check(self): code = "rmem %d\n" % len(self.args) for v, e in self.args: if not e is None: code += e.check() if not e.compatibleWith(self.ref): raise SemanticError(v.get_line(), v.get_col(), "Inicializacion de tipo incompatible") var = mjVariable(self.ref, v, e, self.ts) if not self.ts.addVar(var): raise SemanticError(v.get_line(), v.get_col(), "Variable redefinida") var.offset = self.offset self.offset -= 1 if not e is None: code += "dup\n" code += "store %d ; offset a %s \n" % (var.offset, var.name.get_lexeme()) code += "pop\n" return code
def check(self): e = self.expr.resolve() if mjp.isToken(e): if mjp.literalToType(e.get_type()) != BOOLEAN_TYPE: raise SemanticError(e.get_line(), e.get_col(), "La expresion debe ser de tipo boolean") elif isVariable(e): if e.type.get_type() != BOOLEAN_TYPE: raise SemanticError(e.name.get_line(), e.name.get_col(), "La expresion debe ser de tipo boolean") elif isMethod(e): if e.is_constructor() or e.ret_type.get_type() != BOOLEAN_TYPE: raise SemanticError(self.expr.ref.get_line(), self.expr.ref.get_col(), "La expresion debe ser de tipo boolean") else: raise Exception() rand = "".join( random.choice(string.letters + string.digits) for i in xrange(10)) label_true = "if_true_%s" % rand label_false = "if_false_%s" % rand label_end = "else_false_%s" % rand self.expr.label_cc_true = label_true self.expr.label_cc_false = label_false code = self.expr.check() code += "bf %s\n" % label_false code += "%s: nop\n" % label_true code += self.stat.check() code += "jump %s\n" % label_end code += "%s: nop\n" % label_false if not self.elsestat is None: code += self.elsestat.check() code += "%s: nop\n" % label_end return code
def check(self): if self.method.is_constructor(): if not self.expr is None: raise SemanticError( self.ret.get_line(), self.ret.get_col(), "Los return en constructores no deben retornar valores") else: return "" if self.expr is None: if self.method.ret_type.get_type() != VOID_TYPE: raise SemanticError( self.ret.get_line(), self.ret.get_col(), "La sentencia return debe contener una expresion de tipo %s" % self.method.ret_type.get_lexeme()) else: t = self.expr.resolve() #raise Exception("Checkear compatibilidad de herencia tambien!") if mjp.isToken(t): rt = mjp.literalToType(t.get_type()) if rt != self.method.ret_type.get_type(): raise SemanticError( self.ret.get_line(), self.ret.get_col(), "Se esta retornando %s en un metodo de tipo %s" % (mjp.typeToStr(rt), self.method.ret_type.get_lexeme())) else: if t.type.get_lexeme() != self.method.ret_type.get_lexeme(): raise SemanticError( self.ret.get_line(), self.ret.get_col(), "Se esta retornando %s en un metodo de tipo %s" % (t.type.get_lexeme(), self.method.ret_type.get_lexeme())) offset = 3 if self.method.isStatic(): offset = 2 # no hay this return self.expr.check() + "store %d ; offset a ret_val\n" % ( offset + len(self.method.params) + 1) return ""
def __init__(self, modifs, t, list_ids, ts): super(mjClassVariableDecl, self).__init__() self.modifs = modifs self.type = t self.list_ids = list_ids self.ts = ts for v, i in self.list_ids: var = mjClassVariable(self.type, v, i, self.modifs, self.ts) if not i is None: i.set_ts(ts) i.set_var(var) if not self.ts.addVar(var): raise SemanticError(v.get_line(), v.get_col(), "Variable redefinida")
def raise_error(self, message): print(SemanticError(message))
def error(self, error_code, token): raise SemanticError(error_code=error_code, token=token, message=f"{error_code.value} -> {token}")
def getType(self, v): if not v in self._sections["classes"]: raise SemanticError(0,0, "No existe ningun tipo llamado %s" % v) return self._sections["classes"][v]
def check_type(self, parent): if parent.type: return parent.type core = None if isinstance(parent.core, tuple): core = parent.core[1] else: core = parent.core if core in self.__rules['rules']: if self.__rules['rules'][core]['final']: parent.type = self.__rules['rules'][core]['type'] return parent.type else: rule = self.__rules['rules'][core]['options'][parent.rule] if core == ':declaration': identifier = None type_check = self.check_type(parent.children[rule[0]]) if parent.rule == 0: assignment = parent.children[1] identifier = assignment.children[0].core[2] else: identifier = parent.children[1].core[2] if identifier in self.__identifier_table.keys(): if not isinstance(self.__identifier_table[identifier], dict): raise SemanticError( f'Variable \'{identifier}\' already declared.') raise SemanticError( f'Identifier \'{identifier}\' already used in function.' ) self.__identifier_table[identifier] = parent.children[ rule[0]].core[2] if parent.rule == 0: self.check_type(parent.children[rule[1]]) parent.type = type_check if parent.rule == 0: parent.children[1].children[0].type = self.check_type( parent.children[1].children[0]) else: parent.children[1].type = self.check_type( parent.children[1]) elif core == ':assignment': identifier_raw_type = self.check_type(parent.children[0]) value_type = self.check_type(parent.children[2]) identifier = parent.children[0].core[2] identifier_type = self.__identifier_table[identifier] parent.type = identifier_type if value_type in self.__rules['compatibilities'][ identifier_type]: parent.type = value_type else: raise TypeError( f'\'{identifier_type}\' not compatible with \'{value_type}\' on line {parent.children[0].core[0][1]}.' ) elif core == ':operation': types = [] operator = parent.children[1].core[2] if parent.rule == 0: raise SemanticError( 'Operations with more than 2 elements are currently not supported.' ) for element in rule: node = parent.children[element] types.append(self.check_type(node)) initial_type = None if 'FLOAT' in types: if 'CHAR' not in types and 'STRING' not in types: initial_type = 'FLOAT' else: raise TypeError( f'\'CHAR|STRING\' not compatible with \'FLOAT\'.' ) elif 'STRING' in types: for element in types: if element != 'STRING': raise TypeError( f'\'{element}\' not compatible with \'STRING\'.' ) initial_type = 'STRING' elif 'CHAR' in types: for element in types: if element != 'CHAR': raise TypeError( f'\'{element}\' not compatible with \'CHAR\'.' ) initial_type = 'CHAR' elif 'INT' in types: for element in types: if element != 'INT': raise TypeError( f'\'{element}\' not compatible with \'INT\'.' ) initial_type = 'INT' else: raise TypeError(f'Type not compatible with operation.') if operator != '+': if operator == '%' and initial_type != 'INT': raise TypeError( f'\'{initial_type}\' not compatible with \'{operator}\' operator.' ) if initial_type != 'INT' and initial_type != 'FLOAT': raise TypeError( f'\'{initial_type}\' not compatible with \'{operator}\' operator.' ) parent.type = initial_type elif core == ':logical_value': value_type = self.check_type(parent.children[rule[0]]) if value_type != 'BOOLEAN': raise TypeError( f'\'{value_type}\' not compatible with \'BOOLEAN\'.' ) parent.type = value_type elif core == ':comparison': types = [] operator = parent.children[1].core[2] for element in rule: node = parent.children[element] types.append(self.check_type(node)) numeric_operators = ['<=', '>=', '>', '<'] if operator in numeric_operators: for element in types: if element not in ['INT', 'FLOAT']: raise TypeError( f'\'{element}\' not compatible with \'{operator}\' operator.' ) parent.type = 'BOOLEAN' elif core == ':function': type_node = None identifier_type = 'sokka' type_check = None if rule: type_node = parent.children[rule[0]] if type_node: identifier_type = type_node.core[2] type_check = self.check_type(type_node) identifier = parent.children[1].core[2] if identifier in self.__identifier_table.keys(): if isinstance(self.__identifier_table[identifier], dict): raise SemanticError( f'Function \'{identifier}\' already declared.') raise SemanticError( f'Identifier \'{identifier}\' already used in variable.' ) self.__identifier_table[identifier] = dict() self.__identifier_table[identifier][ 'type'] = identifier_type if parent.rule == 0 or parent.rule == 1: args_node = parent.children[3] args_types = self.check_type(args_node) self.__identifier_table[identifier][ 'args_types'] = args_types parent.type = type_check elif core == ':logical_operation': parent.type = 'BOOLEAN' if rule: if len(rule) == 1: if not parent.type: parent.type = self.check_type( parent.children[rule[0]]) if len(parent.children) > 1: self.check_children(parent) return parent.type elif core == 'identifier': identifier = parent.core[2] if identifier in self.__identifier_table.keys(): if not isinstance(self.__identifier_table[identifier], dict): parent.type = self.__rules['rules'][ self.__identifier_table[identifier]]['type'] return parent.type else: raise SemanticError( f'Variable \'{identifier}\' referenced before assignment.') elif core == 'type': parent.type = self.__rules['rules'][parent.core[2]]['type'] return parent.type elif core == ':args': nodes = [] nodes.append(parent.children[0].children[0].core[2]) if parent.rule == 0: nodes.extend(self.check_type(parent.children[1])) return nodes elif core == ':argses': nodes = [] nodes.append(parent.children[1].children[0].core[2]) if parent.rule == 0: nodes.extend(self.check_type(parent.children[2])) return nodes elif core == ':call': identifier = parent.children[0].core[2] if identifier in self.__identifier_table.keys(): if isinstance(self.__identifier_table[identifier], dict): if 'args_types' in self.__identifier_table[ identifier].keys(): expected_args = self.__identifier_table[identifier][ 'args_types'] if parent.rule == 0: args_raw_types = self.check_type( parent.children[2]) if len(args_raw_types) != len(expected_args): raise SemanticError( f'Missing arguments for functions, expected: {str(expected_args)}.' ) for i, arg_type in enumerate(args_raw_types): if arg_type not in self.__rules[ 'compatibilities'][expected_args[i]]: raise TypeError( f'Incompatible arguments in call, expected: {str(expected_args)}.' ) else: raise SemanticError( f'Missing arguments for functions, expected: {str(expected_args)}.' ) function_type = self.__identifier_table[identifier]['type'] parent.type = self.__rules['rules'][function_type]['type'] return parent.type raise SemanticError(f'Function \'{identifier}\' not declared.') elif core == ':args_call': nodes = [] nodes.append(self.check_type(parent.children[0])) if parent.rule == 0: nodes.extend(self.check_type(parent.children[1])) return nodes elif core == ':args_calls': nodes = [] nodes.append(self.check_type(parent.children[1])) if parent.rule == 0: nodes.extend(self.check_type(parent.children[2])) return nodes else: self.check_children(parent)