diff options
-rwxr-xr-x | build.sh | 2 | ||||
-rw-r--r-- | include/ast.h | 15 | ||||
-rw-r--r-- | include/compiler.h | 2 | ||||
-rw-r--r-- | include/number.h | 21 | ||||
-rw-r--r-- | include/tokenizer.h | 5 | ||||
-rw-r--r-- | src/ast.c | 147 | ||||
-rw-r--r-- | src/compiler.c | 87 | ||||
-rw-r--r-- | src/parser.c | 3 | ||||
-rw-r--r-- | src/ssa/ssa.c | 25 | ||||
-rw-r--r-- | src/std/thread.c | 4 | ||||
-rw-r--r-- | src/tokenizer.c | 83 | ||||
-rw-r--r-- | tests/bytecode.amal | 11 | ||||
-rw-r--r-- | tests/glfw.amal | 7 |
13 files changed, 286 insertions, 126 deletions
@@ -10,7 +10,7 @@ source_files=$(find "src" -name "*.c") cpu_arch="$ARCH" if [ -z "$ARCH" ]; then cpu_arch=$(uname -m) - echo "Cpu architecture detected: $cpu_arch." 'You can override the architecture with the environment variable $ARCH' + echo "Cpu architecture detected: $cpu_arch." 'You can override the architecture with the $ARCH environment variable.' fi if [ "$cpu_arch" = "x86_64" ]; then diff --git a/include/ast.h b/include/ast.h index c45d4aa..f62d31f 100644 --- a/include/ast.h +++ b/include/ast.h @@ -9,6 +9,7 @@ #include "std/misc.h" #include "std/arena_allocator.h" #include "std/hash_map.h" +#include "number.h" #include "binop_type.h" #include "ssa/ssa.h" @@ -209,6 +210,7 @@ struct StructDecl { u32 fields_num_pointers; /* The total size of all fields which are of a type that have the same size on all platforms (i.e u8, i32, etc), recursive */ u32 fields_fixed_size_bytes; + bool is_signed; /* Only default arithmetic types can be signed, everything else is unsigned */ }; struct StructField { @@ -260,11 +262,7 @@ struct String { }; struct Number { - union { - i64 integer; - f64 floating; - } value; - bool is_integer; + AmalNumber value; BufferView code_ref; }; @@ -307,10 +305,7 @@ typedef struct { jmp_buf env; amal_compiler *compiler; /* Borrowed */ Parser *parser; /* Borrowed. This is the parser that belongs to the thread */ - /* - Borrowed. This is the current scope. Note that this scope can belong to another parser (and thread), - as such, @parser and scope_get_parser(@scope) parser may not be the same. - */ + /* Borrowed. This is the current scope. Note that this scope can belong to another parser (and thread) */ Scope *scope; } AstCompilerContext; @@ -336,7 +331,7 @@ void lhsexpr_init(LhsExpr *self, DeclFlag decl_flag, BufferView var_name); void assignmentexpr_init(AssignmentExpr *self, Ast *lhs_expr, Ast *rhs_expr); void import_init(Import *self, BufferView path); CHECK_RESULT int string_init(String *self, BufferView str); -void number_init(Number *self, i64 value, bool is_integer, BufferView code_ref); +void number_init(Number *self, AmalNumber *value, BufferView code_ref); void variable_init(Variable *self, BufferView name); void binop_init(Binop *self); CHECK_RESULT int if_statement_init(IfStatement *self, Scope *parent, ArenaAllocator *allocator); diff --git a/include/compiler.h b/include/compiler.h index 164cf4e..481a107 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -19,7 +19,6 @@ typedef struct { LhsExpr lhs_expr; - bool is_signed; } amal_default_type; typedef struct { @@ -50,6 +49,7 @@ typedef struct { } amal_default_types; bool is_arithmetic_type(LhsExpr *expr, amal_compiler *compiler); +bool amal_default_type_is_signed(amal_default_type *self); struct amal_compiler { amal_default_types default_types; diff --git a/include/number.h b/include/number.h new file mode 100644 index 0000000..a87d5fa --- /dev/null +++ b/include/number.h @@ -0,0 +1,21 @@ +#ifndef AMAL_NUMBER_H +#define AMAL_NUMBER_H + +#include "std/types.h" + +typedef enum { + AMAL_NUMBER_SIGNED_INTEGER, + AMAL_NUMBER_UNSIGNED_INTEGER, + AMAL_NUMBER_FLOAT +} AmalNumberType; + +typedef struct { + union { + i64 integer; + f64 floating; + } value; + int bits; + AmalNumberType type; +} AmalNumber; + +#endif diff --git a/include/tokenizer.h b/include/tokenizer.h index f716ab2..ceb7acf 100644 --- a/include/tokenizer.h +++ b/include/tokenizer.h @@ -5,6 +5,7 @@ #include "std/misc.h" #include "std/defs.h" #include "defs.h" +#include "number.h" #include "binop_type.h" #include "compiler_options.h" #include <stdarg.h> @@ -62,11 +63,9 @@ struct Tokenizer { union { BufferView identifier; BufferView string; - i64 integer; - f64 floating; BinopType binop_type; } value; - bool number_is_integer; + AmalNumber number; ArenaAllocator *allocator; /* borrowed */ const amal_compiler_options *compiler_options; /* borrowed */ }; @@ -299,6 +299,7 @@ int funccall_init(FunctionCall *self, BufferView name, ArenaAllocator *allocator int structdecl_init(StructDecl *self, Scope *parent, ArenaAllocator *allocator) { self->fields_num_pointers = 0; self->fields_fixed_size_bytes = 0; + self->is_signed = bool_false; return scope_init(&self->body, parent, allocator); } @@ -346,9 +347,8 @@ int string_init(String *self, BufferView str) { return 0; } -void number_init(Number *self, i64 value, bool is_integer, BufferView code_ref) { - self->value.integer = value; - self->is_integer = is_integer; +void number_init(Number *self, AmalNumber *value, BufferView code_ref) { + self->value = *value; self->code_ref = code_ref; } @@ -659,7 +659,7 @@ static void assignmentexpr_resolve(Ast *ast, AstCompilerContext *context) { /* This also covers extern variables, since extern variables are always const */ /* TODO: var.field type expressions should also be checked */ if(is_lhs_const) { - compiler_print_error(context->compiler, ast_get_code_reference(self->lhs_expr).data, "Can't assign to a const value"); + compiler_print_error(context->compiler, ast_get_code_reference(self->lhs_expr).data, "Can't assign to a const variable"); throw(AST_ERR); } @@ -757,7 +757,31 @@ static bool is_function_arg_compatible_with_parameter(AstResolvedType *arg, Func function_parameter_is_vararg(param, context); } -static void verify_func_call_matches_func_signature(FunctionCall *func_call, FunctionSignature *func_sig, AstCompilerContext *context) { +/* Pointers, isize and usize are returned with size 4, as that is the smallest possible size for them */ +static int arithmetic_type_get_size(StructDecl *self) { + assert(sizeof(usize) >= 4 && "Make this work when size of pointer is less than 4"); + return self->fields_num_pointers * 4 + self->fields_fixed_size_bytes; +} + +static bool is_implicit_cast_possible(AstResolvedType *from, FunctionParameter *to, AstCompilerContext *context) { + if(from->type == RESOLVED_TYPE_LHS_EXPR && to->resolve_data.type.type == RESOLVED_TYPE_LHS_EXPR) { + LhsExpr *from_lhs_expr = from->value.lhs_expr; + LhsExpr *to_lhs_expr = to->resolve_data.type.value.lhs_expr; + assert(to_lhs_expr->rhs_expr && to_lhs_expr->rhs_expr->type == AST_STRUCT_DECL); + /* TODO: Optimize, dont use is_arithmetic_type */ + if(is_arithmetic_type(from_lhs_expr, context->compiler) && is_arithmetic_type(to_lhs_expr, context->compiler)) { + StructDecl *from_struct_type = from_lhs_expr->rhs_expr->value.struct_decl; + StructDecl *to_struct_type = to_lhs_expr->rhs_expr->value.struct_decl; + assert(from_lhs_expr->rhs_expr->type == AST_STRUCT_DECL); + /* TODO: Also allow implicit cast if @from variable is const and if the const value can be cast to @to without data loss */ + /* TODO: Allow cast between signed<->unsigned if the value is known at compile-time and if it can be cast without data loss */ + return arithmetic_type_get_size(from_struct_type) <= arithmetic_type_get_size(to_struct_type) && from_struct_type->is_signed == to_struct_type->is_signed; + } + } + return bool_false; +} + +static void funccall_resolve_signature_types(FunctionCall *func_call, FunctionSignature *func_sig, AstCompilerContext *context) { Ast **arg = buffer_begin(&func_call->args); Ast **arg_end = buffer_end(&func_call->args); @@ -771,11 +795,18 @@ static void verify_func_call_matches_func_signature(FunctionCall *func_call, Fun usize i = 0; for(; i < num_check; ++i) { if(!is_function_arg_compatible_with_parameter(&(*arg)->resolve_data.type, func_param, context)) { - BufferView arg_name = ast_resolved_type_get_name(&(*arg)->resolve_data.type); - BufferView param_name = ast_resolved_type_get_name(&func_param->resolve_data.type); - compiler_print_error(context->compiler, func_call->func.name.data, - "Can't cast argument of type \"%.*s\" to parameter of type \"%.*s\"", arg_name.size, arg_name.data, param_name.size, param_name.data); - throw(AST_ERR); + /* TODO: Cast data to larger size? */ + if(!is_implicit_cast_possible(&(*arg)->resolve_data.type, func_param, context)) { + BufferView arg_name = ast_resolved_type_get_name(&(*arg)->resolve_data.type); + BufferView param_name = ast_resolved_type_get_name(&func_param->resolve_data.type); + /* + TODO: Use arg as tokenizer reference, but the name is generated right now so it doesn't belong to the tokenizer; + so the reference cant be used. + */ + compiler_print_error(context->compiler, func_call->func.name.data, + "Can't implicitly cast argument of type \"%.*s\" to parameter of type \"%.*s\"", arg_name.size, arg_name.data, param_name.size, param_name.data); + throw(AST_ERR); + } } ++arg; ++func_param; @@ -826,7 +857,7 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) { ast_resolve(*ast, context); } - verify_func_call_matches_func_signature(func_call, func_sig, context); + funccall_resolve_signature_types(func_call, func_sig, context); } static TypeSize variable_type_get_byte_size(VariableType *self) { @@ -1057,6 +1088,88 @@ TypeSize resolved_type_get_byte_size(AstResolvedType *self) { return type_size; } +static void signed_integer_resolve(Ast *self, AstCompilerContext *context) { + Number *number = self->value.number; + assert(number->value.type == AMAL_NUMBER_SIGNED_INTEGER); + switch(number->value.bits) { + case 8: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.i8->lhs_expr; + break; + case 16: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.i16->lhs_expr; + break; + case 32: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.i32->lhs_expr; + break; + case 64: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.i64->lhs_expr; + break; + default: { + compiler_print_error(context->compiler, ast_get_code_reference(self).data, "Currently only 8, 16, 32 and 64 bit integers are supported. TODO: Support arbitrary size integer"); + throw(AST_ERR); + break; + } + } +} + +static void unsigned_integer_resolve(Ast *self, AstCompilerContext *context) { + Number *number = self->value.number; + assert(number->value.type == AMAL_NUMBER_UNSIGNED_INTEGER); + switch(number->value.bits) { + case 8: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.u8->lhs_expr; + break; + case 16: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.u16->lhs_expr; + break; + case 32: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.u32->lhs_expr; + break; + case 64: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.u64->lhs_expr; + break; + default: { + compiler_print_error(context->compiler, ast_get_code_reference(self).data, "Currently only 8, 16, 32 and 64 bit integers are supported. TODO: Support arbitrary size integer"); + throw(AST_ERR); + break; + } + } +} + +static void float_resolve(Ast *self, AstCompilerContext *context) { + Number *number = self->value.number; + assert(number->value.type == AMAL_NUMBER_FLOAT); + switch(number->value.bits) { + case 32: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.f32->lhs_expr; + break; + case 64: + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.f64->lhs_expr; + break; + default: { + compiler_print_error(context->compiler, ast_get_code_reference(self).data, "Currently only 32 and 64 bit floats are supported. TODO: Support arbitrary size float"); + throw(AST_ERR); + break; + } + } +} + +static void number_resolve(Ast *self, AstCompilerContext *context) { + Number *number = self->value.number; + self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; + switch(number->value.type) { + case AMAL_NUMBER_SIGNED_INTEGER: + signed_integer_resolve(self, context); + break; + case AMAL_NUMBER_UNSIGNED_INTEGER: + unsigned_integer_resolve(self, context); + break; + case AMAL_NUMBER_FLOAT: + float_resolve(self, context); + break; + } +} + void ast_resolve(Ast *self, AstCompilerContext *context) { assert(self); assert(context->parser); @@ -1090,17 +1203,9 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { self->resolve_data.status = AST_RESOLVING; self->parser = context->parser; switch(self->type) { - case AST_NUMBER: { - Number *number; - number = self->value.number; - /* TODO: Support other number types */ - self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; - if(number->is_integer) - self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.i64->lhs_expr; - else - self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.f64->lhs_expr; + case AST_NUMBER: + number_resolve(self, context); break; - } case AST_FUNCTION_DECL: funcdecl_resolve(self, context); break; diff --git a/src/compiler.c b/src/compiler.c index 5b48aaf..46d20a8 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -24,8 +24,8 @@ static usize strnlen(const char *str, usize max_length) { return len; } -/* TODO: Allow to specify size and members? */ -static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char *name, u32 num_pointers, u32 fixed_size, amal_default_type **default_type) { +/* TODO: Allow to specify members? */ +static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char *name, u32 num_pointers, u32 fixed_size, amal_default_type **default_type, bool is_signed) { StructDecl *struct_decl; Ast *expr; LhsExpr *lhs_expr; @@ -34,6 +34,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)); struct_decl->fields_num_pointers = num_pointers; struct_decl->fields_fixed_size_bytes = fixed_size; + struct_decl->is_signed = is_signed; return_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(amal_default_type), (void**)default_type)); lhs_expr = &(*default_type)->lhs_expr; @@ -48,41 +49,46 @@ static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char return scope_add_child(&compiler->root_scope, expr); } -static CHECK_RESULT int create_default_type_num_pointers(amal_compiler *compiler, const char *name, u32 num_pointers, amal_default_type **default_type) { - return create_default_type(compiler, name, num_pointers, 0, default_type); +static CHECK_RESULT int create_default_type_num_pointers(amal_compiler *compiler, const char *name, u32 num_pointers, amal_default_type **default_type, bool is_signed) { + return create_default_type(compiler, name, num_pointers, 0, default_type, is_signed); } -static CHECK_RESULT int create_default_type_fixed_size(amal_compiler *compiler, const char *name, u32 byte_size, amal_default_type **default_type) { - return create_default_type(compiler, name, 0, byte_size, default_type); +static CHECK_RESULT int create_default_type_fixed_size(amal_compiler *compiler, const char *name, u32 byte_size, amal_default_type **default_type, bool is_signed) { + return create_default_type(compiler, name, 0, byte_size, default_type, is_signed); } static CHECK_RESULT int init_default_types(amal_compiler *compiler) { - /* POD */ - return_if_error(create_default_type_fixed_size(compiler, "i8", 1, &compiler->default_types.i8)); - return_if_error(create_default_type_fixed_size(compiler, "i16", 2, &compiler->default_types.i16)); - return_if_error(create_default_type_fixed_size(compiler, "i32", 4, &compiler->default_types.i32)); - return_if_error(create_default_type_fixed_size(compiler, "i64", 8, &compiler->default_types.i64)); - return_if_error(create_default_type_fixed_size(compiler, "u8", 1, &compiler->default_types.u8)); - return_if_error(create_default_type_fixed_size(compiler, "u16", 2, &compiler->default_types.u16)); - return_if_error(create_default_type_fixed_size(compiler, "u32", 4, &compiler->default_types.u32)); - return_if_error(create_default_type_fixed_size(compiler, "u64", 8, &compiler->default_types.u64)); - return_if_error(create_default_type_num_pointers(compiler, "isize", 1, &compiler->default_types.isize)); - return_if_error(create_default_type_num_pointers(compiler, "usize", 1, &compiler->default_types.usize)); - return_if_error(create_default_type_fixed_size(compiler, "f32", 4, &compiler->default_types.f32)); - return_if_error(create_default_type_fixed_size(compiler, "f64", 8, &compiler->default_types.f64)); - return_if_error(create_default_type_fixed_size(compiler, "bool", 1, &compiler->default_types.bool)); + /* Plain old datatype */ + return_if_error(create_default_type_fixed_size(compiler, "i8", 1, &compiler->default_types.i8, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "i16", 2, &compiler->default_types.i16, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "i32", 4, &compiler->default_types.i32, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "i64", 8, &compiler->default_types.i64, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "u8", 1, &compiler->default_types.u8, bool_false)); + return_if_error(create_default_type_fixed_size(compiler, "u16", 2, &compiler->default_types.u16, bool_false)); + return_if_error(create_default_type_fixed_size(compiler, "u32", 4, &compiler->default_types.u32, bool_false)); + return_if_error(create_default_type_fixed_size(compiler, "u64", 8, &compiler->default_types.u64, bool_false)); + return_if_error(create_default_type_num_pointers(compiler, "isize", 1, &compiler->default_types.isize, bool_true)); + return_if_error(create_default_type_num_pointers(compiler, "usize", 1, &compiler->default_types.usize, bool_false)); + return_if_error(create_default_type_fixed_size(compiler, "f32", 4, &compiler->default_types.f32, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "f64", 8, &compiler->default_types.f64, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "bool", 1, &compiler->default_types.bool, bool_false)); /* TODO: str should be a struct with the fields @data (ptr) and @size (usize) */ /* Types with more than one member */ - return_if_error(create_default_type_num_pointers(compiler, "str", 1, &compiler->default_types.str)); + return_if_error(create_default_type_num_pointers(compiler, "str", 1, &compiler->default_types.str, bool_false)); /* C types */ - return_if_error(create_default_type_fixed_size(compiler, "c_char", sizeof(char), &compiler->default_types.c_char)); - return_if_error(create_default_type_fixed_size(compiler, "c_short", sizeof(short), &compiler->default_types.c_short)); - return_if_error(create_default_type_fixed_size(compiler, "c_int", sizeof(int), &compiler->default_types.c_int)); - return_if_error(create_default_type_fixed_size(compiler, "c_long", sizeof(long), &compiler->default_types.c_long)); - return_if_error(create_default_type_num_pointers(compiler, "c_void", 0, &compiler->default_types.c_void)); - return_if_error(create_default_type_num_pointers(compiler, "...", 0, &compiler->default_types.c_varargs)); + /* + TODO: Have special handling for these. The size of these types should be the size of the C types + as they are on the machine that runs the final program, not the size of the machine that compiled + the program. + */ + return_if_error(create_default_type_fixed_size(compiler, "c_char", sizeof(char), &compiler->default_types.c_char, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "c_short", sizeof(short), &compiler->default_types.c_short, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "c_int", sizeof(int), &compiler->default_types.c_int, bool_true)); + return_if_error(create_default_type_fixed_size(compiler, "c_long", sizeof(long), &compiler->default_types.c_long, bool_true)); + return_if_error(create_default_type_num_pointers(compiler, "c_void", 0, &compiler->default_types.c_void, bool_false)); + return_if_error(create_default_type_num_pointers(compiler, "...", 0, &compiler->default_types.c_varargs, bool_false)); compiler->default_types.arithmetic_types[0] = compiler->default_types.i8; compiler->default_types.arithmetic_types[1] = compiler->default_types.u8; @@ -99,28 +105,6 @@ static CHECK_RESULT int init_default_types(amal_compiler *compiler) { compiler->default_types.arithmetic_types[11] = compiler->default_types.c_short; compiler->default_types.arithmetic_types[12] = compiler->default_types.c_int; compiler->default_types.arithmetic_types[13] = compiler->default_types.c_long; - - compiler->default_types.i8->is_signed = bool_true; - compiler->default_types.u8->is_signed = bool_false; - compiler->default_types.i16->is_signed = bool_true; - compiler->default_types.u16->is_signed = bool_false; - compiler->default_types.i32->is_signed = bool_true; - compiler->default_types.u32->is_signed = bool_false; - compiler->default_types.i64->is_signed = bool_true; - compiler->default_types.u64->is_signed = bool_false; - compiler->default_types.isize->is_signed = bool_true; - compiler->default_types.usize->is_signed = bool_false; - compiler->default_types.f32->is_signed = bool_true; - compiler->default_types.f64->is_signed = bool_true; - compiler->default_types.bool->is_signed = bool_false; - compiler->default_types.str->is_signed = bool_false; - - compiler->default_types.c_char->is_signed = bool_true; - compiler->default_types.c_short->is_signed = bool_true; - compiler->default_types.c_int->is_signed = bool_true; - compiler->default_types.c_long->is_signed = bool_true; - compiler->default_types.c_void->is_signed = bool_false; - compiler->default_types.c_varargs->is_signed = bool_false; return 0; } @@ -135,6 +119,11 @@ bool is_arithmetic_type(LhsExpr *expr, amal_compiler *compiler) { return bool_false; } +bool amal_default_type_is_signed(amal_default_type *self) { + assert(self->lhs_expr.rhs_expr && self->lhs_expr.rhs_expr->type == AST_STRUCT_DECL); + return self->lhs_expr.rhs_expr->value.struct_decl->is_signed; +} + void amal_compiler_options_init(amal_compiler_options *self) { self->error_callback = NULL; self->error_callback_userdata = NULL; diff --git a/src/parser.c b/src/parser.c index be19a33..01cf196 100644 --- a/src/parser.c +++ b/src/parser.c @@ -663,8 +663,7 @@ static CHECK_RESULT Ast* parser_parse_number(Parser *self) { return result; throw_if_error(arena_allocator_alloc(self->allocator, sizeof(Number), (void**)&number)); - number_init(number, self->tokenizer.value.integer, self->tokenizer.number_is_integer, - create_buffer_view(self->tokenizer.code.data + self->tokenizer.prev_index, self->tokenizer.index - self->tokenizer.prev_index)); + number_init(number, &self->tokenizer.number, self->tokenizer.value.identifier); throw_if_error(ast_create(self->allocator, number, AST_NUMBER, &result)); return result; } diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c index 34ecada..44b5589 100644 --- a/src/ssa/ssa.c +++ b/src/ssa/ssa.c @@ -487,10 +487,15 @@ static bool lhs_expr_is_decl(LhsExpr *self) { static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerContext *context) { SsaRegister reg; SsaNumber number; - if(self->is_integer) - number = create_ssa_integer(self->value.integer); - else - number = create_ssa_float(self->value.floating); + switch(self->value.type) { + case AMAL_NUMBER_SIGNED_INTEGER: + case AMAL_NUMBER_UNSIGNED_INTEGER: + number = create_ssa_integer(self->value.value.integer); + break; + case AMAL_NUMBER_FLOAT: + number = create_ssa_float(self->value.value.floating); + break; + } throw_if_error(ssa_get_unique_reg(context->ssa, ®)); throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number)); return reg; @@ -759,9 +764,9 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_ case BINOP_SUB: return SSA_SUB; case BINOP_MUL: - return type->is_signed ? SSA_IMUL : SSA_MUL; + return amal_default_type_is_signed(type) ? SSA_IMUL : SSA_MUL; case BINOP_DIV: - return type->is_signed ? SSA_IDIV : SSA_DIV; + return amal_default_type_is_signed(type) ? SSA_IDIV : SSA_DIV; case BINOP_DOT: assert(bool_false && "Binop dot not valid for arithmetic operation and requires special functionality"); return 0; @@ -772,13 +777,13 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_ case BINOP_AND: return SSA_AND; case BINOP_LESS: - return type->is_signed ? SSA_ILT : SSA_LT; + return amal_default_type_is_signed(type) ? SSA_ILT : SSA_LT; case BINOP_LESS_EQUAL: - return type->is_signed ? SSA_ILE : SSA_LE; + return amal_default_type_is_signed(type) ? SSA_ILE : SSA_LE; case BINOP_GREATER: - return type->is_signed ? SSA_IGT : SSA_GT; + return amal_default_type_is_signed(type) ? SSA_IGT : SSA_GT; case BINOP_GREATER_EQUAL: - return type->is_signed ? SSA_IGE : SSA_GE; + return amal_default_type_is_signed(type) ? SSA_IGE : SSA_GE; } return 0; } diff --git a/src/std/thread.c b/src/std/thread.c index 9b9b764..8c6d93a 100644 --- a/src/std/thread.c +++ b/src/std/thread.c @@ -174,7 +174,9 @@ void amal_mutex_tryunlock(amal_mutex *self) { } bool amal_thread_is_main(void) { - /* TODO: This only works for linux, use equivalent functions on other platforms */ +#ifndef __linux__ +#error Fix this for non-linux platforms! +#endif return amal_thread_get_id() == amal_process_get_id(); } diff --git a/src/tokenizer.c b/src/tokenizer.c index 2c27809..c93add3 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -35,7 +35,6 @@ int tokenizer_init(Tokenizer *self, ArenaAllocator *allocator, BufferView code, self->token = TOK_NONE; self->needs_update = bool_true; self->code_name = code_name.data ? code_name : create_buffer_view("<buffer>", 8); - self->number_is_integer = bool_false; self->allocator = allocator; self->compiler_options = compiler_options; @@ -236,11 +235,9 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { } *token = TOK_IDENTIFIER; } else if(isDigit(c)) { - int number_start; - int dot_index; BufferView number_str; - number_start = self->index; - dot_index = -1; + int number_start = self->index; + int dot_index = -1; ++self->index; while(self->index < (int)self->code.size) { @@ -256,26 +253,86 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { } number_str = create_buffer_view(self->code.data + number_start, self->index - number_start); + /* TODO: Support octal (0o...), hex (0x...) and binary (0b...) syntax */ + if(number_str.size > 1 && number_str.data[0] == '0') { + tokenizer_print_error(self, number_start, "Invalid number %.*s", (int)number_str.size, number_str.data); + return TOKENIZER_ERR; + } if(dot_index == -1) { - int result; - result = string_to_integer_unchecked(number_str, &self->value.integer); + int result = string_to_integer_unchecked(number_str, &self->number.value.integer); if(result != 0) { /* TODO */ - tokenizer_print_error(self, self->prev_index, "Integer value %.*s is too large to fit in signed 64-bit. Support for large integers is not supported yet.", number_str.size, number_str.data); + tokenizer_print_error(self, self->prev_index, "Integer value %.*s is too large to fit in signed 64-bit. Support for large integers is not supported yet", number_str.size, number_str.data); return TOKENIZER_ERR; } - self->number_is_integer = bool_true; + self->number.type = AMAL_NUMBER_SIGNED_INTEGER; + self->number.bits = 32; } else { - int result; - result = string_to_float_unchecked(number_str, dot_index, &self->value.floating); + int result = string_to_float_unchecked(number_str, dot_index, &self->number.value.floating); if(result != 0) { /* TODO */ - tokenizer_print_error(self, self->prev_index, "Float value %.*s is too large to fit in 64-bit. Support for large floating numbers is not supported yet.", number_str.size, number_str.data); + tokenizer_print_error(self, self->prev_index, "Float value %.*s is too large to fit in 64-bit. Support for large floating numbers is not supported yet", number_str.size, number_str.data); return TOKENIZER_ERR; } - self->number_is_integer = bool_false; + self->number.type = AMAL_NUMBER_FLOAT; + self->number.bits = 32; + } + + if(self->index < (int)self->code.size) { + AmalNumberType number_type = -1; + char suffix_char = self->code.data[self->index]; + + if(suffix_char == 'i') { + number_type = AMAL_NUMBER_SIGNED_INTEGER; + } else if(suffix_char == 'u') { + number_type = AMAL_NUMBER_UNSIGNED_INTEGER; + } else if(suffix_char == 'f') { + number_type = AMAL_NUMBER_FLOAT; + } + + if((int)number_type != -1) { + usize suffix_num_start; + usize suffix_num_len; + i64 suffix_num; + + if(dot_index != -1 && number_type != AMAL_NUMBER_FLOAT) { + tokenizer_print_error(self, self->index, "Floating point number has invalid suffix '%c'. Expected 'f' or nothing", suffix_char); + return TOKENIZER_ERR; + } + + ++self->index; + suffix_num_start = self->index; + while(self->index < (int)self->code.size) { + c = tokenizer_get_char(self); + if(isDigit(c)) + ++self->index; + else + break; + } + + suffix_num_len = self->index - suffix_num_start; + if(suffix_num_len == 0) { + tokenizer_print_error(self, self->index, "Missing number suffix"); + return TOKENIZER_ERR; + } + + number_str = create_buffer_view(self->code.data + suffix_num_start, self->index - suffix_num_start); + int result = string_to_integer_unchecked(number_str, &suffix_num); + /* TODO: Allow larger than 256 bits suffix */ + if(result != 0 || suffix_num > 256) { + /* TODO */ + tokenizer_print_error(self, suffix_num_start, "Number suffix can't be larger than 256"); + return TOKENIZER_ERR; + } + + self->number.type = number_type; + self->number.bits = (int)suffix_num; + } } + + self->value.identifier.data = self->code.data + number_start; + self->value.identifier.size = self->index - number_start; *token = TOK_NUMBER; } else if(c == '"') { int string_end; diff --git a/tests/bytecode.amal b/tests/bytecode.amal index 5ba26ed..730a26e 100644 --- a/tests/bytecode.amal +++ b/tests/bytecode.amal @@ -1,14 +1,3 @@ -extern const printf: fn(fmt: ?&c_char, ...) c_int; - const main = fn { - var value = 23 + 50; - if value < 23 - printf("less!\n"); - else - printf("more!\n"); - while value > 0 { - printf("value: %ld\n", value); - value = value - 1; - } }
\ No newline at end of file diff --git a/tests/glfw.amal b/tests/glfw.amal index e3c2fc6..37608fc 100644 --- a/tests/glfw.amal +++ b/tests/glfw.amal @@ -2,15 +2,14 @@ extern const glfwInit: fn() i32; extern const glfwTerminate: fn() i32; // should return void.... -extern const glfwCreateWindow: fn(x: i32, y: i32, title: str, monitor: usize, share: usize) usize; -extern const glfwWindowShouldClose: fn(window: usize) i64; +extern const glfwCreateWindow: fn(x: i32, y: i32, title: str, monitor: u64, share: u64) u64; +extern const glfwWindowShouldClose: fn(window: u64) i32; const main = fn { glfwInit(); - const window = glfwCreateWindow(50, 50, "hello, world", 0, 0); + const window = glfwCreateWindow(50i32, 50i32, "hello, world", 0, 0); while glfwWindowShouldClose(window) == 0 { } glfwTerminate(); - //const a = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; }
\ No newline at end of file |