Refactor type handling, some extremely simple codegen, but mostly work on casts (not finished)

This commit is contained in:
Christoffer Lerno
2019-08-29 17:08:34 +02:00
parent ebce81ad51
commit 2eb91083a6
45 changed files with 4194 additions and 2747 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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";
}

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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