diff --git a/include/pocketpy/common/export.h b/include/pocketpy/common/export.h index 55b803e4..d2a254fb 100644 --- a/include/pocketpy/common/export.h +++ b/include/pocketpy/common/export.h @@ -1,39 +1,48 @@ #pragma once + // clang-format off #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) //define something for Windows (32-bit and 64-bit, this part is common) #define PK_EXPORT __declspec(dllexport) - #define PK_SYS_PLATFORM 0 + #define PY_SYS_PLATFORM 0 + #define PY_SYS_PLATFORM_STRING "win32" #elif __EMSCRIPTEN__ #define PK_EXPORT - #define PK_SYS_PLATFORM 1 + #define PY_SYS_PLATFORM 1 + #define PY_SYS_PLATFORM_STRING "emscripten" #elif __APPLE__ #include #if TARGET_IPHONE_SIMULATOR // iOS, tvOS, or watchOS Simulator - #define PK_SYS_PLATFORM 2 + #define PY_SYS_PLATFORM 2 + #define PY_SYS_PLATFORM_STRING "ios" #elif TARGET_OS_IPHONE // iOS, tvOS, or watchOS device - #define PK_SYS_PLATFORM 2 + #define PY_SYS_PLATFORM 2 + #define PY_SYS_PLATFORM_STRING "ios" #elif TARGET_OS_MAC - #define PK_SYS_PLATFORM 3 + #define PY_SYS_PLATFORM 3 + #define PY_SYS_PLATFORM_STRING "darwin" #else # error "Unknown Apple platform" #endif #define PK_EXPORT __attribute__((visibility("default"))) #elif __ANDROID__ #define PK_EXPORT __attribute__((visibility("default"))) - #define PK_SYS_PLATFORM 4 + #define PY_SYS_PLATFORM 4 + #define PY_SYS_PLATFORM_STRING "android" #elif __linux__ #define PK_EXPORT __attribute__((visibility("default"))) - #define PK_SYS_PLATFORM 5 + #define PY_SYS_PLATFORM 5 + #define PY_SYS_PLATFORM_STRING "linux" #else #define PK_EXPORT - #define PK_SYS_PLATFORM 6 + #define PY_SYS_PLATFORM 6 + #define PY_SYS_PLATFORM_STRING "unknown" #endif -#if PK_SYS_PLATFORM == 0 || PK_SYS_PLATFORM == 3 || PK_SYS_PLATFORM == 5 +#if PY_SYS_PLATFORM == 0 || PY_SYS_PLATFORM == 3 || PY_SYS_PLATFORM == 5 #define PK_IS_DESKTOP_PLATFORM 1 #else #define PK_IS_DESKTOP_PLATFORM 0 diff --git a/include/pocketpy/common/utils.h b/include/pocketpy/common/utils.h index 66ae8480..1b42ddf7 100644 --- a/include/pocketpy/common/utils.h +++ b/include/pocketpy/common/utils.h @@ -21,8 +21,6 @@ extern "C" { // global constants #define PK_HEX_TABLE "0123456789abcdef" -extern const char* kPlatformStrings[]; - #ifdef _MSC_VER #define c11__unreachedable() __assume(0) #else diff --git a/include/pocketpy/objects/sourcedata.h b/include/pocketpy/objects/sourcedata.h index 0d25364f..fbe646cd 100644 --- a/include/pocketpy/objects/sourcedata.h +++ b/include/pocketpy/objects/sourcedata.h @@ -1,6 +1,7 @@ #pragma once #include +#include "pocketpy/pocketpy.h" #include "pocketpy/common/str.h" #include "pocketpy/common/vector.h" @@ -8,7 +9,6 @@ extern "C" { #endif -enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE }; struct pk_SourceData { RefCounted rc; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 2be80df7..1a280992 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -4,6 +4,9 @@ #include #include +#include "pocketpy/common/config.h" +#include "pocketpy/common/export.h" + /************* Public Types *************/ typedef struct py_TValue py_TValue; typedef uint16_t py_Name; @@ -29,11 +32,19 @@ typedef py_TValue* py_TmpRef; /// @return true if the function is successful. typedef bool (*py_CFunction)(int argc, py_StackRef argv); -typedef enum BindType { +enum BindType { BindType_FUNCTION, BindType_STATICMETHOD, BindType_CLASSMETHOD, -} BindType; +}; + +enum CompileMode { + EXEC_MODE, + EVAL_MODE, + REPL_MODE, + JSON_MODE, + CELL_MODE +}; /************* Global VMs *************/ void py_initialize(); @@ -44,6 +55,7 @@ bool py_exec(const char* source); /// Eval a simple expression. /// The result will be set to `py_retval()`. bool py_eval(const char* source); +bool py_exec2(const char* source, const char* filename, enum CompileMode mode); /************* Values Creation *************/ void py_newint(py_Ref, py_i64); @@ -81,7 +93,7 @@ void py_newfunction(py_Ref out, py_CFunction, const char* sig); void py_newfunction2(py_Ref out, py_CFunction, const char* sig, - BindType bt, + enum BindType bt, const char* docstring, const py_Ref upvalue); // old style argc-based function @@ -115,10 +127,11 @@ bool py_isinstance(const py_Ref obj, py_Type type); bool py_issubclass(py_Type derived, py_Type base); /************* References *************/ -#define PY_CHECK_ARGC(n) \ +#define PY_CHECK_ARGC(n) \ if(argc != n) return TypeError("expected %d arguments, got %d", n, argc) -#define PY_CHECK_ARG_TYPE(i, type) if(!py_checktype(py_arg(i), type)) return false +#define PY_CHECK_ARG_TYPE(i, type) \ + if(!py_checktype(py_arg(i), type)) return false #define py_offset(p, i) ((py_Ref)((char*)p + ((i) << 4))) #define py_arg(i) py_offset(argv, i) @@ -131,12 +144,12 @@ py_TmpRef py_bind(py_Ref obj, const char* sig, py_CFunction f); py_TmpRef py_bind2(py_Ref obj, const char* sig, py_CFunction f, - BindType bt, + enum BindType bt, const char* docstring, const py_Ref upvalue); // old style argc-based bindings void py_bindmethod(py_Type type, const char* name, py_CFunction f); -void py_bindmethod2(py_Type type, const char* name, py_CFunction f, BindType bt); +void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum BindType bt); void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f); /// Get the reference to the i-th register. @@ -321,9 +334,10 @@ py_GlobalRef py_tpobject(py_Type type); const char* py_tpname(py_Type type); /// Check if the object is an instance of the given type. -/// Re bool py_checktype(const py_Ref self, py_Type type); +int py_replinput(char* buf); + /// Python favored string formatting. /// %d: int /// %i: py_i64 (int64_t) @@ -379,12 +393,13 @@ enum py_PredefinedTypes { } #endif - /* Some notes: ## Macros -1. Function macros are partial functions. They can be used as normal expressions. Use the same naming convention as functions. -2. Snippet macros are `do {...} while(0)` blocks. They cannot be used as expressions. Use `UPPER_CASE` naming convention. +1. Function macros are partial functions. They can be used as normal expressions. Use the same +naming convention as functions. +2. Snippet macros are `do {...} while(0)` blocks. They cannot be used as expressions. Use +`UPPER_CASE` naming convention. 3. Constant macros are used for global constants. Use `UPPER_CASE` or k-prefix naming convention. */ \ No newline at end of file diff --git a/include/pocketpy/tools/repl.hpp b/include/pocketpy/tools/repl.hpp deleted file mode 100644 index eb4f047a..00000000 --- a/include/pocketpy/tools/repl.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "pocketpy/interpreter/vm.hpp" - -namespace pkpy { - -class REPL { -protected: - int need_more_lines = 0; - std::string buffer; - VM* vm; - -public: - REPL(VM* vm); - bool input(std::string line); -}; - -} // namespace pkpy diff --git a/src/common/sstream.c b/src/common/sstream.c index 82d5eb7b..c5189ff8 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -220,3 +220,38 @@ void pk_sprintf(c11_sbuf* ss, const char* fmt, ...) { pk_vsprintf(ss, fmt, args); va_end(args); } + +int py_replinput(char* buf) { + int size = 0; + bool multiline = false; + printf(">>> "); + + while(true) { + char c = getchar(); + if(c == EOF) break; + + if(c == '\n') { + char last = '\0'; + if(size > 0) last = buf[size - 1]; + if(multiline) { + if(last == '\n'){ + break; // 2 consecutive newlines to end multiline input + }else{ + printf("... "); + } + } else { + if(last == ':' || last == '(' || last == '[' || last == '{') { + printf("... "); + multiline = true; + } else { + break; + } + } + } + + buf[size++] = c; + } + + buf[size] = '\0'; + return size; +} \ No newline at end of file diff --git a/src/common/utils.c b/src/common/utils.c deleted file mode 100644 index d3032366..00000000 --- a/src/common/utils.c +++ /dev/null @@ -1,9 +0,0 @@ -const char* kPlatformStrings[] = { - "win32", // 0 - "emscripten", // 1 - "ios", // 2 - "darwin", // 3 - "android", // 4 - "linux", // 5 - "unknown" // 6 -}; \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index ac665929..8f3a3f3c 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -1454,7 +1454,7 @@ static void Compiler__dtor(Compiler* self) { #define mode() self->src->mode #define ctx() (&c11_vector__back(Ctx, &self->contexts)) -#define match_newlines() match_newlines_repl(self, NULL) +#define match_newlines() match_newlines_impl(self) #define consume(expected) \ if(!match(expected)) \ @@ -1463,12 +1463,7 @@ static void Compiler__dtor(Compiler* self) { pk_TokenSymbols[curr()->type]); #define consume_end_stmt() \ if(!match_end_stmt(self)) return SyntaxError("expected statement end") -#define check_newlines_repl() \ - do { \ - bool __nml; \ - match_newlines_repl(self, &__nml); \ - if(__nml) return NeedMoreLines(); \ - } while(0) + #define check(B) \ if((err = B)) return err @@ -1480,8 +1475,6 @@ static NameScope name_scope(Compiler* self) { #define SyntaxError(...) NULL -static Error* NeedMoreLines() { return NULL; } - /* Matchers */ static bool is_expression(Compiler* self, bool allow_slice) { PrattCallback prefix = rules[curr()->type].prefix; @@ -1490,14 +1483,13 @@ static bool is_expression(Compiler* self, bool allow_slice) { #define match(expected) (curr()->type == expected ? (++self->i) : 0) -static bool match_newlines_repl(Compiler* self, bool* need_more_lines) { +static bool match_newlines_impl(Compiler* self) { bool consumed = false; if(curr()->type == TK_EOL) { while(curr()->type == TK_EOL) advance(); consumed = true; } - if(need_more_lines) { *need_more_lines = (mode() == REPL_MODE && curr()->type == TK_EOF); } return consumed; } @@ -1540,11 +1532,11 @@ static Error* EXPR_TUPLE_ALLOW_SLICE(Compiler* self, bool allow_slice) { // tuple expression // (a, ) int count = 1; do { - if(curr()->brackets_level) check_newlines_repl(); + if(curr()->brackets_level) match_newlines(); if(!is_expression(self, allow_slice)) break; check(parse_expression(self, PREC_LOWEST + 1, allow_slice)); count += 1; - if(curr()->brackets_level) check_newlines_repl(); + if(curr()->brackets_level) match_newlines(); } while(match(TK_COMMA)); // pop `count` expressions from the stack and merge them into a TupleExpr SequenceExpr* e = TupleExpr__new(prev()->line, count); @@ -1791,9 +1783,9 @@ static Error* exprUnaryOp(Compiler* self) { static Error* exprGroup(Compiler* self) { Error* err; int line = prev()->line; - check_newlines_repl(); + match_newlines(); check(EXPR_TUPLE(self)); // () is just for change precedence - check_newlines_repl(); + match_newlines(); consume(TK_RPAREN); if(Ctx__s_top(ctx())->vt->is_tuple) return NULL; GroupedExpr* g = GroupedExpr__new(line, Ctx__s_popx(ctx())); @@ -1833,7 +1825,7 @@ static Error* consume_comp(Compiler* self, Opcode op0, Opcode op1) { check(EXPR_VARS(self)); // [expr, vars] consume(TK_IN); check(parse_expression(self, PREC_TERNARY + 1, false)); // [expr, vars, iter] - check_newlines_repl(); + match_newlines(); if(match(TK_IF)) { check(parse_expression(self, PREC_TERNARY + 1, false)); // [expr, vars, iter, cond] has_cond = true; @@ -1844,7 +1836,7 @@ static Error* consume_comp(Compiler* self, Opcode op0, Opcode op1) { ce->vars = Ctx__s_popx(ctx()); ce->expr = Ctx__s_popx(ctx()); Ctx__s_push(ctx(), (Expr*)ce); - check_newlines_repl(); + match_newlines(); return NULL; } @@ -1853,17 +1845,17 @@ static Error* exprList(Compiler* self) { int line = prev()->line; int count = 0; do { - check_newlines_repl(); + match_newlines(); if(curr()->type == TK_RBRACKET) break; check(EXPR(self)); count += 1; - check_newlines_repl(); + match_newlines(); if(count == 1 && match(TK_FOR)) { check(consume_comp(self, OP_BUILD_LIST, OP_LIST_APPEND)); consume(TK_RBRACKET); return NULL; } - check_newlines_repl(); + match_newlines(); } while(match(TK_COMMA)); consume(TK_RBRACKET); SequenceExpr* e = ListExpr__new(line, count); @@ -1880,7 +1872,7 @@ static Error* exprMap(Compiler* self) { bool parsing_dict = false; // {...} may be dict or set int count = 0; do { - check_newlines_repl(); + match_newlines(); if(curr()->type == TK_RBRACE) break; check(EXPR(self)); // [key] if(curr()->type == TK_COLON) { parsing_dict = true; } @@ -1889,7 +1881,7 @@ static Error* exprMap(Compiler* self) { check(EXPR(self)); // [key, value] } count += 1; // key-value pair count - check_newlines_repl(); + match_newlines(); if(count == 1 && match(TK_FOR)) { if(parsing_dict) { check(consume_comp(self, OP_BUILD_DICT, OP_DICT_ADD)); @@ -1899,7 +1891,7 @@ static Error* exprMap(Compiler* self) { consume(TK_RBRACE); return NULL; } - check_newlines_repl(); + match_newlines(); } while(match(TK_COMMA)); consume(TK_RBRACE); @@ -1922,7 +1914,7 @@ static Error* exprCall(Compiler* self) { CallExpr* e = CallExpr__new(prev()->line, Ctx__s_popx(ctx())); Ctx__s_push(ctx(), (Expr*)e); // push onto the stack in advance do { - check_newlines_repl(); + match_newlines(); if(curr()->type == TK_RPAREN) break; if(curr()->type == TK_ID && next()->type == TK_ASSIGN) { consume(TK_ID); @@ -1948,7 +1940,7 @@ static Error* exprCall(Compiler* self) { c11_vector__push(Expr*, &e->args, Ctx__s_popx(ctx())); } } - check_newlines_repl(); + match_newlines(); } while(match(TK_COMMA)); consume(TK_RPAREN); return NULL; @@ -1998,9 +1990,9 @@ static Error* exprSlice1(Compiler* self) { static Error* exprSubscr(Compiler* self) { Error* err; int line = prev()->line; - check_newlines_repl(); + match_newlines(); check(EXPR_TUPLE_ALLOW_SLICE(self, true)); - check_newlines_repl(); + match_newlines(); consume(TK_RBRACKET); // [lhs, rhs] SubscrExpr* e = SubscrExpr__new(line); e->rhs = Ctx__s_popx(ctx()); // [lhs] @@ -2032,9 +2024,7 @@ static Error* compile_block_body(Compiler* self, PrattCallback callback) { return NULL; } - bool need_more_lines; - bool consumed = match_newlines_repl(self, &need_more_lines); - if(need_more_lines) return NeedMoreLines(); + bool consumed = match_newlines(); if(!consumed) return SyntaxError("expected a new line after ':'"); consume(TK_INDENT); @@ -2090,17 +2080,18 @@ static Error* compile_while_loop(Compiler* self) { static Error* compile_for_loop(Compiler* self) { Error* err; - check(EXPR_VARS(self)); // [vars] + check(EXPR_VARS(self)); // [vars] consume(TK_IN); - check(EXPR_TUPLE(self)); // [vars, iter] - Ctx__s_emit_top(ctx()); // [vars] + check(EXPR_TUPLE(self)); // [vars, iter] + Ctx__s_emit_top(ctx()); // [vars] Ctx__emit_(ctx(), OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE); CodeBlock* block = Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP); int for_codei = Ctx__emit_(ctx(), OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE); Expr* vars = Ctx__s_popx(ctx()); bool ok = vtemit_store(vars, ctx()); vtdelete(vars); - if(!ok) return SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind + if(!ok) + return SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind // TODO: ?? // ctx()->try_merge_for_iter_store(for_codei); @@ -2405,14 +2396,14 @@ Error* pk_compile(pk_SourceData_ src, CodeObject* out) { Error* err = pk_Lexer__process(src, &tokens); if(err) return err; - Token* data = (Token*)tokens.data; - printf("%s\n", src->filename->data); - for(int i = 0; i < tokens.count; i++) { - Token* t = data + i; - c11_string* tmp = c11_string__new2(t->start, t->length); - printf("[%d] %s: %s\n", t->line, pk_TokenSymbols[t->type], tmp->data); - c11_string__delete(tmp); - } + // Token* data = (Token*)tokens.data; + // printf("%s\n", src->filename->data); + // for(int i = 0; i < tokens.count; i++) { + // Token* t = data + i; + // c11_string* tmp = c11_string__new2(t->start, t->length); + // printf("[%d] %s: %s\n", t->line, pk_TokenSymbols[t->type], tmp->data); + // c11_string__delete(tmp); + // } Compiler compiler; Compiler__ctor(&compiler, src, tokens); diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index f289adef..f0233653 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -201,10 +201,6 @@ static Error* SyntaxError(const char* fmt, ...){ return NULL; } -static Error* NeedMoreLines(){ - return NULL; -} - static Error* eat_name(pk_Lexer* self){ self->curr_char--; while(true) { @@ -288,9 +284,6 @@ static Error* eat_string_until(pk_Lexer* self, char quote, bool raw, c11_string* break; } if(c == '\0') { - if(quote3 && self->src->mode == REPL_MODE){ - return NeedMoreLines(); - } return SyntaxError("EOL while scanning string literal"); } if(c == '\n') { @@ -431,7 +424,6 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){ // line continuation character char c = eatchar_include_newline(self); if(c != '\n') { - if(self->src->mode == REPL_MODE && c == '\0') return NeedMoreLines(); return SyntaxError("expected newline after line continuation character"); } eat_spaces(self); diff --git a/src/public/values.c b/src/public/values.c index a0cee84a..8d1e8689 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -49,7 +49,7 @@ void py_newfunction(py_Ref out, py_CFunction f, const char* sig) { void py_newfunction2(py_Ref out, py_CFunction f, const char* sig, - BindType bt, + enum BindType bt, const char* docstring, const py_Ref upvalue) {} @@ -63,7 +63,7 @@ void py_bindmethod(py_Type type, const char *name, py_CFunction f){ py_bindmethod2(type, name, f, BindType_FUNCTION); } -void py_bindmethod2(py_Type type, const char *name, py_CFunction f, BindType bt){ +void py_bindmethod2(py_Type type, const char *name, py_CFunction f, enum BindType bt){ py_TValue tmp; py_newnativefunc(&tmp, f); py_setdict(py_tpobject(type), py_name(name), &tmp); diff --git a/src/public/vm.c b/src/public/vm.c index 430439af..f6321900 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -168,7 +168,7 @@ static bool return false; } - disassemble(&co); + // disassemble(&co); Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co); pk_VM__push_frame(vm, frame); @@ -184,6 +184,10 @@ bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "", EVAL_MODE); } +bool py_exec2(const char* source, const char* filename, enum CompileMode mode){ + return pk_VM__exec(pk_current_vm, source, filename, mode); +} + bool py_call(py_Ref f, int argc, py_Ref argv) { return -1; } bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1; } diff --git a/src/tools/repl.cpp b/src/tools/repl.cpp deleted file mode 100644 index dff4beb2..00000000 --- a/src/tools/repl.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "pocketpy/tools/repl.hpp" -#include "pocketpy/common/export.h" - -namespace pkpy { -REPL::REPL(VM* vm) : vm(vm) { - vm->stdout_write("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); - vm->stdout_write(_S("[", sizeof(void*) * 8, " bit] on ", kPlatformStrings[PK_SYS_PLATFORM], "\n")); - vm->stdout_write("https://github.com/pocketpy/pocketpy" "\n"); - vm->stdout_write("Type \"exit()\" to exit." "\n"); -} - -bool REPL::input(std::string line) { - CompileMode mode = REPL_MODE; - if(need_more_lines) { - buffer += line; - buffer += '\n'; - int n = buffer.size(); - if(n >= need_more_lines) { - for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) { - // no enough lines - if(buffer[i] != '\n') return true; - } - need_more_lines = 0; - line = buffer; - buffer.clear(); - mode = CELL_MODE; - } else { - return true; - } - } - - try { - vm->exec(line, "", mode); - } catch(NeedMoreLines ne) { - buffer += line; - buffer += '\n'; - need_more_lines = ne.is_compiling_class ? 3 : 2; - if(need_more_lines) return true; - } - return false; -} - -} // namespace pkpy diff --git a/src2/main.c b/src2/main.c index 5286a02d..7d7b3c68 100644 --- a/src2/main.c +++ b/src2/main.c @@ -19,49 +19,40 @@ char* read_file(const char* path) { return buffer; } +static char buf[2048]; + int main(int argc, char** argv) { #if _WIN32 SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); #endif -#if 0 - py_initialize(); - const char* source = "1 < 2"; - - if(py_eval(source)) { - // handle the result - bool _L0 = py_tobool(py_retval()); - printf("%d\n", _L0); + if(argc > 2){ + printf("Usage: pocketpy [filename]\n"); + return 0; } - py_Ref r0 = py_reg(0); - py_Ref r1 = py_reg(1); - - py_newint(r0, 1); - py_newfloat(r1, 2.5); - - bool ok = py_binaryadd(r0, r1); - assert(ok); - double res = py_tofloat(py_retval()); - printf("%f\n", res); - - py_finalize(); - return 0; -#endif - - if(argc != 2) goto __HELP; - char* source = read_file(argv[1]); py_initialize(); - if(!py_exec(source)) py_printexc(); + if(argc == 1){ + printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); + printf("[%d bit] on %s" "\n", (int)(sizeof(void*) * 8), PY_SYS_PLATFORM_STRING); + printf("https://github.com/pocketpy/pocketpy" "\n"); + printf("Type \"exit()\" to exit." "\n"); - py_finalize(); - free(source); - - return 0; + while(true){ + int size = py_replinput(buf); + assert(size < sizeof(buf)); + if(size >= 0){ + if(!py_exec2(buf, "", REPL_MODE)) py_printexc(); + } + } + }else{ + char* source = read_file(argv[1]); + if(!py_exec(source)) py_printexc(); + free(source); + } -__HELP: - printf("Usage: pocketpy [filename]\n"); + py_finalize(); return 0; }