629 lines
18 KiB
C
629 lines
18 KiB
C
//-----------------------------------------------------------------------------
|
|
// Decls
|
|
//-----------------------------------------------------------------------------
|
|
function Decl *
|
|
decl_new(Parser *p, Decl_Kind kind, Token *pos, Intern_String name){
|
|
Decl *result = arena_push_struct(&p->main_arena, Decl);
|
|
result->kind = kind;
|
|
result->pos = pos;
|
|
result->name = name;
|
|
return result;
|
|
}
|
|
|
|
function Decl *
|
|
decl_struct(Parser *p, Decl_Kind kind, Token *pos, Intern_String name, Decl_Struct_Kind struct_kind){
|
|
assert(kind == DECL_Struct || kind == DECL_Union);
|
|
Decl *result = decl_new(p, kind, pos, name);
|
|
result->struct_decl.kind = struct_kind;
|
|
return result;
|
|
}
|
|
|
|
function Decl *
|
|
decl_typedef(Parser *p, Token *pos, Intern_String name, Typespec *type){
|
|
Decl *result = decl_new(p, DECL_Typedef, pos, name);
|
|
result->typedef_decl.type = type;
|
|
return result;
|
|
}
|
|
|
|
function Decl *
|
|
decl_enum(Parser *p, Token *pos, Intern_String name, Typespec *typespec){
|
|
Decl *result = decl_new(p, DECL_Enum, pos, name);
|
|
result->enum_decl.typespec = typespec;
|
|
return result;
|
|
}
|
|
|
|
function Decl *
|
|
decl_variable(Parser *p, Token *pos, Intern_String name, Typespec *typespec, Expr *expr){
|
|
Decl *result = decl_new(p, DECL_Variable, pos, name);
|
|
result->variable_decl.type = typespec;
|
|
result->variable_decl.expr = expr;
|
|
return result;
|
|
}
|
|
|
|
function Decl *
|
|
decl_function(Parser *p, Token *pos, Intern_String name, Typespec *ret){
|
|
Decl *result = decl_new(p, DECL_Function, pos, name);
|
|
result->function_decl.ret = ret;
|
|
return result;
|
|
}
|
|
|
|
function void
|
|
decl_function_push(Parser *p, Decl *parent, Token *pos, Intern_String name, Typespec *type){
|
|
assert(parent->kind == DECL_Function);
|
|
Decl_Function_Arg *result = arena_push_struct(&p->main_arena, Decl_Function_Arg);
|
|
result->name = name;
|
|
result->typespec = type;
|
|
result->pos = pos;
|
|
SLLQueuePush(parent->function_decl.first, parent->function_decl.last, result);
|
|
}
|
|
|
|
function void
|
|
decl_enum_push(Parser *p, Decl *parent, Token *pos, Intern_String name, Expr *expr, Note *notes){
|
|
assert(parent->kind == DECL_Enum);
|
|
Decl_Enum_Child *child = arena_push_struct(&p->main_arena, Decl_Enum_Child);
|
|
child->pos = pos;
|
|
child->name = name;
|
|
child->expr = expr;
|
|
child->first_note = notes->first;
|
|
child->last_note = notes->last;
|
|
SLLQueuePush(parent->enum_decl.first, parent->enum_decl.last, child);
|
|
}
|
|
|
|
function void
|
|
decl_struct_push(Decl *parent, Decl *child){
|
|
assert(parent->kind == DECL_Struct || parent->kind == DECL_Union);
|
|
SLLQueuePush(parent->struct_decl.first, parent->struct_decl.last, child);
|
|
}
|
|
|
|
function void
|
|
decl_list_push(Decl *parent, Decl *child){
|
|
assert(parent->kind == DECL_List);
|
|
SLLQueuePush(parent->list.first, parent->list.last, child);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Ops
|
|
//-----------------------------------------------------------------------------
|
|
function Decl *
|
|
decl_struct_find_node(Decl *decl, String string){
|
|
for(Decl *n = decl->struct_decl.first; n; n=n->next){
|
|
if(string_compare(string, n->name.s)){
|
|
return n;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Notes
|
|
//-----------------------------------------------------------------------------
|
|
function void
|
|
decl_pass_notes(Decl *a, Note *b){
|
|
a->first_note = b->first;
|
|
a->last_note = b->last;
|
|
}
|
|
|
|
function Note *
|
|
note_push_new(Parser *p, Note *parent, Token *pos, Intern_String name, Expr *expr){
|
|
Note *result = arena_push_struct(&p->main_arena, Note);
|
|
result->pos = pos;
|
|
result->name = name;
|
|
result->expr = expr;
|
|
SLLQueuePush(parent->first, parent->last, result);
|
|
return result;
|
|
}
|
|
|
|
function Note *
|
|
find_note(Note *first, String string){
|
|
for(Note *n = first; n; n=n->next){
|
|
if(string_compare(string, n->name.s)){
|
|
return n;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function String
|
|
find_string_note(Note *first, String string, String default_string){
|
|
Note *note = find_note(first, string);
|
|
if(note){
|
|
return note->expr->token->intern_val.s;
|
|
}
|
|
return default_string;
|
|
}
|
|
|
|
function Note *
|
|
decl_find_note(Decl *decl, String string){
|
|
return find_note(decl->first_note, string);
|
|
}
|
|
|
|
function String
|
|
decl_find_string_note(Decl *decl, String string, String default_string){
|
|
return find_string_note(decl->first_note, string, default_string);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Typespec
|
|
//-----------------------------------------------------------------------------
|
|
function Typespec *
|
|
typespec_new(Parser *p, Typespec_Kind kind, Token *pos){
|
|
Typespec *result = arena_push_struct(&p->main_arena, Typespec);
|
|
result->kind = kind;
|
|
result->pos = pos;
|
|
return result;
|
|
}
|
|
|
|
function Typespec *
|
|
typespec_name(Parser *p, Token *pos, Intern_String name){
|
|
Typespec *result = typespec_new(p, TS_Name, pos);
|
|
result->name = name;
|
|
return result;
|
|
}
|
|
|
|
function Typespec *
|
|
typespec_pointer(Parser *p, Token *pos, Typespec *base){
|
|
Typespec *result = typespec_new(p, TS_Pointer, pos);
|
|
result->base = base;
|
|
return result;
|
|
}
|
|
|
|
function Typespec *
|
|
typespec_array(Parser *p, Token *pos, Typespec *base, Expr *size){
|
|
Typespec *result = typespec_new(p, TS_Array, pos);
|
|
result->array_spec.base = base;
|
|
result->array_spec.size = size;
|
|
return result;
|
|
}
|
|
|
|
function Typespec *
|
|
typespec_function(Parser *p, Token *pos, Typespec *ret){
|
|
Typespec *result = typespec_new(p, TS_Function, pos);
|
|
result->function_spec.ret = ret;
|
|
return result;
|
|
}
|
|
|
|
function void
|
|
typespec_function_push(Typespec *func, Typespec *arg){
|
|
SLLQueuePush(func->function_spec.first, func->function_spec.last, arg);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
function Typespec *
|
|
typespec_get_func(Typespec *type){
|
|
switch(type->kind){
|
|
case TS_Name:{return 0;} break;
|
|
case TS_Pointer:{return typespec_get_func(type->base);} break;
|
|
case TS_Array:{return typespec_get_func(type->array_spec.base);} break;
|
|
case TS_Function:{return type;} break;
|
|
default: {invalid_codepath;} break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function Typespec *
|
|
typespec_get_name(Typespec *type){
|
|
switch(type->kind){
|
|
case TS_Name:{return type;} break;
|
|
case TS_Pointer:{return typespec_get_name(type->base);} break;
|
|
case TS_Array:{return typespec_get_name(type->array_spec.base);} break;
|
|
case TS_Function:{return 0;} break;
|
|
default: {invalid_codepath;} break;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function String
|
|
typespec_require_name_string(Typespec *type){
|
|
Typespec *result = typespec_get_name(type);
|
|
if(result){
|
|
if(result->kind == TS_Name){
|
|
return result->name.s;
|
|
}
|
|
}
|
|
invalid_codepath;
|
|
return string_empty;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Statements
|
|
//-----------------------------------------------------------------------------
|
|
function Stmt *
|
|
stmt_new(Parser *p, Stmt_Kind kind, Token *pos){
|
|
Stmt *result = arena_push_struct(&p->main_arena, Stmt);
|
|
result->kind = kind;
|
|
result->pos = pos;
|
|
return result;
|
|
}
|
|
|
|
function Stmt *
|
|
stmt_decl(Parser *p, Token *pos, Decl *decl){
|
|
Stmt *result = stmt_new(p, STMT_Decl, pos);
|
|
result->decl = decl;
|
|
return result;
|
|
}
|
|
|
|
function Stmt *
|
|
stmt_expr(Parser *p, Token *pos, Expr *expr){
|
|
Stmt *result = stmt_new(p, STMT_Expr, pos);
|
|
result->expr = expr;
|
|
return result;
|
|
}
|
|
|
|
function Stmt *
|
|
stmt_list(Parser *p, Token *pos){
|
|
Stmt *result = stmt_new(p, STMT_List, pos);
|
|
return result;
|
|
}
|
|
|
|
function Stmt *
|
|
stmt_return(Parser *p, Token *pos, Expr *expr){
|
|
Stmt *result = stmt_new(p, STMT_Return, pos);
|
|
result->ret.expr = expr;
|
|
return result;
|
|
}
|
|
|
|
function Stmt *
|
|
stmt_if(Parser *p, Token *pos, Stmt *body, Expr *cond){
|
|
Stmt *result = stmt_new(p, STMT_If, pos);
|
|
result->stmt_if.cond = cond;
|
|
result->stmt_if.body = body;
|
|
return result;
|
|
}
|
|
|
|
function void
|
|
stmt_push(Stmt *stmt, Stmt *child){
|
|
SLLQueuePush(stmt->list.first, stmt->list.last, child);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Pointer Array
|
|
//-----------------------------------------------------------------------------
|
|
function Pointer_Array
|
|
pointer_array_make(Arena *arena){
|
|
Pointer_Array result = {
|
|
.last = &result.first,
|
|
.arena = arena,
|
|
};
|
|
return result;
|
|
}
|
|
|
|
#define bucket_size (buff_cap(array->first.data))
|
|
function void
|
|
pointer_array_push(Pointer_Array *array, Pointer p){
|
|
if(array->len >= bucket_size){
|
|
Pointer_Bucket *bucket = arena_push_struct(array->arena, Pointer_Bucket);
|
|
array->last = array->last->next = bucket;
|
|
array->len = 0;
|
|
array->block += 1;
|
|
}
|
|
array->last->data[array->len++] = p;
|
|
}
|
|
|
|
function B32
|
|
pointer_array_iter_is_end(Pointer_Array *array){
|
|
B32 result = array->iter_len == array->len && array->iter_block == array->block;
|
|
return result;
|
|
}
|
|
|
|
function Pointer
|
|
pointer_array_iter_next(Pointer_Array *array){
|
|
if(pointer_array_iter_is_end(array)){
|
|
return (Pointer){0};
|
|
}
|
|
if(array->iter_len >= bucket_size){
|
|
array->iter_len = 0;
|
|
array->iter_block += 1;
|
|
array->iter_bucket = array->iter_bucket->next;
|
|
}
|
|
Pointer result = array->iter_bucket->data[array->iter_len++];
|
|
return result;
|
|
}
|
|
|
|
function Pointer
|
|
pointer_array_iter_begin(Pointer_Array *array){
|
|
array->iter_len = 0;
|
|
array->iter_block = 0;
|
|
array->iter_bucket = &array->first;
|
|
Pointer result = pointer_array_iter_next(array);
|
|
return result;
|
|
}
|
|
|
|
function Pointer
|
|
pointer_typespec(Typespec *t){
|
|
return (Pointer){.kind = PK_Typespec, .typespec = t};
|
|
}
|
|
function Pointer
|
|
pointer_expr(Expr *t){
|
|
return (Pointer){.kind = PK_Expr, .expr = t};
|
|
}
|
|
function Pointer
|
|
pointer_decl(Decl *t){
|
|
return (Pointer){.kind = PK_Decl, .decl = t};
|
|
}
|
|
function Pointer
|
|
pointer_stmt(Stmt *t){
|
|
return (Pointer){.kind = PK_Stmt, .stmt = t};
|
|
}
|
|
function Pointer
|
|
pointer_enum_child(Decl_Enum_Child *t){
|
|
return (Pointer){.kind = PK_Enum_Child, .enum_child = t};
|
|
}
|
|
function Pointer
|
|
pointer_func_arg(Decl_Function_Arg *t){
|
|
return (Pointer){.kind = PK_Func_Arg, .func_arg=t};
|
|
}
|
|
|
|
function void
|
|
pointer_array_push_typespec(Pointer_Array *array, Typespec *typespec){
|
|
pointer_array_push(array, pointer_typespec(typespec));
|
|
}
|
|
function void
|
|
pointer_array_push_decl(Pointer_Array *array, Decl *decl){
|
|
pointer_array_push(array, pointer_decl(decl));
|
|
}
|
|
function void
|
|
pointer_array_push_stmt(Pointer_Array *array, Stmt *stmt){
|
|
pointer_array_push(array, pointer_stmt(stmt));
|
|
}
|
|
function void
|
|
pointer_array_push_expr(Pointer_Array *array, Expr *expr){
|
|
pointer_array_push(array, pointer_expr(expr));
|
|
}
|
|
function void
|
|
pointer_array_push_enum_child(Pointer_Array *array, Decl_Enum_Child *enum_child){
|
|
pointer_array_push(array, pointer_enum_child(enum_child));
|
|
}
|
|
function void
|
|
pointer_array_push_func_arg(Pointer_Array *array, Decl_Function_Arg *func_arg){
|
|
pointer_array_push(array, pointer_func_arg(func_arg));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Gather
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function void
|
|
gather_try_recurse_typespec(Pointer_Array *array, Typespec *typespec, Gather_Flag gflag, Traversal_Flag tflag);
|
|
function void
|
|
gather_recurse_expr(Pointer_Array *array, Expr *expr, Gather_Flag gflag, Traversal_Flag tflag){
|
|
if(gflag & GATHER_Expr)
|
|
pointer_array_push_expr(array, expr);
|
|
|
|
switch(expr->kind) {
|
|
case EK_Atom: {} break;
|
|
case EK_Sizeof:{
|
|
if(expr->size_of.kind == SIZEOF_Expr){
|
|
gather_recurse_expr(array, expr->size_of.expr, gflag, tflag);
|
|
}
|
|
else{
|
|
assert(expr->size_of.kind == SIZEOF_Type);
|
|
gather_try_recurse_typespec(array, expr->size_of.type, gflag, tflag);
|
|
}
|
|
}break;
|
|
|
|
case EK_Binary:{
|
|
gather_recurse_expr(array, expr->binary.left, gflag, tflag);
|
|
gather_recurse_expr(array, expr->binary.right, gflag, tflag);
|
|
} break;
|
|
case EK_Unary:{
|
|
gather_recurse_expr(array, expr->unary.expr, gflag, tflag);
|
|
} break;
|
|
|
|
case EK_Ternary:{
|
|
gather_recurse_expr(array, expr->ternary.cond, gflag, tflag);
|
|
gather_recurse_expr(array, expr->ternary.on_true, gflag, tflag);
|
|
gather_recurse_expr(array, expr->ternary.on_false, gflag, tflag);
|
|
} break;
|
|
case EK_List:{
|
|
for(Expr *n = expr->list.first; n; n=n->next){
|
|
gather_recurse_expr(array, n, gflag, tflag);
|
|
}
|
|
}break;
|
|
|
|
case EK_Cast:{
|
|
gather_try_recurse_typespec(array, expr->cast.type, gflag, tflag);
|
|
gather_recurse_expr(array, expr->cast.expr, gflag, tflag);
|
|
} break;
|
|
|
|
case EK_Index:{
|
|
gather_recurse_expr(array, expr->index.atom, gflag, tflag);
|
|
gather_recurse_expr(array, expr->index.index, gflag, tflag);
|
|
}break;
|
|
|
|
case EK_Call:{
|
|
gather_recurse_expr(array, expr->call.atom, gflag, tflag);
|
|
gather_recurse_expr(array, expr->call.list, gflag, tflag);
|
|
}break;
|
|
default: {invalid_codepath;} break;
|
|
}
|
|
}
|
|
|
|
function void
|
|
gather_try_recurse_expr(Pointer_Array *array, Expr *expr, Gather_Flag gflag, Traversal_Flag tflag){
|
|
if(expr){
|
|
if(tflag & TRAVERS_Expr){
|
|
gather_recurse_expr(array, expr, gflag, tflag);
|
|
}
|
|
else if(gflag & GATHER_Expr){
|
|
pointer_array_push_expr(array, expr);
|
|
}
|
|
}
|
|
}
|
|
|
|
function void
|
|
gather_recurse_decl(Pointer_Array *array, Decl *decl, Gather_Flag gflag, Traversal_Flag tflag);
|
|
function void
|
|
gather_try_recurse_stmt(Pointer_Array *array, Stmt *stmt, Gather_Flag gflag, Traversal_Flag tflag);
|
|
function void
|
|
gather_recurse_stmt(Pointer_Array *array, Stmt *stmt, Gather_Flag gflag, Traversal_Flag tflag){
|
|
switch(stmt->kind) {
|
|
case STMT_List: {
|
|
for(Stmt *s = stmt->list.first; s; s=s->next){
|
|
gather_recurse_stmt(array, s, gflag, tflag);
|
|
}
|
|
} break;
|
|
case STMT_Return:{
|
|
gather_try_recurse_expr(array, stmt->ret.expr, gflag, tflag);
|
|
} break;
|
|
case STMT_If:{
|
|
gather_recurse_expr(array, stmt->stmt_if.cond, gflag, tflag);
|
|
gather_recurse_stmt(array, stmt->stmt_if.body, gflag, tflag);
|
|
for(Stmt_If *s = stmt->stmt_if.next; s; s=s->next){
|
|
gather_recurse_stmt(array, s->body, gflag, tflag);
|
|
gather_recurse_expr(array, s->cond, gflag, tflag);
|
|
}
|
|
} break;
|
|
case STMT_Expr: {
|
|
gather_recurse_expr(array, stmt->expr, gflag, tflag);
|
|
} break;
|
|
case STMT_Decl: {
|
|
gather_recurse_decl(array, stmt->decl, gflag, tflag);
|
|
} break;
|
|
default: {invalid_codepath;} break;
|
|
}
|
|
}
|
|
|
|
function void
|
|
gather_try_recurse_stmt(Pointer_Array *array, Stmt *stmt, Gather_Flag gflag, Traversal_Flag tflag){
|
|
if(stmt){
|
|
if(tflag & TRAVERS_Stmt){
|
|
gather_recurse_stmt(array, stmt, gflag, tflag);
|
|
}
|
|
else if(gflag & GATHER_Stmt){
|
|
pointer_array_push_stmt(array, stmt);
|
|
}
|
|
}
|
|
}
|
|
|
|
function void
|
|
gather_recurse_typespec(Pointer_Array *array, Typespec *typespec, Gather_Flag gflag, Traversal_Flag tflag){
|
|
if(gflag & GATHER_Typespec)
|
|
pointer_array_push_typespec(array, typespec);
|
|
switch(typespec->kind) {
|
|
case TS_Name: {
|
|
} break;
|
|
case TS_Pointer: {
|
|
gather_recurse_typespec(array, typespec->base, gflag, tflag);
|
|
} break;
|
|
case TS_Array: {
|
|
gather_recurse_typespec(array, typespec->array_spec.base, gflag, tflag);
|
|
gather_try_recurse_expr(array, typespec->array_spec.size, gflag, tflag);
|
|
} break;
|
|
case TS_Function: {
|
|
gather_recurse_typespec(array, typespec->function_spec.ret, gflag, tflag);
|
|
for(Typespec *n = typespec->function_spec.first; n; n=n->next){
|
|
gather_recurse_typespec(array, n, gflag, tflag);
|
|
}
|
|
} break;
|
|
default: {invalid_codepath;} break;
|
|
}
|
|
}
|
|
|
|
function void
|
|
gather_try_recurse_typespec(Pointer_Array *array, Typespec *typespec, Gather_Flag gflag, Traversal_Flag tflag){
|
|
if(typespec){
|
|
if(tflag & TRAVERS_Typespec){
|
|
gather_recurse_typespec(array, typespec, gflag, tflag);
|
|
}
|
|
else if(gflag & GATHER_Typespec){
|
|
pointer_array_push_typespec(array, typespec);
|
|
}
|
|
}
|
|
}
|
|
|
|
function void
|
|
gather_recurse_decl(Pointer_Array *array, Decl *decl, Gather_Flag gflag, Traversal_Flag tflag){
|
|
if(gflag & GATHER_Decl) pointer_array_push_decl(array, decl);
|
|
|
|
switch(decl->kind){
|
|
case DECL_Struct:
|
|
case DECL_Union:{
|
|
for(Decl *n = decl->struct_decl.first; n; n=n->next){
|
|
gather_recurse_decl(array, n, gflag, tflag);
|
|
}
|
|
} break;
|
|
case DECL_Enum:{
|
|
gather_try_recurse_typespec(array, decl->enum_decl.typespec, gflag, tflag);
|
|
for(Decl_Enum_Child *child = decl->enum_decl.first; child; child=child->next){
|
|
if(gflag & GATHER_Enum_Child) pointer_array_push_enum_child(array, child);
|
|
gather_try_recurse_expr(array, child->expr, gflag, tflag);
|
|
}
|
|
}break;
|
|
case DECL_Variable:{
|
|
gather_try_recurse_typespec(array, decl->variable_decl.type, gflag, tflag);
|
|
gather_try_recurse_expr(array, decl->variable_decl.expr, gflag, tflag);
|
|
}break;
|
|
case DECL_Typedef:{
|
|
gather_try_recurse_typespec(array, decl->typedef_decl.type, gflag, tflag);
|
|
}break;
|
|
case DECL_Function:{
|
|
gather_try_recurse_typespec(array, decl->function_decl.ret, gflag, tflag);
|
|
for(Decl_Function_Arg *arg = decl->function_decl.first; arg; arg=arg->next){
|
|
if(gflag & GATHER_Func_Arg) pointer_array_push_func_arg(array, arg);
|
|
gather_try_recurse_typespec(array, arg->typespec, gflag, tflag);
|
|
}
|
|
gather_try_recurse_stmt(array, decl->function_decl.body, gflag, tflag);
|
|
}break;
|
|
case DECL_List:{
|
|
for(Decl *n = decl->list.first; n; n=n->next){
|
|
gather_recurse_decl(array, n, gflag, tflag);
|
|
}
|
|
}break;
|
|
default:invalid_codepath;
|
|
}
|
|
|
|
}
|
|
|
|
function Pointer_Array
|
|
gather(Arena *arena, Decl *decl, Gather_Flag gflag, Traversal_Flag tflag){
|
|
Pointer_Array array = pointer_array_make(arena);
|
|
gather_recurse_decl(&array, decl, gflag, tflag);
|
|
return array;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function Decl *
|
|
decl_deep_copy_recurse(Arena *arena, Decl *decl){
|
|
Decl *result = arena_push_struct(arena, Decl);
|
|
memory_copy(result, decl, sizeof(*decl));
|
|
switch(decl->kind) {
|
|
case DECL_Struct:{
|
|
|
|
}break;
|
|
case DECL_Union:{
|
|
|
|
}break;
|
|
case DECL_Enum:{
|
|
|
|
}break;
|
|
case DECL_Variable:{
|
|
|
|
}break;
|
|
case DECL_Typedef:{
|
|
|
|
}break;
|
|
case DECL_Function:{
|
|
|
|
}break;
|
|
case DECL_List:{
|
|
|
|
}break;
|
|
default: {invalid_codepath;} break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function Decl *
|
|
decl_deep_copy(Arena *arena){
|
|
Decl *result = decl_deep_copy_recurse(arena, decl);
|
|
return result;
|
|
}
|
|
|
|
|