mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Refactor type handling, some extremely simple codegen, but mostly work on casts (not finished)
This commit is contained in:
@@ -25,7 +25,6 @@ add_executable(c3c
|
||||
src/compiler/source_file.c
|
||||
src/compiler/diagnostics.c
|
||||
src/compiler/ast.c
|
||||
src/compiler/module.c
|
||||
src/compiler/value.c src/compiler/value.h src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c)
|
||||
src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c src/compiler/builtins.c src/compiler/codegen.c src/compiler/const_folding.c src/compiler/enums.h src/compiler/casts.c src/compiler/compiler.h src/compiler/types.c)
|
||||
|
||||
target_compile_options(c3c PRIVATE -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
module foo;
|
||||
|
||||
struct Foo
|
||||
{
|
||||
int i;
|
||||
Bar *x;
|
||||
}
|
||||
|
||||
struct Bar
|
||||
{
|
||||
Foo foo;
|
||||
Foo* fooPtr;
|
||||
}
|
||||
|
||||
func void test()
|
||||
{
|
||||
int i = 1;
|
||||
int j, k;
|
||||
int l, m = 0;
|
||||
int o = 0, p = 3;
|
||||
short f = -2;
|
||||
c_int x = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
func int test2()
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -8,7 +8,6 @@ macro void @foo(int i, $e)
|
||||
$e = 1;
|
||||
printf("Helo");
|
||||
}
|
||||
|
||||
macro @goo(i, $e)
|
||||
{
|
||||
|
||||
@@ -34,6 +33,7 @@ enum FEok : int {
|
||||
IFEJ
|
||||
}
|
||||
|
||||
|
||||
enum Test
|
||||
{
|
||||
FOO = 1 + 2,
|
||||
@@ -84,7 +84,7 @@ generic boor2(i)
|
||||
case int:
|
||||
return "Helo";
|
||||
default:
|
||||
return 1000;
|
||||
return 10001;
|
||||
}
|
||||
|
||||
$if ($e > 0)
|
||||
|
||||
@@ -264,6 +264,10 @@ void parse_arguments(int argc, const char *argv[])
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
build_options.cshort_size = sizeof(short);
|
||||
build_options.cint_size = sizeof(int);
|
||||
build_options.clong_size = sizeof(long);
|
||||
build_options.clonglong_size = sizeof(long long);
|
||||
build_options.pointer_size = sizeof(void *);
|
||||
build_options.path = ".";
|
||||
build_options.command = COMMAND_MISSING;
|
||||
|
||||
@@ -82,6 +82,11 @@ typedef struct
|
||||
CompileOption compile_option;
|
||||
DiagnosticsSeverity severity[DIAG_END_SENTINEL];
|
||||
int pointer_size;
|
||||
int cshort_size;
|
||||
int cint_size;
|
||||
int clong_size;
|
||||
int clonglong_size;
|
||||
int clongdouble_size;
|
||||
} BuildOptions;
|
||||
|
||||
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <utils/malloc.h>
|
||||
#include <build/build_options.h>
|
||||
#include <utils/lib.h>
|
||||
#include "ast.h"
|
||||
#include "compiler_internal.h"
|
||||
|
||||
Decl *decl_new_in_module(Module *module, DeclKind decl_kind, Token name, Visibility visibility)
|
||||
Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility)
|
||||
{
|
||||
assert(name.string);
|
||||
Decl *decl = malloc_arena(sizeof(Decl));
|
||||
@@ -15,75 +12,34 @@ Decl *decl_new_in_module(Module *module, DeclKind decl_kind, Token name, Visibil
|
||||
decl->decl_kind = decl_kind;
|
||||
decl->name = name;
|
||||
decl->visibility = visibility;
|
||||
decl->module = module;
|
||||
return decl;
|
||||
}
|
||||
|
||||
Type poisoned_type = { .type_kind = TYPE_POISONED };
|
||||
Type poisoned_type = { .type_kind = TYPE_POISONED, .resolve_status = RESOLVE_DONE };
|
||||
|
||||
char *type_to_string(Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_VOID:
|
||||
return "void";
|
||||
case TYPE_UNRESOLVED:
|
||||
TODO
|
||||
case TYPE_STRING:
|
||||
return "string";
|
||||
case TYPE_UNRESOLVED_EXPR:
|
||||
TODO
|
||||
case TYPE_NIL:
|
||||
return "nil";
|
||||
case TYPE_BUILTIN:
|
||||
return "TODO";
|
||||
default:
|
||||
TODO
|
||||
}
|
||||
}
|
||||
|
||||
Type *type_poisoned()
|
||||
{
|
||||
static Type poison = { .type_kind = TYPE_POISONED };
|
||||
return &poison;
|
||||
}
|
||||
Type *type_new(TypeKind type_kind)
|
||||
{
|
||||
Type *type = malloc_arena(sizeof(Type));
|
||||
memset(type, 0, sizeof(Type));
|
||||
type->type_kind = type_kind;
|
||||
return type;
|
||||
}
|
||||
|
||||
Decl *decl_new_self_type(struct _Module *module, Token name, DeclKind decl_type, TypeKind type_kind, Visibility visibility)
|
||||
Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility)
|
||||
{
|
||||
Decl *decl = decl_new_in_module(module, decl_type, name, visibility);
|
||||
Type *type = type_new(type_kind);
|
||||
type->canonical_type = type;
|
||||
Decl *decl = decl_new(decl_type, name, visibility);
|
||||
Type *type = type_new(TYPE_USER_DEFINED);
|
||||
type->resolve_status = RESOLVE_DONE;
|
||||
type->canonical = type;
|
||||
type->decl = decl;
|
||||
decl->type = type;
|
||||
decl->self_type = type;
|
||||
return decl;
|
||||
}
|
||||
|
||||
Decl poisoned_decl = { .decl_kind = DECL_POISONED, .resolve_status = RESOLVE_DONE };
|
||||
|
||||
Decl *decl_new_var(struct _Module *module, Token name, Type *type, VarDeclKind kind, Visibility visibility)
|
||||
Decl *decl_new_var(Token name, Type *type, VarDeclKind kind, Visibility visibility)
|
||||
{
|
||||
Decl *decl = decl_new_in_module(module, DECL_VAR, name, visibility);
|
||||
Decl *decl = decl_new(DECL_VAR, name, visibility);
|
||||
decl->var.kind = kind;
|
||||
decl->var.type = type;
|
||||
return decl;
|
||||
}
|
||||
|
||||
Decl *decl_new_enum_const(Decl *parent, Token name, DeclKind kind)
|
||||
{
|
||||
Decl *decl = decl_new_in_module(parent->module, DECL_VAR, name, parent->visibility);
|
||||
decl->decl_kind = kind;
|
||||
assert(parent->type);
|
||||
decl->type = parent->type;
|
||||
return decl;
|
||||
}
|
||||
|
||||
Decl *struct_find_name(Decl *decl, const char* name)
|
||||
{
|
||||
Decl** compare_members = decl->strukt.members;
|
||||
@@ -110,81 +66,23 @@ Expr *expr_new(ExprKind kind, Token start)
|
||||
return expr;
|
||||
}
|
||||
|
||||
Expr poisoned_expr = { .expr_kind = EXPR_POISONED };
|
||||
Expr poisoned_expr = { .expr_kind = EXPR_POISONED, .resolve_status = RESOLVE_DONE };
|
||||
|
||||
Type type_bool;
|
||||
Type type_void, type_nil, type_string;
|
||||
|
||||
Type type_half, type_float, type_double, type_quad;
|
||||
Type type_char, type_short, type_int, type_long, type_isize;
|
||||
Type type_byte, type_ushort, type_uint, type_ulong, type_usize;
|
||||
Type type_compint, type_compfloat;
|
||||
|
||||
void type_setup(int pointer_size)
|
||||
{
|
||||
type_void = (Type) { .type_kind = TYPE_VOID, .canonical_type = &type_void };
|
||||
type_nil = (Type) { .type_kind = TYPE_NIL, .canonical_type = &type_nil };
|
||||
type_string = (Type) { .type_kind = TYPE_STRING, .canonical_type = &type_string };
|
||||
|
||||
#define DEF_TYPE(name, bits, _bytes, type) name = (Type) { .type_kind = TYPE_BUILTIN, .bitsize = bits, .bytes = _bytes, .num_type = type, .canonical_type = &name }
|
||||
|
||||
DEF_TYPE(type_compint, 0, 0, NUMBER_TYPE_SIGNED_INT);
|
||||
DEF_TYPE(type_compfloat, 0, 0, NUMBER_TYPE_FLOAT);
|
||||
|
||||
DEF_TYPE(type_bool, 1, 8, NUMBER_TYPE_BOOL);
|
||||
|
||||
DEF_TYPE(type_half, 2, 16, NUMBER_TYPE_FLOAT);
|
||||
DEF_TYPE(type_float, 4, 32, NUMBER_TYPE_FLOAT);
|
||||
DEF_TYPE(type_double, 8, 64, NUMBER_TYPE_FLOAT);
|
||||
DEF_TYPE(type_quad, 16, 128, NUMBER_TYPE_FLOAT);
|
||||
|
||||
DEF_TYPE(type_char, 1, 8, NUMBER_TYPE_SIGNED_INT);
|
||||
DEF_TYPE(type_short, 2, 16, NUMBER_TYPE_SIGNED_INT);
|
||||
DEF_TYPE(type_int, 4, 32, NUMBER_TYPE_SIGNED_INT);
|
||||
DEF_TYPE(type_long, 8, 64, NUMBER_TYPE_SIGNED_INT);
|
||||
DEF_TYPE(type_isize, pointer_size / 8, pointer_size, NUMBER_TYPE_SIGNED_INT);
|
||||
|
||||
DEF_TYPE(type_byte, 1, 8, NUMBER_TYPE_UNSIGNED_INT);
|
||||
DEF_TYPE(type_ushort, 2, 16, NUMBER_TYPE_UNSIGNED_INT);
|
||||
DEF_TYPE(type_uint, 4, 32, NUMBER_TYPE_UNSIGNED_INT);
|
||||
DEF_TYPE(type_ulong, 8, 64, NUMBER_TYPE_UNSIGNED_INT);
|
||||
DEF_TYPE(type_usize, pointer_size / 8, pointer_size, NUMBER_TYPE_UNSIGNED_INT);
|
||||
|
||||
#undef DEF_TYPE
|
||||
|
||||
}
|
||||
|
||||
Type* type_int_max_type(bool is_signed)
|
||||
{
|
||||
return is_signed ? &type_long : &type_ulong;
|
||||
}
|
||||
|
||||
Type *type_get_signed(Type *type)
|
||||
{
|
||||
assert(type->type_kind == TYPE_BUILTIN);
|
||||
if (type->num_type == NUMBER_TYPE_SIGNED_INT) return type;
|
||||
assert(type->num_type == NUMBER_TYPE_UNSIGNED_INT);
|
||||
switch (type->bytes)
|
||||
{
|
||||
case 8:
|
||||
return &type_long;
|
||||
case 4:
|
||||
return &type_int;
|
||||
case 2:
|
||||
return &type_short;
|
||||
case 1:
|
||||
return &type_char;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Type* type_get_unsigned(Type *type)
|
||||
{
|
||||
assert(type->type_kind == TYPE_BUILTIN);
|
||||
if (type->num_type == NUMBER_TYPE_UNSIGNED_INT) return type;
|
||||
assert(type->num_type == NUMBER_TYPE_SIGNED_INT);
|
||||
switch (type->bytes)
|
||||
Decl *decl = type->decl;
|
||||
if (decl->builtin.num_type == NUMBER_TYPE_UNSIGNED_INT) return type;
|
||||
assert(decl->builtin.num_type == NUMBER_TYPE_SIGNED_INT);
|
||||
switch (decl->builtin.bytes)
|
||||
{
|
||||
case 8:
|
||||
return &type_ulong;
|
||||
@@ -199,7 +97,7 @@ Type* type_get_unsigned(Type *type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
BinOp bin_op[256] = {
|
||||
[TOKEN_EQ] = BINOP_ASSIGN,
|
||||
@@ -307,6 +205,8 @@ void fprint_endparen(FILE *file, int indent)
|
||||
fprintf(file, ")\n");
|
||||
}
|
||||
|
||||
void fprint_decl_recursive(FILE *file, Decl *decl, int indent);
|
||||
|
||||
void fprint_type_recursive(FILE *file, Type *type, int indent)
|
||||
{
|
||||
fprint_indent(file, indent);
|
||||
@@ -320,73 +220,78 @@ void fprint_type_recursive(FILE *file, Type *type, int indent)
|
||||
case TYPE_POISONED:
|
||||
fprintf(file, "(POISON)\n");
|
||||
return;
|
||||
case TYPE_UNRESOLVED:
|
||||
if (type->unresolved.module.string)
|
||||
case TYPE_USER_DEFINED:
|
||||
if (type->resolve_status == RESOLVE_DONE)
|
||||
{
|
||||
fprintf(file, "(unresolved %s::%s)\n", type->unresolved.module.string, type->unresolved.name.string);
|
||||
if (type->decl != type->canonical->decl)
|
||||
{
|
||||
fprintf(file, "(user-defined %s::%s\n", type->decl->module->name, type->decl->name.string);
|
||||
fprint_type_recursive(file, type->canonical, indent + 1);
|
||||
break;
|
||||
}
|
||||
fprintf(file, "(user-defined %s::%s)\n", type->decl->module->name, type->decl->name.string);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "(unresolved %s)\n", type->unresolved.name.string);
|
||||
fprintf(file, "(unresolved %s::%s)\n", type->unresolved.module.string, type->name_loc.string);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
case TYPE_UNRESOLVED_EXPR:
|
||||
fprintf(file, "(unresolved\n");
|
||||
fprint_expr_recursive(file, type->unresolved_type_expr, indent + 1);
|
||||
fprint_endparen(file, indent);
|
||||
return;
|
||||
case TYPE_VOID:
|
||||
fprintf(file, "(void)\n");
|
||||
return;
|
||||
case TYPE_OPAQUE:
|
||||
break;
|
||||
case TYPE_BUILTIN:
|
||||
fprintf(file, "(builtin)\n");
|
||||
return;
|
||||
case TYPE_NIL:
|
||||
fprintf(file, "(nil)\n");
|
||||
return;
|
||||
case TYPE_POINTER:
|
||||
fprintf(file, "(pointer\n");
|
||||
fprint_type_recursive(file, type->base, indent + 1);
|
||||
fprint_endparen(file, indent);
|
||||
break;
|
||||
case TYPE_VARARRAY:
|
||||
fprintf(file, "(vararray\n");
|
||||
fprint_type_recursive(file, type->base, indent + 1);
|
||||
break;
|
||||
case TYPE_EXPRESSION:
|
||||
fprintf(file, "(typexpr\n");
|
||||
fprint_expr_recursive(file, type->unresolved_type_expr, indent + 1);
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
if (type->resolve_status == RESOLVE_DONE)
|
||||
{
|
||||
fprintf(file, "(array [%zu]\n", type->len);
|
||||
fprint_type_recursive(file, type->base, indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "(unresolved-array\n");
|
||||
fprint_type_recursive(file, type->base, indent + 1);
|
||||
fprint_expr_recursive(file, type->unresolved_len, indent + 1);
|
||||
}
|
||||
break;
|
||||
case TYPE_INC_ARRAY:
|
||||
fprintf(file, "(TYPETODO)\n");
|
||||
return;
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOL:
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
fprintf(file, "(%s)\n", type->name_loc.string);
|
||||
return;
|
||||
case TYPE_IXX:
|
||||
fprintf(file, "(comp time int)\n");
|
||||
return;
|
||||
case TYPE_UXX:
|
||||
fprintf(file, "(comp time uint)\n");
|
||||
return;
|
||||
case TYPE_FXX:
|
||||
fprintf(file, "(comp time float)\n");
|
||||
return;
|
||||
case TYPE_STRING:
|
||||
fprintf(file, "(string)\n");
|
||||
return;
|
||||
case TYPE_ARRAY:
|
||||
fprintf(file, "(array [%zu]\n", type->len);
|
||||
fprint_type_recursive(file, type->base, indent + 1);
|
||||
fprint_endparen(file, indent);
|
||||
return;
|
||||
case TYPE_INC_ARRAY:
|
||||
break;
|
||||
case TYPE_UNRESOLVED_ARRAY:
|
||||
fprintf(file, "(array\n");
|
||||
fprint_type_recursive(file, type->base, indent + 1);
|
||||
fprint_expr_recursive(file, type->unresolved_len, indent + 1);
|
||||
fprint_endparen(file, indent);
|
||||
return;
|
||||
case TYPE_TYPEDEF:
|
||||
break;
|
||||
case TYPE_MACRO:
|
||||
break;
|
||||
case TYPE_FUNC_TYPE:
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
break;
|
||||
case TYPE_FUNC:
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
break;
|
||||
case TYPE_UNION:
|
||||
break;
|
||||
case TYPE_GENERIC:
|
||||
break;
|
||||
TODO
|
||||
}
|
||||
fprintf(file, "(TYPETODO)\n");
|
||||
fprint_endparen(file, indent);
|
||||
}
|
||||
void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
{
|
||||
@@ -398,8 +303,31 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
return;
|
||||
case EXPR_CONST:
|
||||
fprintf(file, "(const ");
|
||||
value_fprint(file, expr->const_expr);
|
||||
fprintf(file, ")\n");
|
||||
switch (expr->const_expr.type)
|
||||
{
|
||||
case CONST_NIL:
|
||||
fprintf(file, "nil)\n");
|
||||
break;
|
||||
case CONST_BOOL:
|
||||
fprintf(file, expr->const_expr.b ? "true" : "false");
|
||||
break;
|
||||
case CONST_INT:
|
||||
if (expr->type->type_kind >= TYPE_U8 && expr->type->type_kind <= TYPE_UXX)
|
||||
{
|
||||
fprintf(file, "%llu)\n", expr->const_expr.i);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "%lld)\n", (int64_t)expr->const_expr.i);
|
||||
}
|
||||
break;
|
||||
case CONST_FLOAT:
|
||||
fprintf(file, "%Lf)\n", expr->const_expr.f);
|
||||
break;
|
||||
case CONST_STRING:
|
||||
fprintf(file, "%s)\n", expr->const_expr.string.chars);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
case EXPR_BINARY:
|
||||
fprintf(file, "(binary %s\n", token_type_to_string(binop_to_token(expr->binary_expr.operator)));
|
||||
@@ -630,12 +558,6 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
|
||||
case DECL_POISONED:
|
||||
fprintf(file, "(poisoned-decl)\n");
|
||||
return;
|
||||
case DECL_BUILTIN:
|
||||
fprintf(file, "(builtin %s)\n", decl->name.string);
|
||||
break;
|
||||
case DECL_FUNC_TYPE:
|
||||
TODO
|
||||
break;
|
||||
case DECL_ARRAY_VALUE:
|
||||
TODO
|
||||
break;
|
||||
@@ -853,4 +775,5 @@ void fprint_decl(FILE *file, Decl *dec)
|
||||
{
|
||||
fprint_decl_recursive(file, dec, 0);
|
||||
}
|
||||
Module module_poisoned = { .name = "INVALID" };
|
||||
Module poisoned_module = { .name = "INVALID" };
|
||||
|
||||
|
||||
@@ -1,812 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "compiler_common.h"
|
||||
#include "symtab.h"
|
||||
#include "value.h"
|
||||
|
||||
typedef enum _NumberType
|
||||
{
|
||||
NUMBER_TYPE_BOOL,
|
||||
NUMBER_TYPE_FLOAT,
|
||||
NUMBER_TYPE_SIGNED_INT,
|
||||
NUMBER_TYPE_UNSIGNED_INT,
|
||||
} NumberType;
|
||||
|
||||
// IF ORDER IS CHANGED, rewrite type_implicit_convert_ordered
|
||||
typedef enum _TypeKind
|
||||
{
|
||||
TYPE_POISONED,
|
||||
TYPE_UNRESOLVED,
|
||||
TYPE_UNRESOLVED_EXPR,
|
||||
TYPE_VOID,
|
||||
TYPE_OPAQUE,
|
||||
TYPE_BUILTIN,
|
||||
TYPE_NIL,
|
||||
TYPE_POINTER,
|
||||
TYPE_STRING,
|
||||
TYPE_ARRAY,
|
||||
TYPE_INC_ARRAY,
|
||||
TYPE_UNRESOLVED_ARRAY,
|
||||
TYPE_TYPEDEF,
|
||||
TYPE_MACRO,
|
||||
TYPE_FUNC_TYPE,
|
||||
TYPE_ENUM,
|
||||
TYPE_ERROR,
|
||||
TYPE_FUNC,
|
||||
TYPE_STRUCT,
|
||||
TYPE_UNION,
|
||||
TYPE_GENERIC,
|
||||
} TypeKind;
|
||||
|
||||
struct _Type
|
||||
{
|
||||
TypeKind type_kind;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char bytes;
|
||||
unsigned char bitsize;
|
||||
NumberType num_type : 8;
|
||||
};
|
||||
Decl *decl;
|
||||
struct
|
||||
{
|
||||
Token module;
|
||||
Token name;
|
||||
} unresolved;
|
||||
Expr *unresolved_type_expr;
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
Expr *unresolved_len;
|
||||
size_t len;
|
||||
};
|
||||
Type *base;
|
||||
bool nullable : 1;
|
||||
};
|
||||
};
|
||||
Type *canonical_type;
|
||||
};
|
||||
|
||||
void type_setup(int pointer_size);
|
||||
Type *type_new(TypeKind type_kind);
|
||||
Type *type_poisoned();
|
||||
char *type_to_string(Type *type);
|
||||
|
||||
static bool type_is_poison(Type *type)
|
||||
{
|
||||
return type->type_kind == TYPE_POISONED;
|
||||
}
|
||||
|
||||
static bool type_ok(Type *type)
|
||||
{
|
||||
return !type || type->type_kind != TYPE_POISONED;
|
||||
}
|
||||
|
||||
extern Type poisoned_type;
|
||||
|
||||
extern Type type_bool, type_void, type_nil, type_string;
|
||||
|
||||
extern Type type_half, type_float, type_double, type_quad;
|
||||
extern Type type_char, type_short, type_int, type_long, type_isize;
|
||||
extern Type type_byte, type_ushort, type_uint, type_ulong, type_usize;
|
||||
|
||||
extern Type type_compint, type_compfloat;
|
||||
|
||||
typedef enum _AttrKind
|
||||
{
|
||||
ATTR_INVALID,
|
||||
ATTR_UNRESOLVED,
|
||||
} AttrKind;
|
||||
|
||||
typedef struct _Attr
|
||||
{
|
||||
Token module;
|
||||
Token name;
|
||||
union
|
||||
{
|
||||
Expr *expr;
|
||||
};
|
||||
} Attr;
|
||||
|
||||
typedef struct _ErrorDecl
|
||||
{
|
||||
Decl **error_constants;
|
||||
} ErrorDecl;
|
||||
|
||||
typedef struct _ImportDecl
|
||||
{
|
||||
ImportType type : 3;
|
||||
Token alias;
|
||||
Expr** generic_parameters;
|
||||
struct _Module *module;
|
||||
} ImportDecl;
|
||||
|
||||
typedef struct _StructDecl
|
||||
{
|
||||
Decl **members;
|
||||
Decl **method_functions;
|
||||
} StructDecl;
|
||||
|
||||
typedef enum _VarDeclKind {
|
||||
VARDECL_CONST = 0,
|
||||
VARDECL_GLOBAL = 1,
|
||||
VARDECL_LOCAL = 2,
|
||||
VARDECL_PARAM = 3,
|
||||
VARDECL_MEMBER = 4,
|
||||
VARDECL_MULTI = 5,
|
||||
} VarDeclKind;
|
||||
|
||||
typedef struct _VarDecl
|
||||
{
|
||||
VarDeclKind kind : 3;
|
||||
Type *type;
|
||||
Expr *init_expr;
|
||||
} VarDecl;
|
||||
|
||||
|
||||
typedef struct _CtIfDecl
|
||||
{
|
||||
Expr *expr;
|
||||
Decl **then;
|
||||
Decl *elif;
|
||||
} CtIfDecl;
|
||||
|
||||
|
||||
typedef enum _DeclKind
|
||||
{
|
||||
DECL_POISONED = 0,
|
||||
DECL_BUILTIN,
|
||||
DECL_FUNC,
|
||||
DECL_VAR,
|
||||
DECL_ENUM_CONSTANT,
|
||||
DECL_TYPEDEF,
|
||||
DECL_STRUCT,
|
||||
DECL_UNION,
|
||||
DECL_ENUM,
|
||||
DECL_ERROR,
|
||||
DECL_ERROR_CONSTANT,
|
||||
DECL_FUNC_TYPE,
|
||||
DECL_ARRAY_VALUE,
|
||||
DECL_IMPORT,
|
||||
DECL_MACRO,
|
||||
DECL_MULTI_DECL,
|
||||
DECL_GENERIC,
|
||||
DECL_CT_IF,
|
||||
DECL_CT_ELSE,
|
||||
DECL_CT_ELIF,
|
||||
} DeclKind;
|
||||
|
||||
static inline bool decl_may_be_type(DeclKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_ENUM:
|
||||
case DECL_ERROR:
|
||||
case DECL_FUNC_TYPE:
|
||||
case DECL_BUILTIN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
typedef struct _EnumConstantDecl
|
||||
{
|
||||
Expr *expr;
|
||||
} EnumConstantDecl;
|
||||
|
||||
typedef struct _ErrorConstantDecl
|
||||
{
|
||||
uint32_t value;
|
||||
} ErrorConstantDecl;
|
||||
|
||||
typedef struct _EnumDecl
|
||||
{
|
||||
Decl** values;
|
||||
Type *type;
|
||||
} EnumDecl;
|
||||
|
||||
|
||||
typedef struct _FunctionSignature
|
||||
{
|
||||
bool variadic : 1;
|
||||
Type *rtype;
|
||||
Decl** params;
|
||||
Token *throws;
|
||||
} FunctionSignature;
|
||||
|
||||
typedef struct _FuncDecl
|
||||
{
|
||||
const char *full_name;
|
||||
Type *struct_parent;
|
||||
FunctionSignature function_signature;
|
||||
Ast *body;
|
||||
} FuncDecl;
|
||||
|
||||
typedef struct _TypedefDecl
|
||||
{
|
||||
bool is_func : 1;
|
||||
union
|
||||
{
|
||||
FunctionSignature function_signature;
|
||||
Type *type;
|
||||
};
|
||||
} TypedefDecl;
|
||||
|
||||
typedef struct _MacroDecl
|
||||
{
|
||||
Decl **parameters;
|
||||
Type *rtype; // May be null!
|
||||
Ast *body;
|
||||
} MacroDecl;
|
||||
|
||||
typedef struct _GenericDecl
|
||||
{
|
||||
Ast **cases;
|
||||
Token *parameters;
|
||||
Type *rtype; // May be null!
|
||||
} GenericDecl;
|
||||
|
||||
|
||||
struct _Decl
|
||||
{
|
||||
DeclKind decl_kind : 6;
|
||||
bool is_exported : 1;
|
||||
Visibility visibility : 2;
|
||||
ResolveStatus resolve_status : 2;
|
||||
bool is_used : 1;
|
||||
bool is_used_public : 1;
|
||||
bool has_cname : 1;
|
||||
uint32_t alignment : 5;
|
||||
union
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t counter;
|
||||
};
|
||||
uint32_t size;
|
||||
Token name;
|
||||
struct _Module *module;
|
||||
Attr** attributes;
|
||||
Type *type;
|
||||
Type *pointer_types[2]; // Up to three stars
|
||||
union
|
||||
{
|
||||
ErrorDecl error;
|
||||
ErrorConstantDecl error_constant;
|
||||
ImportDecl import;
|
||||
StructDecl strukt;
|
||||
VarDecl var;
|
||||
EnumDecl enums;
|
||||
EnumConstantDecl enum_constant;
|
||||
FuncDecl func;
|
||||
TypedefDecl typedef_decl;
|
||||
Decl** multi_decl;
|
||||
MacroDecl macro_decl;
|
||||
GenericDecl generic_decl;
|
||||
CtIfDecl ct_if_decl;
|
||||
CtIfDecl ct_elif_decl;
|
||||
Decl** ct_else_decl;
|
||||
/*
|
||||
QualifiedType alias;
|
||||
SourceRange unparsed_alias;
|
||||
EnumConstantDecl enum_constant;
|
||||
MacroDecl macro_decl;
|
||||
FuncTypeDecl func_type;
|
||||
ArrayDecl array_decl;
|
||||
MacroParmDecl macro_param;*/
|
||||
};
|
||||
};
|
||||
|
||||
Decl *decl_new_in_module(struct _Module *module, DeclKind decl_kind, Token name, Visibility visibility);
|
||||
Decl *decl_new_self_type(struct _Module *module, Token name, DeclKind decl_type, TypeKind type_kind, Visibility visibility);
|
||||
Decl *decl_new_var(struct _Module *module, Token name, Type *type, VarDeclKind kind, Visibility visibility);
|
||||
Decl *decl_new_enum_const(Decl *parent, Token name, DeclKind kind);
|
||||
Decl *struct_find_name(Decl *decl, const char* name);
|
||||
|
||||
static inline Decl *decl_poison(Decl *decl)
|
||||
{
|
||||
decl->decl_kind = DECL_POISONED;
|
||||
return decl;
|
||||
}
|
||||
|
||||
static inline DeclKind decl_from_token(TokenType type)
|
||||
{
|
||||
if (type == TOKEN_STRUCT) return DECL_STRUCT;
|
||||
if (type == TOKEN_UNION) return DECL_UNION;
|
||||
UNREACHABLE
|
||||
}
|
||||
static inline bool decl_ok(Decl *decl)
|
||||
{
|
||||
return decl->decl_kind != DECL_POISONED;
|
||||
}
|
||||
|
||||
extern Decl poisoned_decl;
|
||||
|
||||
typedef enum _BinOp
|
||||
{
|
||||
BINOP_ERROR,
|
||||
BINOP_ASSIGN,
|
||||
BINOP_MULT,
|
||||
BINOP_MULT_ASSIGN,
|
||||
BINOP_ADD,
|
||||
BINOP_ADD_ASSIGN,
|
||||
BINOP_SUB,
|
||||
BINOP_SUB_ASSIGN,
|
||||
BINOP_DIV,
|
||||
BINOP_DIV_ASSIGN,
|
||||
BINOP_MOD,
|
||||
BINOP_MOD_ASSIGN,
|
||||
BINOP_AND,
|
||||
BINOP_AND_ASSIGN,
|
||||
BINOP_OR,
|
||||
BINOP_OR_ASSIGN,
|
||||
BINOP_BIT_AND,
|
||||
BINOP_BIT_AND_ASSIGN,
|
||||
BINOP_BIT_OR,
|
||||
BINOP_BIT_OR_ASSIGN,
|
||||
BINOP_BIT_XOR,
|
||||
BINOP_BIT_XOR_ASSIGN,
|
||||
BINOP_NE,
|
||||
BINOP_EQ,
|
||||
BINOP_GE,
|
||||
BINOP_GT,
|
||||
BINOP_LE,
|
||||
BINOP_LT,
|
||||
BINOP_SHR,
|
||||
BINOP_SHR_ASSIGN,
|
||||
BINOP_SHL,
|
||||
BINOP_SHL_ASSIGN,
|
||||
BINOP_ELVIS
|
||||
} BinOp;
|
||||
|
||||
typedef enum _AssignOp
|
||||
{
|
||||
ASSIGNOP_ERROR,
|
||||
ASSIGNOP_ASSIGN,
|
||||
ASSIGNOP_MULT_ASSIGN,
|
||||
ASSIGNOP_ADD_ASSIGN,
|
||||
ASSIGNOP_SUB_ASSIGN,
|
||||
ASSIGNOP_DIV_ASSIGN,
|
||||
ASSIGNOP_MOD_ASSIGN,
|
||||
ASSIGNOP_AND_ASSIGN,
|
||||
ASSIGNOP_OR_ASSIGN,
|
||||
ASSIGNOP_BIT_AND_ASSIGN,
|
||||
ASSIGNOP_BIT_OR_ASSIGN,
|
||||
ASSIGNOP_BIT_XOR_ASSIGN,
|
||||
ASSIGNOP_SHR_ASSIGN,
|
||||
ASSIGNOP_SHL_ASSIGN,
|
||||
} AssignOp;
|
||||
|
||||
typedef enum _UnaryOp
|
||||
{
|
||||
UNARYOP_ERROR,
|
||||
UNARYOP_DEREF,
|
||||
UNARYOP_ADDR,
|
||||
UNARYOP_NEG,
|
||||
UNARYOP_BITNEG,
|
||||
UNARYOP_NOT,
|
||||
UNARYOP_INC,
|
||||
UNARYOP_DEC,
|
||||
} UnaryOp;
|
||||
|
||||
typedef enum _ExprKind
|
||||
{
|
||||
EXPR_POISONED,
|
||||
EXPR_TRY,
|
||||
EXPR_CONST,
|
||||
EXPR_BINARY,
|
||||
EXPR_CONDITIONAL,
|
||||
EXPR_UNARY,
|
||||
EXPR_POST_UNARY,
|
||||
EXPR_TYPE,
|
||||
EXPR_IDENTIFIER,
|
||||
EXPR_METHOD_REF,
|
||||
EXPR_CALL,
|
||||
EXPR_SIZEOF,
|
||||
EXPR_SUBSCRIPT,
|
||||
EXPR_ACCESS,
|
||||
EXPR_STRUCT_VALUE,
|
||||
EXPR_STRUCT_INIT_VALUES,
|
||||
EXPR_INITIALIZER_LIST,
|
||||
EXPR_EXPRESSION_LIST,
|
||||
EXPR_DEFERRED_TOKENS,
|
||||
} ExprKind;
|
||||
|
||||
typedef struct _ExprTry
|
||||
{
|
||||
Expr *expr;
|
||||
Expr *else_expr;
|
||||
} ExprTry;
|
||||
|
||||
typedef struct _ExprMethodRef
|
||||
{
|
||||
Type *type;
|
||||
Token method;
|
||||
} ExprMethodRef;
|
||||
|
||||
typedef struct _ExprStructValue
|
||||
{
|
||||
Type *type;
|
||||
Expr *init_expr;
|
||||
} ExprStructValue;
|
||||
|
||||
typedef struct _ExprTernary
|
||||
{
|
||||
Expr *cond;
|
||||
Expr *then_expr; // May be null for elvis!
|
||||
Expr *else_expr;
|
||||
} ExprTernary;
|
||||
|
||||
typedef struct _ExprBinary
|
||||
{
|
||||
Expr *left;
|
||||
Expr *right;
|
||||
BinOp operator;
|
||||
} ExprBinary;
|
||||
|
||||
typedef struct _ExprAssign
|
||||
{
|
||||
Expr *left;
|
||||
Expr *right;
|
||||
AssignOp operator;
|
||||
} ExprAssign;
|
||||
|
||||
typedef struct _ExprUnary
|
||||
{
|
||||
Expr* expr;
|
||||
UnaryOp operator;
|
||||
} ExprUnary;
|
||||
|
||||
typedef struct _ExprCall
|
||||
{
|
||||
bool is_struct_function;
|
||||
Expr *function;
|
||||
Expr **parameters;
|
||||
} ExprCall;
|
||||
|
||||
typedef struct _ExprSubscript
|
||||
{
|
||||
Expr *expr;
|
||||
Expr *index;
|
||||
} ExprSubscript;
|
||||
|
||||
typedef struct _ExprAccess
|
||||
{
|
||||
Expr *parent;
|
||||
Token sub_element;
|
||||
} ExprAccess;
|
||||
|
||||
typedef struct _ExprIdentifier
|
||||
{
|
||||
Token module;
|
||||
Token identifier;
|
||||
bool is_ref;
|
||||
Decl *decl;
|
||||
} ExprIdentifier;
|
||||
|
||||
typedef struct _ExprType
|
||||
{
|
||||
Type *type;
|
||||
} ExprType;
|
||||
|
||||
struct _Expr
|
||||
{
|
||||
ExprKind expr_kind : 8;
|
||||
Token loc;
|
||||
Type *type;
|
||||
|
||||
union {
|
||||
Token* deferred_tokens;
|
||||
Token deferred_token;
|
||||
Value const_expr;
|
||||
ExprStructValue struct_value_expr;
|
||||
ExprMethodRef method_ref_expr;
|
||||
ExprTry try_expr;
|
||||
ExprBinary binary_expr;
|
||||
ExprAssign assign_expr;
|
||||
ExprTernary conditional_expr;
|
||||
ExprUnary unary_expr;
|
||||
ExprUnary post_expr;
|
||||
ExprCall call_expr;
|
||||
ExprSubscript subscript_expr;
|
||||
ExprAccess access_expr;
|
||||
ExprIdentifier identifier_expr;
|
||||
ExprType type_expr;
|
||||
Expr** initializer_expr;
|
||||
Expr** expression_list;
|
||||
/*
|
||||
Value const_expr;
|
||||
ExprPost post_expr;
|
||||
ExprStructInitValues struct_init_values_expr;
|
||||
ExprDesignatedInitializer designated_initializer_expr;
|
||||
ExprSizeof sizeof_expr;
|
||||
ExprCast cast_expr;*/
|
||||
};
|
||||
};
|
||||
|
||||
Expr *expr_new(ExprKind kind, Token start);
|
||||
#define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->loc)
|
||||
#define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok)
|
||||
|
||||
AssignOp assignop_from_token(TokenType type);
|
||||
BinOp binop_from_token(TokenType type);
|
||||
UnaryOp unaryop_from_token(TokenType type);
|
||||
|
||||
extern Expr poisoned_expr;
|
||||
|
||||
static inline bool expr_ok(Expr *expr)
|
||||
{
|
||||
return expr == NULL || expr->expr_kind != EXPR_POISONED;
|
||||
}
|
||||
|
||||
typedef struct _AstAttribute
|
||||
{
|
||||
|
||||
} AstAttribute;
|
||||
|
||||
typedef enum _AstKind
|
||||
{
|
||||
AST_POISONED,
|
||||
AST_ASM_STMT,
|
||||
AST_ATTRIBUTE,
|
||||
AST_BREAK_STMT,
|
||||
AST_CASE_STMT,
|
||||
AST_CATCH_STMT,
|
||||
AST_COMPOUND_STMT,
|
||||
AST_COND_STMT,
|
||||
AST_CONTINUE_STMT,
|
||||
AST_CT_IF_STMT,
|
||||
AST_CT_ELIF_STMT,
|
||||
AST_CT_ELSE_STMT,
|
||||
AST_DECLARE_STMT,
|
||||
AST_DECL_EXPR_LIST,
|
||||
AST_DEFAULT_STMT,
|
||||
AST_DEFER_STMT,
|
||||
AST_DO_STMT,
|
||||
AST_EXPR_STMT,
|
||||
AST_FOR_STMT,
|
||||
AST_GOTO_STMT,
|
||||
AST_IF_STMT,
|
||||
AST_LABEL,
|
||||
AST_NOP_STMT,
|
||||
AST_RETURN_STMT,
|
||||
AST_SWITCH_STMT,
|
||||
AST_THROW_STMT,
|
||||
AST_TRY_STMT,
|
||||
AST_NEXT_STMT,
|
||||
AST_VOLATILE_STMT,
|
||||
AST_WHILE_STMT,
|
||||
AST_GENERIC_CASE_STMT,
|
||||
AST_GENERIC_DEFAULT_STMT,
|
||||
} AstKind;
|
||||
|
||||
// Ordering here is in priority if two branches should have the same exit.
|
||||
typedef enum _ExitType
|
||||
{
|
||||
EXIT_NONE,
|
||||
EXIT_BREAK,
|
||||
EXIT_GOTO,
|
||||
EXIT_CONTINUE,
|
||||
EXIT_RETURN,
|
||||
} ExitType;
|
||||
|
||||
typedef struct _AstCompoundStmt
|
||||
{
|
||||
Ast **stmts;
|
||||
// DeferList defer_list; TODO
|
||||
} AstCompoundStmt;
|
||||
|
||||
typedef struct _AstLabel
|
||||
{
|
||||
uint16_t last_goto;
|
||||
bool is_used : 1;
|
||||
Ast *defer;
|
||||
Ast *in_defer;
|
||||
} AstLabelStmt;
|
||||
|
||||
typedef struct _AstReturnStmt
|
||||
{
|
||||
Expr *expr; // May be NULL
|
||||
Ast *defer;
|
||||
} AstReturnStmt;
|
||||
|
||||
typedef struct _AstWhileStmt
|
||||
{
|
||||
Ast *cond;
|
||||
Ast *body;
|
||||
} AstWhileStmt;
|
||||
|
||||
typedef struct _AstDoStmt
|
||||
{
|
||||
Expr *expr;
|
||||
Ast *body;
|
||||
} AstDoStmt;
|
||||
|
||||
typedef struct _AstIfStmt
|
||||
{
|
||||
Ast *cond;
|
||||
Ast *then_body;
|
||||
Ast *else_body;
|
||||
} AstIfStmt;
|
||||
|
||||
|
||||
typedef struct _AstCaseStmt
|
||||
{
|
||||
Expr *expr;
|
||||
} AstCaseStmt;
|
||||
|
||||
typedef struct _AstSwitchStmt
|
||||
{
|
||||
Ast *cond;
|
||||
Ast *body;
|
||||
} AstSwitchStmt;
|
||||
|
||||
typedef struct _AstForStmt
|
||||
{
|
||||
Ast *init;
|
||||
Expr *cond;
|
||||
Expr *incr;
|
||||
Ast *body;
|
||||
} AstForStmt;
|
||||
|
||||
typedef enum DeclExprType
|
||||
{
|
||||
DECLEXPR_DECL,
|
||||
DECLEXPR_EXPR,
|
||||
} DeclExprType;
|
||||
|
||||
typedef struct _AstCondStmt
|
||||
{
|
||||
Decl *decl;
|
||||
Ast *decl_expr;
|
||||
} AstCondStmt;
|
||||
|
||||
|
||||
typedef struct _AstDeclExprList
|
||||
{
|
||||
DeclExprType list_type : 2;
|
||||
union
|
||||
{
|
||||
Decl *decl;
|
||||
Expr *expr;
|
||||
};
|
||||
} AstDeclExprList;
|
||||
|
||||
typedef enum _GotoType
|
||||
{
|
||||
GOTO_NOT_ANALYSED,
|
||||
GOTO_JUMP_FORWARD,
|
||||
GOTO_JUMP_BACK
|
||||
} GotoType;
|
||||
|
||||
typedef struct _AstGotoStmt
|
||||
{
|
||||
GotoType type : 2;
|
||||
Ast *defer;
|
||||
union
|
||||
{
|
||||
Ast *in_defer;
|
||||
Ast *defer_end;
|
||||
};
|
||||
} AstGotoStmt;
|
||||
|
||||
typedef struct _AstDeferStmt
|
||||
{
|
||||
bool emit_boolean : 1;
|
||||
Ast *body; // Compound statement
|
||||
Ast *prev_defer;
|
||||
} AstDeferStmt;
|
||||
|
||||
typedef struct _AstCatchStmt
|
||||
{
|
||||
Decl *error_param;
|
||||
Ast *body;
|
||||
} AstCatchStmt;
|
||||
|
||||
typedef struct _AstCtIfStmt
|
||||
{
|
||||
Expr *expr;
|
||||
Ast *then;
|
||||
Ast *elif;
|
||||
} AstCtIfStmt;
|
||||
|
||||
|
||||
typedef struct _AstGenericCaseStmt
|
||||
{
|
||||
Type **types;
|
||||
Ast *body;
|
||||
} AstGenericCaseStmt;
|
||||
|
||||
typedef struct _Ast
|
||||
{
|
||||
AstKind ast_kind : 8;
|
||||
ExitType exit : 3;
|
||||
Token token;
|
||||
|
||||
union
|
||||
{
|
||||
AstAttribute attribute;
|
||||
AstCompoundStmt compound_stmt;
|
||||
Decl *declare_stmt;
|
||||
Expr *expr_stmt;
|
||||
Expr *throw_stmt;
|
||||
Ast *volatile_stmt;
|
||||
Ast *try_stmt;
|
||||
AstLabelStmt label_stmt;
|
||||
AstReturnStmt return_stmt;
|
||||
AstWhileStmt while_stmt;
|
||||
AstDoStmt do_stmt;
|
||||
AstIfStmt if_stmt;
|
||||
AstDeferStmt defer_stmt;
|
||||
AstSwitchStmt switch_stmt;
|
||||
AstCaseStmt case_stmt;
|
||||
AstCatchStmt catch_stmt;
|
||||
AstGotoStmt goto_stmt;
|
||||
AstForStmt for_stmt;
|
||||
AstCondStmt cond_stmt;
|
||||
AstCtIfStmt ct_if_stmt;
|
||||
AstCtIfStmt ct_elif_stmt;
|
||||
Ast* ct_else_stmt;
|
||||
AstDeclExprList decl_expr_list;
|
||||
AstGenericCaseStmt generic_case_stmt;
|
||||
Ast* generic_default_stmt;
|
||||
};
|
||||
} Ast;
|
||||
|
||||
|
||||
#define NEW_AST(_kind, _token) new_ast(_kind, _token)
|
||||
|
||||
void *malloc_arena(size_t mem);
|
||||
|
||||
static inline Ast *new_ast(AstKind kind, Token token)
|
||||
{
|
||||
Ast *ast = malloc_arena(sizeof(Ast));
|
||||
memset(ast, 0, sizeof(Ast));
|
||||
ast->token = token;
|
||||
ast->ast_kind = kind;
|
||||
ast->exit = EXIT_NONE;
|
||||
return ast;
|
||||
}
|
||||
|
||||
extern Ast poisoned_ast;
|
||||
static inline bool ast_ok(Ast *ast)
|
||||
{
|
||||
return ast == NULL || ast->ast_kind != AST_POISONED;
|
||||
}
|
||||
static inline void ast_poison(Ast *ast)
|
||||
{
|
||||
ast->ast_kind = AST_POISONED;
|
||||
}
|
||||
|
||||
typedef struct _Module
|
||||
{
|
||||
const char *name;
|
||||
|
||||
bool is_external;
|
||||
bool is_c_library;
|
||||
bool is_exported;
|
||||
|
||||
Ast **files; // Asts
|
||||
|
||||
Decl** functions;
|
||||
STable struct_functions;
|
||||
STable symbols;
|
||||
STable public_symbols;
|
||||
} Module;
|
||||
|
||||
extern Module module_poisoned;
|
||||
|
||||
void fprint_ast(FILE *file, Ast *ast);
|
||||
void fprint_decl(FILE *file, Decl *dec);
|
||||
void fprint_type_recursive(FILE *file, Type *type, int indent);
|
||||
void fprint_expr_recursive(FILE *file, Expr *expr, int indent);
|
||||
@@ -3,7 +3,7 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "bigint.h"
|
||||
#include "../utils/malloc.h"
|
||||
#include "../utils/lib.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
static inline uint32_t u32_min(uint32_t a, uint32_t b)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_common.h"
|
||||
#include "compiler_internal.h"
|
||||
|
||||
typedef struct _BigInt
|
||||
{
|
||||
|
||||
160
src/compiler/builtins.c
Normal file
160
src/compiler/builtins.c
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_internal.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
BuiltinType builtin_common_type[16][16] = {
|
||||
// err, wptr, nil, bool, char, short, int, long, byte,ushort, int, ulong, float,double, ctint, ctreal
|
||||
{ TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // Error
|
||||
{ TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // void
|
||||
{ TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // wptr
|
||||
{ TERR, TERR, TERR, T_U1, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_U1, T_FXX }, // bool
|
||||
{ TERR, TERR, TERR, T_I8, T_I8, T_I16, T_I32, T_I64, T_I8, T_I16, T_I32, T_I64, T_F32, T_F64, T_I8, T_FXX }, // char
|
||||
{ TERR, TERR, TERR, T_I16, T_I16, T_I16, T_I32, T_I64, T_I16, T_I16, T_I32, T_I64, T_F32, T_F64, T_I16, T_FXX }, // short
|
||||
{ TERR, TERR, TERR, T_I32, T_I32, T_I32, T_I32, T_I64, T_I32, T_I32, T_I32, T_I64, T_F32, T_F64, T_I32, T_FXX }, // int
|
||||
{ TERR, TERR, TERR, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_F32, T_F64, T_I64, T_FXX }, // long
|
||||
{ TERR, TERR, TERR, T_U8, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_U8, T_FXX }, // byte
|
||||
{ TERR, TERR, TERR, T_U16, T_I16, T_I16, T_I32, T_I64, T_U16, T_U16, T_U32, T_U64, T_F32, T_F64, T_U16, T_FXX }, // ushort
|
||||
{ TERR, TERR, TERR, T_U32, T_I32, T_I32, T_I32, T_I64, T_U32, T_U32, T_U32, T_U64, T_F32, T_F64, T_U32, T_FXX }, // uint
|
||||
{ TERR, TERR, TERR, T_U64, T_I64, T_I64, T_I64, T_I64, T_U64, T_U64, T_U64, T_U64, T_F32, T_F64, T_U64, T_FXX }, // ulong
|
||||
{ TERR, TERR, TERR, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F64, T_F32, T_F32 }, // float
|
||||
{ TERR, TERR, TERR, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64 }, // double
|
||||
{ TERR, TERR, TERR, T_U1, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_IXX, T_FXX }, // ctint
|
||||
{ TERR, TERR, TERR, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_F32, T_F64, T_FXX, T_FXX }, // ctreal
|
||||
};
|
||||
void
|
||||
BuiltinConv BUILTIN_ASSIGN_CONVERSION[16][16] = {
|
||||
//e v w b c s i l b u u u f d c c
|
||||
//r o p o h h n o y s i l l o t t
|
||||
//r i t o a o t n t h n o o u i r
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // error
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // void =
|
||||
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // wptr =
|
||||
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // bool =
|
||||
{ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // char =
|
||||
{ 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }, // short =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // int =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 }, // long =
|
||||
{ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }, // byte =
|
||||
{ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // ushort =
|
||||
{ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0 }, // uint =
|
||||
{ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0 }, // ulong =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, // float =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // double =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctint
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctfloat
|
||||
};
|
||||
|
||||
// x += x -= x /= x *=
|
||||
bool BUILTIN_ASSIGN_UPDATE_CONVERSION[16][16] = {
|
||||
//e v w b c s i l b u u u f d c c
|
||||
//r o p o h h n o y s i l l o t t
|
||||
//r i t o a o t n t h n o o u i r
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // error
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // void =
|
||||
{ 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // wptr =
|
||||
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, // bool =
|
||||
{ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // char =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // short =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // int =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // long =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // byte =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // ushort =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // uint =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // ulong =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // float =
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // double =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctint
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctfloat
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
void builtin_convert(ExprConst *value, BuiltinConv conversion, Type *canonical_target)
|
||||
{
|
||||
assert(canonical_target == canonical_target->canonical);
|
||||
switch (conversion)
|
||||
{
|
||||
case C_XXXX:
|
||||
FATAL_ERROR("Should never be called");
|
||||
break;
|
||||
case C_FPFP:
|
||||
if (canonical_target->builtin.bitsize == 16)
|
||||
{
|
||||
value->f = (float)value->f;
|
||||
}
|
||||
if (canonical_target->builtin.bitsize == 32)
|
||||
{
|
||||
value->f = (double)value->f;
|
||||
}
|
||||
break;
|
||||
case C_FPSI:
|
||||
if (value->f < 0)
|
||||
{
|
||||
value->integer.i = (uint64_t)(-value->f);
|
||||
value->type = CONST_NEGATIVE_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
value->integer.i = (uint64_t)(-value->f);
|
||||
value->type = CONST_POSITIVE_INT;
|
||||
}
|
||||
break;
|
||||
case C_FPUI:
|
||||
assert(value->f >= 0);
|
||||
value->integer.i = (uint64_t)(value->f);
|
||||
value->type = CONST_POSITIVE_INT;
|
||||
break;
|
||||
case C_SIFP:
|
||||
case C_UIFP:
|
||||
value->f = value->integer.i;
|
||||
if (value->type == CONST_NEGATIVE_INT) value->f = -value->f;
|
||||
value->type = CONST_FLOAT;
|
||||
break;
|
||||
case C_SISI:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true);
|
||||
break;
|
||||
case C_SIUI:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true);
|
||||
break;
|
||||
case C_UISI:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true);
|
||||
break;
|
||||
case C_UIUI:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true);
|
||||
break;
|
||||
case C_PTXI:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true);
|
||||
break;
|
||||
case C_XIPT:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true);
|
||||
break;
|
||||
case C_BOFP:
|
||||
// value_convert(value, VALUE_TYPE_FLOAT, canonical_target->decl->builtin.bitsize, false, true);
|
||||
break;
|
||||
case C_BOSI:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true);
|
||||
break;
|
||||
case C_BOUI:
|
||||
// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true);
|
||||
break;
|
||||
case C_FPBO:
|
||||
// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true);
|
||||
break;
|
||||
case C_XIBO:
|
||||
// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true);
|
||||
break;
|
||||
case C_PTBO:
|
||||
// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
508
src/compiler/casts.c
Normal file
508
src/compiler/casts.c
Normal file
@@ -0,0 +1,508 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_internal.h"
|
||||
|
||||
#define EXIT_T_MISMATCH() return sema_type_mismatch(left, canonical, cast_type)
|
||||
|
||||
|
||||
static inline void insert_cast(Expr *expr, CastKind kind, Type *type)
|
||||
{
|
||||
Expr *inner = malloc_arena(sizeof(Expr));
|
||||
*inner = *expr;
|
||||
expr->expr_kind = EXPR_CAST;
|
||||
expr->expr_cast.kind = kind;
|
||||
expr->type = type;
|
||||
}
|
||||
|
||||
static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type)
|
||||
{
|
||||
const char *action = "";
|
||||
switch (cast_type)
|
||||
{
|
||||
case CAST_TYPE_EXPLICIT:
|
||||
action = "cast";
|
||||
break;
|
||||
case CAST_TYPE_IMPLICIT:
|
||||
action = "implicitly cast";
|
||||
break;
|
||||
case CAST_TYPE_IMPLICIT_ASSIGN:
|
||||
case CAST_TYPE_IMPLICIT_ASSIGN_ADD:
|
||||
action = "assign";
|
||||
break;
|
||||
|
||||
}
|
||||
SEMA_ERROR(expr->loc, "Cannot %s '%s' to '%s'", action, type->name_loc.string, expr->type->name_loc.string);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool erro(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
EXIT_T_MISMATCH();
|
||||
}
|
||||
|
||||
bool ptxi(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_NIL);
|
||||
left->const_expr.type = sign_from_type(canonical);
|
||||
left->const_expr.i = 0;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_PTRINT, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ptbo(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_NIL);
|
||||
left->const_expr.type = CONST_BOOL;
|
||||
left->const_expr.b = false;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_PTRBOOL, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *target_type)
|
||||
{
|
||||
assert(current_type->canonical == current_type);
|
||||
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;
|
||||
}
|
||||
|
||||
bool ptpt(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
Type *to_cast_type = left->type->canonical;
|
||||
|
||||
if (cast_type != CAST_TYPE_EXPLICIT && !may_implicitly_cast_ptr_to_ptr(to_cast_type, canonical))
|
||||
{
|
||||
sema_type_mismatch(left, type, cast_type);
|
||||
}
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_NIL);
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_PTRPTR, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ptst(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_INT && type_is_unsigned(left->type->canonical));
|
||||
assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64);
|
||||
left->const_expr.f = left->const_expr.i;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_UIFP, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boxi(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_BOOL);
|
||||
left->const_expr.type = sign_from_type(canonical);
|
||||
left->const_expr.i = left->const_expr.b ? 1 : 0;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_BOOLINT, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bofp(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_NIL);
|
||||
left->const_expr.type = CONST_FLOAT;
|
||||
left->const_expr.f = left->const_expr.b ? 1.0 : 0.0;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_BOOLFP, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xibo(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_INT);
|
||||
left->const_expr.type = CONST_BOOL;
|
||||
left->const_expr.b = left->const_expr.i != 0;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_INTBOOL, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fpbo(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_FLOAT);
|
||||
left->const_expr.type = CONST_BOOL;
|
||||
left->const_expr.b = left->const_expr.f != 0;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_INTBOOL, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool fpfp(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
Type *left_canonical = left->type->canonical;
|
||||
bool is_narrowing = left_canonical->builtin.bytesize < canonical->builtin.bytesize && left_canonical->type_kind != TYPE_FXX;
|
||||
|
||||
// Is this correct? TODO
|
||||
if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
||||
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_FLOAT);
|
||||
if (type->type_kind == TYPE_F32)
|
||||
{
|
||||
left->const_expr.f = (float)left->const_expr.f;
|
||||
}
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_FPFP, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fpui(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_FLOAT);
|
||||
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64);
|
||||
left->const_expr.i = (uint64_t)left->const_expr.f;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_FPUI, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fpsi(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_FLOAT);
|
||||
assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64);
|
||||
left->const_expr.i = (uint64_t)((int64_t)left->const_expr.f);
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_FPUI, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t type_mask[4] = { 0xFF, 0xFFFF, 0xFFFFFFFFU, 0xFFFFFFFFFFFFFFFFLLU};
|
||||
static int64_t int_type_max[4] = { INT8_MAX, INT16_MAX, INT32_MAX, INT64_MAX };
|
||||
static uint64_t uint_type_max[4] = { UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX };
|
||||
static int64_t int_type_min[4] = { INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN };
|
||||
|
||||
bool sisi(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
Type *left_canonical = left->type->canonical;
|
||||
bool is_narrowing = left->type->builtin.bytesize < canonical->builtin.bytesize && left_canonical->type_kind != TYPE_IXX;
|
||||
|
||||
if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
int64_t i = (int64_t)left->const_expr.i;
|
||||
int index = canonical->type_kind - TYPE_I8;
|
||||
if (left_canonical->type_kind == TYPE_IXX)
|
||||
{
|
||||
if ((i > int_type_max[index]) || (i < int_type_min[index]))
|
||||
{
|
||||
SEMA_ERROR(left->loc, "'%lld' does not fit into '%s'", i, canonical->name_loc.string);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(left->const_expr.type == CONST_INT);
|
||||
assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64);
|
||||
uint64_t mask = type_mask[index];
|
||||
if (i < 0)
|
||||
{
|
||||
left->const_expr.i = ~((~((uint64_t)i)) & mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
left->const_expr.i &= mask;
|
||||
}
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
assert(left_canonical->type_kind != TYPE_IXX);
|
||||
insert_cast(left, CAST_SISI, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool siui(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
// TODO
|
||||
Type *left_canonical = left->type->canonical;
|
||||
bool is_narrowing = left->type->builtin.bytesize < canonical->builtin.bytesize && left_canonical->type_kind != TYPE_IXX;
|
||||
if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH();
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_INT);
|
||||
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64);
|
||||
left->const_expr.i &= type_mask[canonical->type_kind - TYPE_U8];
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_SIUI, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xiptr(Expr* left, Type *canonical, Type *type)
|
||||
{
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_INT);
|
||||
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64);
|
||||
assert(left->const_expr.i == 0);
|
||||
left->const_expr.type = CONST_NIL;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_XIPTR, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sifp(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
// TODO
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_INT);
|
||||
assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64);
|
||||
if (left->const_expr.i > (uint64_t)INT64_MAX)
|
||||
{
|
||||
left->const_expr.f = -((long double)(~left->const_expr.i));
|
||||
}
|
||||
else
|
||||
{
|
||||
left->const_expr.f = left->const_expr.i;
|
||||
}
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_SIFP, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool uisi(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64);
|
||||
int index = canonical->type_kind - TYPE_I8;
|
||||
uint64_t mask = type_mask[index];
|
||||
if (cast_type != CAST_TYPE_EXPLICIT && left->type->canonical->type_kind == TYPE_UXX)
|
||||
{
|
||||
if (left->const_expr.i > (uint64_t)int_type_max[index])
|
||||
{
|
||||
SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", left->const_expr.i, type->name_loc.string);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (left->const_expr.i > (uint64_t)INT64_MAX)
|
||||
{
|
||||
left->const_expr.i = ~((~left->const_expr.i) & mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
left->const_expr.i &= mask;
|
||||
}
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_UISI, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uiui(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_INT && type_is_unsigned(left->type));
|
||||
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64);
|
||||
int index = canonical->type_kind - TYPE_U8;
|
||||
if (cast_type != CAST_TYPE_EXPLICIT && left->type->canonical->type_kind == TYPE_UXX)
|
||||
{
|
||||
if (left->const_expr.i > uint_type_max[index])
|
||||
{
|
||||
SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", type->name_loc.string);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
left->const_expr.i &= type_mask[index];
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_UIUI, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool uifp(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
if (left->expr_kind == EXPR_CONST)
|
||||
{
|
||||
assert(left->const_expr.type == CONST_INT && type_is_unsigned(left->type->canonical));
|
||||
assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64);
|
||||
left->const_expr.f = left->const_expr.i;
|
||||
left->type = type;
|
||||
return true;
|
||||
}
|
||||
insert_cast(left, CAST_UIFP, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ussi(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
Decl *decl = type->decl;
|
||||
|
||||
if (decl->decl_kind != DECL_ENUM) return sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT);
|
||||
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
|
||||
|
||||
if (left->expr_kind == EXPR_IDENTIFIER && left->identifier_expr.decl->decl_kind == DECL_ENUM_CONSTANT)
|
||||
{
|
||||
Expr *value = left->identifier_expr.decl->enum_constant.expr;
|
||||
assert(value->expr_kind == EXPR_CONST);
|
||||
assert(value->const_expr.type == CONST_INT);
|
||||
left->const_expr.i = value->const_expr.i;
|
||||
// TODO narrowing
|
||||
}
|
||||
insert_cast(left, CAST_ENUMSI, canonical);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sius(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
bool uius(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
bool xipt(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
bool usus(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
bool usui(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
bool ptva(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
bool usbo(Expr* left, Type *canonical, Type *type, CastType cast_type)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
|
||||
CastFunc BUILTIN_CONVERSION[19][19] = {
|
||||
//to bool, char, short, int, long, ctint, byte, ushort, int, ulong,ctuint, float,double,ctreal, user, ptr, str, arr, varr // from:
|
||||
{ &erro, &boxi, &boxi, &boxi, &boxi, &erro, &boxi, &boxi, &boxi, &boxi, &erro, &bofp, &bofp, &erro, &erro, &erro, &erro, &erro, &erro }, // bool
|
||||
{ &xibo, &erro, &sisi, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &erro, &erro, &erro, &erro }, // char
|
||||
{ &xibo, &sisi, &erro, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &erro, &erro, &erro, &erro }, // short
|
||||
{ &xibo, &sisi, &sisi, &erro, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // int
|
||||
{ &xibo, &sisi, &sisi, &sisi, &erro, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // long
|
||||
{ &xibo, &sisi, &sisi, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // cint
|
||||
{ &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &erro, &uiui, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // byte
|
||||
{ &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &erro, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // ushort
|
||||
{ &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &erro, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // uint
|
||||
{ &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &uiui, &erro, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // ulong
|
||||
{ &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // cuint
|
||||
{ &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // float
|
||||
{ &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // double
|
||||
{ &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // cfloat
|
||||
{ &usbo, &ussi, &ussi, &ussi, &ussi, &erro, &usui, &usui, &usui, &usui, &erro, &erro, &erro, &erro, &usus, &erro, &erro, &erro, &erro }, // user
|
||||
{ &ptbo, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &erro, &erro, &erro, &erro, &ptpt, &ptst, &erro, &ptva }, // ptr
|
||||
{ &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // str
|
||||
{ &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // arr
|
||||
{ &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // varr
|
||||
};
|
||||
|
||||
static inline bool cannot_convert(TypeKind type_kind)
|
||||
{
|
||||
return type_kind <= TYPE_VOID || type_kind >= TYPE_INC_ARRAY;
|
||||
}
|
||||
|
||||
bool cast(Expr *expr, Type *to_type, CastType cast_type)
|
||||
{
|
||||
Type *from_type = expr->type->canonical;
|
||||
Type *canonical = to_type->canonical;
|
||||
TypeKind from_kind = from_type->type_kind;
|
||||
TypeKind to_kind = canonical->type_kind;
|
||||
|
||||
if (cannot_convert(from_kind) || cannot_convert(to_kind))
|
||||
{
|
||||
switch (cast_type)
|
||||
{
|
||||
case CAST_TYPE_EXPLICIT:
|
||||
case CAST_TYPE_IMPLICIT:
|
||||
SEMA_ERROR(expr->loc, "Cannot convert '%s' to '%s'", expr->type->name_loc.start, to_type->name_loc.start);
|
||||
break;
|
||||
case CAST_TYPE_IMPLICIT_ASSIGN:
|
||||
case CAST_TYPE_IMPLICIT_ASSIGN_ADD:
|
||||
SEMA_ERROR(expr->loc, "Cannot assign '%s' to '%s'", expr->type->name_loc.start, to_type->name_loc.start);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
CastFunc func = BUILTIN_CONVERSION[from_type->type_kind - TYPE_BOOL][to_type->type_kind - TYPE_BOOL];
|
||||
return func(expr, to_type, canonical, cast_type);
|
||||
}
|
||||
459
src/compiler/codegen.c
Normal file
459
src/compiler/codegen.c
Normal file
@@ -0,0 +1,459 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_internal.h"
|
||||
|
||||
|
||||
#define PRINTF(...) fprintf(context->codegen_output, __VA_ARGS__)
|
||||
#define PRINTTYPE(_t) print_typename(context->codegen_output, _t)
|
||||
static void codegen_ast(Context *context, Ast *ast, int indent);
|
||||
|
||||
static void print_typename(FILE *file, Type *type)
|
||||
{
|
||||
assert(type->resolve_status == RESOLVE_DONE);
|
||||
type = type->canonical;
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
case TYPE_INC_ARRAY:
|
||||
UNREACHABLE
|
||||
case TYPE_USER_DEFINED:
|
||||
switch (type->decl->decl_kind)
|
||||
{
|
||||
case DECL_STRUCT:
|
||||
fprintf(file, "struct");
|
||||
break;
|
||||
case DECL_UNION:
|
||||
fprintf(file, "union");
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
fprintf(file, "enum");
|
||||
break;
|
||||
case DECL_ERROR:
|
||||
fprintf(file, "int32_t");
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
fprintf(file, " _%s_%s", type->decl->module->name, type->decl->name.string);
|
||||
break;
|
||||
case TYPE_VOID:
|
||||
fprintf(file, "void");
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
fprintf(file, "bool");
|
||||
break;
|
||||
case TYPE_I8:
|
||||
fprintf(file, "int8_t");
|
||||
break;
|
||||
case TYPE_I16:
|
||||
fprintf(file, "int16_t");
|
||||
break;
|
||||
case TYPE_I32:
|
||||
fprintf(file, "int32_t");
|
||||
break;
|
||||
case TYPE_I64:
|
||||
fprintf(file, "int64_t");
|
||||
break;
|
||||
case TYPE_IXX:
|
||||
UNREACHABLE
|
||||
case TYPE_U8:
|
||||
fprintf(file, "uint8_t");
|
||||
break;
|
||||
case TYPE_U16:
|
||||
fprintf(file, "uint16_t");
|
||||
break;
|
||||
case TYPE_U32:
|
||||
fprintf(file, "int32_t");
|
||||
break;
|
||||
case TYPE_U64:
|
||||
fprintf(file, "uint64_t");
|
||||
break;
|
||||
case TYPE_UXX:
|
||||
UNREACHABLE
|
||||
case TYPE_F32:
|
||||
fprintf(file, "float");
|
||||
break;
|
||||
case TYPE_F64:
|
||||
fprintf(file, "double");
|
||||
break;
|
||||
case TYPE_FXX:
|
||||
UNREACHABLE
|
||||
case TYPE_STRING:
|
||||
UNREACHABLE;
|
||||
case TYPE_VARARRAY:
|
||||
case TYPE_POINTER:
|
||||
print_typename(file, type->base);
|
||||
fprintf(file, "*");
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
print_typename(file, type->base);
|
||||
fprintf(file, "[%zu]", type->len);
|
||||
break;
|
||||
case TYPE_EXPRESSION:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
static void indent_line(Context *context, int indent)
|
||||
{
|
||||
for (int i = 0; i < indent; i++)
|
||||
{
|
||||
PRINTF(" ");
|
||||
}
|
||||
}
|
||||
|
||||
static void codegen_expr(Context *context, Expr *expr)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_POISONED:
|
||||
UNREACHABLE;
|
||||
case EXPR_TRY:
|
||||
break;
|
||||
case EXPR_CONST:
|
||||
break;
|
||||
case EXPR_BINARY:
|
||||
break;
|
||||
case EXPR_CONDITIONAL:
|
||||
break;
|
||||
case EXPR_UNARY:
|
||||
break;
|
||||
case EXPR_POST_UNARY:
|
||||
break;
|
||||
case EXPR_TYPE:
|
||||
break;
|
||||
case EXPR_IDENTIFIER:
|
||||
break;
|
||||
case EXPR_METHOD_REF:
|
||||
break;
|
||||
case EXPR_CALL:
|
||||
break;
|
||||
case EXPR_SIZEOF:
|
||||
break;
|
||||
case EXPR_SUBSCRIPT:
|
||||
break;
|
||||
case EXPR_ACCESS:
|
||||
break;
|
||||
case EXPR_STRUCT_VALUE:
|
||||
break;
|
||||
case EXPR_STRUCT_INIT_VALUES:
|
||||
break;
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
break;
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
break;
|
||||
case EXPR_DEFERRED_TOKENS:
|
||||
break;
|
||||
case EXPR_CAST:
|
||||
break;
|
||||
}
|
||||
TODO
|
||||
}
|
||||
static inline void codegen_compound_stmt(Context *context, Ast *ast, int indent)
|
||||
{
|
||||
indent_line(context, indent);
|
||||
PRINTF("{\n");
|
||||
VECEACH(ast->compound_stmt.stmts, i)
|
||||
{
|
||||
codegen_ast(context, ast->compound_stmt.stmts[i], indent + 1);
|
||||
}
|
||||
indent_line(context, indent);
|
||||
PRINTF("}\n");
|
||||
}
|
||||
|
||||
static inline void codegen_emit_cast(Context *context, Type *canonical)
|
||||
{
|
||||
assert(canonical == canonical->canonical);
|
||||
PRINTF("(");
|
||||
TODO
|
||||
}
|
||||
static inline void codegen_emit_const_expr(Context *context, Expr *expr)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_CONST);
|
||||
Type *canonical = expr->type->canonical;
|
||||
switch (canonical->type_kind)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
case TYPE_USER_DEFINED:
|
||||
case TYPE_VOID:
|
||||
UNREACHABLE
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
assert(expr->const_expr.type == CONST_BOOL);
|
||||
PRINTF(expr->const_expr.b ? "true" : "false");
|
||||
break;
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
assert(expr->const_expr.type == CONST_INT);
|
||||
PRINTF("((");
|
||||
print_typename(context->codegen_output, canonical);
|
||||
PRINTF(")");
|
||||
PRINTF("%lld)", (long long)expr->const_expr.i);
|
||||
break;
|
||||
case TYPE_IXX:
|
||||
UNREACHABLE
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
assert(expr->const_expr.type == CONST_INT);
|
||||
PRINTF("((");
|
||||
print_typename(context->codegen_output, canonical);
|
||||
PRINTF(")");
|
||||
PRINTF("%llu)", expr->const_expr.i);
|
||||
break;
|
||||
case TYPE_UXX:
|
||||
UNREACHABLE
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
assert(expr->const_expr.type == CONST_FLOAT);
|
||||
PRINTF("((");
|
||||
print_typename(context->codegen_output, canonical);
|
||||
PRINTF(")");
|
||||
PRINTF("%Lf)", expr->const_expr.f);
|
||||
break;
|
||||
case TYPE_FXX:
|
||||
UNREACHABLE
|
||||
case TYPE_POINTER:
|
||||
assert(expr->const_expr.type == CONST_NIL);
|
||||
PRINTF("((");
|
||||
print_typename(context->codegen_output, canonical);
|
||||
PRINTF("0)");
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
TODO
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_VARARRAY:
|
||||
case TYPE_INC_ARRAY:
|
||||
case TYPE_EXPRESSION:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
static inline void codegen_emit_expr(Context *context, Expr *expr)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_CONST:
|
||||
codegen_emit_const_expr(context, expr);
|
||||
break;
|
||||
default:
|
||||
TODO
|
||||
}
|
||||
}
|
||||
|
||||
static inline void codegen_var_decl(Context *context, Decl *decl, int indent)
|
||||
{
|
||||
assert(decl->decl_kind == DECL_VAR);
|
||||
indent_line(context, indent);
|
||||
print_typename(context->codegen_output, decl->var.type);
|
||||
PRINTF(" ");
|
||||
PRINTF("%s", decl->name.string);
|
||||
PRINTF(";\n");
|
||||
if (!decl->var.init_expr) return;
|
||||
indent_line(context, indent);
|
||||
PRINTF("%s = ", decl->name.string);
|
||||
codegen_emit_expr(context, decl->var.init_expr);
|
||||
PRINTF(";\n");
|
||||
}
|
||||
|
||||
static inline void codegen_declare_stmt(Context *context, Ast *ast, int indent)
|
||||
{
|
||||
Decl *decl = ast->declare_stmt;
|
||||
if (decl->decl_kind == DECL_MULTI_DECL)
|
||||
{
|
||||
VECEACH(decl->multi_decl, i)
|
||||
{
|
||||
codegen_var_decl(context, decl->multi_decl[i], indent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
codegen_var_decl(context, decl, indent);
|
||||
}
|
||||
}
|
||||
|
||||
static void codegen_ast(Context *context, Ast *ast, int indent)
|
||||
{
|
||||
switch (ast->ast_kind)
|
||||
{
|
||||
case AST_POISONED:
|
||||
UNREACHABLE
|
||||
case AST_ASM_STMT:
|
||||
break;
|
||||
case AST_ATTRIBUTE:
|
||||
break;
|
||||
case AST_BREAK_STMT:
|
||||
break;
|
||||
case AST_CASE_STMT:
|
||||
break;
|
||||
case AST_CATCH_STMT:
|
||||
UNREACHABLE
|
||||
case AST_COMPOUND_STMT:
|
||||
codegen_compound_stmt(context, ast, indent);
|
||||
return;
|
||||
case AST_COND_STMT:
|
||||
break;
|
||||
case AST_CONTINUE_STMT:
|
||||
break;
|
||||
case AST_CT_IF_STMT:
|
||||
break;
|
||||
case AST_CT_ELIF_STMT:
|
||||
break;
|
||||
case AST_CT_ELSE_STMT:
|
||||
break;
|
||||
case AST_DECLARE_STMT:
|
||||
codegen_declare_stmt(context, ast, indent);
|
||||
return;
|
||||
case AST_DECL_EXPR_LIST:
|
||||
break;
|
||||
case AST_DEFAULT_STMT:
|
||||
break;
|
||||
case AST_DEFER_STMT:
|
||||
break;
|
||||
case AST_DO_STMT:
|
||||
break;
|
||||
case AST_EXPR_STMT:
|
||||
break;
|
||||
case AST_FOR_STMT:
|
||||
break;
|
||||
case AST_GOTO_STMT:
|
||||
break;
|
||||
case AST_IF_STMT:
|
||||
break;
|
||||
case AST_LABEL:
|
||||
break;
|
||||
case AST_NOP_STMT:
|
||||
break;
|
||||
case AST_RETURN_STMT:
|
||||
indent_line(context, indent);
|
||||
if (ast->return_stmt.expr)
|
||||
{
|
||||
PRINTF("return ");
|
||||
codegen_expr(context, ast->return_stmt.expr);
|
||||
PRINTF(";\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINTF("return;\n");
|
||||
}
|
||||
return;
|
||||
case AST_SWITCH_STMT:
|
||||
break;
|
||||
case AST_THROW_STMT:
|
||||
break;
|
||||
case AST_TRY_STMT:
|
||||
break;
|
||||
case AST_NEXT_STMT:
|
||||
break;
|
||||
case AST_VOLATILE_STMT:
|
||||
break;
|
||||
case AST_WHILE_STMT:
|
||||
break;
|
||||
case AST_GENERIC_CASE_STMT:
|
||||
break;
|
||||
case AST_GENERIC_DEFAULT_STMT:
|
||||
break;
|
||||
}
|
||||
TODO
|
||||
}
|
||||
static inline void codegen_func(Context *context, Decl *decl)
|
||||
{
|
||||
print_typename(context->codegen_output, decl->func.function_signature.rtype);
|
||||
PRINTF(" %s__%s()\n", decl->module->name, decl->name.string);
|
||||
codegen_ast(context, decl->func.body, 0);
|
||||
}
|
||||
|
||||
static void codegen_struct_member(Context *context, Decl *decl, int indent)
|
||||
{
|
||||
indent_line(context, indent);
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_VAR:
|
||||
PRINTTYPE(decl->var.type);
|
||||
PRINTF(" %s;\n", decl->name.string);
|
||||
return;
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
const char* type = decl->decl_kind == DECL_UNION ? "union" : "struct";
|
||||
PRINTF("%s {\n", type);
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
codegen_struct_member(context, decl->strukt.members[i], indent + 1);
|
||||
}
|
||||
indent_line(context, indent);
|
||||
PRINTF("};\n");
|
||||
}
|
||||
|
||||
static inline void codegen_struct_union(Context *context, Decl *decl)
|
||||
{
|
||||
const char* type = decl->decl_kind == DECL_UNION ? "union" : "struct";
|
||||
PRINTF("typedef %s _%s_%s\n", type, decl->module->name, decl->name.string);
|
||||
PRINTF("{\n");
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
codegen_struct_member(context, decl->strukt.members[i], 1);
|
||||
}
|
||||
PRINTF("} %s_%s;\n\n", decl->module->name, decl->name.string);
|
||||
}
|
||||
|
||||
static inline void codegen_decl(Context *context, Decl *decl)
|
||||
{
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_POISONED:
|
||||
FATAL_ERROR("Tried to codegen broken code");
|
||||
return;
|
||||
case DECL_FUNC:
|
||||
codegen_func(context, decl);
|
||||
return;
|
||||
case DECL_VAR:
|
||||
break;
|
||||
case DECL_ENUM_CONSTANT:
|
||||
break;
|
||||
case DECL_TYPEDEF:
|
||||
break;
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
codegen_struct_union(context, decl);
|
||||
return;
|
||||
case DECL_ENUM:
|
||||
break;
|
||||
case DECL_ERROR:
|
||||
break;
|
||||
case DECL_ERROR_CONSTANT:
|
||||
break;
|
||||
case DECL_ARRAY_VALUE:
|
||||
break;
|
||||
case DECL_IMPORT:
|
||||
break;
|
||||
case DECL_MACRO:
|
||||
break;
|
||||
case DECL_MULTI_DECL:
|
||||
break;
|
||||
case DECL_GENERIC:
|
||||
break;
|
||||
case DECL_CT_IF:
|
||||
break;
|
||||
case DECL_CT_ELSE:
|
||||
break;
|
||||
case DECL_CT_ELIF:
|
||||
break;
|
||||
}
|
||||
TODO
|
||||
}
|
||||
void codegen(Context *context)
|
||||
{
|
||||
VECEACH(context->declarations, i)
|
||||
{
|
||||
codegen_decl(context, context->declarations[i]);
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <utils/errors.h>
|
||||
#include <utils/file_utils.h>
|
||||
#include "compiler.h"
|
||||
#include "symtab.h"
|
||||
#include "compiler_internal.h"
|
||||
#include "../build/build_options.h"
|
||||
#include "../utils/lib.h"
|
||||
#include "lexer.h"
|
||||
#include "source_file.h"
|
||||
#include "parser.h"
|
||||
#include "diagnostics.h"
|
||||
#include "semantic_analyser.h"
|
||||
|
||||
void compiler_init(void)
|
||||
{
|
||||
@@ -40,7 +31,7 @@ static void compiler_lex()
|
||||
|
||||
void compiler_parse()
|
||||
{
|
||||
type_setup(build_options.pointer_size);
|
||||
builtin_setup();
|
||||
VECEACH(build_options.files, i)
|
||||
{
|
||||
bool loaded = false;
|
||||
@@ -55,7 +46,7 @@ void compiler_parse()
|
||||
|
||||
void compiler_compile()
|
||||
{
|
||||
type_setup(build_options.pointer_size);
|
||||
builtin_setup();
|
||||
VECEACH(build_options.files, i)
|
||||
{
|
||||
bool loaded = false;
|
||||
@@ -64,6 +55,8 @@ void compiler_compile()
|
||||
diag_reset();
|
||||
parse_file(file);
|
||||
sema_analysis(current_context);
|
||||
current_context->codegen_output = stdout;
|
||||
codegen(current_context);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,5 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
||||
void compiler_init();
|
||||
void compile_file();
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "tokens.h"
|
||||
#include "utils/common.h"
|
||||
#include "symtab.h"
|
||||
|
||||
typedef uint32_t SourceLoc;
|
||||
#define INVALID_LOC UINT32_MAX
|
||||
#define INVALID_RANGE ((SourceRange){ .loc = UINT32_MAX })
|
||||
#define EMPTY_TOKEN ((Token) { .string = NULL })
|
||||
typedef struct _Decl Decl;
|
||||
typedef struct _Type Type;
|
||||
typedef struct _Expr Expr;
|
||||
typedef struct _Ast Ast;
|
||||
|
||||
typedef enum {
|
||||
IMPORT_TYPE_FULL,
|
||||
IMPORT_TYPE_ALIAS,
|
||||
IMPORT_TYPE_ALIAS_LOCAL,
|
||||
IMPORT_TYPE_LOCAL
|
||||
} ImportType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VISIBLE_MODULE,
|
||||
VISIBLE_LOCAL,
|
||||
VISIBLE_PUBLIC,
|
||||
} Visibility;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RESOLVE_NOT_DONE,
|
||||
RESOLVE_RUNNING,
|
||||
RESOLVE_DONE
|
||||
} ResolveStatus;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SourceLoc loc;
|
||||
uint32_t length;
|
||||
} SourceRange;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SourceRange span;
|
||||
TokenType type : 8;
|
||||
union
|
||||
{
|
||||
const char *string;
|
||||
const char* start;
|
||||
};
|
||||
} Token;
|
||||
|
||||
#define TOK2VARSTR(_token) _token.span.length, _token.start
|
||||
|
||||
static inline Token wrap(const char *string)
|
||||
{
|
||||
return (Token) { .span = INVALID_RANGE, .type = TOKEN_IDENT, .string = string };
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *contents;
|
||||
const char *name;
|
||||
const char *full_path;
|
||||
SourceLoc start_id;
|
||||
SourceLoc end_id;
|
||||
} File;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LEXER_STATE_NORMAL,
|
||||
LEXER_STATE_DEFERED_PARSING,
|
||||
LEXER_STATE_DOCS_PARSE,
|
||||
LEXER_STATE_DOCS_PARSE_DIRECTIVE,
|
||||
} LexerState;
|
||||
|
||||
|
||||
#define TOKEN_MAX_LENGTH 0xFFFF
|
||||
|
||||
820
src/compiler/compiler_internal.h
Normal file
820
src/compiler/compiler_internal.h
Normal file
@@ -0,0 +1,820 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "../utils/common.h"
|
||||
#include "../utils/errors.h"
|
||||
#include "../utils/lib.h"
|
||||
#include "../build/build_options.h"
|
||||
#include "compiler.h"
|
||||
#include "enums.h"
|
||||
|
||||
typedef uint32_t SourceLoc;
|
||||
#define INVALID_LOC UINT32_MAX
|
||||
#define INVALID_RANGE ((SourceRange){ .loc = UINT32_MAX })
|
||||
#define EMPTY_TOKEN ((Token) { .string = NULL })
|
||||
#define MAX_LOCALS 0xFFFF
|
||||
#define MAX_SCOPE_DEPTH 0xFF
|
||||
|
||||
|
||||
typedef struct _Ast Ast;
|
||||
typedef struct _Decl Decl;
|
||||
typedef struct _Type Type;
|
||||
typedef struct _Expr Expr;
|
||||
typedef struct _Module Module;
|
||||
|
||||
typedef bool(*CastFunc)(Expr*, Type*, Type*, CastType cast_type);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SourceLoc loc;
|
||||
uint32_t length;
|
||||
} SourceRange;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SourceRange span;
|
||||
TokenType type : 8;
|
||||
union
|
||||
{
|
||||
const char *string;
|
||||
const char* start;
|
||||
};
|
||||
} Token;
|
||||
|
||||
typedef struct _Diagnostics
|
||||
{
|
||||
bool panic_mode;
|
||||
unsigned errors;
|
||||
unsigned warnings;
|
||||
} Diagnostics;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *key;
|
||||
void *value;
|
||||
} SEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
SEntry *entries;
|
||||
} STable;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *contents;
|
||||
const char *name;
|
||||
const char *full_path;
|
||||
SourceLoc start_id;
|
||||
SourceLoc end_id;
|
||||
} File;
|
||||
|
||||
|
||||
struct _Type
|
||||
{
|
||||
TypeKind type_kind : 6;
|
||||
ResolveStatus resolve_status : 2;
|
||||
Type *canonical;
|
||||
Token name_loc;
|
||||
Type **ptr_like_canonical;
|
||||
union
|
||||
{
|
||||
Decl *decl;
|
||||
struct
|
||||
{
|
||||
unsigned bitsize : 16;
|
||||
unsigned char bytesize;
|
||||
} builtin;
|
||||
struct
|
||||
{
|
||||
Token module;
|
||||
} unresolved;
|
||||
Expr *unresolved_type_expr;
|
||||
struct
|
||||
{
|
||||
Type *base;
|
||||
union
|
||||
{
|
||||
Expr *unresolved_len;
|
||||
size_t len;
|
||||
bool nullable;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Token module;
|
||||
Token name;
|
||||
union
|
||||
{
|
||||
Expr *expr;
|
||||
};
|
||||
} Attr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl **error_constants;
|
||||
} ErrorDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ImportType type : 3;
|
||||
Token alias;
|
||||
Expr** generic_parameters;
|
||||
struct _Module *module;
|
||||
} ImportDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl **members;
|
||||
Decl **method_functions;
|
||||
} StructDecl;
|
||||
|
||||
|
||||
typedef struct _VarDecl
|
||||
{
|
||||
VarDeclKind kind : 3;
|
||||
Type *type;
|
||||
Expr *init_expr;
|
||||
} VarDecl;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr;
|
||||
Decl **then;
|
||||
Decl *elif;
|
||||
} CtIfDecl;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl *parent;
|
||||
Expr *expr;
|
||||
} EnumConstantDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl *parent;
|
||||
uint32_t value;
|
||||
} ErrorConstantDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl** values;
|
||||
Type *type;
|
||||
} EnumDecl;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool variadic : 1;
|
||||
Type *rtype;
|
||||
Decl** params;
|
||||
Token *throws;
|
||||
} FunctionSignature;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *full_name;
|
||||
Type *struct_parent;
|
||||
FunctionSignature function_signature;
|
||||
struct _Ast *body;
|
||||
} FuncDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_func : 1;
|
||||
union
|
||||
{
|
||||
FunctionSignature function_signature;
|
||||
Type *type;
|
||||
};
|
||||
} TypedefDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl **parameters;
|
||||
Type *rtype; // May be null!
|
||||
struct _Ast *body;
|
||||
} MacroDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct _Ast **cases;
|
||||
Token *parameters;
|
||||
Type *rtype; // May be null!
|
||||
} GenericDecl;
|
||||
|
||||
|
||||
typedef struct _Decl
|
||||
{
|
||||
Token name;
|
||||
DeclKind decl_kind : 6;
|
||||
Visibility visibility : 2;
|
||||
ResolveStatus resolve_status : 2;
|
||||
/* bool is_exported : 1;
|
||||
bool is_used : 1;
|
||||
bool is_used_public : 1;
|
||||
bool has_cname : 1;
|
||||
uint32_t alignment : 5;
|
||||
union
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t counter;
|
||||
};
|
||||
uint32_t size;*/
|
||||
Type *self_type;
|
||||
struct _Module *module;
|
||||
Attr** attributes;
|
||||
union
|
||||
{
|
||||
ErrorDecl error;
|
||||
ErrorConstantDecl error_constant;
|
||||
ImportDecl import;
|
||||
StructDecl strukt;
|
||||
VarDecl var;
|
||||
EnumDecl enums;
|
||||
EnumConstantDecl enum_constant;
|
||||
FuncDecl func;
|
||||
TypedefDecl typedef_decl;
|
||||
Decl** multi_decl;
|
||||
MacroDecl macro_decl;
|
||||
GenericDecl generic_decl;
|
||||
CtIfDecl ct_if_decl;
|
||||
CtIfDecl ct_elif_decl;
|
||||
Decl** ct_else_decl;
|
||||
};
|
||||
} Decl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr;
|
||||
Expr *else_expr;
|
||||
} ExprTry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Type *type;
|
||||
Token method;
|
||||
} ExprMethodRef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Type *type;
|
||||
Expr *init_expr;
|
||||
} ExprStructValue;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *cond;
|
||||
Expr *then_expr; // May be null for elvis!
|
||||
Expr *else_expr;
|
||||
} ExprTernary;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *left;
|
||||
Expr *right;
|
||||
BinOp operator;
|
||||
} ExprBinary;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *left;
|
||||
Expr *right;
|
||||
AssignOp operator;
|
||||
} ExprAssign;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr* expr;
|
||||
UnaryOp operator;
|
||||
} ExprUnary;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
long double f;
|
||||
uint64_t i;
|
||||
bool b;
|
||||
struct
|
||||
{
|
||||
char* chars;
|
||||
int len;
|
||||
} string;
|
||||
};
|
||||
ConstType type : 3;
|
||||
} ExprConst;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_struct_function;
|
||||
Expr *function;
|
||||
Expr **parameters;
|
||||
} ExprCall;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr;
|
||||
Expr *index;
|
||||
} ExprSubscript;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *parent;
|
||||
Token sub_element;
|
||||
} ExprAccess;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Token module;
|
||||
Token identifier;
|
||||
bool is_ref;
|
||||
Decl *decl;
|
||||
} ExprIdentifier;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Type *type;
|
||||
} ExprType;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CastKind kind;
|
||||
Expr *expr;
|
||||
union
|
||||
{
|
||||
size_t truncated_size;
|
||||
};
|
||||
} ExprCast;
|
||||
|
||||
struct _Expr
|
||||
{
|
||||
ExprKind expr_kind : 8;
|
||||
ResolveStatus resolve_status : 3;
|
||||
Token loc;
|
||||
Type *type;
|
||||
|
||||
union {
|
||||
Token* deferred_tokens;
|
||||
Token deferred_token;
|
||||
ExprCast expr_cast;
|
||||
ExprConst const_expr;
|
||||
ExprStructValue struct_value_expr;
|
||||
ExprMethodRef method_ref_expr;
|
||||
ExprTry try_expr;
|
||||
ExprBinary binary_expr;
|
||||
ExprAssign assign_expr;
|
||||
ExprTernary conditional_expr;
|
||||
ExprUnary unary_expr;
|
||||
ExprUnary post_expr;
|
||||
ExprCall call_expr;
|
||||
ExprSubscript subscript_expr;
|
||||
ExprAccess access_expr;
|
||||
ExprIdentifier identifier_expr;
|
||||
ExprType type_expr;
|
||||
Expr** initializer_expr;
|
||||
Expr** expression_list;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
} AstAttribute;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct _Ast **stmts;
|
||||
// DeferList defer_list; TODO
|
||||
} AstCompoundStmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t last_goto;
|
||||
bool is_used : 1;
|
||||
struct _Ast *defer;
|
||||
struct _Ast *in_defer;
|
||||
} AstLabelStmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr; // May be NULL
|
||||
struct _Ast *defer;
|
||||
} AstReturnStmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast *cond;
|
||||
Ast *body;
|
||||
} AstWhileStmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr;
|
||||
Ast *body;
|
||||
} AstDoStmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast *cond;
|
||||
Ast *then_body;
|
||||
Ast *else_body;
|
||||
} AstIfStmt;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr;
|
||||
} AstCaseStmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast *cond;
|
||||
Ast *body;
|
||||
} AstSwitchStmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast *init;
|
||||
Expr *cond;
|
||||
Expr *incr;
|
||||
Ast *body;
|
||||
} AstForStmt;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl *decl;
|
||||
Ast *decl_expr;
|
||||
} AstCondStmt;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DeclExprType list_type : 2;
|
||||
union
|
||||
{
|
||||
Decl *decl;
|
||||
Expr *expr;
|
||||
};
|
||||
} AstDeclExprList;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GotoType type : 2;
|
||||
struct _Ast *defer;
|
||||
union
|
||||
{
|
||||
struct _Ast *in_defer;
|
||||
struct _Ast *defer_end;
|
||||
};
|
||||
} AstGotoStmt;
|
||||
|
||||
typedef struct _AstDeferStmt
|
||||
{
|
||||
bool emit_boolean : 1;
|
||||
struct _Ast *body; // Compound statement
|
||||
struct _Ast *prev_defer;
|
||||
} AstDeferStmt;
|
||||
|
||||
typedef struct _AstCatchStmt
|
||||
{
|
||||
Decl *error_param;
|
||||
struct _Ast *body;
|
||||
} AstCatchStmt;
|
||||
|
||||
typedef struct _AstCtIfStmt
|
||||
{
|
||||
Expr *expr;
|
||||
struct _Ast *then;
|
||||
struct _Ast *elif;
|
||||
} AstCtIfStmt;
|
||||
|
||||
|
||||
typedef struct _AstGenericCaseStmt
|
||||
{
|
||||
Type **types;
|
||||
struct _Ast *body;
|
||||
} AstGenericCaseStmt;
|
||||
|
||||
typedef struct _Ast
|
||||
{
|
||||
AstKind ast_kind : 8;
|
||||
ExitType exit : 3;
|
||||
Token token;
|
||||
|
||||
union
|
||||
{
|
||||
AstAttribute attribute;
|
||||
AstCompoundStmt compound_stmt;
|
||||
Decl *declare_stmt;
|
||||
Expr *expr_stmt;
|
||||
Expr *throw_stmt;
|
||||
struct _Ast *volatile_stmt;
|
||||
struct _Ast *try_stmt;
|
||||
AstLabelStmt label_stmt;
|
||||
AstReturnStmt return_stmt;
|
||||
AstWhileStmt while_stmt;
|
||||
AstDoStmt do_stmt;
|
||||
AstIfStmt if_stmt;
|
||||
AstDeferStmt defer_stmt;
|
||||
AstSwitchStmt switch_stmt;
|
||||
AstCaseStmt case_stmt;
|
||||
AstCatchStmt catch_stmt;
|
||||
AstGotoStmt goto_stmt;
|
||||
AstForStmt for_stmt;
|
||||
AstCondStmt cond_stmt;
|
||||
AstCtIfStmt ct_if_stmt;
|
||||
AstCtIfStmt ct_elif_stmt;
|
||||
struct _Ast* ct_else_stmt;
|
||||
AstDeclExprList decl_expr_list;
|
||||
AstGenericCaseStmt generic_case_stmt;
|
||||
struct _Ast* generic_default_stmt;
|
||||
};
|
||||
} Ast;
|
||||
|
||||
|
||||
|
||||
typedef struct _Module
|
||||
{
|
||||
const char *name;
|
||||
|
||||
bool is_external;
|
||||
bool is_c_library;
|
||||
bool is_exported;
|
||||
|
||||
Ast **files; // Asts
|
||||
|
||||
Decl** functions;
|
||||
STable struct_functions;
|
||||
STable symbols;
|
||||
STable public_symbols;
|
||||
} Module;
|
||||
|
||||
typedef struct _DynamicScope
|
||||
{
|
||||
int flags;
|
||||
int flags_created;
|
||||
unsigned errors;
|
||||
Decl **local_decl_start;
|
||||
Ast *defer_stack_start;
|
||||
Ast *active_defer;
|
||||
} DynamicScope;
|
||||
|
||||
typedef struct _Context
|
||||
{
|
||||
Token module_name;
|
||||
Token* module_parameters;
|
||||
File * file;
|
||||
Decl** imports;
|
||||
Module *module;
|
||||
STable local_symbols;
|
||||
Decl **declarations;
|
||||
Decl **ct_ifs;
|
||||
Decl *active_function_for_analysis;
|
||||
FILE *codegen_output;
|
||||
Decl *locals[MAX_LOCALS];
|
||||
Decl **last_local;
|
||||
DynamicScope scopes[MAX_SCOPE_DEPTH];
|
||||
DynamicScope *current_scope;
|
||||
} Context;
|
||||
|
||||
extern Context *current_context;
|
||||
|
||||
extern Ast poisoned_ast;
|
||||
extern Decl poisoned_decl;
|
||||
extern Expr poisoned_expr;
|
||||
extern Type poisoned_type;
|
||||
extern Module poisoned_module;
|
||||
|
||||
extern Token next_tok;
|
||||
extern Token tok;
|
||||
|
||||
extern Type type_bool, type_void, type_string;
|
||||
extern Type type_half, type_float, type_double, type_quad;
|
||||
extern Type type_char, type_short, type_int, type_long, type_isize;
|
||||
extern Type type_byte, type_ushort, type_uint, type_ulong, type_usize;
|
||||
extern Type type_compint, type_compuint, type_compfloat;
|
||||
extern Type type_c_short, type_c_int, type_c_long, type_c_longlong;
|
||||
extern Type type_c_ushort, type_c_uint, type_c_ulong, type_c_ulonglong;
|
||||
|
||||
#define AST_NEW(_kind, _token) new_ast(_kind, _token)
|
||||
|
||||
static inline bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; }
|
||||
static inline void ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; }
|
||||
static inline Ast *new_ast(AstKind kind, Token token)
|
||||
{
|
||||
Ast *ast = malloc_arena(sizeof(Ast));
|
||||
memset(ast, 0, sizeof(Ast));
|
||||
ast->token = token;
|
||||
ast->ast_kind = kind;
|
||||
ast->exit = EXIT_NONE;
|
||||
return ast;
|
||||
}
|
||||
|
||||
|
||||
void builtin_setup();
|
||||
|
||||
static inline bool builtin_may_negate(Type *canonical)
|
||||
{
|
||||
assert(canonical->canonical == canonical);
|
||||
switch (canonical->type_kind)
|
||||
{
|
||||
case TYPE_FXX:
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_IXX:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool builtin_may_bit_negate(Type *canonical)
|
||||
{
|
||||
assert(canonical->canonical == canonical);
|
||||
switch (canonical->type_kind)
|
||||
{
|
||||
case TYPE_BOOL:
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_IXX:
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
case TYPE_UXX:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline ConstType sign_from_type(Type *type)
|
||||
{
|
||||
assert(type->canonical == type);
|
||||
TODO // return (type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX) ? CONST_INT : CONST_UINT;
|
||||
}
|
||||
|
||||
bool cast(Expr *expr, Type *to_type, CastType cast_type);
|
||||
|
||||
|
||||
void codegen(Context *context);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Context *context_create(File *file);
|
||||
void context_push(Context *context);
|
||||
void context_register_global_decl(Context *context, Decl *decl);
|
||||
bool context_add_import(Context *context, Token module_name, Token alias, ImportType import_type, Expr** generic_parameters);
|
||||
bool context_set_module_from_filename(Context *context);
|
||||
bool context_set_module(Context *context, Token module_name, Token *generic_parameters);
|
||||
void context_print_ast(Context *context, FILE *file);
|
||||
|
||||
Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility);
|
||||
Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility);
|
||||
Decl *decl_new_var(Token name, Type *type, VarDeclKind kind, Visibility visibility);
|
||||
static inline bool decl_ok(Decl *decl) { return decl->decl_kind != DECL_POISONED; }
|
||||
static inline Decl *decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; return decl; }
|
||||
static inline DeclKind decl_from_token(TokenType type)
|
||||
{
|
||||
if (type == TOKEN_STRUCT) return DECL_STRUCT;
|
||||
if (type == TOKEN_UNION) return DECL_UNION;
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
void diag_reset(void);
|
||||
void diag_error_range(SourceRange span, const char *message, ...);
|
||||
void diag_verror_range(SourceRange span, const char *message, va_list args);
|
||||
|
||||
|
||||
#define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->loc)
|
||||
#define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok)
|
||||
Expr *expr_new(ExprKind kind, Token start);
|
||||
static inline bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; }
|
||||
static inline void expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; }
|
||||
|
||||
void fprint_ast(FILE *file, Ast *ast);
|
||||
void fprint_decl(FILE *file, Decl *dec);
|
||||
void fprint_type_recursive(FILE *file, Type *type, int indent);
|
||||
void fprint_expr_recursive(FILE *file, Expr *expr, int indent);
|
||||
|
||||
|
||||
Token lexer_scan_token(void);
|
||||
Token lexer_scan_ident_test(const char *scan);
|
||||
void lexer_test_setup(const char *text, size_t len);
|
||||
void lexer_add_file_for_lexing(File *file);
|
||||
File* lexer_current_file(void);
|
||||
void lexer_check_init(void);
|
||||
void lexer_store_state(void);
|
||||
void lexer_restore_state(void);
|
||||
|
||||
static inline void advance(void)
|
||||
{
|
||||
tok = next_tok;
|
||||
while (1)
|
||||
{
|
||||
next_tok = lexer_scan_token();
|
||||
// printf(">>> %.*s => %s\n", tok.length, tok.start, token_type_to_string(tok.type));
|
||||
if (next_tok.type != TOKEN_INVALID_TOKEN) break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void advance_and_verify(TokenType token_type)
|
||||
{
|
||||
assert(tok.type == token_type);
|
||||
advance();
|
||||
}
|
||||
|
||||
void parse_file(File *file);
|
||||
|
||||
#define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__)
|
||||
void sema_init(File *file);
|
||||
void sema_analysis(Context *context);
|
||||
bool sema_const_fold_binary(Context *context, Expr *expr);
|
||||
void sema_error_at(SourceLoc loc, const char *message, ...);
|
||||
void sema_error_range(SourceRange range, const char *message, ...);
|
||||
void sema_verror_at(SourceLoc loc, const char *message, va_list args);
|
||||
void sema_verror_range(SourceRange range, const char *message, va_list args);
|
||||
void sema_error(const char *message, ...);
|
||||
void sema_prev_at_range(SourceRange span, const char *message, ...);
|
||||
void sema_prev_at(SourceLoc loc, const char *message, ...);
|
||||
|
||||
|
||||
File *source_file_load(const char *filename, bool *already_loaded);
|
||||
File *source_file_from_position(SourceLoc loc);
|
||||
|
||||
|
||||
void stable_init(STable *table, uint32_t initial_size);
|
||||
void *stable_set(STable *table, const char *key, void *value);
|
||||
void *stable_get(STable *table, const char *key);
|
||||
void *stable_delete(STable *table, const char *key);
|
||||
void stable_clear(STable *table);
|
||||
|
||||
void symtab_init(uint32_t max_size);
|
||||
const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
|
||||
|
||||
#define TOKEN_MAX_LENGTH 0xFFFF
|
||||
#define TOK2VARSTR(_token) _token.span.length, _token.start
|
||||
bool token_is_type(TokenType type);
|
||||
const char *token_type_to_string(TokenType type);
|
||||
static inline Token wrap(const char *string)
|
||||
{
|
||||
return (Token) { .span = INVALID_RANGE, .type = TOKEN_IDENT, .string = string };
|
||||
}
|
||||
|
||||
Type *type_new(TypeKind type_kind);
|
||||
Type *type_get_canonical_ptr(Type *ptr_type);
|
||||
Type *type_get_canonical_array(Type *arr_type);
|
||||
Type *type_signed_int_by_size(int bitsize);
|
||||
Type *type_unsigned_int_by_size(int bitsize);
|
||||
|
||||
size_t type_size(Type *canonical);
|
||||
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; }
|
||||
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX; }
|
||||
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; }
|
||||
|
||||
#define TYPE_MODULE_UNRESOLVED(_module, _name) ({ Type *__type = type_new(TYPE_USER_DEFINED); \
|
||||
__type->name_loc = _name; __type->unresolved.module = _module; __type; })
|
||||
#define TYPE_UNRESOLVED(_name) ({ Type *__type = type_new(TYPE_USER_DEFINED); __type->name_loc = _name; __type; })
|
||||
|
||||
AssignOp assignop_from_token(TokenType type);
|
||||
BinOp binop_from_token(TokenType type);
|
||||
TokenType binop_to_token(BinOp type);
|
||||
UnaryOp unaryop_from_token(TokenType type);
|
||||
Decl *struct_find_name(Decl *decl, const char* name);
|
||||
|
||||
|
||||
static inline const char* struct_union_name_from_token(TokenType type)
|
||||
{
|
||||
return type == TOKEN_STRUCT ? "struct" : "union";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
158
src/compiler/const_folding.c
Normal file
158
src/compiler/const_folding.c
Normal file
@@ -0,0 +1,158 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_internal.h"
|
||||
|
||||
#define COMP_OP(comp) \
|
||||
switch (left->type)\
|
||||
{ case CONST_NIL: result->b = 0 comp 0; break;\
|
||||
case CONST_BOOL: result->b = left->b comp right->b; break;\
|
||||
case CONST_STRING: UNREACHABLE;\
|
||||
case CONST_FLOAT: result->b = left->f comp right->f; break;\
|
||||
case CONST_INT: result->b = left->i comp right->i; break;\
|
||||
default: UNREACHABLE }\
|
||||
result->type = CONST_BOOL; expr->expr_kind = EXPR_CONST; expr->type = &type_bool; return true;
|
||||
|
||||
#define BOOL_COMP(comp) \
|
||||
switch (left->type)\
|
||||
{ case CONST_NIL: result->b = 0 comp 0; break;\
|
||||
case CONST_BOOL: result->b = left->b comp right->b; break;\
|
||||
case CONST_STRING: UNREACHABLE;\
|
||||
case CONST_FLOAT: result->b = (left->f != 0) comp (right->f != 0); break;\
|
||||
case CONST_INT: result->b = (left->i != 0) comp (right->i != 0); break;\
|
||||
default: break; }\
|
||||
result->type = CONST_BOOL; expr->expr_kind = EXPR_CONST; expr->type = &type_bool; return true
|
||||
|
||||
#define BITOP(op)\
|
||||
switch (left->type)\
|
||||
{ case CONST_NIL: break; \
|
||||
case CONST_BOOL: result->b = left->b op right->b; break; \
|
||||
case CONST_STRING: case CONST_FLOAT: UNREACHABLE; \
|
||||
case CONST_INT: result->b = left->i op right->i; break; \
|
||||
default: UNREACHABLE; \
|
||||
} break
|
||||
|
||||
#define ARITH(op)\
|
||||
switch (left->type)\
|
||||
{ case CONST_NIL: case CONST_BOOL: case CONST_STRING: UNREACHABLE; \
|
||||
case CONST_FLOAT: result->f = left->f op right->f; break;\
|
||||
case CONST_INT: result->i = left->i op right->i; break; \
|
||||
default: UNREACHABLE; \
|
||||
} break
|
||||
|
||||
bool sema_const_fold_binary(Context *context, Expr *expr)
|
||||
{
|
||||
Expr *left_expr = expr->binary_expr.left;
|
||||
Expr *right_expr = expr->binary_expr.right;
|
||||
|
||||
if (left_expr->expr_kind != EXPR_CONST || right_expr->expr_kind != EXPR_CONST) return true;
|
||||
Type *type = left_expr->type->canonical;
|
||||
assert(type == right_expr->type->canonical);
|
||||
ExprConst *left = &left_expr->const_expr;
|
||||
ExprConst *right = &right_expr->const_expr;
|
||||
ExprConst *result = &expr->const_expr;
|
||||
switch (expr->binary_expr.operator)
|
||||
{
|
||||
case BINOP_ERROR:
|
||||
case BINOP_ASSIGN:
|
||||
case BINOP_MULT_ASSIGN:
|
||||
case BINOP_ADD_ASSIGN:
|
||||
case BINOP_SUB_ASSIGN:
|
||||
case BINOP_DIV_ASSIGN:
|
||||
case BINOP_MOD_ASSIGN:
|
||||
case BINOP_AND_ASSIGN:
|
||||
case BINOP_OR_ASSIGN:
|
||||
case BINOP_BIT_AND_ASSIGN:
|
||||
case BINOP_BIT_OR_ASSIGN:
|
||||
case BINOP_BIT_XOR_ASSIGN:
|
||||
case BINOP_SHR_ASSIGN:
|
||||
case BINOP_SHL_ASSIGN:
|
||||
SEMA_ERROR(expr->loc, "Invalid operation '%s' %s '%s.", left_expr->type->name_loc.string, token_type_to_string(binop_to_token(expr->binary_expr.operator)), right_expr->type->name_loc.string);
|
||||
return false;
|
||||
case BINOP_MULT:
|
||||
ARITH(*);
|
||||
case BINOP_ADD:
|
||||
ARITH(+);
|
||||
case BINOP_SUB:
|
||||
ARITH(-);
|
||||
case BINOP_DIV:
|
||||
switch (left->type)
|
||||
{
|
||||
case CONST_NIL:
|
||||
case CONST_BOOL:
|
||||
case CONST_STRING:
|
||||
UNREACHABLE;
|
||||
case CONST_INT:
|
||||
if (right->i == 0)
|
||||
{
|
||||
SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed.");
|
||||
return false;
|
||||
}
|
||||
result->i = left->i / right->i;
|
||||
break;
|
||||
case CONST_FLOAT:
|
||||
if (right->f == 0)
|
||||
{
|
||||
SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed.");
|
||||
return false;
|
||||
}
|
||||
expr->const_expr.f = left->f / right->f;
|
||||
expr->const_expr.type = CONST_FLOAT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BINOP_MOD:
|
||||
switch (left->type)
|
||||
{
|
||||
case CONST_NIL:
|
||||
case CONST_BOOL:
|
||||
case CONST_STRING:
|
||||
case CONST_FLOAT:
|
||||
UNREACHABLE;
|
||||
case CONST_INT:
|
||||
if (right->i == 0)
|
||||
{
|
||||
SEMA_ERROR(expr->binary_expr.right->loc, "Cannot do mod by zero.");
|
||||
return false;
|
||||
}
|
||||
result->i = left->i % right->i;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BINOP_AND:
|
||||
BOOL_COMP(&&);
|
||||
case BINOP_OR:
|
||||
BOOL_COMP(||);
|
||||
case BINOP_BIT_AND:
|
||||
BITOP(&);
|
||||
case BINOP_BIT_OR:
|
||||
BITOP(|);
|
||||
case BINOP_BIT_XOR:
|
||||
BITOP(^);
|
||||
case BINOP_NE:
|
||||
COMP_OP(!=)
|
||||
case BINOP_EQ:
|
||||
COMP_OP(==)
|
||||
case BINOP_GE:
|
||||
COMP_OP(>=)
|
||||
case BINOP_GT:
|
||||
COMP_OP(>)
|
||||
case BINOP_LE:
|
||||
COMP_OP(<=)
|
||||
case BINOP_LT:
|
||||
COMP_OP(<)
|
||||
case BINOP_SHR:
|
||||
TODO
|
||||
break;
|
||||
case BINOP_SHL:
|
||||
TODO
|
||||
break;
|
||||
case BINOP_ELVIS:
|
||||
TODO
|
||||
break;
|
||||
}
|
||||
expr->type = type;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
return true;
|
||||
}
|
||||
@@ -2,10 +2,7 @@
|
||||
// Created by Christoffer Lerno on 2019-08-24.
|
||||
//
|
||||
|
||||
#include <utils/file_utils.h>
|
||||
#include <utils/lib.h>
|
||||
#include "context.h"
|
||||
#include "diagnostics.h"
|
||||
#include "compiler_internal.h"
|
||||
|
||||
Context *current_context;
|
||||
|
||||
@@ -85,6 +82,7 @@ bool context_set_module(Context *context, Token module_name, Token *generic_para
|
||||
|
||||
void context_register_global_decl(Context *context, Decl *decl)
|
||||
{
|
||||
decl->module = context->module;
|
||||
if (decl->decl_kind == DECL_CT_IF)
|
||||
{
|
||||
context->ct_ifs = VECADD(context->ct_ifs, decl);
|
||||
@@ -105,7 +103,7 @@ bool context_add_import(Context *context, Token module_name, Token alias, Import
|
||||
sema_error_range(module_name.span, "A module is not expected to have any upper case characters, please change it.");
|
||||
return false;
|
||||
}
|
||||
Decl *decl = decl_new_in_module(context->module, DECL_IMPORT, module_name, VISIBLE_LOCAL);
|
||||
Decl *decl = decl_new(DECL_IMPORT, module_name, VISIBLE_LOCAL);
|
||||
decl->import.type = import_type;
|
||||
decl->import.generic_parameters = generic_parameters;
|
||||
if (import_type == IMPORT_TYPE_ALIAS_LOCAL || import_type == IMPORT_TYPE_ALIAS)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_common.h"
|
||||
#include "ast.h"
|
||||
|
||||
typedef struct _Context
|
||||
{
|
||||
Token module_name;
|
||||
Token* module_parameters;
|
||||
File * file;
|
||||
Decl** imports;
|
||||
Module *module;
|
||||
STable local_symbols;
|
||||
Decl **declarations;
|
||||
Decl **ct_ifs;
|
||||
Decl *active_function_for_analysis;
|
||||
} Context;
|
||||
|
||||
extern Context *current_context;
|
||||
|
||||
Context *context_create(File *file);
|
||||
void context_push(Context *context);
|
||||
|
||||
void context_register_global_decl(Context *context, Decl *decl);
|
||||
bool context_add_import(Context *context, Token module_name, Token alias, ImportType import_type, Expr** generic_parameters);
|
||||
bool context_set_module_from_filename(Context *context);
|
||||
bool context_set_module(Context *context, Token module_name, Token *generic_parameters);
|
||||
void context_print_ast(Context *context, FILE *file);
|
||||
|
||||
@@ -2,18 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "diagnostics.h"
|
||||
#include "source_file.h"
|
||||
#include "lexer.h"
|
||||
#include "compiler_internal.h"
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct _Diagnostics
|
||||
{
|
||||
bool panic_mode;
|
||||
unsigned errors;
|
||||
unsigned warnings;
|
||||
} Diagnostics;
|
||||
|
||||
Diagnostics diagnostics;
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_common.h"
|
||||
|
||||
void diag_reset(void);
|
||||
void diag_error_range(SourceRange span, const char *message, ...);
|
||||
void diag_verror_range(SourceRange span, const char *message, va_list args);
|
||||
void sema_error_at(SourceLoc loc, const char *message, ...);
|
||||
void sema_error_range(SourceRange range, const char *message, ...);
|
||||
void sema_verror_at(SourceLoc loc, const char *message, va_list args);
|
||||
void sema_verror_range(SourceRange range, const char *message, va_list args);
|
||||
void sema_error(const char *message, ...);
|
||||
void sema_prev_at_range(SourceRange span, const char *message, ...);
|
||||
void sema_prev_at(SourceLoc loc, const char *message, ...);
|
||||
|
||||
#define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__)
|
||||
|
||||
/*
|
||||
|
||||
|
||||
typedef struct _Array Array;
|
||||
|
||||
void diagnostics_init(void);
|
||||
void diagnostics_reset(void);
|
||||
void diagnostics_update_severity(DiagnosticsSeverity severity, DiagnosticsType type);
|
||||
bool diagnostics_silence_warnings(Array *warnings);
|
||||
void diagnostics_use_color(bool use_color);
|
||||
void verror_at(SourceRange span, const char *message, va_list args);
|
||||
void sema_error_range(SourceRange token, const char *message, ...);
|
||||
void sema_error_at(SourceLoc loc, const char *message, ...);
|
||||
void prev_at_range(SourceRange span, const char *message, ...);
|
||||
void prev_at(SourceLoc loc, const char *message, ...);
|
||||
void sema_warn_at(DiagnosticsType type, SourceLoc loc, const char *message, ...);
|
||||
void sema_warn_range(DiagnosticsType type, SourceRange span, const char *message, ...);
|
||||
bool in_panic_mode(void);
|
||||
unsigned errors();
|
||||
void reset_panic_mode(void);
|
||||
bool error_found(void);
|
||||
*/
|
||||
525
src/compiler/enums.h
Normal file
525
src/compiler/enums.h
Normal file
@@ -0,0 +1,525 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Only include this from compiler_common.h
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ASSIGNOP_ERROR,
|
||||
ASSIGNOP_ASSIGN,
|
||||
ASSIGNOP_MULT_ASSIGN,
|
||||
ASSIGNOP_ADD_ASSIGN,
|
||||
ASSIGNOP_SUB_ASSIGN,
|
||||
ASSIGNOP_DIV_ASSIGN,
|
||||
ASSIGNOP_MOD_ASSIGN,
|
||||
ASSIGNOP_AND_ASSIGN,
|
||||
ASSIGNOP_OR_ASSIGN,
|
||||
ASSIGNOP_BIT_AND_ASSIGN,
|
||||
ASSIGNOP_BIT_OR_ASSIGN,
|
||||
ASSIGNOP_BIT_XOR_ASSIGN,
|
||||
ASSIGNOP_SHR_ASSIGN,
|
||||
ASSIGNOP_SHL_ASSIGN,
|
||||
} AssignOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AST_POISONED,
|
||||
AST_ASM_STMT,
|
||||
AST_ATTRIBUTE,
|
||||
AST_BREAK_STMT,
|
||||
AST_CASE_STMT,
|
||||
AST_CATCH_STMT,
|
||||
AST_COMPOUND_STMT,
|
||||
AST_COND_STMT,
|
||||
AST_CONTINUE_STMT,
|
||||
AST_CT_IF_STMT,
|
||||
AST_CT_ELIF_STMT,
|
||||
AST_CT_ELSE_STMT,
|
||||
AST_DECLARE_STMT,
|
||||
AST_DECL_EXPR_LIST,
|
||||
AST_DEFAULT_STMT,
|
||||
AST_DEFER_STMT,
|
||||
AST_DO_STMT,
|
||||
AST_EXPR_STMT,
|
||||
AST_FOR_STMT,
|
||||
AST_GOTO_STMT,
|
||||
AST_IF_STMT,
|
||||
AST_LABEL,
|
||||
AST_NOP_STMT,
|
||||
AST_RETURN_STMT,
|
||||
AST_SWITCH_STMT,
|
||||
AST_THROW_STMT,
|
||||
AST_TRY_STMT,
|
||||
AST_NEXT_STMT,
|
||||
AST_VOLATILE_STMT,
|
||||
AST_WHILE_STMT,
|
||||
AST_GENERIC_CASE_STMT,
|
||||
AST_GENERIC_DEFAULT_STMT,
|
||||
} AstKind;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ATTR_INVALID,
|
||||
ATTR_UNRESOLVED,
|
||||
} AttrKind;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BINOP_ERROR,
|
||||
BINOP_ASSIGN,
|
||||
BINOP_MULT,
|
||||
BINOP_MULT_ASSIGN,
|
||||
BINOP_ADD,
|
||||
BINOP_ADD_ASSIGN,
|
||||
BINOP_SUB,
|
||||
BINOP_SUB_ASSIGN,
|
||||
BINOP_DIV,
|
||||
BINOP_DIV_ASSIGN,
|
||||
BINOP_MOD,
|
||||
BINOP_MOD_ASSIGN,
|
||||
BINOP_AND,
|
||||
BINOP_AND_ASSIGN,
|
||||
BINOP_OR,
|
||||
BINOP_OR_ASSIGN,
|
||||
BINOP_BIT_AND,
|
||||
BINOP_BIT_AND_ASSIGN,
|
||||
BINOP_BIT_OR,
|
||||
BINOP_BIT_OR_ASSIGN,
|
||||
BINOP_BIT_XOR,
|
||||
BINOP_BIT_XOR_ASSIGN,
|
||||
BINOP_NE,
|
||||
BINOP_EQ,
|
||||
BINOP_GE,
|
||||
BINOP_GT,
|
||||
BINOP_LE,
|
||||
BINOP_LT,
|
||||
BINOP_SHR,
|
||||
BINOP_SHR_ASSIGN,
|
||||
BINOP_SHL,
|
||||
BINOP_SHL_ASSIGN,
|
||||
BINOP_ELVIS
|
||||
} BinOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAST_ERROR,
|
||||
CAST_TRUNC,
|
||||
CAST_PTRPTR,
|
||||
CAST_PTRINT,
|
||||
CAST_VARRPTR,
|
||||
CAST_ARRPTR,
|
||||
CAST_STRPTR,
|
||||
CAST_PTRBOOL,
|
||||
CAST_BOOLINT,
|
||||
CAST_BOOLFP,
|
||||
CAST_INTBOOL,
|
||||
CAST_FPFP,
|
||||
CAST_FPSI,
|
||||
CAST_FPUI,
|
||||
CAST_SISI,
|
||||
CAST_SIUI,
|
||||
CAST_SIFP,
|
||||
CAST_XIPTR,
|
||||
CAST_UISI,
|
||||
CAST_UIUI,
|
||||
CAST_UIFP,
|
||||
CAST_ENUMSI,
|
||||
/*
|
||||
CAST_NONE,
|
||||
CAST_INLINE,
|
||||
CAST_FAILED,
|
||||
CAST_SUBTYPE,
|
||||
CAST_VARRPTR,
|
||||
CAST_STRPTR,
|
||||
CAST_ARRPTR,
|
||||
CAST_INTPTR,
|
||||
CAST_PTRINT,
|
||||
CAST_PTRBOOL,
|
||||
CAST_FPFP,
|
||||
CAST_FPUI,
|
||||
CAST_FPSI,
|
||||
CAST_FPBOOL,
|
||||
CAST_UIFP,
|
||||
CAST_UIUI,
|
||||
CAST_UISI,
|
||||
CAST_SIFP,
|
||||
CAST_SISI,
|
||||
CAST_SIUI,
|
||||
CAST_INTBOOL,
|
||||
CAST_BOOLFP,
|
||||
CAST_BOOLINT,
|
||||
CAST_RVALUE,*/
|
||||
} CastKind;
|
||||
|
||||
typedef enum _CastType
|
||||
{
|
||||
CAST_TYPE_EXPLICIT,
|
||||
CAST_TYPE_IMPLICIT,
|
||||
CAST_TYPE_IMPLICIT_ASSIGN,
|
||||
CAST_TYPE_IMPLICIT_ASSIGN_ADD,
|
||||
} CastType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CONST_NIL,
|
||||
CONST_BOOL,
|
||||
CONST_INT,
|
||||
CONST_FLOAT,
|
||||
CONST_STRING,
|
||||
} ConstType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DECLEXPR_DECL,
|
||||
DECLEXPR_EXPR,
|
||||
} DeclExprType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DECL_POISONED = 0,
|
||||
DECL_FUNC,
|
||||
DECL_VAR,
|
||||
DECL_ENUM_CONSTANT,
|
||||
DECL_TYPEDEF,
|
||||
DECL_STRUCT,
|
||||
DECL_UNION,
|
||||
DECL_ENUM,
|
||||
DECL_ERROR,
|
||||
DECL_ERROR_CONSTANT,
|
||||
DECL_ARRAY_VALUE,
|
||||
DECL_IMPORT,
|
||||
DECL_MACRO,
|
||||
DECL_MULTI_DECL,
|
||||
DECL_GENERIC,
|
||||
DECL_CT_IF,
|
||||
DECL_CT_ELSE,
|
||||
DECL_CT_ELIF,
|
||||
} DeclKind;
|
||||
|
||||
// Ordering here is in priority if two branches should have the same exit.
|
||||
typedef enum
|
||||
{
|
||||
EXIT_NONE,
|
||||
EXIT_BREAK,
|
||||
EXIT_GOTO,
|
||||
EXIT_CONTINUE,
|
||||
EXIT_RETURN,
|
||||
} ExitType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EXPR_POISONED,
|
||||
EXPR_TRY,
|
||||
EXPR_CONST,
|
||||
EXPR_BINARY,
|
||||
EXPR_CONDITIONAL,
|
||||
EXPR_UNARY,
|
||||
EXPR_POST_UNARY,
|
||||
EXPR_TYPE,
|
||||
EXPR_IDENTIFIER,
|
||||
EXPR_METHOD_REF,
|
||||
EXPR_CALL,
|
||||
EXPR_SIZEOF,
|
||||
EXPR_SUBSCRIPT,
|
||||
EXPR_ACCESS,
|
||||
EXPR_STRUCT_VALUE,
|
||||
EXPR_STRUCT_INIT_VALUES,
|
||||
EXPR_INITIALIZER_LIST,
|
||||
EXPR_EXPRESSION_LIST,
|
||||
EXPR_DEFERRED_TOKENS,
|
||||
EXPR_CAST,
|
||||
} ExprKind;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GOTO_NOT_ANALYSED,
|
||||
GOTO_JUMP_FORWARD,
|
||||
GOTO_JUMP_BACK
|
||||
} GotoType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IMPORT_TYPE_FULL,
|
||||
IMPORT_TYPE_ALIAS,
|
||||
IMPORT_TYPE_ALIAS_LOCAL,
|
||||
IMPORT_TYPE_LOCAL
|
||||
} ImportType;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LEXER_STATE_NORMAL,
|
||||
LEXER_STATE_DEFERED_PARSING,
|
||||
LEXER_STATE_DOCS_PARSE,
|
||||
LEXER_STATE_DOCS_PARSE_DIRECTIVE,
|
||||
} LexerState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NUMBER_TYPE_BOOL,
|
||||
NUMBER_TYPE_FLOAT,
|
||||
NUMBER_TYPE_SIGNED_INT,
|
||||
NUMBER_TYPE_UNSIGNED_INT,
|
||||
} NumberType;
|
||||
|
||||
typedef enum _Precedence
|
||||
{
|
||||
PREC_NONE,
|
||||
PREC_ASSIGNMENT, // =, *=, /=, %=, ...
|
||||
PREC_CONDITIONAL, // ?:
|
||||
PREC_LOGICAL, // && ||
|
||||
PREC_RELATIONAL, // < > <= >= == !=
|
||||
PREC_ADDITIVE, // + -
|
||||
PREC_BIT, // ^ | &
|
||||
PREC_SHIFT, // << >> >>>
|
||||
PREC_MULTIPLICATIVE, // * / %
|
||||
PREC_UNARY, // ! - + ~ * & prefix ++/--
|
||||
PREC_CALL, // . () [] postfix ++/--
|
||||
} Precedence;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RESOLVE_NOT_DONE = 0,
|
||||
RESOLVE_RUNNING,
|
||||
RESOLVE_DONE
|
||||
} ResolveStatus;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TOKEN_INVALID_TOKEN = 0,
|
||||
|
||||
// Single-character tokens.
|
||||
TOKEN_AMP, // &
|
||||
TOKEN_AT, // @
|
||||
TOKEN_BIT_NOT, // ~
|
||||
TOKEN_BIT_OR, // =
|
||||
TOKEN_BIT_XOR, // ^
|
||||
TOKEN_COLON, // :
|
||||
TOKEN_COMMA, // ,
|
||||
TOKEN_EOS, // ;
|
||||
TOKEN_EQ, // =
|
||||
TOKEN_GREATER, // >
|
||||
TOKEN_DIV, // /
|
||||
TOKEN_DOLLAR, // $
|
||||
TOKEN_DOT, // .
|
||||
TOKEN_HASH, // #
|
||||
TOKEN_LESS, // <
|
||||
TOKEN_LBRACE, // {
|
||||
TOKEN_LBRACKET, // [
|
||||
TOKEN_LPAREN, // (
|
||||
TOKEN_MINUS, // -
|
||||
TOKEN_MOD, // %
|
||||
TOKEN_NOT, // !
|
||||
TOKEN_OR, // |
|
||||
TOKEN_PLUS, // +
|
||||
TOKEN_QUESTION, // ?
|
||||
TOKEN_RBRACE, // }
|
||||
TOKEN_RBRACKET, // ]
|
||||
TOKEN_RPAREN, // )
|
||||
TOKEN_STAR, // *
|
||||
|
||||
// two character tokens.
|
||||
TOKEN_AND, // &&
|
||||
TOKEN_ARROW, // -> // Not used but reserved
|
||||
TOKEN_BIT_AND_ASSIGN, // &=
|
||||
TOKEN_BIT_OR_ASSIGN, // |=
|
||||
TOKEN_BIT_XOR_ASSIGN, // ^=
|
||||
TOKEN_DIV_ASSIGN, // /=
|
||||
TOKEN_DOTDOT, // ..
|
||||
TOKEN_ELVIS, // ?:
|
||||
TOKEN_EQEQ, // ==
|
||||
TOKEN_GREATER_EQ, // >=
|
||||
TOKEN_LESS_EQ, // <=
|
||||
TOKEN_MINUS_ASSIGN, // -=
|
||||
TOKEN_MINUSMINUS, // --
|
||||
TOKEN_MOD_ASSIGN, // %=
|
||||
TOKEN_MULT_ASSIGN, // *=
|
||||
TOKEN_NOT_EQUAL, // !=
|
||||
TOKEN_PLUS_ASSIGN, // +=
|
||||
TOKEN_PLUSPLUS, // ++
|
||||
TOKEN_SCOPE, // ::
|
||||
TOKEN_SHR, // >>
|
||||
TOKEN_SHL, // >>
|
||||
|
||||
// Three or more
|
||||
TOKEN_AND_ASSIGN, // &&=
|
||||
TOKEN_ELIPSIS, // ...
|
||||
TOKEN_OR_ASSIGN, // ||=
|
||||
TOKEN_SHR_ASSIGN, // >>=
|
||||
TOKEN_SHL_ASSIGN, // >>=
|
||||
|
||||
// Basic types names
|
||||
TOKEN_VOID,
|
||||
TOKEN_BYTE,
|
||||
TOKEN_BOOL,
|
||||
TOKEN_CHAR,
|
||||
TOKEN_DOUBLE,
|
||||
TOKEN_FLOAT,
|
||||
TOKEN_HALF,
|
||||
TOKEN_INT,
|
||||
TOKEN_ISIZE,
|
||||
TOKEN_LONG,
|
||||
TOKEN_SHORT,
|
||||
TOKEN_UINT,
|
||||
TOKEN_ULONG,
|
||||
TOKEN_USHORT,
|
||||
TOKEN_USIZE,
|
||||
TOKEN_QUAD,
|
||||
|
||||
// C types
|
||||
TOKEN_C_SHORT,
|
||||
TOKEN_C_INT,
|
||||
TOKEN_C_LONG,
|
||||
TOKEN_C_LONGLONG,
|
||||
TOKEN_C_USHORT,
|
||||
TOKEN_C_UINT,
|
||||
TOKEN_C_ULONG,
|
||||
TOKEN_C_ULONGLONG,
|
||||
|
||||
|
||||
// Literals.
|
||||
|
||||
TOKEN_IDENT, // Any normal ident.
|
||||
TOKEN_CONST_IDENT, // Any purely upper case ident,
|
||||
TOKEN_TYPE_IDENT, // Any ident on the format FooBar or __FooBar
|
||||
|
||||
// We want to parse @foo / #foo / $foo separately.
|
||||
// Otherwise we allow things like "@ foo" which would be pretty bad.
|
||||
TOKEN_AT_IDENT, // @foobar
|
||||
TOKEN_HASH_IDENT, // #foobar
|
||||
TOKEN_CT_IDENT, // $foobar
|
||||
|
||||
TOKEN_STRING, // "Teststring"
|
||||
TOKEN_INTEGER, // 123 0x23 0b10010 0o327
|
||||
TOKEN_REAL, // 0x23.2p-2a 43.23e23
|
||||
|
||||
// Keywords
|
||||
TOKEN_ALIAS, // Reserved
|
||||
TOKEN_AS,
|
||||
TOKEN_ASM,
|
||||
TOKEN_ATTRIBUTE,
|
||||
TOKEN_BREAK,
|
||||
TOKEN_CASE,
|
||||
TOKEN_CAST,
|
||||
TOKEN_CATCH,
|
||||
TOKEN_CONST,
|
||||
TOKEN_CONTINUE,
|
||||
TOKEN_DEFAULT,
|
||||
TOKEN_DEFER,
|
||||
TOKEN_DO,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_ENUM,
|
||||
TOKEN_ERROR_TYPE,
|
||||
TOKEN_FALSE,
|
||||
TOKEN_FOR,
|
||||
TOKEN_FUNC,
|
||||
TOKEN_GENERIC,
|
||||
TOKEN_GOTO,
|
||||
TOKEN_IF,
|
||||
TOKEN_IMPORT,
|
||||
TOKEN_LOCAL,
|
||||
TOKEN_MACRO,
|
||||
TOKEN_MODULE,
|
||||
TOKEN_NEXT,
|
||||
TOKEN_NIL,
|
||||
TOKEN_PUBLIC,
|
||||
TOKEN_RETURN,
|
||||
TOKEN_STRUCT,
|
||||
TOKEN_SWITCH,
|
||||
TOKEN_THROW,
|
||||
TOKEN_THROWS,
|
||||
TOKEN_TRUE,
|
||||
TOKEN_TRY,
|
||||
TOKEN_TYPE, // Reserved
|
||||
TOKEN_TYPEDEF,
|
||||
TOKEN_UNION,
|
||||
TOKEN_UNTIL,
|
||||
TOKEN_VAR, // Reserved
|
||||
TOKEN_VOLATILE,
|
||||
TOKEN_WHILE,
|
||||
|
||||
TOKEN_AT_PARAM, // @param
|
||||
TOKEN_AT_THROWS, // @throws
|
||||
TOKEN_AT_RETURN, // @return
|
||||
TOKEN_AT_ENSURE, // @ensure
|
||||
TOKEN_AT_REQUIRE, // @require
|
||||
TOKEN_AT_PURE, // @pure
|
||||
TOKEN_AT_CONST, // @const
|
||||
TOKEN_AT_REQPARSE, // @reqparse
|
||||
TOKEN_AT_DEPRECATED, // @deprecated
|
||||
|
||||
TOKEN_CT_CASE, // $case
|
||||
TOKEN_CT_DEFAULT, // $default
|
||||
TOKEN_CT_EACH, // $each
|
||||
TOKEN_CT_ELIF, // $elif
|
||||
TOKEN_CT_ELSE, // $else
|
||||
TOKEN_CT_IF, // $if
|
||||
TOKEN_CT_SWITCH, // $switch
|
||||
|
||||
TOKEN_DOCS_START, // /**
|
||||
TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*`
|
||||
TOKEN_DOCS_EOL, // "\n" only seen in docs.
|
||||
TOKEN_DOCS_LINE, // Any line within /** **/
|
||||
|
||||
TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN.
|
||||
|
||||
} TokenType;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TYPE_POISONED,
|
||||
TYPE_USER_DEFINED,
|
||||
TYPE_VOID,
|
||||
TYPE_BOOL,
|
||||
TYPE_I8,
|
||||
TYPE_I16,
|
||||
TYPE_I32,
|
||||
TYPE_I64,
|
||||
TYPE_IXX,
|
||||
TYPE_U8,
|
||||
TYPE_U16,
|
||||
TYPE_U32,
|
||||
TYPE_U64,
|
||||
TYPE_UXX,
|
||||
TYPE_F32,
|
||||
TYPE_F64,
|
||||
TYPE_FXX,
|
||||
TYPE_POINTER,
|
||||
TYPE_STRING,
|
||||
TYPE_ARRAY,
|
||||
TYPE_VARARRAY,
|
||||
TYPE_INC_ARRAY,
|
||||
TYPE_EXPRESSION,
|
||||
} TypeKind;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UNARYOP_ERROR,
|
||||
UNARYOP_DEREF,
|
||||
UNARYOP_ADDR,
|
||||
UNARYOP_NEG,
|
||||
UNARYOP_BITNEG,
|
||||
UNARYOP_NOT,
|
||||
UNARYOP_INC,
|
||||
UNARYOP_DEC,
|
||||
} UnaryOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VARDECL_CONST = 0,
|
||||
VARDECL_GLOBAL = 1,
|
||||
VARDECL_LOCAL = 2,
|
||||
VARDECL_PARAM = 3,
|
||||
VARDECL_MEMBER = 4,
|
||||
VARDECL_MULTI = 5,
|
||||
} VarDeclKind;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VISIBLE_MODULE,
|
||||
VISIBLE_LOCAL,
|
||||
VISIBLE_PUBLIC,
|
||||
} Visibility;
|
||||
|
||||
@@ -2,14 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "lexer.h"
|
||||
#include <build/build_options.h>
|
||||
#include "../utils/errors.h"
|
||||
#include "../utils/lib.h"
|
||||
#include "symtab.h"
|
||||
#include "source_file.h"
|
||||
#include "diagnostics.h"
|
||||
#include <stdarg.h>
|
||||
#include "compiler_internal.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "compiler_common.h"
|
||||
|
||||
extern Token next_tok;
|
||||
extern Token tok;
|
||||
|
||||
Token lexer_scan_token(void);
|
||||
Token lexer_scan_ident_test(const char *scan);
|
||||
void lexer_test_setup(const char *text, size_t len);
|
||||
void lexer_add_file_for_lexing(File *file);
|
||||
File* lexer_current_file(void);
|
||||
void lexer_check_init(void);
|
||||
void lexer_store_state(void);
|
||||
void lexer_restore_state(void);
|
||||
|
||||
static inline void advance(void)
|
||||
{
|
||||
tok = next_tok;
|
||||
while (1)
|
||||
{
|
||||
next_tok = lexer_scan_token();
|
||||
// printf(">>> %.*s => %s\n", tok.length, tok.start, token_type_to_string(tok.type));
|
||||
if (next_tok.type != TOKEN_INVALID_TOKEN) break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void advance_and_verify(TokenType token_type)
|
||||
{
|
||||
assert(tok.type == token_type);
|
||||
advance();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "../utils/lib.h"
|
||||
#include "compiler_common.h"
|
||||
#include "ast.h"
|
||||
|
||||
@@ -2,15 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include "../utils/lib.h"
|
||||
#include "parser.h"
|
||||
#include "semantic_analyser.h"
|
||||
#include "lexer.h"
|
||||
#include "ast.h"
|
||||
#include "diagnostics.h"
|
||||
#include "context.h"
|
||||
#include "compiler_internal.h"
|
||||
|
||||
const int MAX_DOCS_ROWS = 1024;
|
||||
|
||||
@@ -200,7 +192,7 @@ static Ast* parse_compound_stmt()
|
||||
{
|
||||
LOG_FUNC
|
||||
CONSUME_OR(TOKEN_LBRACE, &poisoned_ast);
|
||||
Ast *ast = NEW_AST(AST_COMPOUND_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_COMPOUND_STMT, tok);
|
||||
while (!try_consume(TOKEN_RBRACE))
|
||||
{
|
||||
Ast *stmt = TRY_AST(parse_stmt());
|
||||
@@ -238,10 +230,10 @@ static inline Type *parse_base_type(void)
|
||||
|
||||
if (tok.type == TOKEN_IDENT && next_tok.type == TOKEN_SCOPE)
|
||||
{
|
||||
Type *type = type_new(TYPE_UNRESOLVED);
|
||||
Type *type = type_new(TYPE_USER_DEFINED);
|
||||
type->unresolved.module = tok;
|
||||
advance(); advance();
|
||||
type->unresolved.name = tok;
|
||||
type->name_loc = tok;
|
||||
if (!consume_type_name("types")) return &poisoned_type;
|
||||
return type;
|
||||
}
|
||||
@@ -250,14 +242,13 @@ static inline Type *parse_base_type(void)
|
||||
switch (tok.type)
|
||||
{
|
||||
case TOKEN_TYPE_IDENT:
|
||||
type = type_new(TYPE_UNRESOLVED);
|
||||
type->unresolved.name = tok;
|
||||
type = TYPE_UNRESOLVED(tok);
|
||||
break;
|
||||
case TOKEN_TYPE:
|
||||
advance_and_verify(TOKEN_TYPE);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_type);
|
||||
{
|
||||
type = type_new(TYPE_UNRESOLVED_EXPR);
|
||||
type = type_new(TYPE_EXPRESSION);
|
||||
type->unresolved_type_expr = TRY_EXPR_OR(parse_expr(), &poisoned_type);
|
||||
}
|
||||
EXPECT_OR(TOKEN_RPAREN, &poisoned_type);
|
||||
@@ -304,6 +295,31 @@ static inline Type *parse_base_type(void)
|
||||
case TOKEN_USIZE:
|
||||
type = &type_usize;
|
||||
break;
|
||||
case TOKEN_C_SHORT:
|
||||
type = &type_c_short;
|
||||
break;
|
||||
case TOKEN_C_INT:
|
||||
type = &type_c_int;
|
||||
break;
|
||||
case TOKEN_C_LONG:
|
||||
type = &type_c_long;
|
||||
break;
|
||||
case TOKEN_C_LONGLONG:
|
||||
type = &type_c_longlong;
|
||||
break;
|
||||
case TOKEN_C_USHORT:
|
||||
type = &type_c_ushort;
|
||||
break;
|
||||
case TOKEN_C_UINT:
|
||||
type = &type_c_uint;
|
||||
break;
|
||||
case TOKEN_C_ULONG:
|
||||
type = &type_c_ulong;
|
||||
break;
|
||||
case TOKEN_C_ULONGLONG:
|
||||
type = &type_c_ulonglong;
|
||||
break;
|
||||
|
||||
default:
|
||||
SEMA_ERROR(tok, "A type name was expected here.");
|
||||
type = &poisoned_type;
|
||||
@@ -335,16 +351,17 @@ static inline Type *parse_array_type_index(Type *type)
|
||||
CONSUME_OR(TOKEN_RBRACKET, &poisoned_type);
|
||||
Type *incr_array = type_new(TYPE_INC_ARRAY);
|
||||
incr_array->base = type;
|
||||
incr_array->resolve_status = incr_array->base->resolve_status;
|
||||
return incr_array;
|
||||
}
|
||||
if (try_consume(TOKEN_RBRACKET))
|
||||
{
|
||||
Type *array = type_new(TYPE_ARRAY);
|
||||
Type *array = type_new(TYPE_VARARRAY);
|
||||
array->base = type;
|
||||
array->len = 0;
|
||||
return array;
|
||||
}
|
||||
Type *array = type_new(TYPE_UNRESOLVED_ARRAY);
|
||||
Type *array = type_new(TYPE_ARRAY);
|
||||
array->base = type;
|
||||
array->unresolved_len = TRY_EXPR_OR(parse_expr(), &poisoned_type);
|
||||
CONSUME_OR(TOKEN_RBRACKET, &poisoned_type);
|
||||
@@ -377,9 +394,10 @@ static Type *parse_type_expression(void)
|
||||
advance();
|
||||
{
|
||||
Type *ptr_type = type_new(TYPE_POINTER);
|
||||
type->base = type;
|
||||
type->nullable = true;
|
||||
type = ptr_type;
|
||||
assert(type);
|
||||
ptr_type->base = type;
|
||||
ptr_type->nullable = true;
|
||||
type = ptr_type;
|
||||
}
|
||||
break;
|
||||
case TOKEN_AMP:
|
||||
@@ -387,7 +405,8 @@ static Type *parse_type_expression(void)
|
||||
{
|
||||
Type *ptr_type = type_new(TYPE_POINTER);
|
||||
type->base = type;
|
||||
type->nullable = false;
|
||||
assert(type);
|
||||
type->nullable = false;
|
||||
type = ptr_type;
|
||||
}
|
||||
break;
|
||||
@@ -411,7 +430,7 @@ static inline Decl *parse_decl_after_type(bool local, Type *type)
|
||||
advance();
|
||||
|
||||
Visibility visibility = local ? VISIBLE_LOCAL : VISIBLE_MODULE;
|
||||
Decl *decl = decl_new_var(current_context->module, name, type, VARDECL_LOCAL, visibility);
|
||||
Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, visibility);
|
||||
Decl *main_decl = decl;
|
||||
|
||||
while (1)
|
||||
@@ -454,7 +473,7 @@ static inline Decl *parse_decl_after_type(bool local, Type *type)
|
||||
|
||||
if (tok.type == TOKEN_IDENT)
|
||||
{
|
||||
Decl *new_decl = decl_new_var(current_context->module, tok, type, VARDECL_LOCAL, visibility);
|
||||
Decl *new_decl = decl_new_var(tok, type, VARDECL_LOCAL, visibility);
|
||||
advance();
|
||||
if (main_decl->decl_kind == DECL_MULTI_DECL)
|
||||
{
|
||||
@@ -462,7 +481,7 @@ static inline Decl *parse_decl_after_type(bool local, Type *type)
|
||||
decl = new_decl;
|
||||
continue;
|
||||
}
|
||||
Decl *multi = decl_new_in_module(current_context->module, DECL_MULTI_DECL, main_decl->name, visibility);
|
||||
Decl *multi = decl_new(DECL_MULTI_DECL, main_decl->name, visibility);
|
||||
multi->multi_decl = VECADD(multi->multi_decl, main_decl);
|
||||
multi->multi_decl = VECADD(multi->multi_decl, new_decl);
|
||||
main_decl = multi;
|
||||
@@ -499,7 +518,7 @@ static Decl *parse_decl(void)
|
||||
*/
|
||||
static Ast *parse_declaration_stmt(void)
|
||||
{
|
||||
Ast *decl_stmt = NEW_AST(AST_DECLARE_STMT, tok);
|
||||
Ast *decl_stmt = AST_NEW(AST_DECLARE_STMT, tok);
|
||||
decl_stmt->declare_stmt = TRY_DECL_OR(parse_decl(), &poisoned_ast);
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
return decl_stmt;
|
||||
@@ -521,7 +540,7 @@ typedef enum
|
||||
*/
|
||||
static Ast *parse_expr_stmt(void)
|
||||
{
|
||||
Ast *stmt = NEW_AST(AST_EXPR_STMT, tok);
|
||||
Ast *stmt = AST_NEW(AST_EXPR_STMT, tok);
|
||||
stmt->expr_stmt = TRY_EXPR_OR(parse_expr(), &poisoned_ast);
|
||||
TRY_CONSUME_EOS();
|
||||
return stmt;
|
||||
@@ -561,7 +580,7 @@ static inline Ast* parse_decl_expr_list(void)
|
||||
Expr *expr = NULL;
|
||||
Type *type = NULL;
|
||||
|
||||
Ast *decl_expr_list = NEW_AST(AST_DECL_EXPR_LIST, tok);
|
||||
Ast *decl_expr_list = AST_NEW(AST_DECL_EXPR_LIST, tok);
|
||||
|
||||
if (!parse_type_or_expr(&expr, &type)) return &poisoned_ast;
|
||||
|
||||
@@ -637,7 +656,7 @@ static inline Ast *parse_control_expression()
|
||||
static inline Ast* parse_if_stmt(void)
|
||||
{
|
||||
LOG_FUNC
|
||||
Ast *if_ast = NEW_AST(AST_IF_STMT, tok);
|
||||
Ast *if_ast = AST_NEW(AST_IF_STMT, tok);
|
||||
advance_and_verify(TOKEN_IF);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
Ast *cond = TRY_AST(parse_control_expression());
|
||||
@@ -665,7 +684,7 @@ static inline Ast* parse_if_stmt(void)
|
||||
|
||||
static inline Ast* parse_while_stmt(void)
|
||||
{
|
||||
Ast *while_ast = NEW_AST(AST_WHILE_STMT, tok);
|
||||
Ast *while_ast = AST_NEW(AST_WHILE_STMT, tok);
|
||||
|
||||
advance_and_verify(TOKEN_WHILE);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
@@ -684,7 +703,7 @@ static inline Ast* parse_while_stmt(void)
|
||||
*/
|
||||
static inline Ast* parse_defer_stmt(void)
|
||||
{
|
||||
Ast *defer_stmt = NEW_AST(AST_DEFER_STMT, tok);
|
||||
Ast *defer_stmt = AST_NEW(AST_DEFER_STMT, tok);
|
||||
advance_and_verify(TOKEN_DEFER);
|
||||
defer_stmt->defer_stmt.body = TRY_AST(parse_stmt());
|
||||
return defer_stmt;
|
||||
@@ -700,7 +719,7 @@ static inline Ast* parse_defer_stmt(void)
|
||||
*/
|
||||
static inline Ast* parse_catch_stmt(void)
|
||||
{
|
||||
Ast *catch_stmt = NEW_AST(AST_CATCH_STMT, tok);
|
||||
Ast *catch_stmt = AST_NEW(AST_CATCH_STMT, tok);
|
||||
advance_and_verify(TOKEN_CATCH);
|
||||
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
@@ -711,7 +730,7 @@ static inline Ast* parse_catch_stmt(void)
|
||||
type = TRY_TYPE_OR(parse_type_expression(), &poisoned_ast);
|
||||
}
|
||||
EXPECT_IDENT_FOR_OR("error parameter", &poisoned_ast);
|
||||
Decl *decl = decl_new_var(current_context->module, tok, type, VARDECL_PARAM, VISIBLE_LOCAL);
|
||||
Decl *decl = decl_new_var(tok, type, VARDECL_PARAM, VISIBLE_LOCAL);
|
||||
catch_stmt->catch_stmt.error_param = decl;
|
||||
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
|
||||
@@ -730,7 +749,7 @@ static inline Ast* parse_asm_stmt(void)
|
||||
*/
|
||||
static inline Ast* parse_do_stmt(void)
|
||||
{
|
||||
Ast *do_ast = NEW_AST(AST_DO_STMT, tok);
|
||||
Ast *do_ast = AST_NEW(AST_DO_STMT, tok);
|
||||
|
||||
advance_and_verify(TOKEN_DO);
|
||||
|
||||
@@ -755,7 +774,7 @@ static inline Ast* parse_do_stmt(void)
|
||||
*/
|
||||
static inline Ast* parse_switch_stmt(void)
|
||||
{
|
||||
Ast *switch_ast = NEW_AST(AST_SWITCH_STMT, tok);
|
||||
Ast *switch_ast = AST_NEW(AST_SWITCH_STMT, tok);
|
||||
advance_and_verify(TOKEN_SWITCH);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
switch_ast->switch_stmt.cond = TRY_AST(parse_control_expression());
|
||||
@@ -779,7 +798,7 @@ static inline Ast* parse_switch_stmt(void)
|
||||
*/
|
||||
static inline Ast* parse_for_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_FOR_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_FOR_STMT, tok);
|
||||
advance_and_verify(TOKEN_FOR);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
|
||||
@@ -812,7 +831,7 @@ static inline Expr* parse_constant_expr(void)
|
||||
*/
|
||||
static inline Ast* parse_case_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_CASE_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_CASE_STMT, tok);
|
||||
advance();
|
||||
Expr *expr = TRY_EXPR_OR(parse_constant_expr(), &poisoned_ast);
|
||||
ast->case_stmt.expr = expr;
|
||||
@@ -823,7 +842,7 @@ static inline Ast* parse_case_stmt(void)
|
||||
static inline Ast* parse_goto_stmt(void)
|
||||
{
|
||||
advance_and_verify(TOKEN_GOTO);
|
||||
Ast *ast = NEW_AST(AST_GOTO_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_GOTO_STMT, tok);
|
||||
if (!consume_const_name("label")) return &poisoned_ast;
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
return ast;
|
||||
@@ -831,7 +850,7 @@ static inline Ast* parse_goto_stmt(void)
|
||||
|
||||
static inline Ast* parse_continue_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_CONTINUE_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_CONTINUE_STMT, tok);
|
||||
advance_and_verify(TOKEN_CONTINUE);
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
return ast;
|
||||
@@ -839,7 +858,7 @@ static inline Ast* parse_continue_stmt(void)
|
||||
|
||||
static inline Ast* parse_next_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_NEXT_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_NEXT_STMT, tok);
|
||||
advance_and_verify(TOKEN_NEXT);
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
return ast;
|
||||
@@ -847,7 +866,7 @@ static inline Ast* parse_next_stmt(void)
|
||||
|
||||
static inline Ast* parse_break_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_BREAK_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_BREAK_STMT, tok);
|
||||
advance_and_verify(TOKEN_BREAK);
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
return ast;
|
||||
@@ -862,7 +881,7 @@ static inline Ast* parse_ct_switch_stmt(void)
|
||||
static inline Ast* parse_ct_else_stmt(void)
|
||||
{
|
||||
LOG_FUNC
|
||||
Ast *ast = NEW_AST(AST_CT_ELSE_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_CT_ELSE_STMT, tok);
|
||||
advance_and_verify(TOKEN_CT_ELSE);
|
||||
ast->ct_elif_stmt.then = TRY_AST(parse_compound_stmt());
|
||||
return ast;
|
||||
@@ -876,7 +895,7 @@ static inline Ast* parse_ct_else_stmt(void)
|
||||
static inline Ast *parse_ct_elif_stmt(void)
|
||||
{
|
||||
LOG_FUNC
|
||||
Ast *ast = NEW_AST(AST_CT_ELIF_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_CT_ELIF_STMT, tok);
|
||||
advance_and_verify(TOKEN_CT_ELIF);
|
||||
|
||||
ast->ct_elif_stmt.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_ast);
|
||||
@@ -906,7 +925,7 @@ static inline Ast *parse_ct_elif_stmt(void)
|
||||
static inline Ast* parse_ct_if_stmt(void)
|
||||
{
|
||||
LOG_FUNC
|
||||
Ast *ast = NEW_AST(AST_CT_IF_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_CT_IF_STMT, tok);
|
||||
advance_and_verify(TOKEN_CT_IF);
|
||||
ast->ct_if_stmt.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_ast);
|
||||
ast->ct_if_stmt.then = TRY_AST(parse_compound_stmt());
|
||||
@@ -943,7 +962,7 @@ static Ast *parse_return_stmt(void)
|
||||
LOG_FUNC
|
||||
|
||||
advance_and_verify(TOKEN_RETURN);
|
||||
Ast *ast = NEW_AST(AST_RETURN_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_RETURN_STMT, tok);
|
||||
ast->exit = EXIT_RETURN;
|
||||
ast->return_stmt.defer = 0;
|
||||
if (try_consume(TOKEN_EOS))
|
||||
@@ -958,7 +977,7 @@ static Ast *parse_return_stmt(void)
|
||||
|
||||
static Ast *parse_throw_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_THROW_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_THROW_STMT, tok);
|
||||
advance_and_verify(TOKEN_THROW);
|
||||
ast->throw_stmt = TRY_EXPR_OR(parse_expr(), &poisoned_ast);
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
@@ -967,14 +986,14 @@ static Ast *parse_throw_stmt(void)
|
||||
|
||||
static Ast *parse_volatile_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_VOLATILE_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_VOLATILE_STMT, tok);
|
||||
ast->volatile_stmt = TRY_AST_OR(parse_compound_stmt(), &poisoned_ast);
|
||||
return ast;
|
||||
}
|
||||
|
||||
static Ast *parse_default_stmt(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_DEFAULT_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_DEFAULT_STMT, tok);
|
||||
advance_and_verify(TOKEN_DEFAULT);
|
||||
TRY_CONSUME_OR(TOKEN_COLON, "Expected ':' after 'default'.", &poisoned_ast);
|
||||
return ast;
|
||||
@@ -1000,7 +1019,7 @@ bool is_valid_try_statement(TokenType type)
|
||||
static inline Ast *parse_label_stmt(void)
|
||||
{
|
||||
LOG_FUNC
|
||||
Ast *ast = NEW_AST(AST_LABEL, tok);
|
||||
Ast *ast = AST_NEW(AST_LABEL, tok);
|
||||
advance_and_verify(TOKEN_CONST_IDENT);
|
||||
advance_and_verify(TOKEN_COLON);
|
||||
return ast;
|
||||
@@ -1030,6 +1049,14 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr)
|
||||
case TOKEN_USHORT:
|
||||
case TOKEN_USIZE:
|
||||
case TOKEN_QUAD:
|
||||
case TOKEN_C_SHORT:
|
||||
case TOKEN_C_INT:
|
||||
case TOKEN_C_LONG:
|
||||
case TOKEN_C_LONGLONG:
|
||||
case TOKEN_C_USHORT:
|
||||
case TOKEN_C_UINT:
|
||||
case TOKEN_C_ULONG:
|
||||
case TOKEN_C_ULONGLONG:
|
||||
case TOKEN_TYPE_IDENT:
|
||||
if (next_tok.type == TOKEN_DOT || next_tok.type == TOKEN_LPAREN) break;
|
||||
*typePtr = parse_type_expression();
|
||||
@@ -1061,7 +1088,7 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr)
|
||||
CONSUME_OR(TOKEN_RPAREN, false);
|
||||
if (inner_expr)
|
||||
{
|
||||
*typePtr = type_new(TYPE_UNRESOLVED_EXPR);
|
||||
*typePtr = type_new(TYPE_EXPRESSION);
|
||||
(**typePtr).unresolved_type_expr = inner_expr;
|
||||
return true;
|
||||
}
|
||||
@@ -1096,7 +1123,7 @@ static inline Ast *parse_decl_or_expr_stmt(void)
|
||||
else
|
||||
{
|
||||
Decl *decl = TRY_DECL_OR(parse_decl_after_type(false, type), &poisoned_ast);
|
||||
Ast *ast = NEW_AST(AST_DECLARE_STMT, decl->name);
|
||||
Ast *ast = AST_NEW(AST_DECLARE_STMT, decl->name);
|
||||
ast->declare_stmt = decl;
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
return ast;
|
||||
@@ -1129,6 +1156,14 @@ static Ast *parse_stmt(void)
|
||||
case TOKEN_ULONG:
|
||||
case TOKEN_USHORT:
|
||||
case TOKEN_USIZE:
|
||||
case TOKEN_C_SHORT:
|
||||
case TOKEN_C_INT:
|
||||
case TOKEN_C_LONG:
|
||||
case TOKEN_C_LONGLONG:
|
||||
case TOKEN_C_USHORT:
|
||||
case TOKEN_C_UINT:
|
||||
case TOKEN_C_ULONG:
|
||||
case TOKEN_C_ULONGLONG:
|
||||
case TOKEN_TYPE_IDENT:
|
||||
if (next_tok.type == TOKEN_DOT || next_tok.type == TOKEN_LBRACE)
|
||||
{
|
||||
@@ -1176,7 +1211,7 @@ static Ast *parse_stmt(void)
|
||||
Token try_token = tok;
|
||||
advance();
|
||||
Ast *stmt = TRY_AST(parse_stmt());
|
||||
Ast *try_ast = NEW_AST(AST_TRY_STMT, try_token);
|
||||
Ast *try_ast = AST_NEW(AST_TRY_STMT, try_token);
|
||||
try_ast->try_stmt = stmt;
|
||||
return try_ast;
|
||||
}
|
||||
@@ -1313,7 +1348,7 @@ static Ast *parse_stmt(void)
|
||||
return &poisoned_ast;
|
||||
case TOKEN_EOS:
|
||||
advance();
|
||||
return NEW_AST(AST_NOP_STMT, tok);
|
||||
return AST_NEW(AST_NOP_STMT, tok);
|
||||
case TOKEN_EOF:
|
||||
sema_error_at(tok.span.loc - 1, "Reached the end of the file when expecting a statement.");
|
||||
return &poisoned_ast;
|
||||
@@ -1646,7 +1681,7 @@ static inline Decl *parse_const_declaration(Visibility visibility)
|
||||
|
||||
advance_and_verify(TOKEN_CONST);
|
||||
|
||||
Decl *decl = decl_new_var(current_context->module, tok, NULL, VARDECL_CONST, visibility);
|
||||
Decl *decl = decl_new_var(tok, NULL, VARDECL_CONST, visibility);
|
||||
// Parse the compile time constant.
|
||||
if (tok.type == TOKEN_CT_IDENT)
|
||||
{
|
||||
@@ -1685,7 +1720,7 @@ static inline Decl *parse_global_declaration(Visibility visibility)
|
||||
|
||||
Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl);
|
||||
|
||||
Decl *decl = decl_new_var(current_context->module, tok, type, VARDECL_GLOBAL, visibility);
|
||||
Decl *decl = decl_new_var(tok, type, VARDECL_GLOBAL, visibility);
|
||||
|
||||
if (!consume_ident("global variable")) return &poisoned_decl;
|
||||
|
||||
@@ -1787,19 +1822,18 @@ bool parse_struct_body(Decl *parent, Decl *visible_parent)
|
||||
if (token_type == TOKEN_STRUCT || token_type == TOKEN_UNION)
|
||||
{
|
||||
DeclKind decl_kind = decl_from_token(token_type);
|
||||
TypeKind type_kind = DECL_STRUCT == decl_kind ? TYPE_STRUCT : TYPE_UNION;
|
||||
Decl *member;
|
||||
if (next_tok.type != TOKEN_IDENT)
|
||||
{
|
||||
Token name_replacement = tok;
|
||||
name_replacement.string = NULL;
|
||||
member = decl_new_self_type(parent->module, name_replacement, decl_kind, type_kind, parent->visibility);
|
||||
member = decl_new_user_defined_type(name_replacement, decl_kind, parent->visibility);
|
||||
advance();
|
||||
}
|
||||
else
|
||||
{
|
||||
advance();
|
||||
member = decl_new_self_type(parent->module, tok, decl_kind, type_kind, parent->visibility);
|
||||
member = decl_new_user_defined_type(tok, decl_kind, parent->visibility);
|
||||
Decl *other = struct_find_name(visible_parent, tok.string);
|
||||
if (other)
|
||||
{
|
||||
@@ -1825,7 +1859,7 @@ bool parse_struct_body(Decl *parent, Decl *visible_parent)
|
||||
while (1)
|
||||
{
|
||||
EXPECT_OR(TOKEN_IDENT, false);
|
||||
Decl *member = decl_new_var(parent->module, tok, type, VARDECL_MEMBER, parent->visibility);
|
||||
Decl *member = decl_new_var(tok, type, VARDECL_MEMBER, parent->visibility);
|
||||
Decl *other = struct_find_name(visible_parent, member->name.string);
|
||||
if (other)
|
||||
{
|
||||
@@ -1865,10 +1899,8 @@ static inline Decl *parse_struct_declaration(Visibility visibility)
|
||||
Token name = tok;
|
||||
|
||||
if (!consume_type_name(type_name)) return &poisoned_decl;
|
||||
Decl *decl = decl_new_self_type(current_context->module, name,
|
||||
decl_from_token(type),
|
||||
type == TOKEN_STRUCT ? TYPE_STRUCT : TYPE_UNION,
|
||||
visibility);
|
||||
Decl *decl = decl_new_user_defined_type(name, decl_from_token(type), visibility);
|
||||
|
||||
decl->strukt.method_functions = NULL;
|
||||
|
||||
if (!parse_attributes(decl))
|
||||
@@ -1889,7 +1921,7 @@ static inline Decl *parse_struct_declaration(Visibility visibility)
|
||||
*/
|
||||
static inline Ast *parse_generics_statements(void)
|
||||
{
|
||||
Ast *ast = NEW_AST(AST_COMPOUND_STMT, tok);
|
||||
Ast *ast = AST_NEW(AST_COMPOUND_STMT, tok);
|
||||
while (tok.type != TOKEN_RBRACE && tok.type != TOKEN_CASE && tok.type != TOKEN_DEFAULT)
|
||||
{
|
||||
Ast *stmt = TRY_AST_OR(parse_stmt(), &poisoned_ast);
|
||||
@@ -1918,7 +1950,7 @@ static inline Decl *parse_generics_declaration(Visibility visibility)
|
||||
{
|
||||
rtype = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl);
|
||||
}
|
||||
Decl *decl = decl_new_self_type(current_context->module, tok, DECL_GENERIC, TYPE_GENERIC, visibility);
|
||||
Decl *decl = decl_new_user_defined_type(tok, DECL_GENERIC, visibility);
|
||||
if (!consume_ident("generic function name")) return &poisoned_decl;
|
||||
decl->generic_decl.rtype = rtype;
|
||||
Token *parameters = NULL;
|
||||
@@ -1940,7 +1972,7 @@ static inline Decl *parse_generics_declaration(Visibility visibility)
|
||||
{
|
||||
if (tok.type == TOKEN_CASE)
|
||||
{
|
||||
Ast *generic_case = NEW_AST(AST_GENERIC_CASE_STMT, tok);
|
||||
Ast *generic_case = AST_NEW(AST_GENERIC_CASE_STMT, tok);
|
||||
advance_and_verify(TOKEN_CASE);
|
||||
Type **types = NULL;
|
||||
while (!try_consume(TOKEN_COLON))
|
||||
@@ -1960,7 +1992,7 @@ static inline Decl *parse_generics_declaration(Visibility visibility)
|
||||
}
|
||||
if (tok.type == TOKEN_DEFAULT)
|
||||
{
|
||||
Ast *generic_case = NEW_AST(AST_GENERIC_DEFAULT_STMT, tok);
|
||||
Ast *generic_case = AST_NEW(AST_GENERIC_DEFAULT_STMT, tok);
|
||||
advance_and_verify(TOKEN_DEFAULT);
|
||||
CONSUME_OR(TOKEN_COLON, &poisoned_decl);
|
||||
generic_case->generic_default_stmt = TRY_AST_OR(parse_generics_statements(), &poisoned_decl);
|
||||
@@ -1988,7 +2020,7 @@ static inline bool parse_param_decl(Decl *parent, Decl*** parameters, bool type_
|
||||
LOG_FUNC
|
||||
|
||||
Type *type = TRY_TYPE_OR(parse_type_expression(), false);
|
||||
Decl *param = decl_new_var(parent->module, tok, type, VARDECL_PARAM, parent->visibility);
|
||||
Decl *param = decl_new_var(tok, type, VARDECL_PARAM, parent->visibility);
|
||||
|
||||
if (!try_consume(TOKEN_IDENT))
|
||||
{
|
||||
@@ -2141,7 +2173,7 @@ static inline bool parse_func_typedef(Decl *decl, Visibility visibility)
|
||||
static inline Decl *parse_typedef_declaration(Visibility visibility)
|
||||
{
|
||||
LOG_FUNC
|
||||
Decl *decl = decl_new_in_module(current_context->module, DECL_TYPEDEF, tok, visibility);
|
||||
Decl *decl = decl_new(DECL_TYPEDEF, tok, visibility);
|
||||
advance_and_verify(TOKEN_TYPEDEF);
|
||||
if (tok.type == TOKEN_FUNC)
|
||||
{
|
||||
@@ -2171,7 +2203,7 @@ static inline Decl *parse_macro_declaration(Visibility visibility)
|
||||
rtype = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl);
|
||||
}
|
||||
|
||||
Decl *decl = decl_new_in_module(current_context->module, DECL_MACRO, tok, visibility);
|
||||
Decl *decl = decl_new(DECL_MACRO, tok, visibility);
|
||||
decl->macro_decl.rtype = rtype;
|
||||
TRY_CONSUME_OR(TOKEN_AT_IDENT, "Expected a macro name starting with '@'", &poisoned_decl);
|
||||
|
||||
@@ -2197,7 +2229,7 @@ static inline Decl *parse_macro_declaration(Visibility visibility)
|
||||
parm_type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl);
|
||||
goto TEST_TYPE;
|
||||
}
|
||||
Decl *param = decl_new_var(current_context->module, tok, parm_type, VARDECL_PARAM, visibility);
|
||||
Decl *param = decl_new_var(tok, parm_type, VARDECL_PARAM, visibility);
|
||||
advance();
|
||||
params = VECADD(params, param);
|
||||
COMMA_RPAREN_OR(&poisoned_decl);
|
||||
@@ -2238,7 +2270,7 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa
|
||||
|
||||
Type *return_type = TRY_TYPE_OR(parse_type_expression(), false);
|
||||
|
||||
Decl *func = decl_new_self_type(current_context->module, tok, DECL_FUNC, TYPE_FUNC, visibility);
|
||||
Decl *func = decl_new_user_defined_type(tok, DECL_FUNC, visibility);
|
||||
func->func.function_signature.rtype = return_type;
|
||||
|
||||
if (try_consume(TOKEN_IDENT))
|
||||
@@ -2247,9 +2279,9 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa
|
||||
if (try_consume(TOKEN_SCOPE))
|
||||
{
|
||||
TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "A type was expected after '::'.", false);
|
||||
Type *type = type_new(TYPE_UNRESOLVED);
|
||||
Type *type = type_new(TYPE_USER_DEFINED);
|
||||
type->unresolved.module = func->name;
|
||||
type->unresolved.name = tok;
|
||||
type->name_loc = tok;
|
||||
func->func.struct_parent = type;
|
||||
advance_and_verify(TOKEN_TYPE_IDENT);
|
||||
|
||||
@@ -2263,10 +2295,7 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa
|
||||
else
|
||||
{
|
||||
TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "Expected a function name.", false);
|
||||
Type *type = type_new(TYPE_UNRESOLVED);
|
||||
type->unresolved.module = func->name;
|
||||
type->unresolved.name = tok;
|
||||
func->func.struct_parent = type;
|
||||
func->func.struct_parent = TYPE_MODULE_UNRESOLVED(func->name, tok);;
|
||||
advance();
|
||||
EXPECT_OR(TOKEN_DOT, false);
|
||||
EXPECT_IDENT_FOR_OR("function name", false);
|
||||
@@ -2308,7 +2337,7 @@ static inline Decl *parse_error_declaration(Visibility visibility)
|
||||
|
||||
advance_and_verify(TOKEN_ERROR_TYPE);
|
||||
|
||||
Decl *error_decl = decl_new_self_type(current_context->module, tok, DECL_ERROR, TYPE_ERROR, visibility);
|
||||
Decl *error_decl = decl_new_user_defined_type(tok, DECL_ERROR, visibility);
|
||||
|
||||
if (!consume_type_name("error type")) return &poisoned_decl;
|
||||
|
||||
@@ -2316,7 +2345,9 @@ static inline Decl *parse_error_declaration(Visibility visibility)
|
||||
|
||||
while (tok.type == TOKEN_CONST_IDENT)
|
||||
{
|
||||
Decl *err_constant = decl_new_enum_const(error_decl, tok, DECL_ERROR_CONSTANT);
|
||||
Decl *err_constant = decl_new(DECL_ERROR_CONSTANT, tok, error_decl->visibility);
|
||||
|
||||
err_constant->error_constant.parent = error_decl;
|
||||
VECEACH(error_decl->error.error_constants, i)
|
||||
{
|
||||
Decl *other_constant = error_decl->error.error_constants[i];
|
||||
@@ -2357,7 +2388,7 @@ static inline Decl *parse_enum_declaration(Visibility visibility)
|
||||
|
||||
advance_and_verify(TOKEN_ENUM);
|
||||
|
||||
Decl *decl = decl_new_self_type(current_context->module, tok, DECL_ENUM, TYPE_ENUM, visibility);
|
||||
Decl *decl = decl_new_user_defined_type(tok, DECL_ENUM, visibility);
|
||||
|
||||
if (!consume_type_name("enum")) return &poisoned_decl;
|
||||
|
||||
@@ -2367,14 +2398,13 @@ static inline Decl *parse_enum_declaration(Visibility visibility)
|
||||
type = TRY_TYPE_OR(parse_base_type(), &poisoned_decl);
|
||||
}
|
||||
|
||||
decl->enums.type = type;
|
||||
|
||||
CONSUME_OR(TOKEN_LBRACE, false);
|
||||
|
||||
decl->enums.type = type ? type : &type_int;
|
||||
while (!try_consume(TOKEN_RBRACE))
|
||||
{
|
||||
Decl *enum_const = decl_new_enum_const(decl, tok, DECL_ENUM_CONSTANT);
|
||||
Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, tok, decl->visibility);
|
||||
enum_const->enum_constant.parent = decl;
|
||||
VECEACH(decl->enums.values, i)
|
||||
{
|
||||
Decl *other_constant = decl->enums.values[i];
|
||||
@@ -2392,7 +2422,7 @@ static inline Decl *parse_enum_declaration(Visibility visibility)
|
||||
}
|
||||
if (try_consume(TOKEN_EQ))
|
||||
{
|
||||
decl->enum_constant.expr = TRY_EXPR_OR(parse_expr(), &poisoned_decl);
|
||||
enum_const->enum_constant.expr = TRY_EXPR_OR(parse_expr(), &poisoned_decl);
|
||||
}
|
||||
decl->enums.values = VECADD(decl->enums.values, enum_const);
|
||||
// Allow trailing ','
|
||||
@@ -2443,7 +2473,7 @@ static inline bool parse_conditional_top_level(Decl ***decls)
|
||||
static inline Decl *parse_ct_if_top_level(void)
|
||||
{
|
||||
LOG_FUNC
|
||||
Decl *ct = decl_new_in_module(NULL, DECL_CT_IF, tok, VISIBLE_LOCAL);
|
||||
Decl *ct = decl_new(DECL_CT_IF, tok, VISIBLE_LOCAL);
|
||||
advance_and_verify(TOKEN_CT_IF);
|
||||
ct->ct_if_decl.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_decl);
|
||||
|
||||
@@ -2453,7 +2483,7 @@ static inline Decl *parse_ct_if_top_level(void)
|
||||
while (tok.type == TOKEN_CT_ELIF)
|
||||
{
|
||||
advance_and_verify(TOKEN_CT_ELIF);
|
||||
Decl *ct_elif = decl_new_in_module(NULL, DECL_CT_ELIF, tok, VISIBLE_LOCAL);
|
||||
Decl *ct_elif = decl_new(DECL_CT_ELIF, tok, VISIBLE_LOCAL);
|
||||
ct_elif->ct_elif_decl.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_decl);
|
||||
if (!parse_conditional_top_level(&ct_elif->ct_elif_decl.then)) return &poisoned_decl;
|
||||
ct_if_decl->elif = ct_elif;
|
||||
@@ -2462,7 +2492,7 @@ static inline Decl *parse_ct_if_top_level(void)
|
||||
if (tok.type == TOKEN_CT_ELSE)
|
||||
{
|
||||
advance_and_verify(TOKEN_CT_ELSE);
|
||||
Decl *ct_else = decl_new_in_module(NULL, DECL_CT_ELSE, tok, VISIBLE_LOCAL);
|
||||
Decl *ct_else = decl_new(DECL_CT_ELSE, tok, VISIBLE_LOCAL);
|
||||
ct_if_decl->elif = ct_else;
|
||||
if (!parse_conditional_top_level(&ct_else->ct_else_decl)) return &poisoned_decl;
|
||||
}
|
||||
@@ -2728,6 +2758,8 @@ static Expr *parse_string_literal(Expr *left)
|
||||
{
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, tok);
|
||||
expr_string->resolve_status = RESOLVE_DONE;
|
||||
expr_string->type = &type_string;
|
||||
advance_and_verify(TOKEN_STRING);
|
||||
|
||||
char *str = malloc_arena(tok.span.length + 1);
|
||||
@@ -2747,18 +2779,101 @@ static Expr *parse_string_literal(Expr *left)
|
||||
advance();
|
||||
}
|
||||
str[len] = '\0';
|
||||
expr_string->const_expr = value_new_string(str, (uint32_t)len);
|
||||
expr_string->const_expr.string.chars = str;
|
||||
expr_string->const_expr.string.len = len;
|
||||
expr_string->type = &type_string;
|
||||
expr_string->const_expr.type = CONST_STRING;
|
||||
return expr_string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Expr *parse_integer(Expr *left)
|
||||
{
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, tok);
|
||||
expr_int->const_expr = parse_int(tok.start, tok.span.length);
|
||||
const char *string = tok.start;
|
||||
const char *end = string + tok.span.length;
|
||||
uint64_t i = 0;
|
||||
switch (tok.span.length > 2 ? string[1] : '0')
|
||||
{
|
||||
case 'x':
|
||||
string += 2;
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
if (i > (UINT64_MAX >> 4u))
|
||||
{
|
||||
SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number.");
|
||||
return &poisoned_expr;
|
||||
}
|
||||
i <<= 4u;
|
||||
if (c < 'A')
|
||||
{
|
||||
i += c - '0';
|
||||
}
|
||||
else if (c < 'a')
|
||||
{
|
||||
i += c - 'A' + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
i += c - 'a' + 10;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
string += 2;
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
if (i > (UINT64_MAX >> 3u))
|
||||
{
|
||||
SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number.");
|
||||
return &poisoned_expr;
|
||||
}
|
||||
i <<= (unsigned) 3;
|
||||
i += c - '0';
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
string += 2;
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
if (i > (UINT64_MAX >> 1u))
|
||||
{
|
||||
SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number.");
|
||||
return &poisoned_expr;
|
||||
}
|
||||
i <<= (unsigned) 1;
|
||||
i += c - '0';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
if (i > (UINT64_MAX / 10))
|
||||
{
|
||||
SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number.");
|
||||
return &poisoned_expr;
|
||||
}
|
||||
i *= 10;
|
||||
i += c - '0';
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
expr_int->const_expr.i = i;
|
||||
expr_int->const_expr.type = CONST_INT;
|
||||
expr_int->type = i > INT64_MAX ? &type_compuint : &type_compint;
|
||||
expr_int->resolve_status = RESOLVE_DONE;
|
||||
advance();
|
||||
if (expr_int->const_expr.type == VALUE_TYPE_ERROR) return &poisoned_expr;
|
||||
return expr_int;
|
||||
}
|
||||
|
||||
@@ -2776,7 +2891,10 @@ static Expr *parse_double(Expr *left)
|
||||
return &poisoned_expr;
|
||||
}
|
||||
advance();
|
||||
number->const_expr = value_new_float(fval);
|
||||
number->const_expr.f = fval;
|
||||
number->type = &type_compfloat;
|
||||
number->const_expr.type = CONST_FLOAT;
|
||||
number->resolve_status = RESOLVE_DONE;
|
||||
return number;
|
||||
}
|
||||
|
||||
@@ -2784,7 +2902,9 @@ static Expr *parse_bool(Expr *left)
|
||||
{
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok);
|
||||
number->const_expr = (Value) { .b = tok.type == TOKEN_TRUE, .type = VALUE_TYPE_BOOL };
|
||||
number->const_expr = (ExprConst) { .b = tok.type == TOKEN_TRUE, .type = CONST_BOOL };
|
||||
number->type = &type_bool;
|
||||
number->resolve_status = RESOLVE_DONE;
|
||||
advance();
|
||||
return number;
|
||||
}
|
||||
@@ -2793,7 +2913,9 @@ static Expr *parse_nil(Expr *left)
|
||||
{
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok);
|
||||
number->const_expr = (Value) { .type = VALUE_TYPE_NIL };
|
||||
number->const_expr.type = CONST_NIL;
|
||||
number->type = type_get_canonical_ptr(&type_void);
|
||||
number->resolve_status = RESOLVE_DONE;
|
||||
advance();
|
||||
return number;
|
||||
}
|
||||
@@ -2876,9 +2998,7 @@ static Expr *parse_identifier(Expr *left)
|
||||
advance_and_verify(TOKEN_SCOPE);
|
||||
if (try_consume(TOKEN_TYPE_IDENT))
|
||||
{
|
||||
Type *type = type_new(TYPE_UNRESOLVED);
|
||||
type->unresolved.module = mod;
|
||||
type->unresolved.name = tok;
|
||||
Type *type = TYPE_MODULE_UNRESOLVED(mod, tok);
|
||||
if (tok.type == TOKEN_LBRACE)
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_STRUCT_VALUE, mod);
|
||||
@@ -2924,8 +3044,7 @@ static Expr *parse_identifier(Expr *left)
|
||||
static Expr *parse_type_identifier(Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Type *type = type_new(TYPE_UNRESOLVED);
|
||||
type->unresolved.name = tok;
|
||||
Type *type = TYPE_UNRESOLVED(tok);
|
||||
advance_and_verify(TOKEN_TYPE_IDENT);
|
||||
if (tok.type == TOKEN_LBRACE)
|
||||
{
|
||||
@@ -2949,6 +3068,19 @@ static Expr *parse_type_expr(Expr *left)
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_cast_expr(Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CAST, tok);
|
||||
advance_and_verify(TOKEN_CAST);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_expr);
|
||||
expr->type = TRY_TYPE_OR(parse_type_expression(), &poisoned_expr);
|
||||
CONSUME_OR(TOKEN_COMMA, &poisoned_expr);
|
||||
expr->expr_cast.expr = TRY_EXPR_OR(parse_expr(), &poisoned_expr);
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_QUESTION] = { NULL, parse_conditional_expr, PREC_CONDITIONAL },
|
||||
[TOKEN_ELVIS] = { NULL, parse_conditional_expr, PREC_CONDITIONAL },
|
||||
@@ -2956,6 +3088,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_MINUSMINUS] = { parse_unary_expr, parse_post_unary, PREC_CALL },
|
||||
[TOKEN_LPAREN] = { parse_grouping_expr, parse_call_expr, PREC_CALL },
|
||||
[TOKEN_TYPE] = { parse_type_expr, NULL, PREC_NONE },
|
||||
[TOKEN_CAST] = { parse_cast_expr, NULL, PREC_NONE },
|
||||
//[TOKEN_SIZEOF] = { parse_sizeof, NULL, PREC_NONE },
|
||||
[TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL },
|
||||
[TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_common.h"
|
||||
#include "tokens.h"
|
||||
|
||||
typedef enum _Precedence
|
||||
{
|
||||
PREC_NONE,
|
||||
PREC_ASSIGNMENT, // =, *=, /=, %=, ...
|
||||
PREC_CONDITIONAL, // ?:
|
||||
PREC_LOGICAL, // && ||
|
||||
PREC_RELATIONAL, // < > <= >= == !=
|
||||
PREC_ADDITIVE, // + -
|
||||
PREC_BIT, // ^ | &
|
||||
PREC_SHIFT, // << >> >>>
|
||||
PREC_MULTIPLICATIVE, // * / %
|
||||
PREC_UNARY, // ! - + ~ * & prefix ++/--
|
||||
PREC_CALL, // . () [] postfix ++/--
|
||||
} Precedence;
|
||||
|
||||
void parse_file(File *file);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_common.h"
|
||||
#include "ast.h"
|
||||
#include "context.h"
|
||||
|
||||
|
||||
void sema_init(File *file);
|
||||
void sema_analysis(Context *context);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,8 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include "compiler_internal.h"
|
||||
#include "../build/build_options.h"
|
||||
#include "source_file.h"
|
||||
#include "../utils/lib.h"
|
||||
#include "../utils/file_utils.h"
|
||||
#include "lexer.h"
|
||||
|
||||
static const size_t LEXER_FILES_START_CAPACITY = 128;
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "compiler_common.h"
|
||||
|
||||
File *source_file_load(const char *filename, bool *already_loaded);
|
||||
File *source_file_from_position(SourceLoc loc);
|
||||
@@ -2,14 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "symtab.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "../utils/errors.h"
|
||||
#include <assert.h>
|
||||
#include "../utils/lib.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "tokens.h"
|
||||
#include "compiler_internal.h"
|
||||
|
||||
#define TABLE_MAX_LOAD 0.75
|
||||
#define MAX_HASH_SIZE (1024 * 1024)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tokens.h"
|
||||
|
||||
void symtab_init(uint32_t max_size);
|
||||
const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
|
||||
|
||||
typedef struct _VoidEntry
|
||||
{
|
||||
const char *key;
|
||||
void *value;
|
||||
} SEntry;
|
||||
|
||||
typedef struct _STable
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
SEntry *entries;
|
||||
} STable;
|
||||
|
||||
void stable_init(STable *table, uint32_t initial_size);
|
||||
void *stable_set(STable *table, const char *key, void *value);
|
||||
void *stable_get(STable *table, const char *key);
|
||||
void *stable_delete(STable *table, const char *key);
|
||||
void stable_clear(STable *table);
|
||||
@@ -2,8 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "tokens.h"
|
||||
#include "../utils/errors.h"
|
||||
#include "compiler_internal.h"
|
||||
|
||||
const char *token_type_to_string(TokenType type)
|
||||
{
|
||||
@@ -271,6 +270,24 @@ const char *token_type_to_string(TokenType type)
|
||||
case TOKEN_HALF:
|
||||
return "half";
|
||||
|
||||
case TOKEN_C_SHORT:
|
||||
return "c_short";
|
||||
case TOKEN_C_INT:
|
||||
return "c_int";
|
||||
case TOKEN_C_LONG:
|
||||
return "c_long";
|
||||
case TOKEN_C_LONGLONG:
|
||||
return "c_longlong";
|
||||
case TOKEN_C_USHORT:
|
||||
return "c_ushort";
|
||||
case TOKEN_C_UINT:
|
||||
return "c_uint";
|
||||
case TOKEN_C_ULONG:
|
||||
return "c_ulong";
|
||||
case TOKEN_C_ULONGLONG:
|
||||
return "c_ulonglong";
|
||||
|
||||
|
||||
case TOKEN_DOCS_EOL:
|
||||
return "EOL";
|
||||
case TOKEN_DOCS_START:
|
||||
@@ -323,25 +340,6 @@ const char *token_type_to_string(TokenType type)
|
||||
|
||||
bool token_is_type(TokenType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TOKEN_VOID:
|
||||
case TOKEN_BYTE:
|
||||
case TOKEN_BOOL:
|
||||
case TOKEN_CHAR:
|
||||
case TOKEN_DOUBLE:
|
||||
case TOKEN_FLOAT:
|
||||
case TOKEN_INT:
|
||||
case TOKEN_ISIZE:
|
||||
case TOKEN_LONG:
|
||||
case TOKEN_SHORT:
|
||||
case TOKEN_UINT:
|
||||
case TOKEN_ULONG:
|
||||
case TOKEN_USHORT:
|
||||
case TOKEN_USIZE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return type >= TOKEN_VOID && type <= TOKEN_C_ULONGLONG;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum _TokenType
|
||||
{
|
||||
TOKEN_INVALID_TOKEN = 0,
|
||||
|
||||
// Single-character tokens.
|
||||
TOKEN_AMP, // &
|
||||
TOKEN_AT, // @
|
||||
TOKEN_BIT_NOT, // ~
|
||||
TOKEN_BIT_OR, // =
|
||||
TOKEN_BIT_XOR, // ^
|
||||
TOKEN_COLON, // :
|
||||
TOKEN_COMMA, // ,
|
||||
TOKEN_EOS, // ;
|
||||
TOKEN_EQ, // =
|
||||
TOKEN_GREATER, // >
|
||||
TOKEN_DIV, // /
|
||||
TOKEN_DOLLAR, // $
|
||||
TOKEN_DOT, // .
|
||||
TOKEN_HASH, // #
|
||||
TOKEN_LESS, // <
|
||||
TOKEN_LBRACE, // {
|
||||
TOKEN_LBRACKET, // [
|
||||
TOKEN_LPAREN, // (
|
||||
TOKEN_MINUS, // -
|
||||
TOKEN_MOD, // %
|
||||
TOKEN_NOT, // !
|
||||
TOKEN_OR, // |
|
||||
TOKEN_PLUS, // +
|
||||
TOKEN_QUESTION, // ?
|
||||
TOKEN_RBRACE, // }
|
||||
TOKEN_RBRACKET, // ]
|
||||
TOKEN_RPAREN, // )
|
||||
TOKEN_STAR, // *
|
||||
|
||||
// two character tokens.
|
||||
TOKEN_AND, // &&
|
||||
TOKEN_ARROW, // -> // Not used but reserved
|
||||
TOKEN_BIT_AND_ASSIGN, // &=
|
||||
TOKEN_BIT_OR_ASSIGN, // |=
|
||||
TOKEN_BIT_XOR_ASSIGN, // ^=
|
||||
TOKEN_DIV_ASSIGN, // /=
|
||||
TOKEN_DOTDOT, // ..
|
||||
TOKEN_ELVIS, // ?:
|
||||
TOKEN_EQEQ, // ==
|
||||
TOKEN_GREATER_EQ, // >=
|
||||
TOKEN_LESS_EQ, // <=
|
||||
TOKEN_MINUS_ASSIGN, // -=
|
||||
TOKEN_MINUSMINUS, // --
|
||||
TOKEN_MOD_ASSIGN, // %=
|
||||
TOKEN_MULT_ASSIGN, // *=
|
||||
TOKEN_NOT_EQUAL, // !=
|
||||
TOKEN_PLUS_ASSIGN, // +=
|
||||
TOKEN_PLUSPLUS, // ++
|
||||
TOKEN_SCOPE, // ::
|
||||
TOKEN_SHR, // >>
|
||||
TOKEN_SHL, // >>
|
||||
|
||||
// Three or more
|
||||
TOKEN_AND_ASSIGN, // &&=
|
||||
TOKEN_ELIPSIS, // ...
|
||||
TOKEN_OR_ASSIGN, // ||=
|
||||
TOKEN_SHR_ASSIGN, // >>=
|
||||
TOKEN_SHL_ASSIGN, // >>=
|
||||
|
||||
|
||||
// Basic types names
|
||||
TOKEN_VOID,
|
||||
TOKEN_BYTE,
|
||||
TOKEN_BOOL,
|
||||
TOKEN_CHAR,
|
||||
TOKEN_DOUBLE,
|
||||
TOKEN_FLOAT,
|
||||
TOKEN_HALF,
|
||||
TOKEN_INT,
|
||||
TOKEN_ISIZE,
|
||||
TOKEN_LONG,
|
||||
TOKEN_SHORT,
|
||||
TOKEN_UINT,
|
||||
TOKEN_ULONG,
|
||||
TOKEN_USHORT,
|
||||
TOKEN_USIZE,
|
||||
TOKEN_QUAD,
|
||||
|
||||
// Literals.
|
||||
|
||||
|
||||
TOKEN_IDENT, // Any normal ident.
|
||||
TOKEN_CONST_IDENT, // Any purely upper case ident,
|
||||
TOKEN_TYPE_IDENT, // Any ident on the format FooBar or __FooBar
|
||||
|
||||
// We want to parse @foo / #foo / $foo separately.
|
||||
// Otherwise we allow things like "@ foo" which would be pretty bad.
|
||||
TOKEN_AT_IDENT, // @foobar
|
||||
TOKEN_HASH_IDENT, // #foobar
|
||||
TOKEN_CT_IDENT, // $foobar
|
||||
|
||||
TOKEN_STRING, // "Teststring"
|
||||
TOKEN_INTEGER, // 123 0x23 0b10010 0o327
|
||||
TOKEN_REAL, // 0x23.2p-2a 43.23e23
|
||||
|
||||
// Keywords
|
||||
TOKEN_ALIAS, // Reserved
|
||||
TOKEN_AS,
|
||||
TOKEN_ASM,
|
||||
TOKEN_ATTRIBUTE,
|
||||
TOKEN_BREAK,
|
||||
TOKEN_CASE,
|
||||
TOKEN_CAST,
|
||||
TOKEN_CATCH,
|
||||
TOKEN_CONST,
|
||||
TOKEN_CONTINUE,
|
||||
TOKEN_DEFAULT,
|
||||
TOKEN_DEFER,
|
||||
TOKEN_DO,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_ENUM,
|
||||
TOKEN_ERROR_TYPE,
|
||||
TOKEN_FALSE,
|
||||
TOKEN_FOR,
|
||||
TOKEN_FUNC,
|
||||
TOKEN_GENERIC,
|
||||
TOKEN_GOTO,
|
||||
TOKEN_IF,
|
||||
TOKEN_IMPORT,
|
||||
TOKEN_LOCAL,
|
||||
TOKEN_MACRO,
|
||||
TOKEN_MODULE,
|
||||
TOKEN_NEXT,
|
||||
TOKEN_NIL,
|
||||
TOKEN_PUBLIC,
|
||||
TOKEN_RETURN,
|
||||
TOKEN_STRUCT,
|
||||
TOKEN_SWITCH,
|
||||
TOKEN_THROW,
|
||||
TOKEN_THROWS,
|
||||
TOKEN_TRUE,
|
||||
TOKEN_TRY,
|
||||
TOKEN_TYPE, // Reserved
|
||||
TOKEN_TYPEDEF,
|
||||
TOKEN_UNION,
|
||||
TOKEN_UNTIL,
|
||||
TOKEN_VAR, // Reserved
|
||||
TOKEN_VOLATILE,
|
||||
TOKEN_WHILE,
|
||||
|
||||
TOKEN_AT_PARAM, // @param
|
||||
TOKEN_AT_THROWS, // @throws
|
||||
TOKEN_AT_RETURN, // @return
|
||||
TOKEN_AT_ENSURE, // @ensure
|
||||
TOKEN_AT_REQUIRE, // @require
|
||||
TOKEN_AT_PURE, // @pure
|
||||
TOKEN_AT_CONST, // @const
|
||||
TOKEN_AT_REQPARSE, // @reqparse
|
||||
TOKEN_AT_DEPRECATED, // @deprecated
|
||||
|
||||
TOKEN_CT_CASE, // $case
|
||||
TOKEN_CT_DEFAULT, // $default
|
||||
TOKEN_CT_EACH, // $each
|
||||
TOKEN_CT_ELIF, // $elif
|
||||
TOKEN_CT_ELSE, // $else
|
||||
TOKEN_CT_IF, // $if
|
||||
TOKEN_CT_SWITCH, // $switch
|
||||
|
||||
TOKEN_DOCS_START, // /**
|
||||
TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*`
|
||||
TOKEN_DOCS_EOL, // "\n" only seen in docs.
|
||||
TOKEN_DOCS_LINE, // Any line within /** **/
|
||||
|
||||
TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN.
|
||||
|
||||
} TokenType;
|
||||
|
||||
bool token_is_type(TokenType type);
|
||||
|
||||
const char *token_type_to_string(TokenType type);
|
||||
static inline const char* struct_union_name_from_token(TokenType type)
|
||||
{
|
||||
return type == TOKEN_STRUCT ? "struct" : "union";
|
||||
}
|
||||
224
src/compiler/types.c
Normal file
224
src/compiler/types.c
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_internal.h"
|
||||
|
||||
Type type_bool;
|
||||
Type type_void, type_string;
|
||||
|
||||
Type type_half, type_float, type_double, type_quad;
|
||||
Type type_char, type_short, type_int, type_long, type_isize;
|
||||
Type type_byte, type_ushort, type_uint, type_ulong, type_usize;
|
||||
Type type_compint, type_compuint, type_compfloat;
|
||||
Type type_c_short, type_c_int, type_c_long, type_c_longlong;
|
||||
Type type_c_ushort, type_c_uint, type_c_ulong, type_c_ulonglong;
|
||||
|
||||
Type *type_signed_int_by_size(int bitsize)
|
||||
{
|
||||
switch (bitsize)
|
||||
{
|
||||
case 1: return &type_char;
|
||||
case 2: return &type_short;
|
||||
case 4: return &type_int;
|
||||
case 8: return &type_long;
|
||||
default: FATAL_ERROR("Illegal bitsize %d", bitsize);
|
||||
}
|
||||
}
|
||||
Type *type_unsigned_int_by_size(int bitsize)
|
||||
{
|
||||
switch (bitsize)
|
||||
{
|
||||
case 1: return &type_byte;
|
||||
case 2: return &type_ushort;
|
||||
case 4: return &type_uint;
|
||||
case 8: return &type_ulong;
|
||||
default: FATAL_ERROR("Illegal bitsize %d", bitsize);
|
||||
}
|
||||
}
|
||||
|
||||
Type *type_new(TypeKind type_kind)
|
||||
{
|
||||
Type *type = malloc_arena(sizeof(Type));
|
||||
memset(type, 0, sizeof(Type));
|
||||
type->type_kind = type_kind;
|
||||
return type;
|
||||
}
|
||||
|
||||
size_t type_size(Type *canonical)
|
||||
{
|
||||
assert(canonical && canonical->canonical == canonical);
|
||||
switch (canonical->type_kind)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
case TYPE_INC_ARRAY:
|
||||
case TYPE_EXPRESSION:
|
||||
UNREACHABLE;
|
||||
case TYPE_USER_DEFINED:
|
||||
TODO
|
||||
case TYPE_VOID:
|
||||
return 1;
|
||||
case TYPE_BOOL:
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
return canonical->builtin.bytesize;
|
||||
case TYPE_IXX:
|
||||
case TYPE_UXX:
|
||||
case TYPE_FXX:
|
||||
return 8;
|
||||
case TYPE_POINTER:
|
||||
case TYPE_VARARRAY:
|
||||
case TYPE_STRING:
|
||||
return type_isize.canonical->builtin.bytesize;
|
||||
case TYPE_ARRAY:
|
||||
return type_size(canonical->base) * canonical->len;
|
||||
}
|
||||
TODO
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Type *canonical_base = ptr_type->base->canonical;
|
||||
|
||||
assert(canonical_base);
|
||||
|
||||
if (!canonical_base->ptr_like_canonical)
|
||||
{
|
||||
create_ptr_live_canonical(canonical_base);
|
||||
}
|
||||
|
||||
Type *canonical_ptr = canonical_base->ptr_like_canonical[(int)ptr_type->nullable];
|
||||
if (canonical_ptr == NULL)
|
||||
{
|
||||
canonical_ptr = malloc_arena(sizeof(Type));
|
||||
*canonical_ptr = *ptr_type;
|
||||
canonical_ptr->base = canonical_base;
|
||||
canonical_base->ptr_like_canonical[(int)ptr_type->nullable] = canonical_ptr;
|
||||
canonical_base->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
|
||||
return canonical_ptr;
|
||||
}
|
||||
|
||||
Type *type_get_canonical_array(Type *arr_type)
|
||||
{
|
||||
Type *canonical_base = arr_type->base->canonical;
|
||||
if (!arr_type->ptr_like_canonical)
|
||||
{
|
||||
create_ptr_live_canonical(canonical_base);
|
||||
}
|
||||
|
||||
// Dynamic array
|
||||
if (arr_type->len == 0)
|
||||
{
|
||||
Type *canonical = canonical_base->ptr_like_canonical[2];
|
||||
if (canonical == NULL)
|
||||
{
|
||||
canonical = malloc_arena(sizeof(Type));
|
||||
*canonical = *arr_type;
|
||||
canonical->canonical = canonical_base;
|
||||
canonical_base->ptr_like_canonical[2] = 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++)
|
||||
{
|
||||
Type *ptr = canonical_base->ptr_like_canonical[i];
|
||||
if (ptr->len == arr_type->len)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
Type *canonical = malloc_arena(sizeof(Type));
|
||||
*canonical = *arr_type;
|
||||
canonical->base = canonical_base;
|
||||
canonical->resolve_status = RESOLVE_DONE;
|
||||
canonical_base->ptr_like_canonical = VECADD(canonical_base->ptr_like_canonical, canonical);
|
||||
return canonical;
|
||||
}
|
||||
|
||||
static void create_type(const char *name, Type *location, TypeKind kind, unsigned bytesize, unsigned bitsize)
|
||||
{
|
||||
*location = (Type) { .type_kind = kind, .resolve_status = RESOLVE_DONE, .builtin.bytesize = bytesize, .builtin.bitsize = bitsize };
|
||||
location->name_loc.string = name;
|
||||
location->name_loc.span.length = strlen(name);
|
||||
location->canonical = location;
|
||||
}
|
||||
|
||||
static void type_create_alias(const char *name, Type *location, Type *canonical)
|
||||
{
|
||||
*location = (Type) { .type_kind = TYPE_USER_DEFINED, .resolve_status = RESOLVE_DONE };
|
||||
location->name_loc.string = name;
|
||||
location->name_loc.span.length = strlen(name);
|
||||
location->canonical = canonical;
|
||||
}
|
||||
|
||||
|
||||
void builtin_setup()
|
||||
{
|
||||
create_type("void", &type_void, TYPE_VOID, 1, 8);
|
||||
|
||||
/*TODO
|
||||
* decl_string = (Decl) { .decl_kind = DECL_BUILTIN, .name.string = "string" };
|
||||
create_type(&decl_string, &type_string);
|
||||
type_string.type_kind = TYPE_STRING;
|
||||
*/
|
||||
#define DEF_TYPE(_name, _type, _bits) \
|
||||
create_type(#_name, &type_ ## _name, _type, (_bits + 7) / 8, _bits);
|
||||
|
||||
DEF_TYPE(compint, TYPE_IXX, 64);
|
||||
DEF_TYPE(compuint, TYPE_UXX, 64);
|
||||
DEF_TYPE(compfloat, TYPE_FXX, 64);
|
||||
DEF_TYPE(bool, TYPE_BOOL, 1);
|
||||
|
||||
// DEF_TYPE(half, 2, 16, NUMBER_TYPE_FLOAT, "half", T_F16);
|
||||
DEF_TYPE(float, TYPE_F32, 32);
|
||||
DEF_TYPE(double, TYPE_F64, 64);
|
||||
// DEF_TYPE(quad, 16, 128, NUMBER_TYPE_FLOAT, "long double", T_F128);
|
||||
|
||||
DEF_TYPE(char, TYPE_I8, 8);
|
||||
DEF_TYPE(short, TYPE_I16, 16);
|
||||
DEF_TYPE(int, TYPE_I32, 32);
|
||||
DEF_TYPE(long, TYPE_I64, 64);
|
||||
|
||||
DEF_TYPE(byte, TYPE_U8, 8);
|
||||
DEF_TYPE(ushort, TYPE_U16, 16);
|
||||
DEF_TYPE(uint, TYPE_U32, 32);
|
||||
DEF_TYPE(ulong, TYPE_U64, 64);
|
||||
|
||||
type_create_alias("usize", &type_usize, type_unsigned_int_by_size(build_options.pointer_size));
|
||||
type_create_alias("isize", &type_isize, type_signed_int_by_size(build_options.pointer_size));
|
||||
|
||||
type_create_alias("c_ushort", &type_c_ushort, type_unsigned_int_by_size(build_options.cshort_size));
|
||||
type_create_alias("c_uint", &type_c_uint, type_unsigned_int_by_size(build_options.cint_size));
|
||||
type_create_alias("c_ulong", &type_c_ulong, type_unsigned_int_by_size(build_options.clong_size));
|
||||
type_create_alias("c_ulonglong", &type_c_ulonglong, type_unsigned_int_by_size(build_options.clonglong_size));
|
||||
|
||||
type_create_alias("c_short", &type_c_short, type_signed_int_by_size(build_options.cshort_size));
|
||||
type_create_alias("c_int", &type_c_int, type_signed_int_by_size(build_options.cint_size));
|
||||
type_create_alias("c_long", &type_c_long, type_signed_int_by_size(build_options.clong_size));
|
||||
type_create_alias("c_longlong", &type_c_longlong, type_signed_int_by_size(build_options.clonglong_size));
|
||||
|
||||
|
||||
#undef DEF_TYPE
|
||||
|
||||
}
|
||||
@@ -1,902 +0,0 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "value.h"
|
||||
#include "ast.h"
|
||||
|
||||
|
||||
#define ERROR_VALUE (Value) { .type = VALUE_TYPE_ERROR }
|
||||
|
||||
|
||||
Value value_new_int_with_bigint(BigInt big_int)
|
||||
{
|
||||
return (Value) { .big_int = big_int, .type = VALUE_TYPE_INT };
|
||||
}
|
||||
|
||||
Value value_new_float(long double f)
|
||||
{
|
||||
return (Value) { .f = f, .type = VALUE_TYPE_FLOAT };
|
||||
}
|
||||
Value value_new_int_with_int(int64_t val)
|
||||
{
|
||||
Value value = { .type = VALUE_TYPE_INT };
|
||||
bigint_init_signed(&value.big_int, val);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
Value value_nil()
|
||||
{
|
||||
return (Value) { .b = false, .type = VALUE_TYPE_NIL };
|
||||
}
|
||||
|
||||
Value value_not(Value value)
|
||||
{
|
||||
switch (value.type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
return (Value) { .b = value.f == 0.0, .type = VALUE_TYPE_BOOL };
|
||||
case VALUE_TYPE_INT:
|
||||
return (Value) { .b = bigint_cmp_zero(&value.big_int) == CMP_EQ, .type = VALUE_TYPE_BOOL };
|
||||
case VALUE_TYPE_BOOL:
|
||||
return (Value) { .b = !value.b, .type = VALUE_TYPE_BOOL };
|
||||
case VALUE_TYPE_NIL:
|
||||
return value_new_bool(true);
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
break;
|
||||
}
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
#define BIN_OP(_x, _intop, _floatop) \
|
||||
Value value_## _x(Value lhs, Value rhs) { \
|
||||
assert(lhs.type == rhs.type); \
|
||||
switch (lhs.type)\
|
||||
{ \
|
||||
case VALUE_TYPE_FLOAT: \
|
||||
return (Value) { .f = lhs.f _floatop rhs.f, .type = VALUE_TYPE_FLOAT }; \
|
||||
case VALUE_TYPE_INT: {\
|
||||
Value value = value_new_int_with_int(0);\
|
||||
_intop(&value.big_int, &lhs.big_int, &rhs.big_int); \
|
||||
return value;\
|
||||
}\
|
||||
case VALUE_TYPE_BOOL:\
|
||||
case VALUE_TYPE_STRING:\
|
||||
case VALUE_TYPE_NIL:\
|
||||
case VALUE_TYPE_ERROR:\
|
||||
return ERROR_VALUE;\
|
||||
}\
|
||||
}
|
||||
|
||||
#define BIN_OP_W(_x, _intop, _intopwrap, _floatop) \
|
||||
Value value_## _x(Value lhs, Value rhs) { \
|
||||
assert(lhs.type == rhs.type); \
|
||||
switch (lhs.type)\
|
||||
{ \
|
||||
case VALUE_TYPE_FLOAT: \
|
||||
return (Value) { .f = lhs.f _floatop rhs.f, .type = VALUE_TYPE_FLOAT }; \
|
||||
case VALUE_TYPE_INT: {\
|
||||
Value value = value_new_int_with_int(0);\
|
||||
if (lhs.int_bits > 0) { \
|
||||
value.int_bits = lhs.int_bits; value.is_unsigned = lhs.is_unsigned; \
|
||||
_intopwrap(&value.big_int, &lhs.big_int, &rhs.big_int, lhs.int_bits, !lhs.is_unsigned); \
|
||||
} else { \
|
||||
_intop(&value.big_int, &lhs.big_int, &rhs.big_int); \
|
||||
};\
|
||||
return value;\
|
||||
}\
|
||||
case VALUE_TYPE_BOOL:\
|
||||
case VALUE_TYPE_STRING:\
|
||||
case VALUE_TYPE_NIL:\
|
||||
case VALUE_TYPE_ERROR:\
|
||||
return ERROR_VALUE;\
|
||||
}\
|
||||
}
|
||||
|
||||
BIN_OP_W(add, bigint_add, bigint_add_wrap, +)
|
||||
BIN_OP_W(mult, bigint_mul, bigint_mul_wrap, *)
|
||||
BIN_OP(div, bigint_div_floor, /)
|
||||
BIN_OP(mod, bigint_mod, /)
|
||||
|
||||
Value value_sub(Value value1, Value value2)
|
||||
{
|
||||
return value_add(value1, value_negate(value2));
|
||||
}
|
||||
|
||||
Value value_and(Value value1, Value value2)
|
||||
{
|
||||
if (value1.type == VALUE_TYPE_BOOL && value2.type == VALUE_TYPE_BOOL)
|
||||
{
|
||||
value1.b = value1.b && value2.b;
|
||||
return value1;
|
||||
}
|
||||
|
||||
assert(value1.type == VALUE_TYPE_INT && value2.type == VALUE_TYPE_INT);
|
||||
assert(value1.int_bits == value2.int_bits);
|
||||
BigInt res;
|
||||
bigint_and(&res, &value1.big_int, &value2.big_int);
|
||||
value1.big_int = res;
|
||||
return value1;
|
||||
}
|
||||
|
||||
Value value_or(Value value1, Value value2)
|
||||
{
|
||||
if (value1.type == VALUE_TYPE_BOOL && value2.type == VALUE_TYPE_BOOL)
|
||||
{
|
||||
value1.b = value1.b || value2.b;
|
||||
return value1;
|
||||
}
|
||||
assert(value1.type == VALUE_TYPE_INT && value2.type == VALUE_TYPE_INT);
|
||||
assert(value1.int_bits == value2.int_bits);
|
||||
BigInt res;
|
||||
bigint_or(&res, &value1.big_int, &value2.big_int);
|
||||
value1.big_int = res;
|
||||
return value1;
|
||||
}
|
||||
|
||||
static inline CmpRes cmp(Value value1, Value value2)
|
||||
{
|
||||
switch (value1.type)
|
||||
{
|
||||
case VALUE_TYPE_BOOL:
|
||||
if (value1.b < value2.b) return CMP_LT;
|
||||
return value1.b == value2.b ? CMP_EQ : CMP_GT;
|
||||
case VALUE_TYPE_INT:
|
||||
return bigint_cmp(&value1.big_int, &value2.big_int);
|
||||
case VALUE_TYPE_FLOAT:
|
||||
if (value1.f < value2.b) return CMP_LT;
|
||||
return value2.f > value2.f ? CMP_GT : CMP_EQ;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
bool value_le(Value value1, Value value2)
|
||||
{
|
||||
CmpRes res = cmp(value1, value2);
|
||||
return res != CMP_GT;
|
||||
}
|
||||
|
||||
bool value_ge(Value value1, Value value2)
|
||||
{
|
||||
CmpRes res = cmp(value1, value2);
|
||||
return res != CMP_LT;
|
||||
}
|
||||
|
||||
bool value_gt(Value value1, Value value2)
|
||||
{
|
||||
CmpRes res = cmp(value1, value2);
|
||||
return res == CMP_GT;
|
||||
}
|
||||
|
||||
bool value_lt(Value value1, Value value2)
|
||||
{
|
||||
CmpRes res = cmp(value1, value2);
|
||||
return res == CMP_LT;
|
||||
}
|
||||
|
||||
bool value_eq(Value value1, Value value2)
|
||||
{
|
||||
CmpRes res = cmp(value1, value2);
|
||||
return res == CMP_EQ;
|
||||
}
|
||||
|
||||
bool value_ne(Value value1, Value value2)
|
||||
{
|
||||
CmpRes res = cmp(value1, value2);
|
||||
return res != CMP_EQ;
|
||||
}
|
||||
|
||||
Value value_xor(Value value1, Value value2)
|
||||
{
|
||||
if (value1.type == VALUE_TYPE_BOOL && value2.type == VALUE_TYPE_BOOL)
|
||||
{
|
||||
value1.b = value1.b ^ value2.b;
|
||||
return value1;
|
||||
}
|
||||
assert(value1.type == VALUE_TYPE_INT && value2.type == VALUE_TYPE_INT);
|
||||
assert(value1.int_bits == value2.int_bits);
|
||||
BigInt res;
|
||||
bigint_xor(&res, &value1.big_int, &value2.big_int);
|
||||
value1.big_int = res;
|
||||
return value1;
|
||||
}
|
||||
|
||||
Value value_negate(Value value)
|
||||
{
|
||||
switch (value.type)
|
||||
{
|
||||
case VALUE_TYPE_INT:
|
||||
{
|
||||
Value result = value_new_int_with_int(0);
|
||||
result.is_unsigned = value.is_unsigned;
|
||||
result.int_bits = value.int_bits;
|
||||
if (value.int_bits)
|
||||
{
|
||||
bigint_negate_wrap(&result.big_int, &value.big_int, value.int_bits);
|
||||
}
|
||||
else
|
||||
{
|
||||
bigint_negate(&result.big_int, &value.big_int);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case VALUE_TYPE_BOOL:
|
||||
return value_new_int_with_int(value.b ? -1 : 0);
|
||||
case VALUE_TYPE_FLOAT:
|
||||
return value_new_float(-value.f);
|
||||
case VALUE_TYPE_NIL:
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
break;
|
||||
}
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
Value value_bit_not(Value value)
|
||||
{
|
||||
switch (value.type)
|
||||
{
|
||||
case VALUE_TYPE_INT:
|
||||
{
|
||||
value_print(value);
|
||||
printf("--%d--\n", value.is_unsigned);
|
||||
Value result = value_new_int_with_int(0);
|
||||
result.is_unsigned = value.is_unsigned;
|
||||
result.int_bits = value.int_bits;
|
||||
if (!value.int_bits)
|
||||
{
|
||||
FATAL_ERROR("Not supported");
|
||||
}
|
||||
bigint_not(&result.big_int, &value.big_int, value.int_bits, !value.is_unsigned);
|
||||
value_print(result);
|
||||
printf("--%d--\n", result.is_unsigned);
|
||||
return result;
|
||||
}
|
||||
case VALUE_TYPE_BOOL:
|
||||
return value_new_int_with_int(value.b ? 0 : 1);
|
||||
case VALUE_TYPE_FLOAT:
|
||||
case VALUE_TYPE_NIL:
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
break;
|
||||
}
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
inline Value value_new_bool(bool value)
|
||||
{
|
||||
return (Value) { .b = value, .type = VALUE_TYPE_BOOL };
|
||||
}
|
||||
|
||||
Value value_new_string(const char *string, uint32_t len)
|
||||
{
|
||||
return (Value) { .str = string, .str_len = len, .type = VALUE_TYPE_STRING };
|
||||
}
|
||||
|
||||
bool value_as_bool(Value *value)
|
||||
{
|
||||
switch (value->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
return value->f != 0.0;
|
||||
case VALUE_TYPE_INT:
|
||||
return bigint_cmp_zero(&value->big_int) != CMP_EQ;
|
||||
case VALUE_TYPE_BOOL:
|
||||
return value->b;
|
||||
case VALUE_TYPE_NIL:
|
||||
return false;
|
||||
case VALUE_TYPE_STRING:
|
||||
return true;
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Value value_to_bool(Value value)
|
||||
{
|
||||
switch (value.type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
return value_new_bool(value.f != 0.0);
|
||||
case VALUE_TYPE_INT:
|
||||
return value_new_bool(bigint_cmp_zero(&value.big_int) != CMP_EQ);
|
||||
case VALUE_TYPE_BOOL:
|
||||
return value;
|
||||
case VALUE_TYPE_NIL:
|
||||
return value_new_bool(false);
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
break;
|
||||
}
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
Value value_float(Value value)
|
||||
{
|
||||
switch (value.type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
return value_new_bool(value.f != 0.0);
|
||||
case VALUE_TYPE_INT:
|
||||
return value_new_bool(bigint_cmp_zero(&value.big_int) != CMP_EQ);
|
||||
case VALUE_TYPE_BOOL:
|
||||
return value;
|
||||
case VALUE_TYPE_NIL:
|
||||
return value_new_bool(false);
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
break;
|
||||
}
|
||||
return ERROR_VALUE;
|
||||
}
|
||||
|
||||
const char *value_type_name(const Value *value)
|
||||
{
|
||||
switch (value->type)
|
||||
{
|
||||
case VALUE_TYPE_BOOL:
|
||||
return "bool";
|
||||
case VALUE_TYPE_NIL:
|
||||
return "nil";
|
||||
case VALUE_TYPE_FLOAT:
|
||||
switch (value->float_bits)
|
||||
{
|
||||
case 0: return "float";
|
||||
case 16: return "f16";
|
||||
case 32: return "f32";
|
||||
case 64: return "f64";
|
||||
case 128: return "f128";
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
case VALUE_TYPE_STRING:
|
||||
return "string";
|
||||
case VALUE_TYPE_INT:
|
||||
switch (value->int_bits)
|
||||
{
|
||||
case 0: return "int";
|
||||
case 8: return value->is_unsigned ? "u8" : "i8";
|
||||
case 16: return value->is_unsigned ? "u16" : "i16";
|
||||
case 32: return value->is_unsigned ? "u32" : "i32";
|
||||
case 64: return value->is_unsigned ? "u64" : "i64";
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
case VALUE_TYPE_ERROR:
|
||||
return "<error>";
|
||||
}
|
||||
FATAL_ERROR("Can't happen");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool value_is_number(const Value *value)
|
||||
{
|
||||
return value->type == VALUE_TYPE_INT || value->type == VALUE_TYPE_FLOAT;
|
||||
}
|
||||
|
||||
Type *value_find_type(const Value *value)
|
||||
{
|
||||
switch (value->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
switch (value->float_bits)
|
||||
{
|
||||
case 0: return &type_compfloat;
|
||||
case 16: return &type_half;
|
||||
case 32: return &type_float;
|
||||
case 64: return &type_double;
|
||||
// case 128: return type_builtin_f128();
|
||||
default: break;
|
||||
}
|
||||
UNREACHABLE
|
||||
case VALUE_TYPE_INT:
|
||||
switch (value->int_bits)
|
||||
{
|
||||
case 0: return &type_compint;
|
||||
case 8: return value->is_unsigned ? &type_byte : &type_char;
|
||||
case 16: return value->is_unsigned ? &type_ushort : &type_short;
|
||||
case 32: return value->is_unsigned ? &type_uint : &type_int;
|
||||
case 64: return value->is_unsigned ? &type_ulong : &type_long;
|
||||
default: break;
|
||||
}
|
||||
UNREACHABLE
|
||||
case VALUE_TYPE_BOOL:
|
||||
return &type_bool;
|
||||
case VALUE_TYPE_NIL:
|
||||
return &type_nil;
|
||||
case VALUE_TYPE_STRING:
|
||||
return &type_string;
|
||||
case VALUE_TYPE_ERROR:
|
||||
return &poisoned_type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Assume well-formed hex!
|
||||
static inline Value parse_hex(const char *string, int len)
|
||||
{
|
||||
Value value = { .type = VALUE_TYPE_INT };
|
||||
BigInt *b = &value.big_int;
|
||||
bigint_init_signed(b, 0);
|
||||
const char *end = string + len;
|
||||
BigInt temp = { .digit_count = 0 };
|
||||
BigInt add = { .digit_count = 0 };
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
bigint_shl_int(&temp, b, 4);
|
||||
if (c < 'A')
|
||||
{
|
||||
bigint_init_signed(&add, (c - '0'));
|
||||
}
|
||||
else if (c < 'a')
|
||||
{
|
||||
bigint_init_signed(&add, (c - 'A' + 10));
|
||||
}
|
||||
else
|
||||
{
|
||||
bigint_init_signed(&add, (c - 'a' + 10));
|
||||
}
|
||||
bigint_add(b, &temp, &add);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline Value parse_dec(const char *string, int len)
|
||||
{
|
||||
Value value = { .type = VALUE_TYPE_INT };
|
||||
BigInt *b = &value.big_int;
|
||||
bigint_init_signed(b, 0);
|
||||
const char *end = string + len;
|
||||
BigInt temp = { .digit_count = 0 };
|
||||
BigInt mult;
|
||||
bigint_init_signed(&mult, 10);
|
||||
BigInt add = { .digit_count = 0 };
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
bigint_mul(&temp, b, &mult);
|
||||
bigint_init_signed(&add, (c - '0'));
|
||||
bigint_add(b, &temp, &add);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline Value parse_oct(const char *string, int len)
|
||||
{
|
||||
Value value = { .type = VALUE_TYPE_INT };
|
||||
BigInt *b = &value.big_int;
|
||||
bigint_init_signed(b, 0);
|
||||
const char *end = string + len;
|
||||
BigInt temp = { .digit_count = 0 };
|
||||
BigInt add = { .digit_count = 0 };
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
bigint_shl_int(&temp, b, 3);
|
||||
bigint_init_signed(&add, (c - '0'));
|
||||
bigint_add(b, &temp, &add);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline Value parse_bin(const char *string, int len)
|
||||
{
|
||||
Value value = { .type = VALUE_TYPE_INT };
|
||||
BigInt *b = &value.big_int;
|
||||
bigint_init_signed(b, 0);
|
||||
const char *end = string + len;
|
||||
BigInt temp = { .digit_count = 0 };
|
||||
BigInt add = { .digit_count = 0 };
|
||||
while (string < end)
|
||||
{
|
||||
char c = *(string++);
|
||||
if (c == '_') continue;
|
||||
bigint_shl_int(&temp, b, 1);
|
||||
bigint_init_signed(&add, (c - '0'));
|
||||
bigint_add(b, &temp, &add);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Parse normal integers, parse 0xBEEF, parse 0o1337, parse 0b1010101 – positive numbers only
|
||||
Value parse_int(const char *string, int len)
|
||||
{
|
||||
if (len > 2)
|
||||
{
|
||||
switch (string[1])
|
||||
{
|
||||
case 'x':
|
||||
return parse_hex(string + 2, (uint16_t) (len - 2));
|
||||
case 'o':
|
||||
return parse_oct(string + 2, (uint16_t) (len - 2));
|
||||
case 'b':
|
||||
return parse_bin(string + 2, (uint16_t) (len - 2));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parse_dec(string, (uint16_t) len);
|
||||
}
|
||||
|
||||
void value_print(Value value)
|
||||
{
|
||||
switch (value.type)
|
||||
{
|
||||
case VALUE_TYPE_BOOL:
|
||||
printf(value.b ? "true" : "false");
|
||||
break;
|
||||
case VALUE_TYPE_STRING:
|
||||
printf("%.*s", value.str_len, value.str);
|
||||
break;
|
||||
case VALUE_TYPE_INT:
|
||||
bigint_print(&value.big_int, 10);
|
||||
break;
|
||||
case VALUE_TYPE_ERROR:
|
||||
printf("ERROR");
|
||||
break;
|
||||
case VALUE_TYPE_FLOAT:
|
||||
printf("%Lf", value.f);
|
||||
break;
|
||||
case VALUE_TYPE_NIL:
|
||||
printf("nil");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void value_fprint(FILE *file, Value value)
|
||||
{
|
||||
switch (value.type)
|
||||
{
|
||||
case VALUE_TYPE_BOOL:
|
||||
fprintf(file, value.b ? "true" : "false");
|
||||
break;
|
||||
case VALUE_TYPE_STRING:
|
||||
fprintf(file, "%.*s", value.str_len, value.str);
|
||||
break;
|
||||
case VALUE_TYPE_INT:
|
||||
bigint_fprint(file, &value.big_int, 10);
|
||||
break;
|
||||
case VALUE_TYPE_ERROR:
|
||||
fprintf(file, "ERROR");
|
||||
break;
|
||||
case VALUE_TYPE_FLOAT:
|
||||
fprintf(file, "%Lf", value.f);
|
||||
break;
|
||||
case VALUE_TYPE_NIL:
|
||||
fprintf(file, "nil");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void value_update_to_float(Value *value, long double f, uint16_t bits)
|
||||
{
|
||||
value->f = f;
|
||||
value->type = VALUE_TYPE_FLOAT;
|
||||
value->float_bits = bits;
|
||||
}
|
||||
/**
|
||||
* Convert value2 to value1 (note that we have already ordered things in conversion order.
|
||||
*
|
||||
* @param value1
|
||||
* @param value2
|
||||
* @return true if conversion worked.
|
||||
*/
|
||||
static bool value_convert_to_type_ordered(Value *value1, Value *value2)
|
||||
{
|
||||
switch (value1->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
switch (value2->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
value1->float_bits = value2->float_bits;
|
||||
return true;
|
||||
case VALUE_TYPE_INT:
|
||||
value_update_to_float(value2, bigint_as_float(&value2->big_int), value1->float_bits);
|
||||
return true;
|
||||
case VALUE_TYPE_BOOL:
|
||||
value_update_to_float(value2, value2->b ? 1.0 : 0.0, value1->float_bits);
|
||||
return true;
|
||||
case VALUE_TYPE_NIL:
|
||||
value_update_to_float(value2, 0.0, value1->float_bits);
|
||||
return true;
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE
|
||||
case VALUE_TYPE_INT:
|
||||
switch (value2->type)
|
||||
{
|
||||
case VALUE_TYPE_INT:
|
||||
// First check if we have a comptime int. If so, check that it fits.
|
||||
if (value2->int_bits == 0)
|
||||
{
|
||||
if (value1->int_bits == 0) return true;
|
||||
if (!bigint_fits_in_bits(&value2->big_int, value1->int_bits, !value1->is_unsigned)) return false;
|
||||
BigInt res;
|
||||
bigint_truncate(&res, &value2->big_int, value1->int_bits, !value1->is_unsigned);
|
||||
value2->big_int = res;
|
||||
return true;
|
||||
}
|
||||
if (!value1->is_unsigned && value2->is_unsigned)
|
||||
{
|
||||
// If unsigned value is same or larger, disallow!
|
||||
if (value1->int_bits <= value2->int_bits) return false;
|
||||
|
||||
value2->is_unsigned = false;
|
||||
value2->int_bits = value1->int_bits;
|
||||
return true;
|
||||
}
|
||||
// Final case, both has same sign, promote to largest.
|
||||
value2->int_bits = value1->int_bits;
|
||||
return true;
|
||||
case VALUE_TYPE_BOOL:
|
||||
bigint_init_unsigned(&value2->big_int, value2->b ? 1 : 0);
|
||||
value2->int_bits = value1->int_bits;
|
||||
value2->is_unsigned = value1->is_unsigned;
|
||||
value2->type = VALUE_TYPE_INT;
|
||||
return true;
|
||||
case VALUE_TYPE_NIL:
|
||||
bigint_init_unsigned(&value2->big_int, 0);
|
||||
value2->int_bits = value1->int_bits;
|
||||
value2->is_unsigned = value1->is_unsigned;
|
||||
value2->type = VALUE_TYPE_INT;
|
||||
return true;
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
case VALUE_TYPE_FLOAT:
|
||||
UNREACHABLE;
|
||||
}
|
||||
UNREACHABLE;
|
||||
case VALUE_TYPE_BOOL:
|
||||
switch (value2->type)
|
||||
{
|
||||
case VALUE_TYPE_BOOL:
|
||||
return true;
|
||||
case VALUE_TYPE_NIL:
|
||||
value2->b = false;
|
||||
value2->type = VALUE_TYPE_BOOL;
|
||||
return true;
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
case VALUE_TYPE_FLOAT:
|
||||
case VALUE_TYPE_INT:
|
||||
UNREACHABLE;
|
||||
}
|
||||
UNREACHABLE;
|
||||
case VALUE_TYPE_NIL:
|
||||
switch (value2->type)
|
||||
{
|
||||
case VALUE_TYPE_NIL:
|
||||
return true;
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
case VALUE_TYPE_FLOAT:
|
||||
case VALUE_TYPE_BOOL:
|
||||
case VALUE_TYPE_INT:
|
||||
UNREACHABLE;
|
||||
}
|
||||
UNREACHABLE;
|
||||
case VALUE_TYPE_STRING:
|
||||
return value2->type == VALUE_TYPE_STRING;
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
bool value_convert_to_type(Value *value1, Value *value2)
|
||||
{
|
||||
bool reverse_order = false;
|
||||
if (value2->type == value1->type)
|
||||
{
|
||||
switch (value1->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
reverse_order = value2->float_bits > value1->float_bits;
|
||||
break;
|
||||
case VALUE_TYPE_INT:
|
||||
if (value1->is_unsigned != value2->is_unsigned)
|
||||
{
|
||||
reverse_order = value1->is_unsigned;
|
||||
break;
|
||||
}
|
||||
reverse_order = value2->int_bits > value1->int_bits;
|
||||
break;
|
||||
case VALUE_TYPE_BOOL:
|
||||
case VALUE_TYPE_NIL:
|
||||
case VALUE_TYPE_STRING:
|
||||
case VALUE_TYPE_ERROR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reverse_order = value2->type < value1->type;
|
||||
}
|
||||
return reverse_order ? value_convert_to_type_ordered(value2, value1) : value_convert_to_type_ordered(value1, value2);
|
||||
}
|
||||
|
||||
|
||||
static inline bool set_bits_and_truncate_int_value_if_needed(Value *value, uint16_t bits, bool allow_trunc)
|
||||
{
|
||||
value->int_bits = bits;
|
||||
|
||||
// No truncation
|
||||
if (bits == 0) return true;
|
||||
|
||||
// If it fits then we're fine.
|
||||
if (bigint_fits_in_bits(&value->big_int, bits, !value->is_unsigned))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we can truncate, do so.
|
||||
if (allow_trunc)
|
||||
{
|
||||
BigInt temp;
|
||||
bigint_truncate(&temp, &value->big_int, bits, !value->is_unsigned);
|
||||
value->big_int = temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise fail.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool value_int_change_sign(Value *value, bool is_unsigned, bool allow_trunc)
|
||||
{
|
||||
if (value->is_unsigned == is_unsigned) return true;
|
||||
if (value->is_unsigned)
|
||||
{
|
||||
value->is_unsigned = false;
|
||||
|
||||
// No bit limit? Goodie
|
||||
if (!value->int_bits) return true;
|
||||
|
||||
// If it fits, then we're golden.
|
||||
if (bigint_fits_in_bits(&value->big_int, value->int_bits, true)) return true;
|
||||
|
||||
// If not and we're not allowed conversion? Exit:
|
||||
if (!allow_trunc) return false;
|
||||
|
||||
BigInt temp;
|
||||
bigint_truncate(&temp, &value->big_int, value->int_bits, true);
|
||||
value->big_int = temp;
|
||||
// TODO verify that this actually works!
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Signed to unsigned
|
||||
value->is_unsigned = true;
|
||||
|
||||
// No bit limit? Goodie
|
||||
if (!value->int_bits) return true;
|
||||
|
||||
// If the value was positive we're golden
|
||||
if (!value->big_int.is_negative) return true;
|
||||
|
||||
// If not and we're not allowed conversion? Exit:
|
||||
if (!allow_trunc) return false;
|
||||
|
||||
BigInt temp;
|
||||
bigint_truncate(&temp, &value->big_int, value->int_bits, false);
|
||||
value->big_int = temp;
|
||||
// TODO verify that this actually works!
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool value_convert(Value *value, ValueType type, uint16_t bits, bool is_unsigned, bool allow_trunc)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
switch (value->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
// TODO actual truncation
|
||||
value->float_bits = bits;
|
||||
break;
|
||||
case VALUE_TYPE_INT:
|
||||
value->f = bigint_as_float(&value->big_int);
|
||||
break;
|
||||
case VALUE_TYPE_BOOL:
|
||||
value->f = value->b ? 1.0 : 0.0;
|
||||
break;
|
||||
case VALUE_TYPE_NIL:
|
||||
value->f = 0.0;
|
||||
break;
|
||||
case VALUE_TYPE_STRING:
|
||||
return false;
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
}
|
||||
value->float_bits = bits;
|
||||
value->type = VALUE_TYPE_FLOAT;
|
||||
return true;
|
||||
case VALUE_TYPE_INT:
|
||||
switch (value->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
if (value->f < 0 && is_unsigned)
|
||||
{
|
||||
if (!allow_trunc) return false;
|
||||
// First convert to signed, then convert to unsigned.
|
||||
bool success = value_convert(value, type, bits, false, true);
|
||||
assert(success && "Unexpected failure");
|
||||
return value_convert(value, type, bits, true, true);
|
||||
}
|
||||
// TODO actual expansion
|
||||
bigint_init_signed(&value->big_int, (int64_t)value->f);
|
||||
value->is_unsigned = is_unsigned;
|
||||
value->type = VALUE_TYPE_INT;
|
||||
return set_bits_and_truncate_int_value_if_needed(value, bits, allow_trunc);
|
||||
case VALUE_TYPE_INT:
|
||||
if (!value_int_change_sign(value, is_unsigned, allow_trunc)) return false;
|
||||
return set_bits_and_truncate_int_value_if_needed(value, bits, allow_trunc);
|
||||
case VALUE_TYPE_BOOL:
|
||||
value->type = VALUE_TYPE_INT;
|
||||
value->int_bits = bits;
|
||||
value->is_unsigned = is_unsigned;
|
||||
bigint_init_unsigned(&value->big_int, value->b ? 1 : 0);
|
||||
return true;
|
||||
case VALUE_TYPE_NIL:
|
||||
value->type = VALUE_TYPE_INT;
|
||||
value->int_bits = bits;
|
||||
value->is_unsigned = is_unsigned;
|
||||
bigint_init_unsigned(&value->big_int, 0);
|
||||
return true;
|
||||
case VALUE_TYPE_STRING:
|
||||
return false;
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE
|
||||
case VALUE_TYPE_BOOL:
|
||||
switch (value->type)
|
||||
{
|
||||
case VALUE_TYPE_FLOAT:
|
||||
if (!allow_trunc) return false;
|
||||
value->b = value->f != 0.0;
|
||||
break;
|
||||
case VALUE_TYPE_INT:
|
||||
value->b = value->big_int.digit_count != 0;
|
||||
break;
|
||||
case VALUE_TYPE_BOOL:
|
||||
return true;
|
||||
case VALUE_TYPE_NIL:
|
||||
value->b = false;
|
||||
break;
|
||||
case VALUE_TYPE_STRING:
|
||||
return false;
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
}
|
||||
value->type = VALUE_TYPE_BOOL;
|
||||
return true;
|
||||
case VALUE_TYPE_NIL:
|
||||
return value->type == VALUE_TYPE_NIL;
|
||||
case VALUE_TYPE_STRING:
|
||||
return value->type == VALUE_TYPE_STRING;
|
||||
case VALUE_TYPE_ERROR:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_common.h"
|
||||
#include "bigint.h"
|
||||
|
||||
// DO NOT CHANGE ORDER!
|
||||
typedef enum _ValueType
|
||||
{
|
||||
VALUE_TYPE_FLOAT,
|
||||
VALUE_TYPE_INT,
|
||||
VALUE_TYPE_BOOL,
|
||||
VALUE_TYPE_NIL,
|
||||
VALUE_TYPE_STRING,
|
||||
VALUE_TYPE_ERROR,
|
||||
} ValueType;
|
||||
|
||||
typedef struct _BigInt BigInt;
|
||||
|
||||
typedef struct _Value
|
||||
{
|
||||
ValueType type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
BigInt big_int;
|
||||
bool is_unsigned;
|
||||
uint16_t int_bits;
|
||||
};
|
||||
struct
|
||||
{
|
||||
long double f;
|
||||
uint16_t float_bits;
|
||||
};
|
||||
bool b;
|
||||
struct {
|
||||
const char *str;
|
||||
uint32_t str_len;
|
||||
};
|
||||
};
|
||||
uint32_t len;
|
||||
} Value;
|
||||
|
||||
|
||||
bool value_is_number(const Value *value);
|
||||
Value value_new_int_with_bigint(BigInt big_int);
|
||||
Value value_new_int_with_int(int64_t val);
|
||||
Value value_new_float(long double f);
|
||||
Value value_new_string(const char *string, uint32_t len);
|
||||
Value value_new_bool(bool value);
|
||||
Value value_to_bool(Value value);
|
||||
Value value_negate(Value value);
|
||||
Value value_bit_not(Value value);
|
||||
Value value_mult(Value lhs, Value rhs);
|
||||
Value value_sub(Value lhs, Value rhs);
|
||||
Value value_xor(Value lhs, Value rhs);
|
||||
bool value_ne(Value value1, Value value2);
|
||||
bool value_eq(Value value1, Value value2);
|
||||
bool value_gt(Value value1, Value value2);
|
||||
bool value_lt(Value value1, Value value2);
|
||||
bool value_ge(Value value1, Value value2);
|
||||
bool value_le(Value value1, Value value2);
|
||||
|
||||
Value value_and(Value lhs, Value rhs);
|
||||
Value value_or(Value lhs, Value rhs);
|
||||
Value value_add(Value lhs, Value rhs);
|
||||
Value value_mod(Value lhs, Value rhs);
|
||||
Value value_div(Value lhs, Value rhs);
|
||||
Value value_not(Value value);
|
||||
Value value_nil();
|
||||
void value_update_to_float(Value *value, long double f, uint16_t bits);
|
||||
const char *value_type_name(const Value *value);
|
||||
Type *value_find_type(const Value *value);
|
||||
void value_print(Value value);
|
||||
void value_fprint(FILE *file, Value value);
|
||||
bool value_as_bool(Value *value);
|
||||
|
||||
bool value_convert_to_type(Value *value1, Value *value2);
|
||||
bool value_convert(Value *value, ValueType type, uint16_t bits, bool is_unsigned, bool allow_trunc);
|
||||
|
||||
|
||||
// Parse normal integers, parse 0xBEEF, parse 0o1337, parse 0b1010101 – positive numbers only
|
||||
Value parse_int(const char *string, int len);
|
||||
@@ -2,17 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <compiler/lexer.h>
|
||||
#include "tests.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <compiler/compiler.h>
|
||||
#include <utils/lib.h>
|
||||
#include <utils/errors.h>
|
||||
#include <utils/malloc.h>
|
||||
#include "compiler/compiler_internal.h"
|
||||
#include "benchmark.h"
|
||||
#include "../compiler/symtab.h"
|
||||
|
||||
static void test_lexer(void)
|
||||
{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <stdio.h>
|
||||
#include <compiler/compiler.h>
|
||||
#include "compiler/compiler.h"
|
||||
#include "build/build_options.h"
|
||||
#include "build/project_creation.h"
|
||||
#include "utils/errors.h"
|
||||
#include "compiler_tests/tests.h"
|
||||
#include "utils/malloc.h"
|
||||
#include "utils/lib.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
init_arena();
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include "errors.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAX_IDENTIFIER_LENGTH 31
|
||||
@@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "file_utils.h"
|
||||
#include "errors.h"
|
||||
#include "malloc.h"
|
||||
#include "lib.h"
|
||||
|
||||
@@ -6,8 +6,4 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
const char* expand_path(const char* path);
|
||||
|
||||
char *read_file(const char *path, size_t *return_size);
|
||||
|
||||
int filename_to_module(const char *path, char buffer[MAX_IDENTIFIER_LENGTH + 1]);
|
||||
|
||||
@@ -6,7 +6,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "malloc.h"
|
||||
|
||||
const char* expand_path(const char* path);
|
||||
char *read_file(const char *path, size_t *return_size);
|
||||
int filename_to_module(const char *path, char buffer[MAX_IDENTIFIER_LENGTH + 1]);
|
||||
void init_arena(void);
|
||||
void *malloc_arena(unsigned long mem);
|
||||
void free_arena(void);
|
||||
|
||||
void run_arena_allocator_tests(void);
|
||||
|
||||
#define MALLOC(mem) malloc_arena(mem)
|
||||
#define MALLOCS(type) malloc_arena(sizeof(type))
|
||||
|
||||
static inline bool is_power_of_two(uint64_t x)
|
||||
{
|
||||
|
||||
@@ -6,11 +6,3 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void init_arena(void);
|
||||
void *malloc_arena(unsigned long mem);
|
||||
void free_arena(void);
|
||||
|
||||
void run_arena_allocator_tests(void);
|
||||
|
||||
#define MALLOC(mem) malloc_arena(mem)
|
||||
#define MALLOCS(type) malloc_arena(sizeof(type))
|
||||
Reference in New Issue
Block a user