def check_params(self, function): if len(function.params) != len(self.calling_params): Exit(Error.SyntaxError, "Wrong number of parameters") for calling_param, declared_param in zip(self.calling_params, function.params.values()): if calling_param.type != declared_param.type: Exit(Error.TypesIncompatibility, "Parameters types mismatch")
def get_instructions(self, parent): self.parent = parent function = self.find_function() if function.type == VYPaVoid(): if self.expression is not None: Exit(Error.SyntaxError, "Void can not have return value") else: self.instruction_tape.merge(self.expression.get_instructions(self)) self.type = self.expression.type if self.type != function.type: Exit(Error.SemanticError, "Different return type and function type") variables_defined_in_function_count = len(function.variables) scope = self while scope != function: variables_defined_in_function_count += len(scope.variables) scope = scope.parent dealloc_count = variables_defined_in_function_count + len( function.params) if function.type != VYPaVoid(): self.instruction_tape.add(COMMENT(f"Set return value")) self.stack.set(self.expression, -dealloc_count - 1) self.instruction_tape.add( COMMENT( f"Deallocate {dealloc_count} scope variables and paramters")) self.stack.deallocate(dealloc_count) self.stack.deallocate(1) self.instruction_tape.add(RETURN(self.stack.get(1))) return self.instruction_tape
def get_variable(self, name): if self.variables.get(name, None) is not None: return self.variables[name] elif self.params.get(name, None) is not None: return self.params[name] else: Exit(Error.SemanticError, f"Variable {name} was not defined")
def add_param(self, param): param.set_parent(self) if self.params.get(param.name, None) is not None: Exit(Error.SemanticError, f"Param with name {param.name} already exists") else: self.params[param.name] = param
def add_variable(self, variable): if self.variables.get(variable.name, None) is None: variable.set_parent(self) self.variables[variable.name] = variable return variable else: Exit(Error.SyntaxError, f"Variable {variable.name} already exists")
def add_class(self, classs): if not self.classes.get(classs.name, None) is not None: classs.set_parent(self) self.classes[classs.name] = classs return classs else: Exit(Error.SyntaxError, f"Class {classs.name} already exists")
def add_function(self, function): if not self.functions.get(function.name, None) is not None: function.set_parent(self) self.functions[function.name] = function return function else: Exit(Error.SyntaxError, f"Function {function.name} already exists")
def p_program(t): '''program : init program_body''' main = AST.get_root().get_function("main") if not (main and main.type == VYPaVoid()): Exit(Error.SemanticError, "wrong type or not defined Main function") MAIN_INSTRUCTION_TAPE.add_constant_section() MAIN_INSTRUCTION_TAPE.merge(AST.get_root().get_instructions(None)) MAIN_INSTRUCTION_TAPE.add(LABEL("END"))
def get_variable(self, name): if name == "super": return self.predecessor.get_variable("this") if self.variables.get(name, None) is not None: return self.variables[name] else: if self.name != "Object": return self.predecessor.get_variable(name) else: Exit(Error.SyntaxError, f"Variable {name} was not defined")
def get_variable_offset(self, name): if name == "super": return len( self.variables) + self.predecessor.get_variable_offset("this") if self.variables.get(name, None) is not None: return list(self.variables)[::-1].index(name) else: if self.name != "Object": return len(self.variables ) + self.predecessor.get_variable_offset(name) else: Exit(Error.SyntaxError, f"Variable {name} was not defined")
def get_instructions(self, parent): self.parent = parent self.stack_offset += parent.stack_offset # print is a special function which can be called with multiple parameters # so internally we call PrintInt or PrintString for each parameter... if self.name == "print": self.type = VYPaVoid() if len(self.calling_params) == 0: Exit(Error.SemanticError, "Print called with zero params") for idx, param in enumerate(self.calling_params, 1): self.instruction_tape.merge(param.get_instructions(self)) if param.type == VYPaInt(): function = AST.root.get_function("printInt") elif param.type == VYPaString(): function = AST.root.get_function("printString") else: Exit(Error.SemanticError, "argument of print can be only int or str") self.stack.set(param, 3) self.add_instruction(CALL(self.stack.get(2), function)) if idx != len(self.calling_params): self.stack.pop() else: function = AST.root.get_function(self.name) self.type = function.type for offset, param in enumerate(self.calling_params, 3): if self.name != "stringConcat": # string concat has already merged instructions self.instruction_tape.merge(param.get_instructions(self)) self.stack.set(param, offset) self.check_params(function) self.add_instruction(CALL(self.stack.get(2), function)) self.add_expression_stack_offset() return self.instruction_tape
def get_variable_offset(self, name): if self.params.get(name, None) is not None: return len(self.variables) + list(self.params)[::-1].index(name) elif self.variables.get(name, None) is not None: offset = 0 for variable in list(self.variables.values())[::-1]: if variable.name == name: return offset else: offset += variable.get_size() else: Exit(Error.SemanticError, f"Variable {name} not found in function scope")
def get_instructions(self, parent): self.parent = parent self.instruction_tape.clear() for name in self.variable_names: if self.type == VYPaInt(): parent.add_variable(self.declare_integer(name)) elif self.type == VYPaString(): parent.add_variable(self.declare_string(name)) elif self.type == VYPaVoid(): Exit(Error.SemanticError, "Can not create void variable") else: parent.add_variable(self.declare_class_instance(name)) return self.instruction_tape
def t_WORD(t): r'\"([^\\\"]|\\.)*\"' # should be all printable characters hexChars = [x for x in re.findall(r'\\x[A-Fa-f0-9]{6}', t.value)] for hexChar in hexChars: try: unicode_char = chr(int(hexChar[2:], 16)) except ValueError: Exit(Error.LexicalError, "unicode character not in range of unicode characters") t.value = t.value.replace(hexChar, unicode_char) return t
def get_instructions(self, parent): self.parent = parent self.stack_offset += parent.stack_offset self.instruction_tape.merge(self.left.get_instructions(self)) self.instruction_tape.merge(self.right.get_instructions(self)) if self.left.type == VYPaInt() and self.right.type == VYPaInt(): self.instruction = EQI self.type = VYPaInt() self.add_instruction(self.instruction(self.left, self.right)) elif self.left.type == VYPaString() and self.right.type == VYPaString( ): self.instruction = EQS self.type = VYPaInt() self.add_instruction(self.instruction(self.left, self.right)) elif isinstance(self.left.type, VYPaClass) and isinstance( self.right.type, VYPaClass): self.instruction = EQI self.type = VYPaInt() left_class = AST_expression( AST_class_variable_call(self.left.name, "**runtime_name**")) self.merge_instructions(left_class.get_instructions(self)) self.add_instruction(SET("$6", VYPaRegister.Accumulator)) right_class = AST_expression( AST_class_variable_call(self.right.name, "**runtime_name**")) self.merge_instructions(right_class.get_instructions(self)) self.add_instruction(SET("$7", VYPaRegister.Accumulator)) self.add_instruction(DUMPREGS()) self.add_instruction(DUMPSTACK()) self.add_instruction(DUMPHEAP()) self.add_instruction( self.instruction(AST_value(VYPaInt(), "$6"), AST_value(VYPaInt(), "$7"))) else: Exit(Error.SemanticError, "Types mismatch") pass self.stack.push(AST_value(self.type, str(VYPaRegister.Accumulator))) self.add_expression_stack_offset() return self.instruction_tape
def get_instructions(self, parent): self.parent = parent global CLASS_INSTANCE_COUNTS self.instruction_tape.merge(self.expression.get_instructions(self)) self.variables["_"] = AST_variable(VYPaInt(), "_") self.stack.push( AST_value(self.expression.type, VYPaRegister.Accumulator)) self.instruction_tape.merge(self.variable.get_instructions(self)) from src.VYPcode.AST.blocks.class_instance import AST_class_instance if hasattr(self.expression, "expression_root") and isinstance( self.expression.expression_root, AST_class_instance): class_instance_variable = AST_variable( VYPaClass(self.expression.type.name), f"instance of {self.expression.type.name} {CLASS_INSTANCE_COUNTS}" ) class_instance_variable.set_size( AST.root.get_class(self.expression.type.name).get_size()) self.variable.variable.parent.add_variable(class_instance_variable) CLASS_INSTANCE_COUNTS += 1 if self.variable.type != self.expression.type: if self.variable.name != "this": Exit(Error.TypesIncompatibility, "Type check error!") if isinstance(self.variable.type, VYPaClass) and self.variable.name != "this": this_offset = 0 class_name = self.expression.type.name self.add_instruction( SET(VYPaRegister.ClassCallReg, self.stack.top())) while self.variable.type.name != class_name: this_offset -= len(AST.root.get_class(class_name).variables) class_name = AST.root.get_class(class_name).predecessor_name self.instruction_tape.add( SET(self.variable, self.stack.get(this_offset, VYPaRegister.ClassCallReg))) else: self.instruction_tape.add(SET(self.variable, self.stack.top())) self.stack.pop() return self.instruction_tape
def get_instructions(self, parent): self.parent = parent self.stack_offset += parent.stack_offset self.instruction_tape.merge(self.left.get_instructions(self)) self.instruction_tape.merge(self.right.get_instructions(self)) if self.left.type == VYPaInt() and self.right.type == VYPaInt(): self.instruction = GTI self.type = VYPaInt() self.add_instruction(self.instruction(self.left, self.right)) elif self.left.type == VYPaString() and self.right.type == VYPaString( ): self.instruction = GTS self.type = VYPaString() self.add_instruction(self.instruction(self.left, self.right)) else: Exit(Error.SemanticError, "Types mismatch") pass self.stack.push(AST_value(self.type, str(VYPaRegister.Accumulator))) self.add_expression_stack_offset() return self.instruction_tape
def get_instructions(self, parent): self.parent = parent self.stack_offset += parent.stack_offset self.instruction_tape.merge(self.left.get_instructions(self)) self.instruction_tape.merge(self.right.get_instructions(self)) if self.left.type == VYPaInt() and self.right.type == VYPaInt(): self.instruction = ADDI self.check_types() self.type = VYPaInt() self.add_instruction(self.instruction(self.left, self.right)) self.stack.push(AST_value(self.type, str(VYPaRegister.Accumulator))) self.add_expression_stack_offset() elif self.left.type == VYPaString() and self.right.type == VYPaString(): self.check_types() self.type = VYPaString() self.instruction_tape.merge( AST_function_call("stringConcat", [self.left, self.right]).get_instructions(self) ) else: Exit(Error.TypesIncompatibility, "Can not add other types as primitives") return self.instruction_tape
def check_types(self): if not ((self.expression.type == VYPaInt() and self.casting_type == VYPaString()) or (isinstance(self.expression.type, VYPaClass) and AST.root.classes.get(self.casting_type.name, False))): Exit(Error.TypesIncompatibility, "Type check error!")
def t_error(t): Exit(Error.LexicalError, f"Illegal character '{t.value[0]}' on line {t.lexer.lineno}")
def check_types(self): if self.left.type != VYPaInt() or self.right.type != VYPaInt(): Exit(Error.TypesIncompatibility, "Type check error!")
def p_error(t): Exit(Error.SyntaxError, "Syntax error. Can not parse")
def get_class(self, class_name): try: return self.classes[class_name] except KeyError: Exit(Error.SyntaxError, f"Class {class_name} was not defined")
def get_function(self, function_name): try: return self.functions[function_name] except KeyError: Exit(Error.SyntaxError, f"Function {function_name} was not defined")
def get_variable(self, name): Exit(Error.SyntaxError, f"Variable {name} was not defined")
def check_types(self): if self.expression.type != VYPaInt(): Exit(Error.TypesIncompatibility, "Type check error!")
def get_variable_offset(self, name): if self.variables.get(name, None) is not None: return list(self.variables)[::-1].index(name) else: Exit(Error.SyntaxError, f"Variable {name} not found in function scope")