X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fnasal.h;h=a7741b49639657de8885d62ebe612856b90876d7;hb=a1bb62f43c2f68a5ce4424f4d99f785b6d88bafe;hp=a083d02b72ab7c15d69cd81f2829a8f8bd2d6a27;hpb=966331dac7da0f9ec03ffeb052dd2cd72829b2eb;p=simgear.git diff --git a/simgear/nasal/nasal.h b/simgear/nasal/nasal.h index a083d02b..a7741b49 100644 --- a/simgear/nasal/nasal.h +++ b/simgear/nasal/nasal.h @@ -4,73 +4,17 @@ extern "C" { #endif -#ifndef BYTE_ORDER - -# if (BSD >= 199103) -# include -# elif defined(__CYGWIN__) || defined(__MINGW32__) -# include -# elif defined(linux) -# include -# else -# ifndef LITTLE_ENDIAN -# define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ -# endif -# ifndef BIG_ENDIAN -# define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */ -# endif - -# if defined(ultrix) || defined(__alpha__) || defined(__alpha) || \ - defined(__i386__) || defined(__i486__) || defined(_X86_) || \ - defined(sun386) -# define BYTE_ORDER LITTLE_ENDIAN -# else -# define BYTE_ORDER BIG_ENDIAN -# endif -# endif /* BSD */ -#endif /* BYTE_ORDER */ - -#if BYTE_ORDER == BIG_ENDIAN -# include -# if (LONG_MAX == 2147483647) -# define NASAL_BIG_ENDIAN_32_BIT 1 -# endif +#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 -// 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! -#endif - union { - struct naObj* obj; - struct naStr* str; - struct naVec* vec; - struct naHash* hash; - struct naCode* code; - struct naFunc* func; - 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: @@ -80,68 +24,121 @@ typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args); naContext naNewContext(); void naFreeContext(naContext c); -// Save this object in the context, preventing it (and objects +// 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); // 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 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); +// 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); @@ -149,16 +146,16 @@ naRef naNewFunc(naContext c, naRef code); naRef naNewCCode(naContext c, naCFunction fptr); // Some useful conversion/comparison routines -int naEqual(naRef a, naRef b); -int naStrEqual(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); @@ -182,7 +179,8 @@ 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); @@ -191,18 +189,31 @@ 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 (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 modifications to -// Nasal objects are made. It need not be acquired when only read -// access is needed. 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. +// 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