diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01937b07f6dea407f7d45b8995ac8fc1c93945e7..8174912727818c7913092bf3b2ab3615b468d764 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,11 +2,12 @@ cmake_minimum_required(VERSION 2.8) PROJECT(RAILGUN) -SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall -g -ggdb ") -SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall -g -ggdb -rdynamic") +SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -rdynamic") ADD_EXECUTABLE(railgun main.cpp object/hiInteger.cpp + object/hiDouble.cpp object/hiString.cpp object/hiObject.cpp object/hiList.cpp @@ -21,9 +22,22 @@ ADD_EXECUTABLE(railgun main.cpp runtime/functionObject.cpp runtime/stringTable.cpp runtime/module.cpp + runtime/traceback.cpp memory/heap.cpp memory/oopClosure.cpp code/binaryFileParser.cpp code/codeObject.cpp) + +ADD_LIBRARY(math SHARED + extlib/math.cpp) + +ADD_CUSTOM_COMMAND(TARGET math + POST_BUILD + COMMAND mkdir -p lib + COMMAND cp libmath.so lib/ + COMMAND cp ../lib/*.py lib/ + COMMAND python -m compileall lib/*.py + ) INCLUDE_DIRECTORIES(./) +TARGET_LINK_LIBRARIES(railgun ${CMAKE_DL_LIBS}) diff --git a/src/code/binaryFileParser.cpp b/src/code/binaryFileParser.cpp index 4a0009c271212b9a40fe919cfbcdf275e161c25c..47d64c7ef069a3a3c31ee7925197e8f239e59e5d 100644 --- a/src/code/binaryFileParser.cpp +++ b/src/code/binaryFileParser.cpp @@ -4,6 +4,7 @@ #include "code/binaryFileParser.hpp" #include "runtime/universe.hpp" #include "object/hiList.hpp" +#include "object/hiDouble.hpp" BinaryFileParser::BinaryFileParser(BufferedInputStream* buf_file_stream) { file_stream = buf_file_stream; @@ -164,6 +165,9 @@ ArrayList* BinaryFileParser::get_tuple() { case 'i': list->add(new HiInteger(file_stream->read_int())); break; + case 'g': + list->add(new HiDouble(file_stream->read_double())); + break; case 'N': list->add(Universe::HiNone); break; diff --git a/src/code/bytecode.hpp b/src/code/bytecode.hpp index 45180a983dd12e92eb5fe1645599144fb15ddc5f..8ee38b4b34e4fe3b43f1001480794fa2e0c0b409 100644 --- a/src/code/bytecode.hpp +++ b/src/code/bytecode.hpp @@ -34,6 +34,7 @@ public: static const unsigned char LOAD_LOCALS = 82; static const unsigned char RETURN_VALUE = 83; static const unsigned char POP_BLOCK = 87; + static const unsigned char END_FINALLY = 88; static const unsigned char BUILD_CLASS = 89; // TODO: This is a separator @@ -62,7 +63,12 @@ public: static const unsigned char POP_JUMP_IF_FALSE = 114; static const unsigned char POP_JUMP_IF_TRUE = 115; static const unsigned char LOAD_GLOBAL = 116; /* Index in name list */ + + static const unsigned char CONTINUE_LOOP = 119; /* Start of loop (absolute) */ static const unsigned char SETUP_LOOP = 120; /* Target address (relative) */ + static const unsigned char SETUP_EXCEPT = 121; /* "" */ + static const unsigned char SETUP_FINALLY = 122; /* "" */ + static const unsigned char LOAD_FAST = 124; /* Local variable number */ static const unsigned char STORE_FAST = 125; /* Local variable number */ diff --git a/src/extlib/math.cpp b/src/extlib/math.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6caab00802227bf4733315d2d1894abf460b783f --- /dev/null +++ b/src/extlib/math.cpp @@ -0,0 +1,43 @@ +#include "inc/railgun.hpp" + +#include + +double get_double(ObjList args) { + HiObject* x = args->get(0); + double y = 0; + if (x->klass() == IntegerKlass::get_instance()) { + y = ((HiInteger*)x)->value(); + } + else if (x->klass() == DoubleKlass::get_instance()) { + y = ((HiDouble*)x)->value(); + } + return y; +} + +HiObject* math_sqrt(ObjList args) { + double x = get_double(args); + return new HiDouble(sqrt(x)); +} + +HiObject* math_sin(ObjList args) { + double x = get_double(args); + return new HiDouble(sin(x)); +} + +RGMethod math_methods[] = { + { "sin", math_sin, 0, "sin(x)", }, + { "sqrt", math_sqrt, 0, "square root of x", }, + { NULL, NULL, 0, NULL, }, +}; + +#ifdef __cplusplus +extern "C" { +#endif + +SO_PUBLIC RGMethod* init_libmath() { + return math_methods; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/inc/railgun.hpp b/src/inc/railgun.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0d4b0ac78a7485379e1027c04b455fea645b96a3 --- /dev/null +++ b/src/inc/railgun.hpp @@ -0,0 +1,19 @@ +#ifndef RAILGUN_HPP +#define RAILGUN_HPP + +#include "runtime/functionObject.hpp" +#include "object/hiInteger.hpp" +#include "object/hiDouble.hpp" + +#define SO_PUBLIC __attribute__((visibility("default"))) + +struct RGMethod { + const char* meth_name; + NativeFuncPointer meth; + int meth_info; + const char* meth_doc; +}; + +typedef RGMethod* (*INIT_FUNC)(); + +#endif diff --git a/src/lib/math.py b/src/lib/math.py new file mode 100644 index 0000000000000000000000000000000000000000..8e510ea1369c1e49397bf79480e2634af7601904 --- /dev/null +++ b/src/lib/math.py @@ -0,0 +1,5 @@ +from libmath import sin +from libmath import sqrt + +pi = 3.141592653589793 +e = 2.718281828459045 diff --git a/src/object/hiDict.cpp b/src/object/hiDict.cpp index 6f9dd7b88cced21d5d21622fda633f8112f59751..af2ba07f60694fe1a3393b8448babc45249e4cc8 100644 --- a/src/object/hiDict.cpp +++ b/src/object/hiDict.cpp @@ -103,6 +103,13 @@ HiDict::HiDict(Map* x) { set_klass(DictKlass::get_instance()); } +void HiDict::update(HiDict* dict) { + for (int i = 0; i < dict->size(); i++) { + put(dict->map()->get_key(i), + dict->map()->get_value(i)); + } +} + /* * Iterations for dict object */ diff --git a/src/object/hiDict.hpp b/src/object/hiDict.hpp index c0539f55f3f5709fcbc4138de166382fd3886cf4..2c49556fbc98df28d11d717e846feb46e43703b6 100644 --- a/src/object/hiDict.hpp +++ b/src/object/hiDict.hpp @@ -36,12 +36,15 @@ private: public: HiDict(); HiDict(Map* map); + Map* map() { return _map; } void put(HiObject* k, HiObject* v) { _map->put(k, v); } HiObject* get(HiObject* k) { return _map->get(k); } - bool has_key(HiObject* k) { return _map->has_key(k); } - int size() { return _map->size(); } + bool has_key(HiObject* k) { return _map->has_key(k); } + int size() { return _map->size(); } HiObject* remove(HiObject* k) { return _map->remove(k); } + + void update(HiDict* d); }; HiObject* dict_set_default(ObjList args); diff --git a/src/object/hiDouble.cpp b/src/object/hiDouble.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e346be668aa3fb489d1c34a8f33309efd8b25472 --- /dev/null +++ b/src/object/hiDouble.cpp @@ -0,0 +1,197 @@ +#include "object/klass.hpp" +#include "object/hiDict.hpp" +#include "object/hiString.hpp" +#include "object/hiInteger.hpp" +#include "object/hiDouble.hpp" +#include "runtime/universe.hpp" + +#include + +DoubleKlass* DoubleKlass::instance = NULL; + +DoubleKlass::DoubleKlass() { +} + +void DoubleKlass::initialize() { + set_klass_dict(new HiDict()); + set_name(new HiString("int")); + (new HiTypeObject())->set_own_klass(this); + add_super(ObjectKlass::get_instance()); +} + +HiDouble::HiDouble(double x) { + _value = x; + set_klass(DoubleKlass::get_instance()); +} + +DoubleKlass* DoubleKlass::get_instance() { + if (instance == NULL) + instance = new DoubleKlass(); + + return instance; +} + +void DoubleKlass::print(HiObject* obj) { + HiDouble* dbl_obj = (HiDouble*) obj; + assert(dbl_obj && ((char *)dbl_obj->klass()) == ((char *)this)); + printf("%.12g", dbl_obj->value()); +} + +HiObject* DoubleKlass::allocate_instance(HiObject* callable, + ArrayList* args) { + if (!args || args->length() == 0) + return new HiDouble(0); + else + return NULL; +} + +size_t DoubleKlass::size() { + return sizeof(HiDouble); +} + +void DoubleKlass::oops_do(OopClosure* f, HiObject* obj) { + // do nothing + // only overwrite warning message in Klass +} + +HiObject* DoubleKlass::greater(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + if (ix->value() > iy->value()) + return Universe::HiTrue; + else + return Universe::HiFalse; +} + +HiObject* DoubleKlass::less(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + assert(ix && (ix->klass() == (Klass *)this)); + + if (x->klass() != y->klass()) { + if (Klass::compare_klass(x->klass(), y->klass()) < 0) + return Universe::HiTrue; + else + return Universe::HiFalse; + } + + HiDouble* iy = (HiDouble*)y; + assert(iy && (iy->klass() == (Klass *)this)); + + if (ix->value() < iy->value()) + return Universe::HiTrue; + else + return Universe::HiFalse; +} + +HiObject* DoubleKlass::equal(HiObject* x, HiObject* y) { + if (x->klass() != y->klass()) + return Universe::HiFalse; + + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + if (ix->value() == iy->value()) + return Universe::HiTrue; + else + return Universe::HiFalse; +} + +HiObject* DoubleKlass::not_equal(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + if (ix->value() != iy->value()) + return Universe::HiTrue; + else + return Universe::HiFalse; +} + +HiObject* DoubleKlass::ge(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + if (ix->value() >= iy->value()) + return Universe::HiTrue; + else + return Universe::HiFalse; +} + +HiObject* DoubleKlass::le(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + if (ix->value() <= iy->value()) + return Universe::HiTrue; + else + return Universe::HiFalse; +} + +HiObject* DoubleKlass::add(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + return new HiDouble(ix->value() + iy->value()); +} + +HiObject* DoubleKlass::sub(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + return new HiDouble(ix->value() - iy->value()); +} + +HiObject* DoubleKlass::mul(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + HiDouble* iy = (HiDouble*) y; + + assert(ix && (ix->klass() == (Klass *)this)); + assert(iy && (iy->klass() == (Klass *)this)); + + return new HiDouble(ix->value() * iy->value()); +} + +HiObject* DoubleKlass::div(HiObject* x, HiObject* y) { + HiDouble* ix = (HiDouble*) x; + assert(ix && (ix->klass() == (Klass *)this)); + + if (y->klass() == (Klass*)this) { + return new HiDouble(ix->value() / + ((HiDouble*)y)->value()); + } + else if (y->klass() == IntegerKlass::get_instance()) { + return new HiDouble(ix->value() / + ((HiInteger*)y)->value()); + } + else { + //Error + } + + return NULL; +} + +HiObject* DoubleKlass::mod(HiObject* x, HiObject* y) { + return new HiDouble(0.0); +} + diff --git a/src/object/hiDouble.hpp b/src/object/hiDouble.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cb6f4231f28245104c26eb30cd834c440dd911f6 --- /dev/null +++ b/src/object/hiDouble.hpp @@ -0,0 +1,46 @@ +#ifndef HI_DOUBLE_HPP +#define HI_DOUBLE_HPP + +#include "object/hiObject.hpp" + +class DoubleKlass : public Klass { +private: + DoubleKlass(); + static DoubleKlass* instance; + +public: + static DoubleKlass* get_instance(); + void initialize(); + + virtual void print(HiObject* obj); + + virtual HiObject* greater (HiObject* x, HiObject* y); + virtual HiObject* less (HiObject* x, HiObject* y); + virtual HiObject* equal (HiObject* x, HiObject* y); + virtual HiObject* not_equal(HiObject* x, HiObject* y); + virtual HiObject* ge (HiObject* x, HiObject* y); + virtual HiObject* le (HiObject* x, HiObject* y); + + virtual HiObject* add(HiObject* x, HiObject* y); + virtual HiObject* sub(HiObject* x, HiObject* y); + virtual HiObject* mul(HiObject* x, HiObject* y); + virtual HiObject* div(HiObject* x, HiObject* y); + virtual HiObject* mod(HiObject* x, HiObject* y); + + virtual HiObject* allocate_instance(HiObject* callable, + ArrayList* args); + + virtual size_t size(); + virtual void oops_do(OopClosure* f, HiObject* obj); +}; + +class HiDouble : public HiObject { +private: + double _value; + +public: + HiDouble(double x); + double value() { return _value; } +}; + +#endif diff --git a/src/object/hiString.cpp b/src/object/hiString.cpp index 583c9265b3a0fff3b00fb837007c3346cc21dc16..c35da2eea5f190e120c52578d0d68c40807d5300 100644 --- a/src/object/hiString.cpp +++ b/src/object/hiString.cpp @@ -24,6 +24,7 @@ void StringKlass::initialize() { HiDict* klass_dict = new HiDict(); klass_dict->put(new HiString("upper"), new FunctionObject(string_upper)); + klass_dict->put(new HiString("join"), new FunctionObject(string_join)); set_klass_dict(klass_dict); set_name(new HiString("str")); @@ -92,7 +93,7 @@ HiString::HiString(const char * x, const int length) { HiString::HiString(const int length) { _length = length; - _value = (char*)Universe::heap->allocate(_length); + _value = (char*)Universe::heap->allocate(_length + 1); set_klass(StringKlass::get_instance()); } @@ -146,18 +147,14 @@ HiObject* StringKlass::add(HiObject* x, HiObject* y) { HiString* sx = (HiString*)x; HiString* sy = (HiString*)y; - HiString* sz = new HiString(sx->length() + sy->length() + 1); + HiString* sz = new HiString(sx->length() + sy->length()); - int i, j; - for (i = 0; i < sx->length(); i++) { - sz->set(i, sx->value()[i]); - } + memcpy(sz->_value, sx->_value, sx->length()); + memcpy(sz->_value + sx->length(), + sy->_value, + sy->length()); - for (j = 0; j < sy->length(); j++) { - sz->set(sx->length() + j, sy->value()[j]); - } - - sz->set(i + j, '\0'); + sz->set(sx->length() + sy->length(), '\0'); return sz; } @@ -173,3 +170,43 @@ size_t StringKlass::size() { return sizeof(HiString); } +HiString* HiString::join(HiObject* iterable) { + int total = 0; + + HiObject* iter = iterable->iter(); + HiObject* str = iter->next(); + + if (str == NULL) + return new HiString(""); + + total += ((HiString*)str)->length(); + while ((str = iter->next()) != NULL) { + total += _length; + total += ((HiString*)str)->length(); + } + + HiString* sz = new HiString(total); + total = 0; + + iter = iterable->iter(); + str = iter->next(); + HiString* sobj = (HiString*)str; + + memcpy(sz->_value, sobj->_value, sobj->length()); + total += ((HiString*)str)->length(); + while ((str = iter->next()) != NULL) { + HiString* sobj = (HiString*)str; + memcpy(sz->_value + total, _value, _length); + total += _length; + memcpy(sz->_value + total, sobj->_value, sobj->length()); + total += sobj->_length; + } + + return sz; +} + +HiObject* string_join(ObjList args) { + HiString* arg0 = (HiString*)(args->get(0)); + return arg0->join(args->get(1)); +} + diff --git a/src/object/hiString.hpp b/src/object/hiString.hpp index 2e372f347cd30381eb589abab697067c45c46690..927f5288790b6f4291e4edc9232ed8602b0aaf36 100644 --- a/src/object/hiString.hpp +++ b/src/object/hiString.hpp @@ -28,6 +28,7 @@ public: }; class HiString : public HiObject { +friend class StringKlass; private: char* _value; int _length; @@ -41,6 +42,11 @@ public: char** value_address() { return &_value; } int length() { return _length; } void set(int i, char x) { _value[i] = x; } + + HiString* join(HiObject* iterable); }; +HiObject* string_upper(ObjList args); +HiObject* string_join(ObjList args); + #endif diff --git a/src/object/klass.cpp b/src/object/klass.cpp index 6088e140429adc3fbdcc068ee1b1874747970689..4bf1ad95be89abd15379fc0002aa3881a4e0f818 100644 --- a/src/object/klass.cpp +++ b/src/object/klass.cpp @@ -30,6 +30,15 @@ int Klass::compare_klass(Klass* x, Klass* y) { } void Klass::print(HiObject* x) { + HiObject* meth_repr = get_klass_attr(x, ST(repr)); + if (meth_repr != Universe::HiNone) { + Interpreter::get_instance()-> + call_virtual(meth_repr, NULL)-> + print(); + + return; + } + printf("klass()->name()->print(); printf(", at %p>", x); diff --git a/src/runtime/frameObject.cpp b/src/runtime/frameObject.cpp index 4b6548aa877a5fe623527801c67375290d8dd8ad..c778e1c1a8e03726fa00c44aa9a5214f8dd71265 100644 --- a/src/runtime/frameObject.cpp +++ b/src/runtime/frameObject.cpp @@ -172,3 +172,15 @@ HiObject* FrameObject::get_cell_from_parameter(int i) { return _fast_locals->get(i); } +HiString* FrameObject::file_name() { + return _codes->_file_name; +} + +HiString* FrameObject::func_name() { + return _codes->_co_name; +} + +int FrameObject::lineno() { + return _pc; +} + diff --git a/src/runtime/frameObject.hpp b/src/runtime/frameObject.hpp index b913927718446d6f420d4ea5506cee06161c2e98..552b5026ece7afc104e0b73d296bc017e3272947 100644 --- a/src/runtime/frameObject.hpp +++ b/src/runtime/frameObject.hpp @@ -76,6 +76,10 @@ public: HiList* closure() { return _closure; } HiObject* get_cell_from_parameter(int i ); + HiString* file_name(); + HiString* func_name(); + int lineno(); + bool has_more_codes(); unsigned char get_op_code(); int get_op_arg(); diff --git a/src/runtime/functionObject.cpp b/src/runtime/functionObject.cpp index 57636ac363b5b5d00766542fc9f3d5c9ed9e873f..b7ac3b96914479332ee88570b2f7460789bce6fa 100644 --- a/src/runtime/functionObject.cpp +++ b/src/runtime/functionObject.cpp @@ -179,6 +179,9 @@ HiObject* isinstance(ObjList args) { assert(y && y->klass() == TypeKlass::get_instance()); Klass* k = x->klass(); + if (k->type_object() == y) + return Universe::HiTrue; + for (int i = 0; i < k->mro()->size(); i++) { if (k->mro()->get(i) == y) { return Universe::HiTrue; diff --git a/src/runtime/functionObject.hpp b/src/runtime/functionObject.hpp index 2856b31ce0fa2c66bf9e9d4d17401738781afffd..1c6fafdeb948062894b1013f3921a13b0ecaf3cd 100644 --- a/src/runtime/functionObject.hpp +++ b/src/runtime/functionObject.hpp @@ -20,8 +20,6 @@ public: virtual void oops_do(OopClosure* f, HiObject* obj); }; -HiObject* string_upper(ObjList args); - typedef HiObject* (*NativeFuncPointer)(ObjList args); class FunctionObject : public HiObject { diff --git a/src/runtime/interpreter.cpp b/src/runtime/interpreter.cpp index 741d4277d5ea02c839abf1fed0a07edd15a41375..770a52999c9a1e520746ea08fcef5f9cab48e6c8 100644 --- a/src/runtime/interpreter.cpp +++ b/src/runtime/interpreter.cpp @@ -4,6 +4,7 @@ #include "runtime/functionObject.hpp" #include "runtime/stringTable.hpp" #include "runtime/module.hpp" +#include "runtime/traceback.hpp" #include "util/arrayList.hpp" #include "util/map.hpp" #include "object/hiString.hpp" @@ -19,6 +20,7 @@ #define TOP() _frame->stack()->top() #define STACK_LEVEL() _frame->stack()->size() #define PEEK(x) _frame->stack()->get((x)) +#define EMPTY() (_frame->stack()->size() == 0) #define HI_TRUE Universe::HiTrue #define HI_FALSE Universe::HiFalse @@ -38,11 +40,14 @@ Interpreter* Interpreter::get_instance() { Interpreter::Interpreter() { _frame = NULL; -} - -void Interpreter::initialize() { - _builtins = ModuleObject::import_module(new HiString("lib/builtin")); + _exception_class = NULL; + _pending_exception = NULL; + _trace_back = NULL; + _int_status = IS_OK; + // prepare for import builtin, this should be created first + _builtins = new ModuleObject(new HiDict()); + _builtins->put(new HiString("object"), ObjectKlass::get_instance()->type_object()); _builtins->put(new HiString("True"), Universe::HiTrue); _builtins->put(new HiString("False"), Universe::HiFalse); _builtins->put(new HiString("None"), Universe::HiNone); @@ -58,6 +63,11 @@ void Interpreter::initialize() { _builtins->put(new HiString("str"), StringKlass::get_instance()->type_object()); _builtins->put(new HiString("list"), ListKlass::get_instance()->type_object()); _builtins->put(new HiString("dict"), DictKlass::get_instance()->type_object()); +} + +void Interpreter::initialize() { + _builtins->extend(ModuleObject::import_module(new HiString("builtin"))); + Universe::stop_iteration = _builtins->get(new HiString("StopIteration")); _modules = new HiDict(); _modules->put(new HiString("__builtins__"), _builtins); @@ -145,6 +155,19 @@ void Interpreter::run(CodeObject* codes) { _frame = new FrameObject(codes); _frame->locals()->put(ST(name), new HiString("__main__")); eval_frame(); + + if (_int_status == IS_EXCEPTION) { + _int_status = IS_OK; + + _trace_back->print(); + _pending_exception->print(); + printf("\n"); + + _trace_back = NULL; + _pending_exception = NULL; + _exception_class = NULL; + } + destroy_frame(); } @@ -325,6 +348,13 @@ void Interpreter::eval_frame() { printf("\n"); break; + case ByteCode::INPLACE_DIVIDE: + case ByteCode::BINARY_DIVIDE: + v = POP(); + w = POP(); + PUSH(w->div(v)); + break; + case ByteCode::INPLACE_ADD: case ByteCode::BINARY_ADD: v = POP(); @@ -410,10 +440,7 @@ void Interpreter::eval_frame() { case ByteCode::RETURN_VALUE: _ret_value = POP(); - if (_frame->is_first_frame() || - _frame->is_entry_frame()) - return; - leave_frame(); + _int_status = IS_RETURN; break; case ByteCode::COMPARE_OP: @@ -463,6 +490,13 @@ void Interpreter::eval_frame() { PUSH(HI_FALSE); break; + case ByteCode::EXC_MATCH: + if (v == w) + PUSH(Universe::HiTrue); + else + PUSH(Universe::HiFalse); + break; + default: printf("Error: Unrecognized compare op %d\n", op_arg); @@ -489,6 +523,8 @@ void Interpreter::eval_frame() { _frame->set_pc(op_arg); break; + case ByteCode::SETUP_FINALLY: + case ByteCode::SETUP_EXCEPT: case ByteCode::SETUP_LOOP: _frame->loop_stack()->add(new Block( op_code, _frame->get_pc() + op_arg, @@ -503,11 +539,30 @@ void Interpreter::eval_frame() { break; case ByteCode::BREAK_LOOP: - b = _frame->loop_stack()->pop(); - while (STACK_LEVEL() > b->_level) { - POP(); + _int_status = IS_BREAK; + break; + + case ByteCode::CONTINUE_LOOP: + _int_status = IS_CONTINUE; + _ret_value = (HiObject*)((long)op_arg); + break; + + case ByteCode::END_FINALLY: + // TODO: restore exceptions + v = POP(); + if (((long)v) & 0x1) { + _int_status = (Status)(((long)v) >> 1); + if (_int_status == IS_RETURN) + _ret_value = POP(); + else if (_int_status == IS_CONTINUE) + _frame->_pc = (int)((long)(POP())); + } + else if (v != Universe::HiNone) { + _exception_class = v; + _pending_exception = POP(); + _trace_back = POP(); + _int_status = IS_EXCEPTION; } - _frame->set_pc(b->_target); break; case ByteCode::BUILD_TUPLE: // drop down, we need this @@ -542,8 +597,11 @@ void Interpreter::eval_frame() { w = v->next(); if (w == NULL) { + // we may encounter a StopIteration, ignore it. + //assert(_int_status == IS_EXCEPTION && _pending_exception != NULL); _frame->_pc += op_arg; - POP(); + _int_status = IS_OK; + _pending_exception = NULL; } else { PUSH(w); @@ -613,6 +671,7 @@ void Interpreter::eval_frame() { break; case ByteCode::RAISE_VARARGS: + w = v = u = NULL; switch (op_arg) { case 3: u = POP(); @@ -622,14 +681,71 @@ void Interpreter::eval_frame() { w = POP(); break; } - _pending_exception = w; - _int_status = IS_EXCEPTION; + do_raise(w, v, u); break; default: printf("Error: Unrecognized byte code %d\n", op_code); } + + 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) { + _frame->_pc = (int)((long)_ret_value); + _int_status = IS_OK; + break; + } + + b = _frame->_loop_stack->pop(); + while (STACK_LEVEL() > b->_level) { + POP(); + } + + if (_int_status == IS_BREAK && b->_type == ByteCode::SETUP_LOOP) { + _frame->_pc = b->_target;; + _int_status = IS_OK; + } + else if (b->_type == ByteCode::SETUP_FINALLY || + (_int_status == IS_EXCEPTION + && b->_type == ByteCode::SETUP_EXCEPT)) { + if (_int_status == IS_EXCEPTION) { + // traceback, value, exception class + PUSH(_trace_back); + PUSH(_pending_exception); + PUSH(_exception_class); + + _trace_back = NULL; + _pending_exception = NULL; + _exception_class = NULL; + } + else { + if (_int_status == IS_RETURN || + _int_status == IS_CONTINUE) + PUSH(_ret_value); + + PUSH((HiObject*)(((long)_int_status << 1) | 0x1)); + } + _frame->_pc = b->_target;; + _int_status = IS_OK; + } + } + + // has pending exception and no handler found, unwind stack. + if (_int_status != IS_OK && _frame->_loop_stack->size() == 0) { + if (_int_status == IS_EXCEPTION) { + _ret_value = NULL; + ((Traceback*)_trace_back)->record_frame(_frame); + } + + if (_int_status == IS_RETURN) + _int_status = IS_OK; + + if (_frame->is_first_frame() || + _frame->is_entry_frame()) + return; + leave_frame(); + } } } @@ -637,10 +753,39 @@ void Interpreter::oops_do(OopClosure* f) { f->do_oop((HiObject**)&_builtins); f->do_oop((HiObject**)&_modules); f->do_oop((HiObject**)&_ret_value); + f->do_oop((HiObject**)&_exception_class); f->do_oop((HiObject**)&_pending_exception); - f->do_oop((HiObject**)&_reraise_exception); + f->do_oop((HiObject**)&_trace_back); if (_frame) _frame->oops_do(f); } +Interpreter::Status Interpreter::do_raise(HiObject* exc, HiObject* val, HiObject* tb) { + assert(exc != NULL); + + _int_status = IS_EXCEPTION; + + if (tb == NULL) { + tb = new Traceback(); + } + + if (val != NULL) { + _exception_class = exc; + _pending_exception = val; + _trace_back = tb; + return IS_EXCEPTION; + } + + if (exc->klass() == TypeKlass::get_instance()) { + _pending_exception = call_virtual(_pending_exception, NULL); + _exception_class = exc; + } + else { + _pending_exception = exc; + _exception_class = _pending_exception->klass()->type_object(); + } + _trace_back = tb; + return IS_EXCEPTION; +} + diff --git a/src/runtime/interpreter.hpp b/src/runtime/interpreter.hpp index c531796ef1f13644e5dd9072faceed9794032490..63e9041b7a6a7fe32e281114f98b22fc74c6711a 100644 --- a/src/runtime/interpreter.hpp +++ b/src/runtime/interpreter.hpp @@ -13,9 +13,9 @@ class Interpreter { enum Status { IS_OK, IS_BREAK, + IS_CONTINUE, IS_EXCEPTION, - IS_RERAISE, - IS_YIELD, + IS_RETURN, }; private: @@ -24,8 +24,9 @@ private: FrameObject* _frame; HiObject* _ret_value; - HiObject* _reraise_exception; + HiObject* _exception_class; HiObject* _pending_exception; + HiObject* _trace_back; Status _int_status; static Interpreter* _instance; @@ -44,6 +45,7 @@ public: void eval_frame (); void leave_frame (); HiObject* call_virtual (HiObject* func, ObjList args); + Status do_raise (HiObject* exc, HiObject* val, HiObject* tb); void oops_do (OopClosure* f); }; diff --git a/src/runtime/module.cpp b/src/runtime/module.cpp index 00d0e160ae594e1b9df3352f206101c36d0ecafd..583001bfd2b616d792de66ebaa4c2664276670cc 100644 --- a/src/runtime/module.cpp +++ b/src/runtime/module.cpp @@ -1,9 +1,19 @@ #include "object/hiDict.hpp" +#include "object/hiList.hpp" #include "runtime/module.hpp" +#include "runtime/universe.hpp" #include "runtime/interpreter.hpp" +#include "runtime/stringTable.hpp" #include "util/bufferedInputStream.hpp" #include "code/binaryFileParser.hpp" #include "memory/oopClosure.hpp" +#include "inc/railgun.hpp" + +#include +#include + +#define ST(x) StringTable::get_instance()->STR(x) +#define STR(x) x##_str ModuleKlass* ModuleKlass::_instance = NULL; @@ -32,7 +42,28 @@ ModuleObject::ModuleObject(HiDict* dict) { ModuleObject* ModuleObject::import_module(HiObject* x) { HiString* mod_name = (HiString*)x; - HiString* file_name = (HiString*)(mod_name->add(new HiString(".pyc"))); + + HiList* so_list = new HiList(); + so_list->append(ST(libdir_pre)); + so_list->append(mod_name); + so_list->append(ST(so_suf)); + HiString* file_name = ST(empty)->join(so_list); + + if (access(file_name->value(), R_OK) == 0) { + return import_so(mod_name); + } + + file_name = (HiString*)(mod_name->add(ST(pyc_suf))); + if (access(file_name->value(), R_OK) == -1) { + HiList* pyc_list = new HiList(); + pyc_list->append(ST(libdir_pre)); + pyc_list->append(mod_name); + pyc_list->append(ST(pyc_suf)); + file_name = ST(empty)->join(pyc_list); + } + + assert(access(file_name->value(), R_OK) == 0); + BufferedInputStream stream(file_name->value()); BinaryFileParser parser(&stream); CodeObject* mod_code = parser.parse(); @@ -48,6 +79,10 @@ HiObject* ModuleObject::get(HiObject* x) { return obj_dict()->get(x); } +void ModuleObject::extend(ModuleObject* mo) { + obj_dict()->update(mo->obj_dict()); +} + size_t ModuleKlass::size() { return sizeof(ModuleObject); } @@ -56,3 +91,36 @@ void ModuleKlass::oops_do(OopClosure* f, HiObject* obj) { void* temp = &(((ModuleObject*)obj)->_mod_name); f->do_oop((HiObject**)temp); } + +ModuleObject* ModuleObject::import_so(HiString* mod_name) { + char* error_msg = NULL; + + HiString* prefix = new HiString("./lib/"); + HiString* so_suffix = new HiString(".so"); + + HiString* file_name = (HiString*)(prefix->add(mod_name)->add(so_suffix)); + void* handle = dlopen(file_name->value(), RTLD_NOW); + if (handle == NULL) { + printf("error to open file: %s\n", dlerror()); + return NULL; + } + + HiString* method_prefix = new HiString("init_"); + HiString* init_meth = (HiString*)(method_prefix->add(mod_name)); + INIT_FUNC init_func = (INIT_FUNC)dlsym(handle, init_meth->value()); + if ((error_msg = dlerror()) != NULL) { + printf("Symbol init_methods not found: %s\n", error_msg); + dlclose(handle); + return NULL; + } + + RGMethod* ml = init_func(); + ModuleObject* mod = new ModuleObject(new HiDict()); + for (; ml->meth_name != NULL; ml++) { + mod->put(new HiString(ml->meth_name), + new FunctionObject(ml->meth)); + } + + return mod; +} + diff --git a/src/runtime/module.hpp b/src/runtime/module.hpp index bccaf8a76ea1bb21799816499f0360edcfae3839..7794b1ed22692e3c3c11a097de4c85c3ac3d4a5b 100644 --- a/src/runtime/module.hpp +++ b/src/runtime/module.hpp @@ -27,9 +27,11 @@ private: public: ModuleObject(HiDict* x); static ModuleObject* import_module(HiObject* mod_name); + static ModuleObject* import_so (HiString* mod_name); - void put(HiObject* x, HiObject* y); - HiObject* get(HiObject* x); + void put (HiObject* x, HiObject* y); + HiObject* get (HiObject* x); + void extend (ModuleObject* mo); }; #endif diff --git a/src/runtime/stringTable.cpp b/src/runtime/stringTable.cpp index 808a15e204ac194fa5632a28c8031f6ddd31ab84..6961617966d31890d5d8254accea80121bed9ced 100644 --- a/src/runtime/stringTable.cpp +++ b/src/runtime/stringTable.cpp @@ -20,10 +20,17 @@ StringTable::StringTable() { call_str = new HiString("__call__"); name_str = new HiString("__name__"); iter_str = new HiString("__iter__"); + repr_str = new HiString("__repr__"); getitem_str = new HiString("__getitem__"); setitem_str = new HiString("__setitem__"); getattr_str = new HiString("__getattr__"); setattr_str = new HiString("__setattr__"); + + so_pre_str = new HiString("lib"); + libdir_pre_str = new HiString("./lib/"); + empty_str = new HiString(""); + so_suf_str = new HiString(".so"); + pyc_suf_str = new HiString(".pyc"); } void StringTable::oops_do(OopClosure* f) { @@ -35,9 +42,16 @@ void StringTable::oops_do(OopClosure* f) { f->do_oop((HiObject**)&call_str); f->do_oop((HiObject**)&name_str); f->do_oop((HiObject**)&iter_str); + f->do_oop((HiObject**)&repr_str); f->do_oop((HiObject**)&getitem_str); f->do_oop((HiObject**)&setitem_str); f->do_oop((HiObject**)&setattr_str); f->do_oop((HiObject**)&getattr_str); + + f->do_oop((HiObject**)&empty_str); + f->do_oop((HiObject**)&so_suf_str); + f->do_oop((HiObject**)&pyc_suf_str); + f->do_oop((HiObject**)&libdir_pre_str); + f->do_oop((HiObject**)&so_pre_str); } diff --git a/src/runtime/stringTable.hpp b/src/runtime/stringTable.hpp index 9e79796692b44aa2f4a8c5d14ffd6e54ab1d09a7..1921ca31584085c6a97b8f1da113b0401577825c 100644 --- a/src/runtime/stringTable.hpp +++ b/src/runtime/stringTable.hpp @@ -24,6 +24,13 @@ public: HiString* setattr_str; HiString* name_str; HiString* iter_str; + HiString* repr_str; + + HiString* libdir_pre_str; + HiString* empty_str; + HiString* so_pre_str; + HiString* so_suf_str; + HiString* pyc_suf_str; void oops_do(OopClosure* f); }; diff --git a/src/runtime/traceback.cpp b/src/runtime/traceback.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72d9a0a711a161945becdf2b18c4dffd7d0ff05b --- /dev/null +++ b/src/runtime/traceback.cpp @@ -0,0 +1,83 @@ +#include "object/hiString.hpp" +#include "object/hiList.hpp" +#include "runtime/traceback.hpp" +#include "runtime/frameObject.hpp" +#include "memory/oopClosure.hpp" + +StackElementKlass* StackElementKlass::_instance = NULL; +TracebackKlass* TracebackKlass::_instance = NULL; + +StackElementKlass* StackElementKlass::get_instance() { + if (_instance == NULL) { + _instance = new StackElementKlass(); + } + + return _instance; +} + +void StackElementKlass::print(HiObject* x) { + StackElement* xse = (StackElement*)x; + printf(" File \""); + xse->_file_name->print(); + printf("\", line %d,", xse->_line_no); + printf(" in "); + xse->_func_name->print(); + printf("\n"); +} + +size_t StackElementKlass::size() { + return sizeof(StackElement); +} + +StackElement::StackElement(HiString* file_name, + HiString* func_name, + int line_no) : + _file_name(file_name), + _func_name(func_name), + _line_no(line_no) { + set_klass(StackElementKlass::get_instance()); +} + +TracebackKlass* TracebackKlass::get_instance() { + if (_instance == NULL) { + _instance = new TracebackKlass(); + } + + return _instance; +} + +void TracebackKlass::print(HiObject* x) { + Traceback* tbx = (Traceback*)x; + + printf("Traceback (most recent call last):\n"); + for (int i = tbx->_stack_elements->size() - 1; i >= 0; i--) { + tbx->_stack_elements->get(i)->print(); + } +} + +void TracebackKlass::oops_do(OopClosure* f, HiObject* obj) { + f->do_oop((HiObject**)&(((Traceback*)obj)->_stack_elements)); +} + +void StackElementKlass::oops_do(OopClosure* f, HiObject* obj) { + f->do_oop((HiObject**)&(((StackElement*)obj)->_file_name)); + f->do_oop((HiObject**)&(((StackElement*)obj)->_func_name)); +} + +size_t TracebackKlass::size() { + return sizeof(Traceback); +} + +Traceback::Traceback() { + _stack_elements = new HiList(); + set_klass(TracebackKlass::get_instance()); +} + +void Traceback::record_frame(FrameObject* frame) { + _stack_elements->append( + new StackElement( + frame->file_name(), + frame->func_name(), + frame->lineno())); +} + diff --git a/src/runtime/traceback.hpp b/src/runtime/traceback.hpp new file mode 100644 index 0000000000000000000000000000000000000000..062eaaedc76aac37b510e37879c7b5c984797c3b --- /dev/null +++ b/src/runtime/traceback.hpp @@ -0,0 +1,58 @@ +#ifndef TRACEBACK_OBJECT_HPP +#define TRACEBACK_OBJECT_HPP + +#include "object/hiObject.hpp" + +class HiList; +class HiString; +class FrameObject; + +class StackElementKlass : public Klass { +private: + StackElementKlass() {} + static StackElementKlass* _instance; + +public: + static StackElementKlass* get_instance(); + + virtual void print(HiObject* x); + virtual size_t size(); + virtual void oops_do(OopClosure* f, HiObject* obj); +}; + +class StackElement : public HiObject { +friend StackElementKlass; +private: + HiString* _file_name; + HiString* _func_name; + int _line_no; + +public: + StackElement(HiString* fname, HiString* mname, int lineno); +}; + +class TracebackKlass : public Klass { +private: + TracebackKlass() {} + static TracebackKlass* _instance; + +public: + static TracebackKlass* get_instance(); + + virtual void print(HiObject* x); + virtual size_t size(); + virtual void oops_do(OopClosure* f, HiObject* obj); +}; + +class Traceback : public HiObject { +friend class TracebackKlass; +private: + HiList* _stack_elements; + +public: + Traceback(); + + void record_frame(FrameObject* frame); +}; + +#endif diff --git a/src/runtime/universe.cpp b/src/runtime/universe.cpp index 421b81e702cd90abc79bfc1ff60f88df9286e890..4ee7b1f027f9e8df031a5b6b27cbb14a6d766567 100644 --- a/src/runtime/universe.cpp +++ b/src/runtime/universe.cpp @@ -3,6 +3,7 @@ #include "runtime/module.hpp" #include "runtime/interpreter.hpp" #include "object/hiInteger.hpp" +#include "object/hiDouble.hpp" #include "object/hiObject.hpp" #include "object/hiString.hpp" #include "object/hiList.hpp" @@ -12,11 +13,12 @@ HiObject* Universe::HiTrue = NULL; HiObject* Universe::HiFalse = NULL; +HiObject* Universe::HiNone = NULL; -HiObject* Universe::HiNone = NULL; -Heap* Universe::heap = NULL; -CodeObject* Universe::main_code = NULL; +Heap* Universe::heap = NULL; +CodeObject* Universe::main_code = NULL; +HiObject* Universe::stop_iteration = NULL; ArrayList* Universe::klasses = NULL; void Universe::genesis() { @@ -41,6 +43,7 @@ void Universe::genesis() { //object_klass->add_super(NULL); IntegerKlass::get_instance()->initialize(); + DoubleKlass::get_instance()->initialize(); StringKlass::get_instance()->initialize(); DictKlass::get_instance()->initialize(); ListKlass::get_instance()->initialize(); @@ -53,6 +56,7 @@ void Universe::genesis() { object_klass->set_name(new HiString("object")); IntegerKlass::get_instance()->order_supers(); + DoubleKlass::get_instance()->order_supers(); StringKlass::get_instance()->order_supers(); DictKlass::get_instance()->order_supers(); ListKlass::get_instance()->order_supers(); @@ -74,6 +78,7 @@ void Universe::oops_do(OopClosure* closure) { closure->do_oop((HiObject**)&HiTrue); closure->do_oop((HiObject**)&HiFalse); closure->do_oop((HiObject**)&HiNone); + closure->do_oop((HiObject**)&stop_iteration); closure->do_oop((HiObject**)&main_code); closure->do_array_list(&klasses); diff --git a/src/runtime/universe.hpp b/src/runtime/universe.hpp index ec151836c7a66da330f0d3f3376286b6dd8ac4c1..4873cb7094af462c3c3a97908c44af7020b64f03 100644 --- a/src/runtime/universe.hpp +++ b/src/runtime/universe.hpp @@ -23,6 +23,8 @@ public: static CodeObject* main_code; static Heap* heap; + + static HiObject* stop_iteration; public: static void genesis(); static void destroy(); diff --git a/src/util/bufferedInputStream.hpp b/src/util/bufferedInputStream.hpp index 2079da09743dc9bdfcf263b73d8a9d7c94764f11..ad73d46f3d5c128e255e9e3dc328931bc845baf8 100644 --- a/src/util/bufferedInputStream.hpp +++ b/src/util/bufferedInputStream.hpp @@ -41,6 +41,15 @@ public: return b4 << 24 | b3 << 16 | b2 << 8 | b1; } + double read_double() { + char t[8]; + for (int i = 0; i < 8; i++) { + t[i] = read(); + } + + return *(double *)t; + } + void unread() { index--; } diff --git a/test/show_file.py b/test/show_file.py index 77072dcd3cf5a5164d7283087cb42c35d0f4e107..130bf9c81bd66081450186f0bf349fcc97a554b5 100644 --- a/test/show_file.py +++ b/test/show_file.py @@ -4,8 +4,9 @@ def show_file(fname): f = open(fname, "rb") magic = f.read(4) moddate = f.read(4) + #modtime = time.asctime(time.localtime(struct.unpack('L', moddate)[0])) print "magic %s" % (magic.encode('hex')) - print "moddate %s" % (moddate.encode('hex')) + #print "moddate %s (%s)" % (moddate.encode('hex'), modtime) code = marshal.load(f) show_code(code) diff --git a/test/test_exception.py b/test/test_exception.py index 6f20424c5b92bf3cd88fd2a9a075dca59cea5dfa..17100b39b77c075c6b45c5c316249ef83a6e9e46 100644 --- a/test/test_exception.py +++ b/test/test_exception.py @@ -1,22 +1,10 @@ -class Fib(object): - def __init__(self): - self.a = 1 - self.b = 1 - self.i = 0 +try: + raise StopIteration("hello") +except StopIteration, e: + print e - def next(self): - if self.i > 10: - raise StopIteration - else: - t = self.a - self.a = self.a + self.b - self.b = t - self.i += 1 - return self.a +except Exception as e: + print e - def __iter__(self): - return self - -f = Fib() -for i in f: - print i +finally: + print "end" diff --git a/test/test_fib_class.py b/test/test_fib_class.py new file mode 100644 index 0000000000000000000000000000000000000000..bed355ef5fcbf2d261b63827294cf18340218926 --- /dev/null +++ b/test/test_fib_class.py @@ -0,0 +1,22 @@ +class Fib(object): + def __init__(self): + self.a = 1 + self.b = 1 + self.i = 0 + + def next(self): + if self.i > 10: + raise StopIteration("end of iteration") + else: + t = self.a + self.a = self.a + self.b + self.b = t + self.i += 1 + return self.a + + def __iter__(self): + return self + +f = Fib() +for i in f: + print i diff --git a/test/test_float.py b/test/test_float.py new file mode 100644 index 0000000000000000000000000000000000000000..4d9d0e26841f3f6b153f25022874afae6fa55c65 --- /dev/null +++ b/test/test_float.py @@ -0,0 +1,4 @@ +print 1.0 +print 2.0 +print 3.0 +print 1.0 / 2 diff --git a/test/test_import.py b/test/test_import.py index c879de2a7524a29f5aaa85a03f2ba4bc27f650c1..bbc8cb48f4611ec84525a5b26c0d99a49f843009 100644 --- a/test/test_import.py +++ b/test/test_import.py @@ -9,7 +9,7 @@ from test_func import foo, fact print fact(5) -#l = [1, 2, 3, 4] -#print map(lambda x : x + 1, l) -#print filter(lambda x : x % 2 == 0, l) -#print sum(l, 100) +l = [1, 2, 3, 4] +print map(lambda x : x + 1, l) +print filter(lambda x : x % 2 == 0, l) +print sum(l, 100) diff --git a/test/test_math.py b/test/test_math.py new file mode 100644 index 0000000000000000000000000000000000000000..1f966eb751ad08474975bc6d6d7e52d9f816e0b1 --- /dev/null +++ b/test/test_math.py @@ -0,0 +1,6 @@ +import math + +print math.pi +print math.e +print math.sin(math.pi / 3.0) +print math.sqrt(200) diff --git a/test/test_string.py b/test/test_string.py index c451fbd8212639d2b0f8dc9662f2e7218b4c461d..715ebc808fb9e6198a81aada5982d5ca49750814 100644 --- a/test/test_string.py +++ b/test/test_string.py @@ -1,2 +1,11 @@ -s = "hello" -print s[0] +a = "hello" +b = "world" +l = [] +l.append(a) +print ", ".join(l); +l.append(b) +print ", ".join(l); +l.append(a) +print ", ".join(l); +l.append(b) +print ", ".join(l); diff --git a/test/test_tb.py b/test/test_tb.py new file mode 100644 index 0000000000000000000000000000000000000000..68f5ef74f4a2fb68912f486fe07da1cfecb81f3f --- /dev/null +++ b/test/test_tb.py @@ -0,0 +1,8 @@ +def foo(a): + b = a - 1 + bar(a, b) + +def bar(a, b): + raise Exception("something wrong!") + +foo(1) diff --git a/test/test_try.py b/test/test_try.py new file mode 100644 index 0000000000000000000000000000000000000000..f1206f0bb22852a790fa905337c565b9e440051d --- /dev/null +++ b/test/test_try.py @@ -0,0 +1,27 @@ +i = 0 +while i < 10: + i += 1 + try: + if (i == 5): + break + print i + + finally: + print "hello" + + +def foo(): + try: + return "haha" + finally: + print "world" + +print foo() + +for i in range(5): + try: + if (i < 3): + continue + print i + finally: + print "to be continued"