예제 #1
0
def assert_exp_length(ast, length):
    if len(ast) > length:
        msg = "Malformed %s, too many arguments: %s" % (ast[0], unparse(ast))
        raise LispError(msg)
    elif len(ast) < length:
        msg = "Malformed %s, too few arguments: %s" % (ast[0], unparse(ast))
        raise LispError(msg)
예제 #2
0
def parse_text(source):
    """Recursive method to parse the Slow Loris text into an AST"""
    # if type is list
    if type(source) == list:
        for i in range(len(source)):
            source[i] = parse_text(source[i])
        return source

    # type is string
    if len(source) > 0 and source[0] == "'":
        return ['quote', parse_text(source[1:])]
    elif '(' in source:
        start = source.find('(')
        end = find_matching_paren(source, start)
        if end == -1:
            raise LispError("Incomplete expression: %s" % source[start:])
        last = parse_text(source[end + 1:])
        if last:
            return parse_text(split_exps(source[start + 1:end])) + [last]
        else:
            return parse_text(split_exps(source[start + 1:end]))
    elif ')' in source:
        raise LispError("Expected EOF")
    else:
        return source.strip()
예제 #3
0
def assert_valid_definition(d):
    if len(d) != 2:
        msg = "Wrong number of arguments for variable definition: %s" % d
        raise LispError(msg)
    elif not isinstance(d[0], str):
        msg = "Attempted to define non-symbol as variable: %s" % d
        raise LispError(msg)
예제 #4
0
def eval_rhead(ast, env):
    assert_exp_length(ast, 2)
    ls = evaluate(ast[1], env)
    if not is_list(ls):
        raise LispError('The argument of rhead should be a list.')
    elif len(ls) == 0:
        raise LispError('And empty list has no reverse head.')
    return ls[-1]
예제 #5
0
def eval_lambda(ast, env):
    if len(ast) != 3:
        raise LispError('Wrong number of arguments to lambda form')

    if not is_list(ast[1]):
        raise LispError('The parameters of lambda should be a list.')

    return Closure(env, ast[1], ast[2])
예제 #6
0
def eval_env_vars(ast, env):
    if len(env.variables[ast[0]].params) != len(ast) - 1:
        e = "wrong number of arguments, expected %d got %d" % \
            (len(env.variables[ast[0]].params), len(ast) - 1)
        raise LispError("wrong number of arguments, expected 2 got 3")
    vals = [evaluate(t, env) for t in ast[1:]]
    return evaluate([env.variables[ast[0]]] + vals, env)
예제 #7
0
def apply(ast, env):
    closure = ast[0]
    args = ast[1:]
    if len(args) != len(closure.params):
        msg = "wrong number of arguments, expected %d got %d" \
            % (len(closure.params), len(args))
        raise LispError(msg)
    args = [evaluate(a, env) for a in args]
    bindings = dict(zip(closure.params, args))
    new_env = closure.env.extend(bindings)
    return evaluate(closure.body, new_env)
예제 #8
0
def evaluate(ast, env):
    """Evaluate an Abstract Syntax Tree in the specified environment."""
    if is_symbol(ast):
        if ast[0] == '"':
            return ast
        return env.lookup(ast)
    elif is_atom(ast):
        return ast
    elif is_list(ast):
        return eval_list(ast, env)
    else:
        raise LispError('Syntax error: %s' % unparse(ast))
예제 #9
0
def eval_list(ast, env):
    """evaluate all the built-in functions"""
    if ast[0] == 'quote':
        return eval_quote(ast, env)
    elif ast[0] == 'exit':
        return eval_exit(ast)
    elif ast[0] == 'print':
        return eval_print(ast, env)
    elif ast[0] == 'atom':
        return eval_atom(ast, env)
    elif ast[0] == 'let':
        return eval_let(ast, env)
    elif ast[0] == 'def':
        return eval_def(ast, env)
    elif ast[0] == 'lambda':
        return eval_lambda(ast, env)
    elif ast[0] == 'eq':
        return eval_eq(ast, env)
    elif ast[0] == 'set':
        return eval_set(ast, env)
    elif ast[0] == 'if':
        return eval_if(ast, env)
    elif ast[0] == 'cons':
        return eval_cons(ast, env)
    elif ast[0] == 'head':
        return eval_head(ast, env)
    elif ast[0] == 'tail':
        return eval_tail(ast, env)
    elif ast[0] == 'rhead':
        return eval_rhead(ast, env)
    elif ast[0] == 'rtail':
        return eval_rtail(ast, env)
    elif ast[0] == 'empty':
        return eval_empty(ast, env)
    elif ast[0] in [
            '+', '-', '*', '**', '/', 'mod', '<', '<=', '=', '!=', '>=', '>'
    ]:
        return eval_math(ast, env)
    elif ast[0] == 'random':
        return eval_random()
    elif ast[0] in ['int', 'float', 'str', 'type']:
        return eval_types(ast, env)
    elif ast[0] in ['str_append', 'str_split']:
        return eval_string(ast, env)
    elif is_closure(ast[0]):
        return apply(ast, env)
    elif is_symbol(ast[0]) or is_list(ast[0]):
        return evaluate([evaluate(ast[0], env)] + ast[1:], env)
    else:
        raise LispError('%s is not a function' % unparse(ast[0]))
예제 #10
0
def find_matching_paren(source, start=0):
    """Given a string and the index of an opening parenthesis, determines
    the index of the matching closing paren."""

    assert source[start] == '('
    pos = start
    open_brackets = 1
    while open_brackets > 0:
        pos += 1
        if len(source) == pos:
            raise LispError("Incomplete expression: %s" % source[start:])
        if source[pos] == '(':
            open_brackets += 1
        if source[pos] == ')':
            open_brackets -= 1
    return pos
예제 #11
0
def eval_cons(ast, env):
    assert_exp_length(ast, 3)
    ls = evaluate(ast[2], env)
    if not is_list(ls):
        raise LispError('The second argument of cons should be a list.')
    return [evaluate(ast[1], env)] + ls
예제 #12
0
def eval_empty(ast, env):
    assert_exp_length(ast, 2)
    ls = evaluate(ast[1], env)
    if not is_list(ls):
        raise LispError('The argument of empty should be a list.')
    return len(ls) == 0