mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
up
This commit is contained in:
parent
ea86ea3a34
commit
83d6ac2e78
BIN
.github/workflows.rar
vendored
Normal file
BIN
.github/workflows.rar
vendored
Normal file
Binary file not shown.
129
.github/workflows/main.yml
vendored
129
.github/workflows/main.yml
vendored
@ -1,129 +0,0 @@
|
|||||||
name: build
|
|
||||||
on: [push, pull_request]
|
|
||||||
jobs:
|
|
||||||
build_win:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Setup Clang
|
|
||||||
uses: egor-tensin/setup-clang@v1
|
|
||||||
with:
|
|
||||||
version: 15
|
|
||||||
platform: x64
|
|
||||||
- name: Compiling
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python3 build.py windows
|
|
||||||
python3 build.py windows -lib
|
|
||||||
mkdir -p output/windows/x86_64
|
|
||||||
cp pocketpy.exe output/windows/x86_64
|
|
||||||
cp pocketpy.dll output/windows/x86_64
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
path: output
|
|
||||||
- name: Unit Test
|
|
||||||
run: python3 scripts/run_tests.py
|
|
||||||
- name: Benchmark
|
|
||||||
run: python3 scripts/run_tests.py benchmark
|
|
||||||
build_web:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Setup emsdk
|
|
||||||
uses: mymindstorm/setup-emsdk@v12
|
|
||||||
with:
|
|
||||||
version: 3.1.25
|
|
||||||
actions-cache-folder: 'emsdk-cache'
|
|
||||||
- name: Verify emsdk
|
|
||||||
run: emcc -v
|
|
||||||
- name: Compiling
|
|
||||||
run: |
|
|
||||||
mkdir -p output/web/lib
|
|
||||||
python3 build.py web
|
|
||||||
cp web/lib/* output/web/lib
|
|
||||||
- uses: crazy-max/ghaction-github-pages@v3
|
|
||||||
with:
|
|
||||||
target_branch: gh-pages
|
|
||||||
build_dir: web
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
path: output
|
|
||||||
build_linux:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Setup Clang
|
|
||||||
uses: egor-tensin/setup-clang@v1
|
|
||||||
with:
|
|
||||||
version: 15
|
|
||||||
platform: x64
|
|
||||||
- name: Coverage Test
|
|
||||||
run: |
|
|
||||||
sudo apt install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev
|
|
||||||
python3 preprocess.py
|
|
||||||
bash run_tests.sh
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: coverage
|
|
||||||
path: .coverage
|
|
||||||
- name: Compiling
|
|
||||||
run: |
|
|
||||||
python3 build.py linux
|
|
||||||
python3 build.py linux -lib
|
|
||||||
mkdir -p output/linux/x86_64
|
|
||||||
cp pocketpy output/linux/x86_64
|
|
||||||
cp pocketpy.so output/linux/x86_64
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
path: output
|
|
||||||
- name: Unit Test
|
|
||||||
run: python3 scripts/run_tests.py
|
|
||||||
- name: Benchmark
|
|
||||||
run: python3 scripts/run_tests.py benchmark
|
|
||||||
build_android:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
with:
|
|
||||||
flutter-version: '3.3.0'
|
|
||||||
channel: 'stable'
|
|
||||||
cache: true
|
|
||||||
- run: flutter --version
|
|
||||||
- name: Compiling
|
|
||||||
run: |
|
|
||||||
python3 amalgamate.py
|
|
||||||
cd plugins/flutter/example
|
|
||||||
flutter build apk --split-debug-info=.debug-info --split-per-abi
|
|
||||||
cd build/app/outputs/flutter-apk
|
|
||||||
mkdir -p output/android/arm64-v8a
|
|
||||||
mkdir -p output/android/armeabi-v7a
|
|
||||||
mkdir -p output/android/x86_64
|
|
||||||
unzip -q app-arm64-v8a-release.apk -d tmp
|
|
||||||
mv tmp/lib/arm64-v8a/libpocketpy.so output/android/arm64-v8a/libpocketpy.so
|
|
||||||
rm -rf tmp
|
|
||||||
unzip -q app-armeabi-v7a-release.apk -d tmp
|
|
||||||
mv tmp/lib/armeabi-v7a/libpocketpy.so output/android/armeabi-v7a/libpocketpy.so
|
|
||||||
rm -rf tmp
|
|
||||||
unzip -q app-x86_64-release.apk -d tmp
|
|
||||||
mv tmp/lib/x86_64/libpocketpy.so output/android/x86_64/libpocketpy.so
|
|
||||||
rm -rf tmp
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
path: plugins/flutter/example/build/app/outputs/flutter-apk/output
|
|
||||||
build_macos:
|
|
||||||
runs-on: macos-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: |
|
|
||||||
python3 amalgamate.py
|
|
||||||
cd plugins/macos/pocketpy
|
|
||||||
mkdir -p output/macos
|
|
||||||
xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
|
|
||||||
cp -r build/Release/pocketpy.bundle output/macos
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
path: plugins/macos/pocketpy/output
|
|
15
src/ceval.h
15
src/ceval.h
@ -1,13 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "ref.h"
|
#include "ref.h"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
inline PyObject* VM::run_frame(Frame* frame){
|
inline PyObject* VM::run_frame(Frame* frame){
|
||||||
while(frame->has_next_bytecode()){
|
while(true){
|
||||||
heap._auto_collect(this);
|
heap._auto_collect(this); // gc
|
||||||
|
|
||||||
const Bytecode& byte = frame->next_bytecode();
|
const Bytecode& byte = frame->next_bytecode();
|
||||||
switch (byte.op)
|
switch (byte.op)
|
||||||
@ -320,15 +321,7 @@ inline PyObject* VM::run_frame(Frame* frame){
|
|||||||
default: throw std::runtime_error(Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
|
default: throw std::runtime_error(Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UNREACHABLE();
|
||||||
if(frame->co->src->mode == EVAL_MODE || frame->co->src->mode == JSON_MODE){
|
|
||||||
if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE");
|
|
||||||
return frame->pop_value(this);
|
|
||||||
}
|
|
||||||
#if DEBUG_EXTRA_CHECK
|
|
||||||
if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE");
|
|
||||||
#endif
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
209
src/compiler.h
209
src/compiler.h
@ -20,8 +20,6 @@ struct PrattRule{
|
|||||||
Precedence precedence;
|
Precedence precedence;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ExprAction { EXPR_PUSH_STACK, EXPR_RVALUE, EXPR_LVALUE };
|
|
||||||
|
|
||||||
class Compiler {
|
class Compiler {
|
||||||
std::unique_ptr<Lexer> lexer;
|
std::unique_ptr<Lexer> lexer;
|
||||||
stack<CodeEmitContext> contexts;
|
stack<CodeEmitContext> contexts;
|
||||||
@ -42,8 +40,10 @@ class Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void pop_context(){
|
void pop_context(){
|
||||||
if(!ctx()->s_expr.empty()){
|
if(!ctx()->s_expr.empty()) UNREACHABLE();
|
||||||
ctx()->emit_expr();
|
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);
|
||||||
}
|
}
|
||||||
ctx()->co->optimize(vm);
|
ctx()->co->optimize(vm);
|
||||||
contexts.pop();
|
contexts.pop();
|
||||||
@ -164,16 +164,12 @@ private:
|
|||||||
if (!match_end_stmt()) SyntaxError("expected statement end");
|
if (!match_end_stmt()) SyntaxError("expected statement end");
|
||||||
}
|
}
|
||||||
|
|
||||||
void exprLiteral(){
|
void EXPR(ExprAction action=EXPR_PUSH_STACK) {
|
||||||
ctx()->s_expr.push(
|
parse_expression(PREC_TUPLE + 1, action);
|
||||||
expr_prev_line<LiteralExpr>(prev().value)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void exprFString(){
|
void EXPR_TUPLE(ExprAction action=EXPR_PUSH_STACK) {
|
||||||
ctx()->s_expr.push(
|
parse_expression(PREC_TUPLE, action);
|
||||||
expr_prev_line<FStringExpr>(std::get<Str>(prev().value))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
@ -183,6 +179,19 @@ private:
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************/
|
||||||
|
|
||||||
|
// PASS
|
||||||
|
void exprLiteral(){
|
||||||
|
ctx()->s_expr.push(expr_prev_line<LiteralExpr>(prev().value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
|
void exprFString(){
|
||||||
|
ctx()->s_expr.push(expr_prev_line<FStringExpr>(std::get<Str>(prev().value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprLambda(){
|
void exprLambda(){
|
||||||
auto e = expr_prev_line<LambdaExpr>();
|
auto e = expr_prev_line<LambdaExpr>();
|
||||||
e->func.name = "<lambda>";
|
e->func.name = "<lambda>";
|
||||||
@ -192,42 +201,14 @@ private:
|
|||||||
consume(TK(":"));
|
consume(TK(":"));
|
||||||
}
|
}
|
||||||
e->func.code = push_context(lexer->src, "<lambda>");
|
e->func.code = push_context(lexer->src, "<lambda>");
|
||||||
EXPR();
|
// https://github.com/blueloveTH/pocketpy/issues/37
|
||||||
|
EXPR(true);
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
// assignment是一种特殊的无返回值表达式,他不应该位于PREC中
|
|
||||||
void exprInplaceAssign(){
|
|
||||||
auto e = expr_prev_line<InplaceAssignExpr>();
|
|
||||||
e->op = prev().type;
|
|
||||||
e->lhs = ctx()->s_expr.popx();
|
|
||||||
// lhs cannot be a assignment expression, i.e. a = b += c is not allowed
|
|
||||||
if(e->lhs->is_assignment()) SyntaxError();
|
|
||||||
EXPR_TUPLE();
|
|
||||||
e->rhs = ctx()->s_expr.popx();
|
|
||||||
ctx()->s_expr.push(std::move(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPR(ExprAction action=EXPR_PUSH_STACK) {
|
|
||||||
parse_expression(PREC_TUPLE + 1, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPR_TUPLE(ExprAction action=EXPR_PUSH_STACK) {
|
|
||||||
parse_expression(PREC_TUPLE, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exprAssign(){
|
void exprAssign(){
|
||||||
auto e = expr_prev_line<AssignExpr>();
|
|
||||||
e->lhs = ctx()->s_expr.popx();
|
|
||||||
// lhs cannot be a assignment expression, i.e. a = b = c is not allowed
|
|
||||||
// however in cpython, it is allowed, we'll fix it later
|
|
||||||
if(e->lhs->is_assignment()) SyntaxError();
|
|
||||||
EXPR_TUPLE();
|
|
||||||
e->rhs = ctx()->s_expr.popx();
|
|
||||||
ctx()->s_expr.push(std::move(e));
|
|
||||||
|
|
||||||
// if(co()->codes.empty()) UNREACHABLE();
|
// if(co()->codes.empty()) UNREACHABLE();
|
||||||
// bool is_load_name_ref = co()->codes.back().op == OP_LOAD_NAME_REF;
|
// bool is_load_name_ref = co()->codes.back().op == OP_LOAD_NAME_REF;
|
||||||
// int _name_arg = co()->codes.back().arg;
|
// int _name_arg = co()->codes.back().arg;
|
||||||
@ -277,6 +258,7 @@ private:
|
|||||||
// co()->_rvalue -= 1;
|
// co()->_rvalue -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprTuple(){
|
void exprTuple(){
|
||||||
auto e = expr_prev_line<TupleExpr>();
|
auto e = expr_prev_line<TupleExpr>();
|
||||||
do {
|
do {
|
||||||
@ -286,6 +268,7 @@ private:
|
|||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprOr(){
|
void exprOr(){
|
||||||
auto e = expr_prev_line<OrExpr>();
|
auto e = expr_prev_line<OrExpr>();
|
||||||
e->lhs = ctx()->s_expr.popx();
|
e->lhs = ctx()->s_expr.popx();
|
||||||
@ -294,14 +277,16 @@ private:
|
|||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprAnd(){
|
void exprAnd(){
|
||||||
auto e = expr_prev_line<OrExpr>();
|
auto e = expr_prev_line<AndExpr>();
|
||||||
e->lhs = ctx()->s_expr.popx();
|
e->lhs = ctx()->s_expr.popx();
|
||||||
parse_expression(PREC_LOGICAL_AND + 1);
|
parse_expression(PREC_LOGICAL_AND + 1);
|
||||||
e->rhs = ctx()->s_expr.popx();
|
e->rhs = ctx()->s_expr.popx();
|
||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprTernary(){
|
void exprTernary(){
|
||||||
auto e = expr_prev_line<TernaryExpr>();
|
auto e = expr_prev_line<TernaryExpr>();
|
||||||
e->cond = ctx()->s_expr.popx();
|
e->cond = ctx()->s_expr.popx();
|
||||||
@ -313,6 +298,7 @@ private:
|
|||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprBinaryOp(){
|
void exprBinaryOp(){
|
||||||
auto e = expr_prev_line<BinaryExpr>();
|
auto e = expr_prev_line<BinaryExpr>();
|
||||||
e->op = prev().type;
|
e->op = prev().type;
|
||||||
@ -322,85 +308,56 @@ private:
|
|||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprNot() {
|
void exprNot() {
|
||||||
parse_expression(PREC_LOGICAL_NOT + 1);
|
parse_expression(PREC_LOGICAL_NOT + 1);
|
||||||
ctx()->s_expr.push(
|
ctx()->s_expr.push(expr_prev_line<NotExpr>(ctx()->s_expr.popx()));
|
||||||
expr_prev_line<NotExpr>(ctx()->s_expr.popx())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprUnaryOp(){
|
void exprUnaryOp(){
|
||||||
TokenIndex type = prev().type;
|
TokenIndex op = prev().type;
|
||||||
parse_expression(PREC_UNARY + 1);
|
parse_expression(PREC_UNARY + 1);
|
||||||
Expr_ e;
|
switch(op){
|
||||||
switch(type){
|
|
||||||
case TK("-"):
|
case TK("-"):
|
||||||
e = expr_prev_line<NegatedExpr>(ctx()->s_expr.popx());
|
ctx()->s_expr.push(expr_prev_line<NegatedExpr>(ctx()->s_expr.popx()));
|
||||||
|
break;
|
||||||
case TK("*"):
|
case TK("*"):
|
||||||
e = expr_prev_line<StarredExpr>(ctx()->s_expr.popx());
|
ctx()->s_expr.push(expr_prev_line<StarredExpr>(ctx()->s_expr.popx()));
|
||||||
|
break;
|
||||||
default: UNREACHABLE();
|
default: UNREACHABLE();
|
||||||
}
|
}
|
||||||
ctx()->s_expr.push(std::move(e));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// () is just for change precedence
|
// PASS
|
||||||
void exprGroup(){
|
void exprGroup(){
|
||||||
match_newlines(mode()==REPL_MODE);
|
match_newlines(mode()==REPL_MODE);
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE(); // () is just for change precedence
|
||||||
match_newlines(mode()==REPL_MODE);
|
match_newlines(mode()==REPL_MODE);
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// void _consume_comp(Opcode op0, Opcode op1, int _patch, int _body_start){
|
// PASS
|
||||||
// int _body_end_return = emit(OP_JUMP_ABSOLUTE, -1);
|
|
||||||
// int _body_end = co()->codes.size();
|
|
||||||
// co()->codes[_patch].op = OP_JUMP_ABSOLUTE;
|
|
||||||
// co()->codes[_patch].arg = _body_end;
|
|
||||||
// emit(op0, 0);
|
|
||||||
// EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE();
|
|
||||||
// match_newlines(mode()==REPL_MODE);
|
|
||||||
|
|
||||||
// int _skipPatch = emit(OP_JUMP_ABSOLUTE);
|
|
||||||
// int _cond_start = co()->codes.size();
|
|
||||||
// int _cond_end_return = -1;
|
|
||||||
// if(match(TK("if"))) {
|
|
||||||
// EXPR_TUPLE();
|
|
||||||
// _cond_end_return = emit(OP_JUMP_ABSOLUTE, -1);
|
|
||||||
// }
|
|
||||||
// patch_jump(_skipPatch);
|
|
||||||
|
|
||||||
// emit(OP_GET_ITER);
|
|
||||||
// co()->_enter_block(FOR_LOOP);
|
|
||||||
// emit(OP_FOR_ITER);
|
|
||||||
|
|
||||||
// if(_cond_end_return != -1) { // there is an if condition
|
|
||||||
// emit(OP_JUMP_ABSOLUTE, _cond_start);
|
|
||||||
// patch_jump(_cond_end_return);
|
|
||||||
// int ifpatch = emit(OP_POP_JUMP_IF_FALSE);
|
|
||||||
// emit(OP_JUMP_ABSOLUTE, _body_start);
|
|
||||||
// patch_jump(_body_end_return);
|
|
||||||
// emit(op1);
|
|
||||||
// patch_jump(ifpatch);
|
|
||||||
// }else{
|
|
||||||
// emit(OP_JUMP_ABSOLUTE, _body_start);
|
|
||||||
// patch_jump(_body_end_return);
|
|
||||||
// emit(op1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// emit(OP_LOOP_CONTINUE, -1, true);
|
|
||||||
// co()->_exit_block();
|
|
||||||
// match_newlines(mode()==REPL_MODE);
|
|
||||||
// }
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void _consume_comp(Expr_ expr){
|
void _consume_comp(Expr_ expr){
|
||||||
static_assert(std::is_base_of<CompExpr, T>::value);
|
static_assert(std::is_base_of<CompExpr, T>::value);
|
||||||
std::unique_ptr<CompExpr> ce = std::make_unique<T>();
|
std::unique_ptr<CompExpr> ce = std::make_unique<T>();
|
||||||
ce->expr = std::move(expr);
|
ce->expr = std::move(expr);
|
||||||
// ...
|
EXPR_TUPLE(); // must be a lvalue
|
||||||
|
ce->vars = ctx()->s_expr.popx();
|
||||||
|
consume(TK("in"));
|
||||||
|
EXPR();
|
||||||
|
ce->iter = ctx()->s_expr.popx();
|
||||||
|
match_newlines(mode()==REPL_MODE);
|
||||||
|
if(match(TK("if"))){
|
||||||
|
EXPR();
|
||||||
|
ce->cond = ctx()->s_expr.popx();
|
||||||
|
}
|
||||||
ctx()->s_expr.push(std::move(ce));
|
ctx()->s_expr.push(std::move(ce));
|
||||||
|
match_newlines(mode()==REPL_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprList() {
|
void exprList() {
|
||||||
auto e = expr_prev_line<ListExpr>();
|
auto e = expr_prev_line<ListExpr>();
|
||||||
do {
|
do {
|
||||||
@ -414,15 +371,15 @@ private:
|
|||||||
consume(TK("]"));
|
consume(TK("]"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
match_newlines(mode()==REPL_MODE);
|
||||||
} while (match(TK(",")));
|
} while (match(TK(",")));
|
||||||
match_newlines(mode()==REPL_MODE);
|
|
||||||
consume(TK("]"));
|
consume(TK("]"));
|
||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
// {...} may be dict or set
|
// PASS
|
||||||
void exprMap() {
|
void exprMap() {
|
||||||
bool parsing_dict = false;
|
bool parsing_dict = false; // {...} may be dict or set
|
||||||
std::vector<Expr_> items;
|
std::vector<Expr_> items;
|
||||||
do {
|
do {
|
||||||
match_newlines(mode()==REPL_MODE);
|
match_newlines(mode()==REPL_MODE);
|
||||||
@ -446,6 +403,7 @@ private:
|
|||||||
consume(TK("}"));
|
consume(TK("}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
match_newlines(mode()==REPL_MODE);
|
||||||
} while (match(TK(",")));
|
} while (match(TK(",")));
|
||||||
consume(TK("}"));
|
consume(TK("}"));
|
||||||
if(items.size()==0 || parsing_dict){
|
if(items.size()==0 || parsing_dict){
|
||||||
@ -457,8 +415,10 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprCall() {
|
void exprCall() {
|
||||||
auto e = expr_prev_line<CallExpr>();
|
auto e = expr_prev_line<CallExpr>();
|
||||||
|
e->callable = ctx()->s_expr.popx();
|
||||||
do {
|
do {
|
||||||
match_newlines(mode()==REPL_MODE);
|
match_newlines(mode()==REPL_MODE);
|
||||||
if (curr().type==TK(")")) break;
|
if (curr().type==TK(")")) break;
|
||||||
@ -487,12 +447,12 @@ private:
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprName(){
|
void exprName(){
|
||||||
ctx()->s_expr.push(
|
ctx()->s_expr.push(expr_prev_line<NameExpr>(prev().str(), name_scope()));
|
||||||
expr_prev_line<NameExpr>(prev().str(), name_scope())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprAttrib() {
|
void exprAttrib() {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
ctx()->s_expr.push(
|
ctx()->s_expr.push(
|
||||||
@ -500,6 +460,7 @@ private:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprSubscr() {
|
void exprSubscr() {
|
||||||
auto e = expr_prev_line<SubscrExpr>();
|
auto e = expr_prev_line<SubscrExpr>();
|
||||||
std::vector<Expr_> items;
|
std::vector<Expr_> items;
|
||||||
@ -526,10 +487,9 @@ private:
|
|||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS
|
||||||
void exprLiteral0() {
|
void exprLiteral0() {
|
||||||
ctx()->s_expr.push(
|
ctx()->s_expr.push(expr_prev_line<Literal0Expr>(prev().type));
|
||||||
expr_prev_line<Literal0Expr>(prev().type)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_block_body() {
|
void compile_block_body() {
|
||||||
@ -599,7 +559,7 @@ private:
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_expression(int precedence, ExprAction action=EXPR_PUSH_STACK) {
|
void parse_expression(int precedence, bool push_stack=true) {
|
||||||
advance();
|
advance();
|
||||||
PrattCallback prefix = rules[prev().type].prefix;
|
PrattCallback prefix = rules[prev().type].prefix;
|
||||||
if (prefix == nullptr) SyntaxError(Str("expected an expression, but got ") + TK_STR(prev().type));
|
if (prefix == nullptr) SyntaxError(Str("expected an expression, but got ") + TK_STR(prev().type));
|
||||||
@ -611,16 +571,11 @@ private:
|
|||||||
if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true");
|
if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true");
|
||||||
(this->*infix)();
|
(this->*infix)();
|
||||||
}
|
}
|
||||||
switch(action){
|
if(!push_stack) ctx()->emit_expr();
|
||||||
case EXPR_PUSH_STACK: break;
|
|
||||||
case EXPR_RVALUE: ctx()->emit_rvalue(); break;
|
|
||||||
case EXPR_LVALUE: ctx()->emit_lvalue(); break;
|
|
||||||
default: UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_if_stmt() {
|
void compile_if_stmt() {
|
||||||
EXPR(EXPR_RVALUE); // condition
|
EXPR(true); // 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"))) {
|
||||||
@ -640,7 +595,7 @@ private:
|
|||||||
|
|
||||||
void compile_while_loop() {
|
void compile_while_loop() {
|
||||||
ctx()->enter_block(WHILE_LOOP);
|
ctx()->enter_block(WHILE_LOOP);
|
||||||
EXPR(EXPR_RVALUE); // condition
|
EXPR(true); // 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);
|
||||||
@ -649,9 +604,10 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void compile_for_loop() {
|
void compile_for_loop() {
|
||||||
EXPR_TUPLE(EXPR_LVALUE);
|
EXPR_TUPLE();
|
||||||
|
ctx()->emit_lvalue();
|
||||||
consume(TK("in"));
|
consume(TK("in"));
|
||||||
EXPR_TUPLE(EXPR_RVALUE);
|
EXPR(true);
|
||||||
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);
|
||||||
@ -689,10 +645,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void compile_decorated(){
|
void compile_decorated(){
|
||||||
EXPR(EXPR_RVALUE);
|
EXPR(true);
|
||||||
if(!match_newlines(mode()==REPL_MODE)){
|
if(!match_newlines(mode()==REPL_MODE)) SyntaxError();
|
||||||
SyntaxError("expected a new line after '@'");
|
|
||||||
}
|
|
||||||
ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line);
|
ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line);
|
||||||
consume(TK("def"));
|
consume(TK("def"));
|
||||||
compile_function();
|
compile_function();
|
||||||
@ -718,7 +672,7 @@ private:
|
|||||||
break;
|
break;
|
||||||
case TK("yield"):
|
case TK("yield"):
|
||||||
if (contexts.size() <= 1) SyntaxError("'yield' outside function");
|
if (contexts.size() <= 1) SyntaxError("'yield' outside function");
|
||||||
EXPR_TUPLE(EXPR_RVALUE);
|
EXPR_TUPLE(true);
|
||||||
// if yield present, the function is a generator
|
// if yield present, the function is a generator
|
||||||
ctx()->co->is_generator = true;
|
ctx()->co->is_generator = true;
|
||||||
ctx()->emit(OP_YIELD_VALUE, BC_NOARG, kw_line);
|
ctx()->emit(OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||||
@ -729,7 +683,7 @@ private:
|
|||||||
if(match_end_stmt()){
|
if(match_end_stmt()){
|
||||||
ctx()->emit(OP_LOAD_NONE, BC_NOARG, kw_line);
|
ctx()->emit(OP_LOAD_NONE, BC_NOARG, kw_line);
|
||||||
}else{
|
}else{
|
||||||
EXPR_TUPLE(EXPR_RVALUE);
|
EXPR_TUPLE(true);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
}
|
}
|
||||||
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, kw_line);
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, kw_line);
|
||||||
@ -746,13 +700,14 @@ private:
|
|||||||
case TK("pass"): consume_end_stmt(); break;
|
case TK("pass"): consume_end_stmt(); break;
|
||||||
/*************************************************/
|
/*************************************************/
|
||||||
case TK("assert"):
|
case TK("assert"):
|
||||||
EXPR_TUPLE(EXPR_RVALUE);
|
EXPR_TUPLE(true);
|
||||||
// TODO: change OP_ASSERT impl in ceval.h
|
// TODO: change OP_ASSERT impl in ceval.h
|
||||||
ctx()->emit(OP_ASSERT, BC_NOARG, kw_line);
|
ctx()->emit(OP_ASSERT, BC_NOARG, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("del"):
|
case TK("del"):
|
||||||
EXPR_TUPLE(EXPR_LVALUE);
|
EXPR_TUPLE();
|
||||||
|
ctx()->emit_lvalue();
|
||||||
ctx()->emit(OP_DELETE_REF, BC_NOARG, kw_line);
|
ctx()->emit(OP_DELETE_REF, BC_NOARG, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
@ -767,7 +722,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(EXPR_RVALUE); consume(TK(")"));
|
EXPR(true); consume(TK(")"));
|
||||||
}else{
|
}else{
|
||||||
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
@ -775,7 +730,7 @@ private:
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("with"): {
|
case TK("with"): {
|
||||||
EXPR(EXPR_RVALUE);
|
EXPR(true);
|
||||||
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());
|
||||||
@ -953,6 +908,7 @@ public:
|
|||||||
if(mode()==EVAL_MODE) {
|
if(mode()==EVAL_MODE) {
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
consume(TK("@eof"));
|
consume(TK("@eof"));
|
||||||
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
pop_context();
|
pop_context();
|
||||||
return code;
|
return code;
|
||||||
}else if(mode()==JSON_MODE){
|
}else if(mode()==JSON_MODE){
|
||||||
@ -962,6 +918,7 @@ public:
|
|||||||
else if(match(TK("["))) exprList();
|
else if(match(TK("["))) exprList();
|
||||||
else SyntaxError("expect a JSON object or array");
|
else SyntaxError("expect a JSON object or array");
|
||||||
consume(TK("@eof"));
|
consume(TK("@eof"));
|
||||||
|
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
pop_context();
|
pop_context();
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -343,6 +343,7 @@ struct AttribExpr: Expr{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct CallExpr: Expr{
|
struct CallExpr: Expr{
|
||||||
|
Expr_ callable;
|
||||||
std::vector<Expr_> args;
|
std::vector<Expr_> args;
|
||||||
std::vector<std::pair<Str, Expr_>> kwargs;
|
std::vector<std::pair<Str, Expr_>> kwargs;
|
||||||
Str str() const override { return "()"; }
|
Str str() const override { return "()"; }
|
||||||
|
@ -53,10 +53,6 @@ struct Frame {
|
|||||||
// return ss.str();
|
// return ss.str();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
bool has_next_bytecode() const {
|
|
||||||
return _next_ip < co->codes.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* pop(){
|
PyObject* pop(){
|
||||||
#if DEBUG_EXTRA_CHECK
|
#if DEBUG_EXTRA_CHECK
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user