mirror of https://github.com/mode777/rayjs.git
Add getter generation
This commit is contained in:
parent
d9f10bed4f
commit
fd97c55510
|
@ -150,7 +150,7 @@ export abstract class GenericCodeGenerator<T extends CodeGenerator> {
|
||||||
this.tokens.push(Token.UNINDENT)
|
this.tokens.push(Token.UNINDENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
public function(name: string, returnType: string, args: FunctionArgument[], isStatic: boolean, func?: (gen: T) => void){
|
public function(name: string, returnType: string, args: FunctionArgument[], isStatic: boolean, func?: (gen: T) => void): T {
|
||||||
const sub = this.createGenerator();
|
const sub = this.createGenerator();
|
||||||
sub.setTag("_type", "function-body")
|
sub.setTag("_type", "function-body")
|
||||||
sub.setTag("_name", name)
|
sub.setTag("_name", name)
|
||||||
|
|
|
@ -15,7 +15,7 @@ function main(){
|
||||||
core_gen.writeTo("src/bindings/js_raylib_core.h")
|
core_gen.writeTo("src/bindings/js_raylib_core.h")
|
||||||
|
|
||||||
const texture_gen = new RayLibHeader("raylib_texture", apiDesc)
|
const texture_gen = new RayLibHeader("raylib_texture", apiDesc)
|
||||||
texture_gen.addApiStructByName("Image", "UnloadImage")
|
texture_gen.addApiStructByName("Image", "UnloadImage", { properties: { width: { get: true } } })
|
||||||
texture_gen.writeTo("src/bindings/js_raylib_texture.h")
|
texture_gen.writeTo("src/bindings/js_raylib_texture.h")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ export class QuickJsHeader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class GenericQuickJsGenerator<T extends CodeGenerator> extends GenericCodeGenerator<T> {
|
export abstract class GenericQuickJsGenerator<T extends QuickJsGenerator> extends GenericCodeGenerator<T> {
|
||||||
|
|
||||||
jsBindingFunction(jsName: string){
|
jsBindingFunction(jsName: string){
|
||||||
const args = [
|
const args = [
|
||||||
|
@ -69,16 +69,27 @@ export abstract class GenericQuickJsGenerator<T extends CodeGenerator> extends G
|
||||||
return sub
|
return sub
|
||||||
}
|
}
|
||||||
|
|
||||||
jsReadParameter(type: string, name: string, index: number){
|
jsToC(type: string, name: string, src: string){
|
||||||
this.inline(`${type} ${name}`)
|
this.inline(`${type} ${name}`)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "const char *":
|
case "const char *":
|
||||||
this.statement(` = JS_ToCString(ctx, argv[${index}])`)
|
this.statement(` = JS_ToCString(ctx, ${src})`)
|
||||||
this.statement(`if(${name} == NULL) return JS_EXCEPTION`)
|
this.statement(`if(${name} == NULL) return JS_EXCEPTION`)
|
||||||
break;
|
break;
|
||||||
case "int":
|
case "int":
|
||||||
this.statement('')
|
this.statement('')
|
||||||
this.statement(`JS_ToInt32(ctx, &${name}, argv[${index}])`)
|
this.statement(`JS_ToInt32(ctx, &${name}, ${src})`)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Cannot handle parameter type: " + type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsToJs(type: string, name: string, src: string){
|
||||||
|
this.inline(`JSValue ${name}`)
|
||||||
|
switch (type) {
|
||||||
|
case "int":
|
||||||
|
this.statement(` = JS_NewInt32(ctx, ${src})`)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Cannot handle parameter type: " + type)
|
throw new Error("Cannot handle parameter type: " + type)
|
||||||
|
@ -120,6 +131,10 @@ export abstract class GenericQuickJsGenerator<T extends CodeGenerator> extends G
|
||||||
jsPropStringDef(key: string, value: string){
|
jsPropStringDef(key: string, value: string){
|
||||||
this.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`)
|
this.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsGetSetDef(key: string, getFunc?: string, setFunc?: string){
|
||||||
|
this.line(`JS_CGETSET_DEF("${key}",${getFunc || "NULL"},${setFunc || "NULL"}),`)
|
||||||
|
}
|
||||||
|
|
||||||
jsStructFinalizer(classId: string, structName: string, onFinalize?: (gen: T, ptrName: string) => void){
|
jsStructFinalizer(classId: string, structName: string, onFinalize?: (gen: T, ptrName: string) => void){
|
||||||
const args = [{type: "JSRuntime *", name: "rt"},{type: "JSValue", name: "val"}]
|
const args = [{type: "JSRuntime *", name: "rt"},{type: "JSValue", name: "val"}]
|
||||||
|
@ -154,8 +169,9 @@ export abstract class GenericQuickJsGenerator<T extends CodeGenerator> extends G
|
||||||
cond.returnExp("JS_EXCEPTION")
|
cond.returnExp("JS_EXCEPTION")
|
||||||
})
|
})
|
||||||
fun.declare(field, type, false, "ptr->"+field)
|
fun.declare(field, type, false, "ptr->"+field)
|
||||||
// TODO: to JS
|
fun.jsToJs(type, "ret", field)
|
||||||
fun.returnExp("ret")
|
fun.returnExp("ret")
|
||||||
|
return fun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { ApiDescription, ApiFunction, ApiStruct } from "./api"
|
import { ApiDescription, ApiFunction, ApiStruct } from "./api"
|
||||||
|
import { CodeGenerator } from "./generation"
|
||||||
import { QuickJsHeader } from "./quickjs"
|
import { QuickJsHeader } from "./quickjs"
|
||||||
|
|
||||||
export interface StructBindingOptions {
|
export interface StructBindingOptions {
|
||||||
getters?: string[]
|
properties?: { [key:string]: { get?:boolean, set?:boolean } }
|
||||||
setters?: string[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export class RayLibHeader extends QuickJsHeader {
|
||||||
// read parameters
|
// read parameters
|
||||||
for (let i = 0; i < api.params.length; i++) {
|
for (let i = 0; i < api.params.length; i++) {
|
||||||
const para = api.params[i]
|
const para = api.params[i]
|
||||||
fun.jsReadParameter(para.type,para.name,i)
|
fun.jsToC(para.type,para.name,"argv["+i+"]")
|
||||||
}
|
}
|
||||||
// call c function
|
// call c function
|
||||||
fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : {type: api.returnType, name: "returnVal"})
|
fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : {type: api.returnType, name: "returnVal"})
|
||||||
|
@ -33,8 +33,8 @@ export class RayLibHeader extends QuickJsHeader {
|
||||||
if(api.returnType === "void"){
|
if(api.returnType === "void"){
|
||||||
fun.statement("return JS_UNDEFINED")
|
fun.statement("return JS_UNDEFINED")
|
||||||
} else {
|
} else {
|
||||||
// TODO: Convert to JS
|
fun.jsToJs(api.returnType, "ret", "returnVal")
|
||||||
fun.statement("return retVal")
|
fun.returnExp("returnVal")
|
||||||
}
|
}
|
||||||
|
|
||||||
// add binding to function declaration
|
// add binding to function declaration
|
||||||
|
@ -51,8 +51,22 @@ export class RayLibHeader extends QuickJsHeader {
|
||||||
const classId = this.declarations.jsClassId(`js_${struct.name}_class_id`)
|
const classId = this.declarations.jsClassId(`js_${struct.name}_class_id`)
|
||||||
|
|
||||||
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen,ptr) => destructor && gen.call(destructor.name, ["*"+ptr]))
|
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen,ptr) => destructor && gen.call(destructor.name, ["*"+ptr]))
|
||||||
//TODO: declareGetterSetter()
|
|
||||||
|
const propDeclarations = this.structs.createGenerator()
|
||||||
|
if(options && options.properties){
|
||||||
|
for (const field of Object.keys(options.properties)) {
|
||||||
|
const type = struct.fields.find(x => x.name === field)?.type
|
||||||
|
if(!type) throw new Error(`Struct ${struct.name} does not contain field ${field}`)
|
||||||
|
const el = options.properties[field]
|
||||||
|
let _get: CodeGenerator | undefined = undefined
|
||||||
|
let _set: CodeGenerator | undefined = undefined
|
||||||
|
if(el.get) _get = this.structs.jsStructGetter(struct.name, classId, field, type)
|
||||||
|
propDeclarations.jsGetSetDef(field, _get?.getTag("_name"), undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`)
|
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`)
|
||||||
|
classFuncList.child(propDeclarations)
|
||||||
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image")
|
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image")
|
||||||
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"))
|
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"))
|
||||||
|
|
||||||
|
|
|
@ -332,16 +332,26 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator {
|
||||||
const sub = this.function("js_" + jsName, "JSValue", args, true);
|
const sub = this.function("js_" + jsName, "JSValue", args, true);
|
||||||
return sub;
|
return sub;
|
||||||
}
|
}
|
||||||
jsReadParameter(type, name, index) {
|
jsToC(type, name, src) {
|
||||||
this.inline(`${type} ${name}`);
|
this.inline(`${type} ${name}`);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "const char *":
|
case "const char *":
|
||||||
this.statement(` = JS_ToCString(ctx, argv[${index}])`);
|
this.statement(` = JS_ToCString(ctx, ${src})`);
|
||||||
this.statement(`if(${name} == NULL) return JS_EXCEPTION`);
|
this.statement(`if(${name} == NULL) return JS_EXCEPTION`);
|
||||||
break;
|
break;
|
||||||
case "int":
|
case "int":
|
||||||
this.statement('');
|
this.statement('');
|
||||||
this.statement(`JS_ToInt32(ctx, &${name}, argv[${index}])`);
|
this.statement(`JS_ToInt32(ctx, &${name}, ${src})`);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Cannot handle parameter type: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsToJs(type, name, src) {
|
||||||
|
this.inline(`JSValue ${name}`);
|
||||||
|
switch (type) {
|
||||||
|
case "int":
|
||||||
|
this.statement(` = JS_NewInt32(ctx, ${src})`);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Cannot handle parameter type: " + type);
|
throw new Error("Cannot handle parameter type: " + type);
|
||||||
|
@ -378,6 +388,9 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator {
|
||||||
jsPropStringDef(key, value) {
|
jsPropStringDef(key, value) {
|
||||||
this.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`);
|
this.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`);
|
||||||
}
|
}
|
||||||
|
jsGetSetDef(key, getFunc, setFunc) {
|
||||||
|
this.line(`JS_CGETSET_DEF("${key}",${getFunc || "NULL"},${setFunc || "NULL"}),`);
|
||||||
|
}
|
||||||
jsStructFinalizer(classId, structName, onFinalize) {
|
jsStructFinalizer(classId, structName, onFinalize) {
|
||||||
const args = [{ type: "JSRuntime *", name: "rt" }, { type: "JSValue", name: "val" }];
|
const args = [{ type: "JSRuntime *", name: "rt" }, { type: "JSValue", name: "val" }];
|
||||||
const body = this.function(`js_${structName}_finalizer`, "void", args, true);
|
const body = this.function(`js_${structName}_finalizer`, "void", args, true);
|
||||||
|
@ -410,8 +423,9 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator {
|
||||||
cond.returnExp("JS_EXCEPTION");
|
cond.returnExp("JS_EXCEPTION");
|
||||||
});
|
});
|
||||||
fun.declare(field, type, false, "ptr->" + field);
|
fun.declare(field, type, false, "ptr->" + field);
|
||||||
// TODO: to JS
|
fun.jsToJs(type, "ret", field);
|
||||||
fun.returnExp("ret");
|
fun.returnExp("ret");
|
||||||
|
return fun;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.GenericQuickJsGenerator = GenericQuickJsGenerator;
|
exports.GenericQuickJsGenerator = GenericQuickJsGenerator;
|
||||||
|
@ -447,7 +461,7 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
|
||||||
// read parameters
|
// read parameters
|
||||||
for (let i = 0; i < api.params.length; i++) {
|
for (let i = 0; i < api.params.length; i++) {
|
||||||
const para = api.params[i];
|
const para = api.params[i];
|
||||||
fun.jsReadParameter(para.type, para.name, i);
|
fun.jsToC(para.type, para.name, "argv[" + i + "]");
|
||||||
}
|
}
|
||||||
// call c function
|
// call c function
|
||||||
fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : { type: api.returnType, name: "returnVal" });
|
fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : { type: api.returnType, name: "returnVal" });
|
||||||
|
@ -460,8 +474,8 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
|
||||||
fun.statement("return JS_UNDEFINED");
|
fun.statement("return JS_UNDEFINED");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: Convert to JS
|
fun.jsToJs(api.returnType, "ret", "returnVal");
|
||||||
fun.statement("return retVal");
|
fun.returnExp("returnVal");
|
||||||
}
|
}
|
||||||
// add binding to function declaration
|
// add binding to function declaration
|
||||||
this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name"));
|
this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name"));
|
||||||
|
@ -475,8 +489,22 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
|
||||||
addApiStruct(struct, destructor, options) {
|
addApiStruct(struct, destructor, options) {
|
||||||
const classId = this.declarations.jsClassId(`js_${struct.name}_class_id`);
|
const classId = this.declarations.jsClassId(`js_${struct.name}_class_id`);
|
||||||
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen, ptr) => destructor && gen.call(destructor.name, ["*" + ptr]));
|
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen, ptr) => destructor && gen.call(destructor.name, ["*" + ptr]));
|
||||||
//TODO: declareGetterSetter()
|
const propDeclarations = this.structs.createGenerator();
|
||||||
|
if (options && options.properties) {
|
||||||
|
for (const field of Object.keys(options.properties)) {
|
||||||
|
const type = struct.fields.find(x => x.name === field)?.type;
|
||||||
|
if (!type)
|
||||||
|
throw new Error(`Struct ${struct.name} does not contain field ${field}`);
|
||||||
|
const el = options.properties[field];
|
||||||
|
let _get = undefined;
|
||||||
|
let _set = undefined;
|
||||||
|
if (el.get)
|
||||||
|
_get = this.structs.jsStructGetter(struct.name, classId, field, type);
|
||||||
|
propDeclarations.jsGetSetDef(field, _get?.getTag("_name"), undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`);
|
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`);
|
||||||
|
classFuncList.child(propDeclarations);
|
||||||
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image");
|
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image");
|
||||||
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"));
|
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"));
|
||||||
this.moduleInit.call(classDecl.getTag("_name"), ["ctx", "m"]);
|
this.moduleInit.call(classDecl.getTag("_name"), ["ctx", "m"]);
|
||||||
|
@ -559,7 +587,7 @@ function main() {
|
||||||
core_gen.addApiFunctionByName("EndDrawing");
|
core_gen.addApiFunctionByName("EndDrawing");
|
||||||
core_gen.writeTo("src/bindings/js_raylib_core.h");
|
core_gen.writeTo("src/bindings/js_raylib_core.h");
|
||||||
const texture_gen = new raylib_header_1.RayLibHeader("raylib_texture", apiDesc);
|
const texture_gen = new raylib_header_1.RayLibHeader("raylib_texture", apiDesc);
|
||||||
texture_gen.addApiStructByName("Image", "UnloadImage");
|
texture_gen.addApiStructByName("Image", "UnloadImage", { properties: { width: { get: true } } });
|
||||||
texture_gen.writeTo("src/bindings/js_raylib_texture.h");
|
texture_gen.writeTo("src/bindings/js_raylib_texture.h");
|
||||||
}
|
}
|
||||||
main();
|
main();
|
||||||
|
|
|
@ -23,7 +23,18 @@ static void js_Image_finalizer(JSRuntime * rt, JSValue val) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue js_Image_get_width(JSContext* ctx, JSValueConst this_val) {
|
||||||
|
Image* ptr = JS_GetOpaque2(ctx, this_val, js_Image_class_id);
|
||||||
|
if(!ptr) {
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
int width = ptr->width;
|
||||||
|
JSValue ret = JS_NewInt32(ctx, width);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const JSCFunctionListEntry js_Image_proto_funcs[] = {
|
static const JSCFunctionListEntry js_Image_proto_funcs[] = {
|
||||||
|
JS_CGETSET_DEF("width",js_Image_get_width,NULL),
|
||||||
JS_PROP_STRING_DEF("[Symbol.toStringTag]","Image", JS_PROP_CONFIGURABLE),
|
JS_PROP_STRING_DEF("[Symbol.toStringTag]","Image", JS_PROP_CONFIGURABLE),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue