/* duktape binding generation implementation * * This file is part of nsgenbind. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2012 Vincent Sanders */ #include #include #include #include #include #include #include #include #include "options.h" #include "utils.h" #include "nsgenbind-ast.h" #include "webidl-ast.h" #include "ir.h" #include "duk-libdom.h" /** prefix for all generated functions */ #define DLPFX "dukky" #define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_" /** * get default value as a string */ static int get_member_default_str(struct ir_entry *dictionarye, struct ir_operation_argument_entry *membere, enum webidl_type member_type, char **defl_out) { struct webidl_node *lit_node; enum webidl_node_type lit_type; int *lit_int; float *lit_flt; lit_node = webidl_node_getnode( webidl_node_find_type( webidl_node_getnode(membere->node), NULL, WEBIDL_NODE_TYPE_OPTIONAL)); if (lit_node == NULL) { *defl_out = NULL; return 0; } lit_type = webidl_node_gettype(lit_node); switch (lit_type) { case WEBIDL_NODE_TYPE_LITERAL_BOOL: if (member_type != WEBIDL_TYPE_BOOL) { fprintf(stderr, "Dictionary %s:%s literal boolean type mismatch\n", dictionarye->name, membere->name); return -1; } lit_int = webidl_node_getint(lit_node); if (*lit_int == 0) { *defl_out = strdup("false"); } else { *defl_out = strdup("true"); } break; case WEBIDL_NODE_TYPE_LITERAL_NULL: *defl_out = strdup("NULL"); break; case WEBIDL_NODE_TYPE_LITERAL_STRING: *defl_out = strdup(webidl_node_gettext(lit_node)); break; case WEBIDL_NODE_TYPE_LITERAL_INT: lit_int = webidl_node_getint(lit_node); *defl_out = malloc(128); sprintf(*defl_out, "%d", *lit_int); break; case WEBIDL_NODE_TYPE_LITERAL_FLOAT: lit_flt = webidl_node_getfloat(lit_node); *defl_out = malloc(128); sprintf(*defl_out, "%f", *lit_flt); break; default: *defl_out = NULL; break; } return 0; } /** * generate a single class method for an interface operation */ static int output_member_acessor(FILE* outf, struct ir_entry *dictionarye, struct ir_operation_argument_entry *membere) { struct webidl_node *type_node; enum webidl_type *argument_type; char *defl; /* default for member */ int res; type_node = webidl_node_find_type( webidl_node_getnode(membere->node), NULL, WEBIDL_NODE_TYPE_TYPE); if (type_node == NULL) { fprintf(stderr, "%s:%s has no type\n", dictionarye->name, membere->name); return -1; } argument_type = (enum webidl_type *)webidl_node_getint( webidl_node_find_type( webidl_node_getnode(type_node), NULL, WEBIDL_NODE_TYPE_TYPE_BASE)); if (argument_type == NULL) { fprintf(stderr, "%s:%s has no type base\n", dictionarye->name, membere->name); return -1; } /* get default text */ res = get_member_default_str(dictionarye, membere, *argument_type, &defl); if (res != 0) { return res; } switch (*argument_type) { case WEBIDL_TYPE_STRING: fprintf(outf, "const char *\n" "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n" "{\n", DLPFX, dictionarye->class_name, membere->name); if (defl == NULL) { fprintf(outf, "\tconst char *ret = NULL; /* No default */\n"); } else { fprintf(outf, "\tconst char *ret = \"%s\"; /* Default value of %s */\n", defl, membere->name); } fprintf(outf, "\t/* ... obj@idx ... */\n" "\tduk_get_prop_string(ctx, idx, \"%s\");\n" "\t/* ... obj@idx ... value/undefined */\n" "\tif (!duk_is_undefined(ctx, -1)) {\n" "\t\t/* Note, this throws a duk_error if it's not a string */\n" "\t\tret = duk_require_string(ctx, -1);\n" "\t}\n" "\tduk_pop(ctx);\n" "\treturn ret;\n" "}\n\n", membere->name); break; case WEBIDL_TYPE_BOOL: fprintf(outf, "duk_bool_t\n" "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n" "{\n", DLPFX, dictionarye->class_name, membere->name); if (defl == NULL) { fprintf(outf, "\tduk_bool_t ret = false; /* No default */\n"); } else { fprintf(outf, "\tduk_bool_t ret = %s; /* Default value of %s */\n", defl, membere->name); } fprintf(outf, "\t/* ... obj@idx ... */\n" "\tduk_get_prop_string(ctx, idx, \"%s\");\n" "\t/* ... obj@idx ... value/undefined */\n" "\tif (!duk_is_undefined(ctx, -1)) {\n" "\t\t/* Note, this throws a duk_error if it's not a boolean */\n" "\t\tret = duk_require_boolean(ctx, -1);\n" "\t}\n" "\tduk_pop(ctx);\n" "\treturn ret;\n" "}\n\n", membere->name); break; case WEBIDL_TYPE_SHORT: case WEBIDL_TYPE_LONG: case WEBIDL_TYPE_LONGLONG: fprintf(outf, "duk_int_t\n" "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n" "{\n", DLPFX, dictionarye->class_name, membere->name); if (defl == NULL) { fprintf(outf, "\tduk_int_t ret = 0; /* No default */\n"); } else { fprintf(outf, "\tduk_int_t ret = %s; /* Default value of %s */\n", defl, membere->name); } fprintf(outf, "\t/* ... obj@idx ... */\n" "\tduk_get_prop_string(ctx, idx, \"%s\");\n" "\t/* ... obj@idx ... value/undefined */\n" "\tif (!duk_is_undefined(ctx, -1)) {\n" "\t\t/* Note, this throws a duk_error if it's not a int */\n" "\t\tret = duk_require_int(ctx, -1);\n" "\t}\n" "\tduk_pop(ctx);\n" "\treturn ret;\n" "}\n\n", membere->name); break; case WEBIDL_TYPE_FLOAT: case WEBIDL_TYPE_DOUBLE: fprintf(outf, "duk_double_t\n" "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n", DLPFX, dictionarye->class_name, membere->name); fprintf(outf, "{\n" "\tduk_double_t ret = %s; /* Default value of %s */\n" "\t/* ... obj@idx ... */\n" "\tduk_get_prop_string(ctx, idx, \"%s\");\n", defl, membere->name, membere->name); fprintf(outf, "\t/* ... obj@idx ... value/undefined */\n" "\tif (!duk_is_undefined(ctx, -1)) {\n" "\t\t/* Note, this throws a duk_error if it's not a number */\n" "\t\tret = duk_require_number(ctx, -1);\n" "\t}\n" "\tduk_pop(ctx);\n" "\treturn ret;\n" "}\n\n"); break; default: WARN(WARNING_UNIMPLEMENTED, "Dictionary %s:%s unhandled type (%d)", dictionarye->name, membere->name, *argument_type); fprintf(outf, "/* Dictionary %s:%s unhandled type (%d) */\n\n", dictionarye->name, membere->name, *argument_type); } if (defl != NULL) { free(defl); } return 0; } static int output_member_acessors(FILE* outf, struct ir_entry *dictionarye) { int memberc; int res = 0; for (memberc = 0; memberc < dictionarye->u.dictionary.memberc; memberc++) { res = output_member_acessor( outf, dictionarye, dictionarye->u.dictionary.memberv + memberc); if (res != 0) { break; } } return res; } /* exported function documented in duk-libdom.h */ int output_dictionary(struct ir *ir, struct ir_entry *dictionarye) { FILE *ifacef; int res = 0; /* open output file */ ifacef = genb_fopen_tmp(dictionarye->filename); if (ifacef == NULL) { return -1; } /* tool preface */ output_tool_preface(ifacef); /* binding preface */ output_method_cdata(ifacef, ir->binding_node, GENBIND_METHOD_TYPE_PREFACE); /* class preface */ output_method_cdata(ifacef, dictionarye->class, GENBIND_METHOD_TYPE_PREFACE); /* tool prologue */ output_tool_prologue(ifacef); /* binding prologue */ output_method_cdata(ifacef, ir->binding_node, GENBIND_METHOD_TYPE_PROLOGUE); /* class prologue */ output_method_cdata(ifacef, dictionarye->class, GENBIND_METHOD_TYPE_PROLOGUE); fprintf(ifacef, "\n"); res = output_member_acessors(ifacef, dictionarye); if (res != 0) { goto op_error; } fprintf(ifacef, "\n"); /* class epilogue */ output_method_cdata(ifacef, dictionarye->class, GENBIND_METHOD_TYPE_EPILOGUE); /* binding epilogue */ output_method_cdata(ifacef, ir->binding_node, GENBIND_METHOD_TYPE_EPILOGUE); /* class postface */ output_method_cdata(ifacef, dictionarye->class, GENBIND_METHOD_TYPE_POSTFACE); /* binding postface */ output_method_cdata(ifacef, ir->binding_node, GENBIND_METHOD_TYPE_POSTFACE); op_error: genb_fclose_tmp(ifacef, dictionarye->filename); return res; } /** * generate a single class method declaration for an interface operation */ static int output_member_declaration(FILE* outf, struct ir_entry *dictionarye, struct ir_operation_argument_entry *membere) { struct webidl_node *type_node; enum webidl_type *argument_type; type_node = webidl_node_find_type( webidl_node_getnode(membere->node), NULL, WEBIDL_NODE_TYPE_TYPE); if (type_node == NULL) { fprintf(stderr, "%s:%s has no type\n", dictionarye->name, membere->name); return -1; } argument_type = (enum webidl_type *)webidl_node_getint( webidl_node_find_type( webidl_node_getnode(type_node), NULL, WEBIDL_NODE_TYPE_TYPE_BASE)); if (argument_type == NULL) { fprintf(stderr, "%s:%s has no type base\n", dictionarye->name, membere->name); return -1; } switch (*argument_type) { case WEBIDL_TYPE_STRING: fprintf(outf, "const char *%s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n", DLPFX, dictionarye->class_name, membere->name); break; case WEBIDL_TYPE_BOOL: fprintf(outf, "duk_bool_t %s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n", DLPFX, dictionarye->class_name, membere->name); break; case WEBIDL_TYPE_SHORT: case WEBIDL_TYPE_LONG: case WEBIDL_TYPE_LONGLONG: fprintf(outf, "duk_int_t %s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n", DLPFX, dictionarye->class_name, membere->name); break; case WEBIDL_TYPE_FLOAT: case WEBIDL_TYPE_DOUBLE: fprintf(outf, "duk_double_t %s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n", DLPFX, dictionarye->class_name, membere->name); break; default: fprintf(outf, "/* Dictionary %s:%s unhandled type (%d) */\n", dictionarye->name, membere->name, *argument_type); } return 0; } /* exported function documented in duk-libdom.h */ int output_dictionary_declaration(FILE* outf, struct ir_entry *dictionarye) { int memberc; int res = 0; for (memberc = 0; memberc < dictionarye->u.dictionary.memberc; memberc++) { res = output_member_declaration( outf, dictionarye, dictionarye->u.dictionary.memberv + memberc); if (res != 0) { break; } } return res; }