diff --git a/src/codeobject.h b/src/codeobject.h index e851fb31..1795f2c5 100644 --- a/src/codeobject.h +++ b/src/codeobject.h @@ -61,6 +61,7 @@ struct CodeObject { std::vector blocks = { CodeBlock{NO_BLOCK, -1} }; std::map labels; + // may be.. just use a large NameDict? uint32_t perfect_locals_capacity = 2; uint32_t perfect_hash_seed = 0; diff --git a/src/compiler.h b/src/compiler.h index 08068351..6b3dbae6 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,13 +1,6 @@ #pragma once -#include "codeobject.h" -#include "common.h" -#include "lexer.h" -#include "error.h" -#include "ceval.h" #include "expr.h" -#include "obj.h" -#include "str.h" namespace pkpy{ @@ -21,9 +14,9 @@ struct PrattRule{ }; class Compiler { + inline static PrattRule rules[kTokenCount]; std::unique_ptr lexer; stack contexts; - std::map rules; VM* vm; bool used; // for parsing token stream @@ -33,7 +26,6 @@ class Compiler { const Token& prev() { return tokens.at(i-1); } const Token& curr() { return tokens.at(i); } const Token& next() { return tokens.at(i+1); } - const Token& peek(int offset) { return tokens.at(i+offset); } void advance() { i++; } CodeEmitContext* ctx() { return &contexts.top(); } @@ -49,7 +41,7 @@ class Compiler { void pop_context(){ if(!ctx()->s_expr.empty()) UNREACHABLE(); - // if last instruction is not return, add a default return None + // if the last op does not return, add a default return None if(ctx()->co->codes.back().op != OP_RETURN_VALUE){ ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE); ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); @@ -58,14 +50,7 @@ class Compiler { contexts.pop(); } -public: - Compiler(VM* vm, const char* source, Str filename, CompileMode mode){ - this->vm = vm; - this->used = false; - this->lexer = std::make_unique( - make_sp(source, filename, mode) - ); - + static void init_pratt_rules(){ // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ #define METHOD(name) &Compiler::name #define NO_INFIX nullptr, PREC_NONE @@ -112,22 +97,8 @@ public: rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX }; #undef METHOD #undef NO_INFIX - - // rules[TK("=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT }; - // rules[TK("+=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("-=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("*=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("/=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("//=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("%=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("&=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("|=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("^=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK(">>=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; - // rules[TK("<<=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; } -private: bool match(TokenIndex expected) { if (curr().type != expected) return false; advance(); @@ -206,7 +177,7 @@ private: consume(TK(":")); } e->func.code = push_context(lexer->src, ""); - EXPR(true); // https://github.com/blueloveTH/pocketpy/issues/37 + EXPR(false); // https://github.com/blueloveTH/pocketpy/issues/37 ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); pop_context(); ctx()->s_expr.push(std::move(e)); @@ -464,8 +435,8 @@ private: Str _compile_import() { consume(TK("@id")); Str name = prev().str(); - int index = ctx()->add_name(name, NAME_SPECIAL); - ctx()->emit(OP_IMPORT_NAME, index, peek(-2).line); + int index = ctx()->add_name(name); + ctx()->emit(OP_IMPORT_NAME, index, prev().line); return name; } @@ -525,8 +496,9 @@ private: if(!push_stack) ctx()->emit_expr(); } + // PASS void compile_if_stmt() { - EXPR(true); // condition + EXPR(false); // condition int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line); compile_block_body(); if (match(TK("elif"))) { @@ -544,9 +516,10 @@ private: } } + // PASS void compile_while_loop() { ctx()->enter_block(WHILE_LOOP); - EXPR(true); // condition + EXPR(false); // condition int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line); compile_block_body(); ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE); @@ -556,12 +529,17 @@ private: void compile_for_loop() { EXPR_TUPLE(); - ctx()->emit_lvalue(); + Expr_ vars = ctx()->s_expr.popx(); consume(TK("in")); - EXPR(true); + EXPR(false); ctx()->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE); ctx()->enter_block(FOR_LOOP); ctx()->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE); + // set variables and handle implicit unpack + bool ok = vars->emit_store(ctx()); + // this error occurs in `vars` instead of this line + // but...nevermind + if(!ok) SyntaxError(); compile_block_body(); ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE); ctx()->exit_block(); @@ -596,7 +574,7 @@ private: } void compile_decorated(){ - EXPR(true); + EXPR(false); if(!match_newlines(mode()==REPL_MODE)) SyntaxError(); ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line); consume(TK("def")); @@ -680,7 +658,7 @@ private: consume(TK("@id")); int dummy_t = ctx()->add_name(prev().str(), NAME_SPECIAL); if(match(TK("(")) && !match(TK(")"))){ - EXPR(true); consume(TK(")")); + EXPR(false); consume(TK(")")); }else{ ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE); } @@ -697,7 +675,7 @@ private: case TK("with"): { // TODO: reimpl this UNREACHABLE(); - // EXPR(true); + // EXPR(false); // consume(TK("as")); // consume(TK("@id")); // int index = ctx()->add_name(prev().str(), name_scope()); @@ -859,6 +837,27 @@ private: void IndentationError(Str msg){ lexer->throw_err("IndentationError", msg, curr().line, curr().start); } public: + Compiler(VM* vm, const char* source, Str filename, CompileMode mode){ + this->vm = vm; + this->used = false; + this->lexer = std::make_unique( + make_sp(source, filename, mode) + ); + if(rules.empty()) init_pratt_rules(); + // rules[TK("=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT }; + // rules[TK("+=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("-=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("*=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("/=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("//=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("%=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("&=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("|=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("^=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK(">>=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + // rules[TK("<<=")] = { nullptr, METHOD(exprInplaceAssign), PREC_ASSIGNMENT }; + } + CodeObject_ compile(){ if(used) UNREACHABLE(); used = true; diff --git a/src/expr.h b/src/expr.h index c8ef18f7..d3007139 100644 --- a/src/expr.h +++ b/src/expr.h @@ -6,7 +6,6 @@ #include "error.h" #include "ceval.h" - namespace pkpy{ struct CodeEmitContext; @@ -369,7 +368,18 @@ struct TupleExpr: SequenceExpr{ Opcode opcode() const override { return OP_BUILD_TUPLE; } bool emit_store(CodeEmitContext* ctx) override { - // ... + // assume TOS is an iterable + // unpack it and emit several OP_STORE + // https://docs.python.org/3/library/dis.html#opcode-UNPACK_SEQUENCE + // https://docs.python.org/3/library/dis.html#opcode-UNPACK_EX + return true; + } + + bool emit_del(CodeEmitContext* ctx) override{ + for(auto& e: items){ + bool ok = e->emit_del(ctx); + if(!ok) return false; + } return true; } };