mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
More parsing, start working on packages.
This commit is contained in:
@@ -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)
|
||||
|
||||
272
resources/testfragments/compilertest2.c3
Normal file
272
resources/testfragments/compilertest2.c3
Normal 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, ¤t);
|
||||
printf("%d : ", i);
|
||||
current.print();
|
||||
minus1.copyTo(&minus2);
|
||||
current.copyTo(&minus1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
15
resources/testfragments/simple_test1.c3
Normal file
15
resources/testfragments/simple_test1.c3
Normal 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");
|
||||
}
|
||||
13
resources/testfragments/simple_test2.c3
Normal file
13
resources/testfragments/simple_test2.c3
Normal file
@@ -0,0 +1,13 @@
|
||||
module bar;
|
||||
import foo local;
|
||||
|
||||
func void test()
|
||||
{
|
||||
int i = 0;
|
||||
}
|
||||
|
||||
func void main()
|
||||
{
|
||||
gronk();
|
||||
printf("Helo\n");
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
11
src/compiler/module.c
Normal 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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user