implement repl

This commit is contained in:
blueloveTH 2024-07-06 00:36:51 +08:00
parent d74ca31f68
commit f93aefdbe5
13 changed files with 143 additions and 178 deletions

View File

@ -1,39 +1,48 @@
#pragma once #pragma once
// clang-format off // clang-format off
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
//define something for Windows (32-bit and 64-bit, this part is common) //define something for Windows (32-bit and 64-bit, this part is common)
#define PK_EXPORT __declspec(dllexport) #define PK_EXPORT __declspec(dllexport)
#define PK_SYS_PLATFORM 0 #define PY_SYS_PLATFORM 0
#define PY_SYS_PLATFORM_STRING "win32"
#elif __EMSCRIPTEN__ #elif __EMSCRIPTEN__
#define PK_EXPORT #define PK_EXPORT
#define PK_SYS_PLATFORM 1 #define PY_SYS_PLATFORM 1
#define PY_SYS_PLATFORM_STRING "emscripten"
#elif __APPLE__ #elif __APPLE__
#include <TargetConditionals.h> #include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR #if TARGET_IPHONE_SIMULATOR
// iOS, tvOS, or watchOS 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 #elif TARGET_OS_IPHONE
// iOS, tvOS, or watchOS device // 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 #elif TARGET_OS_MAC
#define PK_SYS_PLATFORM 3 #define PY_SYS_PLATFORM 3
#define PY_SYS_PLATFORM_STRING "darwin"
#else #else
# error "Unknown Apple platform" # error "Unknown Apple platform"
#endif #endif
#define PK_EXPORT __attribute__((visibility("default"))) #define PK_EXPORT __attribute__((visibility("default")))
#elif __ANDROID__ #elif __ANDROID__
#define PK_EXPORT __attribute__((visibility("default"))) #define PK_EXPORT __attribute__((visibility("default")))
#define PK_SYS_PLATFORM 4 #define PY_SYS_PLATFORM 4
#define PY_SYS_PLATFORM_STRING "android"
#elif __linux__ #elif __linux__
#define PK_EXPORT __attribute__((visibility("default"))) #define PK_EXPORT __attribute__((visibility("default")))
#define PK_SYS_PLATFORM 5 #define PY_SYS_PLATFORM 5
#define PY_SYS_PLATFORM_STRING "linux"
#else #else
#define PK_EXPORT #define PK_EXPORT
#define PK_SYS_PLATFORM 6 #define PY_SYS_PLATFORM 6
#define PY_SYS_PLATFORM_STRING "unknown"
#endif #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 #define PK_IS_DESKTOP_PLATFORM 1
#else #else
#define PK_IS_DESKTOP_PLATFORM 0 #define PK_IS_DESKTOP_PLATFORM 0

View File

@ -21,8 +21,6 @@ extern "C" {
// global constants // global constants
#define PK_HEX_TABLE "0123456789abcdef" #define PK_HEX_TABLE "0123456789abcdef"
extern const char* kPlatformStrings[];
#ifdef _MSC_VER #ifdef _MSC_VER
#define c11__unreachedable() __assume(0) #define c11__unreachedable() __assume(0)
#else #else

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include "pocketpy/pocketpy.h"
#include "pocketpy/common/str.h" #include "pocketpy/common/str.h"
#include "pocketpy/common/vector.h" #include "pocketpy/common/vector.h"
@ -8,7 +9,6 @@
extern "C" { extern "C" {
#endif #endif
enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE };
struct pk_SourceData { struct pk_SourceData {
RefCounted rc; RefCounted rc;

View File

@ -4,6 +4,9 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdarg.h> #include <stdarg.h>
#include "pocketpy/common/config.h"
#include "pocketpy/common/export.h"
/************* Public Types *************/ /************* Public Types *************/
typedef struct py_TValue py_TValue; typedef struct py_TValue py_TValue;
typedef uint16_t py_Name; typedef uint16_t py_Name;
@ -29,11 +32,19 @@ typedef py_TValue* py_TmpRef;
/// @return true if the function is successful. /// @return true if the function is successful.
typedef bool (*py_CFunction)(int argc, py_StackRef argv); typedef bool (*py_CFunction)(int argc, py_StackRef argv);
typedef enum BindType { enum BindType {
BindType_FUNCTION, BindType_FUNCTION,
BindType_STATICMETHOD, BindType_STATICMETHOD,
BindType_CLASSMETHOD, BindType_CLASSMETHOD,
} BindType; };
enum CompileMode {
EXEC_MODE,
EVAL_MODE,
REPL_MODE,
JSON_MODE,
CELL_MODE
};
/************* Global VMs *************/ /************* Global VMs *************/
void py_initialize(); void py_initialize();
@ -44,6 +55,7 @@ bool py_exec(const char* source);
/// Eval a simple expression. /// Eval a simple expression.
/// The result will be set to `py_retval()`. /// The result will be set to `py_retval()`.
bool py_eval(const char* source); bool py_eval(const char* source);
bool py_exec2(const char* source, const char* filename, enum CompileMode mode);
/************* Values Creation *************/ /************* Values Creation *************/
void py_newint(py_Ref, py_i64); 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, void py_newfunction2(py_Ref out,
py_CFunction, py_CFunction,
const char* sig, const char* sig,
BindType bt, enum BindType bt,
const char* docstring, const char* docstring,
const py_Ref upvalue); const py_Ref upvalue);
// old style argc-based function // old style argc-based function
@ -118,7 +130,8 @@ bool py_issubclass(py_Type derived, py_Type base);
#define PY_CHECK_ARGC(n) \ #define PY_CHECK_ARGC(n) \
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc) 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_offset(p, i) ((py_Ref)((char*)p + ((i) << 4)))
#define py_arg(i) py_offset(argv, i) #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, py_TmpRef py_bind2(py_Ref obj,
const char* sig, const char* sig,
py_CFunction f, py_CFunction f,
BindType bt, enum BindType bt,
const char* docstring, const char* docstring,
const py_Ref upvalue); const py_Ref upvalue);
// old style argc-based bindings // old style argc-based bindings
void py_bindmethod(py_Type type, const char* name, py_CFunction f); 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); void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f);
/// Get the reference to the i-th register. /// 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); const char* py_tpname(py_Type type);
/// Check if the object is an instance of the given type. /// Check if the object is an instance of the given type.
/// Re
bool py_checktype(const py_Ref self, py_Type type); bool py_checktype(const py_Ref self, py_Type type);
int py_replinput(char* buf);
/// Python favored string formatting. /// Python favored string formatting.
/// %d: int /// %d: int
/// %i: py_i64 (int64_t) /// %i: py_i64 (int64_t)
@ -379,12 +393,13 @@ enum py_PredefinedTypes {
} }
#endif #endif
/* /*
Some notes: Some notes:
## Macros ## Macros
1. Function macros are partial functions. They can be used as normal expressions. Use the same naming convention as functions. 1. Function macros are partial functions. They can be used as normal expressions. Use the same
2. Snippet macros are `do {...} while(0)` blocks. They cannot be used as expressions. Use `UPPER_CASE` naming convention. 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. 3. Constant macros are used for global constants. Use `UPPER_CASE` or k-prefix naming convention.
*/ */

View File

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

View File

@ -220,3 +220,38 @@ void pk_sprintf(c11_sbuf* ss, const char* fmt, ...) {
pk_vsprintf(ss, fmt, args); pk_vsprintf(ss, fmt, args);
va_end(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;
}

View File

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

View File

@ -1454,7 +1454,7 @@ static void Compiler__dtor(Compiler* self) {
#define mode() self->src->mode #define mode() self->src->mode
#define ctx() (&c11_vector__back(Ctx, &self->contexts)) #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) \ #define consume(expected) \
if(!match(expected)) \ if(!match(expected)) \
@ -1463,12 +1463,7 @@ static void Compiler__dtor(Compiler* self) {
pk_TokenSymbols[curr()->type]); pk_TokenSymbols[curr()->type]);
#define consume_end_stmt() \ #define consume_end_stmt() \
if(!match_end_stmt(self)) return SyntaxError("expected statement end") 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) \ #define check(B) \
if((err = B)) return err if((err = B)) return err
@ -1480,8 +1475,6 @@ static NameScope name_scope(Compiler* self) {
#define SyntaxError(...) NULL #define SyntaxError(...) NULL
static Error* NeedMoreLines() { return NULL; }
/* Matchers */ /* Matchers */
static bool is_expression(Compiler* self, bool allow_slice) { static bool is_expression(Compiler* self, bool allow_slice) {
PrattCallback prefix = rules[curr()->type].prefix; 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) #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; bool consumed = false;
if(curr()->type == TK_EOL) { if(curr()->type == TK_EOL) {
while(curr()->type == TK_EOL) while(curr()->type == TK_EOL)
advance(); advance();
consumed = true; consumed = true;
} }
if(need_more_lines) { *need_more_lines = (mode() == REPL_MODE && curr()->type == TK_EOF); }
return consumed; return consumed;
} }
@ -1540,11 +1532,11 @@ static Error* EXPR_TUPLE_ALLOW_SLICE(Compiler* self, bool allow_slice) {
// tuple expression // (a, ) // tuple expression // (a, )
int count = 1; int count = 1;
do { do {
if(curr()->brackets_level) check_newlines_repl(); if(curr()->brackets_level) match_newlines();
if(!is_expression(self, allow_slice)) break; if(!is_expression(self, allow_slice)) break;
check(parse_expression(self, PREC_LOWEST + 1, allow_slice)); check(parse_expression(self, PREC_LOWEST + 1, allow_slice));
count += 1; count += 1;
if(curr()->brackets_level) check_newlines_repl(); if(curr()->brackets_level) match_newlines();
} while(match(TK_COMMA)); } while(match(TK_COMMA));
// pop `count` expressions from the stack and merge them into a TupleExpr // pop `count` expressions from the stack and merge them into a TupleExpr
SequenceExpr* e = TupleExpr__new(prev()->line, count); SequenceExpr* e = TupleExpr__new(prev()->line, count);
@ -1791,9 +1783,9 @@ static Error* exprUnaryOp(Compiler* self) {
static Error* exprGroup(Compiler* self) { static Error* exprGroup(Compiler* self) {
Error* err; Error* err;
int line = prev()->line; int line = prev()->line;
check_newlines_repl(); match_newlines();
check(EXPR_TUPLE(self)); // () is just for change precedence check(EXPR_TUPLE(self)); // () is just for change precedence
check_newlines_repl(); match_newlines();
consume(TK_RPAREN); consume(TK_RPAREN);
if(Ctx__s_top(ctx())->vt->is_tuple) return NULL; if(Ctx__s_top(ctx())->vt->is_tuple) return NULL;
GroupedExpr* g = GroupedExpr__new(line, Ctx__s_popx(ctx())); 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] check(EXPR_VARS(self)); // [expr, vars]
consume(TK_IN); consume(TK_IN);
check(parse_expression(self, PREC_TERNARY + 1, false)); // [expr, vars, iter] check(parse_expression(self, PREC_TERNARY + 1, false)); // [expr, vars, iter]
check_newlines_repl(); match_newlines();
if(match(TK_IF)) { if(match(TK_IF)) {
check(parse_expression(self, PREC_TERNARY + 1, false)); // [expr, vars, iter, cond] check(parse_expression(self, PREC_TERNARY + 1, false)); // [expr, vars, iter, cond]
has_cond = true; has_cond = true;
@ -1844,7 +1836,7 @@ static Error* consume_comp(Compiler* self, Opcode op0, Opcode op1) {
ce->vars = Ctx__s_popx(ctx()); ce->vars = Ctx__s_popx(ctx());
ce->expr = Ctx__s_popx(ctx()); ce->expr = Ctx__s_popx(ctx());
Ctx__s_push(ctx(), (Expr*)ce); Ctx__s_push(ctx(), (Expr*)ce);
check_newlines_repl(); match_newlines();
return NULL; return NULL;
} }
@ -1853,17 +1845,17 @@ static Error* exprList(Compiler* self) {
int line = prev()->line; int line = prev()->line;
int count = 0; int count = 0;
do { do {
check_newlines_repl(); match_newlines();
if(curr()->type == TK_RBRACKET) break; if(curr()->type == TK_RBRACKET) break;
check(EXPR(self)); check(EXPR(self));
count += 1; count += 1;
check_newlines_repl(); match_newlines();
if(count == 1 && match(TK_FOR)) { if(count == 1 && match(TK_FOR)) {
check(consume_comp(self, OP_BUILD_LIST, OP_LIST_APPEND)); check(consume_comp(self, OP_BUILD_LIST, OP_LIST_APPEND));
consume(TK_RBRACKET); consume(TK_RBRACKET);
return NULL; return NULL;
} }
check_newlines_repl(); match_newlines();
} while(match(TK_COMMA)); } while(match(TK_COMMA));
consume(TK_RBRACKET); consume(TK_RBRACKET);
SequenceExpr* e = ListExpr__new(line, count); SequenceExpr* e = ListExpr__new(line, count);
@ -1880,7 +1872,7 @@ static Error* exprMap(Compiler* self) {
bool parsing_dict = false; // {...} may be dict or set bool parsing_dict = false; // {...} may be dict or set
int count = 0; int count = 0;
do { do {
check_newlines_repl(); match_newlines();
if(curr()->type == TK_RBRACE) break; if(curr()->type == TK_RBRACE) break;
check(EXPR(self)); // [key] check(EXPR(self)); // [key]
if(curr()->type == TK_COLON) { parsing_dict = true; } if(curr()->type == TK_COLON) { parsing_dict = true; }
@ -1889,7 +1881,7 @@ static Error* exprMap(Compiler* self) {
check(EXPR(self)); // [key, value] check(EXPR(self)); // [key, value]
} }
count += 1; // key-value pair count count += 1; // key-value pair count
check_newlines_repl(); match_newlines();
if(count == 1 && match(TK_FOR)) { if(count == 1 && match(TK_FOR)) {
if(parsing_dict) { if(parsing_dict) {
check(consume_comp(self, OP_BUILD_DICT, OP_DICT_ADD)); check(consume_comp(self, OP_BUILD_DICT, OP_DICT_ADD));
@ -1899,7 +1891,7 @@ static Error* exprMap(Compiler* self) {
consume(TK_RBRACE); consume(TK_RBRACE);
return NULL; return NULL;
} }
check_newlines_repl(); match_newlines();
} while(match(TK_COMMA)); } while(match(TK_COMMA));
consume(TK_RBRACE); consume(TK_RBRACE);
@ -1922,7 +1914,7 @@ static Error* exprCall(Compiler* self) {
CallExpr* e = CallExpr__new(prev()->line, Ctx__s_popx(ctx())); CallExpr* e = CallExpr__new(prev()->line, Ctx__s_popx(ctx()));
Ctx__s_push(ctx(), (Expr*)e); // push onto the stack in advance Ctx__s_push(ctx(), (Expr*)e); // push onto the stack in advance
do { do {
check_newlines_repl(); match_newlines();
if(curr()->type == TK_RPAREN) break; if(curr()->type == TK_RPAREN) break;
if(curr()->type == TK_ID && next()->type == TK_ASSIGN) { if(curr()->type == TK_ID && next()->type == TK_ASSIGN) {
consume(TK_ID); consume(TK_ID);
@ -1948,7 +1940,7 @@ static Error* exprCall(Compiler* self) {
c11_vector__push(Expr*, &e->args, Ctx__s_popx(ctx())); c11_vector__push(Expr*, &e->args, Ctx__s_popx(ctx()));
} }
} }
check_newlines_repl(); match_newlines();
} while(match(TK_COMMA)); } while(match(TK_COMMA));
consume(TK_RPAREN); consume(TK_RPAREN);
return NULL; return NULL;
@ -1998,9 +1990,9 @@ static Error* exprSlice1(Compiler* self) {
static Error* exprSubscr(Compiler* self) { static Error* exprSubscr(Compiler* self) {
Error* err; Error* err;
int line = prev()->line; int line = prev()->line;
check_newlines_repl(); match_newlines();
check(EXPR_TUPLE_ALLOW_SLICE(self, true)); check(EXPR_TUPLE_ALLOW_SLICE(self, true));
check_newlines_repl(); match_newlines();
consume(TK_RBRACKET); // [lhs, rhs] consume(TK_RBRACKET); // [lhs, rhs]
SubscrExpr* e = SubscrExpr__new(line); SubscrExpr* e = SubscrExpr__new(line);
e->rhs = Ctx__s_popx(ctx()); // [lhs] e->rhs = Ctx__s_popx(ctx()); // [lhs]
@ -2032,9 +2024,7 @@ static Error* compile_block_body(Compiler* self, PrattCallback callback) {
return NULL; return NULL;
} }
bool need_more_lines; bool consumed = match_newlines();
bool consumed = match_newlines_repl(self, &need_more_lines);
if(need_more_lines) return NeedMoreLines();
if(!consumed) return SyntaxError("expected a new line after ':'"); if(!consumed) return SyntaxError("expected a new line after ':'");
consume(TK_INDENT); consume(TK_INDENT);
@ -2100,7 +2090,8 @@ static Error* compile_for_loop(Compiler* self) {
Expr* vars = Ctx__s_popx(ctx()); Expr* vars = Ctx__s_popx(ctx());
bool ok = vtemit_store(vars, ctx()); bool ok = vtemit_store(vars, ctx());
vtdelete(vars); 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: ?? // TODO: ??
// ctx()->try_merge_for_iter_store(for_codei); // 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); Error* err = pk_Lexer__process(src, &tokens);
if(err) return err; if(err) return err;
Token* data = (Token*)tokens.data; // Token* data = (Token*)tokens.data;
printf("%s\n", src->filename->data); // printf("%s\n", src->filename->data);
for(int i = 0; i < tokens.count; i++) { // for(int i = 0; i < tokens.count; i++) {
Token* t = data + i; // Token* t = data + i;
c11_string* tmp = c11_string__new2(t->start, t->length); // c11_string* tmp = c11_string__new2(t->start, t->length);
printf("[%d] %s: %s\n", t->line, pk_TokenSymbols[t->type], tmp->data); // printf("[%d] %s: %s\n", t->line, pk_TokenSymbols[t->type], tmp->data);
c11_string__delete(tmp); // c11_string__delete(tmp);
} // }
Compiler compiler; Compiler compiler;
Compiler__ctor(&compiler, src, tokens); Compiler__ctor(&compiler, src, tokens);

View File

@ -201,10 +201,6 @@ static Error* SyntaxError(const char* fmt, ...){
return NULL; return NULL;
} }
static Error* NeedMoreLines(){
return NULL;
}
static Error* eat_name(pk_Lexer* self){ static Error* eat_name(pk_Lexer* self){
self->curr_char--; self->curr_char--;
while(true) { while(true) {
@ -288,9 +284,6 @@ static Error* eat_string_until(pk_Lexer* self, char quote, bool raw, c11_string*
break; break;
} }
if(c == '\0') { if(c == '\0') {
if(quote3 && self->src->mode == REPL_MODE){
return NeedMoreLines();
}
return SyntaxError("EOL while scanning string literal"); return SyntaxError("EOL while scanning string literal");
} }
if(c == '\n') { if(c == '\n') {
@ -431,7 +424,6 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
// line continuation character // line continuation character
char c = eatchar_include_newline(self); char c = eatchar_include_newline(self);
if(c != '\n') { if(c != '\n') {
if(self->src->mode == REPL_MODE && c == '\0') return NeedMoreLines();
return SyntaxError("expected newline after line continuation character"); return SyntaxError("expected newline after line continuation character");
} }
eat_spaces(self); eat_spaces(self);

View File

@ -49,7 +49,7 @@ void py_newfunction(py_Ref out, py_CFunction f, const char* sig) {
void py_newfunction2(py_Ref out, void py_newfunction2(py_Ref out,
py_CFunction f, py_CFunction f,
const char* sig, const char* sig,
BindType bt, enum BindType bt,
const char* docstring, const char* docstring,
const py_Ref upvalue) {} 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); 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_TValue tmp;
py_newnativefunc(&tmp, f); py_newnativefunc(&tmp, f);
py_setdict(py_tpobject(type), py_name(name), &tmp); py_setdict(py_tpobject(type), py_name(name), &tmp);

View File

@ -168,7 +168,7 @@ static bool
return false; return false;
} }
disassemble(&co); // disassemble(&co);
Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co); Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co);
pk_VM__push_frame(vm, frame); 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_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_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; } bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1; }

View File

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

View File

@ -19,49 +19,40 @@ char* read_file(const char* path) {
return buffer; return buffer;
} }
static char buf[2048];
int main(int argc, char** argv) { int main(int argc, char** argv) {
#if _WIN32 #if _WIN32
SetConsoleCP(CP_UTF8); SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);
#endif #endif
#if 0 if(argc > 2){
py_initialize();
const char* source = "1 < 2";
if(py_eval(source)) {
// handle the result
bool _L0 = py_tobool(py_retval());
printf("%d\n", _L0);
}
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;
__HELP:
printf("Usage: pocketpy [filename]\n"); printf("Usage: pocketpy [filename]\n");
return 0; return 0;
} }
py_initialize();
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);
}
py_finalize();
return 0;
}