codeobject.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #pragma once
  2. #include "obj.h"
  3. #include "error.h"
  4. #include "any.h"
  5. namespace pkpy{
  6. enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
  7. enum Opcode: uint8_t {
  8. #define OPCODE(name) OP_##name,
  9. #include "opcodes.h"
  10. #undef OPCODE
  11. };
  12. struct Bytecode{
  13. uint8_t op;
  14. uint16_t arg;
  15. void set_signed_arg(int arg){
  16. if(arg < INT16_MIN || arg > INT16_MAX) throw std::runtime_error("byte.arg overflow");
  17. this->arg = (int16_t)arg;
  18. }
  19. bool is_forward_jump() const{
  20. return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK;
  21. }
  22. };
  23. enum class CodeBlockType {
  24. NO_BLOCK,
  25. FOR_LOOP,
  26. WHILE_LOOP,
  27. CONTEXT_MANAGER,
  28. TRY_EXCEPT,
  29. };
  30. inline const uint8_t BC_NOARG = 0;
  31. inline const int BC_KEEPLINE = -1;
  32. struct CodeBlock {
  33. CodeBlockType type;
  34. int parent; // parent index in blocks
  35. int base_stack_size; // this is used for exception handling
  36. int start; // start index of this block in codes, inclusive
  37. int end; // end index of this block in codes, exclusive
  38. int end2; // ...
  39. CodeBlock(CodeBlockType type, int parent, int base_stack_size, int start):
  40. type(type), parent(parent), base_stack_size(base_stack_size), start(start), end(-1), end2(-1) {}
  41. int get_break_end() const{
  42. if(end2 != -1) return end2;
  43. return end;
  44. }
  45. };
  46. struct CodeObject;
  47. struct FuncDecl;
  48. using CodeObject_ = std::shared_ptr<CodeObject>;
  49. using FuncDecl_ = std::shared_ptr<FuncDecl>;
  50. struct CodeObject {
  51. struct LineInfo{
  52. int lineno; // line number for each bytecode
  53. bool is_virtual; // whether this bytecode is virtual (not in source code)
  54. int iblock; // block index
  55. };
  56. std::shared_ptr<SourceData> src;
  57. Str name;
  58. std::vector<Bytecode> codes;
  59. std::vector<LineInfo> lines;
  60. small_vector_2<PyVar, 8> consts; // constants
  61. small_vector_2<StrName, 8> varnames; // local variables
  62. int nlocals; // varnames.size()
  63. NameDictInt varnames_inv;
  64. std::vector<CodeBlock> blocks;
  65. NameDictInt labels;
  66. std::vector<FuncDecl_> func_decls;
  67. int start_line;
  68. int end_line;
  69. const CodeBlock& _get_block_codei(int codei) const{
  70. return blocks[lines[codei].iblock];
  71. }
  72. CodeObject(std::shared_ptr<SourceData> src, const Str& name);
  73. void _gc_mark(VM*) const;
  74. };
  75. enum class FuncType{
  76. UNSET,
  77. NORMAL,
  78. SIMPLE,
  79. EMPTY,
  80. GENERATOR,
  81. };
  82. struct FuncDecl {
  83. struct KwArg {
  84. int index; // index in co->varnames
  85. StrName key; // name of this argument
  86. PyVar value; // default value
  87. };
  88. CodeObject_ code; // code object of this function
  89. small_vector_2<int, 6> args; // indices in co->varnames
  90. small_vector_2<KwArg, 6> kwargs; // indices in co->varnames
  91. int starred_arg = -1; // index in co->varnames, -1 if no *arg
  92. int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
  93. bool nested = false; // whether this function is nested
  94. const char* docstring; // docstring of this function (weak ref)
  95. FuncType type = FuncType::UNSET;
  96. NameDictInt kw_to_index;
  97. void add_kwarg(int index, StrName key, PyVar value){
  98. kw_to_index.set(key, index);
  99. kwargs.push_back(KwArg{index, key, value});
  100. }
  101. void _gc_mark(VM*) const;
  102. };
  103. struct NativeFunc {
  104. NativeFuncC f;
  105. int argc; // old style argc-based call
  106. FuncDecl_ decl; // new style decl-based call
  107. any _userdata;
  108. NativeFunc(NativeFuncC f, int argc, any userdata={}): f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
  109. NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata={}): f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
  110. PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
  111. void check_size(VM* vm, ArgsView args) const;
  112. void _gc_mark(VM*) const;
  113. };
  114. struct Function{
  115. FuncDecl_ decl;
  116. PyVar _module; // weak ref
  117. PyVar _class; // weak ref
  118. NameDict_ _closure;
  119. explicit Function(FuncDecl_ decl, PyVar _module, PyVar _class, NameDict_ _closure):
  120. decl(decl), _module(_module), _class(_class), _closure(_closure) {}
  121. void _gc_mark(VM*) const;
  122. };
  123. template<typename T>
  124. T& lambda_get_userdata(PyVar* p){
  125. static_assert(std::is_same_v<T, std::decay_t<T>>);
  126. int offset = p[-1] != PY_NULL ? -1 : -2;
  127. return PK_OBJ_GET(NativeFunc, p[offset])._userdata.cast<T>();
  128. }
  129. } // namespace pkpy