diff options
| author | gingerBill <bill@gingerbill.org> | 2017-10-29 15:46:23 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2017-10-29 15:46:23 +0000 |
| commit | 1eb9994d88b874b2f4ac3fdc4d314b1e67fa511b (patch) | |
| tree | 5dd176e7f4e8677ea935762e7044a4d6e3265520 /src | |
| parent | a43b89f36e988df8268ee92ea54017806b3226bb (diff) | |
Attributes; @(link_name="foo")
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_decl.cpp | 97 | ||||
| -rw-r--r-- | src/check_expr.cpp | 7 | ||||
| -rw-r--r-- | src/check_stmt.cpp | 2 | ||||
| -rw-r--r-- | src/checker.cpp | 14 | ||||
| -rw-r--r-- | src/ir.cpp | 41 | ||||
| -rw-r--r-- | src/ir_print.cpp | 17 | ||||
| -rw-r--r-- | src/parser.cpp | 170 | ||||
| -rw-r--r-- | src/ssa.cpp | 4 | ||||
| -rw-r--r-- | src/tokenizer.cpp | 2 | ||||
| -rw-r--r-- | src/types.cpp | 11 |
10 files changed, 260 insertions, 105 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 0baf43349..1361ac31c 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -187,8 +187,13 @@ AstNode *remove_type_alias(AstNode *node) { void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, bool is_alias) { GB_ASSERT(e->type == nullptr); - AstNode *te = remove_type_alias(type_expr); + DeclInfo *decl = decl_info_of_entity(&c->info, e); + if (decl != nullptr && decl->attributes.count > 0) { + error(decl->attributes[0], "Attributes are not allowed on type declarations"); + } + + AstNode *te = remove_type_alias(type_expr); e->type = t_invalid; String name = e->token.string; Type *named = make_type_named(c->allocator, name, nullptr, e); @@ -203,8 +208,11 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, bool if (is_alias) { if (is_type_named(bt)) { e->type = bt; + e->TypeName.is_type_alias = true; } else { - warning(type_expr, "Type declaration will not be an alias type"); + gbString str = type_to_string(bt); + error(type_expr, "Type alias declaration with a non-named type `%s`", str); + gb_string_free(str); } } } @@ -319,6 +327,12 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, error(e->token, "Invalid declaration type `%s`", str); gb_string_free(str); } + + + DeclInfo *decl = decl_info_of_entity(&c->info, e); + if (decl != nullptr && decl->attributes.count > 0) { + error(decl->attributes[0], "Attributes are not allowed on constant value declarations"); + } } @@ -436,8 +450,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { defer (check_close_scope(c)); - - auto prev_context = c->context; c->context.allow_polymorphic_types = true; check_procedure_type(c, proc_type, pl->type); @@ -447,11 +459,65 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { bool is_foreign = e->Procedure.is_foreign; bool is_export = e->Procedure.is_export; - bool is_link_name = (pl->tags & ProcTag_link_name) != 0; bool is_inline = (pl->tags & ProcTag_inline) != 0; bool is_no_inline = (pl->tags & ProcTag_no_inline) != 0; bool is_require_results = (pl->tags & ProcTag_require_results) != 0; + String link_name = {}; + + + if (d != nullptr && d->attributes.count > 0) { + for_array(i, d->attributes) { + AstNode *attr = d->attributes[i]; + if (attr->kind != AstNode_Attribute) continue; + for_array(j, attr->Attribute.elems) { + AstNode *elem = attr->Attribute.elems[j]; + String name = {}; + AstNode *value = nullptr; + + switch (elem->kind) { + case_ast_node(i, Ident, elem); + name = i->token.string; + case_end; + case_ast_node(fv, FieldValue, elem); + GB_ASSERT(fv->field->kind == AstNode_Ident); + name = fv->field->Ident.token.string; + value = fv->value; + case_end; + default: + error(elem, "Invalid attribute element"); + continue; + } + + ExactValue ev = {}; + if (value != nullptr) { + Operand op = {}; + check_expr(c, &op, value); + if (op.mode != Addressing_Constant) { + error(value, "An attribute element must be constant"); + } else { + ev = op.value; + } + } + + if (name == "link_name") { + if (link_name.len > 0) { + error(elem, "Previous declaration of `link_name`"); + } + if (ev.kind == ExactValue_String) { + link_name = ev.value_string; + } else { + error(elem, "Expected a string value for `link_name`"); + } + } else { + error(elem, "Unknown attribute element name `%.*s`", LIT(name)); + } + } + } + } + + + if (d->scope->file != nullptr && e->token.string == "main") { @@ -526,8 +592,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { if (is_foreign) { String name = e->token.string; - if (pl->link_name.len > 0) { - name = pl->link_name; + if (link_name.len > 0) { + name = link_name; } e->Procedure.is_foreign = true; e->Procedure.link_name = name; @@ -562,11 +628,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { } } else { String name = e->token.string; - if (is_link_name) { - name = pl->link_name; + if (link_name.len > 0) { + name = link_name; } - if (is_link_name || is_export) { + if (link_name.len > 0 || is_export) { auto *fp = &c->info.foreigns; e->Procedure.link_name = name; @@ -600,6 +666,11 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } e->flags |= EntityFlag_Visited; + DeclInfo *decl = decl_info_of_entity(&c->info, e); + if (decl != nullptr && decl->attributes.count > 0) { + error(decl->attributes[0], "Attributes are not allowed on variable declarations, yet"); + } + String context_name = str_lit("variable declaration"); if (type_expr != nullptr) { @@ -692,9 +763,11 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { case Entity_Constant: check_const_decl(c, e, d->type_expr, d->init_expr, named_type); break; - case Entity_TypeName: - check_type_decl(c, e, d->type_expr, named_type, d->type_expr->kind == AstNode_AliasType); + case Entity_TypeName: { + bool is_alias = unparen_expr(d->type_expr)->kind == AstNode_AliasType; + check_type_decl(c, e, d->type_expr, named_type, is_alias); break; + } case Entity_Procedure: check_proc_decl(c, e, d); break; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2f3bc4fdf..02c4fbf64 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1238,6 +1238,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type case Basic_u64: case Basic_u128: case Basic_uint: + case Basic_uintptr: return !(u128_lt(u, U128_ZERO) || u128_gt(u, umax)); case Basic_UntypedInteger: @@ -1759,10 +1760,10 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { } // (u)int <-> rawptr - if (is_type_int_or_uint(src) && is_type_rawptr(dst)) { + if (is_type_uintptr(src) && is_type_rawptr(dst)) { return true; } - if (is_type_rawptr(src) && is_type_int_or_uint(dst)) { + if (is_type_rawptr(src) && is_type_uintptr(dst)) { return true; } @@ -2520,7 +2521,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h bool is_declared = entity != nullptr; if (is_declared) { if (entity->kind == Entity_Builtin) { - // NOTE(bill): Builtin's are in the universe scope which is part of every scopes hierarchy + // NOTE(bill): Builtin's are in the universal scope which is part of every scopes hierarchy // This means that we should just ignore the found result through it is_declared = false; } else if (entity->scope->is_global && !import_scope->is_global) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index d7caae280..7cbf479e4 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -206,7 +206,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { check_expr(c, &lhs, lhs_node); if (lhs.mode == Addressing_Invalid || - lhs.type == t_invalid) { + (lhs.type == t_invalid && lhs.mode != Addressing_Overload)) { return nullptr; } diff --git a/src/checker.cpp b/src/checker.cpp index d6bbf754d..35744585a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -182,6 +182,7 @@ struct DeclInfo { AstNode * type_expr; AstNode * init_expr; Array<AstNode *> init_expr_list; + Array<AstNode *> attributes; AstNode * proc_lit; // AstNode_ProcLit Type * gen_proc_type; // Precalculated @@ -1720,11 +1721,14 @@ void init_preload(Checker *c) { { String _global = str_lit("_global"); - Entity *e = make_entity_import_name(c->allocator, c->global_scope->parent, make_token_ident(_global), t_invalid, + Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info")); + Scope *preload_scope = type_info_entity->scope; + + Entity *e = make_entity_import_name(c->allocator, preload_scope, make_token_ident(_global), t_invalid, str_lit(""), _global, - c->global_scope); + preload_scope); - add_entity(c, c->global_scope, nullptr, e); + add_entity(c, universal_scope, nullptr, e); } c->done_preload = true; @@ -1999,6 +2003,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { d->type_expr = vd->type; d->init_expr = init_expr; } + d->attributes = vd->attributes; add_entity_and_decl_info(c, name, e, d); } @@ -2028,6 +2033,8 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl); Entity *e = nullptr; + d->attributes = vd->attributes; + if (is_ast_node_type(init) || (vd->type != nullptr && vd->type->kind == AstNode_TypeType)) { e = make_entity_type_name(c->allocator, d->scope, token, nullptr); @@ -2069,6 +2076,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { } } + add_entity_and_decl_info(c, name, e, d); } diff --git a/src/ir.cpp b/src/ir.cpp index 9b018a2ea..23dfd081e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2852,19 +2852,19 @@ String ir_lookup_subtype_polymorphic_field(CheckerInfo *info, Type *dst, Type *s } -irValue *ir_emit_ptr_to_int(irProcedure *proc, irValue *value, Type *t, bool allow_type_type = false) { +irValue *ir_emit_ptr_to_uintptr(irProcedure *proc, irValue *value, Type *t, bool allow_type_type = false) { Type *vt = core_type(ir_type(value)); GB_ASSERT(is_type_pointer(vt)); if (allow_type_type) { - GB_ASSERT(is_type_int_or_uint(core_type(t))); + GB_ASSERT(is_type_uintptr(core_type(t))); } else { - GB_ASSERT(is_type_int_or_uint(core_type(t))); + GB_ASSERT(is_type_uintptr(core_type(t))); } return ir_emit(proc, ir_instr_conv(proc, irConv_ptrtoint, value, vt, t)); } -irValue *ir_emit_int_to_ptr(irProcedure *proc, irValue *value, Type *t) { +irValue *ir_emit_uintptr_to_ptr(irProcedure *proc, irValue *value, Type *t) { Type *vt = core_type(ir_type(value)); - GB_ASSERT(is_type_int_or_uint(vt)); + GB_ASSERT(is_type_uintptr(vt)); GB_ASSERT(is_type_pointer(core_type(t))); return ir_emit(proc, ir_instr_conv(proc, irConv_inttoptr, value, vt, t)); } @@ -3028,11 +3028,11 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { } // Pointer <-> int - if (is_type_pointer(src) && is_type_int_or_uint(dst)) { - return ir_emit_ptr_to_int(proc, value, t); + if (is_type_pointer(src) && is_type_uintptr(dst)) { + return ir_emit_ptr_to_uintptr(proc, value, t); } - if (is_type_int_or_uint(src) && is_type_pointer(dst)) { - return ir_emit_int_to_ptr(proc, value, t); + if (is_type_uintptr(src) && is_type_pointer(dst)) { + return ir_emit_uintptr_to_ptr(proc, value, t); } if (is_type_union(dst)) { @@ -3250,11 +3250,11 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) { GB_ASSERT_MSG(sz == dz, "Invalid transmute conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); // NOTE(bill): Casting between an integer and a pointer cannot be done through a bitcast - if (is_type_int_or_uint(src) && is_type_pointer(dst)) { - return ir_emit_int_to_ptr(proc, value, t); + if (is_type_uintptr(src) && is_type_pointer(dst)) { + return ir_emit_uintptr_to_ptr(proc, value, t); } - if (is_type_pointer(src) && is_type_int_or_uint(dst)) { - return ir_emit_ptr_to_int(proc, value, t); + if (is_type_pointer(src) && is_type_uintptr(dst)) { + return ir_emit_ptr_to_uintptr(proc, value, t); } if (ir_is_type_aggregate(src) || ir_is_type_aggregate(dst)) { @@ -5886,8 +5886,8 @@ void ir_build_poly_proc(irProcedure *proc, AstNodeProcLit *pd, Entity *e) { // parent.name-guid String original_name = e->token.string; String pd_name = original_name; - if (pd->link_name.len > 0) { - pd_name = pd->link_name; + if (e->Procedure.link_name.len > 0) { + pd_name = e->Procedure.link_name; } isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1; @@ -5978,8 +5978,8 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) { // FFI - Foreign function interace String original_name = e->token.string; String name = original_name; - if (pl->link_name.len > 0) { - name = pl->link_name; + if (e->Procedure.link_name.len > 0) { + name = e->Procedure.link_name; } irValue *value = ir_value_procedure(proc->module->allocator, @@ -7749,7 +7749,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info case Basic_i128: case Basic_u128: case Basic_int: - case Basic_uint: { + case Basic_uint: + case Basic_uintptr: { tag = ir_emit_conv(proc, variant_ptr, t_type_info_integer_ptr); irValue *is_signed = ir_const_bool(a, (t->Basic.flags & BasicFlag_Unsigned) == 0); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), is_signed); @@ -8286,8 +8287,8 @@ void ir_gen_tree(irGen *s) { name = e->token.string; // NOTE(bill): Don't use the mangled name ir_add_foreign_library_path(m, e->Procedure.foreign_library); } - if (pl->link_name.len > 0) { - name = pl->link_name; + if (e->Procedure.link_name.len > 0) { + name = e->Procedure.link_name; } AstNode *type_expr = pl->type; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index edf2665c7..725c08d02 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -245,14 +245,15 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { case Basic_f64: ir_write_string(f, "double"); return; // case Basic_complex32: ir_write_string(f, "%%..complex32"); return; - case Basic_complex64: ir_write_string(f, "%..complex64"); return; - case Basic_complex128: ir_write_string(f, "%..complex128"); return; - - case Basic_rawptr: ir_write_string(f, "%..rawptr"); return; - case Basic_string: ir_write_string(f, "%..string"); return; - case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return; - case Basic_int: ir_fprintf(f, "i%lld", word_bits); return; - case Basic_any: ir_write_string(f, "%..any"); return; + case Basic_complex64: ir_write_string(f, "%..complex64"); return; + case Basic_complex128: ir_write_string(f, "%..complex128"); return; + + case Basic_rawptr: ir_write_string(f, "%..rawptr"); return; + case Basic_string: ir_write_string(f, "%..string"); return; + case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return; + case Basic_int: ir_fprintf(f, "i%lld", word_bits); return; + case Basic_uintptr: ir_fprintf(f, "i%lld", word_bits); return; + case Basic_any: ir_write_string(f, "%..any"); return; } break; case Type_Pointer: { diff --git a/src/parser.cpp b/src/parser.cpp index 94a4e7585..c2a4dc4e4 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -167,10 +167,9 @@ Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) { AstNode *expr; \ }) \ AST_NODE_KIND(ProcLit, "procedure literal", struct { \ - AstNode *type; \ - AstNode *body; \ - u64 tags; \ - String link_name; \ + AstNode *type; \ + AstNode *body; \ + u64 tags; \ }) \ AST_NODE_KIND(CompoundLit, "compound literal", struct { \ AstNode *type; \ @@ -347,6 +346,7 @@ AST_NODE_KIND(_DeclBegin, "", i32) \ u64 flags; \ bool is_mutable; \ bool been_handled; \ + Array<AstNode *> attributes; \ CommentGroup docs; \ CommentGroup comment; \ }) \ @@ -382,12 +382,18 @@ AST_NODE_KIND(_DeclBegin, "", i32) \ CommentGroup comment; \ }) \ AST_NODE_KIND(_DeclEnd, "", i32) \ + AST_NODE_KIND(Attribute, "attribute", struct { \ + Token token; \ + AstNode *type; \ + Array<AstNode *> elems; \ + Token open, close; \ + }) \ AST_NODE_KIND(Field, "field", struct { \ Array<AstNode *> names; \ AstNode * type; \ AstNode * default_value; \ u32 flags; \ - CommentGroup docs; \ + CommentGroup docs; \ CommentGroup comment; \ }) \ AST_NODE_KIND(FieldList, "field list", struct { \ @@ -602,6 +608,8 @@ Token ast_node_token(AstNode *node) { case AstNode_ForeignBlockDecl: return node->ForeignBlockDecl.token; + case AstNode_Attribute: + return node->Attribute.token; case AstNode_Field: if (node->Field.names.count > 0) { @@ -842,8 +850,12 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) { n->ValueDecl.names = clone_ast_node_array(a, n->ValueDecl.names); n->ValueDecl.type = clone_ast_node(a, n->ValueDecl.type); n->ValueDecl.values = clone_ast_node_array(a, n->ValueDecl.values); + n->ValueDecl.attributes = clone_ast_node_array(a, n->ValueDecl.attributes); break; + case AstNode_Attribute: + n->Attribute.elems = clone_ast_node_array(a, n->Attribute.elems); + break; case AstNode_Field: n->Field.names = clone_ast_node_array(a, n->Field.names); n->Field.type = clone_ast_node(a, n->Field.type); @@ -937,7 +949,7 @@ void syntax_error(AstNode *node, char *fmt, ...) { bool ast_node_expect(AstNode *node, AstNodeKind kind) { if (node->kind != kind) { - error(node, "Expected %.*s, got %.*s", LIT(ast_node_strings[node->kind])); + syntax_error(node, "Expected %.*s, got %.*s", LIT(ast_node_strings[node->kind])); return false; } return true; @@ -1124,12 +1136,11 @@ AstNode *ast_ellipsis(AstFile *f, Token token, AstNode *expr) { } -AstNode *ast_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String link_name) { +AstNode *ast_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags) { AstNode *result = make_ast_node(f, AstNode_ProcLit); result->ProcLit.type = type; result->ProcLit.body = body; result->ProcLit.tags = tags; - result->ProcLit.link_name = link_name; return result; } @@ -1556,6 +1567,8 @@ AstNode *ast_value_decl(AstFile *f, Array<AstNode *> names, AstNode *type, Array result->ValueDecl.is_mutable = is_mutable; result->ValueDecl.docs = docs; result->ValueDecl.comment = comment; + + result->ValueDecl.attributes.allocator = heap_allocator(); return result; } @@ -1593,6 +1606,16 @@ AstNode *ast_foreign_import_decl(AstFile *f, Token token, Token filepath, Token } +AstNode *ast_attribute(AstFile *f, Token token, Token open, Token close, Array<AstNode *> elems) { + AstNode *result = make_ast_node(f, AstNode_Attribute); + result->Attribute.token = token; + result->Attribute.open = open; + result->Attribute.elems = elems; + result->Attribute.close = close; + return result; +} + + bool next_token0(AstFile *f) { // Token prev = f->curr_token; if (f->curr_token_index+1 < f->tokens.count) { @@ -1831,7 +1854,7 @@ Token expect_closing(AstFile *f, TokenKind kind, String context) { if (f->curr_token.kind != kind && f->curr_token.kind == Token_Semicolon && f->curr_token.string == "\n") { - error(f->curr_token, "Missing `,` before newline in %.*s", LIT(context)); + syntax_error(f->curr_token, "Missing `,` before newline in %.*s", LIT(context)); advance_token(f); } return expect_token(f, kind); @@ -1854,6 +1877,11 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) { case AstNode_TypeSwitchStmt: return true; + case AstNode_HelperType: + return is_semicolon_optional_for_node(f, s->HelperType.type); + case AstNode_AliasType: + return is_semicolon_optional_for_node(f, s->AliasType.type); + case AstNode_PointerType: return is_semicolon_optional_for_node(f, s->PointerType.type); @@ -1925,7 +1953,7 @@ void expect_semicolon(AstFile *f, AstNode *s) { AstNode * parse_expr(AstFile *f, bool lhs); -AstNode * parse_proc_type(AstFile *f, Token proc_token, String *link_name); +AstNode * parse_proc_type(AstFile *f, Token proc_token); Array<AstNode *> parse_stmt_list(AstFile *f); AstNode * parse_stmt(AstFile *f); AstNode * parse_body(AstFile *f); @@ -2066,9 +2094,8 @@ bool is_foreign_name_valid(String name) { return true; } -void parse_proc_tags(AstFile *f, u64 *tags, String *link_name, ProcCallingConvention *calling_convention) { - GB_ASSERT(tags != nullptr); - GB_ASSERT(link_name != nullptr); +void parse_proc_tags(AstFile *f, u64 *tags, ProcCallingConvention *calling_convention) { + GB_ASSERT(tags != nullptr); ProcCallingConvention cc = ProcCC_Invalid; @@ -2082,24 +2109,10 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *link_name, ProcCallingConven check_proc_add_tag(f, tag_expr, tags, ProcTag_##name, tag_name); \ } - if (tag_name == "link_name") { - check_proc_add_tag(f, tag_expr, tags, ProcTag_link_name, tag_name); - if (f->curr_token.kind == Token_String) { - *link_name = f->curr_token.string; - if (!is_foreign_name_valid(*link_name)) { - syntax_error(tag_expr, "Invalid alternative link procedure name `%.*s`", LIT(*link_name)); - } - - advance_token(f); - } else { - expect_token(f, Token_String); - } - } + if (false) {} ELSE_IF_ADD_TAG(require_results) ELSE_IF_ADD_TAG(bounds_check) ELSE_IF_ADD_TAG(no_bounds_check) - ELSE_IF_ADD_TAG(inline) - ELSE_IF_ADD_TAG(no_inline) else if (tag_name == "cc_odin") { if (cc == ProcCC_Invalid) { cc = ProcCC_Odin; @@ -2278,7 +2291,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { AstNode *expr = parse_expr(f, false); operand = ast_run_expr(f, token, name, expr); if (unparen_expr(expr)->kind != AstNode_CallExpr) { - error(expr, "#run can only be applied to procedure calls"); + syntax_error(expr, "#run can only be applied to procedure calls"); operand = ast_bad_expr(f, token, f->curr_token); } warning(token, "#run is not yet implemented"); @@ -2295,11 +2308,27 @@ AstNode *parse_operand(AstFile *f, bool lhs) { return operand; } + case Token_inline: + case Token_no_inline: + { + Token token = advance_token(f); + AstNode *expr = parse_operand(f, false); + if (expr->kind != AstNode_ProcLit) { + syntax_error(expr, "%.*s must be followed by a procedure literal, got %.*s", LIT(token.string), LIT(ast_node_strings[expr->kind])); + return ast_bad_expr(f, token, f->curr_token); + } + if (token.kind == Token_inline) { + expr->ProcLit.tags |= ProcTag_inline; + } else if (token.kind == Token_no_inline) { + expr->ProcLit.tags |= ProcTag_no_inline; + } + return expr; + } break; + // Parse Procedure Type or Literal case Token_proc: { Token token = expect_token(f, Token_proc); - String link_name = {}; - AstNode *type = parse_proc_type(f, token, &link_name); + AstNode *type = parse_proc_type(f, token); if (f->allow_type && f->expr_level < 0) { return type; @@ -2308,7 +2337,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { u64 tags = type->ProcType.tags; if (allow_token(f, Token_Undef)) { - return ast_proc_lit(f, type, nullptr, tags, link_name); + return ast_proc_lit(f, type, nullptr, tags); } else if (f->curr_token.kind == Token_OpenBrace) { AstNode *curr_proc = f->curr_proc; AstNode *body = nullptr; @@ -2316,7 +2345,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { body = parse_body(f); f->curr_proc = curr_proc; - return ast_proc_lit(f, type, body, tags, link_name); + return ast_proc_lit(f, type, body, tags); } else if (allow_token(f, Token_do)) { AstNode *curr_proc = f->curr_proc; AstNode *body = nullptr; @@ -2324,7 +2353,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { body = convert_stmt_to_body(f, parse_stmt(f)); f->curr_proc = curr_proc; - return ast_proc_lit(f, type, body, tags, link_name); + return ast_proc_lit(f, type, body, tags); } if (tags != 0) { @@ -2791,11 +2820,11 @@ AstNode *parse_atom_expr(AstFile *f, AstNode *operand, bool lhs) { index3 = true; // 2nd and 3rd index must be present if (indices[1] == nullptr) { - error(ellipses[0], "2nd index required in 3-index slice expression"); + syntax_error(ellipses[0], "2nd index required in 3-index slice expression"); indices[1] = ast_bad_expr(f, ellipses[0], ellipses[1]); } if (indices[2] == nullptr) { - error(ellipses[1], "3rd index required in 3-index slice expression"); + syntax_error(ellipses[1], "3rd index required in 3-index slice expression"); indices[2] = ast_bad_expr(f, ellipses[1], close); } } @@ -3020,13 +3049,13 @@ void parse_foreign_block_decl(AstFile *f, Array<AstNode *> *decls) { case AstNode_BadDecl: return; + case AstNode_WhenStmt: case AstNode_ValueDecl: array_add(decls, decl); return; - /* fallthrough */ default: - error(decl, "Foreign blocks only allow procedure and variable declarations"); + syntax_error(decl, "Foreign blocks only allow procedure and variable declarations"); return; } } @@ -3266,7 +3295,7 @@ AstNode *parse_results(AstFile *f) { return list; } -AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) { +AstNode *parse_proc_type(AstFile *f, Token proc_token) { AstNode *params = nullptr; AstNode *results = nullptr; @@ -3276,11 +3305,8 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) { results = parse_results(f); u64 tags = 0; - String link_name = {}; ProcCallingConvention cc = ProcCC_Invalid; - parse_proc_tags(f, &tags, &link_name, &cc); - - if (link_name_) *link_name_ = link_name; + parse_proc_tags(f, &tags, &cc); bool is_generic = false; @@ -3304,7 +3330,7 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) Token tok = advance_token(f); AstNode *type = parse_type_or_ident(f); if (type == nullptr) { - error(tok, "variadic field missing type after `...`"); + syntax_error(tok, "variadic field missing type after `...`"); type = ast_bad_expr(f, tok, f->curr_token); } return ast_ellipsis(f, tok, type); @@ -3323,7 +3349,7 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) } if (type == nullptr) { Token tok = f->curr_token; - error(tok, "Expected a type"); + syntax_error(tok, "Expected a type"); type = ast_bad_expr(f, tok, f->curr_token); } return type; @@ -3426,7 +3452,7 @@ Array<AstNode *> convert_to_ident_list(AstFile *f, Array<AstNodeAndFlags> list, if (!ignore_flags) { if (i != 0) { - error(ident, "Illegal use of prefixes in parameter list"); + syntax_error(ident, "Illegal use of prefixes in parameter list"); } } @@ -3435,7 +3461,7 @@ Array<AstNode *> convert_to_ident_list(AstFile *f, Array<AstNodeAndFlags> list, case AstNode_BadExpr: break; default: - error(ident, "Expected an identifier"); + syntax_error(ident, "Expected an identifier"); ident = ast_ident(f, blank_token); break; } @@ -3451,7 +3477,7 @@ bool parse_expect_field_separator(AstFile *f, AstNode *param) { return true; } if (token.kind == Token_Semicolon) { - error(f->curr_token, "Expected a comma, got a semicolon"); + syntax_error(f->curr_token, "Expected a comma, got a semicolon"); advance_token(f); return true; } @@ -3465,7 +3491,7 @@ bool parse_expect_struct_separator(AstFile *f, AstNode *param) { } if (token.kind == Token_Colon) { - error(f->curr_token, "Expected a semicolon, got a comma"); + syntax_error(f->curr_token, "Expected a semicolon, got a comma"); advance_token(f); return true; } @@ -3506,7 +3532,7 @@ AstNode *parse_struct_field_list(AstFile *f, isize *name_count_) { case_ast_node(vd, ValueDecl, decl); if (vd->flags&VarDeclFlag_thread_local) { vd->flags &= ~VarDeclFlag_thread_local; - error(decl, "Field values cannot be #thread_local"); + syntax_error(decl, "Field values cannot be #thread_local"); } array_add(&decls, decl); total_name_count += vd->names.count; @@ -3517,7 +3543,7 @@ AstNode *parse_struct_field_list(AstFile *f, isize *name_count_) { break; default: - error(decl, "Expected a value declaration, got %.*s", LIT(ast_node_strings[decl->kind])); + syntax_error(decl, "Expected a value declaration, got %.*s", LIT(ast_node_strings[decl->kind])); break; } } @@ -4209,7 +4235,7 @@ AstNode *parse_for_stmt(AstFile *f) { index = cond->AssignStmt.lhs[1]; break; default: - error(cond, "Expected either 1 or 2 identifiers"); + syntax_error(cond, "Expected either 1 or 2 identifiers"); return ast_bad_stmt(f, token, f->curr_token); } @@ -4566,6 +4592,46 @@ AstNode *parse_stmt(AstFile *f) { return ast_push_context(f, token, expr, body); } break; + case Token_At: { + advance_token(f); + + Array<AstNode *> elems = {}; + Token open = expect_token(f, Token_OpenParen); + f->expr_level++; + if (f->curr_token.kind != Token_CloseParen) { + elems = make_ast_node_array(f); + + while (f->curr_token.kind != Token_CloseParen && + f->curr_token.kind != Token_EOF) { + AstNode *elem = parse_ident(f); + if (f->curr_token.kind == Token_Eq) { + Token eq = expect_token(f, Token_Eq); + AstNode *value = parse_value(f); + elem = ast_field_value(f, elem, value, eq); + } + + array_add(&elems, elem); + + if (!allow_token(f, Token_Comma)) { + break; + } + } + } + f->expr_level--; + Token close = expect_closing(f, Token_CloseParen, str_lit("attribute")); + + AstNode *attribute = ast_attribute(f, token, open, close, elems); + + AstNode *decl = parse_stmt(f); + if (decl->kind != AstNode_ValueDecl) { + syntax_error(decl, "Expected a value declaration after an attribute, got %.*s", LIT(ast_node_strings[decl->kind])); + return ast_bad_stmt(f, token, f->curr_token); + } + + array_add(&decl->ValueDecl.attributes, attribute); + return decl; + } + case Token_Hash: { AstNode *s = nullptr; Token hash_token = expect_token(f, Token_Hash); diff --git a/src/ssa.cpp b/src/ssa.cpp index fa83cecb8..3a5e283e2 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -2490,8 +2490,8 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { if (e->Procedure.is_foreign) { name = e->token.string; // NOTE(bill): Don't use the mangled name } - if (pl->link_name.len > 0) { - name = pl->link_name; + if (e->Procedure.link_name.len > 0) { + name = e->Procedure.link_name; } if (e == entry_point) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 7d36e2a66..dc0c2a56d 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -114,6 +114,8 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_cast, "cast"), \ TOKEN_KIND(Token_transmute, "transmute"), \ TOKEN_KIND(Token_using, "using"), \ + TOKEN_KIND(Token_inline, "inline"), \ + TOKEN_KIND(Token_no_inline, "no_inline"), \ TOKEN_KIND(Token_context, "context"), \ TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_push_allocator, "push_allocator"), \ diff --git a/src/types.cpp b/src/types.cpp index f30e47869..fcfc91544 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -28,6 +28,7 @@ enum BasicKind { Basic_int, Basic_uint, + Basic_uintptr, Basic_rawptr, Basic_string, // ^u8 + int Basic_any, // ^Type_Info + rawptr @@ -254,6 +255,7 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}}, {Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}}, + {Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}}, {Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}}, {Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}}, @@ -299,6 +301,7 @@ gb_global Type *t_complex128 = &basic_types[Basic_complex128]; gb_global Type *t_int = &basic_types[Basic_int]; gb_global Type *t_uint = &basic_types[Basic_uint]; +gb_global Type *t_uintptr = &basic_types[Basic_uintptr]; gb_global Type *t_rawptr = &basic_types[Basic_rawptr]; gb_global Type *t_string = &basic_types[Basic_string]; @@ -745,9 +748,9 @@ bool is_type_tuple(Type *t) { } -bool is_type_int_or_uint(Type *t) { +bool is_type_uintptr(Type *t) { if (t->kind == Type_Basic) { - return (t->Basic.kind == Basic_int) || (t->Basic.kind == Basic_uint); + return (t->Basic.kind == Basic_uintptr); } return false; } @@ -1813,7 +1816,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { case Basic_string: return build_context.word_size; case Basic_any: return build_context.word_size; - case Basic_int: case Basic_uint: case Basic_rawptr: + case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr: return build_context.word_size; case Basic_complex64: case Basic_complex128: @@ -2023,7 +2026,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { case Basic_string: return 2*build_context.word_size; case Basic_any: return 2*build_context.word_size; - case Basic_int: case Basic_uint: case Basic_rawptr: + case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr: return build_context.word_size; } } break; |