]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/nasal.h
Removal of PLIB/SG from SimGear
[simgear.git] / simgear / nasal / nasal.h
index 417ca67d3438959a775e89c164b8bfe45f7eebf9..a7741b49639657de8885d62ebe612856b90876d7 100644 (file)
 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;
-        } 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);
@@ -111,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);
@@ -129,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);
@@ -139,6 +177,43 @@ void naHash_cset(naRef hash, char* key, naRef val);
 void naHash_delete(naRef hash, naRef key);
 void naHash_keys(naRef dst, naRef hash);
 
+// Ghost utilities:
+typedef struct naGhostType {
+    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