More parsing, start working on packages.

This commit is contained in:
Christoffer Lerno
2019-09-16 12:34:23 +02:00
parent f6c07d86d0
commit 5f00d4c2bc
15 changed files with 480 additions and 43 deletions

View File

@@ -25,6 +25,6 @@ add_executable(c3c
src/compiler/source_file.c
src/compiler/diagnostics.c
src/compiler/ast.c
src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c src/compiler/codegen.c src/compiler/expr_analysis.c src/compiler/enums.h src/compiler/casts.c src/compiler/compiler.h src/compiler/types.c)
src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c src/compiler/codegen.c src/compiler/expr_analysis.c src/compiler/enums.h src/compiler/casts.c src/compiler/compiler.h src/compiler/types.c src/compiler/module.c)
target_compile_options(c3c PRIVATE -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)

View File

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

View File

@@ -5,6 +5,21 @@ int bob = 'HELO';
typedef Foo* as Bob;
func void testdefer(int x)
{
defer printf("A");
defer
{
int x = 2;
printf("B");
x = x + 1;
}
//defer catch printf("B")
//defer catch (error e) printf("%s", @name(e));
//if (x = 1) return throw Error.FOO;
printf("!");
}
struct Foo
{
int i;

View File

@@ -0,0 +1,15 @@
module foo;
public func void gonk()
{
printf("Bob\n");
}
func void test()
{
int i = 0;
}
func void main()
{
printf("Helo\n");
}

View File

@@ -0,0 +1,13 @@
module bar;
import foo local;
func void test()
{
int i = 0;
}
func void main()
{
gronk();
printf("Helo\n");
}

View File

@@ -698,7 +698,7 @@ static void codegen_ast(Context *context, Ast *ast, int indent)
codegen_declare_stmt(context, ast, indent);
return;
case AST_DEFER_STMT:
break;
return;
case AST_DO_STMT:
codegen_emit_do_stmt(context, ast, indent);
return;

View File

@@ -5,8 +5,12 @@
#include "compiler_internal.h"
#include "../build/build_options.h"
Compiler compiler;
void compiler_init(void)
{
stable_init(&compiler.modules, 64);
compiler.module_list = NULL;
}
static void compiler_lex()
@@ -38,8 +42,9 @@ void compiler_parse()
File *file = source_file_load(build_options.files[i], &loaded);
if (loaded) continue;
diag_reset();
parse_file(file);
context_print_ast(current_context, stdout);
Context *context = context_create(file);
parse_file(context);
context_print_ast(context, stdout);
}
exit(EXIT_SUCCESS);
}
@@ -47,22 +52,32 @@ void compiler_parse()
void compiler_compile()
{
builtin_setup();
Context **contexts = NULL;
VECEACH(build_options.files, i)
{
bool loaded = false;
File *file = source_file_load(build_options.files[i], &loaded);
if (loaded) continue;
diag_reset();
parse_file(file);
sema_analysis(current_context);
Context *context = context_create(file);
vec_add(contexts, context);
parse_file(context);
}
VECEACH(contexts, i)
{
Context *context = contexts[i];
sema_analysis(context);
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
FILE *f = fopen("test.c","w");
char buffer[255];
sprintf(buffer, "%s_test.c", context->module_name.string);
printf("%s\n", buffer);
FILE *f = fopen(buffer,"w");
fprintf(f, "#include <stdbool.h>\n#include <stdint.h>\n");
current_context->codegen_output = f;
codegen(current_context);
context->codegen_output = f;
codegen(context);
fclose(f);
system("cc test.c && ./a.out");
sprintf(buffer, "cc %s_test.c && ./a.out", context->module_name.string);
system(buffer);
}
exit(EXIT_SUCCESS);
}
@@ -86,3 +101,34 @@ void compile_file()
}
Decl *compiler_find_symbol(Token token)
{
Decl *candidate = NULL;
VECEACH(compiler.module_list, i)
{
Module *module = compiler.module_list[i];
Decl *decl = module_find_symbol(module, token.string);
if (decl && candidate)
{
const char *previous = candidate->module->name;
const char *current = decl->module->name;
SEMA_ERROR(token, "Ambiguous use of '%s', matches both %s::%s and %s::%s.", token.string,
previous, token.string, current, token.string);
return &poisoned_decl;
}
candidate = decl;
}
return candidate;
}
Module *compiler_find_or_create_module(const char *module_name)
{
Module *module = stable_get(&compiler.modules, module_name);
if (module) return module;
module = CALLOCS(Module);
module->name = module_name;
stable_init(&module->symbols, 0x10000);
stable_set(&compiler.modules, module_name, module);
vec_add(compiler.module_list, module);
return module;
}

View File

@@ -74,7 +74,7 @@ typedef struct
} File;
typedef struct _Path
typedef struct
{
Token package;
Token module;
@@ -133,7 +133,7 @@ typedef struct
ImportType type : 3;
Token alias;
Expr** generic_parameters;
struct _Module *module;
Module *module;
} ImportDecl;
typedef struct
@@ -552,6 +552,11 @@ typedef struct
Ast *body;
} AstCtForStmt;
typedef struct
{
Ast **defers;
} AstContinueStmt;
typedef struct _Ast
{
AstKind ast_kind : 8;
@@ -577,6 +582,7 @@ typedef struct _Ast
AstCaseStmt case_stmt;
AstCtSwitchStmt ct_switch_stmt;
AstCtCaseStmt ct_case_stmt;
AstContinueStmt continue_stmt;
Ast* ct_default_stmt;
Ast* next_stmt;
AstCatchStmt catch_stmt;
@@ -594,9 +600,14 @@ typedef struct _Ast
} Ast;
typedef struct _Package
{
const char *name;
} Package;
typedef struct _Module
{
Package *package;
const char *name;
bool is_external;
@@ -618,8 +629,7 @@ typedef struct _DynamicScope
ScopeFlags flags_created;
unsigned errors;
Decl **local_decl_start;
Ast *defer_stack_start;
Ast *active_defer;
unsigned defer_start;
ExitType exit;
} DynamicScope;
@@ -638,6 +648,7 @@ typedef struct _Context
Decl **functions;
Decl **vars;
Decl **ct_ifs;
Ast **defers;
Decl *active_function_for_analysis;
Type *left_type_in_assignment;
FILE *codegen_output;
@@ -653,8 +664,14 @@ typedef struct _Context
DynamicScope scopes[MAX_SCOPE_DEPTH];
} Context;
extern Context *current_context;
typedef struct
{
STable modules;
Module **module_list;
} Compiler;
extern Context *current_context;
extern Compiler compiler;
extern Ast poisoned_ast;
extern Decl poisoned_decl;
extern Expr poisoned_expr;
@@ -753,6 +770,9 @@ void codegen(Context *context);
bool sema_analyse_expr(Context *context, Expr *expr);
Decl *compiler_find_symbol(Token token);
Module *compiler_find_or_create_module(const char *module_name);
Context *context_create(File *file);
void context_push(Context *context);
void context_register_global_decl(Context *context, Decl *decl);
@@ -827,7 +847,7 @@ static inline void advance_and_verify(TokenType token_type)
Decl *module_find_symbol(Module *module, const char *symbol);
void parse_file(File *file);
void parse_file(Context *context);
#define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__)
void sema_init(File *file);

View File

@@ -55,11 +55,8 @@ static inline bool create_module_or_check_name(Context *context, Token module_na
context->module_name = module_name;
if (context->module == NULL)
{
context->module = malloc_arena(sizeof(Module));
memset(context->module, 0, sizeof(Module));
context->module->name = module_name.string;
stable_init(&(context->module)->symbols, 0x10000);
return true;
context->module = compiler_find_or_create_module(module_name.string);
return true;
}
else if (context->module->name != module_name.string)
{

View File

@@ -254,6 +254,7 @@ typedef enum
SCOPE_CONTINUE = 1 << 1,
SCOPE_CONTROL = 1 << 2,
SCOPE_NEXT = 1 << 3,
SCOPE_DEFER = 1 << 4,
} ScopeFlags;
typedef enum

View File

@@ -46,10 +46,17 @@ static inline bool sema_expr_analyse_identifier(Context *context, Expr *expr)
}
Decl *decl = context_find_ident(context, expr->identifier_expr.identifier.string);
if (decl == NULL)
{
decl = compiler_find_symbol(expr->identifier_expr.identifier);
if (decl && !decl_ok(decl)) return false;
}
if (decl == NULL)
{
SEMA_ERROR(expr->loc, "Unknown identifier %s.", expr->identifier_expr.identifier.string);
return false;
}
if (!decl_ok(decl)) return expr_poison(expr);
expr->identifier_expr.decl = decl;
expr->type = decl->var.type;
return true;

11
src/compiler/module.c Normal file
View File

@@ -0,0 +1,11 @@
// 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"
Decl *module_find_symbol(Module *module, const char *symbol)
{
return stable_get(&module->symbols, symbol);
}

View File

@@ -693,10 +693,6 @@ static inline Ast* parse_if_stmt(void)
if_ast->if_stmt.then_body = stmt;
if (stmt->ast_kind != AST_COMPOUND_STMT || tok.type != TOKEN_ELSE)
{
if (stmt->ast_kind != AST_COMPOUND_STMT)
{
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
}
return if_ast;
}
advance_and_verify(TOKEN_ELSE);
@@ -2663,10 +2659,9 @@ void parse_current(void)
}
}
void parse_file(File *file)
void parse_file(Context *context)
{
lexer_add_file_for_lexing(file);
Context *context = context_create(file);
lexer_add_file_for_lexing(context->file);
context_push(context);
parse_current();
}

View File

@@ -19,11 +19,6 @@ void sema_shadow_error(Decl *decl, Decl *old)
sema_prev_at_range(old->name.span, "The previous use of '%s' was here.", decl->name.string);
}
Decl *module_find_symbol(Module *module, const char *symbol)
{
return stable_get(&module->symbols, symbol);
}
Decl *context_find_ident(Context *context, const char *symbol)
{
@@ -36,7 +31,6 @@ Decl *context_find_ident(Context *context, const char *symbol)
}
Decl *found = module_find_symbol(context->module, symbol);
if (found) return found;
// TODO check imports
return NULL;
}
@@ -50,6 +44,7 @@ static inline void context_push_scope(Context *context)
context->current_scope++;
context->current_scope->exit = EXIT_NONE;
context->current_scope->local_decl_start = context->last_local;
context->current_scope->defer_start = vec_size(context->defers);
}
static inline void context_push_scope_with_flags(Context *context, ScopeFlags flags)
@@ -64,7 +59,10 @@ static inline void context_pop_scope(Context *context)
{
assert(context->current_scope != &context->scopes[0]);
context->last_local = context->current_scope->local_decl_start;
assert(vec_size(context->defers) == context->current_scope->defer_start);
ExitType exit_type = context->current_scope->exit;
vec_resize(context->defers, context->current_scope->defer_start);
context->current_scope--;
if (context->current_scope->exit < exit_type)
{
@@ -86,6 +84,27 @@ static bool sema_resolve_ptr_type(Context *context, Type *type)
return true;
}
static void sema_build_defer_chain(Context *context, Ast ***statement_list)
{
unsigned size = vec_size(context->defers);
unsigned start = context->current_scope->defer_start;
for (unsigned i = size; i > start; i--)
{
vec_add(*statement_list, context->defers[i - 1]);
}
}
static void sema_release_defer_chain(Context *context, Ast ***statement_list)
{
unsigned size = vec_size(context->defers);
unsigned start = context->current_scope->defer_start;
for (unsigned i = size; i > start; i--)
{
vec_add(*statement_list, context->defers[i - 1]->defer_stmt.body);
}
vec_resize(context->defers, start);
}
static bool sema_resolve_array_type(Context *context, Type *type)
{
if (!sema_resolve_type(context, type->base))
@@ -516,7 +535,19 @@ static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement)
static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement)
{
TODO
context_push_scope_with_flags(context, SCOPE_DEFER | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
// Only ones allowed.
context->current_scope->flags &= SCOPE_DEFER | SCOPE_CONTINUE; // NOLINT(hicpp-signed-bitwise)
bool success = sema_analyse_statement(context, statement->defer_stmt.body);
context_pop_scope(context);
if (!success) return false;
vec_add(context->defers, statement);
return true;
}
static inline bool sema_analyse_default_stmt(Context *context, Ast *statement)
@@ -633,7 +664,7 @@ static bool sema_analyse_asm_stmt(Context *context, Ast *statement)
static bool sema_analyse_break_stmt(Context *context, Ast *statement)
{
if (!(context->current_scope->flags | SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise)
if (!(context->current_scope->flags & SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise)
{
SEMA_ERROR(statement->token, "'break' is not allowed here.");
return false;
@@ -649,11 +680,12 @@ static bool sema_analyse_case_stmt(Context *context, Ast *statement)
static bool sema_analyse_continue_stmt(Context *context, Ast *statement)
{
if (!(context->current_scope->flags | SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise)
if (!(context->current_scope->flags & SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise)
{
SEMA_ERROR(statement->token, "'continue' is not allowed here.");
return false;
}
sema_build_defer_chain(context, &statement->continue_stmt.defers);
return true;
}
@@ -718,6 +750,7 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
{
if (*prev_case)
{
// sema_build_defer_chain(context, prev_cases);
context_pop_scope(context);
*prev_case = NULL;
}
@@ -733,7 +766,6 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
case_stmt->case_stmt.value_type = type_is_signed(case_expr->type->canonical) ? CASE_VALUE_INT : CASE_VALUE_UINT;
uint64_t val = case_expr->const_expr.i;
case_stmt->case_stmt.val = val;
context_push_scope(context);
*prev_case = case_stmt;
VECEACH(*prev_cases, i)
{
@@ -744,6 +776,7 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
return false;
}
}
context_push_scope_with_flags(context, SCOPE_BREAK);
vec_add(*prev_cases, case_stmt);
return true;
}
@@ -894,10 +927,14 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
if (!context_add_local(context, params[i])) return false;
}
if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false;
if (context->current_scope->exit != EXIT_RETURN && func->func.function_signature.rtype->canonical != type_void)
if (context->current_scope->exit != EXIT_RETURN)
{
SEMA_ERROR(func->name, "Missing return statement at the end of the function.");
return false;
if (func->func.function_signature.rtype->canonical != type_void)
{
SEMA_ERROR(func->name, "Missing return statement at the end of the function.");
return false;
}
sema_release_defer_chain(context, &func->func.body->compound_stmt.stmts);
}
context_pop_scope(context);
return true;

View File

@@ -214,6 +214,14 @@ static inline unsigned vec_size(const void*vec)
return vec ? (((_VHeader *)vec) - 1)->size : 0;
}
static inline void vec_resize(const void *vec, unsigned new_size)
{
if (vec)
{
(((_VHeader *)vec) - 1)->size = new_size;
}
}
static inline void vec_pop(const void *vec)
{
assert(vec);
@@ -248,7 +256,7 @@ static inline void* _expand(void *vec, size_t element_size)
typeof(_vec) __temp = (typeof(_vec))_expand((_vec), sizeof((_vec)[0])); \
__temp[vec_size(__temp) - 1] = _value; \
_vec = __temp; })
#define vec_add(_vec, _value) do { _vec = VECADD(_vec, _value); } while (0)
#define vec_add(_vec, _value) do { (_vec) = VECADD((_vec), _value); } while (0)
#define VECLAST(_vec) ( (_vec) ? (_vec)[vec_size(_vec) - 1] : NULL)