This commit is contained in:
blueloveTH 2023-04-02 21:05:24 +08:00
parent a6b4671711
commit ebe3193327
3 changed files with 54 additions and 44 deletions

View File

@ -61,6 +61,7 @@ struct CodeObject {
std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} };
std::map<StrName, int> labels;
// may be.. just use a large NameDict?
uint32_t perfect_locals_capacity = 2;
uint32_t perfect_hash_seed = 0;

View File

@ -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> lexer;
stack<CodeEmitContext> contexts;
std::map<TokenIndex, PrattRule> 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<Lexer>(
make_sp<SourceData>(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, "<lambda>");
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<Lexer>(
make_sp<SourceData>(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;

View File

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