Files
corelang/c_language_codegen.cpp
Krzosa Karol b4f38caabe Module relative pathing seems to work, managed to get out of having to have the exe where the files are,
Got rid of scope names, now unique names uses scope ids, module folder is in top folder
2022-06-27 10:56:17 +02:00

1025 lines
26 KiB
C++

#define gen(...) pctx->gen.addf(__VA_ARGS__)
#define genln(...) do{gen("\n"); gen_indent(); gen(__VA_ARGS__); }while(0)
global S32 global_indent;
global S32 is_inside_struct;
function void gen_ast(Ast *ast);
function bool gen_expr(Ast_Expr *ast, Ast_Type *type_of_var = 0);
function void
gen_indent(){
for(S32 i = 0; i < global_indent; i++) gen(" ");
}
global Intern_String last_filename;
function void
gen_line(Ast *node){
if(emit_line_directives){
genln("#line %d", node->pos->line+1);
if(node->pos->file != last_filename){
last_filename = node->pos->file;
gen(" \"%Q\"", last_filename);
}
}
}
function String
string_scope_name(Allocator *a, Ast_Scope *scope){
String string = {};
if(scope->parent_scope) string = string_scope_name(a, scope->parent_scope);
assert_msg(scope->scope_id != 0, "Scope id is equal to 0 which is invalid, scope didn't initialize id");
string = string_fmt(a, "%QS%u_", string, scope->scope_id);
return string;
}
function void
gen_scope_name(Ast_Scope *scope){
Scratch scratch;
String string = string_scope_name(scratch, scope);
gen("%.*s", (int)string.len, string.str);
}
function String
unique_name(Allocator *allocator, Ast *ast){
Scratch scratch;
String result = string_scope_name(scratch, ast->parent_scope);
assert(result.len);
result = string_fmt(allocator, "%Q%d", result, ast->pos->line);
return result;
}
// @todo: Gen complicated decl
//array 10 ( pointer (pointer array 5 int a))
// int (*(*(a[5])))[10]
//
// 1 Get to the bottom
// 2 Add variable name
// 3 Going backwards add arrays and pointers in parens
// 4 Add type name on the left side
function String
string_simple_decl_prefix(Allocator *a, Ast_Type *ast){
switch(ast->kind){
case TYPE_POINTER:{
String string = string_simple_decl_prefix(a, ast->base);
string = string_fmt(a, "%Q*", string);
return string;
}break;
case TYPE_LAMBDA: return {}; break;
case TYPE_ENUM:
case TYPE_ARRAY: {
return string_simple_decl_prefix(a, ast->base);
}break;
case TYPE_SLICE:{
String string = string_simple_decl_prefix(a, ast->base);
string = string_fmt(a, "Slice%llu ", ast->type_id);
return string;
}break;
case TYPE_TUPLE:{
String string = string_fmt(a, "Tuple%llu ", ast->type_id);
return string;
}break;
case TYPE_STRUCT: {
auto constant = (Ast_Decl *)ast->ast;
auto name = constant->name;
String string = string_fmt(a, "%Q ", name);
String sc = {};
return string_fmt(a, "%Q%Q", sc, string);
}break;
default: {
String string = string_fmt(a, "%s ", name(ast));
return string;
}
}
return {};
}
function String
string_simple_decl_postfix(Allocator *a, Ast_Type *ast){
switch(ast->kind){
case TYPE_POINTER:
return string_simple_decl_postfix(a, ast->base);
break;
case TYPE_ARRAY:{
String result = string_simple_decl_postfix(a, ast->arr.base);
String string = string_fmt(a, "[%d]%Q", ast->arr.size, result);
return string;
}break;
case TYPE_LAMBDA:break;
case TYPE_SLICE: case TYPE_ENUM: case TYPE_STRUCT:break;
default:break;
// default: return string_from_cstring((char *)name(ast));
}
return {};
}
function String
string_simple_decl(Allocator *a, Ast_Type *ast, Intern_String name = {}){
if(ast->kind == TYPE_LAMBDA) {
String prefix = string_simple_decl_prefix(a, ast->func.ret);
String string = string_fmt(a, "%Q(*%Q)(", prefix, name);
For(ast->func.args){
String prefix_arg = string_simple_decl_prefix(a, it);
string = string_fmt(a, "%Q%Q", string, prefix_arg);
if(&it != ast->func.args.end() - 1)
string = string_fmt(a, "%Q, ", string);
}
string = string_fmt(a, "%Q)", string);
return string;
}
else{
String string = string_simple_decl_prefix(a, ast);
if(name.len) {
string = string_fmt(a, "%Q%Q", string, name);
}
String postfix = string_simple_decl_postfix(a, ast);
string = string_fmt(a, "%Q%Q", string, postfix);
return string;
}
}
function void
gen_simple_decl(Ast_Type *ast, Intern_String name = {}){
Scratch scratch;
String string = string_simple_decl(scratch, ast, name);
gen("%.*s", (int)string.len, string.str);
}
function String
gen_string_simple_decl(Allocator *a, Ast_Type *ast, String name){
Scratch scratch;
String string = string_simple_decl(scratch, ast, pctx->intern(name));
String result = string_copy(a, string);
return result;
}
function B32
gen_value(Token *pos, Value a){
if(is_untyped(a.type)) compiler_error(pos, "Internal compiler error: Untyped got propagated to the codegen stage");
B32 result = true;
if(is_enum(a.type))
goto integer;
switch(a.type->kind){
CASE_INT: {
integer:
Scratch scratch;
const char *string = bigint_to_error_string(scratch, &a.big_int_val, 10);
gen("%s", string);
}break;
case TYPE_POINTER:{
if(a.type == type_pointer_to_char){
gen("\"%Q\"", a.intern_val);
}
else{
U64 pointer_value = bigint_as_unsigned(&a.big_int_val);
gen("0x%llx", pointer_value);
}
}break;
case TYPE_STRING:
gen("(String){(U8 *)\"%Q\", %d}", a.intern_val, a.intern_val.len);
break;
CASE_BOOL: a.bool_val ? gen("true"):gen("false"); break;
CASE_FLOAT: gen("%f", a.f64_val); break;
case TYPE_TYPE: {
gen("%d", a.type_val->type_id);
}break;
default: result = false;
}
return result;
}
function void
gen_stmt_scope(Ast_Scope *scope, B32 switch_case_gen_break = 0){
gen("{");
global_indent++;
For(scope->stmts) {
gen_line(it);
genln("");
gen_ast(it);
}
if(switch_case_gen_break == 1) genln("break;");
global_indent--;
genln("}");
}
enum {
ALWAYS_EMIT_VALUE = 0,
DONT_EMIT_VALUE = 1,
};
function void
gen_var(Ast_Decl *decl, B32 emit_value, B32 scope_names){
if(is_flag_set(decl->flags, AST_FOREIGN)) gen("extern ");
gen_simple_decl(decl->type, decl->name);
if(is_flag_set(decl->flags, AST_FOREIGN)) return;
if(emit_value == DONT_EMIT_VALUE){
return;
}
if(decl->expr){
gen(" = ");
gen_expr(decl->expr, decl->type);
} else { // Default zero
if(is_numeric(decl->type)){
gen(" = 0");
} else {
gen(" = {}");
}
}
}
function void
gen_lambda(Intern_String name, Ast_Lambda *lambda, B32 generate_block = true){
bool is_foreign = is_flag_set(lambda->flags, AST_FOREIGN);
if(name == pctx->intern("main"_s) || name == pctx->intern("WinMain"_s)){
is_foreign = true;
}
gen_simple_decl(lambda->resolved_type->func.ret, name);
gen("(");
For(lambda->args){
gen_var(it, DONT_EMIT_VALUE, true);
if(&it != (lambda->args.end() - 1))
gen(", ");
}
gen(")");
if(generate_block && lambda->scope){
gen_stmt_scope(lambda->scope);
}
else gen(";");
}
function bool
gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){
switch(ast->kind){
CASE(IDENT, Atom){
if(node->resolved_decl->kind == AST_MODULE_NAMESPACE || node->resolved_decl->kind == AST_FILE_NAMESPACE)
return false;
if(type_of_var){
if(is_slice(type_of_var) && is_array(node->resolved_decl->type)){
gen("{%d, ", (int)node->resolved_decl->type->arr.size);
gen("%Q}", node->intern_val);
}
else if(!is_any(ast->resolved_type) && is_any(type_of_var)){
gen("(Any){&");
gen_expr(ast);
gen(", %d}", ast->resolved_type->type_id);
}
else goto otherwise;
}
else{
otherwise:
gen("%Q", node->intern_val);
}
BREAK();
}
CASE(VALUE, Atom){
if(is_any(type_of_var)){
gen("(Any){&");
gen("("); gen_simple_decl(node->type); gen("){"); gen_value(node->pos, node->value); gen("}");
gen(", %d}", node->type->type_id);
return true;
}
B32 written = gen_value(node->pos, node->value);
if(!written) {
gen("%Q", node->value.intern_val);
}
BREAK();
}
CASE(ARRAY, Array){
gen("%d", node->resolved_type->type_id);
BREAK();
}
CASE(INDEX, Index){
gen("(");
gen_expr(node->expr);
if(is_string(node->resolved_type)){
if(!(type_of_var && type_of_var == type_pointer_to_char))
gen(".str");
}
else if(is_slice(node->resolved_type)){
gen(".data");
}
gen("[");
gen_expr(node->index);
gen("]");
gen(")");
BREAK();
}
CASE(LAMBDA_EXPR, Lambda){
gen_lambda({}, node);
BREAK();
}
CASE(BINARY, Binary){
if(node->op == TK_Dot){
if(gen_expr(node->left)){
if(node->resolved_type && node->resolved_type->kind == TYPE_POINTER) gen("->");
else gen(".");
}
gen_expr(node->right);
return true;
}
else if(node->op == TK_Arrow){
gen("(");
gen("(");
gen_simple_decl(node->resolved_type);
gen(")");
gen_expr(node->left);
gen(")");
return true;
}
if(!token_is_assign(node->op)) gen("(");
gen_expr(node->left);
gen("%s", name(node->op));
gen_expr(node->right);
if(!token_is_assign(node->op)) gen(")");
BREAK();
}
CASE(UNARY, Unary){
gen("(");
if(node->op != TK_PostIncrement && node->op != TK_PostDecrement) gen("%s", name(node->op));
gen_expr(node->expr);
if(node->op == TK_PostIncrement || node->op == TK_PostDecrement) gen("%s", name(node->op));
gen(")");
BREAK();
}
CASE(VAR, Decl){
gen_ast(node);
BREAK();
}
CASE(LENGTH_OF, Builtin){
gen_expr(node->expr);
if(is_pointer(node->expr->resolved_type))
gen("->len");
else gen(".len");
BREAK();
}
CASE(CALL, Call){
gen_expr(node->name);
gen("(");
For(node->exprs){
gen_expr(it->item, it->resolved_type);
if(!node->exprs.is_last(&it)) gen(", ");
}
gen(")");
BREAK();
}
CASE(COMPOUND, Call){
gen("(");
gen_simple_decl(node->resolved_type);
gen(")");
gen("{");
if(is_slice(node->resolved_type)) {
gen(".len = %d, ", node->exprs.len);
gen(".data = (");
gen_simple_decl(node->resolved_type->base);
gen("[]");
gen(")");
gen("{");
}
For(node->exprs){
if(is_struct(node->resolved_type))
gen(".%Q = ", it->resolved_name);
else if(is_array(node->resolved_type))
gen("[%d] = ", (int)it->resolved_index);
gen_expr(it->item, it->resolved_type);
if(!node->exprs.is_last(&it)) gen(", ");
}
if(is_slice(node->resolved_type)) gen("}");
gen("}");
BREAK();
}
invalid_default_case;
}
return true;
}
function void
gen_ast(Ast *ast){
switch(ast->kind){
CASE(RUNTIME_ASSERT, Builtin){
if(node->assert_message.len == 0) gen("assert");
else gen("assert_msg");
gen("(");
gen_expr(node->expr);
if(node->assert_message.len){
gen(", \"%Q\"", node->assert_message);
}
gen(");");
BREAK();
}
CASE(RETURN, Return){
if(is_tuple(node->resolved_type)) {
Scratch scratch;
Intern_String var_name = pctx->intern(unique_name(scratch, node));
gen_simple_decl(node->resolved_type, var_name);
gen(";");
int i = 0;
For(node->expr){
genln("memcpy(&%Q.m%d, ", var_name, i);
if(!is_array(it->resolved_type)) gen("&");
gen("(");
gen_expr(it);
gen(")");
gen(", sizeof(%Q.m%d));", var_name, i++);
}
genln("return %Q;", var_name);
return;
}
assert(node->expr.len <= 1);
gen("return ");
For(node->expr) gen_expr(it);
gen(";");
BREAK();
}
CASE(VAR, Decl){
gen_var(node, is_inside_struct ? DONT_EMIT_VALUE : ALWAYS_EMIT_VALUE, true);
if(!is_flag_set(ast->flags, AST_EXPR)) gen(";");
BREAK();
}
CASE(IF, If){
For(node->ifs){
gen_line(node);
genln("");
if(it->init) {
gen_expr(it->init);
gen(";");
genln("");
}
if(node->ifs.is_first(&it)){
gen("if(");
gen_expr(it->expr);
gen(")");
gen_stmt_scope(it->scope);
}
else{
genln("else");
if(it->expr){
gen(" if(");
gen_expr(it->expr);
gen(")");
}
gen_stmt_scope(it->scope);
}
}
BREAK();
}
CASE(BREAK, Break){
unused(node);
gen("break;");
BREAK();
}
CASE(PASS, Pass){
unused(node);
gen("//pass");
BREAK();
}
CASE(BINARY,Binary){
gen_expr(node);
gen(";");
BREAK();
}
CASE(FOR, For){
// Array iter
if(node->is_array_traversal){
gen("for(S64 _i%d = 0; _i%d < ", node->pos->line, node->pos->line);
gen_expr(node->cond);
gen(".len; _i%d+=1)", node->pos->line);
gen("{");
global_indent++;
genln("");
gen_simple_decl(node->array_traversal_var->type, node->array_traversal_var->name);
gen(" = ");
gen_expr(node->cond);
if(node->is_also_slice_traversal) gen(".data");
gen(" + _i%d;", node->pos->line);
For(node->scope->stmts) {
gen_line(it);
genln("");
gen_ast(it);
}
global_indent--;
genln("}");
}
// Normal for loop
else{
gen("for(");
if(node->init) gen_expr(node->init);
gen(";");
if(node->cond) gen_expr(node->cond);
gen(";");
if(node->iter) gen_expr(node->iter);
gen(")");
gen_stmt_scope(node->scope);
}
BREAK();
}
CASE(LAMBDA, Decl){
gen_line(node);
genln("");
if(is_flag_set(node->expr->flags, AST_FOREIGN)){
gen("/*foreign*/");
}
gen_lambda(node->name, node->lambda);
BREAK();
}
CASE(STRUCT, Decl){
gen("struct ");
gen("%Q{", node->name);
global_indent++;
is_inside_struct++;
For(node->scope->decls){
genln("");
gen_ast(it);
}
is_inside_struct--;
global_indent--;
genln("};");
BREAK();
}
CASE(TYPE, Decl){
gen("// Type %Q = ", node->name);
gen_simple_decl(node->type_val);
BREAK();
}
CASE(ENUM, Decl){
gen("/*enum %Q{", node->name);
// @todo add typespec
global_indent++;
For(node->scope->decls){
genln("%Q", it->name);
gen(" = ");
gen_value(it->pos, it->value);
gen(",");
}
global_indent--;
genln("};*/");
BREAK();
}
CASE(CONST, Decl){
switch(node->type->kind){
CASE_FLOAT:{
gen("// F64 %Q = ", node->name);
// gen_value(node->pos, node->value);
} break;
CASE_INT:{
gen("// constant int %Q = ", node->name);
// gen_value(node->pos, node->value);
}break;
CASE_STRING:{
assert(is_pointer(node->type) ? node->type == type_pointer_to_char : 1);
gen("// const String %Q = ", node->name);
// gen_value(node->pos, node->value);
}break;
CASE_BOOL:{
gen("// const Bool %Q = ", node->name);
// gen_value(node->pos, node->value);
}break;
case TYPE_LAMBDA:{
gen("// ");
gen_lambda(node->name, node->lambda);
} break;
invalid_default_case;
}
BREAK();
}
CASE(SWITCH, Switch){
gen("switch(");
gen_expr(node->value);
gen("){");
global_indent++;
For(node->cases){
For_Named(it->labels, label){
gen_line(it);
genln("");
gen("case ");
gen_expr(label);
gen(":");
}
gen_stmt_scope(it->scope, it->fallthrough ? false : true);
}
if(node->default_scope){
genln("default: ");
gen_stmt_scope(node->default_scope);
}
global_indent--;
genln("}");
BREAK();
}
CASE(VAR_UNPACK, Var_Unpack){
For(node->vars)
gen_ast(it);
Scratch scratch;
Intern_String var_name = pctx->intern(unique_name(scratch, node));
gen_simple_decl(node->resolved_type, var_name);
gen(" = ");
gen_expr(node->expr);
gen(";");
int i = 0;
For(node->vars){
gen("memcpy((void *)&%Q, (void *)&%Q.m%d, sizeof(%Q));", it->name, var_name, i++, it->name);
}
BREAK();
}
case AST_CONSTANT_ASSERT:
case AST_MODULE_NAMESPACE:
CASE(FILE_NAMESPACE, File_Namespace){unused(node); BREAK();}
default: {
assert(is_flag_set(ast->flags, AST_EXPR));
gen_expr((Ast_Expr *)ast);
gen(";");
}
}
}
function void
parse_file(Ast_File *file){
assert(file);
Scratch scratch;
file->filecontent = os_read_file(pctx->perm, file->absolute_file_path);
if(file->filecontent.len == 0){
compiler_error(file->pos, "Failed to open file \"%Q\"", file->absolute_file_path);
}
pctx->currently_parsed_file = file;
pctx->currently_parsed_scope = file;
lex_restream(pctx, file->filecontent, file->absolute_file_path);
while(token_expect(SAME_SCOPE)){
if(token_match_pound(pctx->intern("load"_s))){
parse_load(true);
continue;
} else if(token_match_pound(pctx->intern("import"_s))){
parse_import(true);
continue;
}
Ast_Decl *decl = parse_decl(true);
if(!decl) break;
set_flag(decl->flags, AST_GLOBAL);
if(decl->kind == AST_STRUCT){
decl->type = type_type;
decl->type_val = type_incomplete(decl);
decl->state = DECL_RESOLVED;
}
insert_into_scope(file, decl);
}
pctx->currently_parsed_scope = 0;
pctx->currently_parsed_file = 0;
}
function void
insert_builtin_into_scope(Ast_Scope *p, String name, Ast_Type *type){
Intern_String string = pctx->intern(name);
Ast_Decl *decl = ast_type(0, string, type);
type->type_id = pctx->type_ids++;
decl->parent_scope = p;
decl->state = DECL_RESOLVED;
insert_into_scope(p, decl);
pctx->all_types.add(type);
}
function void
insert_builtin_types_into_scope(Ast_Scope *p){
insert_builtin_into_scope(p, "S64"_s, type_s64);
insert_builtin_into_scope(p, "S32"_s, type_s32);
insert_builtin_into_scope(p, "S16"_s, type_s16);
insert_builtin_into_scope(p, "S8"_s, type_s8);
insert_builtin_into_scope(p, "int"_s, type_int);
insert_builtin_into_scope(p, "char"_s, type_char);
insert_builtin_into_scope(p, "U64"_s, type_u64);
insert_builtin_into_scope(p, "U32"_s, type_u32);
insert_builtin_into_scope(p, "U16"_s, type_u16);
insert_builtin_into_scope(p, "U8"_s, type_u8);
insert_builtin_into_scope(p, "F64"_s, type_f64);
insert_builtin_into_scope(p, "F32"_s, type_f32);
insert_builtin_into_scope(p, "void"_s , type_void);
insert_builtin_into_scope(p, "Bool"_s , type_bool);
insert_builtin_into_scope(p, "String"_s, type_string);
insert_builtin_into_scope(p, "Type"_s, type_type);
}
global F64 parsing_time_begin;
global F64 parsing_time_end;
function void
parse_all_modules(){
parsing_time_begin = os_time();
for(S64 i = 0; i < pctx->modules.len; i++){
Ast_Module *module = pctx->modules[i];
if(module->state != MODULE_REGISTERED) continue;
for(S64 j = 0; j < module->all_loaded_files.len; j++){
Ast_File *file = module->all_loaded_files.data[j];
parse_file(file);
}
if(module != pctx->language_base_module)
module->implicit_imports.add(pctx->language_base_module);
module->state = MODULE_PARSED;
}
parsing_time_end = os_time();
}
function Ast_Module *
add_module(Token *pos, Intern_String filename, B32 command_line_module){
Scratch scratch;
String absolute_file_path = {};
String absolute_base_folder = {};
//
// Find in working directory
//
if(command_line_module){
if(os_does_file_exist(filename.s)){
String path = os_get_absolute_path(scratch, filename.s);
string_path_normalize(path);
absolute_file_path = string_copy(scratch, path);
absolute_base_folder = string_chop_last_slash(path);
}
}
//
// Find in module folder
//
else{
For(pctx->module_folders){
String path = string_fmt(scratch, "%Q/%Q", it, filename);
if(os_does_file_exist(path)){
absolute_file_path = path;
absolute_base_folder = string_chop_last_slash(path);
break;
}
}
}
if(absolute_file_path.len == 0){
compiler_error(pos, "Couldn't find the module with name %Q", filename);
}
For(pctx->modules){
if(string_compare(it->absolute_file_path, absolute_file_path)){
log_info("Returning registered module: %Q\n", absolute_file_path);
return it;
}
}
Ast_Module *result = ast_new(Ast_Module, AST_MODULE, pos, 0);
result->absolute_file_path = string_copy(pctx->perm, absolute_file_path);
result->absolute_base_folder = string_copy(pctx->perm, absolute_base_folder);
log_info("Adding module: %Q\n", filename);
result->module = result; // @warning: self referential
result->file = result; // @warning: self referential
result->all_loaded_files = {pctx->heap};
result->implicit_imports = {pctx->heap};
result->decls = {pctx->heap};
result->parent_scope = 0;
result->scope_id = pctx->scope_ids++;
register_ast_file(pos, result->absolute_file_path, result, GLOBAL_IMPLICIT_LOAD);
pctx->modules.add(result);
return result;
}
global F64 resolving_time_begin;
global F64 resolving_time_end;
function void
resolve_everything_in_module(Ast_Module *module){
if(module->state == MODULE_RESOLVED) return;
resolving_time_begin = os_time();
for(S64 i = 0; i < module->all_loaded_files.len; i++){
Ast_File *file = module->all_loaded_files[i];
For(file->decls){
resolve_name(file, it->pos, it->name);
if(it->kind == AST_STRUCT){
type_complete(it->type_val);
}
}
}
module->state = MODULE_RESOLVED;
resolving_time_end = os_time();
}
global F64 init_ctx_time_begin;
global F64 init_ctx_time_end;
function void
begin_compilation(){
init_ctx_time_begin = os_time();
OS_Heap *heap = exp_alloc_type(&pernament_arena, OS_Heap);
*heap = win32_os_heap_create(false, mib(4), 0);
Parse_Ctx *ctx = exp_alloc_type(&pernament_arena, Parse_Ctx);
parse_init(ctx, &pernament_arena, heap);
init_ctx_time_end = os_time();
}
global F64 generating_time_begin;
global F64 generating_time_end;
function String
get_compilation_result(){
generating_time_begin = os_time();
gen(R"==(
#include <stdint.h>
#include <math.h>
#include <string.h>
typedef int8_t S8;
typedef int16_t S16;
typedef int32_t S32;
typedef int64_t S64;
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
typedef S8 B8;
typedef S16 B16;
typedef S32 B32;
typedef S64 B64;
typedef U64 SizeU;
typedef S64 SizeS;
typedef float F32;
typedef double F64;
typedef S32 Bool;
typedef S64 Type;
#define true 1
#define false 0
#define assert(x) do{if(!(x))__debugbreak();}while(0)
#define assert_msg(x,...) assert(x)
typedef struct String{
U8 *str;
S64 len;
}String;
)==");
// Generate struct forward decls
For(pctx->ordered_decls){
if(it->kind == AST_STRUCT){
genln("typedef struct %Q %Q;", it->name, it->name);
}
}
// Generate slice and tuple types
For(pctx->all_types){
Scratch scratch;
Ast_Type *type = it;
if(type->kind == TYPE_SLICE){
genln("typedef struct Slice%llu{", type->type_id);
global_indent++;
genln("S64 len;");
genln("");
gen_simple_decl(type_pointer(type->base), pctx->intern("data"_s));
gen(";");
global_indent--;
genln("} Slice%llu;", type->type_id);
}
else if(type->kind == TYPE_TUPLE){
genln("typedef struct Tuple%llu{", type->type_id);
global_indent++;
For(type->agg.members){
genln("");
// @todo remove intern from gen
Intern_String name = pctx->intern(string_fmt(scratch, "m%llu", type->agg.members.get_index(&it)));
gen_simple_decl(it.type, name);
gen(";");
}
global_indent--;
genln("} Tuple%llu;", type->type_id);
}
}
// Generate lambda forward decls
For(pctx->ordered_decls){
if(it->kind == AST_LAMBDA){
genln("");
gen_lambda(it->name, it->lambda, false);
}
}
// Generate language.kl
for(S32 i = 0; i < pctx->base_language_ordered_decl_len; i++){
Ast_Decl *it = pctx->ordered_decls[i];
genln("");
gen_ast(it);
}
// Generate type info
genln("S64 type_infos_len = %d;", pctx->all_types.len);
genln("Type_Info *type_infos = (Type_Info[]){");
global_indent++;
For(pctx->all_types){
genln("{/*%Q*/.kind = %d, .size = %d, .align = %d, .is_unsigned = %s, .type = %d, ", typestring(it),
(S32)it->kind, (S32)it->size, (S32)it->align, it->is_unsigned ? "true" : "false", it->type_id);
switch(it->kind){
case TYPE_POINTER:
case TYPE_SLICE: {
gen(".base_type = %d", it->base->type_id);
} break;
case TYPE_ARRAY: {
gen(".base_type = %d, ", it->base->type_id);
gen(".array_size = %d", it->arr.size);
}break;
case TYPE_LAMBDA: {
gen(".lambda_return = %d, ", it->func.ret->type_id);
gen(".lambda_argument_count = %d, ", it->func.args.len);
gen(".lambda_arguments = (Type_Info[%d]){", it->func.args.len);
For_Named(it->func.args, arg){
gen("{.type = %d}, ", arg->type_id);
}
gen("}");
} break;
case TYPE_STRUCT:{
gen(".struct_member_count = %d, ", it->agg.members.len);
gen(".struct_members = (Type_Info_Struct_Member[]){");
For_Named(it->agg.members, m){
gen("{.name = (String){(U8 *)\"%Q\", %d}, .type = %d, .offset = %d}, ", m.name, m.name.len, m.type->type_id, m.offset);
}
gen("}");
}break;
default: {}
// invalid_default_case;
}
gen("},");
}
global_indent--;
gen("};");
// Generate actual code
for(S32 i = pctx->base_language_ordered_decl_len; i < pctx->ordered_decls.len; i++){
Ast_Decl *it = pctx->ordered_decls[i];
genln("");
gen_ast(it);
}
String string_result = string_flatten(pctx->perm, &pctx->gen);
generating_time_end = os_time();
return string_result;
}
function void
compiler_cleanup(){
exp_destroy(pctx->heap);
}