From 11205f968ad2bf4893fa75df3fc3331f960039d1 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 3 Sep 2016 12:41:03 +0100 Subject: [PATCH] Typesafe variadic procedures --- examples/demo.odin | 27 ++++-- examples/win32.odin | 2 + src/checker/checker.cpp | 2 + src/checker/expr.cpp | 102 +++++++++++++++++++---- src/checker/stmt.cpp | 2 +- src/checker/type.cpp | 25 ++++-- src/codegen/codegen.cpp | 2 +- src/codegen/ssa.cpp | 68 +++++++++++++-- src/parser.cpp | 179 +++++++++++++++++++++++----------------- 9 files changed, 297 insertions(+), 112 deletions(-) diff --git a/examples/demo.odin b/examples/demo.odin index 79cd9643b..a780bef1d 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -3,17 +3,28 @@ #load "game.odin" main :: proc() { - print_int(min(1, 2)); nl() - print_int(max(1, 2)); nl() - print_int(abs(-1337)); nl() - a, b, c := 1, 2, -1337 + print_ints :: proc(args: ..int) { + for i := 0; i < len(args); i++ { + print_int(args[i]) + nl() + } + } + // print_ints() + // print_ints(1) + print_ints(1, 2, 3, 4, 5) - print_int(min(a, b)); nl() - print_int(max(a, b)); nl() - print_int(abs(c) as int); nl() + // print_int(min(1, 2)); nl() + // print_int(max(1, 2)); nl() + // print_int(abs(-1337)); nl() - nl() + // a, b, c := 1, 2, -1337 + + // print_int(min(a, b)); nl() + // print_int(max(a, b)); nl() + // print_int(abs(c) as int); nl() + + // nl() /* Vec3 :: type struct { x, y, z: f32 } Entity :: type struct { diff --git a/examples/win32.odin b/examples/win32.odin index ec543565b..744754b34 100644 --- a/examples/win32.odin +++ b/examples/win32.odin @@ -110,6 +110,8 @@ GetQueryPerformanceFrequency :: proc() -> i64 { return r } +GetCommandLineA :: proc() -> ^u8 #foreign + // File Stuff diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 50d122209..8c95281fc 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -132,6 +132,7 @@ enum BuiltinProcId { BuiltinProc_align_of_val, BuiltinProc_offset_of, BuiltinProc_offset_of_val, + BuiltinProc_type_of_val, BuiltinProc_assert, BuiltinProc_len, @@ -170,6 +171,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("align_of_val"), 1, false, Expr_Expr}, {STR_LIT("offset_of"), 2, false, Expr_Expr}, {STR_LIT("offset_of_val"), 1, false, Expr_Expr}, + {STR_LIT("type_of_val"), 1, false, Expr_Expr}, {STR_LIT("assert"), 1, false, Expr_Stmt}, {STR_LIT("len"), 1, false, Expr_Expr}, diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index ca3667108..dd49e5452 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -459,10 +459,12 @@ void check_enum_type(Checker *c, Type *enum_type, AstNode *node) { enum_type->Record.other_field_count = et->field_count; } -Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize field_count) { +Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize field_count, b32 *is_variadic_) { if (field_list == NULL || field_count == 0) return NULL; + b32 is_variadic = false; + Type *tuple = make_type_tuple(c->allocator); Entity **variables = gb_alloc_array(c->allocator, Entity *, field_count); @@ -471,6 +473,15 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize fiel ast_node(f, Field, field); AstNode *type_expr = f->type; if (type_expr) { + if (type_expr->kind == AstNode_Ellipsis) { + type_expr = type_expr->Ellipsis.expr; + if (field->next == NULL) { + is_variadic = true; + } else { + error(&c->error_collector, ast_node_token(field), "Invalid AST: Invalid variadic parameter"); + } + } + Type *type = check_type(c, type_expr); for (AstNode *name = f->name_list; name != NULL; name = name->next) { if (name->kind == AstNode_Ident) { @@ -478,14 +489,24 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize fiel add_entity(c, scope, name, param); variables[variable_index++] = param; } else { - error(&c->error_collector, ast_node_token(name), "Invalid parameter (invalid AST)"); + error(&c->error_collector, ast_node_token(name), "Invalid AST: Invalid parameter"); } } } } + + if (is_variadic && field_count > 0) { + // NOTE(bill): Change last variadic parameter to be a slice + // Custom Calling convention for variadic parameters + Entity *end = variables[field_count-1]; + end->type = make_type_slice(c->allocator, end->type); + } + tuple->Tuple.variables = variables; tuple->Tuple.variable_count = field_count; + if (is_variadic_) *is_variadic_ = is_variadic; + return tuple; } @@ -520,7 +541,8 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { // gb_printf("%td -> %td\n", param_count, result_count); - Type *params = check_get_params(c, c->context.scope, pt->param_list, param_count); + b32 variadic = false; + Type *params = check_get_params(c, c->context.scope, pt->param_list, param_count, &variadic); Type *results = check_get_results(c, c->context.scope, pt->result_list, result_count); type->Proc.scope = c->context.scope; @@ -528,6 +550,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { type->Proc.param_count = pt->param_count; type->Proc.results = results; type->Proc.result_count = pt->result_count; + type->Proc.variadic = variadic; } @@ -772,10 +795,19 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c goto end; case_end; - default: + default: { + if (e->kind == AstNode_CallExpr) { + Operand o = {}; + check_expr_or_type(c, &o, e); + if (o.mode == Addressing_Type) { + type = o.type; + goto end; + } + } + err_str = expr_to_string(e); error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err_str); - break; + } break; } type = t_invalid; @@ -1894,7 +1926,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_size_of_val: // size_of_val :: proc(val: Type) -> int - check_assignment(c, operand, NULL, make_string("argument of `size_of`")); + check_assignment(c, operand, NULL, make_string("argument of `size_of_val`")); if (operand->mode == Addressing_Invalid) return false; @@ -1917,7 +1949,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_align_of_val: // align_of_val :: proc(val: Type) -> int - check_assignment(c, operand, NULL, make_string("argument of `align_of`")); + check_assignment(c, operand, NULL, make_string("argument of `align_of_val`")); if (operand->mode == Addressing_Invalid) return false; @@ -1996,6 +2028,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->type = t_int; } break; + case BuiltinProc_type_of_val: + // type_of_val :: proc(val: Type) -> type(Type) + check_assignment(c, operand, NULL, make_string("argument of `type_of_val`")); + if (operand->mode == Addressing_Invalid) + return false; + operand->mode = Addressing_Type; + break; + case BuiltinProc_assert: // assert :: proc(cond: bool) @@ -2519,14 +2559,20 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode isize error_code = 0; isize param_index = 0; isize param_count = 0; + b32 variadic = proc_type->Proc.variadic; - if (proc_type->Proc.params) + if (proc_type->Proc.params) { param_count = proc_type->Proc.params->Tuple.variable_count; + } - if (ce->arg_list_count == 0 && param_count == 0) - return; + if (ce->arg_list_count == 0) { + if (variadic && param_count-1 == 0) + return; + if (param_count == 0) + return; + } - if (ce->arg_list_count > param_count) { + if (ce->arg_list_count > param_count && !variadic) { error_code = +1; } else { Entity **sig_params = proc_type->Proc.params->Tuple.variables; @@ -2537,19 +2583,40 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode continue; if (operand->type->kind != Type_Tuple) { check_not_tuple(c, operand); - check_assignment(c, operand, sig_params[param_index]->type, make_string("argument"), true); + isize index = param_index; + b32 end_variadic = false; + if (variadic && param_index >= param_count-1) { + index = param_count-1; + end_variadic = true; + } + Type *arg_type = sig_params[index]->type; + if (end_variadic && is_type_slice(arg_type)) { + arg_type = get_base_type(arg_type)->Slice.elem; + } + check_assignment(c, operand, arg_type, make_string("argument"), true); param_index++; } else { auto *tuple = &operand->type->Tuple; isize i = 0; for (; - i < tuple->variable_count && param_index < param_count; - i++, param_index++) { + i < tuple->variable_count && (param_index < param_count && !variadic); + i++) { Entity *e = tuple->variables[i]; operand->type = e->type; operand->mode = Addressing_Value; check_not_tuple(c, operand); - check_assignment(c, operand, sig_params[param_index]->type, make_string("argument"), true); + isize index = param_index; + b32 end_variadic = false; + if (variadic && param_index >= param_count-1) { + index = param_count-1; + end_variadic = true; + } + Type *arg_type = sig_params[index]->type; + if (end_variadic && is_type_slice(arg_type)) { + arg_type = get_base_type(arg_type)->Slice.elem; + } + check_assignment(c, operand, arg_type, make_string("argument"), true); + param_index++; } if (i < tuple->variable_count && param_index == param_count) { @@ -2558,12 +2625,13 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode } } - if (param_index >= param_count) + if (!variadic && param_index >= param_count) break; } - if (param_index < param_count) { + if ((!variadic && param_index < param_count) || + (variadic && param_index < param_count-1)) { error_code = -1; } else if (call_arg != NULL && call_arg->next != NULL) { error_code = +1; diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 3508321c7..803e777de 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -421,7 +421,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { GB_ASSERT(e->type == NULL); - Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0); + Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false); e->type = proc_type; ast_node(pd, ProcDecl, d->proc_decl); check_open_scope(c, pd->type); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 2ff004636..16453b4dc 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -149,6 +149,7 @@ struct Type { Type * results; // Type_Tuple isize param_count; isize result_count; + b32 variadic; } Proc; }; }; @@ -240,13 +241,27 @@ Type *make_type_tuple(gbAllocator a) { return t; } -Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count) { +Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count, b32 variadic) { Type *t = alloc_type(a, Type_Proc); - t->Proc.scope = scope; - t->Proc.params = params; - t->Proc.param_count = param_count; - t->Proc.results = results; + + if (variadic) { + if (param_count == 0) { + GB_PANIC("variadic procedure must have at least one parameter"); + } + GB_ASSERT(params != NULL && params->kind == Type_Tuple); + Entity *e = params->Tuple.variables[param_count-1]; + if (get_base_type(e->type)->kind != Type_Slice) { + // NOTE(bill): For custom calling convention + GB_PANIC("variadic parameter must be of type slice"); + } + } + + t->Proc.scope = scope; + t->Proc.params = params; + t->Proc.param_count = param_count; + t->Proc.results = results; t->Proc.result_count = result_count; + t->Proc.variadic = variadic; return t; } diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 8235fb615..735dfd580 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -131,7 +131,7 @@ void ssa_gen_code(ssaGen *s) { String name = make_string(SSA_STARTUP_RUNTIME_PROC_NAME); Type *proc_type = make_type_proc(a, gb_alloc_item(a, Scope), NULL, 0, - NULL, 0); + NULL, 0, false); AstNode *body = gb_alloc_item(a, AstNode); ssaValue *p = ssa_make_value_procedure(a, m, proc_type, NULL, body, name); Token token = {}; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 0616a9302..24a350034 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -2159,10 +2159,23 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue auto *type = &proc_type_->Proc; isize arg_index = 0; - isize arg_count = type->param_count; - ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, arg_count); - for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) { + isize arg_count = 0; + for (AstNode *a = ce->arg_list; a != NULL; a = a->next) { + Type *at = get_base_type(type_of_expr(proc->module->info, a)); + if (at->kind == Type_Tuple) { + arg_count += at->Tuple.variable_count; + } else { + arg_count++; + } + } + ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, arg_count); + b32 variadic = proc_type_->Proc.variadic; + + AstNode *arg = ce->arg_list; + for (; + arg != NULL; + arg = arg->next) { ssaValue *a = ssa_build_expr(proc, arg); Type *at = ssa_type(a); if (at->kind == Type_Tuple) { @@ -2176,11 +2189,54 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } } - auto *pt = &proc_type_->Proc.params->Tuple; - for (isize i = 0; i < arg_count; i++) { - args[i] = ssa_emit_conv(proc, args[i], pt->variables[i]->type, true); + auto *pt = &type->params->Tuple; + + if (variadic) { + isize i = 0; + for (; i < type->param_count-1; i++) { + args[i] = ssa_emit_conv(proc, args[i], pt->variables[i]->type, true); + } + Type *variadic_type = pt->variables[i]->type; + GB_ASSERT(is_type_slice(variadic_type)); + variadic_type = get_base_type(variadic_type)->Slice.elem; + for (; i < arg_count; i++) { + args[i] = ssa_emit_conv(proc, args[i], variadic_type, true); + } + } else { + for (isize i = 0; i < arg_count; i++) { + args[i] = ssa_emit_conv(proc, args[i], pt->variables[i]->type, true); + } } + if (variadic) { + gbAllocator allocator = proc->module->allocator; + Type *slice_type = pt->variables[type->param_count-1]->type; + Type *elem_type = get_base_type(slice_type)->Slice.elem; + Type *elem_ptr_type = make_type_pointer(allocator, elem_type); + ssaValue *slice = ssa_add_local_generated(proc, slice_type); + isize slice_len = arg_count+1 - type->param_count; + + if (slice_len > 0) { + ssaValue *base_array = ssa_add_local_generated(proc, make_type_array(allocator, elem_type, slice_len)); + + for (isize i = type->param_count-1, j = 0; i < arg_count; i++, j++) { + ssaValue *addr = ssa_emit_struct_gep(proc, base_array, j, elem_type); + ssa_emit_store(proc, addr, args[i]); + } + + ssaValue *base_elem = ssa_emit_struct_gep(proc, base_array, v_zero32, elem_type); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_zero32, elem_ptr_type), base_elem); + ssaValue *len = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(slice_len)); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_one32, t_int), len); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_two32, t_int), len); + } + + + arg_count = type->param_count; + args[arg_count-1] = ssa_emit_load(proc, slice); + } + + return ssa_emit_call(proc, value, args, arg_count); case_end; diff --git a/src/parser.cpp b/src/parser.cpp index 478e1377a..8ba398020 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -77,6 +77,10 @@ enum CallExprKind { AST_NODE_KIND(Invalid, "invalid node", struct{}) \ AST_NODE_KIND(BasicLit, "basic literal", Token) \ AST_NODE_KIND(Ident, "identifier", Token) \ + AST_NODE_KIND(Ellipsis, "ellipsis", struct { \ + Token token; \ + AstNode *expr; \ + }) \ AST_NODE_KIND(ProcLit, "procedure literal", struct { \ AstNode *type; \ AstNode *body; \ @@ -110,7 +114,6 @@ AST_NODE_KIND(_ExprBegin, "", struct{}) \ b32 triple_indexed; \ }) \ AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \ - AST_NODE_KIND(Ellipsis, "ellipsis", struct { Token token; }) \ AST_NODE_KIND(_ExprEnd, "", struct{}) \ AST_NODE_KIND(_StmtBegin, "", struct{}) \ AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \ @@ -542,11 +545,6 @@ gb_inline AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) { } -gb_inline AstNode *make_ellipsis(AstFile *f, Token token) { - AstNode *result = make_node(f, AstNode_Ellipsis); - result->Ellipsis.token = token; - return result; -} gb_inline AstNode *make_basic_lit(AstFile *f, Token basic_lit) { AstNode *result = make_node(f, AstNode_BasicLit); result->BasicLit = basic_lit; @@ -559,6 +557,14 @@ gb_inline AstNode *make_ident(AstFile *f, Token token) { return result; } +gb_inline AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) { + AstNode *result = make_node(f, AstNode_Ellipsis); + result->Ellipsis.token = token; + result->Ellipsis.expr = expr; + return result; +} + + gb_inline AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags) { AstNode *result = make_node(f, AstNode_ProcLit); result->ProcLit.type = type; @@ -1253,6 +1259,37 @@ b32 is_literal_type(AstNode *node) { return false; } +AstNode *parse_call_expr(AstFile *f, AstNode *operand) { + AstNode *arg_list = NULL; + AstNode *arg_list_curr = NULL; + isize arg_list_count = 0; + Token open_paren, close_paren; + + f->expr_level++; + open_paren = expect_token(f, Token_OpenParen); + + while (f->cursor[0].kind != Token_CloseParen && + f->cursor[0].kind != Token_EOF) { + if (f->cursor[0].kind == Token_Comma) + ast_file_err(f, f->cursor[0], "Expected an expression not a ,"); + + DLIST_APPEND(arg_list, arg_list_curr, parse_expr(f, false)); + arg_list_count++; + + if (f->cursor[0].kind != Token_Comma) { + if (f->cursor[0].kind == Token_CloseParen) + break; + } + + next_token(f); + } + + f->expr_level--; + close_paren = expect_token(f, Token_CloseParen); + + return make_call_expr(f, operand, arg_list, arg_list_count, open_paren, close_paren); +} + AstNode *parse_atom_expr(AstFile *f, b32 lhs) { AstNode *operand = parse_operand(f, lhs); @@ -1273,34 +1310,7 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { if (lhs) { // TODO(bill): Handle this shit! Is this even allowed in this language?! } - AstNode *arg_list = NULL; - AstNode *arg_list_curr = NULL; - isize arg_list_count = 0; - Token open_paren, close_paren; - - f->expr_level++; - open_paren = expect_token(f, Token_OpenParen); - - while (f->cursor[0].kind != Token_CloseParen && - f->cursor[0].kind != Token_EOF) { - if (f->cursor[0].kind == Token_Comma) - ast_file_err(f, f->cursor[0], "Expected an expression not a ,"); - - DLIST_APPEND(arg_list, arg_list_curr, parse_expr(f, false)); - arg_list_count++; - - if (f->cursor[0].kind != Token_Comma) { - if (f->cursor[0].kind == Token_CloseParen) - break; - } - - next_token(f); - } - - f->expr_level--; - close_paren = expect_token(f, Token_CloseParen); - - operand = make_call_expr(f, operand, arg_list, arg_list_count, open_paren, close_paren); + operand = parse_call_expr(f, operand); } break; case Token_Period: { @@ -1617,34 +1627,6 @@ AstNode *parse_type(AstFile *f) { return type; } -AstNode *parse_field_decl(AstFile *f, b32 allow_using) { - b32 is_using = false; - AstNode *name_list = NULL; - isize name_count = 0; - if (allow_using) { - if (allow_token(f, Token_using)) { - is_using = true; - } - } - - name_list = parse_lhs_expr_list(f, &name_count); - if (name_count == 0) - ast_file_err(f, f->cursor[0], "Empty field declaration"); - - if (name_count > 1 && is_using) { - ast_file_err(f, f->cursor[0], "Cannot apply `using` to more than one of the same type"); - } - - - expect_token(f, Token_Colon); - - AstNode *type = parse_type_attempt(f); - if (type == NULL) - ast_file_err(f, f->cursor[0], "Expected a type for this field declaration"); - - AstNode *field = make_field(f, name_list, name_count, type, is_using); - return field; -} Token parse_procedure_signature(AstFile *f, AstNode **param_list, isize *param_count, @@ -1661,20 +1643,65 @@ AstNode *parse_proc_type(AstFile *f) { return make_proc_type(f, proc_token, params, param_count, results, result_count); } +AstNode *parse_field_decl(AstFile *f) { + AstNode *name_list = NULL; + isize name_count = 0; + b32 is_using = false; + if (allow_token(f, Token_using)) { + is_using = true; + } -AstNode *parse_parameter_list(AstFile *f, isize *param_count_, TokenKind separator, b32 allow_using) { + name_list = parse_lhs_expr_list(f, &name_count); + if (name_count == 0) { + ast_file_err(f, f->cursor[0], "Empty field declaration"); + } + + if (name_count > 1 && is_using) { + ast_file_err(f, f->cursor[0], "Cannot apply `using` to more than one of the same type"); + is_using = false; + } + + + expect_token(f, Token_Colon); + + AstNode *type = NULL; + if (f->cursor[0].kind == Token_Ellipsis) { + Token ellipsis = f->cursor[0]; + next_token(f); + type = parse_type_attempt(f); + if (type == NULL) { + ast_file_err(f, f->cursor[0], "variadic parameter is missing a type after `..`"); + type = make_bad_expr(f, ellipsis, f->cursor[0]); + } else { + if (name_count > 1) { + ast_file_err(f, f->cursor[0], "mutliple variadic parameters, only 1 is allowed"); + type = make_bad_expr(f, ellipsis, f->cursor[0]); + } else { + type = make_ellipsis(f, ellipsis, type); + } + } + } else { + type = parse_type_attempt(f); + } + + if (type == NULL) { + ast_file_err(f, f->cursor[0], "Expected a type for this field declaration"); + } + + AstNode *field = make_field(f, name_list, name_count, type, is_using); + return field; +} + +AstNode *parse_parameter_list(AstFile *f, isize *param_count_) { AstNode *param_list = NULL; AstNode *param_list_curr = NULL; isize param_count = 0; while (f->cursor[0].kind == Token_Identifier || - (allow_using && f->cursor[0].kind == Token_using)) { - if (!allow_using && allow_token(f, Token_using)) { - ast_file_err(f, f->cursor[-1], "`using` is only allowed within structures (at the moment)"); - } - AstNode *field = parse_field_decl(f, allow_using); + f->cursor[0].kind == Token_using) { + AstNode *field = parse_field_decl(f); DLIST_APPEND(param_list, param_list_curr, field); param_count += field->Field.name_count; - if (f->cursor[0].kind != separator) + if (f->cursor[0].kind != Token_Comma) break; next_token(f); } @@ -1746,14 +1773,18 @@ AstNode *parse_struct_params(AstFile *f, isize *decl_count_) { AstNode *parse_identifier_or_type(AstFile *f) { switch (f->cursor[0].kind) { case Token_Identifier: { - AstNode *ident = parse_identifier(f); + AstNode *e = parse_identifier(f); while (f->cursor[0].kind == Token_Period) { Token token = f->cursor[0]; next_token(f); AstNode *sel = parse_identifier(f); - ident = make_selector_expr(f, token, ident, sel); + e = make_selector_expr(f, token, e, sel); } - return ident; + if (f->cursor[0].kind == Token_OpenParen) { + // HACK NOTE(bill): For type_of_val(expr) + e = parse_call_expr(f, e); + } + return e; } case Token_Pointer: @@ -1765,7 +1796,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { AstNode *count_expr = NULL; if (f->cursor[0].kind == Token_Ellipsis) { - count_expr = make_ellipsis(f, f->cursor[0]); + count_expr = make_ellipsis(f, f->cursor[0], NULL); next_token(f); } else if (f->cursor[0].kind != Token_CloseBracket) { count_expr = parse_expr(f, false); @@ -1922,7 +1953,7 @@ Token parse_procedure_signature(AstFile *f, AstNode **result_list, isize *result_count) { Token proc_token = expect_token(f, Token_proc); expect_token(f, Token_OpenParen); - *param_list = parse_parameter_list(f, param_count, Token_Comma, true); + *param_list = parse_parameter_list(f, param_count); expect_token(f, Token_CloseParen); *result_list = parse_results(f, result_count); return proc_token;