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
88 lines
2.8 KiB
C
88 lines
2.8 KiB
C
#include <string.h>
|
|
#include "data.h"
|
|
|
|
// Note that this currently supports a maximum field width of 32
|
|
// bits (i.e. an unsigned int). Using a 64 bit integer would stretch
|
|
// that beyond what is representable in the double result, but
|
|
// requires portability work.
|
|
#define MSK(n) (1 << (7 - ((n) & 7)))
|
|
#define BIT(s,l,n) s[(n)>>3] & MSK(n)
|
|
#define CLRB(s,l,n) s[(n)>>3] &= ~MSK(n)
|
|
#define SETB(s,l,n) s[(n)>>3] |= MSK(n)
|
|
|
|
static unsigned int fld(naContext c, unsigned char* s,
|
|
int slen, int bit, int flen)
|
|
{
|
|
int i;
|
|
unsigned int fld = 0;
|
|
if(bit + flen > 8*slen) naRuntimeError(c, "bitfield out of bounds");
|
|
for(i=0; i<flen; i++) if(BIT(s, slen, bit+flen-i-1)) fld |= (1<<i);
|
|
return fld;
|
|
}
|
|
|
|
static void setfld(naContext c, unsigned char* s, int slen,
|
|
int bit, int flen, unsigned int fld)
|
|
{
|
|
int i;
|
|
if(bit + flen > 8*slen) naRuntimeError(c, "bitfield out of bounds");
|
|
for(i=0; i<flen; i++)
|
|
if(fld & (1<<i)) SETB(s, slen, i+bit);
|
|
else CLRB(s, slen, i+bit);
|
|
}
|
|
|
|
static naRef dofld(naContext c, int argc, naRef* args, int sign)
|
|
{
|
|
naRef s = argc > 0 ? args[0] : naNil();
|
|
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
|
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
|
unsigned int f;
|
|
if(!naIsString(s) || !MUTABLE(args[0]) || bit < 0 || len < 0)
|
|
naRuntimeError(c, "missing/bad argument to fld/sfld");
|
|
f = fld(c, (void*)naStr_data(s), naStr_len(s), bit, len);
|
|
if(!sign) return naNum(f);
|
|
if(f & (1 << (len-1))) f |= ~((1<<len)-1); // sign extend
|
|
return naNum((signed int)f);
|
|
}
|
|
|
|
static naRef f_sfld(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
return dofld(c, argc, args, 1);
|
|
}
|
|
|
|
static naRef f_fld(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
return dofld(c, argc, args, 0);
|
|
}
|
|
|
|
static naRef f_setfld(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
naRef s = argc > 0 ? args[0] : naNil();
|
|
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
|
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
|
naRef val = argc > 3 ? naNumValue(args[3]) : naNil();
|
|
if(!argc || !MUTABLE(args[0])|| bit < 0 || len < 0 || IS_NIL(val))
|
|
naRuntimeError(c, "missing/bad argument to setfld");
|
|
setfld(c, (void*)naStr_data(s), naStr_len(s), bit, len, (unsigned int)val.num);
|
|
return naNil();
|
|
}
|
|
|
|
static naRef f_buf(naContext c, naRef me, int argc, naRef* args)
|
|
{
|
|
naRef len = argc ? naNumValue(args[0]) : naNil();
|
|
if(IS_NIL(len)) naRuntimeError(c, "missing/bad argument to buf");
|
|
return naStr_buf(naNewString(c), (int)len.num);
|
|
}
|
|
|
|
static naCFuncItem funcs[] = {
|
|
{ "sfld", f_sfld },
|
|
{ "fld", f_fld },
|
|
{ "setfld", f_setfld },
|
|
{ "buf", f_buf },
|
|
{ 0 }
|
|
};
|
|
|
|
naRef naInit_bits(naContext c)
|
|
{
|
|
return naGenLib(c, funcs);
|
|
}
|