aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.c210
-rw-r--r--src/bytecode/bytecode.c212
-rw-r--r--src/compiler.c3
-rw-r--r--src/parser.c392
-rw-r--r--src/ssa/ssa.c233
-rw-r--r--src/tokenizer.c111
6 files changed, 936 insertions, 225 deletions
diff --git a/src/ast.c b/src/ast.c
index 983b3a4..4194737 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -44,6 +44,8 @@ BufferView ast_get_name(Ast *self) {
case AST_IMPORT:
case AST_STRING:
case AST_BINOP:
+ case AST_IF_STATEMENT:
+ case AST_WHILE_STATEMENT:
name = create_buffer_view_null();
break;
case AST_NUMBER:
@@ -52,6 +54,9 @@ BufferView ast_get_name(Ast *self) {
case AST_LHS:
name = self->value.lhs_expr->var_name;
break;
+ case AST_ASSIGN:
+ name = ast_get_name(self->value.assign_expr->lhs_expr);
+ break;
case AST_FUNCTION_CALL:
name = self->value.func_call->func.name;
break;
@@ -69,7 +74,8 @@ static BufferView ast_get_code_reference(Ast *self) {
return ast_get_name(self);
}
-int funcdecl_init(FunctionDecl *self, Scope *parent, ScopedAllocator *allocator) {
+int funcdecl_init(FunctionDecl *self, FunctionSignature *signature, Scope *parent, ScopedAllocator *allocator) {
+ self->signature = signature;
self->ssa_func_index = 0;
return scope_init(&self->body, parent, allocator);
}
@@ -88,16 +94,23 @@ void structfield_init(StructField *self, BufferView name, BufferView type_name)
variable_init(&self->type, type_name);
}
-int lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator) {
+int lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator) {
+ self->is_extern = is_extern;
self->is_pub = is_pub;
self->is_const = is_const;
- variable_init(&self->type, create_buffer_view_null());
+ self->type.type = VARIABLE_TYPE_NONE;
+ self->type.value.variable = NULL;
self->var_name = var_name;
self->rhs_expr = NULL;
return_if_error(scoped_allocator_create_mutex(allocator, &self->mutex));
return 0;
}
+void assignmentexpr_init(AssignmentExpr *self, Ast *lhs_expr, Ast *rhs_expr) {
+ self->lhs_expr = lhs_expr;
+ self->rhs_expr = rhs_expr;
+}
+
void import_init(Import *self, BufferView path) {
self->path = path;
self->file_scope = NULL;
@@ -117,6 +130,7 @@ void number_init(Number *self, i64 value, bool is_integer, BufferView code_ref)
void variable_init(Variable *self, BufferView name) {
self->name = name;
+ self->resolved_var = NULL;
}
void binop_init(Binop *self) {
@@ -126,6 +140,23 @@ void binop_init(Binop *self) {
self->grouped = bool_false;
}
+int if_statement_init(IfStatement *self, Scope *parent, ScopedAllocator *allocator) {
+ self->condition = NULL;
+ self->else_if_stmt = NULL;
+ return scope_init(&self->body, parent, allocator);
+}
+
+int else_if_statement_init(ElseIfStatement *self, Scope *parent, ScopedAllocator *allocator) {
+ self->condition = NULL;
+ self->next_else_if_stmt = NULL;
+ return scope_init(&self->body, parent, allocator);
+}
+
+int while_statement_init(WhileStatement *self, Scope *parent, ScopedAllocator *allocator) {
+ self->condition = NULL;
+ return scope_init(&self->body, parent, allocator);
+}
+
int scope_init(Scope *self, Scope *parent, ScopedAllocator *allocator) {
return_if_error(buffer_init(&self->ast_objects, allocator));
return_if_error(hash_map_init(&self->named_objects, allocator, sizeof(Ast*), hash_compare_string, amal_hash_string));
@@ -195,17 +226,18 @@ static void parser_print_error(Parser *parser, const char *ref, const char *fmt,
va_list args;
va_start(args, fmt);
if(parser) {
- tokenizer_print_error(&parser->tokenizer,
+ tokenizer_print_error_args(&parser->tokenizer,
tokenizer_get_code_reference_index(&parser->tokenizer, ref),
fmt, args);
} else {
/* TODO: Redirect error to compiler error callback if set */
+ amal_log_error("TODO: Fix this:");
amal_log_error(fmt, args);
}
va_end(args);
}
-static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) {
+static Ast* __scope_get_resolved_variable(Scope *self, Scope *start, AstCompilerContext *context, BufferView name) {
Ast *result;
bool exists;
Scope *prev_scope;
@@ -215,16 +247,16 @@ static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context
if(!exists) {
Parser *parser;
if(self->parent)
- return scope_get_resolved_variable(self->parent, context, name);
+ return __scope_get_resolved_variable(self->parent, start, context, name);
- parser = scope_get_parser(self);
+ parser = scope_get_parser(start);
parser_print_error(parser, name.data, "Undefined reference to variable \"%.*s\"", name.size, name.data);
throw(AST_ERR);
}
/*
Need to change scope here because we are changing the visible scope
- and the ast object may be in another scope than the current
+ and the ast object may be in another scope than the current
resolving ast.
*/
prev_scope = context->scope;
@@ -236,9 +268,58 @@ static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context
return result;
}
+static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) {
+ return __scope_get_resolved_variable(self, self, context, name);
+}
+
+static void function_signature_resolve(FunctionSignature *self, AstCompilerContext *context) {
+ /* TODO: Implement */
+ (void)self;
+ (void)context;
+}
+
static void variable_resolve(Variable *self, AstCompilerContext *context, AstResolveData *resolve_data) {
- if(!resolve_data->type)
- resolve_data->type = scope_get_resolved_variable(context->scope, context, self->name)->resolve_data.type;
+ if(!self->resolved_var) {
+ self->resolved_var = scope_get_resolved_variable(context->scope, context, self->name);
+ resolve_data->type = self->resolved_var->resolve_data.type;
+ }
+}
+
+static LhsExpr* variable_get_resolved_type(Variable *self) {
+ assert(self->resolved_var);
+ return self->resolved_var->value.lhs_expr;
+}
+
+static void variable_type_resolve(VariableType *self, AstCompilerContext *context, AstResolveData *resolve_data) {
+ switch(self->type) {
+ case VARIABLE_TYPE_NONE:
+ return;
+ case VARIABLE_TYPE_VARIABLE:
+ variable_resolve(self->value.variable, context, resolve_data);
+ break;
+ case VARIABLE_TYPE_SIGNATURE:
+ function_signature_resolve(self->value.signature, context);
+ break;
+ }
+}
+
+static BufferView variable_type_get_name(VariableType *self) {
+ BufferView result;
+ switch(self->type) {
+ case VARIABLE_TYPE_NONE:
+ result.data = NULL;
+ result.size = 0;
+ break;
+ case VARIABLE_TYPE_VARIABLE:
+ result = self->value.variable->name;
+ break;
+ case VARIABLE_TYPE_SIGNATURE:
+ /* TODO: Save reference to signature in code in the FunctionSignature type */
+ result.data = "fn()";
+ result.size = 4;
+ break;
+ }
+ return result;
}
static LhsExpr* lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context) {
@@ -259,8 +340,7 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
self = ast->value.lhs_expr;
rhs_resolve_type = NULL;
- if(self->type.name.data)
- variable_resolve(&self->type, context, &ast->resolve_data);
+ variable_type_resolve(&self->type, context, &ast->resolve_data);
/*
TODO: When parameters and return types are implemented, AST_RESOLVE_END should be set after
@@ -274,10 +354,15 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
rhs_resolve_type = lhsexpr_resolve_rhs(self, context);
/* self->rhs_expr can be null here because this is valid: var num: i32; */
+ /* TODO: Add casting */
if(ast->resolve_data.type && self->rhs_expr && ast->resolve_data.type != rhs_resolve_type) {
Parser *parser;
parser = scope_get_parser(context->scope);
- parser_print_error(parser, self->type.name.data,
+ /*
+ TODO: Instead of using self->var_name, using type name. This cant be done right now because
+ type can be function signature.
+ */
+ parser_print_error(parser, self->var_name.data,
"Variable type and variable assignment type (right-hand side) do not match");
throw(AST_ERR);
}
@@ -287,6 +372,67 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
ast->resolve_data.type = rhs_resolve_type;
}
+static LhsExpr* binop_get_lhs_expr(Binop *self) {
+ if(self->rhs) {
+ if(self->rhs->type == AST_LHS)
+ return self->rhs->value.lhs_expr;
+ else if(self->rhs->type == AST_BINOP)
+ return binop_get_lhs_expr(self->rhs->value.binop);
+ } else {
+ if(self->lhs->type == AST_LHS)
+ return self->lhs->value.lhs_expr;
+ else if(self->lhs->type == AST_BINOP)
+ return binop_get_lhs_expr(self->lhs->value.binop);
+ }
+ return NULL;
+}
+
+static void assignmentexpr_resolve(Ast *ast, AstCompilerContext *context) {
+ AssignmentExpr *self;
+ LhsExpr *lhs_source;
+
+ assert(ast->type == AST_ASSIGN);
+ self = ast->value.assign_expr;
+ lhs_source = NULL;
+
+ ast_resolve(self->lhs_expr, context);
+ ast_resolve(self->rhs_expr, context);
+
+ if(self->lhs_expr->type == AST_VARIABLE)
+ lhs_source = variable_get_resolved_type(self->lhs_expr->value.variable);
+ else if(self->lhs_expr->type == AST_BINOP)
+ lhs_source = binop_get_lhs_expr(self->lhs_expr->value.binop);
+
+ /* This also covers extern variables, since extern variables are always const */
+ /* TODO: var.field type expressions should also be checked */
+ if(lhs_source && lhs_source->is_const) {
+ Parser *parser;
+ parser = scope_get_parser(context->scope);
+ parser_print_error(parser, ast_get_code_reference(self->lhs_expr).data, "Can't assign to a const value");
+ throw(AST_ERR);
+ }
+
+ /* TODO: Add casting */
+ if(self->lhs_expr->resolve_data.type != self->rhs_expr->resolve_data.type) {
+ Parser *parser;
+ BufferView rhs_type_name;
+ BufferView lhs_type_name;
+
+ parser = scope_get_parser(context->scope);
+ rhs_type_name = variable_type_get_name(&self->rhs_expr->resolve_data.type->type);
+ lhs_type_name = variable_type_get_name(&self->lhs_expr->resolve_data.type->type);
+ /*
+ TODO: Instead of using self->var_name, using type name. This cant be done right now because
+ type can be function signature.
+ */
+ parser_print_error(parser, ast_get_code_reference(self->lhs_expr).data,
+ "Can't cast data of type %.*s to type %.*s", rhs_type_name.size, rhs_type_name.data, lhs_type_name.size, lhs_type_name.data);
+ throw(AST_ERR);
+ }
+
+ ast->resolve_data.type = self->lhs_expr->resolve_data.type;
+}
+
static void import_resolve(Ast *ast, AstCompilerContext *context) {
Import *self;
assert(ast->type == AST_IMPORT);
@@ -331,6 +477,7 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) {
func_call = self->value.func_call;
variable_resolve(&func_call->func, context, &self->resolve_data);
+ /* Attemping to use call syntax (variable_name ( ) ) with a variable that is not a function */
if(self->resolve_data.type->rhs_expr->type != AST_FUNCTION_DECL) {
Parser *caller_parser;
Parser *callee_parser;
@@ -420,8 +567,12 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) {
if(self->type == BINOP_DOT && (self->rhs->type == AST_VARIABLE || self->rhs->type == AST_FUNCTION_CALL)) {
binop_resolve_dot_access(ast, context);
/* Only function call has extra data that needs to be resolved (args) */
- if(self->rhs->type == AST_FUNCTION_CALL)
+ if(self->rhs->type == AST_FUNCTION_CALL) {
+ Scope *prev_scope = context->scope;
+ context->scope = lhsexpr_get_scope(self->lhs->resolve_data.type);
ast_resolve(self->rhs, context);
+ context->scope = prev_scope;
+ }
self->rhs->resolve_data.status = AST_RESOLVED;
ast->resolve_data.type = self->rhs->resolve_data.type;
} else {
@@ -452,6 +603,28 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) {
}
}
+static void else_if_statement_resolve(ElseIfStatement *else_if_stmt, AstCompilerContext *context) {
+ if(else_if_stmt->condition)
+ ast_resolve(else_if_stmt->condition, context);
+
+ scope_resolve(&else_if_stmt->body, context);
+ if(else_if_stmt->next_else_if_stmt)
+ else_if_statement_resolve(else_if_stmt->next_else_if_stmt, context);
+}
+
+static void if_statement_resolve(IfStatement *if_stmt, AstCompilerContext *context) {
+ assert(if_stmt->condition);
+ ast_resolve(if_stmt->condition, context);
+ scope_resolve(&if_stmt->body, context);
+ if(if_stmt->else_if_stmt)
+ else_if_statement_resolve(if_stmt->else_if_stmt, context);
+}
+
+static void while_statement_resolve(WhileStatement *while_stmt, AstCompilerContext *context) {
+ ast_resolve(while_stmt->condition, context);
+ scope_resolve(&while_stmt->body, context);
+}
+
void ast_resolve(Ast *self, AstCompilerContext *context) {
assert(self);
/*
@@ -515,6 +688,9 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
case AST_LHS:
lhsexpr_resolve(self, context);
break;
+ case AST_ASSIGN:
+ assignmentexpr_resolve(self, context);
+ break;
case AST_IMPORT:
/* TODO: When @import(...).data syntax is added, implement the resolve for it */
import_resolve(self, context);
@@ -529,6 +705,12 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
case AST_BINOP:
binop_resolve(self, context);
break;
+ case AST_IF_STATEMENT:
+ if_statement_resolve(self->value.if_stmt, context);
+ break;
+ case AST_WHILE_STATEMENT:
+ while_statement_resolve(self->value.while_stmt, context);
+ break;
}
/* TODO: See comment at the top of this function */
self->resolve_data.status = AST_RESOLVED;
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 6774a54..789a9f6 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -46,6 +46,17 @@ static CHECK_RESULT usize ssa_extract_func_call(u8 *instruction_data, SsaInsFunc
return sizeof(result->result) + sizeof(result->func_decl);
}
+static CHECK_RESULT usize ssa_extract_jump_zero(u8 *instruction_data, SsaInsJumpZero *result) {
+ am_memcpy(&result->condition_reg, instruction_data, sizeof(result->condition_reg));
+ am_memcpy(&result->jump_offset, instruction_data + sizeof(result->condition_reg), sizeof(result->jump_offset));
+ return sizeof(result->condition_reg) + sizeof(result->jump_offset);
+}
+
+static CHECK_RESULT usize ssa_extract_jump(u8 *instruction_data, SsaInsJump *result) {
+ am_memcpy(&result->jump_offset, instruction_data, sizeof(result->jump_offset));
+ return sizeof(result->jump_offset);
+}
+
static void add_intermediates(BytecodeCompilerContext *self) {
Ssa *ssa;
Buffer *instructions;
@@ -66,19 +77,44 @@ static void add_intermediates(BytecodeCompilerContext *self) {
}
}
+#if 0
#define NUM_MAX_REGS 256
+#define NUM_MAX_FUNC_ARGS 32
+
+static const char* lhs_expr_get_c_name(BytecodeCompilerContext *self, LhsExpr *lhs_expr) {
+ if(lhs_expr == self->parser->compiler->default_types.i64) {
+ return "i64";
+ } else if(lhs_expr == self->parser->compiler->default_types.f64) {
+ return "f64";
+ } else if(lhs_expr == self->parser->compiler->default_types.str) {
+ return"const char*";
+ } else {
+ amal_log_error("Invalid rhs type %p", lhs_expr);
+ assert(bool_false && "TODO: Implement");
+ return "";
+ }
+}
+#endif
static void add_instructions(BytecodeCompilerContext *self) {
Ssa *ssa;
u8 *instruction;
u8 *instructions_end;
+
SsaInsForm1 ssa_ins_form1;
SsaInsForm2 ssa_ins_form2;
SsaInsFuncStart ssa_ins_func_start;
SsaInsFuncCall ssa_ins_func_call;
+ SsaInsJumpZero ssa_ins_jump_zero;
+ SsaInsJump ssa_ins_jump;
+
FILE *file;
char *filename;
+ #ifdef COMPILE_TO_C
LhsExpr *reg_types[NUM_MAX_REGS]; /* TODO: Remove this. Encode this data in the register itself */
+ SsaRegister func_arg_stack[NUM_MAX_FUNC_ARGS]; /* TODO: Remove this? */
+ int func_arg_index;
+ #endif
ssa = self->parser->ssa;
instruction = buffer_begin(&ssa->instructions);
@@ -90,15 +126,27 @@ static void add_instructions(BytecodeCompilerContext *self) {
strcat(filename, ".z");
file = fopen(filename, "wb");
free(filename);
+ #ifdef COMPILE_TO_C
#ifdef DEBUG
am_memset(reg_types, 0, sizeof(reg_types));
#endif
+ func_arg_index = 0;
fputs("typedef i64 signed long long;\n", file);
fputs("typedef f64 double;\n", file);
+ #define ARITH_OP(op) do {\
+ const char *rhs_type_name; \
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2); \
+ assert(ssa_ins_form2.result < NUM_MAX_REGS); \
+ assert(ssa_ins_form2.lhs < NUM_MAX_REGS); \
+ rhs_type_name = lhs_expr_get_c_name(self, reg_types[ssa_ins_form2.lhs]); \
+ fprintf(file, "%s r%d = r%d %s r%d;\n", rhs_type_name, ssa_ins_form2.result, ssa_ins_form2.lhs, (op), ssa_ins_form2.rhs); \
+ reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.lhs]; \
+ } while(0)
+
while(instruction != instructions_end) {
- switch(*instruction++) {
+ switch((SsaInstruction)*instruction++) {
case SSA_ASSIGN_INTER: {
SsaNumber number;
instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
@@ -125,54 +173,32 @@ static void add_instructions(BytecodeCompilerContext *self) {
break;
}
case SSA_ASSIGN_REG: {
- LhsExpr *rhs_type;
const char *rhs_type_name;
instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
assert(ssa_ins_form1.rhs < NUM_MAX_REGS);
- rhs_type = reg_types[ssa_ins_form1.rhs];
- if(rhs_type == self->parser->compiler->default_types.i64) {
- rhs_type_name = "i64";
- } else if(rhs_type == self->parser->compiler->default_types.f64) {
- rhs_type_name = "f64";
- } else if(rhs_type == self->parser->compiler->default_types.str) {
- rhs_type_name = "const char*";
- } else {
- amal_log_error("Invalid rhs type %p for reg %d", rhs_type, ssa_ins_form1.rhs);
- assert(bool_false && "TODO: Implement");
- }
+ rhs_type_name = lhs_expr_get_c_name(self, reg_types[ssa_ins_form1.rhs]);
fprintf(file, "%s r%d = r%d;\n", rhs_type_name, ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ reg_types[ssa_ins_form1.lhs] = reg_types[ssa_ins_form1.rhs];
break;
}
case SSA_ADD: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d + r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("+");
break;
}
case SSA_SUB: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d - r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("-");
break;
}
case SSA_MUL: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d * r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("*");
break;
}
case SSA_DIV: {
- instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
- fprintf(file, "r%d = r%d / r%d;\n", ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs);
- assert(ssa_ins_form2.result < NUM_MAX_REGS);
- assert(ssa_ins_form2.rhs < NUM_MAX_REGS);
- reg_types[ssa_ins_form2.result] = reg_types[ssa_ins_form2.rhs];
+ ARITH_OP("/");
+ break;
+ }
+ case SSA_EQUALS: {
+ ARITH_OP("==");
break;
}
case SSA_FUNC_START: {
@@ -194,20 +220,134 @@ static void add_instructions(BytecodeCompilerContext *self) {
SsaRegister reg;
am_memcpy(&reg, instruction, sizeof(SsaRegister));
instruction += sizeof(SsaRegister);
- fprintf(file, "PUSH r%d ***\n", reg);
+ assert(func_arg_index < NUM_MAX_FUNC_ARGS);
+ func_arg_stack[func_arg_index++] = reg;
break;
}
- case SSA_CALL:
+ case SSA_CALL: {
+ int i;
instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call);
- fprintf(file, "r%d = CALL %p ***\n", ssa_ins_func_call.result, ssa_ins_func_call.func_decl);
+ fprintf(file, "r%d = f%p(", ssa_ins_func_call.result, ssa_ins_func_call.func_decl);
+ for(i = 0; i < func_arg_index; ++i) {
+ if(i > 0)
+ fputs(", ", file);
+ fprintf(file, "r%d", func_arg_stack[i]);
+ }
+ func_arg_index = 0;
+ fputs(");\n", file);
+ break;
+ }
+ case SSA_JUMP_ZERO: {
+ assert(bool_false && "Not implemented!");
+ instruction += ssa_extract_jump_zero(instruction, &ssa_ins_jump_zero);
+ break;
+ }
+ case SSA_JUMP: {
+ assert(bool_false && "Not implemented!");
+ instruction += ssa_extract_jump(instruction, &ssa_ins_jump);
break;
+ }
}
}
+ #else
+ #define ARITH_OP(op) do {\
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2); \
+ fprintf(stderr, "%s r%d, r%d, r%d\n", (op), ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs); \
+ } while(0)
+ while(instruction != instructions_end) {
+ SsaInstruction ins = (SsaInstruction)*instruction++;
+ switch(ins) {
+ case SSA_ASSIGN_INTER: {
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ fprintf(file, "mov r%d, i%d\n", ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ break;
+ }
+ case SSA_ASSIGN_STRING: {
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ fprintf(file, "mov r%d, s%d\n", ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ break;
+ }
+ case SSA_ASSIGN_REG: {
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ fprintf(file, "mov r%d, r%d\n", ssa_ins_form1.lhs, ssa_ins_form1.rhs);
+ break;
+ }
+ case SSA_ADD: {
+ ARITH_OP("add");
+ break;
+ }
+ case SSA_SUB: {
+ ARITH_OP("sub");
+ break;
+ }
+ case SSA_MUL: {
+ ARITH_OP("mul");
+ break;
+ }
+ case SSA_DIV: {
+ ARITH_OP("div");
+ break;
+ }
+ case SSA_EQUALS: {
+ ARITH_OP("eq");
+ break;
+ }
+ case SSA_FUNC_START: {
+ instruction += ssa_extract_func_start(instruction, &ssa_ins_func_start);
+ fprintf(file, "FUNC_START %d\n", ssa_ins_func_start.num_args);
+ break;
+ }
+ case SSA_FUNC_END: {
+ fprintf(file, "FUNC_END\n");
+ break;
+ }
+ case SSA_PUSH: {
+ SsaRegister reg;
+ am_memcpy(&reg, instruction, sizeof(SsaRegister));
+ instruction += sizeof(SsaRegister);
+ fprintf(file, "push r%d\n", reg);
+ break;
+ }
+ case SSA_CALL: {
+ /* TODO: Add args, using number of bytes to pop after function call. */
+ /*
+ TODO: Pass return register to function. The register should be a pointer that
+ has the size of the function return values so the return values can fit in it.
+ */
+ /*
+ TODO: Using ssa_func_index only works correctly if the function was defined in the same
+ file as the function call. To make this work with calling functions in other files,
+ ssa_func_index should also have an offset index or something like that.
+ So each file has it's own function list with indices and when they need to be combined in the end,
+ the function indices can be increased by their block index (ssa_func_index + block index), where block index
+ is defined as the size of all previous files' number of functions.
+ */
+ instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call);
+ fprintf(file, "call %d\n", ssa_ins_func_call.func_decl->ssa_func_index);
+ break;
+ }
+ case SSA_JUMP_ZERO: {
+ instruction += ssa_extract_jump_zero(instruction, &ssa_ins_jump_zero);
+ fprintf(file, "jz r%d, %d\n", ssa_ins_jump_zero.condition_reg, ssa_ins_jump_zero.jump_offset);
+ break;
+ }
+ case SSA_JUMP: {
+ instruction += ssa_extract_jump(instruction, &ssa_ins_jump);
+ fprintf(file, "jmp %d\n", ssa_ins_jump.jump_offset);
+ break;
+ }
+ default:
+ amal_log_error("Instruction not yet implemented: %d", ins);
+ assert(bool_false && "Instruction not yet implemented");
+ }
+ }
+ #endif /* COMPILE_TO_C */
fclose(file);
}
void generate_bytecode_from_ssa(BytecodeCompilerContext *self) {
add_intermediates(self);
+ /* TODO: Also add strings in ssa, so we can index them */
add_instructions(self);
}
diff --git a/src/compiler.c b/src/compiler.c
index 30a583a..bdcb1c8 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -40,7 +40,7 @@ static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char
return_if_error(structdecl_init(struct_decl, &compiler->root_scope, &compiler->allocator));
return_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(LhsExpr), (void**)lhs_expr));
- return_if_error(lhsexpr_init(*lhs_expr, bool_true, bool_true,
+ return_if_error(lhsexpr_init(*lhs_expr, bool_true, bool_true, bool_true,
create_buffer_view(name, strnlen(name, PATH_MAX)),
&compiler->allocator));
return_if_error(ast_create(&compiler->allocator, struct_decl, AST_STRUCT_DECL, &(*lhs_expr)->rhs_expr));
@@ -242,6 +242,7 @@ static CHECK_RESULT int thread_generate_ssa(Parser *parser) {
return_if_error(scoped_allocator_alloc(parser->allocator, sizeof(Ssa), (void**)&compiler_context.ssa));
return_if_error(ssa_init(compiler_context.ssa, parser->allocator));
+ compiler_context.compiler = parser->compiler;
parser->ssa = compiler_context.ssa;
amal_log_debug("Generating SSA for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data);
result = setjmp(compiler_context.env);
diff --git a/src/parser.c b/src/parser.c
index f05b31d..c0d2c6d 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -20,9 +20,10 @@ do { \
throw(return_if_result); \
} while(0)
-static CHECK_RESULT Ast* parser_parse_rhs_start(Parser *self, bool is_standalone);
+static CHECK_RESULT Ast* parser_parse_rhs(Parser *self);
static CHECK_RESULT Ast* parser_parse_body(Parser *self);
static CHECK_RESULT Ast* parser_parse_struct_body(Parser *self);
+static CHECK_RESULT Ast* parser_parse_rhs_binop(Parser *self);
static void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope);
int parser_thread_data_init(ParserThreadData *self) {
@@ -61,7 +62,7 @@ int parser_init(Parser *self, amal_compiler *compiler, ScopedAllocator *allocato
self->error_context = ERROR_CONTEXT_NONE;
return_if_error(structdecl_init(&self->struct_decl, &compiler->root_scope, allocator));
self->struct_decl.body.parser = self;
- return_if_error(lhsexpr_init(&self->file_decl, bool_true, bool_true, create_buffer_view_null(), self->allocator));
+ return_if_error(lhsexpr_init(&self->file_decl, bool_true, bool_true, bool_true, create_buffer_view_null(), self->allocator));
return_if_error(ast_create(self->allocator, &self->struct_decl, AST_STRUCT_DECL, &self->file_decl.rhs_expr));
self->current_scope = &self->struct_decl.body;
self->has_func_parent = bool_false;
@@ -132,30 +133,78 @@ static void parser_parse_struct_body_loop(Parser *self, Scope *scope) {
}
/*
-VAR_TYPE_DEF = ':' TOK_IDENTIFIER
+TODO: Implement params and return types
+FUNC_SIGNATURE = 'fn' ('(' ')')?
*/
-static void parser_parse_var_type_def(Parser *self, BufferView *type_name) {
+static CHECK_RESULT FunctionSignature* parser_parse_function_signature(Parser *self) {
+ FunctionSignature *signature;
bool match;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_FN, &match));
+ if(!match)
+ return NULL;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_PAREN, &match));
+ if(match) {
+ /* TODO: Parse parameters */
+ throw_if_error(tokenizer_accept(&self->tokenizer, TOK_CLOSING_PAREN));
+ /* TODO: Parse return types */
+ }
+
+ throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(FunctionSignature), (void**)&signature));
+ signature->params = 0;
+ return signature;
+}
+
+/*
+VAR_TYPE_DEF = ':' TOK_IDENTIFIER|FUNC_SIGNATURE
+*/
+static CHECK_RESULT int parser_parse_var_type_def(Parser *self, VariableType *result) {
+ bool match;
+
+ result->type = VARIABLE_TYPE_NONE;
+ result->value.variable = NULL;
+
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COLON, &match));
+ if(!match)
+ return -1;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IDENTIFIER, &match));
if(match) {
- throw_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER));
- *type_name = self->tokenizer.value.identifier;
+ result->type = VARIABLE_TYPE_VARIABLE;
+ throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(Variable), (void**)&result->value.variable));
+ variable_init(result->value.variable, self->tokenizer.value.identifier);
+ return 0;
+ }
+
+ result->type = VARIABLE_TYPE_SIGNATURE;
+ result->value.signature = parser_parse_function_signature(self);
+ if(!result->value.signature) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data),
+ "Expected type or closure signature");
+ throw(PARSER_UNEXPECTED_TOKEN);
}
+ return 0;
}
/*
-LHS = ('pub'? 'const' TOK_IDENTIFIER VAR_TYPE_DEF? '=') |
- ('pub'? 'var' TOK_IDENTIFIER VAR_TYPE_DEF? '='|';')
+LHS_DECLARATION = 'extern'? 'pub'? 'const'|'var' TOK_IDENTIFIER VAR_TYPE_DEF?
*/
-static CHECK_RESULT LhsExpr* parser_parse_lhs(Parser *self, bool *assignment_or_rhs) {
+static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) {
LhsExpr *result;
+ bool is_extern;
bool is_pub;
bool is_const;
- bool match;
BufferView var_name;
- result = NULL;
- *assignment_or_rhs = bool_true;
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EXTERN, &is_extern));
+ if(is_extern && self->has_func_parent) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data),
+ "Only declarations in structs can be extern");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_PUB, &is_pub));
if(is_pub && self->has_func_parent) {
@@ -168,77 +217,48 @@ static CHECK_RESULT LhsExpr* parser_parse_lhs(Parser *self, bool *assignment_or_
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_CONST, &is_const));
if(!is_const) {
bool isVar;
+
+ if(is_extern) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data),
+ "Extern variable have to be declared with \"const\"");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
+
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_VAR, &isVar));
if(!isVar)
- return result;
+ return NULL;
}
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER));
var_name = self->tokenizer.value.identifier;
throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&result));
- throw_if_error(lhsexpr_init(result, is_pub, is_const, var_name, self->allocator));
-
- parser_parse_var_type_def(self, &result->type.name);
-
- throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EQUALS, &match));
- if(match) {
- *assignment_or_rhs = bool_true;
- return result;
- }
+ throw_if_error(lhsexpr_init(result, is_extern, is_pub, is_const, var_name, self->allocator));
- if(!result->type.name.data) {
- self->error = tokenizer_create_error(&self->tokenizer,
- tokenizer_get_error_index(&self->tokenizer),
- "Variable declaration requires type or right-hand side expression (Expected ':' or '=')");
- throw(PARSER_UNEXPECTED_TOKEN);
- }
-
- *assignment_or_rhs = bool_false;
- throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_SEMICOLON, &match));
- if(match && is_const) {
- self->error = tokenizer_create_error(&self->tokenizer,
- tokenizer_get_error_index(&self->tokenizer),
- "Const variable declaration requires assignment (expected '=', got ';')");
- throw(PARSER_UNEXPECTED_TOKEN);
- }
- if(!match) {
- self->error = tokenizer_create_error(&self->tokenizer,
- tokenizer_get_error_index(&self->tokenizer),
- "Expected ';'");
- throw(PARSER_UNEXPECTED_TOKEN);
- }
+ ignore_result_int(parser_parse_var_type_def(self, &result->type));
return result;
}
/*
-TODO: Implement params and return types
-CLOSURE = 'fn' ('(' PARAM? (',' PARAM)* ')')? '{' BODY_LOOP '}'
+
+CLOSURE = FUNC_SIGNATURE '{' BODY_LOOP '}'
*/
static CHECK_RESULT FunctionDecl* parser_parse_closure(Parser *self) {
+ FunctionSignature *signature;
FunctionDecl *result;
- bool match;
bool prev_has_func_parent;
- result = NULL;
- throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_FN, &match));
- if(!match)
- return result;
-
- throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match));
- if(!match) {
- throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_PAREN));
- /* TODO: Parse parameters */
- throw_if_error(tokenizer_accept(&self->tokenizer, TOK_CLOSING_PAREN));
- /* TODO: Parse return types */
- throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_BRACE));
- }
+ signature = parser_parse_function_signature(self);
+ if(!signature)
+ return NULL;
throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(FunctionDecl), (void**)&result));
- throw_if_error(funcdecl_init(result, self->current_scope, self->allocator));
+ throw_if_error(funcdecl_init(result, signature, self->current_scope, self->allocator));
self->current_scope = &result->body;
prev_has_func_parent = self->has_func_parent;
self->has_func_parent = bool_true;
+ throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_BRACE));
parser_parse_body_loop(self, self->current_scope, TOK_CLOSING_BRACE);
self->current_scope = result->body.parent;
self->has_func_parent = prev_has_func_parent;
@@ -286,14 +306,14 @@ static void parser_parse_function_args(Parser *self, FunctionCall *func_call) {
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_COMMA));
first_arg = bool_false;
- arg_expr = parser_parse_rhs_start(self, bool_false);
+ arg_expr = parser_parse_rhs(self);
throw_if_error(buffer_append(&func_call->args, &arg_expr, sizeof(arg_expr)));
}
}
/*
VARIABLE = TOK_IDENTIFIER
-FUNC_CALL_OR_VARIABLE = VARIABLE '(' FUNC_ARGS ')'
+FUNC_CALL_OR_VARIABLE = VARIABLE ('(' FUNC_ARGS ')')?
*/
static CHECK_RESULT Ast* parser_parse_function_call_or_variable(Parser *self) {
Ast *result;
@@ -319,6 +339,7 @@ static CHECK_RESULT Ast* parser_parse_function_call_or_variable(Parser *self) {
throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(FunctionCall), (void**)&func_call));
throw_if_error(funccall_init(func_call, self->tokenizer.value.identifier, self->allocator));
throw_if_error(ast_create(self->allocator, func_call, AST_FUNCTION_CALL, &result));
+ /* Ends after TOK_CLOSING_PAREN */
parser_parse_function_args(self, func_call);
return result;
}
@@ -340,6 +361,109 @@ static CHECK_RESULT Import* parser_parse_import(Parser *self) {
return result;
}
+/*
+ELSE_IF_STATEMENT = 'else' ('if' RHS_BINOP)? ('{' BODY_LOOP '}')|BODY
+*/
+static CHECK_RESULT ElseIfStatement* parser_parse_else_if_statement(Parser *self) {
+ ElseIfStatement *result;
+ bool match;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_ELSE, &match));
+ if(!match)
+ return NULL;
+
+ throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(ElseIfStatement), (void**)&result));
+ throw_if_error(else_if_statement_init(result, self->current_scope, self->allocator));
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IF, &match));
+ if(match)
+ result->condition = parser_parse_rhs_binop(self);
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match));
+ if(match) {
+ parser_parse_body_loop(self, &result->body, TOK_CLOSING_BRACE);
+ } else {
+ Ast *body_obj;
+ body_obj = parser_parse_body(self);
+ throw_if_error(scope_add_child(&result->body, body_obj));
+ }
+
+ return result;
+}
+
+static void parser_parse_else_if_statement_loop(Parser *self, IfStatement *if_stmt) {
+ ElseIfStatement *else_if_stmt;
+ else_if_stmt = if_stmt->else_if_stmt;
+ for(;;) {
+ ElseIfStatement *next_else_if;
+ next_else_if = parser_parse_else_if_statement(self);
+ if(!next_else_if)
+ break;
+ else_if_stmt->next_else_if_stmt = next_else_if;
+ /* else statement, which because they have no conditions; can't be followed by another else statement */
+ if(!else_if_stmt->condition)
+ break;
+ else_if_stmt = next_else_if;
+ }
+}
+
+/*
+IF_STATEMENT = 'if' RHS_BINOP ('{' BODY_LOOP '}')|BODY ELSE_IF_STATEMENT*
+*/
+static CHECK_RESULT IfStatement* parser_parse_if_statement(Parser *self) {
+ IfStatement *result;
+ bool match;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IF, &match));
+ if(!match)
+ return NULL;
+
+ throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(IfStatement), (void**)&result));
+ throw_if_error(if_statement_init(result, self->current_scope, self->allocator));
+
+ result->condition = parser_parse_rhs_binop(self);
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match));
+ if(match) {
+ parser_parse_body_loop(self, &result->body, TOK_CLOSING_BRACE);
+ } else {
+ Ast *body_obj;
+ body_obj = parser_parse_body(self);
+ throw_if_error(scope_add_child(&result->body, body_obj));
+ }
+
+ parser_parse_else_if_statement_loop(self, result);
+ return result;
+}
+
+/*
+WHILE_STATEMENT = 'while' RHS_BINOP ('{' BODY_LOOP '}')|BODY
+*/
+static CHECK_RESULT WhileStatement* parser_parse_while_statement(Parser *self) {
+ WhileStatement *result;
+ bool match;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_WHILE, &match));
+ if(!match)
+ return NULL;
+
+ throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(WhileStatement), (void**)&result));
+ throw_if_error(while_statement_init(result, self->current_scope, self->allocator));
+
+ result->condition = parser_parse_rhs_binop(self);
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match));
+ if(match) {
+ parser_parse_body_loop(self, &result->body, TOK_CLOSING_BRACE);
+ } else {
+ Ast *body_obj;
+ body_obj = parser_parse_body(self);
+ throw_if_error(scope_add_child(&result->body, body_obj));
+ }
+
+ return result;
+}
+
static CHECK_RESULT Ast* parser_parse_number(Parser *self) {
Ast *result;
bool match;
@@ -388,8 +512,6 @@ static Ast* parser_parse_rhs_single_expr(Parser *self) {
throw(PARSER_UNEXPECTED_TOKEN);
}
-static CHECK_RESULT Ast* parser_parse_rhs_binop(Parser *self);
-
/*
RHS_BINOP_OPT_PAREN = RHS_S | '(' RHS_BINOP ')'
*/
@@ -442,7 +564,7 @@ RHS = RHS_BINOP ';'
Note: Parantheses count has to match for the beginning paranthesis and the ending parenthesis.
*/
-static CHECK_RESULT Ast* parser_parse_rhs(Parser *self) {
+Ast* parser_parse_rhs(Parser *self) {
/* TODO: If binop only contains one expression, then use that directly for @rhs_expr */
Ast *result;
result = parser_parse_rhs_binop(self);
@@ -452,41 +574,9 @@ static CHECK_RESULT Ast* parser_parse_rhs(Parser *self) {
return result;
}
-/*
-RHS_START = CLOSURE | IMPORT | RHS
-*/
-Ast* parser_parse_rhs_start(Parser *self, bool is_standalone) {
- Ast *result;
-
- if(!is_standalone) {
- FunctionDecl *func_decl;
- StructDecl *struct_decl;
- Import *import;
-
- func_decl = parser_parse_closure(self);
- if(func_decl) {
- throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &result));
- return result;
- }
-
- struct_decl = parser_parse_struct_decl(self);
- if(struct_decl) {
- throw_if_error(ast_create(self->allocator, struct_decl, AST_STRUCT_DECL, &result));
- return result;
- }
-
- import = parser_parse_import(self);
- if(import) {
- parser_queue_file(self, import->path, &import->file_scope);
- throw_if_error(ast_create(self->allocator, import, AST_IMPORT, &result));
- return result;
- }
- self->error_context = ERROR_CONTEXT_RHS_STANDALONE;
- }
-
- result = parser_parse_rhs(self);
- self->error_context = ERROR_CONTEXT_NONE;
- return result;
+static bool type_requires_semicolon_at_end(AstType type) {
+ /* TODO: Check for tables */
+ return type != AST_FUNCTION_DECL && type != AST_STRUCT_DECL && type != AST_IF_STATEMENT;
}
/*
@@ -508,37 +598,109 @@ static void parser_parse_body_semicolon(Parser *self, Ast *expr) {
return;
}
- /* TODO: Check for tables */
- if(expr->type != AST_FUNCTION_DECL && expr->type != AST_STRUCT_DECL)
+ if(type_requires_semicolon_at_end(expr->type))
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON));
}
+/* CONDITIONAL = (IF_STATEMENT|WHILE_STATEMENT)? */
+static CHECK_RESULT Ast* parser_parse_conditional(Parser *self) {
+ Ast *result;
+ IfStatement *if_stmt;
+ WhileStatement *while_stmt;
+
+ if_stmt = parser_parse_if_statement(self);
+ if(if_stmt) {
+ throw_if_error(ast_create(self->allocator, if_stmt, AST_IF_STATEMENT, &result));
+ self->error_context = ERROR_CONTEXT_NONE;
+ return result;
+ }
+
+ while_stmt = parser_parse_while_statement(self);
+ if(while_stmt) {
+ throw_if_error(ast_create(self->allocator, while_stmt, AST_WHILE_STATEMENT, &result));
+ self->error_context = ERROR_CONTEXT_NONE;
+ return result;
+ }
+
+ return NULL;
+}
+
/*
-BODY = LHS ';' |
- (LHS '=' RHS_START BODY_SEMICOLON) |
- (RHS_START BODY_SEMICOLON)
+BODY = (LHS_DECLARATION ';') |
+ (LHS_DECLARATION '=' CLOSURE|STRUCT|IMPORT|(RHS BODY_SEMICOLON)) |
+ CONDITIONAL |
+ (RHS ';'|('=' RHS BODY_SEMICOLON))
*/
Ast* parser_parse_body(Parser *self) {
- bool assignment_or_rhs;
Ast *result;
LhsExpr *lhs_expr;
Ast *rhs_expr;
- lhs_expr = parser_parse_lhs(self, &assignment_or_rhs);
- if(!assignment_or_rhs) {
+ lhs_expr = parser_parse_declaration_lhs(self);
+ if(lhs_expr) {
+ bool match;
throw_if_error(ast_create(self->allocator, lhs_expr, AST_LHS, &result));
- return result;
- }
-
- if(!lhs_expr)
+ if(lhs_expr->is_extern) {
+ throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON));
+ return result;
+ } else {
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_SEMICOLON, &match));
+ if(match)
+ return result;
+ }
+
+ throw_if_error(tokenizer_accept(&self->tokenizer, TOK_EQUALS));
+
+ FunctionDecl *func_decl;
+ StructDecl *struct_decl;
+ Import *import;
+
+ func_decl = parser_parse_closure(self);
+ if(func_decl) {
+ throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &lhs_expr->rhs_expr));
+ return result;
+ }
+
+ struct_decl = parser_parse_struct_decl(self);
+ if(struct_decl) {
+ throw_if_error(ast_create(self->allocator, struct_decl, AST_STRUCT_DECL, &lhs_expr->rhs_expr));
+ return result;
+ }
+
+ import = parser_parse_import(self);
+ if(import) {
+ parser_queue_file(self, import->path, &import->file_scope);
+ throw_if_error(ast_create(self->allocator, import, AST_IMPORT, &lhs_expr->rhs_expr));
+ parser_parse_body_semicolon(self, lhs_expr->rhs_expr);
+ return result;
+ }
+ } else {
self->error_context = ERROR_CONTEXT_NO_LHS;
+ result = parser_parse_conditional(self);
+ if(result)
+ return result;
+ }
- rhs_expr = parser_parse_rhs_start(self, !lhs_expr);
+ self->error_context = ERROR_CONTEXT_RHS_STANDALONE;
+ rhs_expr = parser_parse_rhs(self);
+ self->error_context = ERROR_CONTEXT_NONE;
if(lhs_expr) {
lhs_expr->rhs_expr = rhs_expr;
- throw_if_error(ast_create(self->allocator, lhs_expr, AST_LHS, &result));
} else {
- result = rhs_expr;
+ bool match;
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EQUALS, &match));
+ if(match) {
+ AssignmentExpr *assign_expr;
+ throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(AssignmentExpr), (void**)&assign_expr));
+ throw_if_error(ast_create(self->allocator, assign_expr, AST_ASSIGN, &result));
+ assign_expr->lhs_expr = rhs_expr;
+
+ self->error_context = ERROR_CONTEXT_RHS_STANDALONE;
+ assign_expr->rhs_expr = parser_parse_rhs(self);
+ self->error_context = ERROR_CONTEXT_NONE;
+ } else {
+ result = rhs_expr;
+ }
}
parser_parse_body_semicolon(self, rhs_expr);
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index c4ed0d3..91ba185 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -4,6 +4,7 @@
#include "../../include/std/hash.h"
#include "../../include/std/thread.h"
#include "../../include/ast.h"
+#include "../../include/compiler.h"
#include <assert.h>
#define throw(result) do { longjmp(context->env, (result)); } while(0)
@@ -59,7 +60,7 @@ int ssa_init(Ssa *self, ScopedAllocator *allocator) {
return 0;
}
-int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
+static CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
/* Overflow */
if(self->reg_counter + 1 < self->reg_counter)
return -1;
@@ -144,12 +145,13 @@ static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstruction ins_type, Ss
}
static const char* binop_type_to_string(SsaInstruction binop_type) {
- assert(binop_type >= SSA_ADD && binop_type <= SSA_DIV);
+ assert(binop_type >= SSA_ADD && binop_type <= SSA_EQUALS);
switch(binop_type) {
case SSA_ADD: return "+";
case SSA_SUB: return "-";
case SSA_MUL: return "*";
case SSA_DIV: return "/";
+ case SSA_EQUALS: return "==";
default: return "";
}
}
@@ -173,31 +175,31 @@ static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstruction ins_type, Ss
return 0;
}
-int ssa_ins_assign_inter(Ssa *self, SsaRegister dest, SsaNumber number) {
+static CHECK_RESULT int ssa_ins_assign_inter(Ssa *self, SsaRegister dest, SsaNumber number) {
SsaIntermediateIndex index;
return_if_error(ssa_try_add_intermediate(self, number, &index));
amal_log_debug("r%u = i%u", dest, index);
return ssa_add_ins_form1(self, SSA_ASSIGN_INTER, dest, index);
}
-int ssa_ins_assign_string(Ssa *self, SsaRegister dest, BufferView str) {
+static CHECK_RESULT int ssa_ins_assign_string(Ssa *self, SsaRegister dest, BufferView str) {
SsaStringIndex index;
return_if_error(ssa_try_add_string(self, str, &index));
amal_log_debug("r%u = s%u", dest, index);
return ssa_add_ins_form1(self, SSA_ASSIGN_STRING, dest, index);
}
-int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) {
+static CHECK_RESULT int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) {
amal_log_debug("r%u = r%u", dest, src);
return ssa_add_ins_form1(self, SSA_ASSIGN_REG, dest, src);
}
-int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
- assert(binop_type >= SSA_ADD && binop_type <= SSA_DIV);
+static CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
+ assert(binop_type >= SSA_ADD && binop_type <= SSA_EQUALS);
return ssa_add_ins_form2(self, binop_type, lhs, rhs, result);
}
-int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
+static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
usize index;
index = self->instructions.size;
@@ -214,14 +216,14 @@ int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
return 0;
}
-int ssa_ins_func_end(Ssa *self) {
+static CHECK_RESULT int ssa_ins_func_end(Ssa *self) {
u8 ins;
ins = SSA_FUNC_END;
amal_log_debug("FUNC_END");
return buffer_append(&self->instructions, &ins, 1);
}
-int ssa_ins_push(Ssa *self, SsaRegister reg) {
+static CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg) {
usize index;
index = self->instructions.size;
@@ -232,7 +234,7 @@ int ssa_ins_push(Ssa *self, SsaRegister reg) {
return 0;
}
-int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
+static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
usize index;
index = self->instructions.size;
@@ -249,31 +251,88 @@ int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
return 0;
}
+static CHECK_RESULT int ssa_ins_jumpzero(Ssa *self, SsaRegister condition_reg, JumpOffset jump_offset) {
+ usize index;
+ index = self->instructions.size;
+
+ return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(JumpOffset)));
+ self->instructions.data[index + 0] = SSA_JUMP_ZERO;
+ am_memcpy(self->instructions.data + index + 1, &condition_reg, sizeof(SsaRegister));
+ am_memcpy(self->instructions.data + index + 1 + sizeof(SsaRegister), &jump_offset, sizeof(JumpOffset));
+ if(jump_offset == 0)
+ amal_log_debug("JUMP_ZERO r%u, DUMMY", condition_reg);
+ else
+ amal_log_debug("JUMP_ZERO r%u, %d", condition_reg, jump_offset);
+ return 0;
+}
+
+static CHECK_RESULT int ssa_ins_jump(Ssa *self, JumpOffset jump_offset) {
+ usize index;
+ index = self->instructions.size;
+
+ return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(JumpOffset)));
+ self->instructions.data[index + 0] = SSA_JUMP;
+ am_memcpy(self->instructions.data + index + 1, &jump_offset, sizeof(JumpOffset));
+ amal_log_debug("JUMP %d", jump_offset);
+ return 0;
+}
+
+static usize ssa_ins_get_index(Ssa *self) {
+ return self->instructions.size;
+}
+
+/* Set target of jump instruction to current location */
+static CHECK_RESULT int ssa_ins_jump_set_target(Ssa *self, usize jump_ins_index) {
+ switch(self->instructions.data[jump_ins_index]) {
+ case SSA_JUMP_ZERO: {
+ isize jump_offset = (isize)ssa_ins_get_index(self) - (isize)jump_ins_index;
+ /* TODO: Should something be done about this? */
+ if(jump_offset < -0x7FFF || jump_offset > 0x7FFF) {
+ amal_log_error("Unexpected error. Jump offset has to be less than +-32767, was %d", jump_offset);
+ return 1;
+ }
+ am_memcpy(self->instructions.data + jump_ins_index + 1 + sizeof(SsaRegister), &jump_offset, sizeof(JumpOffset));
+ break;
+ }
+ default:
+ assert(bool_false && "Unexpected error... jump_ins_index doesn't point to a valid index to a jump instruction");
+ break;
+ }
+ return 0;
+}
+
static CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context);
static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerContext *context) {
SsaRegister reg;
SsaNumber number;
- if(self->is_integer) {
+ if(self->is_integer)
number = create_ssa_integer(self->value.integer);
- throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
- throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
- } else {
+ else
number = create_ssa_float(self->value.floating);
- throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
- throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
- }
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
return reg;
}
+static CHECK_RESULT SsaRegister lhsexpr_extern_generate_ssa(LhsExpr *self, SsaCompilerContext *context) {
+ /* TODO: SsaRegister should be extended to include static and extern data */
+ (void)self;
+ (void)context;
+ amal_log_error("TODO: Implement lhsexpr_extern_generate_ssa");
+ return 0;
+}
+
static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerContext *context) {
- /* TODO: Implement */
LhsExpr *lhs_expr;
SsaRegister reg;
assert(self->type == AST_LHS);
lhs_expr = self->value.lhs_expr;
+ if(lhs_expr->is_extern)
+ return lhsexpr_extern_generate_ssa(lhs_expr, context);
+
if(lhs_expr->rhs_expr) {
SsaRegister rhs_reg;
rhs_reg = ast_generate_ssa(lhs_expr->rhs_expr, context);
@@ -283,8 +342,10 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
Import expression also has no meaning in SSA until it's used.
TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types?
*/
- if(self->resolve_data.type == lhs_expr || lhs_expr->rhs_expr->type == AST_IMPORT)
+ if(self->resolve_data.type == lhs_expr || lhs_expr->rhs_expr->type == AST_IMPORT) {
+ /*assert(bool_false);*/
return 0;
+ }
throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
if(reg == rhs_reg) {
amal_log_error("rhs_expr is same as reg.. rhs type: %d", lhs_expr->rhs_expr->type);
@@ -292,12 +353,33 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
assert(reg != rhs_reg);
throw_if_error(ssa_ins_assign_reg(context->ssa, reg, rhs_reg));
} else {
- /* TODO: assign default value to reg depending on LhsExpr type */
- reg = 0;
+ /* TODO: Do not assign if we dont want default value */
+ SsaNumber number;
+ if(self->resolve_data.type == context->compiler->default_types.i64)
+ number = create_ssa_integer(0);
+ else if(self->resolve_data.type == context->compiler->default_types.f64)
+ number = create_ssa_float(0.0);
+ else
+ assert(bool_false && "TODO: assign default value to reg depending on LhsExpr type");
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
}
return reg;
}
+static CHECK_RESULT SsaRegister assignmentexpr_generate_ssa(Ast *ast, SsaCompilerContext *context) {
+ AssignmentExpr *self;
+ SsaRegister lhs_reg, rhs_reg;
+
+ assert(ast->type == AST_ASSIGN);
+ self = ast->value.assign_expr;
+
+ lhs_reg = ast_generate_ssa(self->lhs_expr, context);
+ rhs_reg = ast_generate_ssa(self->rhs_expr, context);
+ throw_if_error(ssa_ins_assign_reg(context->ssa, lhs_reg, rhs_reg));
+ return lhs_reg;
+}
+
/*
TODO: Each function declaration should be in separate SSA instances so ast can be converted into ssa
in any order.
@@ -314,6 +396,7 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
throw_if_error(ssa_ins_func_end(context->ssa));
context->ssa->reg_counter = prev_reg_counter;
+ /*assert(bool_false);*/
return 0;
}
@@ -348,12 +431,14 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont
static CHECK_RESULT SsaRegister structdecl_generate_ssa(StructDecl *self, SsaCompilerContext *context) {
/* TODO: Implement */
+ /*assert(bool_false);*/
scope_generate_ssa(&self->body, context);
return 0;
}
static CHECK_RESULT SsaRegister structfield_generate_ssa(StructField *self, SsaCompilerContext *context) {
/* TODO: Implement */
+ /*assert(bool_false);*/
(void)self;
(void)context;
return 0;
@@ -367,10 +452,10 @@ static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerCon
}
static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) {
- /* TODO: Implement, and with cross field references */
- (void)self;
- (void)context;
- return 0;
+ /* TODO: If resolved_var refers to a variable in another file, use a cross file reference that requires no locking (not yet implemented) */
+ /* This is not thread-safe:*/
+ assert(self->resolved_var);
+ return ast_generate_ssa(self->resolved_var, context);
}
static SsaInstruction binop_type_to_ssa_type(BinopType binop_type) {
@@ -386,6 +471,8 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type) {
case BINOP_DOT:
assert(bool_false && "Binop dot not valid for arithmetic operation and requires special functionality");
return 0;
+ case BINOP_EQUALS:
+ return SSA_EQUALS;
}
return 0;
}
@@ -405,7 +492,57 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte
return reg;
}
-CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context) {
+static void else_if_statement_generate_ssa(ElseIfStatement *else_if_stmt, SsaCompilerContext *context) {
+ usize jump_ins_index;
+ if(else_if_stmt->condition) {
+ SsaRegister condition_reg;
+ condition_reg = ast_generate_ssa(else_if_stmt->condition, context);
+ jump_ins_index = ssa_ins_get_index(context->ssa);
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ }
+ scope_generate_ssa(&else_if_stmt->body, context);
+ if(else_if_stmt->condition)
+ throw_if_error(ssa_ins_jump_set_target(context->ssa, jump_ins_index));
+ if(else_if_stmt->next_else_if_stmt)
+ else_if_statement_generate_ssa(else_if_stmt->next_else_if_stmt, context);
+}
+
+static void if_statement_generate_ssa(IfStatement *if_stmt, SsaCompilerContext *context) {
+ SsaRegister condition_reg;
+ usize jump_ins_index;
+
+ condition_reg = ast_generate_ssa(if_stmt->condition, context);
+ jump_ins_index = ssa_ins_get_index(context->ssa);
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ scope_generate_ssa(&if_stmt->body, context);
+ throw_if_error(ssa_ins_jump_set_target(context->ssa, jump_ins_index));
+ if(if_stmt->else_if_stmt)
+ else_if_statement_generate_ssa(if_stmt->else_if_stmt, context);
+}
+
+static void while_statement_generate_ssa(WhileStatement *while_stmt, SsaCompilerContext *context) {
+ SsaRegister condition_reg;
+ usize jump_back_ins_index;
+ usize jump_condition_ins_index;
+ isize jump_offset;
+
+ jump_back_ins_index = ssa_ins_get_index(context->ssa);
+ condition_reg = ast_generate_ssa(while_stmt->condition, context);
+ jump_condition_ins_index = ssa_ins_get_index(context->ssa);
+ throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0));
+ scope_generate_ssa(&while_stmt->body, context);
+ /* Jump back and check condition again before running the content of the loop again */
+ jump_offset = (isize)jump_back_ins_index - (isize)ssa_ins_get_index(context->ssa);
+ /* TODO: Should something be done about this? */
+ if(jump_offset < -0x7FFF || jump_offset > 0x7FFF) {
+ amal_log_error("Unexpected error. Jump offset has to be less than +-32767, was %d", jump_offset);
+ throw(1);
+ }
+ throw_if_error(ssa_ins_jump(context->ssa, (JumpOffset)jump_offset));
+ throw_if_error(ssa_ins_jump_set_target(context->ssa, jump_condition_ins_index));
+}
+
+static CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context) {
assert(self);
#ifdef DEBUG
if(self->resolve_data.status != AST_RESOLVED && self->resolve_data.status != AST_SSA_RESOLVED) {
@@ -420,48 +557,48 @@ CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context
switch(self->type) {
case AST_NUMBER:
self->ssa_reg = number_generate_ssa(self->value.number, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_FUNCTION_DECL:
self->ssa_reg = funcdecl_generate_ssa(self->value.func_decl, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_FUNCTION_CALL:
self->ssa_reg = funccall_generate_ssa(self, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_STRUCT_DECL:
self->ssa_reg = structdecl_generate_ssa(self->value.struct_decl, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_STRUCT_FIELD:
self->ssa_reg = structfield_generate_ssa(self->value.struct_field, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_LHS:
self->ssa_reg = lhsexpr_generate_ssa(self, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
+ case AST_ASSIGN:
+ self->ssa_reg = assignmentexpr_generate_ssa(self, context);
+ break;
case AST_IMPORT:
/* TODO: Implement cross file references */
self->ssa_reg = 0;
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_STRING:
self->ssa_reg = string_generate_ssa(self->value.string, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_VARIABLE:
self->ssa_reg = variable_generate_ssa(self->value.variable, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
case AST_BINOP:
self->ssa_reg = binop_generate_ssa(self->value.binop, context);
- self->resolve_data.status = AST_SSA_RESOLVED;
- return self->ssa_reg;
+ break;
+ case AST_IF_STATEMENT:
+ if_statement_generate_ssa(self->value.if_stmt, context);
+ break;
+ case AST_WHILE_STATEMENT:
+ while_statement_generate_ssa(self->value.while_stmt, context);
+ break;
}
- return 0;
+ self->resolve_data.status = AST_SSA_RESOLVED;
+ return self->ssa_reg;
}
void scope_generate_ssa(Scope *self, SsaCompilerContext *context) {
diff --git a/src/tokenizer.c b/src/tokenizer.c
index 7f6d08e..03a72a1 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -170,6 +170,9 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
if(am_memeql(self->value.identifier.data, "fn", 2)) {
*token = TOK_FN;
return TOKENIZER_OK;
+ } else if(am_memeql(self->value.identifier.data, "if", 2)) {
+ *token = TOK_IF;
+ return TOKENIZER_OK;
}
break;
}
@@ -183,10 +186,20 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
}
break;
}
+ case 4: {
+ if(am_memeql(self->value.identifier.data, "else", 4)) {
+ *token = TOK_ELSE;
+ return TOKENIZER_OK;
+ }
+ break;
+ }
case 5: {
if(am_memeql(self->value.identifier.data, "const", 5)) {
*token = TOK_CONST;
return TOKENIZER_OK;
+ } else if(am_memeql(self->value.identifier.data, "while", 5)) {
+ *token = TOK_WHILE;
+ return TOKENIZER_OK;
}
break;
}
@@ -194,6 +207,9 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
if(am_memeql(self->value.identifier.data, "struct", 6)) {
*token = TOK_STRUCT;
return TOKENIZER_OK;
+ } else if(am_memeql(self->value.identifier.data, "extern", 6)) {
+ *token = TOK_EXTERN;
+ return TOKENIZER_OK;
}
break;
}
@@ -288,7 +304,12 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
SET_BINOP(BINOP_DIV);
} else if(c == '=') {
++self->index;
- *token = TOK_EQUALS;
+ if(self->index < (int)self->code.size && tokenizer_get_char(self) == '=') {
+ ++self->index;
+ SET_BINOP(BINOP_EQUALS);
+ } else {
+ *token = TOK_EQUALS;
+ }
} else if(c == '(') {
++self->index;
*token = TOK_OPEN_PAREN;
@@ -450,6 +471,18 @@ static BufferView tokenizer_expected_token_as_string(Token token) {
case TOK_PUB:
str = "pub";
break;
+ case TOK_IF:
+ str = "if";
+ break;
+ case TOK_ELSE:
+ str = "else";
+ break;
+ case TOK_WHILE:
+ str = "while";
+ break;
+ case TOK_EXTERN:
+ str = "extern";
+ break;
}
return create_buffer_view(str, strlen(str));
}
@@ -588,18 +621,15 @@ int tokenizer_get_end_of_multiline_comment(Tokenizer *self, int index) {
int comment_count;
comment_count = 1;
+ ++index;
while(index < (int)self->code.size) {
c = self->code.data[index];
- if(c == '*') {
- if(index - 1 >= 0 && self->code.data[index - 1] == '/') {
- ++comment_count;
- }
- } else if(c == '/') {
- if(index - 1 >= 0 && self->code.data[index - 1] == '*') {
- --comment_count;
- if(comment_count == 0)
- return index + 1;
- }
+ if(c == '*' && self->code.data[index - 1] == '/') {
+ ++comment_count;
+ } else if(c == '/' && self->code.data[index - 1] == '*') {
+ --comment_count;
+ if(comment_count == 0)
+ return index + 1;
}
++index;
}
@@ -625,7 +655,61 @@ static int max(int a, int b) {
return a > b ? a : b;
}
+void tokenizer_print_error_args(Tokenizer *self, int index, const char *fmt, va_list args) {
+ int line;
+ int line_start;
+ int line_end;
+ /*int code_start;*/
+ int prev_column;
+ int i;
+
+ line = tokenizer_get_line_by_index(self, index);
+ line_start = tokenizer_get_start_of_line_from_index(self, index);
+ line_end = tokenizer_get_end_of_line_from_index(self, index);
+ /*code_start = find_non_whitespace(&self->code.data[line_start], line_end - line_start);
+ if(code_start != -1)
+ line_start += code_start;*/
+ prev_column = index - line_start;
+
+ if(self->compiler_options->error_callback) {
+ char buffer[2048];
+ int bytes_copied;
+
+ bytes_copied = 0;
+ bytes_copied += max(0, snprintf(buffer + bytes_copied, sizeof(buffer) - bytes_copied, "%.*s:%d:%d: error: ", (int)self->code_name.size, self->code_name.data, line, 1 + prev_column));
+
+ if(sizeof(buffer) - bytes_copied > 0) {
+ bytes_copied += max(0, vsnprintf(buffer + bytes_copied, sizeof(buffer) - bytes_copied, fmt, args));
+ }
+
+ if(sizeof(buffer) - bytes_copied > 0)
+ bytes_copied += max(0, snprintf(buffer + bytes_copied, sizeof(buffer) - bytes_copied, "\n%.*s\n", line_end - line_start, self->code.data + line_start));
+
+ if(sizeof(buffer) - bytes_copied > 0) {
+ for(i = 0; i < prev_column; ++i)
+ bytes_copied += max(0, snprintf(buffer + bytes_copied, sizeof(buffer) - bytes_copied, " "));
+ }
+
+ if(sizeof(buffer) - bytes_copied > 0)
+ bytes_copied += max(0, snprintf(buffer + bytes_copied, sizeof(buffer) - bytes_copied, "^\n"));
+
+ self->compiler_options->error_callback(buffer, bytes_copied, self->compiler_options->error_callback_userdata);
+ } else {
+ amal_mutex *mutex;
+ mutex = amal_log_get_mutex();
+ ignore_result_int(amal_mutex_lock(mutex, "tokenizer_print_error"));
+ fprintf(stderr, "\x1b[1;37m%.*s:%d:%d:\x1b[0m \x1b[1;31merror:\x1b[0m ", (int)self->code_name.size, self->code_name.data, line, 1 + prev_column);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n%.*s\n", line_end - line_start, self->code.data + line_start);
+ for(i = 0; i < prev_column; ++i)
+ fprintf(stderr, " ");
+ fprintf(stderr, "\x1b[1;32m^\x1b[0m\n");
+ ignore_result_int(amal_mutex_unlock(mutex));
+ }
+}
+
void tokenizer_print_error(Tokenizer *self, int index, const char *fmt, ...) {
+#if 0
va_list args;
int line;
int line_start;
@@ -681,6 +765,11 @@ void tokenizer_print_error(Tokenizer *self, int index, const char *fmt, ...) {
va_end(args);
ignore_result_int(amal_mutex_unlock(mutex));
}
+#endif
+ va_list args;
+ va_start(args, fmt);
+ tokenizer_print_error_args(self, index, fmt, args);
+ va_end(args);
}
void tokenizer_print_error_object(Tokenizer *self, TokenizerError *error) {