Beispiel #1
0
def string_ref(arguments):
    check_argument_number('string-ref', arguments, 2, 2)

    string_atom = arguments[0]
    if not isinstance(string_atom, String):
        raise SchemeTypeError(
            "string-ref takes a string as its first argument, "
            "not a %s." % string_atom.__class__)

    char_index_atom = arguments[1]
    if not isinstance(char_index_atom, Integer):
        raise SchemeTypeError(
            "string-ref takes an integer as its second argument, "
            "not a %s." % char_index_atom.__class__)

    string = string_atom.value
    char_index = char_index_atom.value

    if char_index >= len(string):
        # FIXME: this will say 0--1 if string is ""
        raise InvalidArgument("String index out of bounds: index must be in"
                              " the range 0-%d, got %d." %
                              (len(string) - 1, char_index))

    return Character(string[char_index])
Beispiel #2
0
def make_string(arguments):
    check_argument_number('make-string', arguments, 1, 2)

    string_length_atom = arguments[0]

    if not isinstance(string_length_atom, Integer):
        raise SchemeTypeError("String length must be an integer, "
                              "got %d." % string_length_atom.__class__)

    string_length = string_length_atom.value

    if string_length < 0:
        raise InvalidArgument("String length must be non-negative, "
                              "got %d." % string_length)

    if len(arguments) == 1:
        return String(' ' * string_length)

    else:
        repeated_character_atom = arguments[1]

        if not isinstance(repeated_character_atom, Character):
            raise SchemeTypeError("The second argument to make-string must be"
                                  " a character, got a %s." %
                                  repeated_character_atom.__class__)

        repeated_character = repeated_character_atom.value
        return String(repeated_character * string_length)
def define_function(arguments, environment):
    function_name_with_parameters = arguments[0]
    function_name = function_name_with_parameters[0]

    if not isinstance(function_name, Symbol):
        raise SchemeTypeError("Function names must be symbols, not a %s." %
                              function_name.__class__)

    # check that all our arguments are symbols:
    function_parameters = function_name_with_parameters.tail

    for parameter in function_parameters:
        if not isinstance(parameter, Symbol):
            raise SchemeTypeError(
                "Function arguments must be symbols, not a %s." %
                parameter.__class__)

    # check if this function can take a variable number of arguments
    is_variadic = False

    for parameter in function_parameters:
        if parameter.value == '.':
            if is_variadic:
                raise SchemeSyntaxError(
                    "May not have . more than once in a parameter list.")
            else:
                is_variadic = True

    if is_variadic:
        return define_variadic_function(arguments, environment)
    else:
        return define_normal_function(arguments, environment)
Beispiel #4
0
def subtract(arguments):
    check_argument_number('-', arguments, 1)

    if len(arguments) == 1:
        # we just negate a single argument
        if isinstance(arguments[0], Integer):
            return Integer(-1 * arguments[0].value)
        elif isinstance(arguments[0], FloatingPoint):
            return FloatingPoint(-1 * arguments[0].value)
        else:
            raise SchemeTypeError("Subtraction is only defined for integers and "
                                  "floating point, you gave me %s." % arguments[0].__class__)

    total = copy(arguments[0])

    for argument in arguments.tail:
        if not isinstance(argument, Number):
            raise SchemeTypeError("Subtraction is only defined for numbers, "
                                  "you gave me %s." % argument.__class__)

        # subtracting a float from an integer gives us a float
        if isinstance(total, Integer) and isinstance(argument, FloatingPoint):
            total = FloatingPoint(float(total.value))

        total.value -= argument.value

    return total
Beispiel #5
0
def exp(arguments):
    check_argument_number('exp', arguments, 1, 1)

    if arguments[0].__class__ not in [Integer, FloatingPoint]:
        raise SchemeTypeError("exp only takes integers or floats, "
                              "got %s" % arguments[0].__class__)

    x1 = arguments[0].value
    return FloatingPoint(math.exp(x1))
Beispiel #6
0
def log(arguments):
    check_argument_number('log', arguments, 1, 1)

    if not isinstance(arguments[0], Number):
        raise SchemeTypeError("Log is only defined for numbers, "
                              "you gave me %s." % arguments[0].__class__)

    x1 = arguments[0].value
    return FloatingPoint(math.log(x1))
Beispiel #7
0
def modulo(arguments):
    check_argument_number('modulo', arguments, 2, 2)

    if not isinstance(arguments[0], Integer) or not isinstance(arguments[1], Integer):
        raise SchemeTypeError("modulo is only defined for integers, "
                              "got %s and %s." % (arguments[0].__class__,
                                                  arguments[1].__class__))

    return Integer(arguments[0].value % arguments[1].value)
Beispiel #8
0
def string_length(arguments):
    check_argument_number('string-length', arguments, 1, 1)

    string_atom = arguments[0]
    if not isinstance(string_atom, String):
        raise SchemeTypeError("string-length takes a string as its argument, "
                              "not a %s." % string_atom.__class__)

    string_length = len(string_atom.value)
    return Integer(string_length)
def make_lambda_function(arguments, environment):
    check_argument_number('lambda', arguments, 2)

    parameter_list = arguments[0]
    function_body = arguments.tail

    if isinstance(parameter_list, Atom):
        raise SchemeTypeError(
            "The first argument to `lambda` must be a list of variables.")

    for parameter in parameter_list:
        if not isinstance(parameter, Symbol):
            raise SchemeTypeError(
                "Parameters of lambda functions must be symbols, not %s." %
                parameter.__class__)

    def lambda_function(_arguments, _environment):
        check_argument_number('(anonymous function)', _arguments,
                              len(parameter_list), len(parameter_list))

        local_environment = {}

        for (parameter_name,
             parameter_expression) in zip(parameter_list, _arguments):
            local_environment[
                parameter_name.value], _environment = eval_s_expression(
                    parameter_expression, _environment)

        new_environment = dict(_environment, **local_environment)

        # now we have set up the correct scope, evaluate our function block
        for s_exp in function_body:
            result, new_environment = eval_s_expression(s_exp, new_environment)

        # update any global variables that weren't masked
        for variable_name in _environment:
            if variable_name not in local_environment:
                _environment[variable_name] = new_environment[variable_name]

        return (result, _environment)

    return (LambdaFunction(lambda_function), environment)
def equality(arguments):

    for argument in arguments:
        if not isinstance(argument, Number):
            raise SchemeTypeError("Numerical equality test is only defined for numbers, "
                                  "you gave me %s." % argument.__class__)

        if argument != arguments[0]:
            return Boolean(False)

    return Boolean(True)
Beispiel #11
0
def inexact(arguments):
    check_argument_number('inexact?', arguments, 1, 1)

    if isinstance(arguments[0], FloatingPoint):
        return Boolean(True)
    elif isinstance(arguments[0], Integer):
        return Boolean(False)
    else:
        raise SchemeTypeError("exact? only takes integers or floating point "
                              "numbers as arguments, you gave me ""%s." % \
                                  len(arguments))
Beispiel #12
0
def char_less_than(arguments):
    check_argument_number('char<?', arguments, 2, 2)

    if not isinstance(arguments[0], Character) or not isinstance(
            arguments[1], Character):
        raise SchemeTypeError("char<? takes only character arguments, got a "
                              "%s and a %s." %
                              (arguments[0].__class__, arguments[1].__class__))

    if arguments[0].value < arguments[1].value:
        return Boolean(True)

    return Boolean(False)
Beispiel #13
0
def eval_list(linked_list, environment):
    if not linked_list:
        raise SchemeSyntaxError("() is not syntactically valid.")

    # find the function/primitive we are calling
    function, environment = eval_s_expression(linked_list[0], environment)

    if isinstance(function, Atom):
        raise SchemeTypeError("You can only call functions, but "
                              "you gave me a %s." % function.__class__)

    # call it (internally we require the function to decide whether or
    # not to evaluate the arguments)
    return function(linked_list.tail, environment)
Beispiel #14
0
def remainder(arguments):
    check_argument_number('remainder', arguments, 2, 2)

    if not isinstance(arguments[0], Integer) or not isinstance(arguments[1], Integer):
        raise SchemeTypeError("remainder is only defined for integers, "
                              "got %s and %s." % (arguments[0].__class__,
                                                  arguments[1].__class__))

    # as with quotient, we can't use Python's integer division here because it floors rather than truncates
    x1 = arguments[0].value
    x2 = arguments[1].value
    value = x1 - (math.trunc(x1 / x2) * x2)

    return Integer(value)
Beispiel #15
0
def string_set(arguments):
    check_argument_number('string-set!', arguments, 3, 3)

    string_atom = arguments[0]
    if not isinstance(string_atom, String):
        raise SchemeTypeError(
            "string-set! takes a string as its first argument, "
            "not a %s." % string_atom.__class__)

    char_index_atom = arguments[1]
    if not isinstance(char_index_atom, Integer):
        raise SchemeTypeError(
            "string-set! takes an integer as its second argument, "
            "not a %s." % char_index_atom.__class__)

    replacement_char_atom = arguments[2]
    if not isinstance(replacement_char_atom, Character):
        raise SchemeTypeError(
            "string-set! takes a character as its third argument, "
            "not a %s." % replacement_char_atom.__class__)

    string = string_atom.value
    char_index = char_index_atom.value

    if char_index >= len(string):
        # FIXME: this will say 0--1 if string is ""
        raise InvalidArgument("String index out of bounds: index must be in"
                              " the range 0-%d, got %d." %
                              (len(string) - 1, char_index))

    characters = list(string)
    characters[char_index] = replacement_char_atom.value
    new_string = "".join(characters)

    string_atom.value = new_string

    return None
Beispiel #16
0
def quotient(arguments):
    # integer division
    check_argument_number('quotient', arguments, 2, 2)

    if not isinstance(arguments[0], Integer) or not isinstance(arguments[1], Integer):
        raise SchemeTypeError("quotient is only defined for integers, "
                              "got %s and %s." % (arguments[0].__class__,
                                                  arguments[1].__class__))

    # Python's integer division floors, whereas Scheme rounds towards zero
    x1 = arguments[0].value
    x2 = arguments[1].value
    result = math.trunc(x1 / x2)

    return Integer(result)
Beispiel #17
0
def define_variable(arguments, environment):
    if not isinstance(arguments[0], Symbol):
        raise SchemeTypeError(
            "Tried to assign to a %s, which isn't a symbol." %
            arguments[0].__class__)

    if arguments[0].value in environment:
        raise RedefinedVariable(
            "Cannot define %s, as it has already been defined." %
            arguments[0].value)

    variable_name = arguments[0].value
    variable_value_expression = arguments[1]

    result, environment = eval_s_expression(variable_value_expression,
                                            environment)
    environment[variable_name] = result

    return (None, environment)
Beispiel #18
0
def add(arguments):
    if not arguments:
        return Integer(0)

    if isinstance(arguments[0], Integer):
        total = Integer(0)
    elif isinstance(arguments[0], FloatingPoint):
        total = FloatingPoint(0.0)

    for argument in arguments:
        if not isinstance(argument, Number):
            raise SchemeTypeError("Addition is only defined for numbers, "
                                  "you gave me %s." % argument.__class__)

        # adding a float to an integer gives us a float
        if isinstance(total, Integer) and isinstance(argument, FloatingPoint):
            total = FloatingPoint(float(total.value))

        total.value += argument.value
    return total
Beispiel #19
0
def set_variable(arguments, environment):
    check_argument_number('set!', arguments, 2, 2)

    variable_name = arguments[0]

    if not isinstance(variable_name, Symbol):
        raise SchemeTypeError(
            "Tried to assign to a %s, which isn't a symbol." %
            variable_name.__class__)

    if variable_name.value not in environment:
        raise UndefinedVariable("Can't assign to undefined variable %s." %
                                variable_name.value)

    variable_value_expression = arguments[1]
    result, environment = eval_s_expression(variable_value_expression,
                                            environment)
    environment[variable_name.value] = result

    return (None, environment)
Beispiel #20
0
def multiply(arguments):
    if not arguments:
        return Integer(1)

    if isinstance(arguments[0], Integer):
        product = Integer(1)

    elif isinstance(arguments[0], FloatingPoint):
        product = FloatingPoint(1.0)

    for argument in arguments:
        if not isinstance(argument, Number):
            raise SchemeTypeError("Multiplication is only defined for numbers, "
                                  "you gave me %s." % argument.__class__)

        if isinstance(product, Integer) and isinstance(argument, FloatingPoint):
            product = FloatingPoint(float(product.value))

        product.value *= argument.value

    return product