def define(env, id, *body):
    if type(id) == List:
        # procedure definition
        head, *args = id
        env[str(head)] = Procedure(args, body)
        return List()
    else:
        assert len(body) > 0, "Expression required for assignment."
        assert len(
            body) < 2, "Cannot assign multiple values to single identifier."
        env[str(id)] = scheme.eval(body[0], env)
        return List()
예제 #2
0
def read_exprs(session, env):
    completer = WordCompleter((word for word in env.keys()))
    expr_str = ''
    prompt = '> '
    while True:
        try:
            expr_str += session.prompt(prompt, completer=completer) + '\n'
            tree = parser.parse(expr_str)
        except ParseError:
            prompt = '  '
            continue
        except UnexpectedCharacters as e:
            print(e)
            return List([])
        except KeyboardInterrupt:
            return List([])
        break
    return transformer.transform(tree)
예제 #3
0
def test_parsing():
    # symbols
    assert parse_str(r'foobar') == [Symbol('foobar')]
    assert parse_str(r'    foobar    ') == [Symbol('foobar')]
    # strings
    assert parse_str(r'"hello world"') == [String("hello world")]
    assert parse_str(r'"hello\nworld"') == [String("hello\nworld")]
    # integers
    assert parse_str(r"123") == [123]
    assert parse_str(r"-42") == [-42]
    # floats
    assert parse_str(r"3.14159265359") == [3.14159265359]
    assert parse_str(r"-2.7") == [-2.7]
    assert parse_str(r"2.99e8") == [2.99e8]
    # quote
    assert parse_str(r"'foobar") == [List([Symbol('quote'), Symbol('foobar')])]
    assert parse_str(r"'123") == [List([Symbol('quote'), Integer(123)])]
    assert parse_str(r"'()") == [List([Symbol('quote'), List([])])]
    # list
    assert parse_str(r'(1 2 3)') == [[1, 2, 3]]
    assert parse_str(r"('a 2 3)") == [
        List([[Symbol('quote'), Symbol('a')], 2, 3])
    ]
    assert parse_str("(+\n1\n2)") == [List([Symbol('+'), 1, 2])]
    assert parse_str("(define (add a b) (+ a b))") == [[
        'define', ['add', 'a', 'b'], ['+', 'a', 'b']
    ]]
예제 #4
0
def eval(expr, env):
    # self-evaluating expressions
    if type(expr) in (Integer, Float, String):
        return expr
    # symbols
    elif type(expr) == Symbol:
        if expr == Symbol('#f') or expr == Symbol('#t'):
            return expr
        try:
            return env[str(expr)]
        except KeyError:
            raise EvalError(
                f'Symbol "{expr}" not found in current environment.')
    elif type(expr) == List:
        op, *args = expr  # unpack
        proc = eval(op, env)
        if type(proc) not in (Procedure, BuiltinProcedure):
            raise EvalError(f'{op} is not a procedure.')
        if type(proc) == BuiltinProcedure:
            return proc.call(env, *args)
            # try:
            #     return proc(env, *args)
            # except TypeError as e:
            #    raise EvalError(str(e))
            # except AssertionError as e:
            #    raise EvalError(str(e))
        else:
            vals = [eval(arg, env) for arg in args]
            if len(vals) != len(proc.arguments):
                raise EvalError(
                    f'Received wrong number of arguments (expected {len(proc.arguments)} and got {len(vals)}).'
                )
            last = List()
            for expr in proc.body:
                last = eval(
                    expr,
                    env.new_child(
                        {k: vals[i]
                         for i, k in enumerate(proc.arguments)}))
            return last
    else:
        raise ValueError(f'Invalid argument passed to eval: {expr}')
예제 #5
0
 def quote(self, items):
     return List([Symbol('quote')] + items)
예제 #6
0
 def list(self, items):
     return List(items)
예제 #7
0
     lambda env, *args: _bool(reduce(operator.eq, args[1:], args[0]))),
 '<':
 _builtin(
     lambda env, *args: _bool(reduce(operator.lt, args[1:], args[0]))),
 '>':
 _builtin(
     lambda env, *args: _bool(reduce(operator.gt, args[1:], args[0]))),
 '<=':
 _builtin(
     lambda env, *args: _bool(reduce(operator.le, args[1:], args[0]))),
 '>=':
 _builtin(
     lambda env, *args: _bool(reduce(operator.ge, args[1:], args[0]))),
 # list operations
 'list':
 _builtin(lambda env, *args: List(args)),
 'length':
 _builtin(lambda env, l: len(l)),
 'cons':
 _builtin(lambda env, a, b: Pair(a, b)),
 'car':
 _builtin(builtins.car),
 'cdr':
 _builtin(builtins.cdr),
 'null?':
 _builtin(lambda env, l: _bool(len(l) == 0)),
 'pair?':
 _builtin(builtins.pair),
 # system
 'exit':
 BuiltinProcedure(lambda env: sys.exit())
def _set(env, id, val):
    env[str(id)] = scheme.eval(val, env)
    return List()
def cdr(env, val):
    if type(val) == Pair:
        return val.cdr
    else:
        return List(val[1:])
def begin(env, *args):
    last = List()
    for expr in args:
        last = scheme.eval(expr, env)
    return last