I spent a bit of time yesterday browsing the old LOLCODE forums, thinking about this, and writing a little bit of pseudo-code. First, here is what it may look like:
HAI 1.4
   CAN HAS STDIO?
   I HAS A filename ITZ "temp.txt"
   I HAS A mode ITZ "r"
   I HAS A file
   file R STDIO IZ FOPENIN YR filename AN YR mode
   BTW "file" is a BUKKIT with some state that's used by the stdio functions
   ...
   STDIO IZ FCLOSEIN YR file
KTHXBYE
Here is one possible implementation sketch which I tried to have leverage the existing parsing and interpretation structure as much as possible:
Create binding.{c,h}, which provide the binding infrastructure. For example, in binding.h, there would be something like:
#ifndef __BINDING_H__
#define __BINDING_H__
#include "parser.h"
/**
 * Stores a binding to an external library call to export.
 */
typedef struct {
   IdentifierNode *library;   /**< The library this binding belongs to. */
   FuncDefStmtNode *interface; /**< The interface that exports the binding. */
} Binding;
#endif /* __BINDING_H__ */
Here, "library" is used to determine which top-level BUKKIT to add "interface" to as an element. "interface" is defined like other FuncDefStmtNodes (i.e., it contains a function name, an argument list, and a function body), *except* that it's function body is actually a call to some C code that can reference the current variable scope (which will contain the arguments). Here is how that might be accomplished:
In parser.h, add a new type of statement node, ST_BINDING, whose corresponding struct looks like this:
/**
 * Stores a binding to a native function.
 */
typedef struct {
   ReturnObject *(*binding)(ScopeObject *); /**< The function that implements the binding. */
} BindingStmtNode;
This is really ugly because it deals with a pointer to a function, but here is what is going on: This statement type's member "binding" is a pointer to a C function that takes as an argument a pointer to a ScopeObject (which stores variable state), and returns a pointer to a ReturnObject. This function could be implemented by the person binding libraries like this:
ReturnObject *FOPENIN(ScopeObject scope)
{
   /* extract arguments from scope */
   ValueObject fname = getScopeValueLocal(scope, ...);
   ValueObject mode = getScopeValueLocal(scope, ...);
   /* do actual binding stuff */
   FILE *file = fopen(getString(fname), getString(mode));
   /* create a BUKKIT and store "file" in it */
   return createArrayValueObject(/* the BUKKIT created above */);
}
This can be stored in the body of the FuncDefStmtNode from the Binding struct defined above, and will more or less "just work" with the existing function call code.
Notice that this will probably require modifying the ValueData union to store a new void * element of binary blob data to store state passed around among library calls.
Also, this implementation source code should probably live in a "libs/" folder in the main source code directory with sub-folders for each of the libraries ("libs/STDIO" and so on). It would be nice to have pre-compiled BUKKITs for each of the libraries that can be dynamically inserted into the top-level scope as they are imported via "CAN HAS" statements.
Just some thoughts!
- Justin