def run_code(env, code): code = preprocessor.remove_comments(code) lexed = desugarizer.desugar(lexer.lex(code)) nodes = [parser.parse(tree) for tree in lexed] for node in nodes: value = env.eval(node) return value
def eval(self, program): """Evaluate this program in a fresh environment with the prelude already included. Returns the result of the last expression. """ # Fresh copy of the environment so tests don't interfere with one another. env = Environment([Scope({})]) global_scope = self.env.scopes[0] for key, value in global_scope.bindings.iteritems(): # We do a deep copy of mutable values. if isinstance(value, List): env.set(key, deepcopy(value)) elif isinstance(value, String): env.set(key, deepcopy(value)) elif isinstance(value, Bytestring): env.set(key, deepcopy(value)) else: env.set(key, value) parse_tree = parse(lex(program)) if isinstance(parse_tree, TrifleExceptionInstance): self.fail("Parse error on: %r" % program) result = NULL for expression in parse_tree.values: result = evaluate(expression, env) if is_thrown_exception(result, error): return result return result
def env_with_prelude(): """Return a fresh environment where the prelude has already been evaluated. """ # todo: document TRIFLEPATH # todo: should we inline the prelude, so changing TRIFLEPATH doens't break this? trifle_path = getenv_llimpl("TRIFLEPATH") or "." prelude_path = os.path.join(trifle_path, "prelude.tfl") # Trifle equivalent of PYTHONPATH. try: code = get_contents(prelude_path) except OSError: # TODO: work out which error occurred (not found/wrong # permissions/other) and be more helpful. print "Could not find prelude.tfl. Have you set TRIFLEPATH?" raise # TODO: either of these could return errors, and we should handle that. lexed_tokens = lex(code) parse_tree = parse(lexed_tokens) env = fresh_environment() result = evaluate_all(parse_tree, env) assert not is_thrown_exception(result, error), "Error when evaluating prelude: %s" % result return env
def test_rest_bytestring(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(rest #bytes("abc"))'))), Bytestring([ord(c) for c in b"bc"]))
def test_push_returns_null(self): self.assertEqual( evaluate_with_prelude(parse_one(lex( u"(push! (quote ()) 1)"))), NULL)
def test_last_string(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(last "abc")'))), Character(u'c'))
def test_last_bytestring(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(last #bytes("abc"))'))), Integer.fromint(99))
def test_desugar(test_case, expected): lexed = lex(test_case) actual = desugar(lexed) assert actual == expected
def test_second_string(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(second "abc")'))), Character(u'b'))
def test_map_string(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(filter (lambda (x) (equal? x \'b\')) "abc")'))), String(list(u"b")))
def test_map_bytestring(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(filter (lambda (x) (equal? x 98)) #bytes("abc"))'))), Bytestring([ord("b")]))
def test_map_string(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(map (lambda (x) \'z\') "abc")'))), String(list(u"zzz")))
def test_map_bytestring(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(map (lambda (x) (+ x 1)) #bytes("abc"))'))), Bytestring([ord(c) for c in "bcd"]))
def test_for_each(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u"""(let (total 0 numbers (list 1 2 3 4)) (for-each number numbers (set! total (+ total number))) total)"""))), Integer.fromint(10))
def test_rest_string(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(rest "abc")'))), String(list(u"bc")))
def test_fifth_bytestring(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(fifth #bytes("abcde"))'))), Integer.fromint(101))
def test_fifth_string(self): self.assertEqual( evaluate_with_prelude(parse_one(lex(u'(fifth "abcde")'))), Character(u'e'))
def entry_point(argv): """Either a file name: $ ./trifle ~/files/foo.tfl A code snippet: $ ./trifle -i '1 2' """ if len(argv) == 2: # open the file filename = argv[1] if not os.path.exists(filename): print 'No such file: %s' % filename return 2 try: env = env_with_prelude() except OSError: return 2 code = get_contents(filename) lexed_tokens = lex(code) if is_thrown_exception(lexed_tokens, error): print u'Uncaught error: %s: %s' % ( lexed_tokens.exception_type.name, lexed_tokens.message) return 1 parse_tree = parse(lexed_tokens) try: result = evaluate_all(parse_tree, env) if is_thrown_exception(result, error): # TODO: a proper stack trace. print u'Uncaught error: %s: %s' % (result.exception_type.name, result.message) return 1 except SystemExit: return 0 return 0 elif len(argv) == 3: if argv[1] == '-i': try: env = env_with_prelude() except OSError: return 2 code_snippet = argv[2].decode('utf-8') lexed_tokens = lex(code_snippet) if is_thrown_exception(lexed_tokens, error): print u'Uncaught error: %s: %s' % ( lexed_tokens.exception_type.name, lexed_tokens.message) return 1 parse_tree = parse(lexed_tokens) try: result = evaluate_all(parse_tree, env) if is_thrown_exception(result, error): # TODO: a proper stack trace. print u'Uncaught error: %s: %s' % (result.exception_type.name, result.message) return 1 else: print result.repr().encode('utf-8') except SystemExit: return 0 return 0 print USAGE return 1
def test_lexer(test_case, expected): actual = lex(test_case) assert actual == expected