blueloveTH 1 год назад
Родитель
Сommit
f93aefdbe5

+ 18 - 9
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 <TargetConditionals.h>
     #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

+ 0 - 2
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

+ 1 - 1
include/pocketpy/objects/sourcedata.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <stdbool.h>
+#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;

+ 26 - 11
include/pocketpy/pocketpy.h

@@ -4,6 +4,9 @@
 #include <stdbool.h>
 #include <stdarg.h>
 
+#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.
 */

+ 0 - 18
include/pocketpy/tools/repl.hpp

@@ -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

+ 35 - 0
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;
+}

+ 0 - 9
src/common/utils.c

@@ -1,9 +0,0 @@
-const char* kPlatformStrings[] = {
-    "win32",       // 0
-    "emscripten",  // 1
-    "ios",         // 2
-    "darwin",      // 3
-    "android",     // 4
-    "linux",       // 5
-    "unknown"      // 6
-};

+ 33 - 42
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);

+ 0 - 8
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);

+ 2 - 2
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);

+ 5 - 1
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, "<e
 
 bool py_eval(const char* source) { return pk_VM__exec(pk_current_vm, source, "<eval>", 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; }

+ 0 - 43
src/tools/repl.cpp

@@ -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, "<stdin>", 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

+ 24 - 33
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();
-
-    py_finalize();
-    free(source);
-
-    return 0;
+    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");
+
+        while(true){
+            int size = py_replinput(buf);
+            assert(size < sizeof(buf));
+            if(size >= 0){
+                if(!py_exec2(buf, "<stdin>", 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;
 }