mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-28 18:30:06 +00:00
Dynamic array syntax [...]Type; make entities private with a prefix of _; fix extension checking
This commit is contained in:
+44
-13
@@ -1081,6 +1081,11 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
|
||||
return 0;
|
||||
}
|
||||
Operand o = {0};
|
||||
if (e->kind == AstNode_UnaryExpr &&
|
||||
e->UnaryExpr.op.kind == Token_Question) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
check_expr(c, &o, e);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
@@ -1314,7 +1319,12 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
||||
case_ast_node(at, ArrayType, e);
|
||||
if (at->count != NULL) {
|
||||
Type *elem = check_type_extra(c, at->elem, NULL);
|
||||
type = make_type_array(c->allocator, elem, check_array_or_map_count(c, at->count, false));
|
||||
i64 count = check_array_or_map_count(c, at->count, false);
|
||||
if (count < 0) {
|
||||
error_node(at->count, "? can only be used in conjuction with compound literals");
|
||||
count = 0;
|
||||
}
|
||||
type = make_type_array(c->allocator, elem, count);
|
||||
} else {
|
||||
Type *elem = check_type(c, at->elem);
|
||||
type = make_type_slice(c->allocator, elem);
|
||||
@@ -2529,8 +2539,11 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
add_entity_use(c, op_expr, e);
|
||||
expr_entity = e;
|
||||
|
||||
if (e != NULL && e->kind == Entity_ImportName &&
|
||||
selector->kind == AstNode_Ident) {
|
||||
if (e != NULL && e->kind == Entity_ImportName && selector->kind == AstNode_Ident) {
|
||||
// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
|
||||
// It pretty much needs to be in this order and this way
|
||||
// If you can clean this up, please do but be really careful
|
||||
|
||||
String sel_name = selector->Ident.string;
|
||||
|
||||
check_op_expr = false;
|
||||
@@ -2539,8 +2552,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
if (is_declared) {
|
||||
if (entity->kind == Entity_Builtin) {
|
||||
is_declared = false;
|
||||
}
|
||||
if (entity->scope->is_global && !e->ImportName.scope->is_global) {
|
||||
} else if (entity->scope->is_global && !e->ImportName.scope->is_global) {
|
||||
is_declared = false;
|
||||
}
|
||||
}
|
||||
@@ -2564,6 +2576,17 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
is_not_exported = !is_entity_name_exported(entity);
|
||||
|
||||
if (is_not_exported) {
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name));
|
||||
gb_string_free(sel_str);
|
||||
// NOTE(bill): We will have to cause an error his even though it exists
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (is_overloaded) {
|
||||
Scope *s = entity->scope;
|
||||
bool skip = false;
|
||||
@@ -2608,7 +2631,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
}
|
||||
|
||||
bool *found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity));
|
||||
|
||||
if (!found) {
|
||||
is_not_exported = false;
|
||||
} else {
|
||||
@@ -4479,16 +4501,18 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
|
||||
case_ast_node(cl, CompoundLit, node);
|
||||
Type *type = type_hint;
|
||||
bool ellipsis_array = false;
|
||||
bool is_to_be_determined_array_count = false;
|
||||
bool is_constant = true;
|
||||
if (cl->type != NULL) {
|
||||
type = NULL;
|
||||
|
||||
// [..]Type
|
||||
if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) {
|
||||
if (cl->type->ArrayType.count->kind == AstNode_Ellipsis) {
|
||||
AstNode *count = cl->type->ArrayType.count;
|
||||
if (count->kind == AstNode_UnaryExpr &&
|
||||
count->UnaryExpr.op.kind == Token_Question) {
|
||||
type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1);
|
||||
ellipsis_array = true;
|
||||
is_to_be_determined_array_count = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4663,7 +4687,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
}
|
||||
}
|
||||
|
||||
if (t->kind == Type_Array && ellipsis_array) {
|
||||
if (t->kind == Type_Array && is_to_be_determined_array_count) {
|
||||
t->Array.count = max;
|
||||
}
|
||||
} break;
|
||||
@@ -5185,11 +5209,13 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
case AstNode_ProcType:
|
||||
case AstNode_PointerType:
|
||||
case AstNode_ArrayType:
|
||||
case AstNode_DynamicArrayType:
|
||||
case AstNode_VectorType:
|
||||
case AstNode_StructType:
|
||||
case AstNode_UnionType:
|
||||
case AstNode_RawUnionType:
|
||||
case AstNode_EnumType:
|
||||
case AstNode_MapType:
|
||||
o->mode = Addressing_Type;
|
||||
o->type = check_type(c, node);
|
||||
break;
|
||||
@@ -5417,7 +5443,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(e, Ellipsis, node);
|
||||
str = gb_string_appendc(str, "..");
|
||||
str = gb_string_appendc(str, "...");
|
||||
case_end;
|
||||
|
||||
case_ast_node(fv, FieldValue, node);
|
||||
@@ -5433,13 +5459,18 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
|
||||
case_ast_node(at, ArrayType, node);
|
||||
str = gb_string_appendc(str, "[");
|
||||
str = write_expr_to_string(str, at->count);
|
||||
if (at->count->kind == AstNode_UnaryExpr &&
|
||||
at->count->UnaryExpr.op.kind == Token_Hash) {
|
||||
str = gb_string_appendc(str, "#");
|
||||
} else {
|
||||
str = write_expr_to_string(str, at->count);
|
||||
}
|
||||
str = gb_string_appendc(str, "]");
|
||||
str = write_expr_to_string(str, at->elem);
|
||||
case_end;
|
||||
|
||||
case_ast_node(at, DynamicArrayType, node);
|
||||
str = gb_string_appendc(str, "[dynamic]");
|
||||
str = gb_string_appendc(str, "[...]");
|
||||
str = write_expr_to_string(str, at->elem);
|
||||
case_end;
|
||||
|
||||
|
||||
+37
-3
@@ -1531,6 +1531,8 @@ void check_all_global_entities(Checker *c) {
|
||||
add_curr_ast_file(c, d->scope->file);
|
||||
|
||||
if (!d->scope->has_been_imported) {
|
||||
// NOTE(bill): All of these unchecked entities could mean a lot of unused allocations
|
||||
// TODO(bill): Should this be worried about?
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1567,6 +1569,30 @@ void check_all_global_entities(Checker *c) {
|
||||
}
|
||||
|
||||
|
||||
bool is_string_an_identifier(String s) {
|
||||
isize offset = 0;
|
||||
if (s.len < 1) {
|
||||
return false;
|
||||
}
|
||||
while (offset < s.len) {
|
||||
bool ok = false;
|
||||
Rune r = -1;
|
||||
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
|
||||
if (offset == 0) {
|
||||
ok = rune_is_letter(r);
|
||||
} else {
|
||||
ok = rune_is_letter(r) || rune_is_digit(r);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return offset == s.len;
|
||||
}
|
||||
|
||||
String path_to_entity_name(String name, String fullpath) {
|
||||
if (name.len != 0) {
|
||||
return name;
|
||||
@@ -1677,9 +1703,17 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||
case Entity_LibraryName:
|
||||
break;
|
||||
default: {
|
||||
bool ok = add_entity(c, parent_scope, NULL, e);
|
||||
if (ok && id->is_import) { // `#import`ed entities don't get exported
|
||||
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
|
||||
|
||||
if (id->is_import) {
|
||||
if (is_entity_name_exported(e)) {
|
||||
// TODO(bill): Should these entities be imported but cause an error when used?
|
||||
bool ok = add_entity(c, parent_scope, NULL, e);
|
||||
if (ok) {
|
||||
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* bool ok = */add_entity(c, parent_scope, NULL, e);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ gbAllocator heap_allocator(void) {
|
||||
return gb_heap_allocator();
|
||||
}
|
||||
|
||||
#include "unicode.c"
|
||||
#include "string.c"
|
||||
#include "array.c"
|
||||
|
||||
|
||||
@@ -98,6 +98,15 @@ struct Entity {
|
||||
|
||||
gb_global Entity *e_context = NULL;
|
||||
|
||||
bool is_entity_name_exported(Entity *e) {
|
||||
GB_ASSERT(e != NULL);
|
||||
String name = e->token.string;
|
||||
if (name.len == 0) {
|
||||
return false;
|
||||
}
|
||||
return name.text[0] != '_';
|
||||
}
|
||||
|
||||
|
||||
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
Entity *entity = gb_alloc_item(a, Entity);
|
||||
|
||||
@@ -4,7 +4,6 @@ extern "C" {
|
||||
|
||||
#include "common.c"
|
||||
#include "timings.c"
|
||||
#include "unicode.c"
|
||||
#include "build.c"
|
||||
#include "tokenizer.c"
|
||||
#include "parser.c"
|
||||
|
||||
+9
-4
@@ -1832,6 +1832,7 @@ bool is_literal_type(AstNode *node) {
|
||||
case AstNode_ArrayType:
|
||||
case AstNode_VectorType:
|
||||
case AstNode_StructType:
|
||||
case AstNode_DynamicArrayType:
|
||||
case AstNode_MapType:
|
||||
return true;
|
||||
}
|
||||
@@ -2575,8 +2576,8 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
AstNode *count_expr = NULL;
|
||||
bool is_vector = false;
|
||||
|
||||
if (f->curr_token.kind == Token_Ellipsis) {
|
||||
count_expr = ast_ellipsis(f, expect_token(f, Token_Ellipsis), NULL);
|
||||
if (f->curr_token.kind == Token_Question) {
|
||||
count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL);
|
||||
} else if (f->curr_token.kind == Token_vector) {
|
||||
next_token(f);
|
||||
if (f->curr_token.kind != Token_CloseBracket) {
|
||||
@@ -2587,7 +2588,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
syntax_error(f->curr_token, "Vector type missing count");
|
||||
}
|
||||
is_vector = true;
|
||||
} else if (f->curr_token.kind == Token_dynamic) {
|
||||
} else if (f->curr_token.kind == Token_Ellipsis) {
|
||||
next_token(f);
|
||||
expect_token(f, Token_CloseBracket);
|
||||
return ast_dynamic_array_type(f, token, parse_type(f));
|
||||
@@ -3527,6 +3528,7 @@ AstNodeArray parse_stmt_list(AstFile *f) {
|
||||
|
||||
|
||||
ParseFileError init_ast_file(AstFile *f, String fullpath) {
|
||||
fullpath = string_trim_whitespace(fullpath); // Just in case
|
||||
if (!string_has_extension(fullpath, str_lit("odin"))) {
|
||||
return ParseFile_WrongExtension;
|
||||
}
|
||||
@@ -3606,6 +3608,9 @@ void destroy_parser(Parser *p) {
|
||||
bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
|
||||
gb_mutex_lock(&p->mutex);
|
||||
|
||||
path = string_trim_whitespace(path);
|
||||
rel_path = string_trim_whitespace(rel_path);
|
||||
|
||||
for_array(i, p->imports) {
|
||||
String import = p->imports.e[i].path;
|
||||
if (str_eq(import, path)) {
|
||||
@@ -3786,7 +3791,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||
gb_printf_err("Invalid file extension: File must have the extension `.odin`");
|
||||
break;
|
||||
case ParseFile_InvalidFile:
|
||||
gb_printf_err("Invalid file");
|
||||
gb_printf_err("Invalid file or cannot be found");
|
||||
break;
|
||||
case ParseFile_Permission:
|
||||
gb_printf_err("File permissions problem");
|
||||
|
||||
+28
-7
@@ -145,16 +145,37 @@ gb_inline isize string_extension_position(String str) {
|
||||
return dot_pos;
|
||||
}
|
||||
|
||||
String string_trim_whitespace(String str) {
|
||||
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) {
|
||||
str.len--;
|
||||
}
|
||||
|
||||
while (str.len > 0 && rune_is_whitespace(str.text[0])) {
|
||||
str.text++;
|
||||
str.len--;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
gb_inline bool string_has_extension(String str, String ext) {
|
||||
if (str.len > ext.len+1) {
|
||||
u8 *s = str.text+str.len - ext.len-1;
|
||||
if (s[0] == '.') {
|
||||
s++;
|
||||
return gb_memcompare(s, ext.text, ext.len) == 0;
|
||||
}
|
||||
str = string_trim_whitespace(str);
|
||||
if (str.len <= ext.len+1) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
isize len = str.len;
|
||||
for (isize i = len-1; i >= 0; i--) {
|
||||
if (str.text[i] == '.') {
|
||||
break;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 *s = str.text + len;
|
||||
return gb_memcompare(s, ext.text, ext.len) == 0;
|
||||
}
|
||||
|
||||
bool string_contains_char(String s, u8 c) {
|
||||
|
||||
+4
-4
@@ -107,12 +107,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
TOKEN_KIND(Token_map, "map"), \
|
||||
TOKEN_KIND(Token_static, "static"), \
|
||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||
/* TOKEN_KIND(Token_static, "static"), */ \
|
||||
/* TOKEN_KIND(Token_dynamic, "dynamic"), */ \
|
||||
TOKEN_KIND(Token_using, "using"), \
|
||||
TOKEN_KIND(Token_no_alias, "no_alias"), \
|
||||
/* TOKEN_KIND(Token_mutable, "mutable"), */ \
|
||||
/* TOKEN_KIND(Token_immutable, "immutable"), */\
|
||||
/* TOKEN_KIND(Token_mutable, "mutable"), */ \
|
||||
/* TOKEN_KIND(Token_immutable, "immutable"), */ \
|
||||
TOKEN_KIND(Token_thread_local, "thread_local"), \
|
||||
TOKEN_KIND(Token_cast, "cast"), \
|
||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||
|
||||
@@ -39,28 +39,3 @@ bool rune_is_whitespace(Rune r) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_string_an_identifier(String s) {
|
||||
isize offset = 0;
|
||||
if (s.len < 1) {
|
||||
return false;
|
||||
}
|
||||
while (offset < s.len) {
|
||||
bool ok = false;
|
||||
Rune r = -1;
|
||||
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
|
||||
if (offset == 0) {
|
||||
ok = rune_is_letter(r);
|
||||
} else {
|
||||
ok = rune_is_letter(r) || rune_is_digit(r);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return offset == s.len;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user