def import_file(env): def extract_string(cap_string): if cap_string.__class__ is not strtools.CapString: throw_exception('ExpectedString', '{0} is not a string'.format(cap_string)) return cap_string.contents def read_entire_text_file(filename): filename = extract_string(filename) with open(filename, 'r') as file_obj: return strtools.CapString(file_obj.read()) def write_entire_text_file(filename, contents): filename = extract_string(filename) contents = extract_string(contents) with open(filename, 'w') as file_obj: file_obj.write(contents) env.assign( 'readEntireTextFile', builtin_function.BuiltinFunction('readEntireTextFile', ['filename'], read_entire_text_file)) env.assign( 'writeEntireTextFile', builtin_function.BuiltinFunction('writeEntireTextFile', ['filename', 'contents'], write_entire_text_file))
def table_methods(obj, name, env): if name == 'length' or name == 'size': return builtin_function.BuiltinFunction('constant', [], lambda: len(obj)) elif name == 'keys': return builtin_function.BuiltinFunction('constant', [], lambda: obj.keys()) elif name == 'hasKey': return builtin_function.BuiltinFunction('hasKey', ['key'], lambda key: obj.has_key(key)) return None
def import_pretty_print(env): env.assign( 'prettyFormat', builtin_function.BuiltinFunction('prettyFormat', ['obj'], pretty_print.pretty_format_wrapper)) env.assign( 'prettyPrint', builtin_function.BuiltinFunction('prettyPrint', ['obj'], pretty_print.pretty_print))
def import_debugging(env): env.assign( 'getFrames', builtin_function.BuiltinFunction('getFrames', [], lambda: env.frames)) env.assign( 'getThisFrames', builtin_function.BuiltinFunction('getThisFrames', [], lambda: env.this_pointers)) env.assign( 'repl', builtin_function.BuiltinFunction('repl', [], lambda: capacita.repl(env)))
def str_methods(obj, name, env): if name == 'length' or name == 'size': # Strings are immutable, so only call len() once length = len(obj) return builtin_function.BuiltinFunction('constant', [], lambda: length) elif name == 'ord' or name == 'charNum': def char_num(string): if len(string) == 0: throw_exception( 'StringEmpty', 'Cannot convert first character to integer when string is empty' ) return ord(string[0]) return builtin_function.BuiltinFunction('charNum', [], lambda: char_num(obj)) elif name == 'charAt': return builtin_function.BuiltinFunction('charAt', ['i'], lambda i: strtools.index_string(obj, i)) elif name == 'insertAt': def insert_at(index, substr): strtools.validate_string_index(obj, index) return strtools.CapString(obj.contents[0:index] + substr.contents + obj.contents[index:], False) return builtin_function.BuiltinFunction('insertAt', ['index', 'substr'], insert_at) elif name == '$internals': # View internals of a string, for debugging purposes. print(repr(obj)) return builtin_function.BuiltinFunction('constant', [], lambda: None) elif name == 'slice': def slice_string(start, stop=None): strtools.validate_string_index(obj, start) if stop is not None: strtools.validate_string_index(obj, stop) return strtools.CapString(obj.contents[start:stop], False) else: return strtools.CapString(obj.contents[start:], False) return builtin_function.BuiltinFunction('slice', ['start', 'stop?'], slice_string) elif name == 'replaceSlice': def replace_slice(start, stop, substr): strtools.validate_string_index(obj, start) strtools.validate_string_index(obj, stop) return strtools.CapString(obj.contents[0:start] + substr.contents + obj.contents[stop:]) return builtin_function.BuiltinFunction('replaceSlice', ['start', 'stop', 'substr'], replace_slice) contents = obj.contents if name == 'split': def split_string(separator=None): if separator is None: return [strtools.CapString(elem, False) for elem in contents.split()] else: separator = separator.contents return [strtools.CapString(elem, False) for elem in contents.split(separator)] return builtin_function.BuiltinFunction('split', ['separator?'], split_string) elif name == 'find': def find_in_string(string, substr): result = string.find(substr) if result == -1: return None return result return builtin_function.BuiltinFunction('find', ['substring'], lambda s: find_in_string(contents, s.contents)) return None
def import_data_structures(env): def list_range(start, stop, step=1): return range(start, stop + 1, step) env.assign( 'ListRange', builtin_function.BuiltinFunction('ListRange', ['start', 'stop', 'step?'], list_range))
def curry(f): num_args = f.get_num_args() if num_args <= 1: return f else: def curried_f(x): partially_applied_f = partial(f, [x]) return curry(partially_applied_f) return builtin_function.BuiltinFunction('g', ['x'], curried_f)
def import_random(env): def throw_select_on_empty_list(): throw_exception('SelectOnEmptyList', "Can't select item from empty list") def select(lst): if len(lst) == 0: throw_select_on_empty_list() return random.sample(lst, 1)[0] def select_and_remove(lst): if len(lst) == 0: throw_select_on_empty_list() index = random.randint(0, len(lst) - 1) return lst.pop(index) def shuffle_and_return(lst): random.shuffle(lst) return lst env.assign( 'randInt', builtin_function.BuiltinFunction('randInt', ['a', 'b'], random.randint)) env.assign( 'randDouble', builtin_function.BuiltinFunction('randDouble', [], random.random)) env.assign( 'shuffle', builtin_function.BuiltinFunction('shuffle', ['lst'], shuffle_and_return)) env.assign('select', builtin_function.BuiltinFunction('select', ['lst'], select)) env.assign( 'selectAndRemove', builtin_function.BuiltinFunction('selectAndRemove', ['lst'], select_and_remove))
def partial(f, fixed_args): num_original_args = f.get_num_args() num_fixed_args = len(fixed_args) num_args_needed = num_original_args - num_fixed_args if num_args_needed < 0: throw_exception( 'TooManyFixedArguments', 'Function {0} requires {1} arguments, but passing in {2}'. format(f.name, num_original_args, num_fixed_args)) arg_names = ['x' + str(i) for i in xrange(num_args_needed)] def partially_applied_f(*args): return f.execute(fixed_args + list(args), env) return builtin_function.BuiltinFunction('fPrime', arg_names, partially_applied_f)
def number_methods(obj, name, env): if name == 'next': return builtin_function.BuiltinFunction('constant', [], lambda: obj + 1) elif name == 'previous': return builtin_function.BuiltinFunction('constant', [], lambda: obj - 1) if type(obj) in [int, long]: if name == 'toChar': return builtin_function.BuiltinFunction('toChar', [], lambda: strtools.CapString(chr(obj), False)) elif name == 'bitNot': return builtin_function.BuiltinFunction('bitNot', [], lambda: ~obj) elif name == 'bitAnd': return builtin_function.BuiltinFunction('bitAnd', ['n'], lambda n: obj & n) elif name == 'bitOr': return builtin_function.BuiltinFunction('bitOr', ['n'], lambda n: obj | n) elif name == 'bitXor': return builtin_function.BuiltinFunction('bitXor', ['n'], lambda n: obj ^ n) elif name == 'bitNand': return builtin_function.BuiltinFunction('bitNand', ['n'], lambda n: ~(obj & n)) elif name == 'bitNor': return builtin_function.BuiltinFunction('bitNor', ['n'], lambda n: ~(obj | n)) elif name == 'bitXnor': return builtin_function.BuiltinFunction('bitXnor', ['n'], lambda n: ~(obj ^ n)) elif name == 'toBin': # The bin function will add '0b' to the beginning of the binary string, which should be removed return builtin_function.BuiltinFunction('toBin', [], lambda: strtools.CapString(remove_radix_prefix(bin(obj)), False)) elif name == 'toHex': # The hex function will add '0x' to the beginning of the hexadecimal string, which should be removed return builtin_function.BuiltinFunction('toHex', [], lambda: strtools.CapString(remove_radix_prefix(hex(obj)), False)) elif name == 'toUnsignedBits': return builtin_function.BuiltinFunction('toUnsignedBits', [], lambda: strtools.CapString(to_unsigned_bits(obj), False)) elif name == 'getBit': return builtin_function.BuiltinFunction('getBit', ['i'], lambda i: (obj & (1 << i)) >> i) elif name == 'setBit': return builtin_function.BuiltinFunction('setBit', ['i'], lambda i: obj | (1 << i)) elif name == 'resetBit': return builtin_function.BuiltinFunction('resetBit', ['i'], lambda i: obj & ~(1 << i)) elif name == 'toggleBit': return builtin_function.BuiltinFunction('toggleBit', ['i'], lambda i: obj ^ (1 << i)) elif name == 'toBase': return builtin_function.BuiltinFunction('toBase', ['base'], lambda base: strtools.CapString(to_base(obj, base), False)) elif name == 'getDigit': return builtin_function.BuiltinFunction('getDigit', ['index', 'base?'], lambda index, base=10: get_digit(obj, index, base)) elif name == 'setDigit': return builtin_function.BuiltinFunction('setDigit', ['index', 'newDigit', 'base?'], lambda index, new_digit, base=10: set_digit(obj, index, base, new_digit)) elif name == 'shiftLeft': return builtin_function.BuiltinFunction('shiftLeft', ['numDigits', 'base?'], lambda num_digits, base=2: shift_left(obj, num_digits, base)) elif name == 'shiftRight': return builtin_function.BuiltinFunction('shiftRight', ['numDigits', 'base?'], lambda num_digits, base=2: shift_right(obj, num_digits, base)) return None
def import_math(env): def binomial_choose(n, k): if k < 0 or k > n: return 0 result = 1 for i in xrange(1, min(k, n - k) + 1): # Do not use # result *= (n + 1 - i) / i # since dividing by i before multiplying # by result may have rounding errors result = (result * (n + 1 - i)) / i return result def fib(n): # Use the matrix form of Fibonacci numbers # to perform the computation in O(log(n)) operations. # Please see the Wikipedia page on Fibonacci numbers # for more information. if n == 0 or n == 1: return n def is_odd(n): return (n & 1) == 1 if is_odd(n): k = (n + 1) / 2 return fib(k)**2 + fib(k - 1)**2 else: k = n / 2 fib_k = fib(k) return 2 * fib(k - 1) * fib_k + fib_k**2 def differentiate(f, dx=1e-6): def f_prime(x): df = f.execute([x + dx], env) - f.execute([x], env) return df / dx return builtin_function.BuiltinFunction('fPrime', ['x'], f_prime) def integrate(f, a, b, num_rectangles=1000): if b < a: return -integrate(f, b, a, num_rectangles) current_sum = 0 dx = (b - a) / float(num_rectangles) while a < b: current_sum += f.execute([a], env) * dx a += dx return current_sum env.assign('pi', math.pi) env.assign('e', math.e) env.assign('phi', 1.6180339887498948482) env.assign('infinity', float('inf')) env.assign('negativeInfinity', -float('inf')) env.assign('nan', float('nan')) env.assign('sqrt', builtin_function.BuiltinFunction('sqrt', ['x'], math.sqrt)) env.assign( 'cbrt', builtin_function.BuiltinFunction('cbrt', ['x'], lambda x: x**0.3333333333333333333)) env.assign( 'log', builtin_function.BuiltinFunction('log', ['x', 'b'], lambda x, b: math.log(x, b))) env.assign( 'ln', builtin_function.BuiltinFunction('ln', ['x'], lambda x: math.log(x))) env.assign( 'binomialChoose', builtin_function.BuiltinFunction('binomialChoose', ['n', 'k'], binomial_choose)) env.assign('fib', builtin_function.BuiltinFunction('fib', ['n'], fib)) env.assign( 'factorial', builtin_function.BuiltinFunction('factorial', ['n'], math.factorial)) env.assign( 'differentiate', builtin_function.BuiltinFunction('differentiate', ['f', 'epsilon?'], differentiate)) env.assign('min', builtin_function.BuiltinFunction('min', ['n', '[args]'], min)) env.assign('max', builtin_function.BuiltinFunction('max', ['n', '[args]'], max)) env.assign( 'integrate', builtin_function.BuiltinFunction('integrate', ['f', 'a', 'b', 'numRectangles?'], integrate)) env.assign('sin', builtin_function.BuiltinFunction('sin', ['x'], math.sin)) env.assign('cos', builtin_function.BuiltinFunction('cos', ['x'], math.cos)) env.assign('atan', builtin_function.BuiltinFunction('atan', ['x'], math.atan)) env.assign( 'atan2', builtin_function.BuiltinFunction('atan2', ['y', 'x'], math.atan2))
def compose(f, g): def h(x): return f.execute([g.execute([x], env)], env) return builtin_function.BuiltinFunction('h', ['x'], h)
def import_functional(env): def compose(f, g): def h(x): return f.execute([g.execute([x], env)], env) return builtin_function.BuiltinFunction('h', ['x'], h) def map_prime(f, lst): return map(lambda x: f.execute([x], env), lst) def filter_prime(predicate, lst): return filter(lambda x: predicate.execute([x], env), lst) def flip(f): return builtin_function.BuiltinFunction( 'g', ['x', 'y'], lambda x, y: f.execute([y, x], env)) def fold_left(f, lst): if len(lst) < 2: return lst[0] result = f.execute(lst[:2], env) lst = lst[2:] for elem in lst: result = f.execute([result, elem], env) return result def fold_right(f, lst): if len(lst) < 2: return lst[0] result = f.execute(lst[-2:], env) lst = lst[:-2] for elem in reversed(lst): result = f.execute([elem, result], env) return result def any_prime(f, lst): for elem in lst: result = f.execute([elem], env) if result: return True return False def all_prime(f, lst): for elem in lst: result = f.execute([elem], env) if not result: return False return True def curry(f): num_args = f.get_num_args() if num_args <= 1: return f else: def curried_f(x): partially_applied_f = partial(f, [x]) return curry(partially_applied_f) return builtin_function.BuiltinFunction('g', ['x'], curried_f) def partial(f, fixed_args): num_original_args = f.get_num_args() num_fixed_args = len(fixed_args) num_args_needed = num_original_args - num_fixed_args if num_args_needed < 0: throw_exception( 'TooManyFixedArguments', 'Function {0} requires {1} arguments, but passing in {2}'. format(f.name, num_original_args, num_fixed_args)) arg_names = ['x' + str(i) for i in xrange(num_args_needed)] def partially_applied_f(*args): return f.execute(fixed_args + list(args), env) return builtin_function.BuiltinFunction('fPrime', arg_names, partially_applied_f) def feed(*args): if len(args) == 0: throw_exception('NotEnoughArguments', 'Function requires at least 1 argument') result = args[0] for elem in args[1:]: if function.is_function(elem): result = elem.execute([result], env) elif type(elem) is list: if len(elem) == 0 or not function.is_function(elem[0]): throw_exception( 'InvalidArgument', 'List must contain a function as first element') f = elem[0] rest = list(elem[1:]) result = f.execute(rest + [result], env) else: throw_exception('InvalidArgument', 'Argument must be a list or function') return result env.assign( 'compose', builtin_function.BuiltinFunction('compose', ['f', 'g'], compose)) env.assign( 'map', builtin_function.BuiltinFunction('map', ['f', 'lst'], map_prime)) env.assign( 'filter', builtin_function.BuiltinFunction('filter', ['predicate', 'lst'], filter_prime)) env.assign('flip', builtin_function.BuiltinFunction('flip', ['f'], flip)) env.assign( 'foldLeft', builtin_function.BuiltinFunction('foldLeft', ['f', 'lst'], fold_left)) env.assign( 'foldRight', builtin_function.BuiltinFunction('foldRight', ['f', 'lst'], fold_right)) env.assign( 'any', builtin_function.BuiltinFunction('any', ['f', 'lst'], any_prime)) env.assign( 'all', builtin_function.BuiltinFunction('all', ['f', 'lst'], all_prime)) env.assign('curry', builtin_function.BuiltinFunction('curry', ['f'], curry)) env.assign( 'partial', builtin_function.BuiltinFunction('partial', ['f', 'fixedArgs'], partial)) env.assign( 'feed', builtin_function.BuiltinFunction('feed', ['initial', '[tasks]'], feed))
def type_tree_methods(obj, name, env): # This method allows us to view the type tree of a given environment if name == 'format': return builtin_function.BuiltinFunction('constant', [], lambda: obj.format_as_literal()) return None
def flip(f): return builtin_function.BuiltinFunction( 'g', ['x', 'y'], lambda x, y: f.execute([y, x], env))
def differentiate(f, dx=1e-6): def f_prime(x): df = f.execute([x + dx], env) - f.execute([x], env) return df / dx return builtin_function.BuiltinFunction('fPrime', ['x'], f_prime)
def list_methods(obj, name, env): if name == 'length' or name == 'size': length = len(obj) return builtin_function.BuiltinFunction('constant', [], lambda: length) elif name == 'pop': last_elem = obj.pop() return builtin_function.BuiltinFunction('constant', [], lambda: last_elem) elif name == 'push': def func_push(new_elem): obj.append(new_elem) return obj return builtin_function.BuiltinFunction('list', ['newElem'], func_push) elif name == 'removeAt': return builtin_function.BuiltinFunction('constant', ['index'], lambda i: obj.pop(i)) elif name == 'insertAt': def insert_at(index, elem): obj.insert(index, elem) return obj return builtin_function.BuiltinFunction('insertAt', ['index', 'elem'], insert_at) elif name == 'reverse': def reverse_list(): obj.reverse() return obj return builtin_function.BuiltinFunction('reverse', [], reverse_list) elif name == 'find': # Returns the position of the element in the list. # If the element is not found, returns null. def find(elem): if type(elem) is dict and '$eq' in elem: eq_method = elem['$eq'] # TODO : if there is no $eq method, and the $notEq (not equals) method # is defined, use the default definition $eq(a, b) = not $notEq(a, b) for i, item in enumerate(obj): if eq_method.execute([item], env): return i return None try: return obj.index(elem) except ValueError: return None return builtin_function.BuiltinFunction('find', ['elem'], find) elif name == 'slice': def slice(start, stop=None): if stop is None: return obj[start:] else: return obj[start:stop] return builtin_function.BuiltinFunction('slice', ['start', 'stop?'], slice) elif name == 'first': return builtin_function.BuiltinFunction('first', [], lambda: None if len(obj) == 0 else obj[0]) elif name == 'last': return builtin_function.BuiltinFunction('last', [], lambda: None if len(obj) == 0 else obj[-1]) elif name == 'rest': return builtin_function.BuiltinFunction('rest', [], lambda: obj[1:]) elif name == 'leading': return builtin_function.BuiltinFunction('leading', [], lambda: obj[:-1]) return None