import object as obj
import ast
from evaluator import NULL, TRUE, FALSE


class Builtin(object):
    builtins = []
    
    """a builtin function"""
    def __init__(self, pattern, fn):
        self.pattern = pattern # e.g. ["print", "$obj"]
        self.fn = fn           # fn(args) where args is a dictionary
        
        Builtin.builtins.append(self)


def builtin(pattern):
    pattern = pattern.split(" ")
    
    def builtin_gen(fn):
        Builtin(pattern, fn)
        return fn
        
    return builtin_gen  
    
    
## Builtin definitions ##  

@builtin("print $obj")
def print_builtin(args, context):
    print(args["obj"])
    return NULL
    
@builtin("print $obj without newline")
def print_wn(args, context):
    print(args["obj"], end="")
    return NULL
    
@builtin("input")
def input_builtin(args, context):
    try:
        return obj.String(input())
    except (KeyboardInterrupt, EOFError):
        return NULL
        
@builtin("input with prompt $prompt")
def input_prompt_builtin(args, context):
    try:
        return obj.String(input(args["prompt"]))
    except (KeyboardInterrupt, EOFError):
        return NULL

@@ -25,16 +25,31 @@
 ort ast%0A
+import context%0A
 from eva
@@ -79,16 +79,31 @@
 E, FALSE
+, evaluate, err
 %0A%0A%0Aclass
@@ -1147,32 +1147,32 @@
 upt, EOFError):%0A
-
         return N
@@ -1155,28 +1155,1246 @@
 Error):%0A        return NULL%0A
+        %0A@builtin(%22run $block%22)%0Adef run_block_builtin(args, context):%0A    block = args%5B%22block%22%5D%0A    %0A    if type(block) != obj.Block:%0A        return err(%22the $block parameter in 'run $block' must be of type %3Cblock%3E%22)%0A    %0A    if len(block.params) %3E 0:%0A        return err(%22since no arguments are provided, $block of 'run $block' must have no parameters%22)%0A    %0A    ctx = context.enclose()%0A    return evaluate(block.body, ctx)%0A    %0A@builtin(%22run $block with $args%22)%0Adef run_block_with_args_builtin(args, context):%0A    block = args%5B%22block%22%5D%0A    b_args = args%5B%22args%22%5D%0A    %0A    if type(block) != obj.Block:%0A        return err(%22the $block parameter in 'run $block' must be of type %3Cblock%3E%22)%0A        %0A    if type(b_args) != obj.Array:%0A        return err(%22the $args parameter in 'run $block with $args' must be of type %3Carray%3E%22)%0A    %0A    if len(block.params) != len(b_args.elements):%0A        return err(%22the amount of arguments provided in 'run $block with $args' should match the number of parameters in the block%22)%0A    %0A    params = %5Bparam.value for param in block.params%5D%0A    args_dictionary = dict(zip(params, b_args.elements))%0A    %0A    ctx = context.enclose_with_args(args_dictionary)%0A    return evaluate(block.body, ctx)%0A

Add two builtin functions for running blocks