mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-26 14:30:17 +00:00
up
This commit is contained in:
parent
a6b4671711
commit
ebe3193327
@ -61,6 +61,7 @@ struct CodeObject {
|
|||||||
std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} };
|
std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} };
|
||||||
std::map<StrName, int> labels;
|
std::map<StrName, int> labels;
|
||||||
|
|
||||||
|
// may be.. just use a large NameDict?
|
||||||
uint32_t perfect_locals_capacity = 2;
|
uint32_t perfect_locals_capacity = 2;
|
||||||
uint32_t perfect_hash_seed = 0;
|
uint32_t perfect_hash_seed = 0;
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "codeobject.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "lexer.h"
|
|
||||||
#include "error.h"
|
|
||||||
#include "ceval.h"
|
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "obj.h"
|
|
||||||
#include "str.h"
|
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -21,9 +14,9 @@ struct PrattRule{
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Compiler {
|
class Compiler {
|
||||||
|
inline static PrattRule rules[kTokenCount];
|
||||||
std::unique_ptr<Lexer> lexer;
|
std::unique_ptr<Lexer> lexer;
|
||||||
stack<CodeEmitContext> contexts;
|
stack<CodeEmitContext> contexts;
|
||||||
std::map<TokenIndex, PrattRule> rules;
|
|
||||||
VM* vm;
|
VM* vm;
|
||||||
bool used;
|
bool used;
|
||||||
// for parsing token stream
|
// for parsing token stream
|
||||||
@ -33,7 +26,6 @@ class Compiler {
|
|||||||
const Token& prev() { return tokens.at(i-1); }
|
const Token& prev() { return tokens.at(i-1); }
|
||||||
const Token& curr() { return tokens.at(i); }
|
const Token& curr() { return tokens.at(i); }
|
||||||
const Token& next() { return tokens.at(i+1); }
|
const Token& next() { return tokens.at(i+1); }
|
||||||
const Token& peek(int offset) { return tokens.at(i+offset); }
|
|
||||||
void advance() { i++; }
|
void advance() { i++; }
|
||||||
|
|
||||||
CodeEmitContext* ctx() { return &contexts.top(); }
|
CodeEmitContext* ctx() { return &contexts.top(); }
|
||||||
@ -49,7 +41,7 @@ class Compiler {
|
|||||||
|
|
||||||
void pop_context(){
|
void pop_context(){
|
||||||
if(!ctx()->s_expr.empty()) UNREACHABLE();
|
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){
|
if(ctx()->co->codes.back().op != OP_RETURN_VALUE){
|
||||||
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
@ -58,14 +50,7 @@ class Compiler {
|
|||||||
contexts.pop();
|
contexts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
static void init_pratt_rules(){
|
||||||
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)
|
|
||||||
);
|
|
||||||
|
|
||||||
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
|
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
|
||||||
#define METHOD(name) &Compiler::name
|
#define METHOD(name) &Compiler::name
|
||||||
#define NO_INFIX nullptr, PREC_NONE
|
#define NO_INFIX nullptr, PREC_NONE
|
||||||
@ -112,22 +97,8 @@ public:
|
|||||||
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
|
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
|
||||||
#undef METHOD
|
#undef METHOD
|
||||||
#undef NO_INFIX
|
#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) {
|
bool match(TokenIndex expected) {
|
||||||
if (curr().type != expected) return false;
|
if (curr().type != expected) return false;
|
||||||
advance();
|
advance();
|
||||||
@ -206,7 +177,7 @@ private:
|
|||||||
consume(TK(":"));
|
consume(TK(":"));
|
||||||
}
|
}
|
||||||
e->func.code = push_context(lexer->src, "<lambda>");
|
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);
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
pop_context();
|
pop_context();
|
||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
@ -464,8 +435,8 @@ private:
|
|||||||
Str _compile_import() {
|
Str _compile_import() {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
Str name = prev().str();
|
Str name = prev().str();
|
||||||
int index = ctx()->add_name(name, NAME_SPECIAL);
|
int index = ctx()->add_name(name);
|
||||||
ctx()->emit(OP_IMPORT_NAME, index, peek(-2).line);
|
ctx()->emit(OP_IMPORT_NAME, index, prev().line);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,8 +496,9 @@ private:
|
|||||||
if(!push_stack) ctx()->emit_expr();
|
if(!push_stack) ctx()->emit_expr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void compile_if_stmt() {
|
void compile_if_stmt() {
|
||||||
EXPR(true); // condition
|
EXPR(false); // condition
|
||||||
int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
if (match(TK("elif"))) {
|
if (match(TK("elif"))) {
|
||||||
@ -544,9 +516,10 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void compile_while_loop() {
|
void compile_while_loop() {
|
||||||
ctx()->enter_block(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);
|
int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE);
|
||||||
@ -556,12 +529,17 @@ private:
|
|||||||
|
|
||||||
void compile_for_loop() {
|
void compile_for_loop() {
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
ctx()->emit_lvalue();
|
Expr_ vars = ctx()->s_expr.popx();
|
||||||
consume(TK("in"));
|
consume(TK("in"));
|
||||||
EXPR(true);
|
EXPR(false);
|
||||||
ctx()->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->enter_block(FOR_LOOP);
|
ctx()->enter_block(FOR_LOOP);
|
||||||
ctx()->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE);
|
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();
|
compile_block_body();
|
||||||
ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->exit_block();
|
ctx()->exit_block();
|
||||||
@ -596,7 +574,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void compile_decorated(){
|
void compile_decorated(){
|
||||||
EXPR(true);
|
EXPR(false);
|
||||||
if(!match_newlines(mode()==REPL_MODE)) SyntaxError();
|
if(!match_newlines(mode()==REPL_MODE)) SyntaxError();
|
||||||
ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line);
|
ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line);
|
||||||
consume(TK("def"));
|
consume(TK("def"));
|
||||||
@ -680,7 +658,7 @@ private:
|
|||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
int dummy_t = ctx()->add_name(prev().str(), NAME_SPECIAL);
|
int dummy_t = ctx()->add_name(prev().str(), NAME_SPECIAL);
|
||||||
if(match(TK("(")) && !match(TK(")"))){
|
if(match(TK("(")) && !match(TK(")"))){
|
||||||
EXPR(true); consume(TK(")"));
|
EXPR(false); consume(TK(")"));
|
||||||
}else{
|
}else{
|
||||||
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
@ -697,7 +675,7 @@ private:
|
|||||||
case TK("with"): {
|
case TK("with"): {
|
||||||
// TODO: reimpl this
|
// TODO: reimpl this
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
// EXPR(true);
|
// EXPR(false);
|
||||||
// consume(TK("as"));
|
// consume(TK("as"));
|
||||||
// consume(TK("@id"));
|
// consume(TK("@id"));
|
||||||
// int index = ctx()->add_name(prev().str(), name_scope());
|
// 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); }
|
void IndentationError(Str msg){ lexer->throw_err("IndentationError", msg, curr().line, curr().start); }
|
||||||
|
|
||||||
public:
|
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(){
|
CodeObject_ compile(){
|
||||||
if(used) UNREACHABLE();
|
if(used) UNREACHABLE();
|
||||||
used = true;
|
used = true;
|
||||||
|
|||||||
14
src/expr.h
14
src/expr.h
@ -6,7 +6,6 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "ceval.h"
|
#include "ceval.h"
|
||||||
|
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
struct CodeEmitContext;
|
struct CodeEmitContext;
|
||||||
@ -369,7 +368,18 @@ struct TupleExpr: SequenceExpr{
|
|||||||
Opcode opcode() const override { return OP_BUILD_TUPLE; }
|
Opcode opcode() const override { return OP_BUILD_TUPLE; }
|
||||||
|
|
||||||
bool emit_store(CodeEmitContext* ctx) override {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user