X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fnasal.h;h=a7741b49639657de8885d62ebe612856b90876d7;hb=a1bb62f43c2f68a5ce4424f4d99f785b6d88bafe;hp=57b0372de295c78fa401df1ac1360f7a8eba6551;hpb=83b4dcb55cea1ba30a1ccfd08b517926672a018b;p=simgear.git diff --git a/simgear/nasal/nasal.h b/simgear/nasal/nasal.h index 57b0372d..a7741b49 100644 --- a/simgear/nasal/nasal.h +++ b/simgear/nasal/nasal.h @@ -4,107 +4,141 @@ extern "C" { #endif -// This is a nasal "reference". They are always copied by value, and -// contain either a pointer to a garbage-collectable nasal object -// (string, vector, hash) or a floating point number. Keeping the -// number here is an optimization to prevent the generation of -// zillions of tiny "number" object that have to be collected. Note -// sneaky hack: on little endian systems, placing reftag after ptr and -// putting 1's in the top 13 (except the sign bit) bits makes the -// double value a NaN, and thus unmistakable (no actual number can -// appear as a reference, and vice versa). Swap the structure order -// on 32 bit big-endian systems. On 64 bit sytems of either -// endianness, reftag and the double won't be coincident anyway. -#define NASAL_REFTAG 0x7ff56789 // == 2,146,789,257 decimal -typedef union { - double num; - struct { -#ifdef NASAL_BIG_ENDIAN_32_BIT - int reftag; // Big-endian systems need this here! +#include "naref.h" + +#if __GNUC__ > 2 +/* This marks the function as having no side effects and depending on + * nothing but its arguments, which allows the optimizer to avoid + * duplicate calls to naNil(). */ +#define GCC_PURE __attribute__((__pure__)) +#else +#define GCC_PURE #endif - union { - struct naObj* obj; - struct naStr* str; - struct naVec* vec; - struct naHash* hash; - struct naCode* code; - struct naFunc* func; - struct naClosure* closure; - struct naCCode* ccode; - struct naGhost* ghost; - } ptr; -#ifndef NASAL_BIG_ENDIAN_32_BIT - int reftag; // Little-endian and 64 bit systems need this here! -#endif - } ref; -} naRef; typedef struct Context* naContext; // The function signature for an extension function: -typedef naRef (*naCFunction)(naContext ctx, naRef args); +typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args); // All Nasal code runs under the watch of a naContext: naContext naNewContext(); - -// Save this object in the context, preventing it (and objects +void naFreeContext(naContext c); + +// Use this when making a call to a new context "underneath" a +// preexisting context on the same stack. It allows stack walking to +// see through the boundary, and eliminates the need to release the +// mod lock (i.e. must be called with the mod lock held!) +naContext naSubContext(naContext super); + +// The naContext supports a user data pointer that can be used to +// store data specific to an naCall invocation without exposing it to +// Nasal as a ghost. FIXME: this API is semi-dangerous, there is no +// provision for sharing it, nor for validating the source or type of +// the pointer returned. +void naSetUserData(naContext c, void* p); +void* naGetUserData(naContext c) GCC_PURE; + +// "Save" this object in the context, preventing it (and objects // referenced by it) from being garbage collected. void naSave(naContext ctx, naRef obj); -// Parse a buffer in memory into a code object. +// Similar, but the object is automatically released when the +// context next runs native bytecode. Useful for saving off C-space +// temporaries to protect them before passing back into a naCall. +void naTempSave(naContext c, naRef r); + +// Parse a buffer in memory into a code object. The srcFile parameter +// is a Nasal string representing the "file" from which the code is +// read. The "first line" is typically 1, but is settable for +// situations where the Nasal code is embedded in another context with +// its own numbering convetions. If an error occurs, returns nil and +// sets the errLine pointer to point to the line at fault. The string +// representation of the error can be retrieved with naGetError() on +// the context. naRef naParseCode(naContext c, naRef srcFile, int firstLine, char* buf, int len, int* errLine); // Binds a bare code object (as returned from naParseCode) with a // closure object (a hash) to act as the outer scope / namespace. -// FIXME: this API is weak. It should expose the recursive nature of -// closures, and allow for extracting the closure and namespace -// information from function objects. naRef naBindFunction(naContext ctx, naRef code, naRef closure); -// Call a code or function object with the specifed arguments "on" the -// specified object and using the specified hash for the local -// variables. Any of args, obj or locals may be nil. -naRef naCall(naContext ctx, naRef func, naRef args, naRef obj, naRef locals); +// Similar, but it binds to the current context's closure (i.e. the +// namespace at the top of the current call stack). +naRef naBindToContext(naContext ctx, naRef code); + +// Call a code or function object with the specified arguments "on" +// the specified object and using the specified hash for the local +// variables. Passing a null args array skips the parameter variables +// (e.g. "arg") assignments; to get a zero-length arg instead, pass in +// argc==0 and a non-null args vector. The obj or locals parameters +// may be nil. Will attempt to acquire the mod lock, so call +// naModUnlock() first if the lock is already held. +naRef naCall(naContext ctx, naRef func, int argc, naRef* args, + naRef obj, naRef locals); + +// As naCall(), but continues execution at the operation after a +// previous die() call or runtime error. Useful to do "yield" +// semantics, leaving the context in a condition where it can be +// restarted from C code. Cannot be used currently to restart a +// failed operation. Will attempt to acquire the mod lock, so call +// naModUnlock() first if the lock is already held. +naRef naContinue(naContext ctx); // Throw an error from the current call stack. This function makes a // longjmp call to a handler in naCall() and DOES NOT RETURN. It is // intended for use in library code that cannot otherwise report an // error via the return value, and MUST be used carefully. If in -// doubt, return naNil() as your error condition. -void naRuntimeError(naContext ctx, char* msg); +// doubt, return naNil() as your error condition. Works like +// printf(). +void naRuntimeError(naContext c, const char* fmt, ...); + +// "Re-throws" a runtime error caught from the subcontext. Acts as a +// naRuntimeError() called on the parent context. Does not return. +void naRethrowError(naContext subc); -// Call a method on an object (NOTE: func is a function binding, *not* -// a code object as returned from naParseCode). -naRef naMethod(naContext ctx, naRef func, naRef object); +// Retrieve the specified member from the object, respecting the +// "parents" array as for "object.field". Returns zero for missing +// fields. +int naMember_get(naRef obj, naRef field, naRef* out); +int naMember_cget(naRef obj, const char* field, naRef* out); // Returns a hash containing functions from the Nasal standard library // Useful for passing as a namespace to an initial function call -naRef naStdLib(naContext c); - -// Ditto, with math functions -naRef naMathLib(naContext c); - -// Current line number & error message +naRef naInit_std(naContext c); + +// Ditto, for other core libraries +naRef naInit_math(naContext c); +naRef naInit_bits(naContext c); +naRef naInit_io(naContext c); +naRef naInit_regex(naContext c); +naRef naInit_unix(naContext c); +naRef naInit_thread(naContext c); +naRef naInit_utf8(naContext c); +naRef naInit_sqlite(naContext c); +naRef naInit_readline(naContext c); +naRef naInit_gtk(naContext ctx); +naRef naInit_cairo(naContext ctx); + +// Context stack inspection, frame zero is the "top" int naStackDepth(naContext ctx); int naGetLine(naContext ctx, int frame); naRef naGetSourceFile(naContext ctx, int frame); char* naGetError(naContext ctx); // Type predicates -int naIsNil(naRef r); -int naIsNum(naRef r); -int naIsString(naRef r); -int naIsScalar(naRef r); -int naIsVector(naRef r); -int naIsHash(naRef r); -int naIsCode(naRef r); -int naIsFunc(naRef r); -int naIsCCode(naRef r); +int naIsNil(naRef r) GCC_PURE; +int naIsNum(naRef r) GCC_PURE; +int naIsString(naRef r) GCC_PURE; +int naIsScalar(naRef r) GCC_PURE; +int naIsVector(naRef r) GCC_PURE; +int naIsHash(naRef r) GCC_PURE; +int naIsCode(naRef r) GCC_PURE; +int naIsFunc(naRef r) GCC_PURE; +int naIsCCode(naRef r) GCC_PURE; // Allocators/generators: -naRef naNil(); -naRef naNum(double num); +naRef naNil() GCC_PURE; +naRef naNum(double num) GCC_PURE; naRef naNewString(naContext c); naRef naNewVector(naContext c); naRef naNewHash(naContext c); @@ -112,17 +146,19 @@ naRef naNewFunc(naContext c, naRef code); naRef naNewCCode(naContext c, naCFunction fptr); // Some useful conversion/comparison routines -int naEqual(naRef a, naRef b); -int naTrue(naRef b); -naRef naNumValue(naRef n); +int naEqual(naRef a, naRef b) GCC_PURE; +int naStrEqual(naRef a, naRef b) GCC_PURE; +int naTrue(naRef b) GCC_PURE; +naRef naNumValue(naRef n) GCC_PURE; naRef naStringValue(naContext c, naRef n); // String utilities: -int naStr_len(naRef s); -char* naStr_data(naRef s); -naRef naStr_fromdata(naRef dst, char* data, int len); +int naStr_len(naRef s) GCC_PURE; +char* naStr_data(naRef s) GCC_PURE; +naRef naStr_fromdata(naRef dst, const char* data, int len); naRef naStr_concat(naRef dest, naRef s1, naRef s2); naRef naStr_substr(naRef dest, naRef str, int start, int len); +naRef naInternSymbol(naRef sym); // Vector utilities: int naVec_size(naRef v); @@ -130,6 +166,7 @@ naRef naVec_get(naRef v, int i); void naVec_set(naRef vec, int i, naRef o); int naVec_append(naRef vec, naRef o); naRef naVec_removelast(naRef vec); +void naVec_setsize(naRef vec, int sz); // Hash utilities: int naHash_size(naRef h); @@ -142,13 +179,41 @@ void naHash_keys(naRef dst, naRef hash); // Ghost utilities: typedef struct naGhostType { - void (*destroy)(void* ghost); + void(*destroy)(void*); + const char* name; } naGhostType; naRef naNewGhost(naContext c, naGhostType* t, void* ghost); naGhostType* naGhost_type(naRef ghost); void* naGhost_ptr(naRef ghost); int naIsGhost(naRef r); +// Acquires a "modification lock" on a context, allowing the C code to +// modify Nasal data without fear that such data may be "lost" by the +// garbage collector (nasal data on the C stack is not examined in +// GC!). This disallows garbage collection until the current thread +// can be blocked. The lock should be acquired whenever nasal objects +// are being modified. It need not be acquired when only read access +// is needed, PRESUMING that the Nasal data being read is findable by +// the collector (via naSave, for example) and that another Nasal +// thread cannot or will not delete the reference to the data. It +// MUST NOT be acquired by naCFunction's, as those are called with the +// lock already held; acquiring two locks for the same thread will +// cause a deadlock when the GC is invoked. It should be UNLOCKED by +// naCFunction's when they are about to do any long term non-nasal +// processing and/or blocking I/O. Note that naModLock() may need to +// block to allow garbage collection to occur, and that garbage +// collection by other threads may be blocked until naModUnlock() is +// called. It must also be UNLOCKED by threads that hold a lock +// already before making a naCall() or naContinue() call -- these +// functions will attempt to acquire the lock again. +void naModLock(); +void naModUnlock(); + +// Library utilities. Generate namespaces and add symbols. +typedef struct { char* name; naCFunction func; } naCFuncItem; +naRef naGenLib(naContext c, naCFuncItem *funcs); +void naAddSym(naContext c, naRef ns, char *sym, naRef val); + #ifdef __cplusplus } // extern "C" #endif