Example #1
0
def cdr(e):
    '''Return the second element of a pair.'''
    util.ensure_type(lang.Cons, e)

    if e is lang.NIL:
        raise errors.WrongArgumentTypeError('wrong argument type for cdr: ' +
                'expected pair, got ' + str(e))

    return e.cdr
Example #2
0
def gensym(prefix='SYM__'):
    '''
    Generate a unique symbol with the given prefix in its name. Generated
    symbols have names that contain syntax elements, and hence can't be entered
    via the reader.
    '''
    util.ensure_type(basestring, prefix)
    return lang.Symbol(prefix + tokens.OPEN_PAREN + str(GENSYM_COUNTER()) +
            tokens.CLOSE_PAREN)
Example #3
0
def car(e):
    '''Return the first element of a pair.'''
    util.ensure_type(lang.Cons, e)

    # nil isn't allowed to be indexed into, since it has no car or cdr
    if e is lang.NIL:
        raise errors.WrongArgumentTypeError('wrong argument type for car: ' +
                'expected pair, got ' + str(e))

    return e.car
Example #4
0
def div(a, b, *rest):
    '''Divides the given numbers in sequence.'''

    util.ensure_type(numbers.Number, a, b)

    # divide all the arguments in sequence while checking type
    quotient = a / b
    for n in rest:
        util.ensure_type(numbers.Number, n)
        quotient /= n

    return quotient
Example #5
0
def sub(a, b, *rest):
    '''Subtracts the given numbers in sequence.'''

    util.ensure_type(numbers.Number, a, b)

    # subtract all the arguments in sequence while checking type
    difference = a - b
    for n in rest:
        util.ensure_type(numbers.Number, n)
        difference -= n

    return difference
Example #6
0
def add(a, b, *rest):
    '''Adds the all the given numbers together.'''

    util.ensure_type(numbers.Number, a, b)

    # add all the arguments together while checking type
    total = a + b
    for n in rest:
        util.ensure_type(numbers.Number, n)
        total += n

    return total
Example #7
0
def mul(a, b, *rest):
    '''Multiplies all the given numbers together.'''

    util.ensure_type(numbers.Number, a, b)

    # multiply all the arguments together while checking type
    product = a * b
    for n in rest:
        # stop multiplying if the product ever goes to zero
        if product == 0:
            break

        util.ensure_type(numbers.Number, n)
        product *= n

    return product
Example #8
0
def evaluate(sexp, env):
    '''
    Given an Atom or list, evaluates it using the given environment
    (global by default) and returns the result as represented in our language
    constructs.
    '''

    # symbol
    if isinstance(sexp, lang.Symbol):
        # look it up in the environment for its value
        return env[sexp]

    # atom (not a literal list)
    elif not lang.Cons.is_list(sexp):
        # it's a generic atom and evaluates to itself
        return sexp

    # list
    else:
        # we can't evaluate functions that have nothing in them
        if len(sexp) == 0:
            raise errors.ApplicationError('nothing to apply')

        # evaluate functions using their arguments
        function = evaluate(sexp.car, env)
        args = sexp.cdr

        # make sure our first item evaluated to a function
        if not isinstance(function, lang.Callable):
            raise errors.ApplicationError('wrong type to apply: ' +
                    str(function))

        # quote
        if function is primitives.quote:
            # return the argument unevaluated
            util.ensure_args(args, num_required=1)
            return args.car

        # quasiquote
        elif function is primitives.quasiquote:
            util.ensure_args(args, num_required=1)
            return quasiquote_evaluate(args.car, env)

        # function
        elif function is primitives.lambda_:
            util.ensure_args(args, num_required=2)

            arg_symbols = args.car
            body = args.cdr.car

            # return a function with the current environment as the parent
            return lang.Function(evaluate, env, arg_symbols, body)

        # macro
        elif function is primitives.macro:
            util.ensure_args(args, num_required=2)

            arg_symbols = args.car
            body = args.cdr.car

            # return a macro with the given symbols and body
            return lang.Macro(evaluate, env, arg_symbols, body)

        # macro expand
        elif function is primitives.expand:
            util.ensure_args(args, num_required=1, is_variadic=True)

            # evaluate to get the macro and its arguments
            m = evaluate(args.car, env)
            arg_expressions = [evaluate(arg, env) for arg in args.cdr]

            # make sure we got a macro
            util.ensure_type(lang.Macro, m)

            return m(evaluate, env, *arg_expressions)

        # define
        elif function is primitives.define:
            util.ensure_args(args, num_required=2)

            symbol = args.car
            value = args.cdr.car

            # make sure we're defining to a symbol
            util.ensure_type(lang.Symbol, symbol)

            # evaluate the argument, map the symbol to the result in the current
            # environment, then return the evaluated value. this allows for
            # chains of definitions, or simultaneous variable assignments to the
            # same value.
            result = evaluate(value, env)
            env[symbol] = result

            # set the function or macro name if possible
            if isinstance(result, lang.Callable):
                result.name(symbol.value)

            return result

        # cond
        elif function is primitives.cond:
            for tup in args:
                # if e is not a list, len() raises an error for us
                if len(tup) != 2:
                    # make sure each is a list of exactly two expressions
                    s = 'expected 2 expressions, got ' + str(len(tup))
                    raise errors.IncorrectArgumentCountError(s)

                # first and second list items are condition and result
                condition = tup.car
                result = tup.cdr.car

                # evaluate and return the result if condition is true
                if evaluate(condition, env):
                    return evaluate(result, env)

            # if no result is returned, result is undefined
            raise errors.ApplicationError('at least one condition must ' +
                    'evaluate to ' + tokens.TRUE)

        # logical and
        elif function is primitives.and_:
            util.ensure_args(args, num_required=2, is_variadic=True)

            # evaluate the arguments, returning the final one if none were #f,
            # otherwise the last evaluated item, #f.
            last_item = None
            for item in args:
                last_item = evaluate(item, env)
                if last_item is False:
                    break

            return last_item

        # logical or
        elif function is primitives.or_:
            util.ensure_args(args, num_required=2, is_variadic=True)

            # evaluate the arguments, returning the first one that's not #f,
            last_item = None
            for item in args:
                last_item = evaluate(item, env)
                if not last_item is False:
                    break

            return last_item

        # eval
        elif function is primitives.eval_:
            util.ensure_args(args, num_required=1)

            # evaluate the given s-expression and return it
            return evaluate(evaluate(args.car, env), env)

        # load
        elif function is primitives.load:
            util.ensure_args(args, num_required=1)
            util.ensure_type(basestring, args.car)

            # evaluate every expression in the file in sequence, top to bottom
            with open(os.path.abspath(args.car), 'r') as f:
                for result in parse(tokens.tokenize(util.file_char_iter(f))):
                    evaluate(result, env)

            # return that we were successful
            return True

        # evaluate macros
        elif isinstance(function, lang.Macro):
            # evaluate the expanded form of the macro in the current environment
            return evaluate(function(evaluate, env, *args), env)

        else:
            # evaluate args and call the function with them
            return function(evaluate, *[evaluate(arg, env) for arg in args])
Example #9
0
def power(a, b):
    '''Raises a to the power of b.'''
    util.ensure_type(numbers.Number, a, b)
    return a ** b
Example #10
0
def mod(a, b):
    '''Takes the modulus of a number.'''
    util.ensure_type(numbers.Number, a, b)
    return a % b
Example #11
0
def parse_(s):
    '''Parse a string into a list of the S-expressions it describes.'''
    util.ensure_type(basestring, s)
    return lang.Cons.build(*parse(tokens.tokenize(s)))
Example #12
0
def read(prompt):
    '''Print the prompt, read input from stdin, and return it as a string.'''
    util.ensure_type(basestring, prompt)
    return unicode(raw_input(prompt))
Example #13
0
def gt(a, b):
    '''Compare two numbers using '>'.'''
    util.ensure_type(numbers.Number, a, b)
    return (a > b)