Remove threads and mutexed data from the language in favor of a
module-based approach
This commit is contained in:
parent
d3655740cc
commit
7a172be621
4
Makefile
4
Makefile
@ -47,7 +47,7 @@ LDLIBS=-lgc -lcord -lm -lunistring -lgmp
|
||||
LIBTOMO_FLAGS=-shared
|
||||
|
||||
ifeq ($(OS),OpenBSD)
|
||||
LDLIBS += -lpthread -lexecinfo
|
||||
LDLIBS += -lexecinfo
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
@ -107,7 +107,7 @@ clean:
|
||||
examples: examples/base64/base64 examples/ini/ini examples/game/game \
|
||||
examples/tomodeps/tomodeps examples/tomo-install/tomo-install examples/wrap/wrap examples/colorful/colorful
|
||||
./build/tomo -qIL examples/time examples/commands examples/shell examples/base64 examples/log examples/ini examples/vectors examples/game \
|
||||
examples/http examples/threads examples/tomodeps examples/tomo-install examples/wrap examples/pthreads examples/colorful
|
||||
examples/http examples/tomodeps examples/tomo-install examples/wrap examples/pthreads examples/colorful
|
||||
./build/tomo examples/learnxiny.tm
|
||||
|
||||
deps: check-gcc
|
||||
|
@ -77,7 +77,6 @@ of many language features or the other example programs/modules in
|
||||
- Built-in doctests with syntax highlighting
|
||||
- [Automatic command line argument parsing with type safety](docs/command-line-parsing.md)
|
||||
- [Easy interoperability with C](docs/c-interoperability.md)
|
||||
- Support for [POSIX threads](docs/threads.tm) and mutex-guarded datastructures.
|
||||
- Built-in [data serialization and deserialization](docs/serialization.md).
|
||||
|
||||
## Dependencies
|
||||
|
@ -25,7 +25,6 @@ Information about Tomo's built-in types can be found here:
|
||||
- [Floating point numbers](nums.md)
|
||||
- [Integers](integers.md)
|
||||
- [Languages](langs.md)
|
||||
- [Mutexed Data](mutexed.md)
|
||||
- [Paths](paths.md)
|
||||
- [Random Number Generators](rng.md)
|
||||
- [Sets](sets.md)
|
||||
@ -33,7 +32,6 @@ Information about Tomo's built-in types can be found here:
|
||||
- [Tables](tables.md)
|
||||
- [Text](text.md)
|
||||
- [Text Pattern Matching](patterns.md)
|
||||
- [Threads](threads.md)
|
||||
|
||||
## Built-in Functions
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
# Mutexed Data
|
||||
|
||||
To serve the general case of synchronizing access to shared datastructures,
|
||||
Tomo uses the `mutexed` keyword, which allocates a mutex and some heap memory
|
||||
for a value. Access to the heap-allocated value's memory can only be obtained
|
||||
by using a `holding` block. `holding` blocks ensure that the underlying mutex
|
||||
is locked before entering the block and unlocked before leaving it (even if a
|
||||
short-circuiting control flow statement like `return` or `stop` is used). Here
|
||||
is a simple example:
|
||||
|
||||
```tomo
|
||||
nums := mutexed [10, 20, 30]
|
||||
|
||||
>> nums
|
||||
= mutexed [Int]<0x12345678> : mutexed([Int])
|
||||
|
||||
holding nums:
|
||||
# Inside this block, the type of `nums` is `&[Int]`
|
||||
>> nums
|
||||
= &[10, 20, 30] : &[Int]
|
||||
|
||||
thread := Thread.new(func():
|
||||
holding nums:
|
||||
nums:insert(30)
|
||||
)
|
||||
|
||||
holding nums:
|
||||
nums:insert(40)
|
||||
|
||||
thread:join()
|
||||
```
|
||||
|
||||
Without using a mutex, the code above could run into concurrency issues leading
|
||||
to data corruption.
|
@ -70,7 +70,6 @@ only 9 bytes for the whole thing!
|
||||
|
||||
## Unserializable Types
|
||||
|
||||
Unfortunately, not all types can be easily serialized. In particular,
|
||||
`Thread`s, types, and functions cannot be serialized because their data
|
||||
contents cannot be easily converted to portable byte arrays. All other
|
||||
datatypes _can_ be serialized.
|
||||
Unfortunately, not all types can be easily serialized. In particular, types and
|
||||
functions cannot be serialized because their data contents cannot be easily
|
||||
converted to portable byte arrays. All other datatypes _can_ be serialized.
|
||||
|
@ -1,93 +0,0 @@
|
||||
# Threads
|
||||
|
||||
Tomo supports POSIX threads (pthreads) through the `Thread` type. The
|
||||
recommended practice is to have each thread interact with other threads only
|
||||
through [mutex-guarded datastructures](mutexed.md).
|
||||
|
||||
## Thread Methods
|
||||
|
||||
- [`func cancel(thread: Thread)`](#cancel)
|
||||
- [`func detach(thread: Thread)`](#detach)
|
||||
- [`func join(thread: Thread)`](#join)
|
||||
- [`func new(fn: func(->Void) -> Thread)`](#new)
|
||||
|
||||
### `cancel`
|
||||
Requests the cancellation of a specified thread.
|
||||
|
||||
```tomo
|
||||
func cancel(thread: Thread)
|
||||
```
|
||||
|
||||
- `thread`: The thread to cancel.
|
||||
|
||||
**Returns:**
|
||||
Nothing.
|
||||
|
||||
**Example:**
|
||||
```tomo
|
||||
>> thread:cancel()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `detach`
|
||||
Detaches a specified thread, allowing it to run independently.
|
||||
|
||||
```tomo
|
||||
func detach(thread: Thread)
|
||||
```
|
||||
|
||||
- `thread`: The thread to detach.
|
||||
|
||||
**Returns:**
|
||||
Nothing.
|
||||
|
||||
**Example:**
|
||||
```tomo
|
||||
>> thread:detach()
|
||||
```
|
||||
### `join`
|
||||
Waits for a specified thread to terminate.
|
||||
|
||||
```tomo
|
||||
func join(thread: Thread)
|
||||
```
|
||||
|
||||
- `thread`: The thread to join.
|
||||
|
||||
**Returns:**
|
||||
Nothing.
|
||||
|
||||
**Example:**
|
||||
```tomo
|
||||
>> thread:join()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `new`
|
||||
Creates a new thread to execute a specified function.
|
||||
|
||||
```tomo
|
||||
func new(fn: func(->Void) -> Thread)
|
||||
```
|
||||
|
||||
- `fn`: The function to be executed by the new thread.
|
||||
|
||||
**Returns:**
|
||||
A new `Thread` object representing the created thread.
|
||||
|
||||
**Example:**
|
||||
```tomo
|
||||
>> jobs := |Int|
|
||||
>> results := |Int|
|
||||
>> thread := Thread.new(func():
|
||||
repeat:
|
||||
input := jobs:get()
|
||||
results:give(input + 10
|
||||
)
|
||||
= Thread<0x12345678>
|
||||
>> jobs:give(10)
|
||||
>> results:get()
|
||||
= 11
|
||||
```
|
@ -1,106 +0,0 @@
|
||||
use <pthread.h>
|
||||
|
||||
struct Mutex(_mutex:@Memory):
|
||||
func new(->Mutex):
|
||||
return Mutex(
|
||||
inline C : @Memory {
|
||||
pthread_mutex_t *mutex = GC_MALLOC(sizeof(pthread_mutex_t));
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
GC_register_finalizer(mutex, (void*)pthread_mutex_destroy, NULL, NULL, NULL);
|
||||
mutex
|
||||
}
|
||||
)
|
||||
|
||||
func do_locked(m:Mutex, fn:func(); inline):
|
||||
inline C {
|
||||
pthread_mutex_lock((pthread_mutex_t*)_$m._mutex);
|
||||
}
|
||||
fn()
|
||||
inline C {
|
||||
pthread_mutex_unlock((pthread_mutex_t*)_$m._mutex);
|
||||
}
|
||||
|
||||
struct ThreadCondition(_cond:@Memory):
|
||||
func new(->ThreadCondition):
|
||||
return ThreadCondition(
|
||||
inline C : @Memory {
|
||||
pthread_cond_t *cond = GC_MALLOC(sizeof(pthread_cond_t));
|
||||
pthread_cond_init(cond, NULL);
|
||||
GC_register_finalizer(cond, (void*)pthread_cond_destroy, NULL, NULL, NULL);
|
||||
cond
|
||||
}
|
||||
)
|
||||
|
||||
func wait(c:ThreadCondition, m:Mutex; inline):
|
||||
inline C {
|
||||
pthread_cond_wait((pthread_cond_t*)_$c._cond, (pthread_mutex_t*)_$m._mutex);
|
||||
}
|
||||
|
||||
func signal(c:ThreadCondition; inline):
|
||||
inline C {
|
||||
pthread_cond_signal((pthread_cond_t*)_$c._cond);
|
||||
}
|
||||
|
||||
func broadcast(c:ThreadCondition; inline):
|
||||
inline C {
|
||||
pthread_cond_broadcast((pthread_cond_t*)_$c._cond);
|
||||
}
|
||||
|
||||
struct Guard(mutex=Mutex.new(), cond=ThreadCondition.new()):
|
||||
func guarded(g:Guard, fn:func(); inline):
|
||||
g.mutex:do_locked(fn)
|
||||
g.cond:signal()
|
||||
|
||||
func wait(g:Guard):
|
||||
g.cond:wait(g.mutex)
|
||||
|
||||
struct PThread(_thread:@Memory):
|
||||
func new(fn:func() -> PThread):
|
||||
return PThread(
|
||||
inline C : @Memory {
|
||||
pthread_t *thread = GC_MALLOC(sizeof(pthread_t));
|
||||
pthread_create(thread, NULL, _$fn.fn, _$fn.userdata);
|
||||
thread
|
||||
}
|
||||
)
|
||||
|
||||
func join(t:PThread):
|
||||
inline C {
|
||||
pthread_join(*(pthread_t*)_$t._thread, NULL);
|
||||
}
|
||||
|
||||
func cancel(t:PThread):
|
||||
inline C {
|
||||
pthread_cancel(*(pthread_t*)_$t._thread);
|
||||
}
|
||||
|
||||
func detatch(t:PThread):
|
||||
inline C {
|
||||
pthread_detach(*(pthread_t*)_$t._thread);
|
||||
}
|
||||
|
||||
func main():
|
||||
g := Guard()
|
||||
queue := @[10, 20]
|
||||
|
||||
t := PThread.new(func():
|
||||
say("In another thread!")
|
||||
item := @none:Int
|
||||
while item[] != 30:
|
||||
g:guarded(func():
|
||||
while queue.length == 0:
|
||||
g:wait()
|
||||
|
||||
item[] = queue[1]
|
||||
queue:remove_at(1)
|
||||
)
|
||||
say("Processing: $item")
|
||||
sleep(0.01)
|
||||
say("All done!")
|
||||
)
|
||||
>> t
|
||||
>> sleep(1)
|
||||
>> g:guarded(func():
|
||||
queue:insert(30)
|
||||
)
|
||||
>> t:join()
|
@ -116,8 +116,6 @@ CORD ast_to_xml(ast_t *ast)
|
||||
T(Not, "<Not>%r</Not>", ast_to_xml(data.value))
|
||||
T(HeapAllocate, "<HeapAllocate>%r</HeapAllocate>", ast_to_xml(data.value))
|
||||
T(StackReference, "<StackReference>%r</StackReference>", ast_to_xml(data.value))
|
||||
T(Mutexed, "<Mutexed>%r</Mutexed>", ast_to_xml(data.value))
|
||||
T(Holding, "<Holding>%r%r</Holding>", ast_to_xml(data.mutexed), ast_to_xml(data.body))
|
||||
T(Min, "<Min>%r%r%r</Min>", ast_to_xml(data.lhs), ast_to_xml(data.rhs), optional_tagged("key", data.key))
|
||||
T(Max, "<Max>%r%r%r</Max>", ast_to_xml(data.lhs), ast_to_xml(data.rhs), optional_tagged("key", data.key))
|
||||
T(Array, "<Array>%r%r</Array>", optional_tagged_type("item-type", data.item_type), ast_list_to_xml(data.items))
|
||||
@ -192,7 +190,6 @@ CORD type_ast_to_xml(type_ast_t *t)
|
||||
T(TableTypeAST, "<TableType>%r %r</TableType>", type_ast_to_xml(data.key), type_ast_to_xml(data.value))
|
||||
T(FunctionTypeAST, "<FunctionType>%r %r</FunctionType>", arg_list_to_xml(data.args), type_ast_to_xml(data.ret))
|
||||
T(OptionalTypeAST, "<OptionalType>%r</OptionalType>", data.type)
|
||||
T(MutexedTypeAST, "<MutexedType>%r</MutexedType>", data.type)
|
||||
#undef T
|
||||
default: return CORD_EMPTY;
|
||||
}
|
||||
|
10
src/ast.h
10
src/ast.h
@ -75,7 +75,6 @@ typedef enum {
|
||||
TableTypeAST,
|
||||
FunctionTypeAST,
|
||||
OptionalTypeAST,
|
||||
MutexedTypeAST,
|
||||
} type_ast_e;
|
||||
|
||||
typedef struct tag_ast_s {
|
||||
@ -114,7 +113,7 @@ struct type_ast_s {
|
||||
} FunctionTypeAST;
|
||||
struct {
|
||||
type_ast_t *type;
|
||||
} OptionalTypeAST, MutexedTypeAST;
|
||||
} OptionalTypeAST;
|
||||
} __data;
|
||||
};
|
||||
|
||||
@ -126,7 +125,7 @@ typedef enum {
|
||||
Path,
|
||||
Declare, Assign,
|
||||
BinaryOp, UpdateAssign,
|
||||
Not, Negative, HeapAllocate, StackReference, Mutexed, Holding,
|
||||
Not, Negative, HeapAllocate, StackReference,
|
||||
Min, Max,
|
||||
Array, Set, Table, TableEntry, Comprehension,
|
||||
FunctionDef, Lambda, ConvertDef,
|
||||
@ -194,10 +193,7 @@ struct ast_s {
|
||||
} BinaryOp, UpdateAssign;
|
||||
struct {
|
||||
ast_t *value;
|
||||
} Not, Negative, HeapAllocate, StackReference, Mutexed;
|
||||
struct {
|
||||
ast_t *mutexed, *body;
|
||||
} Holding;
|
||||
} Not, Negative, HeapAllocate, StackReference;
|
||||
struct {
|
||||
ast_t *lhs, *rhs, *key;
|
||||
} Min, Max;
|
||||
|
@ -39,7 +39,7 @@ static CORD compile_string_literal(CORD literal);
|
||||
|
||||
CORD promote_to_optional(type_t *t, CORD code)
|
||||
{
|
||||
if (t == THREAD_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE || t == MATCH_TYPE) {
|
||||
if (t == PATH_TYPE || t == PATH_TYPE_TYPE || t == MATCH_TYPE) {
|
||||
return code;
|
||||
} else if (t->tag == IntType) {
|
||||
switch (Match(t, IntType)->bits) {
|
||||
@ -228,18 +228,13 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
|
||||
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, UpdateAssign)->rhs);
|
||||
break;
|
||||
}
|
||||
case Not: case Negative: case HeapAllocate: case StackReference: case Mutexed: {
|
||||
case Not: case Negative: case HeapAllocate: case StackReference: {
|
||||
// UNSAFE:
|
||||
ast_t *value = ast->__data.Not.value;
|
||||
// END UNSAFE
|
||||
add_closed_vars(closed_vars, enclosing_scope, env, value);
|
||||
break;
|
||||
}
|
||||
case Holding: {
|
||||
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Holding)->mutexed);
|
||||
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Holding)->body);
|
||||
break;
|
||||
}
|
||||
case Min: {
|
||||
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Min)->lhs);
|
||||
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Min)->rhs);
|
||||
@ -501,8 +496,7 @@ PUREFUNC CORD compile_unsigned_type(type_t *t)
|
||||
|
||||
CORD compile_type(type_t *t)
|
||||
{
|
||||
if (t == THREAD_TYPE) return "Thread_t";
|
||||
else if (t == RNG_TYPE) return "RNG_t";
|
||||
if (t == RNG_TYPE) return "RNG_t";
|
||||
else if (t == MATCH_TYPE) return "Match_t";
|
||||
else if (t == PATH_TYPE) return "Path_t";
|
||||
else if (t == PATH_TYPE_TYPE) return "PathType_t";
|
||||
@ -512,7 +506,6 @@ CORD compile_type(type_t *t)
|
||||
case AbortType: return "void";
|
||||
case VoidType: return "void";
|
||||
case MemoryType: return "void";
|
||||
case MutexedType: return "MutexedData_t";
|
||||
case BoolType: return "Bool_t";
|
||||
case ByteType: return "Byte_t";
|
||||
case CStringType: return "const char*";
|
||||
@ -556,7 +549,7 @@ CORD compile_type(type_t *t)
|
||||
case OptionalType: {
|
||||
type_t *nonnull = Match(t, OptionalType)->type;
|
||||
switch (nonnull->tag) {
|
||||
case CStringType: case FunctionType: case ClosureType: case MutexedType:
|
||||
case CStringType: case FunctionType: case ClosureType:
|
||||
case PointerType: case EnumType:
|
||||
return compile_type(nonnull);
|
||||
case TextType:
|
||||
@ -565,8 +558,6 @@ CORD compile_type(type_t *t)
|
||||
case ArrayType: case TableType: case SetType:
|
||||
return CORD_all("Optional", compile_type(nonnull));
|
||||
case StructType: {
|
||||
if (nonnull == THREAD_TYPE)
|
||||
return "Thread_t";
|
||||
if (nonnull == MATCH_TYPE)
|
||||
return "OptionalMatch_t";
|
||||
if (nonnull == PATH_TYPE)
|
||||
@ -689,7 +680,7 @@ CORD optional_into_nonnone(type_t *t, CORD value)
|
||||
case IntType:
|
||||
return CORD_all(value, ".value");
|
||||
case StructType:
|
||||
if (t == THREAD_TYPE || t == MATCH_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE)
|
||||
if (t == MATCH_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE)
|
||||
return value;
|
||||
return CORD_all(value, ".value");
|
||||
default:
|
||||
@ -702,8 +693,7 @@ CORD check_none(type_t *t, CORD value)
|
||||
t = Match(t, OptionalType)->type;
|
||||
// NOTE: these use statement expressions ({...;}) because some compilers
|
||||
// complain about excessive parens around equality comparisons
|
||||
if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType
|
||||
|| t == THREAD_TYPE)
|
||||
if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType)
|
||||
return CORD_all("({", value, " == NULL;})");
|
||||
else if (t == MATCH_TYPE)
|
||||
return CORD_all("({(", value, ").index.small == 0;})");
|
||||
@ -729,8 +719,6 @@ CORD check_none(type_t *t, CORD value)
|
||||
return CORD_all("(", value, ").is_none");
|
||||
else if (t->tag == EnumType)
|
||||
return CORD_all("({(", value, ").$tag == 0;})");
|
||||
else if (t->tag == MutexedType)
|
||||
return CORD_all("({", value, " == NULL;})");
|
||||
print_err("Optional check not implemented for: ", type_to_str(t));
|
||||
}
|
||||
|
||||
@ -1344,30 +1332,6 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
|
||||
loop = CORD_all(loop, "\n", loop_ctx.stop_label, ":;");
|
||||
return loop;
|
||||
}
|
||||
case Holding: {
|
||||
ast_t *held = Match(ast, Holding)->mutexed;
|
||||
type_t *held_type = get_type(env, held);
|
||||
if (held_type->tag != MutexedType)
|
||||
code_err(held, "This is a ", type_to_str(held_type), ", not a mutexed value");
|
||||
CORD code = CORD_all(
|
||||
"{ // Holding\n",
|
||||
"MutexedData_t mutexed = ", compile(env, held), ";\n",
|
||||
"pthread_mutex_lock(&mutexed->mutex);\n");
|
||||
|
||||
env_t *body_scope = fresh_scope(env);
|
||||
body_scope->deferred = new(deferral_t, .defer_env=env,
|
||||
.block=FakeAST(InlineCCode, .code="pthread_mutex_unlock(&mutexed->mutex);"),
|
||||
.next=body_scope->deferred);
|
||||
if (held->tag == Var) {
|
||||
CORD held_var = CORD_all(Match(held, Var)->name, "$held");
|
||||
set_binding(body_scope, Match(held, Var)->name,
|
||||
Type(PointerType, .pointed=Match(held_type, MutexedType)->type, .is_stack=true), held_var);
|
||||
code = CORD_all(code, compile_declaration(Type(PointerType, .pointed=Match(held_type, MutexedType)->type), held_var),
|
||||
" = (", compile_type(Type(PointerType, .pointed=Match(held_type, MutexedType)->type)), ")mutexed->data;\n");
|
||||
}
|
||||
return CORD_all(code, compile_statement(body_scope, Match(ast, Holding)->body),
|
||||
"pthread_mutex_unlock(&mutexed->mutex);\n}");
|
||||
}
|
||||
case For: {
|
||||
auto for_ = Match(ast, For);
|
||||
|
||||
@ -1811,7 +1775,7 @@ CORD expr_as_text(CORD expr, type_t *t, CORD color)
|
||||
case FunctionType: case ClosureType: return CORD_asprintf("Func$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t));
|
||||
case PointerType: return CORD_asprintf("Pointer$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t));
|
||||
case OptionalType: return CORD_asprintf("Optional$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t));
|
||||
case StructType: case EnumType: case MutexedType:
|
||||
case StructType: case EnumType:
|
||||
return CORD_asprintf("generic_as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t));
|
||||
default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for ", type_to_str(t));
|
||||
}
|
||||
@ -2199,8 +2163,7 @@ CORD compile_none(type_t *t)
|
||||
if (t->tag == OptionalType)
|
||||
t = Match(t, OptionalType)->type;
|
||||
|
||||
if (t == THREAD_TYPE) return "NULL";
|
||||
else if (t == PATH_TYPE) return "NONE_PATH";
|
||||
if (t == PATH_TYPE) return "NONE_PATH";
|
||||
else if (t == PATH_TYPE_TYPE) return "((OptionalPathType_t){})";
|
||||
else if (t == MATCH_TYPE) return "NONE_MATCH";
|
||||
|
||||
@ -2231,7 +2194,6 @@ CORD compile_none(type_t *t)
|
||||
env_t *enum_env = Match(t, EnumType)->env;
|
||||
return CORD_all("((", compile_type(t), "){", namespace_prefix(enum_env, enum_env->namespace), "null})");
|
||||
}
|
||||
case MutexedType: return "NONE_MUTEXED_DATA";
|
||||
default: compiler_err(NULL, NULL, NULL, "none isn't implemented for this type: ", type_to_str(t));
|
||||
}
|
||||
}
|
||||
@ -2339,36 +2301,6 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
else
|
||||
return CORD_all("stack(", compile(env, subject), ")");
|
||||
}
|
||||
case Mutexed: {
|
||||
ast_t *mutexed = Match(ast, Mutexed)->value;
|
||||
return CORD_all("new(struct MutexedData_s, .mutex=PTHREAD_MUTEX_INITIALIZER, .data=", compile(env, WrapAST(mutexed, HeapAllocate, mutexed)), ")");
|
||||
}
|
||||
case Holding: {
|
||||
ast_t *held = Match(ast, Holding)->mutexed;
|
||||
type_t *held_type = get_type(env, held);
|
||||
if (held_type->tag != MutexedType)
|
||||
code_err(held, "This is a ", type_to_str(held_type), ", not a mutexed value");
|
||||
CORD code = CORD_all(
|
||||
"({ // Holding\n",
|
||||
"MutexedData_t mutexed = ", compile(env, held), ";\n",
|
||||
"pthread_mutex_lock(&mutexed->mutex);\n");
|
||||
|
||||
env_t *body_scope = fresh_scope(env);
|
||||
body_scope->deferred = new(deferral_t, .defer_env=env,
|
||||
.block=FakeAST(InlineCCode, .code="pthread_mutex_unlock(&mutexed->mutex);"),
|
||||
.next=body_scope->deferred);
|
||||
if (held->tag == Var) {
|
||||
CORD held_var = CORD_all(Match(held, Var)->name, "$held");
|
||||
set_binding(body_scope, Match(held, Var)->name,
|
||||
Type(PointerType, .pointed=Match(held_type, MutexedType)->type, .is_stack=true), held_var);
|
||||
code = CORD_all(code, compile_declaration(Type(PointerType, .pointed=Match(held_type, MutexedType)->type), held_var),
|
||||
" = (", compile_type(Type(PointerType, .pointed=Match(held_type, MutexedType)->type)), ")mutexed->data;\n");
|
||||
}
|
||||
type_t *body_type = get_type(env, ast);
|
||||
return CORD_all(code, compile_declaration(body_type, "result"), " = ", compile(body_scope, Match(ast, Holding)->body), ";\n"
|
||||
"pthread_mutex_unlock(&mutexed->mutex);\n"
|
||||
"result;\n})");
|
||||
}
|
||||
case Optional: {
|
||||
ast_t *value = Match(ast, Optional)->value;
|
||||
CORD value_code = compile(env, value);
|
||||
@ -3829,8 +3761,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
|
||||
CORD compile_type_info(type_t *t)
|
||||
{
|
||||
if (t == THREAD_TYPE) return "&Thread$info";
|
||||
else if (t == RNG_TYPE) return "&RNG$info";
|
||||
if (t == RNG_TYPE) return "&RNG$info";
|
||||
else if (t == MATCH_TYPE) return "&Match$info";
|
||||
else if (t == PATH_TYPE) return "&Path$info";
|
||||
else if (t == PATH_TYPE_TYPE) return "&PathType$info";
|
||||
@ -3890,10 +3821,6 @@ CORD compile_type_info(type_t *t)
|
||||
type_t *non_optional = Match(t, OptionalType)->type;
|
||||
return CORD_asprintf("Optional$info(sizeof(%r), __alignof__(%r), %r)", compile_type(non_optional), compile_type(non_optional), compile_type_info(non_optional));
|
||||
}
|
||||
case MutexedType: {
|
||||
type_t *mutexed = Match(t, MutexedType)->type;
|
||||
return CORD_all("MutexedData$info(", compile_type_info(mutexed), ")");
|
||||
}
|
||||
case TypeInfoType: return CORD_all("Type$info(", CORD_quoted(type_to_cord(Match(t, TypeInfoType)->type)), ")");
|
||||
case MemoryType: return "&Memory$info";
|
||||
case VoidType: return "&Void$info";
|
||||
|
@ -16,7 +16,6 @@ type_t *TEXT_TYPE = NULL;
|
||||
type_t *MATCH_TYPE = NULL;
|
||||
type_t *RNG_TYPE = NULL;
|
||||
public type_t *PATH_TYPE = NULL;
|
||||
public type_t *THREAD_TYPE = NULL;
|
||||
public type_t *PATH_TYPE_TYPE = NULL;
|
||||
|
||||
static type_t *declare_type(env_t *env, const char *def_str)
|
||||
@ -70,7 +69,6 @@ env_t *global_env(void)
|
||||
PATH_TYPE_TYPE = declare_type(env, "enum PathType(Relative, Absolute, Home)");
|
||||
MATCH_TYPE = declare_type(env, "struct Match(text:Text, index:Int, captures:[Text])");
|
||||
PATH_TYPE = declare_type(env, "struct Path(type:PathType, components:[Text])");
|
||||
THREAD_TYPE = declare_type(env, "struct Thread(; opaque)");
|
||||
RNG_TYPE = declare_type(env, "struct RNG(state:@Memory)");
|
||||
|
||||
typedef struct {
|
||||
@ -394,12 +392,6 @@ env_t *global_env(void)
|
||||
{"utf32_codepoints", "Text$utf32_codepoints", "func(text:Text -> [Int32])"},
|
||||
{"width", "Text$width", "func(text:Text, language='C' -> Int)"},
|
||||
)},
|
||||
{"Thread", THREAD_TYPE, "Thread_t", "Thread", TypedArray(ns_entry_t,
|
||||
{"new", "Thread$new", "func(fn:func() -> Thread)"},
|
||||
{"cancel", "Thread$cancel", "func(thread:Thread)"},
|
||||
{"join", "Thread$join", "func(thread:Thread)"},
|
||||
{"detach", "Thread$detach", "func(thread:Thread)"},
|
||||
)},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(global_types)/sizeof(global_types[0]); i++) {
|
||||
@ -535,7 +527,6 @@ env_t *global_env(void)
|
||||
{"Int$value_as_text", "func(i:Int -> Path)"});
|
||||
ADD_CONSTRUCTORS("CString", {"Text$as_c_string", "func(text:Text -> CString)"});
|
||||
ADD_CONSTRUCTORS("RNG", {"RNG$new", "func(-> RNG)"});
|
||||
ADD_CONSTRUCTORS("Thread", {"Thread$new", "func(fn:func() -> Thread)"});
|
||||
#undef ADD_CONSTRUCTORS
|
||||
|
||||
set_binding(namespace_env(env, "Path"), "from_text",
|
||||
|
@ -93,6 +93,5 @@ extern type_t *MATCH_TYPE;
|
||||
extern type_t *RNG_TYPE;
|
||||
extern type_t *PATH_TYPE;
|
||||
extern type_t *PATH_TYPE_TYPE;
|
||||
extern type_t *THREAD_TYPE;
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
40
src/parse.c
40
src/parse.c
@ -63,8 +63,8 @@ int op_tightness[] = {
|
||||
|
||||
static const char *keywords[] = {
|
||||
"yes", "xor", "while", "when", "use", "unless", "struct", "stop", "skip", "return",
|
||||
"or", "not", "none", "no", "mutexed", "mod1", "mod", "pass", "lang", "inline", "in", "if",
|
||||
"holding", "func", "for", "extern", "enum", "else", "do", "deserialize", "defer", "and",
|
||||
"or", "not", "none", "no", "mod1", "mod", "pass", "lang", "inline", "in", "if",
|
||||
"func", "for", "extern", "enum", "else", "do", "deserialize", "defer", "and",
|
||||
"_min_", "_max_", NULL,
|
||||
};
|
||||
|
||||
@ -94,7 +94,6 @@ static type_ast_t *parse_array_type(parse_ctx_t *ctx, const char *pos);
|
||||
static type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos);
|
||||
static type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos);
|
||||
static type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos);
|
||||
static type_ast_t *parse_mutexed_type(parse_ctx_t *ctx, const char *pos);
|
||||
static type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos);
|
||||
static type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos);
|
||||
static type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos);
|
||||
@ -116,13 +115,11 @@ static PARSER(parse_file_body);
|
||||
static PARSER(parse_for);
|
||||
static PARSER(parse_func_def);
|
||||
static PARSER(parse_heap_alloc);
|
||||
static PARSER(parse_holding);
|
||||
static PARSER(parse_if);
|
||||
static PARSER(parse_inline_c);
|
||||
static PARSER(parse_int);
|
||||
static PARSER(parse_lambda);
|
||||
static PARSER(parse_lang_def);
|
||||
static PARSER(parse_mutexed);
|
||||
static PARSER(parse_namespace);
|
||||
static PARSER(parse_negative);
|
||||
static PARSER(parse_not);
|
||||
@ -573,19 +570,6 @@ type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos) {
|
||||
return ptr_type;
|
||||
}
|
||||
|
||||
type_ast_t *parse_mutexed_type(parse_ctx_t *ctx, const char *pos) {
|
||||
const char *start = pos;
|
||||
if (!match_word(&pos, "mutexed")) return NULL;
|
||||
spaces(&pos);
|
||||
if (!match(&pos, "(")) return NULL;
|
||||
spaces(&pos);
|
||||
type_ast_t *mutexed = expect(ctx, start, &pos, parse_type,
|
||||
"I couldn't parse a mutexed type after this point");
|
||||
spaces(&pos);
|
||||
if (!match(&pos, ")")) return NULL;
|
||||
return NewTypeAST(ctx->file, start, pos, MutexedTypeAST, .type=mutexed);
|
||||
}
|
||||
|
||||
type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos) {
|
||||
const char *start = pos;
|
||||
const char *id = get_id(&pos);
|
||||
@ -612,7 +596,6 @@ type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos) {
|
||||
|| (type=parse_set_type(ctx, pos))
|
||||
|| (type=parse_type_name(ctx, pos))
|
||||
|| (type=parse_func_type(ctx, pos))
|
||||
|| (type=parse_mutexed_type(ctx, pos))
|
||||
);
|
||||
if (!success && match(&pos, "(")) {
|
||||
whitespace(&pos);
|
||||
@ -1190,23 +1173,6 @@ PARSER(parse_stack_reference) {
|
||||
return ast;
|
||||
}
|
||||
|
||||
PARSER(parse_mutexed) {
|
||||
const char *start = pos;
|
||||
if (!match_word(&pos, "mutexed")) return NULL;
|
||||
spaces(&pos);
|
||||
ast_t *val = expect(ctx, start, &pos, parse_term, "I expected an expression for this 'mutexed'");
|
||||
return NewAST(ctx->file, start, pos, Mutexed, .value=val);
|
||||
}
|
||||
|
||||
PARSER(parse_holding) {
|
||||
const char *start = pos;
|
||||
if (!match_word(&pos, "holding")) return NULL;
|
||||
spaces(&pos);
|
||||
ast_t *mutexed = expect(ctx, start, &pos, parse_expr, "I expected an expression for this 'holding'");
|
||||
ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a block to be here");
|
||||
return NewAST(ctx->file, start, pos, Holding, .mutexed=mutexed, .body=body);
|
||||
}
|
||||
|
||||
PARSER(parse_not) {
|
||||
const char *start = pos;
|
||||
if (!match_word(&pos, "not")) return NULL;
|
||||
@ -1526,7 +1492,6 @@ PARSER(parse_term_no_suffix) {
|
||||
|| (term=parse_stop(ctx, pos))
|
||||
|| (term=parse_return(ctx, pos))
|
||||
|| (term=parse_not(ctx, pos))
|
||||
|| (term=parse_mutexed(ctx, pos))
|
||||
|| (term=parse_extern(ctx, pos))
|
||||
|| (term=parse_inline_c(ctx, pos))
|
||||
);
|
||||
@ -1858,7 +1823,6 @@ PARSER(parse_extended_expr) {
|
||||
|| (expr=optional(ctx, &pos, parse_when))
|
||||
|| (expr=optional(ctx, &pos, parse_repeat))
|
||||
|| (expr=optional(ctx, &pos, parse_do))
|
||||
|| (expr=optional(ctx, &pos, parse_holding))
|
||||
)
|
||||
return expr;
|
||||
|
||||
|
@ -31,5 +31,4 @@ some common functionality.
|
||||
- Pointers: [pointers.h](pointers.h), [pointers.c](pointers.c)
|
||||
- Tables: [tables.h](tables.h), [tables.c](tables.c)
|
||||
- Text: [text.h](text.h), [text.c](text.c)
|
||||
- Threads: [threads.h](threads.h), [threads.c](threads.c)
|
||||
- Type Infos (for representing types as values): [types.h](types.h), [types.c](types.c)
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Common datastructures (arrays, tables, closures)
|
||||
|
||||
#include <gmp.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
@ -111,11 +110,6 @@ typedef struct {
|
||||
|
||||
typedef struct RNGState_t* RNG_t;
|
||||
|
||||
typedef struct MutexedData_s {
|
||||
pthread_mutex_t mutex;
|
||||
void *data;
|
||||
} *MutexedData_t;
|
||||
|
||||
#define OptionalBool_t uint8_t
|
||||
#define OptionalArray_t Array_t
|
||||
#define OptionalTable_t Table_t
|
||||
|
@ -1,39 +0,0 @@
|
||||
// Mutexed data methods/type info
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <gc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "bools.h"
|
||||
#include "metamethods.h"
|
||||
#include "optionals.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
|
||||
static Text_t MutexedData$as_text(const void *m, bool colorize, const TypeInfo_t *type)
|
||||
{
|
||||
auto mutexed = type->MutexedDataInfo;
|
||||
Text_t typename = generic_as_text(NULL, false, mutexed.type);
|
||||
if (!m) {
|
||||
return Texts(colorize ? Text("\x1b[34;1mmutexed\x1b[m(") : Text("mutexed("), typename, Text(")"));
|
||||
}
|
||||
return Texts(colorize ? Text("\x1b[34;1mmutexed ") : Text("mutexed "), typename,
|
||||
Text$format(colorize ? "<%p>\x1b[m" : "<%p>", *((MutexedData_t*)m)));
|
||||
}
|
||||
|
||||
static bool MutexedData$is_none(const void *m, const TypeInfo_t *)
|
||||
{
|
||||
return *((MutexedData_t*)m) == NULL;
|
||||
}
|
||||
|
||||
public const metamethods_t MutexedData$metamethods = {
|
||||
.as_text=MutexedData$as_text,
|
||||
.is_none=MutexedData$is_none,
|
||||
.serialize=cannot_serialize,
|
||||
.deserialize=cannot_deserialize,
|
||||
};
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Metamethods and type info for mutexed data
|
||||
|
||||
#include "types.h"
|
||||
#include "optionals.h"
|
||||
#include "util.h"
|
||||
|
||||
#define NONE_MUTEXED_DATA ((MutexedData_t)NULL)
|
||||
|
||||
extern const metamethods_t MutexedData$metamethods;
|
||||
|
||||
#define MutexedData$info(t) &((TypeInfo_t){.size=sizeof(MutexedData_t), .align=__alignof(MutexedData_t), \
|
||||
.tag=MutexedDataInfo, .MutexedDataInfo.type=t, \
|
||||
.metamethods=MutexedData$metamethods})
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
@ -1,7 +1,5 @@
|
||||
// Optional types
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "bools.h"
|
||||
#include "bytes.h"
|
||||
#include "datatypes.h"
|
||||
@ -10,7 +8,6 @@
|
||||
#include "nums.h"
|
||||
#include "patterns.h"
|
||||
#include "text.h"
|
||||
#include "threads.h"
|
||||
#include "util.h"
|
||||
|
||||
public PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type)
|
||||
|
@ -1,92 +0,0 @@
|
||||
// Logic for the Thread type, representing a pthread
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <gc.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "arrays.h"
|
||||
#include "datatypes.h"
|
||||
#include "metamethods.h"
|
||||
#include "rng.h"
|
||||
#include "text.h"
|
||||
#include "threads.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||
static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
|
||||
(void)flags;
|
||||
arc4random_buf(buf, buflen);
|
||||
return buflen;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
// Use getrandom()
|
||||
# include <sys/random.h>
|
||||
#else
|
||||
#error "Unsupported platform for secure random number generation"
|
||||
#endif
|
||||
|
||||
static void *run_thread(Closure_t *closure)
|
||||
{
|
||||
uint8_t *random_bytes = GC_MALLOC_ATOMIC(40);
|
||||
getrandom(random_bytes, 40, 0);
|
||||
Array_t rng_seed = {.length=40, .data=random_bytes, .stride=1, .atomic=1};
|
||||
default_rng = RNG$new(rng_seed);
|
||||
((void(*)(void*))closure->fn)(closure->userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public Thread_t Thread$new(Closure_t fn)
|
||||
{
|
||||
Thread_t thread = GC_MALLOC(sizeof(pthread_t));
|
||||
Closure_t *closure = new(Closure_t, .fn=fn.fn, .userdata=fn.userdata);
|
||||
pthread_create(thread, NULL, (void*)run_thread, closure);
|
||||
return thread;
|
||||
}
|
||||
|
||||
public void Thread$join(Thread_t thread)
|
||||
{
|
||||
pthread_join(*thread, NULL);
|
||||
}
|
||||
|
||||
public void Thread$cancel(Thread_t thread)
|
||||
{
|
||||
pthread_cancel(*thread);
|
||||
}
|
||||
|
||||
public void Thread$detach(Thread_t thread)
|
||||
{
|
||||
pthread_detach(*thread);
|
||||
}
|
||||
|
||||
Text_t Thread$as_text(const void *thread, bool colorize, const TypeInfo_t*)
|
||||
{
|
||||
if (!thread) {
|
||||
return colorize ? Text("\x1b[34;1mThread\x1b[m") : Text("Thread");
|
||||
}
|
||||
return Text$format(colorize ? "\x1b[34;1mThread(%p)\x1b[m" : "Thread(%p)", *(Thread_t**)thread);
|
||||
}
|
||||
|
||||
static bool Thread$is_none(const void *obj, const TypeInfo_t*)
|
||||
{
|
||||
return *(Thread_t*)obj == NULL;
|
||||
}
|
||||
|
||||
public const TypeInfo_t Thread$info = {
|
||||
.size=sizeof(Thread_t), .align=__alignof(Thread_t),
|
||||
.metamethods={
|
||||
.as_text=Thread$as_text,
|
||||
.is_none=Thread$is_none,
|
||||
.serialize=cannot_serialize,
|
||||
.deserialize=cannot_deserialize,
|
||||
},
|
||||
};
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Logic for the Thread type, representing a pthread
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
#define Thread_t pthread_t*
|
||||
|
||||
Thread_t Thread$new(Closure_t fn);
|
||||
void Thread$cancel(Thread_t thread);
|
||||
void Thread$join(Thread_t thread);
|
||||
void Thread$detach(Thread_t thread);
|
||||
Text_t Thread$as_text(const void *thread, bool colorize, const TypeInfo_t *type);
|
||||
|
||||
extern const TypeInfo_t Thread$info;
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
@ -17,7 +17,6 @@
|
||||
#include "integers.h"
|
||||
#include "memory.h"
|
||||
#include "metamethods.h"
|
||||
#include "mutexeddata.h"
|
||||
#include "nums.h"
|
||||
#include "optionals.h"
|
||||
#include "paths.h"
|
||||
@ -29,7 +28,6 @@
|
||||
#include "structs.h"
|
||||
#include "tables.h"
|
||||
#include "text.h"
|
||||
#include "threads.h"
|
||||
#include "types.h"
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -30,7 +30,7 @@ struct TypeInfo_s {
|
||||
metamethods_t metamethods;
|
||||
struct { // Anonymous tagged union for convenience
|
||||
enum { OpaqueInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ArrayInfo, TableInfo, FunctionInfo,
|
||||
OptionalInfo, MutexedDataInfo, TypeInfoInfo } tag;
|
||||
OptionalInfo, TypeInfoInfo } tag;
|
||||
union {
|
||||
struct {} OpaqueInfo;
|
||||
struct {
|
||||
@ -54,7 +54,7 @@ struct TypeInfo_s {
|
||||
} TypeInfoInfo;
|
||||
struct {
|
||||
const TypeInfo_t *type;
|
||||
} OptionalInfo, MutexedDataInfo;
|
||||
} OptionalInfo;
|
||||
struct {
|
||||
const char *name;
|
||||
int num_tags;
|
||||
|
@ -114,7 +114,7 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
ldlibs = Texts(ldlibs, Text(" -lexecinfo -lpthread"));
|
||||
ldlibs = Texts(ldlibs, Text(" -lexecinfo"));
|
||||
#endif
|
||||
|
||||
USE_COLOR = getenv("COLOR") ? strcmp(getenv("COLOR"), "1") == 0 : isatty(STDOUT_FILENO);
|
||||
|
@ -128,13 +128,6 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
|
||||
code_err(ast, "Nested optional types are not currently supported");
|
||||
return Type(OptionalType, .type=t);
|
||||
}
|
||||
case MutexedTypeAST: {
|
||||
type_ast_t *mutexed = Match(ast, MutexedTypeAST)->type;
|
||||
type_t *t = parse_type_ast(env, mutexed);
|
||||
if (t->tag == VoidType || t->tag == AbortType || t->tag == ReturnType)
|
||||
code_err(ast, "Mutexed ", type_to_str(t), " types are not supported.");
|
||||
return Type(MutexedType, .type=t);
|
||||
}
|
||||
case UnknownTypeAST: code_err(ast, "I don't know how to get this type");
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
@ -1027,21 +1020,6 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
}
|
||||
code_err(ast, "I only know how to get 'not' of boolean, numeric, and optional pointer types, not ", type_to_str(t));
|
||||
}
|
||||
case Mutexed: {
|
||||
type_t *item_type = get_type(env, Match(ast, Mutexed)->value);
|
||||
return Type(MutexedType, .type=item_type);
|
||||
}
|
||||
case Holding: {
|
||||
ast_t *held = Match(ast, Holding)->mutexed;
|
||||
type_t *held_type = get_type(env, held);
|
||||
if (held_type->tag != MutexedType)
|
||||
code_err(held, "This is a ", type_to_str(held_type), ", not a mutexed value");
|
||||
if (held->tag == Var) {
|
||||
env = fresh_scope(env);
|
||||
set_binding(env, Match(held, Var)->name, Type(PointerType, .pointed=Match(held_type, MutexedType)->type, .is_stack=true), CORD_EMPTY);
|
||||
}
|
||||
return get_type(env, Match(ast, Holding)->body);
|
||||
}
|
||||
case BinaryOp: {
|
||||
auto binop = Match(ast, BinaryOp);
|
||||
type_t *lhs_t = get_type(env, binop->lhs),
|
||||
|
13
src/types.c
13
src/types.c
@ -84,13 +84,6 @@ CORD type_to_cord(type_t *t) {
|
||||
else
|
||||
return "(Unknown optional type)";
|
||||
}
|
||||
case MutexedType: {
|
||||
type_t *opt = Match(t, MutexedType)->type;
|
||||
if (opt)
|
||||
return CORD_all("mutexed ", type_to_cord(opt));
|
||||
else
|
||||
return "(Unknown optional type)";
|
||||
}
|
||||
case TypeInfoType: {
|
||||
return CORD_all("Type$info(", Match(t, TypeInfoType)->name, ")");
|
||||
}
|
||||
@ -250,7 +243,6 @@ PUREFUNC bool has_heap_memory(type_t *t)
|
||||
case SetType: return true;
|
||||
case PointerType: return true;
|
||||
case OptionalType: return has_heap_memory(Match(t, OptionalType)->type);
|
||||
case MutexedType: return true;
|
||||
case BigIntType: return true;
|
||||
case StructType: {
|
||||
for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
|
||||
@ -276,7 +268,6 @@ PUREFUNC bool has_stack_memory(type_t *t)
|
||||
switch (t->tag) {
|
||||
case PointerType: return Match(t, PointerType)->is_stack;
|
||||
case OptionalType: return has_stack_memory(Match(t, OptionalType)->type);
|
||||
case MutexedType: return has_stack_memory(Match(t, MutexedType)->type);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@ -483,7 +474,6 @@ PUREFUNC size_t unpadded_struct_size(type_t *t)
|
||||
|
||||
PUREFUNC size_t type_size(type_t *t)
|
||||
{
|
||||
if (t == THREAD_TYPE) return sizeof(pthread_t*);
|
||||
if (t == PATH_TYPE) return sizeof(Path_t);
|
||||
if (t == PATH_TYPE_TYPE) return sizeof(PathType_t);
|
||||
#ifdef __GNUC__
|
||||
@ -514,7 +504,6 @@ PUREFUNC size_t type_size(type_t *t)
|
||||
case FunctionType: return sizeof(void*);
|
||||
case ClosureType: return sizeof(struct {void *fn, *userdata;});
|
||||
case PointerType: return sizeof(void*);
|
||||
case MutexedType: return sizeof(MutexedData_t);
|
||||
case OptionalType: {
|
||||
type_t *nonnull = Match(t, OptionalType)->type;
|
||||
switch (nonnull->tag) {
|
||||
@ -575,7 +564,6 @@ PUREFUNC size_t type_size(type_t *t)
|
||||
|
||||
PUREFUNC size_t type_align(type_t *t)
|
||||
{
|
||||
if (t == THREAD_TYPE) return __alignof__(pthread_t*);
|
||||
if (t == PATH_TYPE) return __alignof__(Path_t);
|
||||
if (t == PATH_TYPE_TYPE) return __alignof__(PathType_t);
|
||||
#ifdef __GNUC__
|
||||
@ -606,7 +594,6 @@ PUREFUNC size_t type_align(type_t *t)
|
||||
case FunctionType: return __alignof__(void*);
|
||||
case ClosureType: return __alignof__(struct {void *fn, *userdata;});
|
||||
case PointerType: return __alignof__(void*);
|
||||
case MutexedType: return __alignof__(MutexedData_t);
|
||||
case OptionalType: {
|
||||
type_t *nonnull = Match(t, OptionalType)->type;
|
||||
switch (nonnull->tag) {
|
||||
|
@ -57,7 +57,6 @@ struct type_s {
|
||||
EnumType,
|
||||
OptionalType,
|
||||
TypeInfoType,
|
||||
MutexedType,
|
||||
ModuleType,
|
||||
} tag;
|
||||
|
||||
@ -116,7 +115,7 @@ struct type_s {
|
||||
} EnumType;
|
||||
struct {
|
||||
type_t *type;
|
||||
} OptionalType, MutexedType;
|
||||
} OptionalType;
|
||||
struct {
|
||||
const char *name;
|
||||
type_t *type;
|
||||
|
@ -61,18 +61,6 @@ func maybe_c_string(should_i:Bool->CString?):
|
||||
else:
|
||||
return none
|
||||
|
||||
func maybe_thread(should_i:Bool->Thread?):
|
||||
if should_i:
|
||||
return Thread.new(func(): pass)
|
||||
else:
|
||||
return none
|
||||
|
||||
func maybe_mutexed(should_i:Bool->mutexed(Bool)?):
|
||||
if should_i:
|
||||
return mutexed no
|
||||
else:
|
||||
return none
|
||||
|
||||
func main():
|
||||
>> 5?
|
||||
= 5?
|
||||
@ -244,33 +232,6 @@ func main():
|
||||
fail("Truthy: $nope")
|
||||
else: !! Falsey: $nope
|
||||
|
||||
do:
|
||||
!! ...
|
||||
!! Threads:
|
||||
>> yep := maybe_thread(yes)
|
||||
# No "=" test here because threads use addresses in the text version
|
||||
>> nope := maybe_thread(no)
|
||||
= none : Thread
|
||||
>> if yep: >> yep
|
||||
else: fail("Falsey: $yep")
|
||||
>> if nope:
|
||||
fail("Truthy: $nope")
|
||||
else: !! Falsey: $nope
|
||||
|
||||
do:
|
||||
!! ...
|
||||
!! Mutexed:
|
||||
>> yep := maybe_mutexed(yes)
|
||||
# No "=" test here because threads use addresses in the text version
|
||||
>> nope := maybe_mutexed(no)
|
||||
= none : mutexed(Bool)
|
||||
>> if yep: >> yep
|
||||
else: fail("Falsey: $yep")
|
||||
>> if nope:
|
||||
fail("Truthy: $nope")
|
||||
else: !! Falsey: $nope
|
||||
|
||||
|
||||
if yep := maybe_int(yes):
|
||||
>> yep
|
||||
= 123
|
||||
|
@ -1,70 +0,0 @@
|
||||
enum Job(Increment(x:Int), Decrement(x:Int))
|
||||
|
||||
func main():
|
||||
do:
|
||||
>> nums := mutexed [10, 20, 30]
|
||||
holding nums:
|
||||
>> nums[]
|
||||
= [10, 20, 30]
|
||||
nums:insert(40)
|
||||
|
||||
holding nums:
|
||||
>> nums[]
|
||||
= [10, 20, 30, 40]
|
||||
|
||||
|
||||
jobs := mutexed [Job.Increment(5)]
|
||||
|
||||
results := mutexed [:Int]
|
||||
|
||||
>> thread := Thread.new(func():
|
||||
!! In another thread!
|
||||
repeat:
|
||||
job := holding jobs: (jobs:pop(1) or stop)
|
||||
when job is Increment(x):
|
||||
holding results: results:insert(x + 1)
|
||||
is Decrement(x):
|
||||
holding results: results:insert(x - 1)
|
||||
)
|
||||
|
||||
holding jobs:
|
||||
jobs:insert(Decrement(100))
|
||||
jobs:insert(Decrement(200))
|
||||
jobs:insert(Decrement(300))
|
||||
jobs:insert(Decrement(400))
|
||||
jobs:insert(Decrement(500))
|
||||
jobs:insert(Decrement(600))
|
||||
jobs:insert(Increment(1000))
|
||||
|
||||
dequeue_result := func():
|
||||
result := none:Int
|
||||
repeat:
|
||||
result = (holding results: results:pop(1))
|
||||
stop if result
|
||||
sleep(0.00001)
|
||||
return result!
|
||||
|
||||
>> dequeue_result()
|
||||
= 6
|
||||
>> dequeue_result()
|
||||
= 99
|
||||
|
||||
>> dequeue_result()
|
||||
= 199
|
||||
>> dequeue_result()
|
||||
= 299
|
||||
>> dequeue_result()
|
||||
= 399
|
||||
>> dequeue_result()
|
||||
= 499
|
||||
>> dequeue_result()
|
||||
= 599
|
||||
|
||||
>> dequeue_result()
|
||||
= 1001
|
||||
|
||||
!! Canceling...
|
||||
>> thread:cancel()
|
||||
!! Joining...
|
||||
>> thread:join()
|
||||
!! Done!
|
Loading…
Reference in New Issue
Block a user