2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 private unit compiler.parser.dict;
23 uses compiler.parser.istring;
24 uses compiler.parser.token;
27 fn unimplemented(m : bytes) : unit_type;
29 const T_NoLocalType : int := T_InvalidType;
31 record variable_dictionary [
36 gvn_backup : list(int);
37 next : maybe(variable_dictionary);
38 parent : maybe(variable_dictionary);
41 record local_variable [
49 const defined_argument : int := 0;
50 const defined_multiple : int := -1;
62 record module_unique_id [
64 unit_string : istring;
68 record function_unique_id [
70 unit_string : istring;
72 function_index : list(int);
75 implicit fn instance_eq_function_unique_id~inline : class_eq(function_unique_id);
77 type function_dictionary;
86 const op_name : bytes := "{";
87 const op_prefix_name : bytes := "}";
92 accessing_other : bool;
95 record record_definition [
97 is_flat_option : bool;
98 entries : list(record_entry);
102 type function_definition;
104 record function_context [
106 n_return_values : int;
107 variables : list(local_variable);
108 instructions : list(instruction);
110 lambdas : list(function_definition);
115 defined_labels : list(bool);
116 used_labels : list(int);
117 list_of_used_labels : list(istring);
120 inferred_return : bool;
126 record_def : maybe(record_definition);
128 local_types : list(local_type);
129 local_types_map : list(int);
131 dict : function_dictionary;
132 id : function_unique_id;
134 parent_function : maybe(function_context);
142 record function_definition [
143 signature : function_context;
144 body : maybe(function_context);
145 vd : variable_dictionary;
148 op_bypass_reverse : bool;
151 pcode : list(pcode_t);
154 type macro := tokens;
156 record function_dictionary [
157 defs : list(function_definition);
159 macros : list(macro);
160 id : module_unique_id;
165 modules : list(function_dictionary);
166 modules_map : list(int);
169 fn new_variable_dictionary(parent : maybe(variable_dictionary)) : variable_dictionary;
170 fn new_variable_dictionary_chained(ctx : function_context, v : variable_dictionary) : variable_dictionary;
171 fn free_variable_dictionary_chained(ctx : function_context, v : variable_dictionary) : function_context;
172 fn new_variable(ctx : function_context, t def_at : int, mut : bool) : (function_context, local_variable);
173 fn set_variable_type(ctx : function_context, idx typ : int) : function_context;
174 fn add_variable(ctx : function_context, vd : variable_dictionary, name : istring, idx : int, impl : bool, t : tokens) : (function_context, variable_dictionary);
175 fn search_variable_dictionary(vd : variable_dictionary, name : istring) : int;
176 fn search_break(vd : variable_dictionary) : int;
177 fn search_continue(vd : variable_dictionary) : int;
178 fn get_implicit_variables(vd : variable_dictionary) : list(int);
180 fn new_function_dictionary(path_index : int, unit_string : istring, program : bool) : function_dictionary;
181 fn new_function_context(dict : function_dictionary, parent_function : maybe(function_context), n_arguments n_return_values : int, name : istring) : function_context;
182 fn function_context_is_privileged(ctx : function_context) : bool;
183 fn function_context_clear_temp_values(ctx : function_context) : function_context;
184 fn add_function(dict : function_dictionary, name : istring, ctx : function_context, vd : variable_dictionary, call_mode : int, op_bypass : int, op_bypass_reverse : bool, private_flag implicit_flag conversion_flag : bool) : (function_dictionary, function_definition);
185 fn add_lambda(ctx ctx_head ctx_body : function_context, call_mode : int) : (function_context, function_definition);
186 fn search_function_dictionary(dict : function_dictionary, name : istring) : function_definition;
187 fn search_function(ctx : function_context, name : istring, t : tokens) : function_definition;
188 fn search_function_from_id(ctx : function_context, id : function_unique_id) : function_definition;
189 fn get_implicits(ctx : function_context, conv : bool) : list(function_definition);
190 fn new_record_definition(is_option : bool) : record_definition;
192 fn encode_module_id~inline(id : module_unique_id) : int;
194 fn dump_function_context(ctx : function_context) : unit_type;
200 fn function_unique_id_equal(x1 x2 : function_unique_id) : bool
202 return x1.path_index = x2.path_index and
203 x1.unit_string = x2.unit_string and
204 x1.program = x2.program and
205 x1.function_index = x2.function_index;
208 implicit fn instance_eq_function_unique_id~inline : class_eq(function_unique_id) :=
209 class_eq(function_unique_id).[
210 equal : function_unique_id_equal,
213 fn unimplemented(m : bytes) : unit_type
215 m := "Unimplemented: " + m;
219 fn new_variable_dictionary(parent : maybe(variable_dictionary)) : variable_dictionary
221 return variable_dictionary.[
222 dict : infinite_uninitialized(int),
226 gvn_backup : exception_make(list(int), ec_sync, error_record_field_not_initialized, 0, false),
227 next : maybe(variable_dictionary).n,
232 fn new_variable_dictionary_chained(ctx : function_context, v : variable_dictionary) : variable_dictionary
234 var vd := new_variable_dictionary(maybe(variable_dictionary).n);
236 vd.gvn_backup := ctx.gvn;
240 fn free_variable_dictionary_chained(ctx : function_context, v : variable_dictionary) : function_context
242 ctx.gvn := v.gvn_backup;
246 fn new_variable(ctx : function_context, t def_at : int, mut : bool) : (function_context, local_variable)
248 return ctx, local_variable.[
252 local_type : T_NoLocalType,
257 fn set_variable_type(ctx : function_context, idx typ : int) : function_context
259 ctx.variables[idx].type_idx := typ;
263 fn add_variable(ctx : function_context, vd : variable_dictionary, name : istring, idx : int, impl : bool, t : tokens) : (function_context, variable_dictionary)
266 var existing := vd.dict[name];
267 if not is_uninitialized(existing) then [
268 abort compiler_error("Variable " + i_decode(name) + " already exists", t);
270 vd.dict[name] := idx;
271 ctx.variables[idx].name := name;
278 fn search_variable_dictionary(vd : variable_dictionary, name : istring) : int
281 var v := vd.dict[name];
282 if not is_uninitialized(v) then
284 if vd.next is j then [
289 if vd.parent is j then [
292 var v := vd.dict[name];
293 if not is_uninitialized(v) then
294 return exception_make_str(int, ec_sync, error_user2, 0, false, i_decode(name));
295 if vd.next is j then [
304 fn search_break(vd : variable_dictionary) : int
307 if vd.break_label >= 0 then
308 return vd.break_label;
309 if vd.next is j then [
316 fn search_continue(vd : variable_dictionary) : int
319 if vd.continue_label >= 0 then
320 return vd.continue_label;
321 if vd.next is j then [
328 fn get_implicit_variables(vd : variable_dictionary) : list(int)
330 var i := len(vd.impl) - 1;
331 var lst := empty(int);
337 lst += get_implicit_variables(vd.next.j);
341 fn new_function_dictionary(path_index : int, unit_string : istring, program : bool) : function_dictionary
343 return function_dictionary.[
344 defs : empty(function_definition),
345 dict : infinite_uninitialized(int),
346 macros : infinite_uninitialized(macro),
347 id : module_unique_id.[
348 path_index : path_index,
349 unit_string : unit_string,
354 name_prefix : exception_make(bytes, ec_sync, error_record_field_not_initialized, 0, false),
356 modules : empty(function_dictionary),
357 modules_map : infinite_uninitialized(int),
361 fn new_function_context(dict : function_dictionary, parent_function : maybe(function_context), n_arguments n_return_values : int, name : istring) : function_context
363 var function_index : list(int);
364 if parent_function is j then
365 function_index := parent_function.j.id.function_index +< len(parent_function.j.lambdas);
367 function_index := [ len(dict.defs) ];
368 var id := function_unique_id.[
369 path_index : dict.id.path_index,
370 unit_string : dict.id.unit_string,
371 program : dict.id.program,
372 function_index : function_index,
375 var nv := exception_make(local_variable, ec_sync, error_record_field_not_initialized, 0, false);
376 var ctx := function_context.[
377 n_arguments : n_arguments,
378 n_return_values : n_return_values,
379 variables : fill(nv, n_arguments + n_return_values),
380 instructions : empty(instruction),
382 lambdas : empty(function_definition),
387 defined_labels : infinite(false),
388 used_labels : infinite_uninitialized(int),
389 list_of_used_labels : empty(istring),
392 inferred_return : false,
395 op_mode : exception_make(op_option, ec_sync, error_record_field_not_initialized, 0, false),
396 op_priority : exception_make(int, ec_sync, error_record_field_not_initialized, 0, false),
398 record_def : maybe(record_definition).n,
400 local_types : empty(local_type),
401 local_types_map : infinite_uninitialized(int),
406 parent_function : parent_function,
411 inferred_base : T_InferredType,
416 fn function_context_is_privileged(ctx : function_context) : bool
418 return is_privileged or ctx.id.path_index = 0;
421 fn function_context_clear_temp_values(ctx : function_context) : function_context
423 ctx.dict := exception_make(function_dictionary, ec_sync, error_record_field_not_initialized, 0, false);
427 fn add_function(dict : function_dictionary, name : istring, ctx : function_context, vd : variable_dictionary, call_mode : int, op_bypass : int, op_bypass_reverse : bool, private_flag implicit_flag conversion_flag : bool) : (function_dictionary, function_definition)
429 ctx := function_context_clear_temp_values(ctx);
431 var def := function_definition.[
433 body : maybe(function_context).n,
435 call_mode : call_mode,
436 op_bypass : op_bypass,
437 op_bypass_reverse : op_bypass_reverse,
438 typ : exception_make(int, ec_sync, error_record_field_not_initialized, 0, false),
439 private_flag : private_flag,
440 pcode : exception_make(list(pcode_t), ec_sync, error_record_field_not_initialized, 0, false),
443 if implicit_flag then
444 dict.impl +<= len(dict.defs);
446 if conversion_flag then
447 dict.conv +<= len(dict.defs);
449 dict.dict[name] := len(dict.defs);
454 fn add_lambda(ctx ctx_head ctx_body : function_context, call_mode : int) : (function_context, function_definition)
456 ctx_head := function_context_clear_temp_values(ctx_head);
457 ctx_body := function_context_clear_temp_values(ctx_body);
459 var def := function_definition.[
460 signature : ctx_head,
461 body : maybe(function_context).j.(ctx_body),
462 call_mode : call_mode,
464 op_bypass_reverse : false,
467 pcode : exception_make(list(pcode_t), ec_sync, error_record_field_not_initialized, 0, false),
474 fn search_function_dictionary(dict : function_dictionary, name : istring) : function_definition
476 var fd := dict.defs[dict.dict[name]];
478 if fd.signature.inferred_return, fd.body is n then
479 return uninitialized(function_definition);
483 fn search_function(ctx : function_context, name : istring, t : tokens) : function_definition
485 var fd := search_function_dictionary(ctx.dict, name);
486 if not is_uninitialized(fd) then
489 var dict := ctx.dict;
490 var found := empty(function_definition);
491 for i := 0 to len(dict.modules) do [
492 fd := search_function_dictionary(dict.modules[i], name);
493 if not is_uninitialized(fd) then [
494 if fd.private_flag then [
495 if ctx.id.path_index <> fd.signature.id.path_index and not function_context_is_privileged(ctx) then
503 for i := 0 to len(found) do [
504 if found[i].signature.id.path_index > path_idx then
505 path_idx := found[i].signature.id.path_index;
508 for i := 0 to len(found) do [
509 if found[i].signature.id.path_index = path_idx then
513 abort compiler_error("Muliple functions named " + i_decode(name), t);
514 for i := 0 to len(found) do [
515 if found[i].signature.id.path_index = path_idx then
519 return uninitialized(function_definition);
522 fn search_function_from_id(ctx : function_context, id : function_unique_id) : function_definition
524 var fd : function_definition;
525 if ctx.dict.id.path_index = id.path_index, ctx.dict.id.unit_string = id.unit_string, ctx.dict.id.program = id.program then [
526 fd := ctx.dict.defs[id.function_index[0]];
528 var m_id := encode_module_id(module_unique_id.[ path_index : id.path_index, unit_string : id.unit_string, program : id.program ]);
530 var m_idx := ctx.dict.modules_map[m_id];
531 var m := ctx.dict.modules[m_idx];
533 fd := m.defs[id.function_index[0]];
535 var nested_path := id.function_index[1 .. ];
536 for p in list_consumer(nested_path) do [
538 fd := fd.body.j.lambdas[p];
540 fd := fd.signature.lambdas[p];
546 fn get_implicits(ctx : function_context, conv : bool) : list(function_definition)
548 var this_unit := empty(function_definition);
549 var max_path_index := ctx.dict.id.path_index;
550 var all_units : list(list(function_definition)) := fill(empty(function_definition), max_path_index + 1);
554 lst := ctx.dict.impl;
556 lst := ctx.dict.conv;
557 var i := len(lst) - 1;
560 this_unit +<= ctx.dict.defs[idx];
564 var dict := ctx.dict;
565 for i := 0 to len(dict.modules) do [
566 var md := dict.modules[i];
567 if md.id.path_index > max_path_index then
574 var i := len(lst) - 1;
577 all_units[md.id.path_index] +<= md.defs[idx];
583 var result := this_unit;
586 result += all_units[i];
593 fn new_record_definition(is_option : bool) : record_definition
595 return record_definition. [
596 is_option : is_option,
597 is_flat_option : false,
598 entries : empty(record_entry),
599 dict : infinite_uninitialized(int),
604 fn encode_module_id~inline(id : module_unique_id) : int
606 if id.path_index <= 7 then
607 return id.path_index shl 1 or id.unit_string shl 4;
609 return 1 or id.path_index shl 1 or id.unit_string shl 32;
612 fn dump_function_context(ctx : function_context) : unit_type
614 eval debug("--- dumping function: " + i_decode(ctx.name));
615 for i := 0 to len(ctx.instructions) do [
616 var ins := ctx.instructions[i];
617 var instr_name := (ntos(i) + " " + pcode_name(ins.opcode) + " ")[ .. 20];
618 var msg := "instr: " + instr_name + " ";
619 for j := 0 to len(ins.args) do
620 msg += " " + ntos(ins.args[j]);
623 for i := 0 to len(ctx.variables) do [
624 var va := ctx.variables[i];
626 {if va.name <> 0 then
627 name := i_decode(va.name);}
628 var var_name := (ntos(i) + " " + ntos_base(va.name, 16) + " ")[ .. 20];
629 var msg := "var: " + var_name + " ";
630 msg += "type_idx: " + ntos(va.type_idx) + ",";
631 msg += " defined_at: " + ntos(va.defined_at) + ",";
632 msg += " local_type: " + ntos(va.local_type);