def call(interpreter, args): if (self.arrayType != _number.RocketInt) and ( self.arrayType != _number.RocketFloat): raise _RuntimeError( self, "Can only perform operation on number Arrays.") if len(self.elements) == 0: return _number.Int().call(self, [0]) prod = 1 for i in range(len(self.elements)): prod *= self.elements[i].value return _number.Int().call(self, [prod])
def call(interpreter, args): if self.notEmpty(): for i in range(len(self.elements)): if args[0].value == self.elements[i].value: return _number.Int().call(self, [i]) raise _RuntimeError('List', "IndexError: Item not in list") else: raise _RuntimeError('List', "IndexError: cannot index from an empty list")
def sanitizeNum(self, n): # Returns a Rocket num if number received if (self.is_number(n)): if (isinstance(n, int)): return _rocketNumber.Int().call(self, [n]) if (isinstance(n, float)): return _rocketNumber.Float().call(self, [n]) # otherwise it returns it unchanged return n
def visitUnaryExpr(self, expr: _Unary): right = self.sanitizeNum(self.evaluate(expr.right)) # Handle '~' bit shifter if (expr.operator.type == _TokenType.TILDE): self.checkNumberOperand(expr.operator, right.value) sum = -right.value - 1 return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.MINUS): self.checkNumberOperand(expr.operator, right.value) sum = -right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.BANG): return not (self.isTruthy(right.value)) # If can't be matched return nothing return None
def visitLiteralExpr(self, expr: _Literal): if type(expr.value) == int: return _rocketNumber.Int().call(self, [expr.value]) if type(expr.value) == float: return _rocketNumber.Float().call(self, [expr.value]) if type(expr.value) == str: return _rocketString.String().call(self, [expr.value]) if type(expr.value) == bool: return _rocketBoolean.Bool().call(self, [expr.value]) return expr.value
def call(interpreter, args): if (self.arrayType != _number.RocketInt) and ( self.arrayType != _number.RocketFloat): raise _RuntimeError( self, "Can only perform operation on number Arrays.") if len(self.elements) == 0: return _RuntimeError(self, "Can't get max of empty an Array.") max = self.elements[0].value for i in range(1, len(self.elements)): if max < self.elements[i].value: max = self.elements[i].value return _number.Int().call(self, [max])
def call(interpreter, args): if self.notEmpty(): removed_index = -1 for i in range(len(self.elements) - 1): if args[0].value == self.elements[i].value: self.elements.remove(self.elements[i]) removed_index = i if removed_index == -1: raise _RuntimeError('List', "IndexError: Item not in list") else: return _number.Int().call(self, [removed_index]) else: raise _RuntimeError('List', "IndexError: cannot remove items from an empty list")
def __init__(self, KSL: list): self.globals = _Environment() # For the native functions self.environment = _Environment() # Functions / classes self.locals = {} self.errors = [] self.KSL = KSL self.stackCount = 0 # tracks stmt repetitions, 'stackoverflow' errs self.fnCallee = None # Tracks current fn callee # Statically define 'native' functions # random n between '0-1' {insecure} self.globals.define(_random.Random().callee, _random.Random) # print (escaped) output. i.e print("hello\tmr.Jim") -> "Hello mr.Jim" self.globals.define(_output.Print().callee, _output.Print) # grab user input self.globals.define(_input.Input().callee, _input.Input) # 'locals' return all globally defined 'vars' and 'consts' self.globals.define(_locals.Locals().callee, _locals.Locals) # 'clock' self.globals.define(_clock.Clock().callee, _clock.Clock) # 'copyright' self.globals.define(_copyright.Copyright().callee, _copyright.Copyright) # 'natives' -> names of nativr functions self.globals.define(_natives.Natives().callee, _natives.Natives) # 'type' -> check datatype self.globals.define(_kind.Type().callee, _kind.Type) # Datatypes self.globals.define(_rocketList.List().callee, _rocketList.List) self.globals.define(_rocketArray.Array().callee, _rocketArray.Array) self.globals.define(_rocketString.String().callee, _rocketString.String) self.globals.define(_rocketNumber.Int().callee, _rocketNumber.Int) self.globals.define(_rocketNumber.Float().callee, _rocketNumber.Float) self.globals.define(_rocketBoolean.Bool().callee, _rocketBoolean.Bool)
def visitAssignExpr(self, expr: _Assign): if type(expr.value) == list: init_value = self.environment.get(expr.value[0]) var_value = expr.value[1] if type( expr.value[1]) != _Literal else self.evaluate(expr.value[1]) ### Lets handle our post fix arithmetic ops # First lets start with '++' if expr.value[2] == 'inc': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform arithmetic increment on string.", False) value = _rocketNumber.Int().call(self, [ init_value.value + 1 ]) if type( init_value.value) == int else _rocketNumber.Float().call( self, [init_value.value + 1]) self.environment.assign(expr.name, value) # I.e :- # var p = 2; # print p++; /// returns '2' return init_value # For our decrement post fix operator '--' if expr.value[2] == 'dec': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform arithmetic decrement on string.", False) value = _rocketNumber.Int().call(self, [ init_value.value - 1 ]) if type(init_value) == int else _rocketNumber.Float().call( self, [init_value.value - 1]) self.environment.assign(expr.name, value) # I.e :- # var p = 2; # print p--; /// returns '2' return init_value ### END of post arithmetic ops ### Beginning of assignment arithmetic ops # Perform op check to determine arithmetic operation to perform # Check for '+=' # also works in cases were string concatenation is intended 'home += "/Github;"' if expr.value[2] == 'add': value = init_value.value + var_value value = _rocketNumber.Int().call(self, [value]) if type( value) == int else _rocketNumber.Float().call( self, [value]) self.environment.assign(expr.name, value) return value # Check for '-=' if expr.value[2] == 'sub': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform subtraction arithmetic assignment on string.", False) value = init_value.value - var_value value = _rocketNumber.Int().call(self, [value]) if type( value) == int else _rocketNumber.Float().call( self, [value]) self.environment.assign(expr.name, value) return value # Check for '*=' if expr.value[2] == 'mul': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform multiplication arithmetic assignment on string.", False) value = init_value.value * var_value value = _rocketNumber.Int().call(self, [value]) if type( value) == int else _rocketNumber.Float().call( self, [value]) self.environment.assign(expr.name, value) return value # Check for '/=' if expr.value[2] == 'div': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform division arithmetic assignment on string.", False) value = init_value.value / var_value value = _rocketNumber.Int().call(self, [value]) if type( value) == int else _rocketNumber.Float().call( self, [value]) self.environment.assign(expr.name, value) return value # Check for '//=' if expr.value[2] == 'flo': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform floor division arithmetic assignment on string.", False) value = init_value.value // var_value value = _rocketNumber.Int().call(self, [value]) if type( value) == int else _rocketNumber.Float().call( self, [value]) self.environment.assign(expr.name, value) return value # Check for '%=' if expr.value[2] == 'mod': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform modulo arithmetic assignment on string.", False) value = init_value.value % var_value value = _rocketNumber.Int().call(self, [value]) if type( value) == int else _rocketNumber.Float().call( self, [value]) self.environment.assign(expr.name, value) return value # Check for '**=' if expr.value[2] == 'exp': if type(init_value) == str: raise _RuntimeError( expr.name, "cannot perform exponent arithmetic assignment on string.", False) value = init_value.value**var_value value = _rocketNumber.Int().call(self, [value]) if type( value) == int else _rocketNumber.Float().call( self, [value]) self.environment.assign(expr.name, value) return value ### END of assignment arithmetic ops else: value = self.evaluate(expr.value) try: self.environment.assign(expr.name, value) except _RuntimeError as error: if ('ReferenceError:' in error.msg) or ('AssignmentError: ' in error.msg): self.errors.append(error) else: pass return value
def visitBinaryExpr(self, expr: _Binary): # Sanitize to get nums if avail left = self.sanitizeNum(self.evaluate(expr.left)) right = self.sanitizeNum(self.evaluate(expr.right)) # Catches all ops over an Array with a num # That is '+', '-', '*', '/', '//', '%', '**' if (expr.operator.lexeme in ['+', '-', '*', '/', '//', '%', '**']): if (self.isRocketArray(left)) and (self.isRocketNumber(right)): if (self.isNumberArray(left)) and not left.isEmpty: return _rocketArray.Array().call( self, _opOverArray(left, right, self.sanitizeNum, expr.operator.lexeme)) else: raise _RuntimeError(expr.operator, "Array must contain Number elements.", False) if (self.isRocketArray(right)) and (self.isRocketNumber(left)): if (self.isNumberArray(right)) and not right.isEmpty: return _rocketArray.Array().call( self, _opOverArray(right, left, self.sanitizeNum, expr.operator.lexeme)) else: raise _RuntimeError(expr.operator, "Array must contain Number elements.", False) # overloaded operator '+' that performs: # basic arithmetic addition (between numbers) # string and implicit concatenation, i.e. String + [other type] = String # list concatenation, i.e. [4,2,1] + [4,6] = [4,2,1,4,6] # Array addition, i.e. [4,3,5] + [3,1,0] = [7,4,5] if (expr.operator.type == _TokenType.PLUS): # basic arithmetic addition if self.is_number(left) and self.is_number(right): sum = left.value + right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) # String concatenation if (isinstance(left, _rocketString.RocketString) and isinstance(right, _rocketString.RocketString)): return _rocketString.String().call( self, [str(left.value) + str(right.value)]) # To support implicit string concactination # E.g "Hailey" + 4 -> "Hailey4" # No need to allow this anymore. We make 'String' compulsory if ((isinstance(left, _rocketString.RocketString)) or (isinstance(right, _rocketString.RocketString))): # Concatenation of 'nin' is prohibited! if (type(left) == type(None)) or (type(right) == type(None)): raise _RuntimeError( expr.operator.lexeme, "Operands must be either both strings or both numbers.", False) return _rocketString.String().call( self, [self.sanitizeString(left) + self.sanitizeString(right)]) # allow python style list concatenation if (isinstance(left, _rocketList.RocketList) or isinstance(right, _rocketList.RocketList)): concat_tok = _Token(_TokenType.STRING, 'concat', 'concat', 0) # return new concatenated list return left.get(concat_tok).call(self, [right]) if (self.isRocketArray(left)) and (self.isRocketArray(right)): if (self.isNumberArray(left) and self.isNumberArray(right) ) and not (left.isEmpty or right.isEmpty): return _rocketArray.Array().call( self, _addArrays(left, right, self.sanitizeNum)) else: raise _RuntimeError(expr.operator, "Cannot concat empty Array(s).", False) if (type(left) == type(None)) or (type(right) == type(None)): raise _RuntimeError( expr.operator, "Operands must be either both strings or both numbers.", False) # Arithmetic operators "-", "/", "%", "//", "*", "**" if (expr.operator.type == _TokenType.MINUS): self.checkNumberOperands(expr.operator, left, right) sum = left.value - right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.DIV): self.checkNumberOperands(expr.operator, left, right) if right.value == 0: raise _RuntimeError(right, "ZeroDivError: Can't divide by zero", False) sum = left.value / right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.MOD): self.checkNumberOperands(expr.operator, left, right) if right.value == 0: raise _RuntimeError(right, "ZeroDivError: Can't divide by zero", False) sum = left.value % right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.FLOOR): self.checkNumberOperands(expr.operator, left, right) if right.value == 0: raise _RuntimeError(right, "ZeroDivError: Can't divide by zero", False) sum = left.value // right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.MULT): self.checkNumberOperands(expr.operator, left, right) sum = left.value * right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.EXP): self.checkNumberOperands(expr.operator, left, right) sum = left.value**right.value return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) # bitshifters "<<", ">>" if (expr.operator.type == _TokenType.LESS_LESS): self.checkNumberOperands(expr.operator, left, right) sum = left.value * (2**right.value) return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) if (expr.operator.type == _TokenType.GREATER_GREATER): self.checkNumberOperands(expr.operator, left, right) sum = left.value // (2**right.value) return _rocketNumber.Int().call(self, [sum]) if type( sum) == int else _rocketNumber.Float().call(self, [sum]) # Comparison operators ">", "<", ">=", "<=", "!=", "==" if (expr.operator.type == _TokenType.GREATER): self.checkNumberOperands(expr.operator, left, right) return left.value > right.value if (expr.operator.type == _TokenType.LESS): self.checkNumberOperands(expr.operator, left, right) return left.value < right.value if (expr.operator.type == _TokenType.GREATER_EQUAL): self.checkNumberOperands(expr.operator, left, right) return left.value >= right.value if (expr.operator.type == _TokenType.LESS_EQUAL): self.checkNumberOperands(expr.operator, left, right) return left.value <= right.value if (expr.operator.type == _TokenType.BANG_EQUAL): self.checkValidOperands(expr.operator, left, right) return not (self.isEqual(left, right)) if (expr.operator.type == _TokenType.EQUAL_EQUAL): if left == None or right == None: return self.isEqual(left, right) if isinstance(left, _rocketBoolean.Bool) or isinstance( right, _rocketBoolean.Bool): return self.isEqual(left, right) self.checkValidOperands(expr.operator, left, right) return self.isEqual(left, right) # If can't be matched return None return None
def call(interpreter, args): if self.notEmpty(): return _number.Int().call(self, [len(self.value)]) else: return 0