def compile(self, compiler): function = SodaFunction(name=self.name, arity=len(self.params), compiler=self.compiler, package=self.package, line=self.line, col=self.col) compiler.register_function(function) for constant in compiler.constants: if isinstance(constant, SodaFunction): self.compiler.register_function(constant) sd = SodaDummy() for i in range(0, function.arity): self.compiler.emit(bytecode.LOAD_CONST, self.compiler.register_constant(sd), self.package, self.line, self.col) for param in self.params: assert isinstance(param, RegisterVariable) if param.value == unicode("vargs"): if self.params.index(param) != len(self.params) - 1: sodaError( self.package, self.line, self.col, "vargs must be final parameter in " "function declaration") function.isvariadic = True param.compile(self.compiler) for statement in self.body: statement.compile(self.compiler) self.returnstatement.compile(self.compiler)
def error_handler(token): package = fetcher.packages[token.getsourcepos().idx] line = str(token.getsourcepos().lineno) col = str(token.getsourcepos().colno) if token.name == "ERROR": sodaError(package, line, col, token.value) else: msg = "unexpected \"%s\"" % token.value sodaError(package, line, col, msg)
def statement_assignment(s): sourcepos = s[1].getsourcepos() package = fetcher.packages[sourcepos.idx] line = str(sourcepos.lineno) col = str(sourcepos.colno) if not len(s[0].get()) == len(s[2].get()): sodaError( package, line, col, "assignment operator requires number " "of variables to match number of expressions") return ast.Assignment(s[0], s[2], package, line, col)
def register_function(self, function): package = unicode(function.package) try: self.functions[function.name + package] sodaError( function.package, function.line, function.col, "redeclaration of function \"%s\"" % function.name.encode("utf-8")) except KeyError: self.functions[function.name + package] = self.register_constant(function)
def number_number(s): sourcepos = s[0].getsourcepos() package = fetcher.packages[sourcepos.idx] line = str(sourcepos.lineno) col = str(sourcepos.colno) try: a = rbigint() return ast.Integer(a.fromstr(s[0].getstr()), package, line, col) except Exception: package = fetcher.packages[s[0].getsourcepos().idx] line = str(s[0].getsourcepos().lineno) col = str(s[0].getsourcepos().colno) msg = "error in number %s" % s[0].getstr() sodaError(package, line, col, msg)
def fetch(self): data = "" for package in self.packages: fetchfound = False packagefound = False filepath = self.pathtopackage[package] + package + ".na" try: sourcefile = open_file_as_stream(filepath) data = sourcefile.readall() sourcefile.close() except OSError: errtok = self.tokentopackage.get(package, None) errfile = self.packages[errtok.getsourcepos().idx] sodaError(errfile, str(errtok.getsourcepos().lineno), str(errtok.getsourcepos().colno), "package \"%s\" not found" % package) i = 0 tokenlist = [] if not data == "": for token in lexer.lex(data, self.idx): if not fetchfound: if token.name == "FETCH": if not i == 0: sodaError( package, str(token.getsourcepos().lineno), str(token.getsourcepos().colno), "fetch statement must precede main program" ) else: i += 1 fetchfound = True else: i += 1 tokenlist.append(token) else: if token.name == "STRING": self.tokentopackage[token.value] = token if not packagefound: fullpath = self.pathtopackage[self.packages[ self.idx]] + token.value self.addpackage(fullpath) packagefound = True continue else: sodaError( package, str(token.getsourcepos().lineno), str(token.getsourcepos().colno), "package names must be " "separated by newlines") elif token.name == "END": packagefound = False continue else: tokenlist.append(token) fetchfound = False data = "" self.idx += 1 self.tokgeneratorlist.append(tokenlist)
def run(frame, bc): code = bc.code positions = bc.positions pc = 0 iteridx = 0 while pc < len(bc.code): driver.jit_merge_point(pc=pc, iteridx=iteridx, code=code, positions=positions, bc=bc, frame=frame) c = code[pc] arg = code[pc + 1] package, line, col = positions[pc] pc += 2 if c == bytecode.DROP_CONST: frame.pop() elif c == bytecode.LOAD_CONST: const = bc.constants[arg] frame.push(const) elif c == bytecode.LOAD_VAR: if arg == -1: sodaError(package, line, col, "cannot evaluate undeclared variable") var = frame.variables[arg] frame.push(var) elif c == bytecode.STORE_VAR: package = package line = line col = col value = frame.pop() frame.variables[arg] = value elif c == bytecode.STOR_ARRAY: package = package line = line col = col items = [] for i in range(0, arg): items.append(frame.pop()) sa = SodaArray(items) frame.push(sa) elif c == bytecode.NEG: operand = frame.pop() if not operand.isint(): try: operand = operand.toint() except Exception: sodaError(package, line, col, "cannot negate non-integer type") result = operand.neg() frame.push(result) elif c == bytecode.ADD: right = frame.pop() left = frame.pop() if not right.isint(): try: right = right.toint() except Exception: sodaError(package, line, col, "cannot add non-integer types") if not left.isint(): try: left = left.toint() except Exception: sodaError(package, line, col, "cannot add non-integer types") result = right.add(left) frame.push(result) elif c == bytecode.CONCAT: right = frame.pop() left = frame.pop() if not left.isstr(): try: left = left.tostr() except Exception: sodaError(package, line, col, "cannot concatenate non-string types") if not right.isstr(): try: right = right.tostr() except Exception: sodaError(package, line, col, "cannot concatenate non-string types") result = right.concat(left) frame.push(result) elif c == bytecode.DIFF: right = frame.pop() left = frame.pop() if not left.isstr(): try: left = left.tostr() except Exception: sodaError( package, line, col, "cannot find string difference of non-string" " types") if not right.isstr(): try: right = right.tostr() except Exception: sodaError( package, line, col, "cannot find string difference of non-string" " types") result = right.diff(left) frame.push(result) elif c == bytecode.SUB: right = frame.pop() left = frame.pop() if not right.isint(): try: right = right.toint() except Exception: sodaError(package, line, col, "cannot subtract non-integer types") if not left.isint(): try: left = left.toint() except Exception: sodaError(package, line, col, "cannot subtract non-integer types") result = right.sub(left) frame.push(result) elif c == bytecode.MUL: right = frame.pop() left = frame.pop() if not right.isint(): try: right = right.toint() except Exception: sodaError(package, line, col, "cannot multiply non-integer types") if not left.isint(): try: left = left.toint() except Exception: sodaError(package, line, col, "cannot multiply non-integer types") result = right.mul(left) frame.push(result) elif c == bytecode.DIV: right = frame.pop() left = frame.pop() if not right.isint(): try: right = right.toint() except Exception: sodaError(package, line, col, "cannot divide non-integer types") if not left.isint(): try: left = left.toint() except Exception: sodaError(package, line, col, "cannot divide non-integer types") try: result = right.div(left) except ZeroDivisionError: sodaError(package, line, col, "cannot divide by zero") break frame.push(result) elif c == bytecode.MOD: right = frame.pop() left = frame.pop() if not right.isint(): try: right = right.toint() except Exception: sodaError(package, line, col, "cannot modulo non-integer types") if not left.isint(): try: left = left.toint() except Exception: sodaError(package, line, col, "cannot modulo non-integer types") try: result = right.mod(left) except ZeroDivisionError: sodaError(package, line, col, "cannot modulo by zero") break frame.push(result) elif c == bytecode.POW: right = frame.pop() left = frame.pop() if not right.isint(): try: right = right.toint() except Exception: sodaError(package, line, col, "cannot exponentiate non-integer types") if not left.isint(): try: left = left.toint() except Exception: sodaError(package, line, col, "cannot exponentiate non-integer types") try: result = right.pow(left) except ValueError: sodaError(package, line, col, "cannot exponentiate by a negative integer") break frame.push(result) elif c == bytecode.EQ: right = frame.pop() left = frame.pop() if left.isstr() and right.isstr() or left.isint()\ and right.isint(): result = right.eq(left) frame.push(result) continue try: right = right.toint() left = left.toint() result = right.eq(left) frame.push(result) continue except Exception: try: right = right.tostr() left = left.tostr() result = right.eq(left) frame.push(result) continue except Exception: sodaError(package, line, col, "cannot compare arrays") elif c == bytecode.NE: right = frame.pop() left = frame.pop() if left.isstr() and right.isstr() or left.isint()\ and right.isint(): result = right.ne(left) frame.push(result) continue try: right = right.toint() left = left.toint() result = right.ne(left) frame.push(result) continue except Exception: try: right = right.tostr() left = left.tostr() result = right.ne(left) frame.push(result) continue except Exception: sodaError(package, line, col, "cannot compare arrays") elif c == bytecode.GT: right = frame.pop() left = frame.pop() if left.isstr() and right.isstr() or left.isint()\ and right.isint(): result = right.gt(left) frame.push(result) continue try: right = right.toint() left = left.toint() result = right.gt(left) frame.push(result) continue except Exception: try: right = right.tostr() left = left.tostr() result = right.gt(left) frame.push(result) continue except Exception: sodaError(package, line, col, "cannot compare arrays") elif c == bytecode.LT: right = frame.pop() left = frame.pop() if left.isstr() and right.isstr() or left.isint()\ and right.isint(): result = right.lt(left) frame.push(result) continue try: right = right.toint() left = left.toint() result = right.lt(left) frame.push(result) continue except Exception: try: right = right.tostr() left = left.tostr() result = right.lt(left) frame.push(result) continue except Exception: sodaError(package, line, col, "cannot compare arrays") elif c == bytecode.GE: right = frame.pop() left = frame.pop() if left.isstr() and right.isstr() or left.isint()\ and right.isint(): result = right.ge(left) frame.push(result) continue try: right = right.toint() left = left.toint() result = right.ge(left) frame.push(result) continue except Exception: try: right = right.tostr() left = left.tostr() result = right.ge(left) frame.push(result) continue except Exception: sodaError(package, line, col, "cannot compare arrays") elif c == bytecode.LE: right = frame.pop() left = frame.pop() if left.isstr() and right.isstr() or left.isint()\ and right.isint(): result = right.le(left) frame.push(result) continue try: right = right.toint() left = left.toint() result = right.le(left) frame.push(result) continue except Exception: try: right = right.tostr() left = left.tostr() result = right.le(left) frame.push(result) continue except Exception: sodaError(package, line, col, "cannot compare arrays") elif c == bytecode.AND: right = frame.pop() left = frame.pop() if not left.isstr(): try: left = left.tostr() except Exception: sodaError(package, line, col, "cannot compare arrays") if not right.isstr(): try: right = right.tostr() except Exception: sodaError(package, line, col, "cannot compare arrays") result = right.land(left) frame.push(result) elif c == bytecode.OR: right = frame.pop() left = frame.pop() if not left.isstr(): try: left = left.tostr() except Exception: sodaError(package, line, col, "cannot compare arrays") if not right.isstr(): try: right = right.tostr() except Exception: sodaError(package, line, col, "cannot compare arrays") result = right.lor(left) frame.push(result) elif c == bytecode.NOT: operand = frame.pop() if not operand.isstr(): try: operand = operand.tostr() except Exception: sodaError(package, line, col, "cannot compare arrays") result = operand.lnot() frame.push(result) elif c == bytecode.RETURN: result = frame.pop() return result elif c == bytecode.CALL: if arg == -1: sodaError(package, line, col, "cannot evaluate undeclared function") elif arg == -2: sodaError( package, line, col, "number of arguments passed to function " "must match number of expected parameters") function = bc.constants[arg] if unicode(function.name) == u"Print" and unicode( function.package) == u"io": output = frame.pop().str() os.write(1, output) fbc = function.compiler.create_bytecode() frame.push(interpret(fbc)) if unicode(function.name) == u"Error" and unicode( function.package) == u"io": output = frame.pop().str() os.write(2, output) fbc = function.compiler.create_bytecode() frame.push(interpret(fbc)) else: arglist = [] if function.isvariadic: function.numargs = len(frame.valuestack) for i in range(0, function.numargs): value = frame.pop() arglist.append(value) function.evaluate_args(arglist) fbc = function.compiler.create_bytecode() fbc.textarrays = bc.textarrays try: function.revert_state() result = interpret(fbc) frame.push(result) except RuntimeError: sodaError(package, line, col, "maximum recursion depth exceeded") elif c == bytecode.J_IF_TRUE: if not frame.pop().str() == "false": pc = arg elif c == bytecode.J_IF_FALSE: if frame.pop().str() == "false": pc = arg elif c == bytecode.ITERATE: array = frame.pop() try: keyval = array.getkey(iteridx) if keyval is None: pc = arg iteridx = 0 else: frame.push(keyval) iteridx += 1 except Exception: sodaError(package, line, col, "cannot iterate non-array types") elif c == bytecode.SET_INDEX: expr = frame.pop() var = frame.pop() newval = frame.pop() try: var.setval(expr, newval) except Exception: sodaError(package, line, col, "cannot mutate non-array types") elif c == bytecode.GET_INDEX: expr = frame.pop() var = frame.pop() try: result = var.getval(expr) frame.push(result) except IndexError: sodaError(package, line, col, "string index out of range") except Exception: sodaError(package, line, col, "cannot index integers") elif c == bytecode.JUMP: if arg == -3: sodaError(package, line, col, "break statement outside loop") oldpc = pc pc = arg if pc < oldpc: driver.can_enter_jit(pc=pc, iteridx=iteridx, code=code, positions=positions, bc=bc, frame=frame) elif c == bytecode.LEN: length = frame.pop().length if length is not None: frame.push(length) else: sodaError(package, line, col, "cannot find length of integer") elif c == bytecode.CHARS: frame.push(bc.textarrays[0]) elif c == bytecode.WORDS: frame.push(bc.textarrays[1]) elif c == bytecode.LINES: frame.push(bc.textarrays[2]) else: sodaError("test", "-1", "-1", "unrecognized bytecode %s" % c)