aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-03-22 20:48:40 +0100
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commit4f308829ad0e81a59971e172284c018cf2bdca3d (patch)
treeeb11a69a471e31aa7be8e46bce6d1b3ded28e056
parent5df7f92e715ba764ee57f65d78e73111492bb64c (diff)
Add mutex for lhs expr, add error for missing lhs expr for func, struct
TODO: Use mutex in lhs expr and set resolved_type
-rw-r--r--include/ast.h10
-rw-r--r--include/parser.h3
-rw-r--r--include/std/scoped_allocator.h4
-rw-r--r--include/std/thread.h13
-rw-r--r--src/ast.c39
-rw-r--r--src/compiler.c6
-rw-r--r--src/parser.c54
-rw-r--r--src/std/scoped_allocator.c39
-rw-r--r--src/std/thread.c6
-rw-r--r--tests/main.amal3
10 files changed, 134 insertions, 43 deletions
diff --git a/include/ast.h b/include/ast.h
index 7b16796..25d9034 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -2,6 +2,7 @@
#define AMALGAM_AST_H
#include "defs.h"
+#include "std/defs.h"
#include "std/buffer_view.h"
#include "std/buffer.h"
#include "std/misc.h"
@@ -108,6 +109,13 @@ struct LhsExpr {
BufferView var_name;
Variable type;
Ast rhs_expr;
+ /*
+ A mutex is only available if the LhsExpr is public, because other threads (files)
+ can access it. It's used to prevent usage of unresolved data and also to decide which
+ thread has responsibility of resolving data.
+ TODO: Find a better way to store this. This most likely will use too much memory.
+ */
+ amal_mutex *mutex;
};
struct Import {
@@ -149,7 +157,7 @@ CHECK_RESULT int funcdecl_init(FunctionDecl *self, Scope *parent, ScopedAllocato
CHECK_RESULT int funccall_init(FunctionCall *self, BufferView name, ScopedAllocator *allocator);
CHECK_RESULT int structdecl_init(StructDecl *self, Scope *parent, ScopedAllocator *allocator);
void structfield_init(StructField *self, BufferView name, BufferView type_name);
-void lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name);
+CHECK_RESULT int lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator);
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);
diff --git a/include/parser.h b/include/parser.h
index 84d46bd..92e6d46 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -29,7 +29,8 @@ struct ParserThreadData {
typedef enum {
ERROR_CONTEXT_NONE,
- ERROR_CONTEXT_RHS_START
+ ERROR_CONTEXT_RHS_STANDALONE,
+ ERROR_CONTEXT_NO_LHS
} ErrorContext;
struct Parser {
diff --git a/include/std/scoped_allocator.h b/include/std/scoped_allocator.h
index 9090767..d7ec1e1 100644
--- a/include/std/scoped_allocator.h
+++ b/include/std/scoped_allocator.h
@@ -15,7 +15,10 @@ struct ScopedAllocatorNode {
struct ScopedAllocator {
ScopedAllocatorNode head;
ScopedAllocatorNode *current;
+ /* TODO: Use linked-list instead, since the elements are dynamically allocated anyways */
+ /* Find another way to store mutexes */
Buffer/*<Buffer*>*/ buffers;
+ Buffer/*<amal_mutex*>*/ mutexes;
};
CHECK_RESULT int scoped_allocator_node_init(ScopedAllocatorNode *self);
@@ -25,5 +28,6 @@ CHECK_RESULT int scoped_allocator_init(ScopedAllocator *self);
void scoped_allocator_deinit(ScopedAllocator *self);
CHECK_RESULT int scoped_allocator_alloc(ScopedAllocator *self, usize size, void **mem);
CHECK_RESULT int scoped_allocator_add_buffer(ScopedAllocator *self, Buffer *buffer);
+CHECK_RESULT int scoped_allocator_create_mutex(ScopedAllocator *self, amal_mutex **mutex);
#endif
diff --git a/include/std/thread.h b/include/std/thread.h
index 6eedb08..356ebf0 100644
--- a/include/std/thread.h
+++ b/include/std/thread.h
@@ -13,6 +13,8 @@ typedef void* (AmalThreadCallbackFunc)(void *userdata);
#define AMAL_THREAD_ERR -1
#define AMAL_THREAD_NOT_JOINABLE -23
+/*#define AMAL_MUTEX_DEBUG*/
+
struct amal_thread {
pthread_t thread_id;
pthread_attr_t thread_attr;
@@ -28,7 +30,9 @@ typedef enum {
struct amal_mutex {
pthread_mutex_t mutex;
+ #ifdef AMAL_MUTEX_DEBUG
const char *lock_identifier;
+ #endif
bool locked;
pthread_t owner_thread;
};
@@ -39,6 +43,10 @@ CHECK_RESULT int amal_thread_deinit(amal_thread *self);
CHECK_RESULT int amal_thread_detach(amal_thread *self);
CHECK_RESULT int amal_thread_join(amal_thread *self, void **result);
+bool amal_thread_is_main();
+/* Returns 0 if the number of usable threads is unknown */
+int amal_get_usable_thread_count();
+
void amal_mutex_init(amal_mutex *self);
void amal_mutex_deinit(amal_mutex *self);
CHECK_RESULT int amal_mutex_lock(amal_mutex *self, const char *lock_identifier);
@@ -46,9 +54,4 @@ CHECK_RESULT int amal_mutex_lock(amal_mutex *self, const char *lock_identifier);
CHECK_RESULT int amal_mutex_unlock(amal_mutex *self);
void amal_mutex_tryunlock(amal_mutex *self);
-bool amal_thread_is_main();
-
-/* Returns 0 if the number of usable threads is unknown */
-int amal_get_usable_thread_count();
-
#endif
diff --git a/src/ast.c b/src/ast.c
index 1bb1eb3..d0a5030 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -82,12 +82,17 @@ void structfield_init(StructField *self, BufferView name, BufferView type_name)
variable_init(&self->type, type_name);
}
-void lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name) {
+int lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator) {
self->is_pub = is_pub;
self->is_const = is_const;
variable_init(&self->type, create_buffer_view_null());
self->var_name = var_name;
self->rhs_expr = ast_none();
+ if(is_pub && allocator)
+ return_if_error(scoped_allocator_create_mutex(allocator, &self->mutex));
+ else
+ self->mutex = NULL;
+ return 0;
}
void import_init(Import *self, BufferView path) {
@@ -208,7 +213,7 @@ static void variable_resolve(Variable *self, AstCompilerContext *context, LhsExp
*resolved_type = scope_get_resolved_variable(context->scope, context, self->name);
}
-static void lhs_resolve(Ast *self, AstCompilerContext *context) {
+static void lhsexpr_resolve(Ast *self, AstCompilerContext *context) {
LhsExpr *lhs_expr;
lhs_expr = self->value.lhs_expr;
@@ -228,6 +233,22 @@ static void lhs_resolve(Ast *self, AstCompilerContext *context) {
self->resolved_type = lhs_expr->rhs_expr.resolved_type;
}
+/* LhsExpr has to be resolved before this is called */
+static Scope* lhsexpr_get_scope(LhsExpr *self) {
+ switch(self->rhs_expr.type) {
+ case AST_FUNCTION_DECL:
+ return &self->rhs_expr.value.func_decl->body;
+ case AST_STRUCT_DECL:
+ return &self->rhs_expr.value.struct_decl->body;
+ case AST_IMPORT:
+ return self->rhs_expr.value.import->file_scope->scope;
+ default:
+ break;
+ }
+ assert(bool_false && "Expected lhsexpr_get_scope to only be called for function decl and struct decl");
+ return NULL;
+}
+
static void import_resolve(Ast *self, AstCompilerContext *context) {
Import *import;
import = self->value.import;
@@ -278,7 +299,17 @@ static void structfield_resolve(Ast *self, AstCompilerContext *context) {
static void binop_resolve(Binop *self, AstCompilerContext *context) {
/* TODO: Implement */
ast_resolve(&self->lhs, context);
- ast_resolve(&self->rhs, context);
+ if(self->rhs.type == AST_VARIABLE) {
+ Scope *prev_scope;
+ assert(self->lhs.resolved_type);
+ prev_scope = context->scope;
+ context->scope = lhsexpr_get_scope(self->lhs.resolved_type);
+ assert(context->scope);
+ ast_resolve(&self->rhs, context);
+ context->scope = prev_scope;
+ } else {
+ ast_resolve(&self->rhs, context);
+ }
}
void ast_resolve(Ast *self, AstCompilerContext *context) {
@@ -317,7 +348,7 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
structfield_resolve(self, context);
break;
case AST_LHS:
- lhs_resolve(self, context);
+ lhsexpr_resolve(self, context);
break;
case AST_IMPORT:
/* TODO: When @import(...).data syntax is added, implement the resolve for it */
diff --git a/src/compiler.c b/src/compiler.c
index 6f9cc92..50678d8 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -47,9 +47,13 @@ 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));
- lhsexpr_init(lhs_expr, bool_true, bool_true, create_buffer_view(name, strnlen(name, PATH_MAX)));
+ return_if_error(lhsexpr_init(lhs_expr, bool_true, bool_true,
+ create_buffer_view(name, strnlen(name, PATH_MAX)),
+ NULL));
ast_init(&lhs_expr->rhs_expr, struct_decl, AST_STRUCT_DECL);
ast_init(&expr, lhs_expr, AST_LHS);
+ expr.resolved_type = lhs_expr;
+ expr.resolve_status = AST_RESOLVED;
return scope_add_child(&compiler->root_scope, &expr);
}
diff --git a/src/parser.c b/src/parser.c
index 57606b5..b1764a1 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -33,7 +33,7 @@ do { \
throw(return_if_result); \
} while(0)
-static THROWABLE parser_parse_rhs_start(Parser *self, Ast *rhs_expr);
+static THROWABLE parser_parse_rhs_start(Parser *self, Ast *rhs_expr, bool is_standalone);
static THROWABLE parser_parse_body(Parser *self, Ast *ast);
static THROWABLE parser_parse_struct_body(Parser *self, Ast *ast);
static THROWABLE parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope);
@@ -188,7 +188,7 @@ static THROWABLE parser_parse_lhs(Parser *self, LhsExpr **result, bool *assignme
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));
- lhsexpr_init(*result, is_pub, is_const, var_name);
+ throw_if_error(lhsexpr_init(*result, is_pub, is_const, var_name, self->allocator));
try(parser_parse_var_type_def(self, &(*result)->type.name));
@@ -292,7 +292,7 @@ static THROWABLE parser_parse_function_args(Parser *self, FunctionCall *func_cal
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_COMMA));
first_arg = bool_false;
- try(parser_parse_rhs_start(self, &arg_expr));
+ try(parser_parse_rhs_start(self, &arg_expr, bool_false));
throw_if_error(buffer_append(&func_call->args, &arg_expr, sizeof(arg_expr)));
}
@@ -457,31 +457,33 @@ static THROWABLE parser_parse_rhs(Parser *self, Ast *rhs_expr) {
/*
RHS_START = CLOSURE | IMPORT | RHS
*/
-int parser_parse_rhs_start(Parser *self, Ast *rhs_expr) {
+int parser_parse_rhs_start(Parser *self, Ast *rhs_expr, bool is_standalone) {
FunctionDecl *func_decl;
StructDecl *struct_decl;
Import *import;
- try(parser_parse_function_decl(self, &func_decl));
- if(func_decl) {
- ast_init(rhs_expr, func_decl, AST_FUNCTION_DECL);
- return PARSER_OK;
- }
-
- try(parser_parse_struct_decl(self, &struct_decl));
- if(struct_decl) {
- ast_init(rhs_expr, struct_decl, AST_STRUCT_DECL);
- return PARSER_OK;
- }
+ if(!is_standalone) {
+ try(parser_parse_function_decl(self, &func_decl));
+ if(func_decl) {
+ ast_init(rhs_expr, func_decl, AST_FUNCTION_DECL);
+ return PARSER_OK;
+ }
+
+ try(parser_parse_struct_decl(self, &struct_decl));
+ if(struct_decl) {
+ ast_init(rhs_expr, struct_decl, AST_STRUCT_DECL);
+ return PARSER_OK;
+ }
- try(parser_parse_import(self, &import));
- if(import) {
- try(parser_queue_file(self, import->path, &import->file_scope));
- ast_init(rhs_expr, import, AST_IMPORT);
- return PARSER_OK;
+ try(parser_parse_import(self, &import));
+ if(import) {
+ try(parser_queue_file(self, import->path, &import->file_scope));
+ ast_init(rhs_expr, import, AST_IMPORT);
+ return PARSER_OK;
+ }
+ self->error_context = ERROR_CONTEXT_RHS_STANDALONE;
}
- self->error_context = ERROR_CONTEXT_RHS_START;
try(parser_parse_rhs(self, rhs_expr));
self->error_context = ERROR_CONTEXT_NONE;
return PARSER_OK;
@@ -530,7 +532,10 @@ int parser_parse_body(Parser *self, Ast *ast) {
return PARSER_OK;
}
- try(parser_parse_rhs_start(self, &rhs_expr));
+ if(!lhs_expr)
+ self->error_context = ERROR_CONTEXT_NO_LHS;
+
+ try(parser_parse_rhs_start(self, &rhs_expr, lhs_expr == NULL));
if(lhs_expr) {
lhs_expr->rhs_expr = rhs_expr;
ast_init(ast, lhs_expr, AST_LHS);
@@ -576,9 +581,12 @@ int parser_parse_buffer(Parser *self, BufferView code_buffer, BufferView buffer_
case ERROR_CONTEXT_NONE:
tokenizer_print_error_object(&self->tokenizer, &self->error);
break;
- case ERROR_CONTEXT_RHS_START:
+ case ERROR_CONTEXT_RHS_STANDALONE:
tokenizer_print_error(&self->tokenizer, self->tokenizer.prev_index, "Expected string, variable, closure, struct, function call or import");
break;
+ case ERROR_CONTEXT_NO_LHS:
+ tokenizer_print_error(&self->tokenizer, self->tokenizer.prev_index, "Expected variable declaration, string, variable or function call");
+ break;
default:
assert(bool_false && "Error context handling not implemented");
break;
diff --git a/src/std/scoped_allocator.c b/src/std/scoped_allocator.c
index c66639a..3104fd3 100644
--- a/src/std/scoped_allocator.c
+++ b/src/std/scoped_allocator.c
@@ -1,5 +1,6 @@
#include "../../include/std/scoped_allocator.h"
#include "../../include/std/alloc.h"
+#include "../../include/std/thread.h"
#include "../../include/std/log.h"
#include <assert.h>
@@ -26,7 +27,8 @@ void scoped_allocator_node_deinit(ScopedAllocatorNode *self) {
int scoped_allocator_init(ScopedAllocator *self) {
return_if_error(scoped_allocator_node_init(&self->head));
self->current = &self->head;
- return buffer_init(&self->buffers, NULL);
+ return_if_error(buffer_init(&self->buffers, NULL));
+ return buffer_init(&self->mutexes, NULL);
}
static void buffer_deinit(Buffer *self) {
@@ -36,11 +38,9 @@ static void buffer_deinit(Buffer *self) {
self->capacity = 0;
}
-void scoped_allocator_deinit(ScopedAllocator *self) {
+static void scoped_allocator_deinit_buffers(ScopedAllocator *self) {
Buffer **buffer;
Buffer **buffers_end;
-
- self->current = NULL;
buffer = buffer_start(&self->buffers);
buffers_end = buffer_end(&self->buffers);
while(buffer != buffers_end) {
@@ -48,6 +48,24 @@ void scoped_allocator_deinit(ScopedAllocator *self) {
++buffer;
}
buffer_deinit(&self->buffers);
+}
+
+static void scoped_allocator_deinit_mutexes(ScopedAllocator *self) {
+ amal_mutex **mutex;
+ amal_mutex **mutexes_end;
+ mutex = buffer_start(&self->mutexes);
+ mutexes_end = buffer_end(&self->mutexes);
+ while(mutex != mutexes_end) {
+ amal_mutex_deinit(*mutex);
+ ++mutex;
+ }
+ buffer_deinit(&self->mutexes);
+}
+
+void scoped_allocator_deinit(ScopedAllocator *self) {
+ self->current = NULL;
+ scoped_allocator_deinit_buffers(self);
+ scoped_allocator_deinit_mutexes(self);
scoped_allocator_node_deinit(&self->head);
}
@@ -79,6 +97,8 @@ static usize align_ptr_ceil_offset(void *ptr, uintptr_t alignment) {
return (uintptr_t)align_ptr_ceil(ptr, alignment) - (uintptr_t)ptr;
}
+#define SCOPED_ALLOC_ALIGNMENT 8
+
int scoped_allocator_alloc(ScopedAllocator *self, usize size, void **mem) {
ScopedAllocatorNode *current;
usize alloc_size;
@@ -90,14 +110,14 @@ int scoped_allocator_alloc(ScopedAllocator *self, usize size, void **mem) {
return -1;
}
- alloc_size = size + align_ptr_ceil_offset(self->current->data + self->current->size, 16);
+ alloc_size = size + align_ptr_ceil_offset(self->current->data + self->current->size, SCOPED_ALLOC_ALIGNMENT);
return_if_error(scoped_allocator_ensure_capacity_for(self, alloc_size));
/* Reallocated (new node created) */
if(self->current != current) {
*mem = self->current->data;
self->current->size += size;
} else {
- *mem = align_ptr_ceil(self->current->data + self->current->size, 16);
+ *mem = align_ptr_ceil(self->current->data + self->current->size, SCOPED_ALLOC_ALIGNMENT);
self->current->size += alloc_size;
}
return 0;
@@ -106,3 +126,10 @@ int scoped_allocator_alloc(ScopedAllocator *self, usize size, void **mem) {
int scoped_allocator_add_buffer(ScopedAllocator *self, Buffer *buffer) {
return buffer_append(&self->buffers, &buffer, sizeof(Buffer*));
}
+
+int scoped_allocator_create_mutex(ScopedAllocator *self, amal_mutex **mutex) {
+ *mutex = NULL;
+ return_if_error(scoped_allocator_alloc(self, sizeof(amal_mutex), (void**)mutex));
+ amal_mutex_init(*mutex);
+ return buffer_append(&self->mutexes, mutex, sizeof(amal_mutex*));
+}
diff --git a/src/std/thread.c b/src/std/thread.c
index ba67463..350631a 100644
--- a/src/std/thread.c
+++ b/src/std/thread.c
@@ -109,7 +109,9 @@ int amal_thread_join(amal_thread *self, void **result) {
void amal_mutex_init(amal_mutex *self) {
pthread_mutex_init(&self->mutex, NULL);
+ #ifdef AMAL_MUTEX_DEBUG
self->lock_identifier = NULL;
+ #endif
self->locked = bool_false;
self->owner_thread = 0;
}
@@ -129,10 +131,11 @@ static long amal_thread_get_id() {
int amal_mutex_lock(amal_mutex *self, const char *lock_identifier) {
int result;
result = pthread_mutex_lock(&self->mutex);
- self->lock_identifier = lock_identifier;
self->owner_thread = pthread_self();
self->locked = bool_true;
+ (void)lock_identifier;
#ifdef AMAL_MUTEX_DEBUG
+ self->lock_identifier = lock_identifier;
if(result == 0 && self->lock_identifier) {
amal_log_debug("amal_mutex_lock: mutex locked by thread %lu (%s), identification: %s",
amal_thread_get_id(),
@@ -149,6 +152,7 @@ int amal_mutex_unlock(amal_mutex *self) {
const char *identifier;
identifier = self->lock_identifier;
#endif
+ /* No-op if mutex isn't locked or if another thread owns the mutex lock */
if(!self->locked || pthread_equal(self->owner_thread, pthread_self()) == 0)
return 0;
self->locked = bool_false;
diff --git a/tests/main.amal b/tests/main.amal
index 65ac43b..3af537b 100644
--- a/tests/main.amal
+++ b/tests/main.amal
@@ -10,6 +10,7 @@ const main = fn {
}
const value = "hello";
+ // fn {} // error, function declaration can't be by itself. Needs left-hand side
print(value, "world", 356, 13.37);
var num1: i32;
const num2 = 23232;
@@ -20,7 +21,7 @@ const main = fn {
/*
episfjpseifipesf
*/
- //io.puts("lole");
+ io.puts("lole");
}
const print = fn {