def execute_len(self, exec_context):
     list_ = exec_context.symbol_table.get("list")
     if not isinstance(list_, List):
         return RuntimeResult().failure(
             ActiveRuntimeError("Argument must be list", self.start_pos,
                                self.end_pos, exec_context))
     return RuntimeResult().success(Number(len(list_.elements)))
 def execute_append(self, exec_context):
     list_ = exec_context.symbol_table.get("list")
     value = exec_context.symbol_table.get("value")
     if not isinstance(list_, List):
         return RuntimeResult().failure(
             ActiveRuntimeError("First argument must be list",
                                self.start_pos, self.end_pos, exec_context))
     list_.elements.append(value)
     return RuntimeResult().success(Number(0))
 def visit_callnode(self, node, context):
     """
     Visits the CallNode instance.
     :param node: The CallNode instance.
     :param context: The caller's context.
     :return: The resulting Node from the exec call.
     """
     args = []
     runtime_result = RuntimeResult()
     value_to_call = runtime_result.register(
         self.visit(node.node_to_call, context))
     if runtime_result.should_return():
         return runtime_result
     value_to_call = value_to_call.copy().set_position(
         node.start_pos, node.end_pos)
     for arg_node in node.arg_nodes:
         args.append(runtime_result.register(self.visit(arg_node, context)))
         if runtime_result.should_return():
             return runtime_result
     return_value = runtime_result.register(value_to_call.execute(args))
     if runtime_result.should_return():
         return runtime_result
     return_value = return_value.copy().set_position(
         node.start_pos, node.end_pos).set_context(context)
     return runtime_result.success(return_value)
 def execute_extend(self, exec_context):
     first_list = exec_context.symbol_table.get("first_list")
     end_list = exec_context.symbol_table.get("second_list")
     if not isinstance(first_list, List):
         return RuntimeResult().failure(
             ActiveRuntimeError("First argument must be list",
                                self.start_pos, self.end_pos, exec_context))
     if not isinstance(end_list, List):
         return RuntimeResult().failure(
             ActiveRuntimeError("Second argument must be list",
                                self.start_pos, self.end_pos, exec_context))
     first_list.elements.extend(end_list.elements)
     return RuntimeResult().success(Number(0))
 def check_and_populate_args(self, arg_names, args, exec_context):
     """
     Checks args before populating the Context.
     :param arg_names: Names of all args.
     :param args: Values of all args.
     :param exec_context: Context we wish to update.
     :return: None, if there are no issues.
     """
     runtime_result = RuntimeResult()
     runtime_result.register(self.check_args(arg_names, args))
     if runtime_result.error:
         return runtime_result
     self.populate_args(arg_names, args, exec_context)
     return runtime_result.success(None)
 def visit_varassignnode(self, node, context):
     """
     Assigns the value of variables in the stream.
     :param node: Node of a variable to assign.
     :param context: Context of the caller.
     :return: Value of the variable.
     """
     runtime_result = RuntimeResult()
     var_name = node.var_name.value
     var_value = runtime_result.register(
         self.visit(node.value_node, context))
     if runtime_result.should_return():
         return runtime_result
     context.symbol_table.set(var_name, var_value)
     return runtime_result.success(var_value)
 def visit_funcdefnode(self, node, context):
     """
     Visits a FuncDefNode instance.
     :param node: The FuncDefNode instance.
     :param context: The caller's context.
     :return: Function Node instance.
     """
     runtime_result = RuntimeResult()
     func_name = node.var_name_token.value if node.var_name_token else None
     body_node = node.body_node
     arg_names = [arg_name.value for arg_name in node.arg_name_tokens]
     func_node = Function(func_name, body_node, arg_names, node.should_auto_return) \
         .set_context(context).set_position(node.start_pos, node.end_pos)
     if node.var_name_token:
         context.symbol_table.set(func_name, func_node)
     return runtime_result.success(func_node)
 def visit_returnnode(self, node, context):
     """
     Visits the ReturnNode instance.
     :param node: The ReturnNode instance.
     :param context: The caller's context.
     :return: Value of the ReturnNode instance.
     """
     runtime_result = RuntimeResult()
     if node.node_to_return:
         value = runtime_result.register(
             self.visit(node.node_to_return, context))
         if runtime_result.should_return():
             return runtime_result
     else:
         value = Number(0)
     return runtime_result.success_return(value)
 def visit_varaccessnode(self, node, context):
     """
     Accesses the value of variables in the stream.
     :param node: Node with which to fetch the variable.
     :param context: Context of the caller.
     :return: Value of fetching a variable's value and executing it.
     """
     runtime_result = RuntimeResult()
     var_name = node.var_name.value
     var_value = context.symbol_table.get(var_name)
     if var_value is None:
         runtime_result.failure(
             ActiveRuntimeError('VAR "{}" not defined'.format(var_name),
                                node.start_pos, node.end_pos, context))
     var_value = var_value.copy().set_position(
         node.start_pos, node.end_pos).set_context(context)
     return runtime_result.success(var_value)
 def visit_listnode(self, node, context):
     """
     Visits the ListNode instance.
     :param node:  The ListNode instance.
     :param context: The caller's context.
     :return: List instance with all values.
     """
     elements = []
     runtime_result = RuntimeResult()
     for element_node in node.element_nodes:
         elements.append(
             runtime_result.register(self.visit(element_node, context)))
         if runtime_result.should_return():
             return runtime_result
     return runtime_result.success(
         List(elements).set_context(context).set_position(
             node.start_pos, node.end_pos))
 def visit_breaknode(self, node, context):
     """
     Visits the BreakNode instance.
     :param node: The BreakNode instance.
     :param context: The caller's context.
     :return: The RuntimeResult of a successful BREAK.
     """
     return RuntimeResult().success_break()
 def visit_binopnode(self, node, context):
     """
     Returns the result of the binary operation.
     :param node: Node which houses two children Nodes.
     :param context: Context of the caller.
     :return: Result of the binary operation on both child Nodes.
     """
     result, error = None, None
     runtime_result = RuntimeResult()
     left_node = runtime_result.register(self.visit(node.left_node,
                                                    context))
     right_node = runtime_result.register(
         self.visit(node.right_node, context))
     if runtime_result.should_return():
         return runtime_result
     if node.op_token.type == TP_PLUS:
         result, error = left_node.add_to(right_node)
     elif node.op_token.type == TP_MINUS:
         result, error = left_node.subtract_by(right_node)
     elif node.op_token.type == TP_POWER:
         result, error = left_node.power_by(right_node)
     elif node.op_token.type == TP_MUL:
         result, error = left_node.multiply_by(right_node)
     elif node.op_token.type == TP_DIV:
         result, error = left_node.divide_by(right_node)
     elif node.op_token.type == TP_MODULO:
         result, error = left_node.modulo_by(right_node)
     elif node.op_token.type == TP_CLEAN_DIV:
         result, error = left_node.divide_by(right_node, clean=True)
     elif node.op_token.type == TP_NE:
         result, error = left_node.get_comparison_ne(right_node)
     elif node.op_token.type == TP_EE:
         result, error = left_node.get_comparison_ee(right_node)
     elif node.op_token.type == TP_LT:
         result, error = left_node.get_comparison_lt(right_node)
     elif node.op_token.type == TP_LTE:
         result, error = left_node.get_comparison_lte(right_node)
     elif node.op_token.type == TP_GT:
         result, error = left_node.get_comparison_gt(right_node)
     elif node.op_token.type == TP_GTE:
         result, error = left_node.get_comparison_gte(right_node)
     elif node.op_token.matches(TP_KEYWORD, 'AND'):
         result, error = left_node.anded_by(right_node)
     elif node.op_token.matches(TP_KEYWORD, 'OR'):
         result, error = left_node.ored_by(right_node)
     if runtime_result.should_return():
         return runtime_result.failure(runtime_result)
     if error:
         return runtime_result.failure(error)
     return runtime_result.success(
         result.set_position(node.start_pos, node.end_pos))
 def visit_continuenode(self, node, context):
     """
     Visits the ContinueNode instance.
     :param node: The ContinueNode instance.
     :param context: The caller's context.
     :return: The RuntimeResult of a successful CONTINUE.
     """
     return RuntimeResult().success_continue()
 def visit_whilenode(self, node, context):
     """
     Visits the WhileNode for while-loops in the stream.
     :param node: Node of the while-loop.
     :param context: Context of the caller.
     :return: List of all evaluated results.
     """
     elements = []
     runtime_result = RuntimeResult()
     while True:
         condition = runtime_result.register(
             self.visit(node.condition, context))
         if runtime_result.should_return():
             return runtime_result
         if not condition.is_true():
             break
         current_value = runtime_result.register(
             self.visit(node.body_node, context))
         if runtime_result.should_return() \
                 and runtime_result.loop_should_continue is False \
                 and runtime_result.loop_should_break is False:
             return runtime_result
         if runtime_result.loop_should_continue:
             continue
         if runtime_result.loop_should_break:
             break
         elements.append(current_value)
     return runtime_result.success(
         Number(0) if node.should_return_null else List(elements).
         set_context(context).set_position(node.start_pos, node.end_pos))
 def execute(self, args):
     """
     Executes the BuiltInFunction instance.
     :param args: List of all arguments.
     :return: Value of whichever of the exec methods were called.
     """
     runtime_result = RuntimeResult()
     exec_context = self.generate_new_context()
     method_name = 'execute_{}'.format(self.name.lower())
     method = getattr(self, method_name, self.no_visit_method)
     runtime_result.register(
         self.check_and_populate_args(method.arg_names, args, exec_context))
     if runtime_result.error:
         return runtime_result
     return_value = runtime_result.register(method(exec_context))
     if runtime_result.error:
         return runtime_result
     return return_value
 def execute_input_int(self, exec_context):
     while True:
         text = input()
         try:  # Try converting to int
             number = int(text)
             break
         except ValueError:
             print("'{}' must be an integer. Try again!".format(text))
     return RuntimeResult().success(Number(number))
 def visit_stringnode(self, node, context):
     """
     Visits the StringNode instance.
     :param node: The StringNode instance.
     :param context: The caller's Context instance.
     :return: A String instance.
     """
     return RuntimeResult().success(
         String(node.token.value).set_context(context).set_position(
             node.start_pos, node.end_pos))
 def visit_numbernode(self, node, context):
     """
     Returns the value of the Node as a Number.
     :param node: The Node with the numeric value.
     :param context: Context of the caller.
     :return: Number instance with the Node value.
     """
     return RuntimeResult().success(
         Number(node.token.value).set_context(context).set_position(
             node.start_pos, node.end_pos))
 def execute_pop(self, exec_context):
     list_ = exec_context.symbol_table.get("list")
     index = exec_context.symbol_table.get("index")
     if not isinstance(list_, List):
         return RuntimeResult().failure(
             ActiveRuntimeError("First argument must be list",
                                self.start_pos, self.end_pos, exec_context))
     if not isinstance(index, Number):
         return RuntimeResult().failure(
             ActiveRuntimeError("Second argument must be number",
                                self.start_pos, self.end_pos, exec_context))
     try:  # Try pop() command in Python
         element = list_.elements.pop(index.value)
     except IndexError:
         return RuntimeResult().failure(
             ActiveRuntimeError(
                 'Element at this index could not be removed from list because index is out of bounds',
                 self.start_pos, self.end_pos, exec_context))
     return RuntimeResult().success(element)
 def check_args(self, arg_names, args):
     """
     Checks that correct number of args are present.
     :param arg_names: List of argument names.
     :param args: List of arguments passed into func.
     :return: None, if there are no issues.
     """
     runtime_result = RuntimeResult()
     if len(args) > len(arg_names):
         return runtime_result.failure(
             ActiveRuntimeError(
                 'Too many arguments'.format(len(args) - len(arg_names)),
                 self.start_pos, self.end_pos, self.context))
     if len(args) < len(arg_names):
         return runtime_result.failure(
             ActiveRuntimeError(
                 'Too few arguments'.format(len(arg_names) - len(args)),
                 self.start_pos, self.end_pos, self.context))
     return runtime_result.success(None)
 def execute_run(self, exec_context):
     file_name = exec_context.symbol_table.get("fn")
     if not isinstance(file_name, String):
         return RuntimeResult().failure(
             ActiveRuntimeError("Second argument must be string",
                                self.start_pos, self.end_pos, exec_context))
     file_name = file_name.value
     try:
         with open(file_name, "r") as f:
             script = f.read()
     except Exception as exception:
         return RuntimeResult().failure(
             ActiveRuntimeError(
                 "Failed to load script \"{}\"\n".format(file_name) +
                 str(exception), self.start_pos, self.end_pos,
                 exec_context))
     _, error = run(file_name, script)
     if error:
         return RuntimeResult().failure(
             ActiveRuntimeError(
                 "Failed to finish executing script \"{}\"\n".format(
                     file_name) + error.as_string(), self.start_pos,
                 self.end_pos, exec_context))
     return RuntimeResult().success(Number(0))
 def execute(self, args):
     """
     Execute a Function instance.
     :param args: Arguments being passed into the Function.
     :return: Value of the executed Function.
     """
     runtime_result = RuntimeResult()
     interpreter = Interpreter()
     exec_context = self.generate_new_context()
     runtime_result.register(
         self.check_and_populate_args(self.arg_names, args, exec_context))
     if runtime_result.should_return():
         return runtime_result
     value = runtime_result.register(
         interpreter.visit(self.body_node, exec_context))
     if runtime_result.should_return(
     ) and runtime_result.func_return_value is None:
         return runtime_result
     return_value \
         = (value if self.should_auto_return else None) or runtime_result.func_return_value or Number(0)
     return runtime_result.success(return_value)
 def visit_unaryopnode(self, node, context):
     """
     Returns result of the unary operator on the node.
     :param node: Node with which to perform a unary operation.
     :param context: Context of the caller.
     :return: Result of the unary operation on the node.
     """
     error = None
     runtime_result = RuntimeResult()
     number = runtime_result.register(self.visit(node.right_node, context))
     if runtime_result.should_return():
         return runtime_result
     if node.op_token.type == TP_MINUS:
         number, error = number.multiply_by(Number(-1))
     elif node.op_token.matches(TP_KEYWORD, 'NOT'):
         number, error = number.notted()
     if error:
         return runtime_result.failure(error)
     return runtime_result.success(
         number.set_position(node.start_pos, node.end_pos))
 def execute_print(self, exec_context):
     print(str(exec_context.symbol_table.get('value')))
     return RuntimeResult().success(Number(0))
    def visit_fornode(self, node, context):
        """
        Visits the ForNode for for-loops in the stream.
        :param node: Node of the for-loop.
        :param context: Context of the caller.
        :return: List of evaluated values.
        """
        elements = []
        runtime_result = RuntimeResult()
        start_value = runtime_result.register(
            self.visit(node.start_value_node, context))
        if runtime_result.should_return():
            return runtime_result
        end_value = runtime_result.register(
            self.visit(node.end_value_node, context))
        if runtime_result.should_return():
            return runtime_result
        if node.step_value_node:
            step_value = runtime_result.register(
                self.visit(node.step_value_node, context))
            if runtime_result.should_return():
                return runtime_result
        else:  # Default to one iteration
            step_value = Number(1)

        # Note: PEP 8 doesn't allow for lambda expressions to be assigned to
        #       variables directly. They prefer a function definition. However, this
        #       is the cleanest way to do this. Code is read more often than it's
        #       written. This expression is easier to read and understand as an
        #       inline lambda assignment.
        index = start_value.value
        if step_value.value >= 0:
            condition = lambda: index < end_value.value
        else:  # Step value must be negative
            condition = lambda: index > end_value.value

        while condition():
            context.symbol_table.set(node.var_name_token.value, Number(index))
            index += step_value.value
            current_value = runtime_result.register(
                self.visit(node.body_node, context))
            if runtime_result.should_return() \
                    and runtime_result.loop_should_continue is False \
                    and runtime_result.loop_should_break is False:
                return runtime_result
            if runtime_result.loop_should_continue:
                continue
            if runtime_result.loop_should_break:
                break
            elements.append(current_value)
        return runtime_result.success(
            Number(0) if node.should_return_null else List(elements).
            set_context(context).set_position(node.start_pos, node.end_pos))
 def execute_print_ret(self, exec_context):
     return RuntimeResult().success(
         String(str(exec_context.symbol_table.get('value'))))
 def execute_input(self, exec_context):
     text = input()
     return RuntimeResult().success(String(text))
 def execute_clear(self, exec_context):
     os.system('cls' if os.name == 'nt' else 'cls')
     return RuntimeResult().success(Number(0))
 def execute_is_string(self, exec_context):
     is_number = isinstance(exec_context.symbol_table.get("value"), String)
     return RuntimeResult().success(Number(1) if is_number else Number(0))
 def execute_is_function(self, exec_context):
     is_number = isinstance(exec_context.symbol_table.get("value"),
                            BaseFunction)
     return RuntimeResult().success(Number(1) if is_number else Number(0))