mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Removed non-null references.
This commit is contained in:
@@ -7,8 +7,7 @@
|
||||
Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility)
|
||||
{
|
||||
assert(name.string);
|
||||
Decl *decl = malloc_arena(sizeof(Decl));
|
||||
memset(decl, 0, sizeof(Decl));
|
||||
Decl *decl = CALLOCS(Decl);
|
||||
decl->decl_kind = decl_kind;
|
||||
decl->name = name;
|
||||
decl->visibility = visibility;
|
||||
@@ -318,9 +317,9 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
fprintf(file, "(postunary %s\n", token_type_to_string(expr->post_expr.operator));
|
||||
fprint_expr_recursive(file, expr->post_expr.expr, indent + 1);
|
||||
break;
|
||||
case EXPR_METHOD_REF:
|
||||
fprintf(file, "(methodref .%s\n", expr->method_ref_expr.method.string);
|
||||
fprint_type_recursive(file, expr->method_ref_expr.type, indent + 1);
|
||||
case EXPR_TYPE_ACCESS:
|
||||
fprintf(file, "(typeaccess .%s\n", expr->type_access.name.string);
|
||||
fprint_type_recursive(file, expr->type_access.type, indent + 1);
|
||||
break;
|
||||
case EXPR_STRUCT_VALUE:
|
||||
fprintf(file, "(structvalue\n");
|
||||
@@ -434,7 +433,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
|
||||
break;
|
||||
case DECL_FUNC:
|
||||
fprintf(file, "(func %s\n", decl->name.string);
|
||||
fprint_type_recursive(file, decl->func.struct_parent, indent + 1);
|
||||
fprint_type_recursive(file, decl->func.type_parent, indent + 1);
|
||||
fprint_func_signature(file, &decl->func.function_signature, indent + 1);
|
||||
fprint_ast_recursive(file, decl->func.body, indent + 1);
|
||||
break;
|
||||
|
||||
@@ -84,11 +84,9 @@ static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *targ
|
||||
assert(target_type->canonical == target_type);
|
||||
|
||||
// Neither is void* or have matching bases:
|
||||
// TODO recursively check for ?* or?
|
||||
if (target_type->base != type_void && current_type->base != type_void && target_type->base != current_type->base) return false;
|
||||
|
||||
// Current is not null, or target is nullable? Ok!
|
||||
return target_type->nullable || !current_type->nullable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ptpt(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
@@ -446,11 +444,8 @@ bool usus(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (type_is_subtype(left_canonical->base, canonical->base))
|
||||
{
|
||||
if (!left_canonical->base->nullable || canonical->base->nullable)
|
||||
{
|
||||
insert_cast(left, CAST_PTRPTR, canonical);
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_PTRPTR, canonical);
|
||||
return true;
|
||||
}
|
||||
sema_type_mismatch(left, type, cast_type);
|
||||
return false;
|
||||
|
||||
@@ -379,6 +379,16 @@ static int codegen_emit_initializer_list(Context *context, Expr *expr, int inden
|
||||
return index;
|
||||
}
|
||||
|
||||
static int codegen_emit_access(Context *context, Expr *expr, int indent)
|
||||
{
|
||||
int left = codegen_emit_expr(context, expr->access_expr.parent, indent);
|
||||
int index = ++context->unique_index;
|
||||
INDENT();
|
||||
PRINTTYPE(expr->type);
|
||||
PRINTF(" _%d = _%d.%s;\n", index, left, expr->access_expr.sub_element.string);
|
||||
return index;
|
||||
}
|
||||
|
||||
static int codegen_emit_unary_expr(Context *context, Expr *expr, int indent)
|
||||
{
|
||||
int index = ++context->unique_index;
|
||||
@@ -452,6 +462,8 @@ static int codegen_emit_expr(Context *context, Expr *expr, int indent)
|
||||
return codegen_emit_unary_expr(context, expr, indent);
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
return codegen_emit_initializer_list(context, expr, indent);
|
||||
case EXPR_ACCESS:
|
||||
return codegen_emit_access(context, expr, indent);
|
||||
default:
|
||||
TODO
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ Compiler compiler;
|
||||
void compiler_init(void)
|
||||
{
|
||||
stable_init(&compiler.modules, 64);
|
||||
compiler.module_list = NULL;
|
||||
stable_init(&compiler.global_symbols, 0x1000);
|
||||
}
|
||||
|
||||
static void compiler_lex()
|
||||
@@ -63,14 +63,33 @@ void compiler_compile()
|
||||
vec_add(contexts, context);
|
||||
parse_file(context);
|
||||
}
|
||||
const char *printf = "printf";
|
||||
TokenType t_type = TOKEN_IDENT;
|
||||
const char *interned = symtab_add(printf, (uint32_t) 6, fnv1a(printf, (uint32_t)6), &t_type);
|
||||
Decl *decl = decl_new(DECL_FUNC, wrap(interned), VISIBLE_PUBLIC);
|
||||
Type *type = type_new(TYPE_POINTER);
|
||||
type->base = type_char;
|
||||
sema_resolve_type(contexts[0], type);
|
||||
Decl *param = decl_new_var(wrap("str"), type, VARDECL_PARAM, VISIBLE_LOCAL);
|
||||
vec_add(decl->func.function_signature.params, param);
|
||||
decl->func.function_signature.rtype = type_void;
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
context_register_global_decl(contexts[0], decl);
|
||||
|
||||
VECEACH(contexts, i)
|
||||
{
|
||||
sema_analysis_pass_conditional_compilation(contexts[i]);
|
||||
}
|
||||
VECEACH(contexts, i)
|
||||
{
|
||||
sema_analysis_pass_decls(contexts[i]);
|
||||
}
|
||||
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
|
||||
VECEACH(contexts, i)
|
||||
{
|
||||
Context *context = contexts[i];
|
||||
sema_analysis(context);
|
||||
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
|
||||
char buffer[255];
|
||||
sprintf(buffer, "%s_test.c", context->module_name.string);
|
||||
printf("%s\n", buffer);
|
||||
FILE *f = fopen(buffer,"w");
|
||||
fprintf(f, "#include <stdbool.h>\n#include <stdint.h>\n");
|
||||
context->codegen_output = f;
|
||||
@@ -103,22 +122,7 @@ void compile_file()
|
||||
|
||||
Decl *compiler_find_symbol(Token token)
|
||||
{
|
||||
Decl *candidate = NULL;
|
||||
VECEACH(compiler.module_list, i)
|
||||
{
|
||||
Module *module = compiler.module_list[i];
|
||||
Decl *decl = module_find_symbol(module, token.string);
|
||||
if (decl && candidate)
|
||||
{
|
||||
const char *previous = candidate->module->name;
|
||||
const char *current = decl->module->name;
|
||||
SEMA_ERROR(token, "Ambiguous use of '%s', matches both %s::%s and %s::%s.", token.string,
|
||||
previous, token.string, current, token.string);
|
||||
return &poisoned_decl;
|
||||
}
|
||||
candidate = decl;
|
||||
}
|
||||
return candidate;
|
||||
return stable_get(&compiler.global_symbols, token.string);
|
||||
}
|
||||
|
||||
Module *compiler_find_or_create_module(const char *module_name)
|
||||
@@ -129,6 +133,21 @@ Module *compiler_find_or_create_module(const char *module_name)
|
||||
module->name = module_name;
|
||||
stable_init(&module->symbols, 0x10000);
|
||||
stable_set(&compiler.modules, module_name, module);
|
||||
vec_add(compiler.module_list, module);
|
||||
return module;
|
||||
}
|
||||
|
||||
void compiler_register_public_symbol(Decl *decl)
|
||||
{
|
||||
Decl *prev = stable_get(&compiler.global_symbols, decl->name.string);
|
||||
// If the previous symbol was already declared globally, remove it.
|
||||
stable_set(&compiler.global_symbols, decl->name.string, prev ? &poisoned_decl : decl);
|
||||
STable *sub_module_space = stable_get(&compiler.qualified_symbols, decl->module->name);
|
||||
if (!sub_module_space)
|
||||
{
|
||||
sub_module_space = malloc_arena(sizeof(*sub_module_space));
|
||||
stable_init(sub_module_space, 0x100);
|
||||
stable_set(&compiler.qualified_symbols, decl->module->name, sub_module_space);
|
||||
}
|
||||
prev = stable_get(sub_module_space, decl->name.string);
|
||||
stable_set(sub_module_space, decl->name.string, prev ? &poisoned_decl : decl);
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Token package;
|
||||
Token module;
|
||||
Token sub_module;
|
||||
} Path;
|
||||
|
||||
struct _Type
|
||||
@@ -107,7 +107,6 @@ struct _Type
|
||||
{
|
||||
Expr *unresolved_len;
|
||||
size_t len;
|
||||
bool nullable;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -139,7 +138,6 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
Decl **members;
|
||||
Decl **method_functions;
|
||||
} StructDecl;
|
||||
|
||||
|
||||
@@ -195,7 +193,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
const char *full_name;
|
||||
Type *struct_parent;
|
||||
Type *type_parent;
|
||||
FunctionSignature function_signature;
|
||||
Ast *body;
|
||||
FuncAnnotations *annotations;
|
||||
@@ -251,16 +249,23 @@ typedef struct _Decl
|
||||
};
|
||||
uint32_t size;*/
|
||||
Type *self_type;
|
||||
struct _Module *module;
|
||||
Module *module;
|
||||
Attr** attributes;
|
||||
union
|
||||
{
|
||||
ErrorDecl error;
|
||||
struct
|
||||
{
|
||||
Decl** method_functions;
|
||||
union
|
||||
{
|
||||
ErrorDecl error;
|
||||
StructDecl strukt;
|
||||
EnumDecl enums;
|
||||
};
|
||||
};
|
||||
ErrorConstantDecl error_constant;
|
||||
ImportDecl import;
|
||||
StructDecl strukt;
|
||||
VarDecl var;
|
||||
EnumDecl enums;
|
||||
EnumConstantDecl enum_constant;
|
||||
FuncDecl func;
|
||||
AttrDecl attr;
|
||||
@@ -284,8 +289,12 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
Type *type;
|
||||
Token method;
|
||||
} ExprMethodRef;
|
||||
union
|
||||
{
|
||||
Token name;
|
||||
Decl *method;
|
||||
};
|
||||
} ExprTypeRef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -353,7 +362,11 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
Expr *parent;
|
||||
Token sub_element;
|
||||
union
|
||||
{
|
||||
Token sub_element;
|
||||
Decl *ref;
|
||||
};
|
||||
} ExprAccess;
|
||||
|
||||
typedef struct
|
||||
@@ -393,7 +406,7 @@ struct _Expr
|
||||
ExprCast expr_cast;
|
||||
ExprConst const_expr;
|
||||
ExprStructValue struct_value_expr;
|
||||
ExprMethodRef method_ref_expr;
|
||||
ExprTypeRef type_access;
|
||||
ExprTry try_expr;
|
||||
ExprBinary binary_expr;
|
||||
ExprAssign assign_expr;
|
||||
@@ -600,14 +613,8 @@ typedef struct _Ast
|
||||
} Ast;
|
||||
|
||||
|
||||
typedef struct _Package
|
||||
{
|
||||
const char *name;
|
||||
} Package;
|
||||
|
||||
typedef struct _Module
|
||||
{
|
||||
Package *package;
|
||||
const char *name;
|
||||
|
||||
bool is_external;
|
||||
@@ -646,6 +653,7 @@ typedef struct _Context
|
||||
Decl **enums;
|
||||
Decl **types;
|
||||
Decl **functions;
|
||||
Decl **struct_functions;
|
||||
Decl **vars;
|
||||
Decl **ct_ifs;
|
||||
Ast **defers;
|
||||
@@ -667,7 +675,8 @@ typedef struct _Context
|
||||
typedef struct
|
||||
{
|
||||
STable modules;
|
||||
Module **module_list;
|
||||
STable global_symbols;
|
||||
STable qualified_symbols;
|
||||
} Compiler;
|
||||
|
||||
extern Context *current_context;
|
||||
@@ -682,7 +691,7 @@ extern Diagnostics diagnostics;
|
||||
extern Token next_tok;
|
||||
extern Token tok;
|
||||
|
||||
extern Type *type_bool, *type_void, *type_string;
|
||||
extern Type *type_bool, *type_void, *type_string, *type_voidptr, *type_voidref;
|
||||
extern Type *type_float, *type_double;
|
||||
extern Type *type_char, *type_short, *type_int, *type_long, *type_isize;
|
||||
extern Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
||||
@@ -696,6 +705,7 @@ extern Type t_f32, t_f64, t_fxx;
|
||||
extern Type t_u0, t_str;
|
||||
extern Type t_cus, t_cui, t_cul, t_cull;
|
||||
extern Type t_cs, t_ci, t_cl, t_cll;
|
||||
extern Type t_voidstar;
|
||||
|
||||
#define AST_NEW(_kind, _token) new_ast(_kind, _token)
|
||||
|
||||
@@ -772,6 +782,7 @@ bool sema_analyse_expr(Context *context, Expr *expr);
|
||||
|
||||
Decl *compiler_find_symbol(Token token);
|
||||
Module *compiler_find_or_create_module(const char *module_name);
|
||||
void compiler_register_public_symbol(Decl *decl);
|
||||
|
||||
Context *context_create(File *file);
|
||||
void context_push(Context *context);
|
||||
@@ -851,7 +862,9 @@ void parse_file(Context *context);
|
||||
|
||||
#define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__)
|
||||
void sema_init(File *file);
|
||||
void sema_analysis(Context *context);
|
||||
void sema_analysis_pass_conditional_compilation(Context *context);
|
||||
void sema_analysis_pass_decls(Context *context);
|
||||
void sema_analysis_pass_3(Context *context);
|
||||
|
||||
bool sema_analyse_statement(Context *context, Ast *statement);
|
||||
bool sema_resolve_type(Context *context, Type *type);
|
||||
@@ -900,6 +913,7 @@ static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I
|
||||
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_UXX; }
|
||||
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
||||
static inline void type_poison(Type *type) { type->type_kind = TYPE_POISONED; type->resolve_status = RESOLVE_DONE; }
|
||||
bool type_may_have_method_functions(Type *type);
|
||||
static inline bool type_is_integer(Type *type)
|
||||
{
|
||||
assert(type == type->canonical);
|
||||
|
||||
@@ -114,7 +114,15 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
case DECL_GENERIC:
|
||||
break;
|
||||
case DECL_FUNC:
|
||||
vec_add(context->functions, decl);
|
||||
if (decl->func.type_parent)
|
||||
{
|
||||
vec_add(context->struct_functions, decl);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_add(context->functions, decl);
|
||||
}
|
||||
break;
|
||||
case DECL_VAR:
|
||||
vec_add(context->vars, decl);
|
||||
@@ -123,6 +131,7 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
case DECL_UNION:
|
||||
case DECL_TYPEDEF:
|
||||
vec_add(context->types, decl);
|
||||
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
vec_add(context->enums, decl);
|
||||
@@ -140,7 +149,6 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
case DECL_ATTRIBUTE:
|
||||
UNREACHABLE
|
||||
break;
|
||||
|
||||
case DECL_CT_IF:
|
||||
vec_add(context->ct_ifs, decl);
|
||||
return;
|
||||
@@ -154,6 +162,7 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
}
|
||||
if (!old && decl->visibility == VISIBLE_PUBLIC)
|
||||
{
|
||||
compiler_register_public_symbol(decl);
|
||||
old = stable_set(&context->module->public_symbols, decl->name.string, decl);
|
||||
}
|
||||
if (old != NULL)
|
||||
|
||||
@@ -188,7 +188,7 @@ typedef enum
|
||||
EXPR_POST_UNARY,
|
||||
EXPR_TYPE,
|
||||
EXPR_IDENTIFIER,
|
||||
EXPR_METHOD_REF,
|
||||
EXPR_TYPE_ACCESS,
|
||||
EXPR_CALL,
|
||||
EXPR_SIZEOF,
|
||||
EXPR_SUBSCRIPT,
|
||||
|
||||
@@ -65,7 +65,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Expr *expr)
|
||||
static inline bool sema_expr_analyse_var_call(Context *context, Expr *expr) { TODO }
|
||||
static inline bool sema_expr_analyse_macro_call(Context *context, Expr *expr, Decl *macro)
|
||||
{
|
||||
Ast macro_parent;
|
||||
Ast *macro_parent;
|
||||
// TODO handle loops
|
||||
Decl *stored_macro = context->evaluating_macro;
|
||||
Type *stored_rtype = context->rtype;
|
||||
@@ -104,11 +104,18 @@ static inline bool sema_expr_analyse_call(Context *context, Expr *expr)
|
||||
{
|
||||
Expr *func_expr = expr->call_expr.function;
|
||||
if (!sema_analyse_expr(context, func_expr)) return false;
|
||||
if (func_expr->expr_kind != EXPR_IDENTIFIER)
|
||||
Decl *decl;
|
||||
switch (func_expr->expr_kind)
|
||||
{
|
||||
TODO
|
||||
case EXPR_TYPE_ACCESS:
|
||||
decl = func_expr->type_access.method;
|
||||
break;
|
||||
case EXPR_IDENTIFIER:
|
||||
decl = func_expr->identifier_expr.decl;
|
||||
break;
|
||||
default:
|
||||
TODO
|
||||
}
|
||||
Decl *decl = func_expr->identifier_expr.decl;
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_VAR:
|
||||
@@ -141,14 +148,166 @@ static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr)
|
||||
TODO
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
|
||||
static inline bool sema_expr_analyse_method_function(Context *context, Expr *expr, Decl *decl, bool is_pointer)
|
||||
{
|
||||
TODO
|
||||
const char *name = expr->access_expr.sub_element.string;
|
||||
VECEACH(decl->method_functions, i)
|
||||
{
|
||||
Decl *function = decl->method_functions[i];
|
||||
if (function->name.string == name)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SEMA_ERROR(expr->loc, "Cannot find method function '%s.%s'", decl->name.string, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_method_ref(Context *context, Expr *expr)
|
||||
static inline bool sema_expr_analyse_enum_constant(Context *context, Expr *expr, Decl *decl)
|
||||
{
|
||||
TODO
|
||||
const char *name = expr->type_access.name.string;
|
||||
VECEACH(decl->enums.values, i)
|
||||
{
|
||||
Decl *enum_constant = decl->enums.values[i];
|
||||
if (enum_constant->name.string == name)
|
||||
{
|
||||
assert(enum_constant->resolve_status == RESOLVE_DONE);
|
||||
expr_replace(expr, decl->enum_constant.expr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SEMA_ERROR(expr->loc, "'%s' has no enumeration value '%s'.", decl->name.string, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr, Decl *decl)
|
||||
{
|
||||
const char *name = expr->type_access.name.string;
|
||||
VECEACH(decl->error.error_constants, i)
|
||||
{
|
||||
Decl *error_constant = decl->error.error_constants[i];
|
||||
if (error_constant->name.string == name)
|
||||
{
|
||||
assert(error_constant->resolve_status == RESOLVE_DONE);
|
||||
expr->type = decl->self_type;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
expr->const_expr.type = CONST_INT;
|
||||
expr->const_expr.i = decl->error_constant.value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SEMA_ERROR(expr->loc, "'%s' has no error type '%s'.", decl->name.string, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static Decl *strukt_recursive_search_member(Decl *strukt, const char *name)
|
||||
{
|
||||
VECEACH(strukt->strukt.members, i)
|
||||
{
|
||||
Decl *member = strukt->strukt.members[i];
|
||||
if (member->name.string == name) return member;
|
||||
if (!member->name.string && decl_is_struct_type(member))
|
||||
{
|
||||
Decl *result = strukt_recursive_search_member(member, name);
|
||||
if (result) return result;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
|
||||
{
|
||||
if (!sema_analyse_expr(context, expr->access_expr.parent)) return false;
|
||||
Type *parent_type = expr->access_expr.parent->type;
|
||||
|
||||
Type *type = parent_type->canonical;
|
||||
bool is_pointer = type->type_kind == TYPE_POINTER;
|
||||
if (is_pointer)
|
||||
{
|
||||
type = type->base;
|
||||
}
|
||||
if (!type_may_have_method_functions(type))
|
||||
{
|
||||
SEMA_ERROR(expr->loc, "Cannot access '%s' on '%s'", expr->access_expr.sub_element.string, type_to_error_string(parent_type));
|
||||
return false;
|
||||
}
|
||||
Decl *decl = type->decl;
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_ENUM:
|
||||
case DECL_ERROR:
|
||||
return sema_expr_analyse_method_function(context, expr, decl, is_pointer);
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string);
|
||||
if (!member)
|
||||
{
|
||||
SEMA_ERROR(expr->access_expr.sub_element, "There is no element '%s.%s'.", decl->name.string, expr->access_expr.sub_element.string);
|
||||
return false;
|
||||
}
|
||||
if (is_pointer)
|
||||
{
|
||||
Expr *deref = expr_new(EXPR_UNARY, expr->loc);
|
||||
deref->unary_expr.operator = TOKEN_STAR;
|
||||
deref->unary_expr.expr = expr->access_expr.parent;
|
||||
deref->resolve_status = RESOLVE_DONE;
|
||||
deref->type = type;
|
||||
expr->access_expr.parent = deref;
|
||||
}
|
||||
if (member->decl_kind == DECL_VAR)
|
||||
{
|
||||
expr->type = member->var.type;
|
||||
}
|
||||
else
|
||||
{
|
||||
expr->type = member->self_type;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr)
|
||||
{
|
||||
Type *type = expr->type_access.type;
|
||||
if (!sema_resolve_type(context, type)) return false;
|
||||
if (!type_may_have_method_functions(type))
|
||||
{
|
||||
SEMA_ERROR(expr->loc, "'%s' does not have method functions.", type_to_error_string(type));
|
||||
return false;
|
||||
}
|
||||
Decl *decl = type->decl;
|
||||
// TODO add more constants that can be inspected?
|
||||
// e.g. SomeEnum.values, MyUnion.x.offset etc?
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_ENUM:
|
||||
if (expr->type_access.name.type == TOKEN_CONST_IDENT) return sema_expr_analyse_enum_constant(context, expr, decl);
|
||||
break;
|
||||
case DECL_ERROR:
|
||||
if (expr->type_access.name.type == TOKEN_CONST_IDENT) return sema_expr_analyse_error_constant(context, expr, decl);
|
||||
break;
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
VECEACH(type->decl->method_functions, i)
|
||||
{
|
||||
Decl *function = type->decl->method_functions[i];
|
||||
if (expr->type_access.name.string == function->name.string)
|
||||
{
|
||||
expr->type_access.method = function;
|
||||
expr->type = function->func.function_signature.rtype;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SEMA_ERROR(expr->loc, "No function '%s.%s' found.", type_to_error_string(type), expr->type_access.name.string);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline Decl *decl_find_by_name(Decl** decls, const char *name)
|
||||
@@ -631,11 +790,6 @@ static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner)
|
||||
SEMA_ERROR(inner->loc, "Dereferencing nil is not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (canonical->nullable)
|
||||
{
|
||||
SEMA_ERROR(inner->loc, "Dereferencing a nullable pointer is not allowed.");
|
||||
return false;
|
||||
}
|
||||
Type *deref_type = inner->type->type_kind != TYPE_POINTER ? inner->type : canonical;
|
||||
expr->type = deref_type->base;
|
||||
return true;
|
||||
@@ -651,7 +805,6 @@ static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *inner)
|
||||
Type *type = type_new(TYPE_POINTER);
|
||||
type->name_loc = inner->type->name_loc;
|
||||
type->base = inner->type;
|
||||
type->nullable = false;
|
||||
type->resolve_status = RESOLVE_DONE;
|
||||
type->canonical = type_get_canonical_ptr(type);
|
||||
assert(type->resolve_status == RESOLVE_DONE);
|
||||
@@ -912,7 +1065,7 @@ static ExprAnalysis EXPR_ANALYSIS[EXPR_CAST + 1] = {
|
||||
[EXPR_POST_UNARY] = &sema_expr_analyse_postunary,
|
||||
[EXPR_TYPE] = &sema_expr_analyse_type,
|
||||
[EXPR_IDENTIFIER] = &sema_expr_analyse_identifier,
|
||||
[EXPR_METHOD_REF] = &sema_expr_analyse_method_ref,
|
||||
[EXPR_TYPE_ACCESS] = &sema_expr_analyse_type_access,
|
||||
[EXPR_CALL] = &sema_expr_analyse_call,
|
||||
[EXPR_SIZEOF] = &sema_expr_analyse_sizeof,
|
||||
[EXPR_SUBSCRIPT] = &sema_expr_analyse_subscript,
|
||||
|
||||
@@ -207,14 +207,14 @@ static Path *parse_path(void)
|
||||
Path *path = malloc_arena(sizeof(Path));
|
||||
memset(path, 0, sizeof(Path));
|
||||
|
||||
path->package = tok;
|
||||
path->sub_module = tok;
|
||||
|
||||
if (tok.type == TOKEN_IDENT && next_tok.type == TOKEN_SCOPE)
|
||||
{
|
||||
advance();
|
||||
advance();
|
||||
path->module = tok;
|
||||
path->package = tok;
|
||||
path->module = path->sub_module;
|
||||
path->sub_module = tok;
|
||||
}
|
||||
|
||||
return path;
|
||||
@@ -409,33 +409,8 @@ static Type *parse_type_expression(void)
|
||||
Type *ptr_type = type_new(TYPE_POINTER);
|
||||
assert(type);
|
||||
ptr_type->base = type;
|
||||
ptr_type->nullable = true;
|
||||
type = ptr_type;
|
||||
}
|
||||
break;
|
||||
case TOKEN_AND:
|
||||
advance();
|
||||
{
|
||||
Type *ptr_type = type_new(TYPE_POINTER);
|
||||
assert(type);
|
||||
ptr_type->base = type;
|
||||
ptr_type->nullable = false;
|
||||
type = ptr_type;
|
||||
ptr_type = type_new(TYPE_POINTER);
|
||||
ptr_type->base = type;
|
||||
ptr_type->nullable = false;
|
||||
type = ptr_type;
|
||||
break;
|
||||
}
|
||||
case TOKEN_AMP:
|
||||
advance();
|
||||
{
|
||||
Type *ptr_type = type_new(TYPE_POINTER);
|
||||
assert(type);
|
||||
ptr_type->base = type;
|
||||
ptr_type->nullable = false;
|
||||
type = ptr_type;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return type;
|
||||
@@ -1901,8 +1876,6 @@ static inline Decl *parse_struct_declaration(Visibility visibility)
|
||||
if (!consume_type_name(type_name)) return &poisoned_decl;
|
||||
Decl *decl = decl_new_user_defined_type(name, decl_from_token(type), visibility);
|
||||
|
||||
decl->strukt.method_functions = NULL;
|
||||
|
||||
if (!parse_attributes(decl))
|
||||
{
|
||||
return &poisoned_decl;
|
||||
@@ -2344,7 +2317,7 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa
|
||||
Type *type = type_new(TYPE_USER_DEFINED);
|
||||
type->unresolved.path = path;
|
||||
type->name_loc = tok;
|
||||
func->func.struct_parent = type;
|
||||
func->func.type_parent = type;
|
||||
advance_and_verify(TOKEN_TYPE_IDENT);
|
||||
|
||||
TRY_CONSUME_OR(TOKEN_DOT, "Expected '.' after the type in a method function.", false);
|
||||
@@ -3029,7 +3002,7 @@ static Expr *parse_nil(Expr *left)
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok);
|
||||
number->const_expr.type = CONST_NIL;
|
||||
number->type = type_get_canonical_ptr(type_void);
|
||||
number->type = type_voidptr;
|
||||
number->resolve_status = RESOLVE_DONE;
|
||||
advance();
|
||||
return number;
|
||||
@@ -3089,13 +3062,13 @@ static Expr *parse_initializer(void)
|
||||
* @param type
|
||||
* @return Expr
|
||||
*/
|
||||
static Expr *parse_method_ref(Type *type)
|
||||
static Expr *parse_type_access(Type *type)
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_METHOD_REF, tok);
|
||||
expr->method_ref_expr.type = type;
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPE_ACCESS, tok);
|
||||
expr->type_access.type = type;
|
||||
|
||||
advance_and_verify(TOKEN_DOT);
|
||||
expr->method_ref_expr.method = tok;
|
||||
expr->type_access.name = tok;
|
||||
|
||||
TRY_CONSUME_OR(TOKEN_IDENT, "Expected a function name or value", &poisoned_expr);
|
||||
|
||||
@@ -3141,7 +3114,7 @@ static Expr *parse_type_identifier_with_path(Path *path)
|
||||
return expr;
|
||||
}
|
||||
EXPECT_OR(TOKEN_DOT, &poisoned_expr);
|
||||
return parse_method_ref(type);
|
||||
return parse_type_access(type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@ void sema_shadow_error(Decl *decl, Decl *old)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Decl *context_find_ident(Context *context, const char *symbol)
|
||||
{
|
||||
Decl **first = &context->locals[0];
|
||||
@@ -185,7 +186,6 @@ static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
|
||||
|
||||
static inline bool sema_analyse_function_param(Context *context, Decl *param, bool is_function)
|
||||
{
|
||||
if (!decl_ok(param)) return false;
|
||||
assert(param->decl_kind == DECL_VAR);
|
||||
assert(param->var.kind == VARDECL_PARAM);
|
||||
if (!sema_resolve_type(context, param->var.type))
|
||||
@@ -218,11 +218,16 @@ static inline bool sema_analyse_function_signature(Context *context, FunctionSig
|
||||
// TODO check parameter name appearing more than once.
|
||||
VECEACH(signature->params, i)
|
||||
{
|
||||
if (!sema_analyse_function_param(context, signature->params[i], is_function))
|
||||
Decl *param = signature->params[i];
|
||||
assert(param->resolve_status == RESOLVE_NOT_DONE);
|
||||
param->resolve_status = RESOLVE_RUNNING;
|
||||
if (!sema_analyse_function_param(context, param, is_function))
|
||||
{
|
||||
decl_poison(signature->params[i]);
|
||||
decl_poison(param);
|
||||
all_ok = false;
|
||||
continue;
|
||||
}
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
VECEACH(signature->throws, i)
|
||||
{
|
||||
@@ -939,13 +944,40 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
|
||||
context_pop_scope(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_analyse_method_function(Context *context, Decl *decl)
|
||||
{
|
||||
Type *parent_type = decl->func.type_parent;
|
||||
if (!sema_resolve_type(context, parent_type)) return false;
|
||||
if (!type_may_have_method_functions(parent_type))
|
||||
{
|
||||
SEMA_ERROR(decl->name, "Method functions can not be associated with '%s'", type_to_error_string(decl->func.type_parent));
|
||||
return false;
|
||||
}
|
||||
Decl *parent = parent_type->decl;
|
||||
VECEACH(parent->method_functions, i)
|
||||
{
|
||||
Decl *function = parent->method_functions[i];
|
||||
if (function->name.string == decl->name.string)
|
||||
{
|
||||
SEMA_ERROR(decl->name, "Duplicate name '%s' for method function.", function->name);
|
||||
sema_prev_at_range(function->name.span, "Previous definition here.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG("Method function '%s.%s' analysed.", parent->name.string, decl->name.string);
|
||||
vec_add(parent->method_functions, decl);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_func(Context *context, Decl *decl)
|
||||
{
|
||||
DEBUG_LOG("Analysing function %s", decl->name.string);
|
||||
bool all_ok = sema_analyse_function_signature(context, &decl->func.function_signature, true);
|
||||
if (decl->func.struct_parent)
|
||||
if (decl->func.type_parent)
|
||||
{
|
||||
all_ok = sema_resolve_type(context, decl->func.struct_parent) && all_ok;
|
||||
all_ok = all_ok && sema_analyse_method_function(context, decl);
|
||||
}
|
||||
all_ok = all_ok && sema_analyse_function_body(context, decl);
|
||||
if (!all_ok) decl_poison(decl);
|
||||
@@ -1128,26 +1160,19 @@ static inline void sema_process_imports(Context *context)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
void sema_analysis(Context *context)
|
||||
{
|
||||
const char *printf = "printf";
|
||||
TokenType t_type = TOKEN_IDENT;
|
||||
const char *interned = symtab_add(printf, (uint32_t) 6, fnv1a(printf, (uint32_t)6), &t_type);
|
||||
Decl *decl = decl_new(DECL_FUNC, wrap(interned), VISIBLE_PUBLIC);
|
||||
Type *type = type_new(TYPE_POINTER);
|
||||
type->base = type_char;
|
||||
sema_resolve_type(context, type);
|
||||
Decl *param = decl_new_var(wrap("str"), type, VARDECL_PARAM, VISIBLE_LOCAL);
|
||||
|
||||
vec_add(decl->func.function_signature.params, param);
|
||||
decl->func.function_signature.rtype = type_void;
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
context_register_global_decl(context, decl);
|
||||
sema_process_imports(context);
|
||||
void sema_analysis_pass_conditional_compilation(Context *context)
|
||||
{
|
||||
DEBUG_LOG("Pass 1 - analyse: %s", context->file->name);
|
||||
VECEACH(context->ct_ifs, i)
|
||||
{
|
||||
sema_analyse_top_level_if(context, context->ct_ifs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void sema_analysis_pass_decls(Context *context)
|
||||
{
|
||||
DEBUG_LOG("Pass 2 - analyse: %s", context->file->name);
|
||||
VECEACH(context->enums, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->enums[i]);
|
||||
@@ -1156,6 +1181,10 @@ void sema_analysis(Context *context)
|
||||
{
|
||||
sema_analyse_decl(context, context->types[i]);
|
||||
}
|
||||
VECEACH(context->struct_functions, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->struct_functions[i]);
|
||||
}
|
||||
VECEACH(context->vars, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->vars[i]);
|
||||
@@ -1175,7 +1204,7 @@ bool sema_resolve_type_shallow(Context *context, Type *type)
|
||||
|
||||
if (type->resolve_status == RESOLVE_RUNNING)
|
||||
{
|
||||
SEMA_ERROR(type->name_loc, "Circular dependency resolving type '%s'.", type->name_loc);
|
||||
SEMA_ERROR(type->name_loc, "Circular dependency resolving type '%s'.", type->name_loc.string);
|
||||
type_poison(type);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ void symtab_init(uint32_t capacity)
|
||||
uint32_t len = (uint32_t)strlen(name);
|
||||
TokenType type = (TokenType)i;
|
||||
const char* interned = symtab_add(name, (uint32_t)strlen(name), fnv1a(name, len), &type);
|
||||
assert(type == i);
|
||||
assert(type == (TokenType)i);
|
||||
assert(symtab_add(name, (uint32_t)strlen(name), fnv1a(name, len), &type) == interned);
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "compiler_internal.h"
|
||||
|
||||
Type *type_bool, *type_void, *type_string;
|
||||
Type *type_bool, *type_void, *type_string, *type_voidptr;
|
||||
Type *type_float, *type_double;
|
||||
Type *type_char, *type_short, *type_int, *type_long, *type_isize;
|
||||
Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
||||
@@ -19,7 +19,7 @@ Type t_f32, t_f64, t_fxx;
|
||||
Type t_usz, t_isz;
|
||||
Type t_cus, t_cui, t_cul, t_cull;
|
||||
Type t_cs, t_ci, t_cl, t_cll;
|
||||
|
||||
Type t_voidstar;
|
||||
|
||||
Type *type_signed_int_by_size(int bitsize)
|
||||
{
|
||||
@@ -70,7 +70,7 @@ const char *type_to_error_string(Type *type)
|
||||
case TYPE_FXX:
|
||||
return type->name_loc.string;
|
||||
case TYPE_POINTER:
|
||||
asprintf(&buffer, "%s%s", type_to_error_string(type->base), type->nullable ? "*" : "?");
|
||||
asprintf(&buffer, "%s*", type_to_error_string(type->base));
|
||||
return buffer;
|
||||
case TYPE_STRING:
|
||||
return "string";
|
||||
@@ -147,7 +147,6 @@ static inline void create_ptr_live_canonical(Type *canonical_type)
|
||||
assert(canonical_type->canonical == canonical_type);
|
||||
canonical_type->ptr_like_canonical = VECADD(canonical_type->ptr_like_canonical, NULL);
|
||||
canonical_type->ptr_like_canonical = VECADD(canonical_type->ptr_like_canonical, NULL);
|
||||
canonical_type->ptr_like_canonical = VECADD(canonical_type->ptr_like_canonical, NULL);
|
||||
}
|
||||
|
||||
Type *type_get_canonical_ptr(Type *ptr_type)
|
||||
@@ -161,7 +160,7 @@ Type *type_get_canonical_ptr(Type *ptr_type)
|
||||
create_ptr_live_canonical(canonical_base);
|
||||
}
|
||||
|
||||
Type *canonical_ptr = canonical_base->ptr_like_canonical[(int)ptr_type->nullable];
|
||||
Type *canonical_ptr = canonical_base->ptr_like_canonical[0];
|
||||
if (canonical_ptr == NULL)
|
||||
{
|
||||
canonical_ptr = malloc_arena(sizeof(Type));
|
||||
@@ -169,7 +168,7 @@ Type *type_get_canonical_ptr(Type *ptr_type)
|
||||
canonical_ptr->base = canonical_base;
|
||||
canonical_ptr->canonical = canonical_ptr;
|
||||
canonical_ptr->resolve_status = RESOLVE_DONE;
|
||||
canonical_base->ptr_like_canonical[(int)ptr_type->nullable] = canonical_ptr;
|
||||
canonical_base->ptr_like_canonical[0] = canonical_ptr;
|
||||
canonical_base->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
|
||||
@@ -187,20 +186,20 @@ Type *type_get_canonical_array(Type *arr_type)
|
||||
// Dynamic array
|
||||
if (arr_type->len == 0)
|
||||
{
|
||||
Type *canonical = canonical_base->ptr_like_canonical[2];
|
||||
Type *canonical = canonical_base->ptr_like_canonical[1];
|
||||
if (canonical == NULL)
|
||||
{
|
||||
canonical = malloc_arena(sizeof(Type));
|
||||
*canonical = *arr_type;
|
||||
canonical->canonical = canonical_base;
|
||||
canonical_base->ptr_like_canonical[2] = canonical;
|
||||
canonical_base->ptr_like_canonical[1] = canonical;
|
||||
canonical->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
return canonical;
|
||||
}
|
||||
|
||||
int entries = (int)vec_size(canonical_base->ptr_like_canonical);
|
||||
for (int i = 3; i < entries; i++)
|
||||
for (int i = 1; i < entries; i++)
|
||||
{
|
||||
Type *ptr = canonical_base->ptr_like_canonical[i];
|
||||
if (ptr->len == arr_type->len)
|
||||
@@ -239,6 +238,10 @@ void builtin_setup()
|
||||
{
|
||||
create_type("void", &t_u0, &type_void, TYPE_VOID, 1, 8);
|
||||
create_type("string", &t_str, &type_string, TYPE_STRING, build_options.pointer_size, build_options.pointer_size * 8);
|
||||
create_ptr_live_canonical(type_void);
|
||||
type_void->ptr_like_canonical[0] = &t_voidstar;
|
||||
create_type("void*", &t_voidstar, &type_voidptr, TYPE_POINTER, 0, 0);
|
||||
t_voidstar.base = type_void;
|
||||
|
||||
/*TODO
|
||||
* decl_string = (Decl) { .decl_kind = DECL_BUILTIN, .name.string = "string" };
|
||||
@@ -308,3 +311,19 @@ bool type_is_subtype(Type *type, Type *possible_subtype)
|
||||
}
|
||||
|
||||
|
||||
bool type_may_have_method_functions(Type *type)
|
||||
{
|
||||
// An alias is not ok.
|
||||
if (type->type_kind != TYPE_USER_DEFINED) return false;
|
||||
Decl *decl = type->decl;
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
case DECL_ERROR:
|
||||
case DECL_ENUM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user