Ejemplo n.º 1
0
            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])
Ejemplo n.º 2
0
            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")
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
            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])
Ejemplo n.º 7
0
            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")
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
 def call(interpreter, args):
     if self.notEmpty():
         return _number.Int().call(self, [len(self.value)])
     else:
         return 0