diff --git a/include/pocketpy/codeobject.h b/include/pocketpy/codeobject.h index a128ef10..03b90cd8 100644 --- a/include/pocketpy/codeobject.h +++ b/include/pocketpy/codeobject.h @@ -131,6 +131,7 @@ struct FuncDecl { Str signature; // signature of this function Str docstring; // docstring of this function + bool is_simple; void _gc_mark() const; }; diff --git a/include/pocketpy/expr.h b/include/pocketpy/expr.h index 1cb34269..1283fa5c 100644 --- a/include/pocketpy/expr.h +++ b/include/pocketpy/expr.h @@ -42,6 +42,7 @@ struct Expr{ struct CodeEmitContext{ VM* vm; + FuncDecl_ func; // optional CodeObject_ co; // some bugs on MSVC (error C2280) when using std::vector // so we use stack_no_copy instead diff --git a/run_profile.sh b/run_profile.sh index 49e46d82..b06d24a2 100644 --- a/run_profile.sh +++ b/run_profile.sh @@ -1,7 +1,7 @@ python3 prebuild.py SRC=$(find src/ -name "*.cpp") clang++ -pg -O1 -std=c++17 -stdlib=libc++ -Wfatal-errors -o main $SRC src2/main.cpp -Iinclude -time ./main benchmarks/primes.py +time ./main benchmarks/fib.py mv benchmarks/gmon.out . gprof main gmon.out > gprof.txt rm gmon.out diff --git a/src/compiler.cpp b/src/compiler.cpp index 3fcf5737..1415ba35 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -19,6 +19,7 @@ namespace pkpy{ decl->code = std::make_shared(lexer->src, name); decl->nested = name_scope() == NAME_LOCAL; contexts.push(CodeEmitContext(vm, decl->code, contexts.size())); + contexts.top().func = decl; return decl; } @@ -35,11 +36,21 @@ namespace pkpy{ if(ctx()->co->varnames.size() > PK_MAX_CO_VARNAMES){ SyntaxError("maximum number of local variables exceeded"); } + FuncDecl_ func = contexts.top().func; + if(func){ + func->is_simple = true; + if(func->code->is_generator) func->is_simple = false; + if(func->kwargs.size() > 0) func->is_simple = false; + if(func->starred_arg >= 0) func->is_simple = false; + if(func->starred_kwarg >= 0) func->is_simple = false; + } contexts.pop(); } void Compiler::init_pratt_rules(){ - if(rules[TK(".")].precedence != PREC_NONE) return; + PK_LOCAL_STATIC unsigned int count = 0; + if(count > 0) return; + count += 1; // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ #define METHOD(name) &Compiler::name #define NO_INFIX nullptr, PREC_NONE diff --git a/src/vm.cpp b/src/vm.cpp index 63f6873f..da7205c0 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -739,15 +739,15 @@ void VM::_prepare_py_call(PyObject** buffer, ArgsView args, ArgsView kwargs, con if(args.size() < decl_argc){ vm->TypeError(fmt( - "expected ", decl_argc, " positional arguments, got ", args.size(), - " (", co->name, ')' + co->name, "() takes ", decl_argc, " positional arguments but ", args.size(), " were given" )); + UNREACHABLE(); } int i = 0; // prepare args for(int index: decl->args) buffer[index] = args[i++]; - // set extra varnames to nullptr + // set extra varnames to PY_NULL for(int j=i; jkwargs) buffer[kv.key] = kv.value; @@ -843,6 +843,28 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){ const CodeObject* co = decl->code.get(); int co_nlocals = co->varnames.size(); + PyObject** _base = args.begin(); + + if(decl->is_simple){ + if(args.size() != decl->args.size()){ + TypeError(fmt( + co->name, "() takes ", decl->args.size(), " positional arguments but ", args.size(), " were given" + )); + UNREACHABLE(); + } + if(!kwargs.empty()){ + TypeError(fmt(co->name, "() takes no keyword arguments")); + UNREACHABLE(); + } + s_data.reset(_base + co_nlocals); + int i = 0; + // prepare args + for(int index: decl->args) _base[index] = args[i++]; + // set extra varnames to PY_NULL + for(int j=i; jis_generator){ @@ -854,8 +876,10 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){ } // copy buffer back to stack - s_data.reset(args.begin()); - for(int j=0; j