aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.sh2
-rw-r--r--include/ast.h15
-rw-r--r--include/compiler.h2
-rw-r--r--include/number.h21
-rw-r--r--include/tokenizer.h5
-rw-r--r--src/ast.c147
-rw-r--r--src/compiler.c87
-rw-r--r--src/parser.c3
-rw-r--r--src/ssa/ssa.c25
-rw-r--r--src/std/thread.c4
-rw-r--r--src/tokenizer.c83
-rw-r--r--tests/bytecode.amal11
-rw-r--r--tests/glfw.amal7
13 files changed, 286 insertions, 126 deletions
diff --git a/build.sh b/build.sh
index c309380..144ae2f 100755
--- a/build.sh
+++ b/build.sh
@@ -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 */
};
diff --git a/src/ast.c b/src/ast.c
index 5336e1e..e18b906 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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, &reg));
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