Explorar o código

use error code

blueloveTH hai 1 ano
pai
achega
81c4853f04

+ 1 - 1
include/pocketpy/common/gil.hpp

@@ -15,6 +15,6 @@ struct GIL {
 #define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
 
 #else
-#define PK_THREAD_LOCAL
+#define PK_THREAD_LOCAL static
 #define PK_GLOBAL_SCOPE_LOCK()
 #endif

+ 1 - 1
include/pocketpy/common/str.hpp

@@ -25,7 +25,7 @@ struct Str {
     Str(std::string_view s);
     Str(const char* s);
     Str(const char* s, int len);
-    Str(std::pair<char*, int>);
+    Str(pair<char*, int>);      // take ownership
     Str(const Str& other);
     Str(Str&& other);
 

+ 7 - 0
include/pocketpy/common/types.hpp

@@ -15,6 +15,13 @@ struct explicit_copy_t {
     explicit explicit_copy_t() = default;
 };
 
+template <typename K, typename V>
+struct pair {
+    K first;
+    V second;
+    pair(K first, V second) : first(first), second(second) {}
+};
+
 // Dummy types
 struct DummyInstance {};
 

+ 8 - 12
include/pocketpy/common/vector.hpp

@@ -13,6 +13,8 @@ namespace pkpy {
 
 template <typename T>
 struct array {
+    static_assert(is_pod_v<T>);
+
     T* _data;
     int _size;
 
@@ -39,10 +41,7 @@ struct array {
     array(T* data, int size) : _data(data), _size(size) {}
 
     array& operator= (array&& other) noexcept {
-        if(_data) {
-            std::destroy(begin(), end());
-            std::free(_data);
-        }
+        if(_data) std::free(_data);
         _data = other._data;
         _size = other._size;
         other._data = nullptr;
@@ -70,18 +69,15 @@ struct array {
 
     T* data() const { return _data; }
 
-    std::pair<T*, int> detach() noexcept {
-        std::pair<T*, int> retval(_data, _size);
+    pair<T*, int> detach() noexcept {
+        pair<T*, int> retval(_data, _size);
         _data = nullptr;
         _size = 0;
         return retval;
     }
 
     ~array() {
-        if(_data) {
-            std::destroy(begin(), end());
-            std::free(_data);
-        }
+        if(_data) std::free(_data);
     }
 };
 
@@ -260,8 +256,8 @@ struct vector {
         return retval;
     }
 
-    std::pair<T*, int> detach() noexcept {
-        std::pair<T*, int> retval(_data, _size);
+    pair<T*, int> detach() noexcept {
+        pair<T*, int> retval(_data, _size);
         _data = nullptr;
         _capacity = 0;
         _size = 0;

+ 81 - 110
include/pocketpy/compiler/compiler.hpp

@@ -1,11 +1,12 @@
 #pragma once
 
 #include "pocketpy/compiler/expr.hpp"
+#include "pocketpy/objects/error.hpp"
 
 namespace pkpy {
 
-class Compiler;
-typedef void (Compiler::*PrattCallback)();
+struct Compiler;
+typedef Error* (Compiler::*PrattCallback)() noexcept;
 
 struct PrattRule {
     PrattCallback prefix;
@@ -13,7 +14,7 @@ struct PrattRule {
     Precedence precedence;
 };
 
-class Compiler {
+struct Compiler {
     PK_ALWAYS_PASS_BY_POINTER(Compiler)
 
     static PrattRule rules[kTokenCount];
@@ -24,47 +25,41 @@ class Compiler {
     bool unknown_global_scope;  // for eval/exec() call
     // for parsing token stream
     int i = 0;
-    vector<Token> tokens;
 
-    const Token& prev() const { return tokens[i - 1]; }
+    const Token& tk(int i) const noexcept{ return lexer.nexts[i]; }
+    const Token& prev() const noexcept{ return tk(i - 1); }
+    const Token& curr() const noexcept{ return tk(i); }
+    const Token& next() const noexcept{ return tk(i + 1); }
 
-    const Token& curr() const { return tokens[i]; }
-
-    const Token& next() const { return tokens[i + 1]; }
-
-    const Token& err() const {
-        if(i >= tokens.size()) return prev();
+    const Token& err() const noexcept{
+        if(i >= lexer.nexts.size()) return prev();
         return curr();
     }
 
-    void advance(int delta = 1) { i += delta; }
-
-    CodeEmitContext* ctx() { return &contexts.back(); }
+    void advance(int delta = 1) noexcept{ i += delta; }
 
-    CompileMode mode() const { return lexer.src->mode; }
+    CodeEmitContext* ctx() noexcept{ return &contexts.back(); }
+    vector<Expr*>& s_expr() noexcept{ return ctx()->s_expr; }
 
-    NameScope name_scope() const;
-    CodeObject_ push_global_context();
-    FuncDecl_ push_f_context(Str name);
-    void pop_context();
+    CompileMode mode() const noexcept{ return lexer.src->mode; }
 
-    static void init_pratt_rules();
+    NameScope name_scope() const noexcept;
+    CodeObject_ push_global_context() noexcept;
+    FuncDecl_ push_f_context(Str name) noexcept;
 
-    bool match(TokenIndex expected);
-    void consume(TokenIndex expected);
-    bool match_newlines_repl();
-
-    bool match_newlines(bool repl_throw = false);
-    bool match_end_stmt();
-    void consume_end_stmt();
+    static void init_pratt_rules() noexcept;
 
+    bool match(TokenIndex expected) noexcept;
+    bool match_newlines_repl() noexcept{ return match_newlines(mode() == REPL_MODE); }
+    bool match_newlines(bool repl_throw = false) noexcept;
+    bool match_end_stmt() noexcept;
     /*************************************************/
-    void EXPR();
-    void EXPR_TUPLE(bool allow_slice = false);
-    Expr* EXPR_VARS();  // special case for `for loop` and `comp`
+    [[nodiscard]] Error* EXPR() noexcept{ return parse_expression(PREC_LOWEST + 1); }
+    [[nodiscard]] Error* EXPR_TUPLE(bool allow_slice = false) noexcept;
+    [[nodiscard]] Error* EXPR_VARS() noexcept;  // special case for `for loop` and `comp`
 
     template <typename T, typename... Args>
-    T* make_expr(Args&&... args) {
+    T* make_expr(Args&&... args) noexcept{
         static_assert(sizeof(T) <= kPoolExprBlockSize);
         static_assert(std::is_base_of_v<Expr, T>);
         void* p = PoolExpr_alloc();
@@ -73,87 +68,63 @@ class Compiler {
         return expr;
     }
 
-    void consume_comp(CompExpr* ce, Expr* expr);
-
-    void exprLiteral();
-    void exprLong();
-    void exprImag();
-    void exprBytes();
-    void exprFString();
-    void exprLambda();
-    void exprOr();
-    void exprAnd();
-    void exprTernary();
-    void exprBinaryOp();
-    void exprNot();
-    void exprUnaryOp();
-    void exprGroup();
-    void exprList();
-    void exprMap();
-    void exprCall();
-    void exprName();
-    void exprAttrib();
-    void exprSlice0();
-    void exprSlice1();
-    void exprSubscr();
-    void exprLiteral0();
-
-    void compile_block_body(void (Compiler::*callback)() = nullptr);
-    void compile_normal_import();
-    void compile_from_import();
-    bool is_expression(bool allow_slice = false);
-    void parse_expression(int precedence, bool allow_slice = false);
-    void compile_if_stmt();
-    void compile_while_loop();
-    void compile_for_loop();
-    void compile_try_except();
-    void compile_decorated();
-
-    bool try_compile_assignment();
-    void compile_stmt();
-    void consume_type_hints();
-    void _add_decorators(const Expr_vector& decorators);
-    void compile_class(const Expr_vector& decorators = {});
-    void _compile_f_args(FuncDecl_ decl, bool enable_type_hints);
-    void compile_function(const Expr_vector& decorators = {});
-
-    PyVar to_object(const TokenValue& value);
-    PyVar read_literal();
-
-    void SyntaxError(Str msg) { lexer.throw_err("SyntaxError", msg, err().line, err().start); }
-
-    void SyntaxError() { lexer.throw_err("SyntaxError", "invalid syntax", err().line, err().start); }
-
-    void IndentationError(Str msg) { lexer.throw_err("IndentationError", msg, err().line, err().start); }
+    [[nodiscard]] Error* consume_comp(Opcode op0, Opcode op1) noexcept;
+    [[nodiscard]] Error* pop_context() noexcept;
+
+    Error* exprLiteral() noexcept;
+    Error* exprLong() noexcept;
+    Error* exprImag() noexcept;
+    Error* exprBytes() noexcept;
+    Error* exprFString() noexcept;
+    Error* exprLambda() noexcept;
+    Error* exprOr() noexcept;
+    Error* exprAnd() noexcept;
+    Error* exprTernary() noexcept;
+    Error* exprBinaryOp() noexcept;
+    Error* exprNot() noexcept;
+    Error* exprUnaryOp() noexcept;
+    Error* exprGroup() noexcept;
+    Error* exprList() noexcept;
+    Error* exprMap() noexcept;
+    Error* exprCall() noexcept;
+    Error* exprName() noexcept;
+    Error* exprAttrib() noexcept;
+    Error* exprSlice0() noexcept;
+    Error* exprSlice1() noexcept;
+    Error* exprSubscr() noexcept;
+    Error* exprLiteral0() noexcept;
+
+    bool is_expression(bool allow_slice = false) noexcept;
+
+    [[nodiscard]] Error* compile_block_body(PrattCallback callback = NULL) noexcept;
+    [[nodiscard]] Error* compile_normal_import() noexcept;
+    [[nodiscard]] Error* compile_from_import() noexcept;
+    [[nodiscard]] Error* parse_expression(int precedence, bool allow_slice = false) noexcept;
+    [[nodiscard]] Error* compile_if_stmt() noexcept;
+    [[nodiscard]] Error* compile_while_loop() noexcept;
+    [[nodiscard]] Error* compile_for_loop() noexcept;
+    [[nodiscard]] Error* compile_try_except() noexcept;
+    [[nodiscard]] Error* compile_decorated() noexcept;
+
+    [[nodiscard]] Error* try_compile_assignment(bool* is_assign) noexcept;
+    [[nodiscard]] Error* compile_stmt() noexcept;
+    [[nodiscard]] Error* consume_type_hints() noexcept;
+    [[nodiscard]] Error* _compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcept;
+    [[nodiscard]] Error* compile_function(int decorators = 0) noexcept;
+    [[nodiscard]] Error* compile_class(int decorators = 0) noexcept;
+
+    PyVar to_object(const TokenValue& value) noexcept;
+
+    [[nodiscard]] Error* read_literal(PyVar* out) noexcept;
+
+    [[nodiscard]] Error* SyntaxError(const char* msg = "invalid syntax", ...) noexcept;
+    [[nodiscard]] Error* IndentationError(const char* msg) noexcept{ return lexer._error(false, "IndentationError", msg, {}); }
+    [[nodiscard]] Error* NeedMoreLines() noexcept{ return lexer._error(false, "NeedMoreLines", "", {}, (i64)ctx()->is_compiling_class); }
 
 public:
-    Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false);
-    Str precompile();
-    void from_precompiled(const char* source);
-    CodeObject_ compile();
-};
-
-struct TokenDeserializer {
-    const char* curr;
-    const char* source;
-
-    TokenDeserializer(const char* source) : curr(source), source(source) {}
-
-    char read_char() { return *curr++; }
-
-    bool match_char(char c) {
-        if(*curr == c) {
-            curr++;
-            return true;
-        }
-        return false;
-    }
-
-    std::string_view read_string(char c);
-    Str read_string_from_hex(char c);
-    int read_count();
-    i64 read_uint(char c);
-    f64 read_float(char c);
+    Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false) noexcept;
+    [[nodiscard]] Error* compile(CodeObject_* out) noexcept;
+    ~Compiler();
 };
 
 }  // namespace pkpy

+ 25 - 41
include/pocketpy/compiler/expr.hpp

@@ -56,7 +56,7 @@ inline void delete_expr(Expr* p){
     PoolExpr_dealloc(p);
 }
 
-struct CodeEmitContext {
+struct CodeEmitContext{
     VM* vm;
     FuncDecl_ func;  // optional
     CodeObject_ co;  // 1 CodeEmitContext <=> 1 CodeObject_
@@ -72,21 +72,22 @@ struct CodeEmitContext {
     small_map<PyVar, int> _co_consts_nonstring_dedup_map;
     small_map<std::string_view, int> _co_consts_string_dedup_map;
 
-    int get_loop() const;
-    CodeBlock* enter_block(CodeBlockType type);
-    void exit_block();
-    void emit_expr(bool emit = true);  // clear the expression stack and generate bytecode
-    int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false);
-    void revert_last_emit_();
-    int emit_int(i64 value, int line);
-    void patch_jump(int index);
-    bool add_label(StrName name);
-    int add_varname(StrName name);
-    int add_const(PyVar);
-    int add_const_string(std::string_view);
-    int add_func_decl(FuncDecl_ decl);
-    void emit_store_name(NameScope scope, StrName name, int line);
-    void try_merge_for_iter_store(int);
+    int get_loop() const noexcept;
+    CodeBlock* enter_block(CodeBlockType type) noexcept;
+    void exit_block() noexcept;
+    void emit_expr(bool emit = true) noexcept;  // clear the expression stack and generate bytecode
+    void emit_decorators(int count) noexcept;
+    int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false) noexcept;
+    void revert_last_emit_() noexcept;
+    int emit_int(i64 value, int line) noexcept;
+    void patch_jump(int index) noexcept;
+    bool add_label(StrName name) noexcept;
+    int add_varname(StrName name) noexcept;
+    int add_const(PyVar) noexcept;
+    int add_const_string(std::string_view) noexcept;
+    int add_func_decl(FuncDecl_ decl) noexcept;
+    void emit_store_name(NameScope scope, StrName name, int line) noexcept;
+    void try_merge_for_iter_store(int) noexcept;
 };
 
 struct NameExpr : Expr {
@@ -236,15 +237,14 @@ struct DictItemExpr : Expr {
 };
 
 struct SequenceExpr : Expr {
-    Expr_vector items;
+    array<Expr*> items;
 
-    SequenceExpr(Expr_vector&& items) : items(std::move(items)) {}
+    SequenceExpr(int count) : items(count) {}
 
     virtual Opcode opcode() const = 0;
 
     void emit_(CodeEmitContext* ctx) override {
-        for(auto& item: items)
-            item->emit_(ctx);
+        for(auto& item: items) item->emit_(ctx);
         ctx->emit_(opcode(), items.size(), line);
     }
 
@@ -308,8 +308,10 @@ struct CompExpr : Expr {
     Expr* iter = nullptr;  // loop iter
     Expr* cond = nullptr;  // optional if condition
 
-    virtual Opcode op0() = 0;
-    virtual Opcode op1() = 0;
+    Opcode op0;
+    Opcode op1;
+
+    CompExpr(Opcode op0, Opcode op1) : op0(op0), op1(op1) {}
 
     void emit_(CodeEmitContext* ctx) override;
 
@@ -321,24 +323,6 @@ struct CompExpr : Expr {
     }
 };
 
-struct ListCompExpr : CompExpr {
-    Opcode op0() override { return OP_BUILD_LIST; }
-
-    Opcode op1() override { return OP_LIST_APPEND; }
-};
-
-struct DictCompExpr : CompExpr {
-    Opcode op0() override { return OP_BUILD_DICT; }
-
-    Opcode op1() override { return OP_DICT_ADD; }
-};
-
-struct SetCompExpr : CompExpr {
-    Opcode op0() override { return OP_BUILD_SET; }
-
-    Opcode op1() override { return OP_SET_ADD; }
-};
-
 struct LambdaExpr : Expr {
     FuncDecl_ decl;
 
@@ -391,7 +375,7 @@ struct CallExpr : Expr {
     Expr* callable;
     Expr_vector args;
     // **a will be interpreted as a special keyword argument: {"**": a}
-    vector<std::pair<StrName, Expr*>> kwargs;
+    vector<pair<StrName, Expr*>> kwargs;
     void emit_(CodeEmitContext* ctx) override;
 
     ~CallExpr() {

+ 50 - 27
include/pocketpy/compiler/lexer.hpp

@@ -92,7 +92,7 @@ enum Precedence {
     PREC_HIGHEST,
 };
 
-enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
+enum class StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
 
 struct Lexer {
     VM* vm;
@@ -104,38 +104,38 @@ struct Lexer {
     small_vector_2<int, 8> indents;
     int brackets_level = 0;
 
-    char peekchar() const { return *curr_char; }
+    char peekchar() const noexcept { return *curr_char; }
 
-    bool match_n_chars(int n, char c0);
-    bool match_string(const char* s);
-    int eat_spaces();
+    bool match_n_chars(int n, char c0) noexcept;
+    bool match_string(const char* s) noexcept;
+    int eat_spaces() noexcept;
 
-    bool eat_indentation();
-    char eatchar();
-    char eatchar_include_newline();
-    int eat_name();
-    void skip_line_comment();
-    bool matchchar(char c);
-    void add_token(TokenIndex type, TokenValue value = {});
-    void add_token_2(char c, TokenIndex one, TokenIndex two);
-    Str eat_string_until(char quote, bool raw);
-    void eat_string(char quote, StringType type);
+    bool eat_indentation() noexcept;
+    char eatchar() noexcept;
+    char eatchar_include_newline() noexcept;
+    void skip_line_comment() noexcept;
+    bool matchchar(char c) noexcept;
+    void add_token(TokenIndex type, TokenValue value = {}) noexcept;
+    void add_token_2(char c, TokenIndex one, TokenIndex two) noexcept;
 
-    void eat_number();
-    bool lex_one_token();
+    [[nodiscard]] Error* eat_name() noexcept;
+    [[nodiscard]] Error* eat_string_until(char quote, bool raw, Str* out) noexcept;
+    [[nodiscard]] Error* eat_string(char quote, StringType type) noexcept;
+    [[nodiscard]] Error* eat_number() noexcept;
+    [[nodiscard]] Error* lex_one_token(bool* eof) noexcept;
 
     /***** Error Reporter *****/
-    [[noreturn]] void throw_err(StrName type, Str msg);
-    [[noreturn]] void throw_err(StrName type, Str msg, int lineno, const char* cursor);
+    [[nodiscard]] Error* _error(bool lexer_err, const char* type, const char* msg, va_list args, i64 userdata=0) noexcept;
+    [[nodiscard]] Error* SyntaxError(const char* fmt, ...) noexcept;
+    [[nodiscard]] Error* IndentationError(const char* msg) noexcept { return _error(true, "IndentationError", msg, {}); }
+    [[nodiscard]] Error* NeedMoreLines() noexcept { return _error(true, "NeedMoreLines", "", {}, 0); }
 
-    [[noreturn]] void SyntaxError(Str msg) { throw_err("SyntaxError", msg); }
+    Lexer(VM* vm, std::shared_ptr<SourceData> src) noexcept;
+    
+    [[nodiscard]] Error* run() noexcept;
 
-    [[noreturn]] void SyntaxError() { throw_err("SyntaxError", "invalid syntax"); }
-
-    [[noreturn]] void IndentationError(Str msg) { throw_err("IndentationError", msg); }
-
-    Lexer(VM* vm, std::shared_ptr<SourceData> src);
-    vector<Token> run();
+    void from_precompiled();
+    [[nodiscard]] Error* precompile(Str* out);
 };
 
 enum class IntParsingResult {
@@ -144,6 +144,29 @@ enum class IntParsingResult {
     Overflow,
 };
 
-IntParsingResult parse_uint(std::string_view text, i64* out, int base);
+IntParsingResult parse_uint(std::string_view text, i64* out, int base) noexcept;
+
+struct TokenDeserializer {
+    const char* curr;
+    const char* source;
+
+    TokenDeserializer(const char* source) : curr(source), source(source) {}
+
+    char read_char() { return *curr++; }
+
+    bool match_char(char c) {
+        if(*curr == c) {
+            curr++;
+            return true;
+        }
+        return false;
+    }
+
+    std::string_view read_string(char c);
+    Str read_string_from_hex(char c);
+    int read_count();
+    i64 read_uint(char c);
+    f64 read_float(char c);
+};
 
 }  // namespace pkpy

+ 5 - 5
include/pocketpy/interpreter/cffi.hpp

@@ -36,11 +36,11 @@ struct VoidP {
     static void _register(VM* vm, PyObject* mod, PyObject* type);
 };
 
-#define POINTER_VAR(Tp, NAME)                                                                                          \
-    inline PyVar py_var(VM* vm, Tp val) {                                                                              \
-        const static std::pair<StrName, StrName> P("c", NAME);                                                         \
-        PyVar type = vm->_modules[P.first]->attr(P.second);                                                            \
-        return vm->new_object<VoidP>(type->as<Type>(), val);                                                           \
+#define POINTER_VAR(Tp, NAME)                                       \
+    inline PyVar py_var(VM* vm, Tp val) {                           \
+        const static pair<StrName, StrName> P("c", NAME);           \
+        PyVar type = vm->_modules[P.first]->attr(P.second);         \
+        return vm->new_object<VoidP>(type->as<Type>(), val);        \
     }
 
 POINTER_VAR(char*, "char_p")

+ 23 - 98
include/pocketpy/interpreter/vm.hpp

@@ -463,7 +463,6 @@ public:
         vm->s_data.emplace(p->type, p);
     }
 #endif
-    // clang-format on
 
     template <typename T>
     Type _find_type_in_cxx_typeid_map() {
@@ -500,31 +499,26 @@ public:
     [[noreturn]] void __builtin_error(StrName type);
     [[noreturn]] void __builtin_error(StrName type, PyVar arg);
     [[noreturn]] void __builtin_error(StrName type, const Str& msg);
+    [[noreturn]] void __compile_error(Error* err);
     void __init_builtin_types();
     void __post_init_builtin_types();
-
     void __push_varargs() {}
-
     void __push_varargs(PyVar _0) { PUSH(_0); }
-
     void __push_varargs(PyVar _0, PyVar _1) {
         PUSH(_0);
         PUSH(_1);
     }
-
     void __push_varargs(PyVar _0, PyVar _1, PyVar _2) {
         PUSH(_0);
         PUSH(_1);
         PUSH(_2);
     }
-
     void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3) {
         PUSH(_0);
         PUSH(_1);
         PUSH(_2);
         PUSH(_3);
     }
-
     PyVar __pack_next_retval(unsigned);
     PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key);
     bool __py_bool_non_trivial(PyVar);
@@ -539,95 +533,26 @@ constexpr inline bool is_immutable_v =
     std::is_same_v<T, Bytes> || std::is_same_v<T, bool> || std::is_same_v<T, Range> || std::is_same_v<T, Slice> ||
     std::is_pointer_v<T> || std::is_enum_v<T>;
 
-template <typename T>
-constexpr Type _find_type_in_const_cxx_typeid_map() {
-    return Type();
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Str>() {
-    return VM::tp_str;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<List>() {
-    return VM::tp_list;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>() {
-    return VM::tp_tuple;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Function>() {
-    return VM::tp_function;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>() {
-    return VM::tp_native_func;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>() {
-    return VM::tp_bound_method;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Range>() {
-    return VM::tp_range;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Slice>() {
-    return VM::tp_slice;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Exception>() {
-    return VM::tp_exception;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>() {
-    return VM::tp_bytes;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>() {
-    return VM::tp_mappingproxy;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Dict>() {
-    return VM::tp_dict;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<Property>() {
-    return VM::tp_property;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>() {
-    return VM::tp_star_wrapper;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>() {
-    return VM::tp_staticmethod;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>() {
-    return VM::tp_classmethod;
-}
-
-template <>
-constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>() {
-    return VM::tp_stack_memory;
-}
+template<typename T> constexpr Type _tp_builtin() { return Type(); }
+template<> constexpr Type _tp_builtin<Str>() { return VM::tp_str; }
+template<> constexpr Type _tp_builtin<List>() { return VM::tp_list; }
+template<> constexpr Type _tp_builtin<Tuple>() { return VM::tp_tuple; }
+template<> constexpr Type _tp_builtin<Function>() { return VM::tp_function; }
+template<> constexpr Type _tp_builtin<NativeFunc>() { return VM::tp_native_func; }
+template<> constexpr Type _tp_builtin<BoundMethod>() { return VM::tp_bound_method; }
+template<> constexpr Type _tp_builtin<Range>() { return VM::tp_range; }
+template<> constexpr Type _tp_builtin<Slice>() { return VM::tp_slice; }
+template<> constexpr Type _tp_builtin<Exception>() { return VM::tp_exception; }
+template<> constexpr Type _tp_builtin<Bytes>() { return VM::tp_bytes; }
+template<> constexpr Type _tp_builtin<MappingProxy>() { return VM::tp_mappingproxy; }
+template<> constexpr Type _tp_builtin<Dict>() { return VM::tp_dict; }
+template<> constexpr Type _tp_builtin<Property>() { return VM::tp_property; }
+template<> constexpr Type _tp_builtin<StarWrapper>() { return VM::tp_star_wrapper; }
+template<> constexpr Type _tp_builtin<StaticMethod>() { return VM::tp_staticmethod; }
+template<> constexpr Type _tp_builtin<ClassMethod>() { return VM::tp_classmethod; }
+template<> constexpr Type _tp_builtin<StackMemory>() { return VM::tp_stack_memory; }
+
+// clang-format on
 
 template <typename __T>
 PyVar py_var(VM* vm, __T&& value) {
@@ -654,7 +579,7 @@ PyVar py_var(VM* vm, __T&& value) {
     } else if constexpr(std::is_pointer_v<T>) {
         return from_void_p(vm, (void*)value);
     } else {
-        constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
+        constexpr Type const_type = _tp_builtin<T>();
         if constexpr((bool)const_type) {
             if constexpr(is_sso_v<T>)
                 return PyVar(const_type, value);
@@ -715,7 +640,7 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
         static_assert(!std::is_reference_v<__T>);
         return to_void_p<T>(vm, obj);
     } else {
-        constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
+        constexpr Type const_type = _tp_builtin<T>();
         if constexpr((bool)const_type) {
             if constexpr(with_check) {
                 if constexpr(std::is_same_v<T, Exception>) {

+ 11 - 2
include/pocketpy/objects/error.hpp

@@ -33,14 +33,14 @@ struct Exception {
     PyObject* _self;  // weak reference
 
     struct Frame {
-        std::shared_ptr<SourceData> src;
+        SourceData* src;        // weak ref
         int lineno;
         const char* cursor;
         std::string name;
 
         Str snapshot() const { return src->snapshot(lineno, cursor, name); }
 
-        Frame(std::shared_ptr<SourceData> src, int lineno, const char* cursor, std::string_view name) :
+        Frame(SourceData* src, int lineno, const char* cursor, std::string_view name) :
             src(src), lineno(lineno), cursor(cursor), name(name) {}
     };
 
@@ -77,4 +77,13 @@ struct TopLevelException : std::exception {
     }
 };
 
+struct Error{
+    const char* type;
+    SourceData* src;
+    int lineno;
+    const char* cursor;
+    char msg[100];
+    i64 userdata;
+};
+
 }  // namespace pkpy

+ 2 - 2
include/pocketpy/objects/namedict.hpp

@@ -10,9 +10,9 @@ namespace pkpy {
 struct NameDict {
     PK_ALWAYS_PASS_BY_POINTER(NameDict)
 
-    using Item = std::pair<StrName, PyVar>;
+    using Item = pair<StrName, PyVar>;
+
     constexpr static uint16_t kInitialCapacity = 16;
-    static_assert(is_pod_v<PyVar>);
 
     float _load_factor;
     uint16_t _size;

+ 1 - 1
include/pocketpy/objects/sourcedata.hpp

@@ -21,7 +21,7 @@ struct SourceData {
 
     SourceData(std::string_view source, const Str& filename, CompileMode mode);
     SourceData(const Str& filename, CompileMode mode);
-    std::pair<const char*, const char*> _get_line(int lineno) const;
+    pair<const char*, const char*> _get_line(int lineno) const;
     std::string_view get_line(int lineno) const;
     Str snapshot(int lineno, const char* cursor, std::string_view name) const;
 };

+ 1 - 1
src/common/str.cpp

@@ -52,7 +52,7 @@ Str::Str(int size, bool is_ascii) :
     Str::Str(const char* s, int len) :
     size(len), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
 
-    Str::Str(std::pair<char*, int> detached) : size(detached.second), is_ascii(true) {
+    Str::Str(pair<char*, int> detached) : size(detached.second), is_ascii(true) {
     this->data = detached.first;
     for(int i = 0; i < size; i++) {
         if(!isascii(data[i])) {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 349 - 248
src/compiler/compiler.cpp


+ 33 - 20
src/compiler/expr.cpp

@@ -13,7 +13,7 @@ inline bool is_identifier(std::string_view s) {
 
 inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT16_MAX; }
 
-int CodeEmitContext::get_loop() const {
+int CodeEmitContext::get_loop() const noexcept{
     int index = curr_iblock;
     while(index >= 0) {
         if(co->blocks[index].type == CodeBlockType::FOR_LOOP) break;
@@ -23,13 +23,13 @@ int CodeEmitContext::get_loop() const {
     return index;
 }
 
-CodeBlock* CodeEmitContext::enter_block(CodeBlockType type) {
+CodeBlock* CodeEmitContext::enter_block(CodeBlockType type) noexcept{
     co->blocks.push_back(CodeBlock(type, curr_iblock, (int)co->codes.size()));
     curr_iblock = co->blocks.size() - 1;
     return &co->blocks[curr_iblock];
 }
 
-void CodeEmitContext::exit_block() {
+void CodeEmitContext::exit_block() noexcept{
     auto curr_type = co->blocks[curr_iblock].type;
     co->blocks[curr_iblock].end = co->codes.size();
     curr_iblock = co->blocks[curr_iblock].parent;
@@ -41,14 +41,27 @@ void CodeEmitContext::exit_block() {
 }
 
 // clear the expression stack and generate bytecode
-void CodeEmitContext::emit_expr(bool emit) {
-    assert(s_expr.size() == 1);
+void CodeEmitContext::emit_expr(bool emit) noexcept{
+    // assert(s_expr.size() == 1);
     Expr* e = s_expr.popx_back();
     if(emit) e->emit_(this);
     delete_expr(e);
 }
 
-int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) {
+void CodeEmitContext::emit_decorators(int count) noexcept{
+    // [obj]
+    for(int i=0; i<count; i++) {
+        Expr* deco = s_expr.popx_back();
+        deco->emit_(this);                           // [obj, f]
+        emit_(OP_ROT_TWO, BC_NOARG, deco->line);     // [f, obj]
+        emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);  // [f, obj, NULL]
+        emit_(OP_ROT_TWO, BC_NOARG, BC_KEEPLINE);    // [obj, NULL, f]
+        emit_(OP_CALL, 1, deco->line);               // [obj]
+        delete_expr(deco);
+    }
+}
+
+int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) noexcept{
     co->codes.push_back(Bytecode{(uint8_t)opcode, arg});
     co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
     int i = co->codes.size() - 1;
@@ -61,12 +74,12 @@ int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtua
     return i;
 }
 
-void CodeEmitContext::revert_last_emit_() {
+void CodeEmitContext::revert_last_emit_() noexcept{
     co->codes.pop_back();
     co->lines.pop_back();
 }
 
-void CodeEmitContext::try_merge_for_iter_store(int i) {
+void CodeEmitContext::try_merge_for_iter_store(int i) noexcept{
     // [FOR_ITER, STORE_?, ]
     if(co->codes[i].op != OP_FOR_ITER) return;
     if(co->codes.size() - i != 2) return;
@@ -85,7 +98,7 @@ void CodeEmitContext::try_merge_for_iter_store(int i) {
     }
 }
 
-int CodeEmitContext::emit_int(i64 value, int line) {
+int CodeEmitContext::emit_int(i64 value, int line) noexcept{
     if(is_small_int(value)) {
         return emit_(OP_LOAD_SMALL_INT, (uint16_t)value, line);
     } else {
@@ -93,18 +106,18 @@ int CodeEmitContext::emit_int(i64 value, int line) {
     }
 }
 
-void CodeEmitContext::patch_jump(int index) {
+void CodeEmitContext::patch_jump(int index) noexcept{
     int target = co->codes.size();
     co->codes[index].set_signed_arg(target - index);
 }
 
-bool CodeEmitContext::add_label(StrName name) {
+bool CodeEmitContext::add_label(StrName name) noexcept{
     if(co->labels.contains(name)) return false;
     co->labels.insert(name, co->codes.size());
     return true;
 }
 
-int CodeEmitContext::add_varname(StrName name) {
+int CodeEmitContext::add_varname(StrName name) noexcept{
     // PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
     int index = co->varnames_inv.get(name, -1);
     if(index >= 0) return index;
@@ -115,7 +128,7 @@ int CodeEmitContext::add_varname(StrName name) {
     return index;
 }
 
-int CodeEmitContext::add_const_string(std::string_view key) {
+int CodeEmitContext::add_const_string(std::string_view key) noexcept{
     int* val = _co_consts_string_dedup_map.try_get(key);
     if(val) {
         return *val;
@@ -128,7 +141,7 @@ int CodeEmitContext::add_const_string(std::string_view key) {
     }
 }
 
-int CodeEmitContext::add_const(PyVar v) {
+int CodeEmitContext::add_const(PyVar v) noexcept{
     assert(!is_type(v, VM::tp_str));
     // non-string deduplication
     int* val = _co_consts_nonstring_dedup_map.try_get(v);
@@ -142,12 +155,12 @@ int CodeEmitContext::add_const(PyVar v) {
     }
 }
 
-int CodeEmitContext::add_func_decl(FuncDecl_ decl) {
+int CodeEmitContext::add_func_decl(FuncDecl_ decl) noexcept{
     co->func_decls.push_back(decl);
     return co->func_decls.size() - 1;
 }
 
-void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) {
+void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) noexcept{
     switch(scope) {
         case NAME_LOCAL: emit_(OP_STORE_FAST, add_varname(name), line); break;
         case NAME_GLOBAL: emit_(OP_STORE_GLOBAL, StrName(name).index, line); break;
@@ -321,8 +334,8 @@ void DictItemExpr::emit_(CodeEmitContext* ctx) {
         assert(key == nullptr);
         value->emit_(ctx);
     } else {
+        key->emit_(ctx);
         value->emit_(ctx);
-        key->emit_(ctx);  // reverse order
         ctx->emit_(OP_BUILD_TUPLE, 2, line);
     }
 }
@@ -378,7 +391,7 @@ bool TupleExpr::emit_del(CodeEmitContext* ctx) {
 }
 
 void CompExpr::emit_(CodeEmitContext* ctx) {
-    ctx->emit_(op0(), 0, line);
+    ctx->emit_(op0, 0, line);
     iter->emit_(ctx);
     ctx->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
     ctx->enter_block(CodeBlockType::FOR_LOOP);
@@ -392,11 +405,11 @@ void CompExpr::emit_(CodeEmitContext* ctx) {
         cond->emit_(ctx);
         int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
         expr->emit_(ctx);
-        ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
+        ctx->emit_(op1, BC_NOARG, BC_KEEPLINE);
         ctx->patch_jump(patch);
     } else {
         expr->emit_(ctx);
-        ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
+        ctx->emit_(op1, BC_NOARG, BC_KEEPLINE);
     }
     ctx->emit_(OP_LOOP_CONTINUE, curr_iblock, BC_KEEPLINE);
     ctx->exit_block();

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2 - 0
src/compiler/lexer.cpp


+ 1 - 1
src/interpreter/vm.cpp

@@ -1455,7 +1455,7 @@ void VM::__raise_exc(bool re_raise) {
     int current_line = frame->co->lines[actual_ip].lineno;  // current line
     auto current_f_name = frame->co->name.sv();             // current function name
     if(frame->_callable == nullptr) current_f_name = "";    // not in a function
-    e.st_push(frame->co->src, current_line, nullptr, current_f_name);
+    e.st_push(frame->co->src.get(), current_line, nullptr, current_f_name);
 
     if(next_ip >= 0) {
         throw InternalException(InternalExceptionType::Handled, next_ip);

+ 2 - 2
src/objects/sourcedata.cpp

@@ -25,7 +25,7 @@ SourceData::SourceData(const Str& filename, CompileMode mode) : filename(filenam
     line_starts.push_back(this->source.c_str());
 }
 
-std::pair<const char*, const char*> SourceData::_get_line(int lineno) const {
+pair<const char*, const char*> SourceData::_get_line(int lineno) const {
     if(is_precompiled || lineno == -1) return {nullptr, nullptr};
     lineno -= 1;
     if(lineno < 0) lineno = 0;
@@ -49,7 +49,7 @@ Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name)
     if(!name.empty()) ss << ", in " << name;
     if(!is_precompiled) {
         ss << '\n';
-        std::pair<const char*, const char*> pair = _get_line(lineno);
+        pair<const char*, const char*> pair = _get_line(lineno);
         Str line = "<?>";
         int removed_spaces = 0;
         if(pair.first && pair.second) {

+ 19 - 12
src/pocketpy.cpp

@@ -1723,22 +1723,29 @@ void VM::__post_init_builtin_types() {
 
 CodeObject_ VM::compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) {
     Compiler compiler(this, source, filename, mode, unknown_global_scope);
-    try {
-        return compiler.compile();
-    } catch(TopLevelException e) {
-        _error(e.ptr->self());
-        return nullptr;
-    }
+    CodeObject_ code;
+    Error* err = compiler.compile(&code);
+    if(err) __compile_error(err);
+    return code;
+}
+
+void VM::__compile_error(Error* err){
+    assert(err != nullptr);
+    __last_exception = vm->call(
+        vm->builtins->attr(err->type),
+        VAR((const char*)err->msg)
+    ).get();
+    Exception& e = __last_exception->as<Exception>();
+    e.st_push(err->src, err->lineno, err->cursor, "");
+    _error(__last_exception);
 }
 
 Str VM::precompile(std::string_view source, const Str& filename, CompileMode mode) {
     Compiler compiler(this, source, filename, mode, false);
-    try {
-        return compiler.precompile();
-    } catch(TopLevelException e) {
-        _error(e.ptr->self());
-        return nullptr;
-    }
+    Str out;
+    Error* err = compiler.lexer.precompile(&out);
+    if(err) __compile_error(err);
+    return out;
 }
 
 }  // namespace pkpy

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio