/src/ruby/prism_compile.h
Line | Count | Source |
1 | | #include "prism/prism.h" |
2 | | #include "ruby/encoding.h" |
3 | | |
4 | | /** |
5 | | * the getlocal and setlocal instructions require two parameters. level is how |
6 | | * many hops up the iseq stack one needs to go before finding the correct local |
7 | | * table. The index is the index in that table where our variable is. |
8 | | * |
9 | | * Because these are always calculated and used together, we'll bind them |
10 | | * together as a tuple. |
11 | | */ |
12 | | typedef struct pm_local_index_struct { |
13 | | int index, level; |
14 | | } pm_local_index_t; |
15 | | |
16 | | // A declaration for the struct that lives in compile.c. |
17 | | struct iseq_link_anchor; |
18 | | |
19 | | /** |
20 | | * A direct-indexed lookup table mapping constant IDs to local variable indices. |
21 | | * Regular constant IDs (1..constants_size) index directly. Special forwarding |
22 | | * parameter IDs (idMULT|FLAG, etc.) are mapped to 4 extra slots at the end. |
23 | | * |
24 | | * All lookups are O(1) — a single array dereference. |
25 | | * The table is arena-allocated for child scopes (no explicit free needed). |
26 | | */ |
27 | | typedef struct { |
28 | | /** Array of local indices, indexed by constant_id. -1 means not present. */ |
29 | | int *values; |
30 | | |
31 | | /** Total number of slots (constants_size + PM_INDEX_LOOKUP_SPECIALS). */ |
32 | | int capacity; |
33 | | |
34 | | /** Whether the values array is heap-allocated and needs explicit free. */ |
35 | | bool owned; |
36 | | } pm_index_lookup_table_t; |
37 | | |
38 | | /** Number of extra slots for special forwarding parameter IDs. */ |
39 | 0 | #define PM_INDEX_LOOKUP_SPECIALS 4 |
40 | | |
41 | | /** Slot offsets for special forwarding parameters (relative to constants_size). */ |
42 | 0 | #define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t) (1 << 31)) |
43 | 0 | #define PM_INDEX_LOOKUP_SPECIAL_MULT 0 |
44 | 0 | #define PM_INDEX_LOOKUP_SPECIAL_POW 1 |
45 | 0 | #define PM_INDEX_LOOKUP_SPECIAL_AND 2 |
46 | 0 | #define PM_INDEX_LOOKUP_SPECIAL_DOT3 3 |
47 | | |
48 | | /** |
49 | | * Special constant IDs for forwarding parameters. These use bit 31 to |
50 | | * distinguish them from regular prism constant pool IDs. The lower bits |
51 | | * encode which special slot (0-3) they map to in the lookup table. |
52 | | */ |
53 | 0 | #define PM_CONSTANT_MULT ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_MULT)) |
54 | 0 | #define PM_CONSTANT_POW ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_POW)) |
55 | 0 | #define PM_CONSTANT_AND ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_AND)) |
56 | 0 | #define PM_CONSTANT_DOT3 ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_DOT3)) |
57 | | |
58 | | static inline int |
59 | | pm_index_lookup_table_index(const pm_index_lookup_table_t *table, pm_constant_id_t key) |
60 | 0 | { |
61 | 0 | if (LIKELY(!(key & PM_SPECIAL_CONSTANT_FLAG))) { |
62 | 0 | return (int) key - 1; |
63 | 0 | } |
64 | 0 | return table->capacity - PM_INDEX_LOOKUP_SPECIALS + (int)(key & ~PM_SPECIAL_CONSTANT_FLAG); |
65 | 0 | } Unexecuted instantiation: eval.c:pm_index_lookup_table_index Unexecuted instantiation: gc.c:pm_index_lookup_table_index Unexecuted instantiation: hash.c:pm_index_lookup_table_index Unexecuted instantiation: iseq.c:pm_index_lookup_table_index Unexecuted instantiation: load.c:pm_index_lookup_table_index Unexecuted instantiation: proc.c:pm_index_lookup_table_index Unexecuted instantiation: ruby.c:pm_index_lookup_table_index Unexecuted instantiation: thread.c:pm_index_lookup_table_index Unexecuted instantiation: vm.c:pm_index_lookup_table_index Unexecuted instantiation: vm_backtrace.c:pm_index_lookup_table_index Unexecuted instantiation: vm_dump.c:pm_index_lookup_table_index Unexecuted instantiation: vm_trace.c:pm_index_lookup_table_index Unexecuted instantiation: builtin.c:pm_index_lookup_table_index Unexecuted instantiation: ast.c:pm_index_lookup_table_index Unexecuted instantiation: box.c:pm_index_lookup_table_index Unexecuted instantiation: compile.c:pm_index_lookup_table_index Unexecuted instantiation: cont.c:pm_index_lookup_table_index |
66 | | |
67 | | static inline void |
68 | | pm_index_lookup_table_insert(pm_index_lookup_table_t *table, pm_constant_id_t key, int value) |
69 | 0 | { |
70 | 0 | int idx = pm_index_lookup_table_index(table, key); |
71 | 0 | RUBY_ASSERT(idx >= 0 && idx < table->capacity); |
72 | 0 | table->values[idx] = value; |
73 | 0 | } Unexecuted instantiation: eval.c:pm_index_lookup_table_insert Unexecuted instantiation: gc.c:pm_index_lookup_table_insert Unexecuted instantiation: hash.c:pm_index_lookup_table_insert Unexecuted instantiation: iseq.c:pm_index_lookup_table_insert Unexecuted instantiation: load.c:pm_index_lookup_table_insert Unexecuted instantiation: proc.c:pm_index_lookup_table_insert Unexecuted instantiation: ruby.c:pm_index_lookup_table_insert Unexecuted instantiation: thread.c:pm_index_lookup_table_insert Unexecuted instantiation: vm.c:pm_index_lookup_table_insert Unexecuted instantiation: vm_backtrace.c:pm_index_lookup_table_insert Unexecuted instantiation: vm_dump.c:pm_index_lookup_table_insert Unexecuted instantiation: vm_trace.c:pm_index_lookup_table_insert Unexecuted instantiation: builtin.c:pm_index_lookup_table_insert Unexecuted instantiation: ast.c:pm_index_lookup_table_insert Unexecuted instantiation: box.c:pm_index_lookup_table_insert Unexecuted instantiation: compile.c:pm_index_lookup_table_insert Unexecuted instantiation: cont.c:pm_index_lookup_table_insert |
74 | | |
75 | | static inline int |
76 | | pm_index_lookup_table_lookup(const pm_index_lookup_table_t *table, pm_constant_id_t key, int *value) |
77 | 0 | { |
78 | 0 | int idx = pm_index_lookup_table_index(table, key); |
79 | 0 | RUBY_ASSERT(idx >= 0 && idx < table->capacity); |
80 | 0 | if (table->values[idx] == -1) return 0; |
81 | 0 | *value = table->values[idx]; |
82 | 0 | return 1; |
83 | 0 | } Unexecuted instantiation: eval.c:pm_index_lookup_table_lookup Unexecuted instantiation: gc.c:pm_index_lookup_table_lookup Unexecuted instantiation: hash.c:pm_index_lookup_table_lookup Unexecuted instantiation: iseq.c:pm_index_lookup_table_lookup Unexecuted instantiation: load.c:pm_index_lookup_table_lookup Unexecuted instantiation: proc.c:pm_index_lookup_table_lookup Unexecuted instantiation: ruby.c:pm_index_lookup_table_lookup Unexecuted instantiation: thread.c:pm_index_lookup_table_lookup Unexecuted instantiation: vm.c:pm_index_lookup_table_lookup Unexecuted instantiation: vm_backtrace.c:pm_index_lookup_table_lookup Unexecuted instantiation: vm_dump.c:pm_index_lookup_table_lookup Unexecuted instantiation: vm_trace.c:pm_index_lookup_table_lookup Unexecuted instantiation: builtin.c:pm_index_lookup_table_lookup Unexecuted instantiation: ast.c:pm_index_lookup_table_lookup Unexecuted instantiation: box.c:pm_index_lookup_table_lookup Unexecuted instantiation: compile.c:pm_index_lookup_table_lookup Unexecuted instantiation: cont.c:pm_index_lookup_table_lookup |
84 | | |
85 | | static inline void |
86 | | pm_index_lookup_table_init_heap(pm_index_lookup_table_t *table, int constants_size) |
87 | 0 | { |
88 | 0 | int cap = constants_size + PM_INDEX_LOOKUP_SPECIALS; |
89 | 0 | table->values = (int *) ruby_xmalloc(cap * sizeof(int)); |
90 | 0 | memset(table->values, -1, cap * sizeof(int)); |
91 | 0 | table->capacity = cap; |
92 | | table->owned = true; |
93 | 0 | } Unexecuted instantiation: eval.c:pm_index_lookup_table_init_heap Unexecuted instantiation: gc.c:pm_index_lookup_table_init_heap Unexecuted instantiation: hash.c:pm_index_lookup_table_init_heap Unexecuted instantiation: iseq.c:pm_index_lookup_table_init_heap Unexecuted instantiation: load.c:pm_index_lookup_table_init_heap Unexecuted instantiation: proc.c:pm_index_lookup_table_init_heap Unexecuted instantiation: ruby.c:pm_index_lookup_table_init_heap Unexecuted instantiation: thread.c:pm_index_lookup_table_init_heap Unexecuted instantiation: vm.c:pm_index_lookup_table_init_heap Unexecuted instantiation: vm_backtrace.c:pm_index_lookup_table_init_heap Unexecuted instantiation: vm_dump.c:pm_index_lookup_table_init_heap Unexecuted instantiation: vm_trace.c:pm_index_lookup_table_init_heap Unexecuted instantiation: builtin.c:pm_index_lookup_table_init_heap Unexecuted instantiation: ast.c:pm_index_lookup_table_init_heap Unexecuted instantiation: box.c:pm_index_lookup_table_init_heap Unexecuted instantiation: compile.c:pm_index_lookup_table_init_heap Unexecuted instantiation: cont.c:pm_index_lookup_table_init_heap |
94 | | |
95 | | // ScopeNodes are helper nodes, and will never be part of the AST. We manually |
96 | | // declare them here to avoid generating them. |
97 | | typedef struct pm_scope_node { |
98 | | pm_node_t base; |
99 | | struct pm_scope_node *previous; |
100 | | pm_node_t *ast_node; |
101 | | pm_node_t *parameters; |
102 | | pm_node_t *body; |
103 | | pm_constant_id_list_t locals; |
104 | | |
105 | | const pm_parser_t *parser; |
106 | | const pm_options_t *options; |
107 | | const pm_line_offset_list_t *line_offsets; |
108 | | int32_t start_line; |
109 | | rb_encoding *encoding; |
110 | | |
111 | | /** |
112 | | * This is a pointer to the list of script lines for the ISEQs that will be |
113 | | * associated with this scope node. It is only set if |
114 | | * RubyVM.keep_script_lines is true. If it is set, it will be set to a |
115 | | * pointer to an array that is always stack allocated (so no GC marking is |
116 | | * needed by this struct). If it is not set, it will be NULL. It is |
117 | | * inherited by all child scopes. |
118 | | */ |
119 | | VALUE *script_lines; |
120 | | |
121 | | /** |
122 | | * This is the encoding of the actual filepath object that will be used when |
123 | | * a __FILE__ node is compiled or when the path has to be set on a syntax |
124 | | * error. |
125 | | */ |
126 | | rb_encoding *filepath_encoding; |
127 | | |
128 | | // The size of the local table on the iseq which includes locals and hidden |
129 | | // variables. |
130 | | int local_table_for_iseq_size; |
131 | | |
132 | | ID *constants; |
133 | | |
134 | | /** |
135 | | * A flat lookup table mapping constant IDs (or special IDs) to local |
136 | | * variable indices. When allocated from the compile data arena (child |
137 | | * scopes), no explicit free is needed. When heap-allocated (top-level |
138 | | * scope in pm_parse_process), owned is set to true so destroy can free it. |
139 | | */ |
140 | | pm_index_lookup_table_t index_lookup_table; |
141 | | |
142 | | // The current coverage setting, passed down through the various scopes. |
143 | | int coverage_enabled; |
144 | | |
145 | | /** |
146 | | * This will only be set on the top-level scope node. It will contain all of |
147 | | * the instructions pertaining to BEGIN{} nodes. |
148 | | */ |
149 | | struct iseq_link_anchor *pre_execution_anchor; |
150 | | |
151 | | /** |
152 | | * Cached line hint for line offset list lookups. Since the compiler walks |
153 | | * the AST roughly in source order, consecutive lookups tend to be for |
154 | | * nearby byte offsets. This avoids repeated binary searches. |
155 | | */ |
156 | | size_t last_line; |
157 | | } pm_scope_node_t; |
158 | | |
159 | | void pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous); |
160 | | void pm_scope_node_destroy(pm_scope_node_t *scope_node); |
161 | | |
162 | | typedef struct { |
163 | | /** The arena allocator for AST-lifetime memory. */ |
164 | | pm_arena_t *arena; |
165 | | |
166 | | /** The parser that will do the actual parsing. */ |
167 | | pm_parser_t *parser; |
168 | | |
169 | | /** The options that will be passed to the parser. */ |
170 | | pm_options_t *options; |
171 | | |
172 | | /** The source backing the parse (file, string, or stream). */ |
173 | | pm_source_t *source; |
174 | | |
175 | | /** The resulting scope node that will hold the generated AST. */ |
176 | | pm_scope_node_t node; |
177 | | |
178 | | /** Whether or not this parse result has performed its parsing yet. */ |
179 | | bool parsed; |
180 | | } pm_parse_result_t; |
181 | | |
182 | | void pm_parse_result_init(pm_parse_result_t *result); |
183 | | VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error); |
184 | | VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines); |
185 | | VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines); |
186 | | VALUE pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *script_lines); |
187 | | VALUE pm_parse_stdin(pm_parse_result_t *result); |
188 | | void pm_options_version_for_current_ruby_set(pm_options_t *options); |
189 | | void pm_parse_result_free(pm_parse_result_t *result); |
190 | | |
191 | | rb_iseq_t *pm_iseq_new(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum rb_iseq_type, int *error_state); |
192 | | rb_iseq_t *pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, int *error_state); |
193 | | rb_iseq_t *pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state); |
194 | | rb_iseq_t *pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, int *error_state); |
195 | | rb_iseq_t *pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t *option, int *error_state); |
196 | | rb_iseq_t *pm_iseq_build(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t *option); |
197 | | |
198 | | VALUE pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node); |