aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2017-10-29 15:46:23 +0000
committergingerBill <bill@gingerbill.org>2017-10-29 15:46:23 +0000
commit1eb9994d88b874b2f4ac3fdc4d314b1e67fa511b (patch)
tree5dd176e7f4e8677ea935762e7044a4d6e3265520 /src
parenta43b89f36e988df8268ee92ea54017806b3226bb (diff)
Attributes; @(link_name="foo")
Diffstat (limited to 'src')
-rw-r--r--src/check_decl.cpp97
-rw-r--r--src/check_expr.cpp7
-rw-r--r--src/check_stmt.cpp2
-rw-r--r--src/checker.cpp14
-rw-r--r--src/ir.cpp41
-rw-r--r--src/ir_print.cpp17
-rw-r--r--src/parser.cpp170
-rw-r--r--src/ssa.cpp4
-rw-r--r--src/tokenizer.cpp2
-rw-r--r--src/types.cpp11
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;