cleaning up binding code

This commit is contained in:
Justin Meza 2013-02-24 15:44:33 -05:00
parent 38e67f8287
commit 5337b65513
9 changed files with 262 additions and 67 deletions

102
binding.c
View File

@ -3,28 +3,33 @@
struct returnobject;
struct scopeobject;
ValueObject *getArg(struct scopeobject *scope, char *name)
{
IdentifierNode *id = createIdentifierNode(IT_DIRECT, (void *)copyString(name), NULL, NULL, 0);
ValueObject *val = getScopeValueLocal(scope, scope, id);
deleteIdentifierNode(id);
return val;
}
struct returnobject *fopenWrapper(struct scopeobject *scope)
{
IdentifierNode *id1 = createIdentifierNode(IT_DIRECT, (void *)copyString("filename"), NULL, NULL, 0);
ValueObject *val1 = getScopeValueLocal(scope, scope, id1);
IdentifierNode *id2 = createIdentifierNode(IT_DIRECT, (void *)copyString("mode"), NULL, NULL, 0);
ValueObject *val2 = getScopeValueLocal(scope, scope, id2);
char *filename = getString(val1);
char *mode = getString(val2);
ValueObject *arg1 = getArg(scope, "filename");
ValueObject *arg2 = getArg(scope, "mode");
char *filename = getString(arg1);
char *mode = getString(arg2);
FILE *f = fopen(filename, mode);
ValueObject *ret = createBlobValueObject(f);
return createReturnObject(RT_RETURN, ret);
}
struct returnobject *freadWrapper(struct scopeobject *scope)
{
IdentifierNode *id1 = createIdentifierNode(IT_DIRECT, (void *)copyString("file"), NULL, NULL, 0);
ValueObject *val1 = getScopeValueLocal(scope, scope, id1);
IdentifierNode *id2 = createIdentifierNode(IT_DIRECT, (void *)copyString("length"), NULL, NULL, 0);
ValueObject *val2 = getScopeValueLocal(scope, scope, id2);
FILE *file = (FILE *)getBlob(val1);
int length = getInteger(val2);
ValueObject *arg1 = getArg(scope, "file");
ValueObject *arg2 = getArg(scope, "length");
FILE *file = (FILE *)getBlob(arg1);
int length = getInteger(arg2);
char *buf = malloc((sizeof(char) * length) + 1);
fread(buf, 1, length, file);
@ -36,46 +41,83 @@ struct returnobject *freadWrapper(struct scopeobject *scope)
struct returnobject *fcloseWrapper(struct scopeobject *scope)
{
IdentifierNode *id1 = createIdentifierNode(IT_DIRECT, (void *)copyString("file"), NULL, NULL, 0);
ValueObject *val1 = getScopeValueLocal(scope, scope, id1);
FILE *file = (FILE *)getBlob(val1);
ValueObject *arg1 = getArg(scope, "file");
FILE *file = (FILE *)getBlob(arg1);
fclose(file);
deleteValueObject(arg1);
return createReturnObject(RT_DEFAULT, NULL);
}
void loadBinding(ScopeObject *scope)
void loadLibrary(ScopeObject *scope, IdentifierNode *name)
{
/* TODO: make this select which library to load */
/* stdio */
ScopeObject *lib = createScopeObject(scope);
IdentifierNode* id = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0);
createScopeValue(scope, scope, id);
ValueObject *val = createArrayValueObject(lib);
updateScopeValue(scope, scope, id, val);
loadBinding(lib, "FOPENIN", "filename mode", &fopenWrapper);
loadBinding(lib, "FREADIN", "file length", &freadWrapper);
loadBinding(lib, "FCLOSIN", "file", &fcloseWrapper);
}
void loadBinding(ScopeObject *scope, char *name, const char *args, struct returnobject *(*binding)(struct scopeobject *))
{
/* TODO: add error checking and handling */
/* stdio */
ScopeObject *stdio = createScopeObject(scope);
IdentifierNode* name_stdio = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0);
createScopeValue(scope, scope, name_stdio);
ValueObject *val_stdio = createArrayValueObject(stdio);
updateScopeValue(scope, scope, name_stdio, val_stdio);
IdentifierNode* id = createIdentifierNode(IT_DIRECT, (void *)copyString(name), NULL, NULL, 0);
StmtNodeList *stmts = createStmtNodeList();
BindingStmtNode *stmt = createBindingStmtNode(binding);
StmtNode *wrapper = createStmtNode(ST_BINDING, stmt);
addStmtNode(stmts, wrapper);
BlockNode *body = createBlockNode(stmts);
IdentifierNodeList *ids = createIdentifierNodeList();
const char *start = args;
while (start != NULL) {
char *end = strchr(start, ' ');
char *temp = NULL;
unsigned int len = 0;
if (end != NULL) len = (end - start);
else len = strlen(start);
temp = malloc(sizeof(char) * (len + 1));
strncpy(temp, start, len);
temp[len] = '\0';
if (end != NULL) start = (end + 1);
else start = NULL;
IdentifierNode *arg = createIdentifierNode(IT_DIRECT, (void *)temp, NULL, NULL, 0);
addIdentifierNode(ids, arg);
}
FuncDefStmtNode *interface = createFuncDefStmtNode(NULL, id, ids, body);
ValueObject *val = createFunctionValueObject(interface);
createScopeValue(scope, scope, id);
updateScopeValue(scope, scope, id, val);
return;
/* fopen */
/*
{
IdentifierNode* name = createIdentifierNode(IT_DIRECT, (void *)copyString("FOPENIN"), NULL, NULL, 0);
IdentifierNodeList *args = createIdentifierNodeList();
IdentifierNode *filename = createIdentifierNode(IT_DIRECT, (void *)copyString("filename"), NULL, NULL, 0);
IdentifierNode *mode = createIdentifierNode(IT_DIRECT, (void *)copyString("mode"), NULL, NULL, 0);
addIdentifierNode(args, filename);
addIdentifierNode(args, mode);
StmtNodeList *stmts = createStmtNodeList();
BindingStmtNode *binding = createBindingStmtNode(&fopenWrapper);
StmtNode *wrapper = createStmtNode(ST_BINDING, binding);
addStmtNode(stmts, wrapper);
BlockNode *body = createBlockNode(stmts);
/* TODO: should this first parameter be NULL? */
FuncDefStmtNode *interface = createFuncDefStmtNode(NULL, name, args, body);
ValueObject *val = createFunctionValueObject(interface);
createScopeValue(stdio, stdio, name);
updateScopeValue(stdio, stdio, name, val);
}
*/
/* fread */
/*
{
IdentifierNode* name = createIdentifierNode(IT_DIRECT, (void *)copyString("FREADIN"), NULL, NULL, 0);
IdentifierNodeList *args = createIdentifierNodeList();
@ -88,14 +130,15 @@ void loadBinding(ScopeObject *scope)
StmtNode *wrapper = createStmtNode(ST_BINDING, binding);
addStmtNode(stmts, wrapper);
BlockNode *body = createBlockNode(stmts);
/* TODO: should this first parameter be NULL? */
FuncDefStmtNode *interface = createFuncDefStmtNode(NULL, name, args, body);
ValueObject *val = createFunctionValueObject(interface);
createScopeValue(stdio, stdio, name);
updateScopeValue(stdio, stdio, name, val);
}
*/
/* fclose */
/*
{
IdentifierNode* name = createIdentifierNode(IT_DIRECT, (void *)copyString("FCLOSIN"), NULL, NULL, 0);
IdentifierNodeList *args = createIdentifierNodeList();
@ -111,6 +154,7 @@ void loadBinding(ScopeObject *scope)
createScopeValue(stdio, stdio, name);
updateScopeValue(stdio, stdio, name, val);
}
*/
return;

View File

@ -23,27 +23,8 @@ typedef struct {
FuncDefStmtNode *interface; /**< The interface that exports the binding. */
} Binding;
void loadBinding(ScopeObject *); /* TODO: make this take an IdentifierNode library to load */
/**
* TODO:
* - At startup, check which bindings are imported (using "CAN HAS" syntax)
* - Package those bindings as VT_FUNCs in BUKKITs
* - Add those bindings to the top-level scope (maybe create a new,
* higher-than-global scope for this)
* - To implement a new binding, specify the interface, which will contain a
* BlockNode that contains a StmtListNode with one statement: a
* BindingStmtNode that implements a native function that modifies directly
* the scope.
* - Binding creation/deletion helper functions.
IdentifierNode *scope = ??? what goes here again?;
IdentifierNode *name = createIdentifierNode("FileOpen");
IdentifierNodeList *args = ... add these ...
BlockNode *block = ... block with appropriate BindingStmtNode ...
FuncDefStmtNode *def = createFuncDefStmtNode();
Binding *binding = createBinding("STDIO", def);
*/
ValueObject *getArg(struct scopeobject *, char *);
void loadLibrary(ScopeObject *, IdentifierNode *);
void loadBinding(ScopeObject *, char *, const char *, struct returnobject *(*)(struct scopeobject *));
#endif /* __BINDING_H__ */

View File

@ -3683,11 +3683,32 @@ ReturnObject *interpretBindingStmtNode(StmtNode *node,
return (stmt->binding)(scope);
}
/**
* Interprets a library import statement.
*
* \param [in] node The statement to interpret.
*
* \param [in] scope The scope to evaluate \a node under.
*
* \pre \a node contains a statement created by createImportStmtNode().
*
* \return A pointer to a default return value.
*
* \retval NULL An error occurred during interpretation.
*/
ReturnObject *interpretImportStmtNode(StmtNode *node,
ScopeObject *scope)
{
ImportStmtNode *stmt = (ImportStmtNode *)node->stmt;
loadLibrary(scope, stmt->name);
return createReturnObject(RT_DEFAULT, NULL);
}
/*
* A jump table for statements. The index of a function in the table is given
* by its its index in the enumerated StmtType type.
*/
static ReturnObject *(*StmtJumpTable[15])(StmtNode *, ScopeObject *) = {
static ReturnObject *(*StmtJumpTable[16])(StmtNode *, ScopeObject *) = {
interpretCastStmtNode,
interpretPrintStmtNode,
interpretInputStmtNode,
@ -3702,7 +3723,8 @@ static ReturnObject *(*StmtJumpTable[15])(StmtNode *, ScopeObject *) = {
interpretFuncDefStmtNode,
interpretExprStmtNode,
interpretAltArrayDefStmtNode,
interpretBindingStmtNode };
interpretBindingStmtNode,
interpretImportStmtNode };
/**
* Interprets a statement.
@ -3798,10 +3820,7 @@ int interpretMainNode(MainNode *main)
{
ReturnObject *ret = NULL;
if (!main) return 1;
ScopeObject *libs = createScopeObject(NULL);
if (!libs) return 1;
loadBinding(libs);
ret = interpretBlockNode(main->block, libs);
ret = interpretBlockNode(main->block, NULL);
if (!ret) return 1;
deleteReturnObject(ret);
return 0;

View File

@ -260,6 +260,8 @@ ReturnObject *interpretDeallocationStmtNode(StmtNode *, ScopeObject *);
ReturnObject *interpretFuncDefStmtNode(StmtNode *, ScopeObject *);
ReturnObject *interpretExprStmtNode(StmtNode *, ScopeObject *);
ReturnObject *interpretAltArrayDefStmtNode(StmtNode *, ScopeObject *);
ReturnObject *interpretBindingStmtNode(StmtNode *, ScopeObject *);
ReturnObject *interpretImportStmtNode(StmtNode *, ScopeObject *);
/**@}*/
/**

17
lexer.c
View File

@ -198,6 +198,21 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
start += 2;
continue;
}
/* Question mark (?) is its own lexeme */
if (*start == '?') {
Lexeme *lex = createLexeme("?", fname, line);
if (!lex) {
deleteLexemeList(list);
return NULL;
}
if (!addLexeme(list, lex)) {
deleteLexeme(lex);
deleteLexemeList(list);
return NULL;
}
start++;
continue;
}
/* Skip over leading whitespace */
while (isspace(*start)) {
unsigned int newline = 0;
@ -292,6 +307,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
if (start[len] && !isspace(start[len])
&& *(start + len) != ','
&& *(start + len) != '!'
&& *(start + len) != '?'
&& strncmp(start + len, "'Z", 2)
&& strncmp(start + len, "...", 3)
&& strncmp(start + len, "\xE2\x80\xA6", 3)) {
@ -305,6 +321,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
while (start[len] && !isspace(start[len])
&& *(start + len) != ','
&& *(start + len) != '!'
&& *(start + len) != '?'
&& strncmp(start + len, "'Z", 2)
&& strncmp(start + len, "...", 3)
&& strncmp(start + len, "\xE2\x80\xA6", 3))

118
parser.c
View File

@ -514,6 +514,16 @@ void deleteStmtNode(StmtNode *node)
deleteAltArrayDefStmtNode(stmt);
break;
}
case ST_BINDING: {
BindingStmtNode *stmt = (BindingStmtNode *)node->stmt;
deleteBindingStmtNode(stmt);
break;
}
case ST_IMPORT: {
ImportStmtNode *stmt = (ImportStmtNode *)node->stmt;
deleteImportStmtNode(stmt);
break;
}
default:
error(PR_UNKNOWN_STATEMENT_TYPE);
break;
@ -1105,6 +1115,40 @@ void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *node)
free(node);
}
/**
* Creates a library import statement.
*
* \param [in] name The name of the library to import.
*
* \return A pointer to a library import statement with the desired properties.
*
* \retval NULL Memory allocation failed.
*/
ImportStmtNode *createImportStmtNode(IdentifierNode *name)
{
ImportStmtNode *p = malloc(sizeof(ImportStmtNode));
if (!p) {
perror("malloc");
return NULL;
}
p->name = name;
return p;
}
/**
* Deletes a library import statement.
*
* \param [in,out] node The library import statement to delete.
*
* \post The memory at \a node and all of its members will be freed.
*/
void deleteImportStmtNode(ImportStmtNode *node)
{
if (!node) return;
deleteIdentifierNode(node->name);
free(node);
}
/**
* Creates a binding statement.
*
@ -3905,6 +3949,76 @@ parseAltArrayDefStmtNodeAbort: /* Exception handling */
return NULL;
}
/**
* Parses tokens into a library import statement.
*
* \param [in] tokenp The position in a token list to start parsing at.
*
* \post \a tokenp will point to the next unparsed token.
*
* \return A pointer to a return statement.
*
* \retval NULL Unable to parse.
*/
StmtNode *parseImportStmtNode(Token ***tokenp)
{
IdentifierNode *value = NULL;
ImportStmtNode *stmt = NULL;
StmtNode *ret = NULL;
int status;
/* Work from a copy of the token stream in case something goes wrong */
Token **tokens = *tokenp;
#ifdef DEBUG
debug("ST_IMPORT");
#endif
/* Remove the library import keyword from the token stream */
status = acceptToken(&tokens, TT_CANHAS);
if (!status) {
parser_error_expected_token(TT_CANHAS, tokens);
goto parseImportStmtNodeAbort;
}
/* Parse the library name */
value = parseIdentifierNode(&tokens);
if (!value) goto parseImportStmtNodeAbort;
/* Check for the question mark token (currently optional) */
acceptToken(&tokens, TT_QUESTION);
/* The library import statement must reside on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseImportStmtNodeAbort;
}
/* Create the new ImportStmtNode structure */
stmt = createImportStmtNode(value);
if (!stmt) goto parseImportStmtNodeAbort;
/* Create the new StmtNode structure */
ret = createStmtNode(ST_IMPORT, stmt);
if (!ret) goto parseImportStmtNodeAbort;
/* Since we're successful, update the token stream */
*tokenp = tokens;
return ret;
parseImportStmtNodeAbort: /* Exception handling */
/* Clean up any allocated structures */
if (ret) deleteStmtNode(ret);
else if (stmt) deleteImportStmtNode(stmt);
else {
if (value) deleteIdentifierNode(value);
}
return NULL;
}
/**
* Parses tokens into a statement.
*
@ -4023,6 +4137,10 @@ StmtNode *parseStmtNode(Token ***tokenp)
else if (peekToken(&tokens, TT_OHAIIM)) {
ret = parseAltArrayDefStmtNode(tokenp);
}
/* Library import statement */
else if (peekToken(&tokens, TT_CANHAS)) {
ret = parseImportStmtNode(tokenp);
}
/* Bare expression */
else if ((expr = parseExprNode(&tokens))) {
int status;

View File

@ -229,6 +229,7 @@ typedef enum {
ST_EXPR, /**< Expression statement. */
ST_ALTARRAYDEF, /**< Function definition statement. */
ST_BINDING, /**< Binding to external library. */
ST_IMPORT, /**< Library import statement. */
} StmtType;
/**
@ -365,6 +366,13 @@ typedef struct {
IdentifierNode *parent; /**< An optional inherited array. */
} AltArrayDefStmtNode;
/**
* Stores a library import statement.
*/
typedef struct {
IdentifierNode *name; /**< The name of the library to import. */
} ImportStmtNode;
/**
* Stores a binding to a native function.
*/
@ -726,6 +734,16 @@ AltArrayDefStmtNode *createAltArrayDefStmtNode(IdentifierNode *, BlockNode *, Id
void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *);
/**@}*/
/**
* \name ImportStmtNode modifiers
*
* Functions for creating and deleting ImportStmtNodes.
*/
/**@{*/
ImportStmtNode *createImportStmtNode(IdentifierNode *);
void deleteImportStmtNode(ImportStmtNode *);
/**@}*/
/**
* \name BindingStmtNode modifiers
*
@ -734,7 +752,7 @@ void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *);
/**@{*/
struct returnobject;
struct scopeobject;
BindingStmtNode *createBindingStmtNode(struct returnobject *(*binding)(struct scopeobject *));
BindingStmtNode *createBindingStmtNode(struct returnobject *(*)(struct scopeobject *));
void deleteBindingStmtNode(BindingStmtNode *);
/**@}*/
@ -823,6 +841,7 @@ StmtNode *parseLoopStmtNode(Token ***);
StmtNode *parseDeallocationStmtNode(Token ***);
StmtNode *parseFuncDefStmtNode(Token ***);
StmtNode *parseAltArrayDefStmtNode(Token ***);
StmtNode *parseImportStmtNode(Token ***);
/**@}*/
/**

View File

@ -319,15 +319,6 @@ Token **tokenizeLexemes(LexemeList *list)
token = createToken(TT_BOOLEAN, "WIN", fname, line);
token->data.i = 1;
}
/* CAN HAS STDIO? */
else if (n < list->num - 2
&& !strcmp(lexeme->image, "CAN")
&& !strcmp(list->lexemes[n + 1]->image, "HAS")
&& !strcmp(list->lexemes[n + 2]->image, "STDIO?")) {
n += 2;
/* Just for fun; not actually in spec */
continue;
}
/* Newline */
/* Note that the spec is unclear as to whether a command *must*
* follow a comma. For now, we let commas end a line. */

View File

@ -104,6 +104,8 @@ typedef enum {
TT_OHAIIM, /**< Alternate array declaration. */
TT_IMLIEK, /**< Alternate inherited object declaration. */
TT_KTHX, /**< End of alternate array declaration. */
TT_CANHAS, /**< Library import declaration. */
TT_QUESTION, /**< End of library import declaration. */
TT_ENDOFTOKENS /**< Sentinel end of this enum -- don't move it! */
} TokenType;
@ -181,6 +183,8 @@ static const char *keywords[] = {
"O HAI IM", /* TT_OHAIIM */
"IM LIEK", /* TT_IMLIEK */
"KTHX", /* TT_KTHX */
"CAN HAS", /* TT_CANHAS */
"?", /* TT_QUESTION */
"" /* TT_ENDOFTOKENS */
};