so hopefully not too much breaks). New syntax features:
1. Call-by-name function arguments. You can specify a hash literal in
place of ordered function arguments, and it will become the local
variable namespace for the called function, making functions with many
arguments more readable. Ex:
view_manager.lookat(heading:180, pitch:20, roll:0, x:X0, y:Y0, z:Z0,
time:now, fov:55);
Declared arguments are checked and defaulted as would be expected:
it's an error if you fail to pass a value for an undefaulted argument,
missing default arguments get assigned, and any rest parameter
(e.g. "func(a,b=2,rest...){}") will be assigned with an empty vector.
2. Vector slicing. Vectors (lists) can now be created from others
using an ordered list of indexes and ranges. For example:
var v1 = ["a","b","c","d","e"]
var v2 = v1[3,2]; # == ["d","c"];
var v3 = v1[1:3]; # i.e. range from 1 to 3: ["b","c","d"];
var v4 = v1[1:]; # no value means "to the end": ["b","c","d","e"]
var i = 2;
var v5 = v1[i]; # runtime expressions are fine: ["c"]
var v6 = v1[-2,-1]; # negative indexes are relative to end: ["d","e"]
The range values can be computed at runtime (e.g. i=1; v5=v1[i:]).
Negative indices work the same way the do with the vector functions
(-1 is the last element, -2 is 2nd to last, etc...).
3. Multi-assignment expressions. You can assign more than one
variable (or lvalue) at a time by putting them in a parenthesized
list:
(var a, var b) = (1, 2);
var (a, b) = (1, 2); # Shorthand for (var a, var b)
(var a, v[0], obj.field) = (1,2,3) # Any assignable lvalue works
var color = [1, 1, 0.5];
var (r, g, b) = color; # works with runtime vectors too
116 lines
2.6 KiB
C
116 lines
2.6 KiB
C
#include <string.h>
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#include "data.h"
|
|
#include "code.h"
|
|
|
|
static void lockDestroy(void* lock) { naFreeLock(lock); }
|
|
static naGhostType LockType = { lockDestroy };
|
|
|
|
static void semDestroy(void* sem) { naFreeSem(sem); }
|
|
static naGhostType SemType = { semDestroy };
|
|
|
|
typedef struct {
|
|
naContext ctx;
|
|
naRef func;
|
|
} ThreadData;
|
|
|
|
#ifdef _WIN32
|
|
static DWORD WINAPI threadtop(LPVOID param)
|
|
#else
|
|
static void* threadtop(void* param)
|
|
#endif
|
|
{
|
|
ThreadData* td = param;
|
|
naCall(td->ctx, td->func, 0, 0, naNil(), naNil());
|
|
naFreeContext(td->ctx);
|
|
naFree(td);
|
|
return 0;
|
|
}
|
|
|
|
static naRef f_newthread(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
ThreadData *td;
|
|
if(argc < 1 || !naIsFunc(args[0]))
|
|
naRuntimeError(c, "bad/missing argument to newthread");
|
|
td = naAlloc(sizeof(*td));
|
|
td->ctx = naNewContext();
|
|
td->func = args[0];
|
|
naTempSave(td->ctx, td->func);
|
|
#ifdef _WIN32
|
|
CreateThread(0, 0, threadtop, td, 0, 0);
|
|
#else
|
|
{
|
|
pthread_t t; int err;
|
|
if((err = pthread_create(&t, 0, threadtop, td)))
|
|
naRuntimeError(c, "newthread failed: %s", strerror(err));
|
|
pthread_detach(t);
|
|
}
|
|
#endif
|
|
return naNil();
|
|
}
|
|
|
|
static naRef f_newlock(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
return naNewGhost(c, &LockType, naNewLock());
|
|
}
|
|
|
|
static naRef f_lock(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
if(argc > 0 && naGhost_type(args[0]) == &LockType) {
|
|
naModUnlock();
|
|
naLock(naGhost_ptr(args[0]));
|
|
naModLock();
|
|
}
|
|
return naNil();
|
|
}
|
|
|
|
static naRef f_unlock(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
if(argc > 0 && naGhost_type(args[0]) == &LockType)
|
|
naUnlock(naGhost_ptr(args[0]));
|
|
return naNil();
|
|
}
|
|
|
|
static naRef f_newsem(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
return naNewGhost(c, &SemType, naNewSem());
|
|
}
|
|
|
|
static naRef f_semdown(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
if(argc > 0 && naGhost_type(args[0]) == &SemType) {
|
|
naModUnlock();
|
|
naSemDown(naGhost_ptr(args[0]));
|
|
naModLock();
|
|
}
|
|
return naNil();
|
|
}
|
|
|
|
static naRef f_semup(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
if(argc > 0 && naGhost_type(args[0]) == &SemType)
|
|
naSemUp(naGhost_ptr(args[0]), 1);
|
|
return naNil();
|
|
}
|
|
|
|
static naCFuncItem funcs[] = {
|
|
{ "newthread", f_newthread },
|
|
{ "newlock", f_newlock },
|
|
{ "lock", f_lock },
|
|
{ "unlock", f_unlock },
|
|
{ "newsem", f_newsem },
|
|
{ "semdown", f_semdown },
|
|
{ "semup", f_semup },
|
|
{ 0 }
|
|
};
|
|
|
|
naRef naInit_thread(naContext c)
|
|
{
|
|
return naGenLib(c, funcs);
|
|
}
|