diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8174912727818c7913092bf3b2ab3615b468d764..2b17fba47721d518e099e9fb5e827b59e5c10ca8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,8 @@ ADD_EXECUTABLE(railgun main.cpp runtime/stringTable.cpp runtime/module.cpp runtime/traceback.cpp + runtime/generator.cpp + runtime/cellObject.cpp memory/heap.cpp memory/oopClosure.cpp code/binaryFileParser.cpp diff --git a/src/code/bytecode.hpp b/src/code/bytecode.hpp index 8ee38b4b34e4fe3b43f1001480794fa2e0c0b409..5c036424e2a3c5cf14194342f212bdd5a44bcbe8 100644 --- a/src/code/bytecode.hpp +++ b/src/code/bytecode.hpp @@ -33,6 +33,7 @@ public: static const unsigned char BREAK_LOOP = 80; static const unsigned char LOAD_LOCALS = 82; static const unsigned char RETURN_VALUE = 83; + static const unsigned char YIELD_VALUE = 86; static const unsigned char POP_BLOCK = 87; static const unsigned char END_FINALLY = 88; static const unsigned char BUILD_CLASS = 89; diff --git a/src/lib/builtin.py b/src/lib/builtin.py index bd42b7791f342321c113a05a0e2933544c253d79..c7f49406797e933b92c67227461b4188c44afefa 100644 --- a/src/lib/builtin.py +++ b/src/lib/builtin.py @@ -47,3 +47,41 @@ def range(*args): print "Error" return lst + +class Exception(object): + def __init__(self, *args): + self.info = args + + def __repr__(self): + return " ".join(self.info) + +class StopIteration(Exception): + pass + +def xrange(*alist): + start = 0 + step = 1 + if len(alist) == 1: + end = alist[0] + elif len(alist) == 2: + start = alist[0] + end = alist[1] + elif len(alist) == 3: + start = alist[0] + end = alist[1] + step = alist[2] + + if (start < end and step > 0): + while start < end: + yield start + start += step + elif (start > end and step < 0): + while start > end: + yield start + start += step + else: + raise StopIteration + + return + + diff --git a/src/object/hiDict.cpp b/src/object/hiDict.cpp index af2ba07f60694fe1a3393b8448babc45249e4cc8..047475db4de46fc0b4ed3a02870d8c18fc353a0a 100644 --- a/src/object/hiDict.cpp +++ b/src/object/hiDict.cpp @@ -132,10 +132,7 @@ DictIteratorKlass::DictIteratorKlass() { "dictionary-valueiterator", "dictionary-itemiterator", }; - HiDict* klass_dict = new HiDict(); - klass_dict->put(StringTable::get_instance()->next_str, - new FunctionObject(dict_iterator_next)); - set_klass_dict(klass_dict); + set_klass_dict(new HiDict()); set_name(new HiString(klass_names[iter_type])); } @@ -225,8 +222,8 @@ HiObject* dict_iteritems(ObjList args) { } template -HiObject* dict_iterator_next(ObjList args) { - DictIterator* iter = (DictIterator*)(args->get(0)); +HiObject* DictIteratorKlass::next(HiObject* x) { + DictIterator* iter = (DictIterator*)x; HiDict* adict = iter->owner(); int iter_cnt = iter->iter_cnt(); diff --git a/src/object/hiDict.hpp b/src/object/hiDict.hpp index 2c49556fbc98df28d11d717e846feb46e43703b6..a20096b4aad94b197c4aaf31f8a2a72c4f9e1716 100644 --- a/src/object/hiDict.hpp +++ b/src/object/hiDict.hpp @@ -71,6 +71,7 @@ private: public: static DictIteratorKlass* get_instance(); virtual HiObject* iter(HiObject* x) { return x; } + virtual HiObject* next(HiObject* x); }; class DictIterator : public HiObject { @@ -84,9 +85,5 @@ public: int iter_cnt() { return _iter_cnt; } void inc_cnt() { _iter_cnt++; } }; - -template -HiObject* dict_iterator_next(ObjList args); - #endif diff --git a/src/runtime/cellObject.cpp b/src/runtime/cellObject.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43a8bd9a5c7ee41b074ed080d35fce19e2e71199 --- /dev/null +++ b/src/runtime/cellObject.cpp @@ -0,0 +1,40 @@ +#include "runtime/cellObject.hpp" +#include "object/hiList.hpp" +#include "object/hiDict.hpp" +#include "object/hiString.hpp" +#include "memory/oopClosure.hpp" + +CellKlass* CellKlass::_instance = NULL; + +CellKlass* CellKlass::get_instance() { + if (_instance == NULL) { + _instance = new CellKlass(); + } + + return _instance; +} + +CellKlass::CellKlass() { + set_klass_dict(new HiDict()); + set_name(new HiString("cell")); +} + +CellObject::CellObject(HiList* t, int i) : + _table(t), + _index(i) { + set_klass(CellKlass::get_instance()); +} + +HiObject* CellObject::value() { + return _table->get(_index); +} + +size_t CellKlass::size() { + return sizeof(CellKlass); +} + +void CellKlass::oops_do(OopClosure* closure, HiObject* obj) { + CellObject* co = (CellObject*)obj; + closure->do_oop((HiObject**)&co->_table); +} + diff --git a/src/runtime/cellObject.hpp b/src/runtime/cellObject.hpp new file mode 100644 index 0000000000000000000000000000000000000000..24fa48fe322e53975fb8888ab6f4bc04947a1754 --- /dev/null +++ b/src/runtime/cellObject.hpp @@ -0,0 +1,31 @@ +#ifndef CELL_OBJECT_HPP +#define CELL_OBJECT_HPP + +#include "object/klass.hpp" +#include "object/hiObject.hpp" + +class CellKlass : public Klass { +private: + CellKlass(); + static CellKlass* _instance; + +public: + static CellKlass* get_instance(); + + virtual void oops_do(OopClosure* closure, HiObject* obj); + virtual size_t size(); +}; + +class CellObject : public HiObject { +friend class CellKlass; + +private: + HiList* _table; + int _index; + +public: + CellObject(HiList* l, int i); + HiObject* value(); +}; + +#endif diff --git a/src/runtime/frameObject.cpp b/src/runtime/frameObject.cpp index c778e1c1a8e03726fa00c44aa9a5214f8dd71265..1c5d0c445f30e3fb354b86e2be7f0e8ade9ad1e3 100644 --- a/src/runtime/frameObject.cpp +++ b/src/runtime/frameObject.cpp @@ -181,6 +181,20 @@ HiString* FrameObject::func_name() { } int FrameObject::lineno() { - return _pc; + int pc_offset = 0; + int line_no = _codes->_lineno; + + const char* lnotab = _codes->_notable->value(); + int length = _codes->_notable->length(); + + for (int i = 0; i < length; i++) { + pc_offset += lnotab[i++]; + if (pc_offset >= _pc) + return line_no; + + line_no += lnotab[i]; + } + + return line_no; } diff --git a/src/runtime/functionObject.cpp b/src/runtime/functionObject.cpp index b7ac3b96914479332ee88570b2f7460789bce6fa..39957ba7428b9341d0c1910bcea57f6919adcb9f 100644 --- a/src/runtime/functionObject.cpp +++ b/src/runtime/functionObject.cpp @@ -218,6 +218,15 @@ bool MethodObject::is_function(HiObject *x) { return false; } +bool MethodObject::is_yield_function(HiObject *x) { + Klass* k = x->klass(); + if (k != (Klass*) FunctionKlass::get_instance()) + return false; + + FunctionObject* fo = (FunctionObject*)x; + return ((fo->flags() & FunctionObject::CO_GENERATOR) != 0); +} + size_t NativeFunctionKlass::size() { return sizeof(FunctionObject); } @@ -233,3 +242,7 @@ void NativeFunctionKlass::oops_do(OopClosure* f, HiObject* obj) { f->do_array_list(&fo->_defaults); } +HiObject* iter(ObjList args) { + return args->get(0)->iter(); +} + diff --git a/src/runtime/functionObject.hpp b/src/runtime/functionObject.hpp index 1c6fafdeb948062894b1013f3921a13b0ecaf3cd..8691731322de861ebda87acdf27575a31b452db9 100644 --- a/src/runtime/functionObject.hpp +++ b/src/runtime/functionObject.hpp @@ -107,6 +107,7 @@ public: FunctionObject* func() { return _func; } static bool is_function(HiObject* x); + static bool is_yield_function(HiObject* x); }; class NativeFunctionKlass : public Klass { @@ -122,6 +123,7 @@ public: }; HiObject* len(ObjList args); +HiObject* iter(ObjList args); HiObject* type_of(ObjList args); HiObject* isinstance(ObjList args); HiObject* builtin_super(ObjList args); diff --git a/src/runtime/generator.cpp b/src/runtime/generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd0f258592aa5290c415b511e070296af69f4c60 --- /dev/null +++ b/src/runtime/generator.cpp @@ -0,0 +1,48 @@ +#include "runtime/generator.hpp" +#include "runtime/functionObject.hpp" +#include "runtime/frameObject.hpp" +#include "runtime/interpreter.hpp" +#include "code/codeObject.hpp" +#include "object/hiDict.hpp" +#include "object/hiList.hpp" +#include "memory/oopClosure.hpp" + +GeneratorKlass* GeneratorKlass::instance = NULL; + +GeneratorKlass::GeneratorKlass() { +} + +GeneratorKlass* GeneratorKlass::get_instance() { + if (instance == NULL) + instance = new GeneratorKlass(); + + return instance; +} + +HiObject* GeneratorKlass::iter(HiObject* obj) { + return obj; +} + +HiObject* GeneratorKlass::next(HiObject* obj) { + assert(obj->klass() == (Klass*) this); + Generator* g = (Generator*) obj; + return Interpreter::get_instance()->eval_generator(g); +} + +size_t GeneratorKlass::size() { + return sizeof(Generator); +} + +void GeneratorKlass::oops_do(OopClosure* f, HiObject* obj) { + Generator* g = (Generator*)obj; + assert(g->klass() == (Klass*)this); + + if (g->frame()) + g->frame()->oops_do(f); +} + +Generator::Generator(FunctionObject* func, ArrayList* args, int arg_cnt) { + _frame = new FrameObject(func, args, arg_cnt); + set_klass(GeneratorKlass::get_instance()); +} + diff --git a/src/runtime/generator.hpp b/src/runtime/generator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e33540b8faf639157f1a8e0bd56d7a99e646ca50 --- /dev/null +++ b/src/runtime/generator.hpp @@ -0,0 +1,51 @@ +#ifndef GENERATOR_HPP +#define GENERATOR_HPP + +#include "object/hiObject.hpp" +#include "object/klass.hpp" +#include "util/arrayList.hpp" +#include "util/stack.hpp" + +class OopClosure; +class FunctionObject; +class CodeObject; +class HiDict; +class HiList; + +class FrameObject; +class Interpreter; + +class Block; + +class GeneratorKlass : public Klass { +private: + static GeneratorKlass* instance; + GeneratorKlass(); + +public: + static GeneratorKlass* get_instance(); + + virtual HiObject* next(HiObject* obj); + virtual HiObject* iter(HiObject* obj); + + virtual size_t size(); + virtual void oops_do(OopClosure* f, HiObject* obj); +}; + +class Generator : public HiObject { +friend class Interpreter; +friend class FrameObject; +friend class GeneratorKlass; + +private: + FrameObject* _frame; + +public: + Generator(FunctionObject* func, ArrayList* args, int arg_cnt); + + FrameObject* frame() { return _frame; } + void set_frame(FrameObject* x) { _frame = x; } +}; + +#endif + diff --git a/src/runtime/interpreter.cpp b/src/runtime/interpreter.cpp index 770a52999c9a1e520746ea08fcef5f9cab48e6c8..e3e6d0e962febeba4a4cb3e778eb467cae252bc9 100644 --- a/src/runtime/interpreter.cpp +++ b/src/runtime/interpreter.cpp @@ -5,8 +5,11 @@ #include "runtime/stringTable.hpp" #include "runtime/module.hpp" #include "runtime/traceback.hpp" +#include "runtime/generator.hpp" +#include "runtime/cellObject.hpp" #include "util/arrayList.hpp" #include "util/map.hpp" +#include "util/handles.hpp" #include "object/hiString.hpp" #include "object/hiInteger.hpp" #include "object/hiList.hpp" @@ -53,6 +56,7 @@ Interpreter::Interpreter() { _builtins->put(new HiString("None"), Universe::HiNone); _builtins->put(new HiString("len"), new FunctionObject(len)); + _builtins->put(new HiString("iter"), new FunctionObject(iter)); _builtins->put(new HiString("type"), new FunctionObject(type_of)); _builtins->put(new HiString("isinstance"),new FunctionObject(isinstance)); _builtins->put(new HiString("super"), new FunctionObject(builtin_super)); @@ -87,6 +91,11 @@ void Interpreter::build_frame(HiObject* callable, ObjList args, int op_arg) { args->insert(0, method->owner()); build_frame(method->func(), args, op_arg + 1); } + else if (MethodObject::is_yield_function(callable)) { + Generator* gtor = new Generator((FunctionObject*) callable, args, op_arg); + PUSH(gtor); + return; + } else if (callable->klass() == FunctionKlass::get_instance()) { FrameObject* frame = new FrameObject((FunctionObject*) callable, args, op_arg); frame->set_sender(_frame); @@ -188,12 +197,18 @@ void Interpreter::eval_frame() { FunctionObject* fo; ArrayList* args = NULL; HiObject *v, *w, *u; + unsigned char op_code; + bool has_argument; + int op_arg; while (_frame->has_more_codes()) { - unsigned char op_code = _frame->get_op_code(); - bool has_argument = (op_code & 0xFF) >= ByteCode::HAVE_ARGUMENT; + if (_int_status != IS_OK) + goto fast_handle_exception; + + op_code = _frame->get_op_code(); + has_argument = (op_code & 0xFF) >= ByteCode::HAVE_ARGUMENT; - int op_arg = -1; + op_arg = -1; if (has_argument) { op_arg = _frame->get_op_arg(); } @@ -283,15 +298,25 @@ void Interpreter::eval_frame() { case ByteCode::LOAD_CLOSURE: v = _frame->closure()->get(op_arg); - if (v != NULL) { + if (v == NULL) { + _frame->closure()->set(op_arg, (_frame->get_cell_from_parameter(op_arg))); + } + + v = _frame->closure()->get(op_arg); + if (v->klass() == CellKlass::get_instance()) { PUSH(v); - break; } - PUSH(_frame->get_cell_from_parameter(op_arg)); + else + PUSH(new CellObject(_frame->closure(), op_arg)); + break; case ByteCode::LOAD_DEREF: - PUSH(_frame->closure()->get(op_arg)); + v = _frame->closure()->get(op_arg); + if (v->klass() == CellKlass::get_instance()) { + v = ((CellObject*)v)->value(); + } + PUSH(v); break; case ByteCode::STORE_NAME: @@ -491,11 +516,28 @@ void Interpreter::eval_frame() { break; case ByteCode::EXC_MATCH: + { + bool found = false; + Klass* k = ((HiTypeObject*)v)->own_klass(); + if (v == w) + found = true; + else { + for (int i = 0; i < k->mro()->size(); i++) { + if (v->klass()->mro()->get(i) == w) { + found = true; + break; + } + } + } + + if (found) PUSH(Universe::HiTrue); else PUSH(Universe::HiFalse); + break; + } default: printf("Error: Unrecognized compare op %d\n", op_arg); @@ -633,7 +675,7 @@ void Interpreter::eval_frame() { case ByteCode::IMPORT_FROM: v = _frame->names()->get(op_arg); w = TOP(); - u = w->getattr(v); + u = ((ModuleObject*)w)->get(v); PUSH(u); break; @@ -685,10 +727,18 @@ void Interpreter::eval_frame() { break; + case ByteCode::YIELD_VALUE: + // we are assured that we're in the progress + // of evalating generator. + _int_status = IS_YIELD; + _ret_value = TOP(); + return; + default: printf("Error: Unrecognized byte code %d\n", op_code); } +fast_handle_exception: while (_int_status != IS_OK && _frame->_loop_stack->size() != 0) { b = _frame->_loop_stack->get(_frame->_loop_stack->size()-1); if (_int_status == IS_CONTINUE && b->_type == ByteCode::SETUP_LOOP) { @@ -778,7 +828,7 @@ Interpreter::Status Interpreter::do_raise(HiObject* exc, HiObject* val, HiObject } if (exc->klass() == TypeKlass::get_instance()) { - _pending_exception = call_virtual(_pending_exception, NULL); + _pending_exception = call_virtual(exc, NULL); _exception_class = exc; } else { @@ -789,3 +839,22 @@ Interpreter::Status Interpreter::do_raise(HiObject* exc, HiObject* val, HiObject return IS_EXCEPTION; } +HiObject* Interpreter::eval_generator(Generator* g) { + Handle handle(g); + enter_frame(g->frame()); + g->frame()->set_entry_frame(true); + eval_frame(); + + if (_int_status != IS_YIELD) { + _int_status = IS_OK; + leave_frame(); + ((Generator*)handle())->set_frame(NULL); + return NULL; + } + + _int_status = IS_OK; + _frame = _frame->sender(); + + return _ret_value; +} + diff --git a/src/runtime/interpreter.hpp b/src/runtime/interpreter.hpp index 63e9041b7a6a7fe32e281114f98b22fc74c6711a..8e00df3af52e5c0e8e9848449cc1b4dd24945347 100644 --- a/src/runtime/interpreter.hpp +++ b/src/runtime/interpreter.hpp @@ -8,6 +8,7 @@ class FrameObject; class HiDict; class OopClosure; class ModuleObject; +class Generator; class Interpreter { enum Status { @@ -16,6 +17,7 @@ class Interpreter { IS_CONTINUE, IS_EXCEPTION, IS_RETURN, + IS_YIELD, }; private: @@ -44,6 +46,7 @@ public: void enter_frame (FrameObject* frame); void eval_frame (); void leave_frame (); + HiObject* eval_generator (Generator* g); HiObject* call_virtual (HiObject* func, ObjList args); Status do_raise (HiObject* exc, HiObject* val, HiObject* tb); diff --git a/src/util/handles.cpp b/src/util/handles.cpp index 5e032594f0b2e713cd9f65eb03cac9743f4860f3..6e82a30d4000ff15549d18e03128fefdd43d2484 100644 --- a/src/util/handles.cpp +++ b/src/util/handles.cpp @@ -1,32 +1,40 @@ #include "util/handles.hpp" #include "memory/oopClosure.hpp" -HandleMark* HandleMark::instance = new HandleMark(); +#include + +HandleMark* HandleMark::instance = NULL; HandleMark::HandleMark() { _head = 0x0; } HandleMark* HandleMark::get_instance() { + if (!instance) + instance = new HandleMark(); + return instance; } void HandleMark::oops_do(OopClosure* f) { - if (_head) - _head->oops_do(f); + Handle* cur = _head; + while (cur) { + cur->oops_do(f); + cur = cur->_next; + } } Handle::Handle(HiObject* t) { _value = t; - _next = HandleMark::instance->_head; - HandleMark::instance->_head = this; + _next = HandleMark::get_instance()->head(); + HandleMark::get_instance()->set_head(this); } Handle::~Handle() { _value = 0x0; - HandleMark::instance->_head = _next; + HandleMark::get_instance()->set_head(_next); _next = 0x0; } diff --git a/src/util/handles.hpp b/src/util/handles.hpp index 69b9ba3f58be4cd7ff480a2f19b72f38f26924d4..f183cd29f7c8efc2a0c4b9651a168008265ea753 100644 --- a/src/util/handles.hpp +++ b/src/util/handles.hpp @@ -5,6 +5,8 @@ class HiObject; class OopClosure; class Handle { +friend class HandleMark; +private: HiObject* _value; Handle* _next; @@ -14,11 +16,11 @@ public: void oops_do(OopClosure* f); HiObject* operator ->(); + HiObject* operator ()() { return _value; } HiObject* resolve(); }; class HandleMark { -friend class Handle; private: static HandleMark* instance; Handle* _head; @@ -28,6 +30,8 @@ public: static HandleMark* get_instance(); void oops_do(OopClosure* f); + Handle* head() { return _head; } + void set_head(Handle* x) { _head = x; } }; #endif diff --git a/test/test_buildin.py b/test/test_buildin.py deleted file mode 100644 index e4fafd84ec4e0fc5bd2465b4b78f5e8d8182e4a6..0000000000000000000000000000000000000000 --- a/test/test_buildin.py +++ /dev/null @@ -1,4 +0,0 @@ -True, False = 0, 1 - -if False: - print "hello" diff --git a/test/test_builtin.py b/test/test_builtin.py index 33a586664385754185b6ca344b48204c74d90e95..2b2f7dbabf2d97628f9047cf2fc9c691eea64cb3 100644 --- a/test/test_builtin.py +++ b/test/test_builtin.py @@ -1,3 +1,13 @@ print range(3) print range(0, 10) print range(10, 0, -2) + +lst = list() +i = 0 +while i < 10: + lst.append(i) + i += 1 + +print map(lambda x : x * 2, lst) +print filter(lambda x : x % 2 == 1, lst) +print sum(lst, 0) diff --git a/test/test_closure.py b/test/test_closure.py index ce2382fb9e94cdcc5ffcd53c51f2513b596b7410..578cfb243eeea3d927654256c22ae7f24abf8416 100644 --- a/test/test_closure.py +++ b/test/test_closure.py @@ -23,3 +23,27 @@ f() f, g = f() f() g() + +def func(x = 5): + def say(): + print x + + x = 3 + print x + return say + +f = func() +print "hello" +f() + +def foo(): + x = 2 + def bar(): + print x + + x = 3 + + return bar + +f = foo() +f() diff --git a/test/test_fib_class.py b/test/test_fib_class.py index bed355ef5fcbf2d261b63827294cf18340218926..d220c914f24143aa36737230de3983ec4f839f72 100644 --- a/test/test_fib_class.py +++ b/test/test_fib_class.py @@ -20,3 +20,19 @@ class Fib(object): f = Fib() for i in f: print i + +def fib(n): + i = 0 + a = 1 + b = 1 + while i < n: + yield a + i += 1 + t = a + a = a + b + b = t + + return + +for i in fib(10): + print i diff --git a/test/test_yield.py b/test/test_yield.py new file mode 100644 index 0000000000000000000000000000000000000000..557830570f7d9f28afad1c1b76f1c73556081c8c --- /dev/null +++ b/test/test_yield.py @@ -0,0 +1,10 @@ +def foo(): + i = 0 + while i < 10: + yield i + i += 1 + + return + +for i in foo(): + print i