Removed non-null references.

This commit is contained in:
Christoffer Lerno
2019-09-30 13:29:41 +02:00
parent 5f00d4c2bc
commit a3b90b9500
16 changed files with 650 additions and 144 deletions

View File

@@ -257,7 +257,6 @@ base_type
type_expression
: base_type
| type_expression '*'
| type_expression '&'
| type_expression '[' constant_expression ']'
| type_expression '[' ']'
| type_expression '[' '+' ']'

View File

@@ -0,0 +1,273 @@
module bigint;
macro @max(a, b)
{
return a > b ? a : b;
}
// Horribly bad implementation of BigInt with add/sub.
public struct BigInt @opaque
{
byte& number;
uint length;
char sign;
}
public func void BigInt.init(BigInt& bigInt)
{
bigInt.number = malloc(1);
bigInt.number[0] = 0;
bigInt.length = 1;
bigInt.sign = 1;
}
public func void BigInt.initFromString(BigInt& bigInt, char& str)
{
uint size = strlen(str);
bigInt.sign = 1;
switch (str[0])
{
case '-':
bigInt.sign = -1;
size--;
str++;
case '+':
size--;
str++;
default:
break;
}
char* res = malloc(size);
for (uint i = 0; i < size; i++)
{
res[i] = str[size - i - 1] - '0';
}
bigInt.number = res;
bigInt.length = size;
}
public func BigInt& BigInt.newFromString(char& str)
{
BigInt& bigInt = malloc(sizeof(BigInt));
bigInt.initFromString(str);
return bigInt;
}
public func void BigInt.copyTo(BigInt& source, BigInt& target)
{
target.number = realloc(target.number, source.length);
target.sign = source.sign;
target.length = source.length;
for (uint i = 0; i < target.length; i++) target.number[i] = source.number[i];
}
public func void BigInt.destroy(BigInt& bigInt)
{
free(bigInt.number);
}
func void BigInt.addIgnoreSign(BigInt& a, BigInt& b, BigInt& result)
{
uint length = @max(a.length, b.length) + 1;
byte* res = malloc(length);
char carry = 0;
BigInt* x;
BigInt* y;
if (a.length > b.length)
{
x = a;
y = b;
}
else
{
x = b;
y = a;
}
for (uint i = 0; i < length; i++)
{
if (i >= y.length)
{
res[i] = carry + (i >= x.length ? 0 : x.number[i]);
}
else
{
res[i] = x.number[i] + y.number[i] + carry;
}
carry = 0;
if (res[i] > 9)
{
carry = 1;
res[i] -= 10;
}
}
result.destroy();
result.number = res;
result.length = length;
}
public func void BigInt.getMaxVal(BigInt &bigInt, uint& pos, int& val)
{
for (uint i = bigInt.length; i > 0; i++)
{
if (bigInt.number[i] != 0)
{
*pos = i;
*val = bigInt.number[i];
return;
}
}
*pos = 0;
*val = 0;
}
public func char BigInt.compare(BigInt& a, BigInt& b)
{
if (a.sign != b.sign) return a.sign;
byte aMax;
uint aMaxPos;
a.getMaxVal(&aMaxPos, &aMax);
if (aMaxPos >= b.length) return a.sign;
byte bMax;
uint bMaxPos;
b.getMaxVal(&bMaxPos, &bMax);
if (aMaxPos > bMaxPos) return a.sign;
if (aMaxPos < bMaxPos) return -a.sign;
if (aMax > bMax) return a.sign;
if (aMax < bMax) return -a.sign;
return 0;
}
public func char BigInt.compareNoSign(BigInt& a, BigInt& b)
{
byte aMax;
uint aMaxPos;
a.getMaxVal(&aMaxPos, &aMax);
if (aMaxPos >= b.length) return 1;
byte bMax;
uint bMaxPos;
b.getMaxVal(&bMaxPos, &bMax);
if (aMaxPos > bMaxPos) return 1;
if (aMaxPos < bMaxPos) return -1;
if (aMax > bMax) return 1;
if (aMax < bMax) return -1;
return 0;
}
func void BigInt.subIgnoreSign(BigInt& a, BigInt& b, BigInt& result)
{
uint length = @max(a.length, b.length);
byte& res = malloc(length);
BigInt& x;
BigInt& y;
if (a.compareNoSign(b) < 0)
{
result.sign = -1;
x = b;
y = a;
}
else
{
result.sign = 1;
x = a;
y = b;
}
byte borrow = 0;
for (uint i = 0; i < length; i++)
{
byte aValue = i >= x.length ? 0 : x.number[i];
byte bValue = borrow + (i >= y.length ? 0 : y.number[i]);
if (bValue > aValue)
{
borrow = 1;
aValue += 10;
}
else
{
borrow = 0;
}
res[i] = aValue - bValue;
}
result.destroy();
result.number = res;
result.length = length;
}
public func void BigInt.add(BigInt& a, BigInt& b, BigInt& result)
{
if (a.sign == b.sign)
{
a.addIgnoreSign(b, result);
result.sign = a.sign;
return;
}
if (a.sign < 0)
{
b.subIgnoreSign(a, result);
}
else
{
a.subIgnoreSign(a, result);
}
}
public func char* BigInt.toCharArray(BigInt* bigInt)
{
uint charLen = bigInt.length + 1 + (bigInt.sign < 0 ? 1 : 0);
byte* out = malloc(charLen);
out[charLen - 1] = '\0';
byte* start = out;
if (bigInt.sign < 0)
{
out[0] = '-';
start++;
}
bool nonZeroFound = false;
for (uint i = bigInt.length; i > 0; i--)
{
byte digit = bigInt.number[i - 1];
if (i > 1 && !nonZeroFound && digit == 0) continue;
nonZeroFound = true;
*(start++) = digit + '0';
}
return out;
}
public func void BigInt.print(BigInt& bigInt)
{
char* chars = bigInt.toCharArray();
puts(chars);
free(chars);
}
/*
public func void BigInt.fprint(BigInt* bigInt, FILE* file)
{
char* chars = bigInt.toCharArray();
fputs(chars, file);
putc('\n', file);
free(chars);
}*/
public func int main(int size, char*& args)
{
BigInt minus2;
BigInt minus1;
BigInt current;
minus2.initFromString("0");
minus1.initFromString("1");
current.initFromString("0");
for (int i = 1; i <= 500; i++)
{
minus1.add(&minus2, &current);
printf("%d : ", i);
current.print();
minus1.copyTo(&minus2);
current.copyTo(&minus1);
}
return 0;
}

View File

@@ -1,7 +1,19 @@
module foo;
public struct Foo
{
int i;
}
public func int Foo.test(Foo *foo)
{
if (!foo) return 0;
return foo.i;
}
public func void gonk()
{
Foo.test(nil);
printf("Bob\n");
}
func void test()

View File

@@ -8,6 +8,6 @@ func void test()
func void main()
{
gronk();
gonk();
printf("Helo\n");
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);
}
/**

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}
}