Refactor binding generator

This commit is contained in:
Alexander Klingenbeck (SHS DI SY R&D DEV4) 2023-05-08 16:43:50 +02:00
parent e2d140e25b
commit d9f10bed4f
11 changed files with 602 additions and 636 deletions

View File

@ -1,69 +0,0 @@
import { ApiFunction } from "./api"
import { FunctionGenerator } from "./generation"
import { RayLibParamDescription } from "./interfaces"
export class RayLibFunctionGenerator extends FunctionGenerator {
constructor(public readonly jsName: string, public readonly func: ApiFunction){
super("js_"+jsName, "JSValue", [
{type: "JSContext *", name: "ctx"},
{type: "JSValueConst", name: "this_val"},
{type: "int", name: "argc"},
{type: "JSValueConst *", name: "argv"},
], true)
this.readParameters()
this.callFunction()
this.cleanUp()
this.returnValue()
}
readParameters() {
for (let i = 0; i < this.func.params.length; i++) {
const para = this.func.params[i]
this.readParameter(para,i)
}
}
callFunction() {
this.body.call(this.func.name, this.func.params.map(x => x.name), this.func.returnType === "void" ? null : {type: this.func.returnType, name: "returnVal"})
}
cleanUp() {
for (const param of this.func.params) {
this.cleanUpParameter(param)
}
}
returnValue() {
if(this.func.returnType === "void"){
this.body.statement("return JS_UNDEFINED")
} else {
this.body.statement("return retVal")
}
}
private readParameter(para: RayLibParamDescription, index: number){
this.body.inline(`${para.type} ${para.name}`)
switch (para.type) {
case "const char *":
this.body.statement(` = JS_ToCString(ctx, argv[${index}])`)
this.body.statement(`if(${para.name} == NULL) return JS_EXCEPTION`)
break;
case "int":
this.body.statement('')
this.body.statement(`JS_ToInt32(ctx, &${para.name}, argv[${index}])`)
break;
default:
throw new Error("Cannot handle parameter type: " + para.type)
}
}
private cleanUpParameter(param: RayLibParamDescription) {
switch (param.type) {
case "const char *":
this.body.statement(`JS_FreeCString(ctx, ${param.name})`)
break;
default:
break;
}
}
}

View File

@ -1,24 +0,0 @@
import { CodeGenerator } from "./generation"
export class RayLibFunctionListGenerator extends CodeGenerator {
private entries = new CodeGenerator()
constructor(public readonly name: string){
super()
this.line("static const JSCFunctionListEntry "+ name + "[] = {")
this.indent()
this.child(this.entries)
this.unindent()
this.statement("}")
}
addFunction(jsName: string, numArgs: number, cName: string){
this.entries.line(`JS_CFUNC_DEF("${jsName}",${numArgs},${cName}),`)
}
addPropertyString(key: string, value: string) {
this.entries.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`)
}
}

View File

@ -63,11 +63,28 @@ enum Token {
GOSUB = 4
}
export class CodeGenerator {
export interface FunctionArgument {
type: string,
name: string
}
export abstract class GenericCodeGenerator<T extends CodeGenerator> {
private children: CodeGenerator[] = []
private text: string[] = []
private tokens: Token[] = []
private tags: {[key:string]:any} = {}
getTag(key: string){
return this.tags[key]
}
setTag(key: string, value: any){
this.tags[key] = value
}
iterateTokens(){
return this.tokens[Symbol.iterator]()
}
@ -79,6 +96,8 @@ export class CodeGenerator {
iterateChildren(){
return this.children[Symbol.iterator]()
}
abstract createGenerator(): T;
line(text: string){
this.tokens.push(Token.STRING, Token.NEWLINE)
@ -100,22 +119,14 @@ export class CodeGenerator {
if(isStatic) this.inline("static ")
this.inline(type + " " + name)
if(initValue) this.inline(" = " + initValue)
this.statement("")
this.statement("")
}
child(sub: CodeGenerator){
child(sub?: T){
if(!sub) sub = this.createGenerator()
this.tokens.push(Token.GOSUB)
this.children.push(sub)
}
childFunc(sub: CodeGenerator, func: (gen: CodeGenerator) => void){
this.child(sub)
func(sub)
}
childFuncBody(sub: FunctionGenerator | ConditionGenerator, func: (gen: CodeGenerator) => void): void {
this.child(sub)
func(sub.body)
return sub
}
inline(str: string){
@ -138,56 +149,76 @@ export class CodeGenerator {
public unindent(){
this.tokens.push(Token.UNINDENT)
}
}
export class ConditionGenerator extends CodeGenerator {
body = new CodeGenerator()
constructor(condition: string){
super()
this.line("if("+condition+") {")
this.indent()
this.child(this.body)
this.unindent()
this.line("}")
}
}
export class HeaderGenerator extends CodeGenerator {
guardStart(name: string){
this.line("#ifndef " + name)
this.line("#define " + name)
}
guardEnd(name: string){
this.line("#endif // " + name)
}
include(name: string){
this.line("#include <" + name + ">")
}
}
export interface FunctionArgument {
type: string,
name: string
}
export class CustomFunctionGenerator<T extends CodeGenerator> extends CodeGenerator {
constructor(public readonly name: string, returnType: string, args: FunctionArgument[], public readonly body: T, isStatic = false){
super()
public function(name: string, returnType: string, args: FunctionArgument[], isStatic: boolean, func?: (gen: T) => void){
const sub = this.createGenerator();
sub.setTag("_type", "function-body")
sub.setTag("_name", name)
sub.setTag("_isStatic", isStatic)
sub.setTag("_returnType", returnType)
if(isStatic) this.inline("static ")
this.inline(returnType + " " + name + "(")
this.inline(args.map(x => x.type + " " + x.name).join(", "))
this.inline(") {")
this.breakLine()
this.indent()
this.child(body)
this.child(sub)
this.unindent()
this.line("}")
this.breakLine()
if(func) func(sub)
return sub
}
public if(condition: string, funIf?: (gen: T) => void){
this.line("if("+condition+") {")
this.indent()
const sub = this.createGenerator()
sub.setTag("_type", "if-body")
sub.setTag("_condition", condition)
this.child(sub)
this.unindent()
this.line("}")
if(funIf) funIf(sub)
return sub
}
public else(funElse?: (gen: T) => void){
this.line("else {")
this.indent()
const sub = this.createGenerator()
sub.setTag("_type", "else-body")
this.child(sub)
this.unindent()
this.line("}")
if(funElse) funElse(sub)
return sub
}
public returnExp(exp: string){
this.statement("return "+exp)
}
public include(name: string){
this.line("#include <" + name + ">")
}
public header(guard: string, fun?: (gen: T) => void){
this.line("#ifndef " + guard)
this.line("#define " + guard)
this.breakLine()
const sub = this.child()
sub.setTag("_type", "header-body")
sub.setTag("_guardName", guard)
this.line("#endif // " + guard)
if(fun) fun(sub)
return sub
}
}
export class FunctionGenerator extends CustomFunctionGenerator<CodeGenerator> {
constructor(name: string, returnType: string, args: FunctionArgument[], isStatic = false, body: CodeGenerator = new CodeGenerator()){
super(name, returnType, args, body, isStatic)
export class CodeGenerator extends GenericCodeGenerator<CodeGenerator>{
createGenerator(): CodeGenerator {
return new CodeGenerator()
}
}

View File

@ -1,102 +0,0 @@
import { ApiDescription, ApiFunction, ApiStruct } from "./api"
import { RayLibFunctionGenerator } from "./function"
import { RayLibFunctionListGenerator } from "./functionList"
import { CodeGenerator, FunctionGenerator, HeaderGenerator } from "./generation"
import { RayLibStructGenerator, StructBindingOptions } from "./struct"
export class RayLibHeaderGenerator extends HeaderGenerator {
public readonly moduleFunctionList: RayLibFunctionListGenerator
public readonly moduleInit = new CodeGenerator()
public readonly moduleEntry = new CodeGenerator()
public readonly declarations = new CodeGenerator()
public readonly body = new CodeGenerator()
constructor(public readonly name: string, private api: ApiDescription){
super()
this.moduleFunctionList = new RayLibFunctionListGenerator("js_"+name+"_funcs")
this.init()
}
addApiFunction(func: ApiFunction, jsName: string | null = null){
const jName = jsName || func.name.charAt(0).toLowerCase() + func.name.slice(1)
const gen = new RayLibFunctionGenerator(jName, func)
this.body.child(gen)
this.body.breakLine()
this.moduleFunctionList.addFunction(jName, func.argc, gen.name)
}
addApiFunctionByName(name: string, jsName: string | null = null){
const func = this.api.getFunction(name)
if(func === null) throw new Error("Function not in API: " + name)
this.addApiFunction(func, jsName)
}
addApiStruct(struct: ApiStruct, destructor: ApiFunction | null, options?: StructBindingOptions){
const classIdName = `js_${struct.name}_class_id`
this.declarations.declare(classIdName, "JSClassID", true)
const gen = new RayLibStructGenerator(classIdName, struct, destructor, options)
this.body.child(gen)
this.moduleInit.call(gen.classDeclarationName, ["ctx", "m"])
// OPT: 7. expose class and constructor
}
addApiStructByName(structName: string, destructorName: string | null = null, options?: StructBindingOptions){
const struct = this.api.getStruct(structName)
if(!struct) throw new Error("Struct not in API: "+ structName)
let destructor: ApiFunction | null = null
if(destructorName !== null){
destructor = this.api.getFunction(destructorName)
if(!destructor) throw new Error("Destructor func not in API: "+ destructorName)
}
this.addApiStruct(struct, destructor, options)
}
private init(){
const guardName = "JS_"+this.name+"_GUARD";
this.guardStart(guardName)
this.breakLine()
this.include("stdio.h")
this.include("stdlib.h")
this.include("string.h")
this.breakLine()
this.include("quickjs.h")
this.include("raylib.h")
this.breakLine()
this.line("#ifndef countof")
this.line("#define countof(x) (sizeof(x) / sizeof((x)[0]))")
this.line("#endif")
this.breakLine()
this.child(this.declarations)
this.breakLine()
this.child(this.body)
this.child(this.moduleFunctionList)
this.breakLine()
const moduleInitFunc = new FunctionGenerator("js_"+this.name+"_init", "int", [
{type: "JSContext *", name: "ctx"},
{type: "JSModuleDef *", name: "m"}])
moduleInitFunc.body.statement(`JS_SetModuleExportList(ctx, m,${this.moduleFunctionList.name},countof(${this.moduleFunctionList.name}))`)
moduleInitFunc.body.child(this.moduleInit)
moduleInitFunc.body.statement("return 0")
this.child(moduleInitFunc)
this.breakLine()
const moduleEntryFunc = new FunctionGenerator("js_init_module_"+this.name, "JSModuleDef *", [
{type: "JSContext *", name: "ctx"},
{type: "const char *", name: "module_name"}
])
moduleEntryFunc.body.statement("JSModuleDef *m")
moduleEntryFunc.body.statement(`m = JS_NewCModule(ctx, module_name, ${moduleInitFunc.name})`)
moduleEntryFunc.body.statement("if(!m) return NULL")
moduleEntryFunc.body.statement(`JS_AddModuleExportList(ctx, m, ${this.moduleFunctionList.name}, countof(${this.moduleFunctionList.name}))`)
moduleEntryFunc.body.child(this.moduleEntry)
moduleEntryFunc.body.statement("return m")
this.child(moduleEntryFunc)
this.breakLine()
this.guardEnd(guardName)
}
}

View File

@ -1,31 +1,22 @@
import { readFileSync, writeFileSync } from "fs";
import { Bindings, RayLibApi } from "./interfaces";
import { CodeWriter, HeaderGenerator } from "./generation";
import { ApiDescription } from "./api";
import { RayLibHeaderGenerator } from "./header";
const bindings = <Bindings>JSON.parse(readFileSync("bindings.json", 'utf8'))
function writeHeader(header: HeaderGenerator, filename: string){
const writer = new CodeWriter()
writer.writeGenerator(header)
writeFileSync(filename, writer.toString())
}
import { RayLibHeader } from "./raylib-header";
function main(){
const api = <RayLibApi>JSON.parse(readFileSync("thirdparty/raylib/parser/output/raylib_api.json", 'utf8'))
const apiDesc = new ApiDescription(api)
const core_gen = new RayLibHeaderGenerator("raylib_core", apiDesc)
const core_gen = new RayLibHeader("raylib_core", apiDesc)
core_gen.addApiFunctionByName("SetWindowTitle")
core_gen.addApiFunctionByName("SetWindowPosition")
core_gen.addApiFunctionByName("BeginDrawing")
core_gen.addApiFunctionByName("EndDrawing")
writeHeader(core_gen, "src/bindings/js_raylib_core.h")
core_gen.writeTo("src/bindings/js_raylib_core.h")
const texture_gen = new RayLibHeaderGenerator("raylib_texture", apiDesc)
const texture_gen = new RayLibHeader("raylib_texture", apiDesc)
texture_gen.addApiStructByName("Image", "UnloadImage")
writeHeader(texture_gen, "src/bindings/js_raylib_texture.h")
texture_gen.writeTo("src/bindings/js_raylib_texture.h")
}
main()

167
bindings/src/quickjs.ts Normal file
View File

@ -0,0 +1,167 @@
import { writeFileSync } from "fs";
import { ApiFunction } from "./api"
import { CodeGenerator, CodeWriter, GenericCodeGenerator } from "./generation"
export class QuickJsHeader {
public readonly moduleFunctionList: QuickJsGenerator
public readonly structs: QuickJsGenerator
public readonly functions: QuickJsGenerator
public readonly moduleInit: QuickJsGenerator
public readonly moduleEntry: QuickJsGenerator
public readonly declarations: QuickJsGenerator
public readonly body: QuickJsGenerator
public readonly includes: QuickJsGenerator
private readonly root: QuickJsGenerator
constructor(private name: string){
const root = this.root = new QuickJsGenerator()
const body = this.body = root.header("JS_"+this.name+"_GUARD")
const includes = this.includes = body.child()
includes.include("stdio.h")
includes.include("stdlib.h")
includes.include("string.h")
includes.breakLine()
includes.include("quickjs.h")
body.breakLine()
body.line("#ifndef countof")
body.line("#define countof(x) (sizeof(x) / sizeof((x)[0]))")
body.line("#endif")
body.breakLine()
this.declarations = body.child()
body.breakLine()
this.structs = body.child()
this.functions = body.child()
this.moduleFunctionList = body.jsFunctionList("js_"+name+"_funcs")
const moduleInitFunc = body.function("js_"+this.name+"_init", "int", [{type: "JSContext *", name: "ctx"},{type: "JSModuleDef *", name: "m"}], true)
const moduleInit = this.moduleInit = moduleInitFunc.child()
moduleInit.statement(`JS_SetModuleExportList(ctx, m,${this.moduleFunctionList.getTag("_name")},countof(${this.moduleFunctionList.getTag("_name")}))`)
moduleInitFunc.returnExp("0")
const moduleEntryFunc = body.function("js_init_module_"+this.name, "JSModuleDef *", [{type: "JSContext *", name: "ctx"},{type: "const char *", name: "module_name"}], false)
const moduleEntry = this.moduleEntry = moduleEntryFunc.child()
moduleEntry.statement("JSModuleDef *m")
moduleEntry.statement(`m = JS_NewCModule(ctx, module_name, ${moduleInitFunc.getTag("_name")})`)
moduleEntry.statement("if(!m) return NULL")
moduleEntry.statement(`JS_AddModuleExportList(ctx, m, ${this.moduleFunctionList.getTag("_name")}, countof(${this.moduleFunctionList.getTag("_name")}))`)
moduleEntryFunc.statement("return m")
}
public writeTo(filename: string){
const writer = new CodeWriter()
writer.writeGenerator(this.root)
writeFileSync(filename, writer.toString())
}
}
export abstract class GenericQuickJsGenerator<T extends CodeGenerator> extends GenericCodeGenerator<T> {
jsBindingFunction(jsName: string){
const args = [
{type: "JSContext *", name: "ctx"},
{type: "JSValueConst", name: "this_val"},
{type: "int", name: "argc"},
{type: "JSValueConst *", name: "argv"},
]
const sub = this.function("js_"+jsName, "JSValue", args, true)
return sub
}
jsReadParameter(type: string, name: string, index: number){
this.inline(`${type} ${name}`)
switch (type) {
case "const char *":
this.statement(` = JS_ToCString(ctx, argv[${index}])`)
this.statement(`if(${name} == NULL) return JS_EXCEPTION`)
break;
case "int":
this.statement('')
this.statement(`JS_ToInt32(ctx, &${name}, argv[${index}])`)
break;
default:
throw new Error("Cannot handle parameter type: " + type)
}
}
jsCleanUpParameter(type: string, name: string) {
switch (type) {
case "const char *":
this.statement(`JS_FreeCString(ctx, ${name})`)
break;
default:
break;
}
}
jsFunctionList(name: string){
this.line("static const JSCFunctionListEntry "+ name + "[] = {")
this.indent()
const sub = this.createGenerator()
sub.setTag("_type", "js-function-list")
sub.setTag("_name", name)
this.child(sub)
this.unindent()
this.statement("}")
this.breakLine()
return sub
}
jsFuncDef(jsName: string, numArgs: number, cName: string){
this.line(`JS_CFUNC_DEF("${jsName}",${numArgs},${cName}),`)
}
jsClassId(id: string){
this.declare(id, "JSClassID", true)
return id
}
jsPropStringDef(key: string, value: string){
this.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`)
}
jsStructFinalizer(classId: string, structName: string, onFinalize?: (gen: T, ptrName: string) => void){
const args = [{type: "JSRuntime *", name: "rt"},{type: "JSValue", name: "val"}]
const body = this.function(`js_${structName}_finalizer`, "void", args, true)
body.statement(`${structName}* ptr = JS_GetOpaque(val, ${classId})`)
body.if("ptr", cond => {
cond.call("puts", ["\"Finalize "+structName+"\""])
if(onFinalize) onFinalize(<T>cond, "ptr")
cond.call("js_free_rt", ["rt","ptr"])
})
return body
}
jsClassDeclaration(structName: string, classId: string, finalizerName: string, funcListName: string){
const body = this.function("js_declare_" + structName, "int", [{type: "JSContext *", name: "ctx"},{type: "JSModuleDef *", name: "m"}],true)
body.call("JS_NewClassID", ["&"+classId])
const classDefName = `js_${structName}_def`
body.declare(classDefName, "JSClassDef", false, `{ .class_name = "${structName}", .finalizer = ${finalizerName} }`)
body.call("JS_NewClass", ["JS_GetRuntime(ctx)",classId,"&"+classDefName])
body.declare("proto", "JSValue", false, "JS_NewObject(ctx)")
body.call("JS_SetPropertyFunctionList", ["ctx", "proto", funcListName, `countof(${funcListName})`])
body.call("JS_SetClassProto", ["ctx",classId,"proto"])
body.statement("return 0")
return body
}
jsStructGetter(structName: string, classId: string, field: string, type: string){
const args = [{type: "JSContext*", name: "ctx" }, {type: "JSValueConst", name: "this_val"}]
const fun = this.function(`js_${structName}_get_${field}`,"JSValue",args,true)
fun.declare("ptr", structName+"*", false, `JS_GetOpaque2(ctx, this_val, ${classId})`)
fun.if("!ptr", cond => {
cond.returnExp("JS_EXCEPTION")
})
fun.declare(field, type, false, "ptr->"+field)
// TODO: to JS
fun.returnExp("ret")
}
}
export class QuickJsGenerator extends GenericQuickJsGenerator<QuickJsGenerator> {
createGenerator(): QuickJsGenerator {
return new QuickJsGenerator()
}
}

View File

@ -0,0 +1,73 @@
import { ApiDescription, ApiFunction, ApiStruct } from "./api"
import { QuickJsHeader } from "./quickjs"
export interface StructBindingOptions {
getters?: string[]
setters?: string[]
}
export class RayLibHeader extends QuickJsHeader {
constructor(name: string, private api: ApiDescription){
super(name)
this.includes.include("raylib.h")
}
addApiFunction(api: ApiFunction, jsName: string | null = null){
const jName = jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1)
const fun = this.functions.jsBindingFunction(jName)
// read parameters
for (let i = 0; i < api.params.length; i++) {
const para = api.params[i]
fun.jsReadParameter(para.type,para.name,i)
}
// call c function
fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : {type: api.returnType, name: "returnVal"})
// clean up parameters
for (const param of api.params) {
fun.jsCleanUpParameter(param.type, param.name)
}
// return result
if(api.returnType === "void"){
fun.statement("return JS_UNDEFINED")
} else {
// TODO: Convert to JS
fun.statement("return retVal")
}
// add binding to function declaration
this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name"))
}
addApiFunctionByName(name: string, jsName: string | null = null){
const func = this.api.getFunction(name)
if(func === null) throw new Error("Function not in API: " + name)
this.addApiFunction(func, jsName)
}
addApiStruct(struct: ApiStruct, destructor: ApiFunction | null, options?: StructBindingOptions){
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]))
//TODO: declareGetterSetter()
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`)
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image")
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"))
this.moduleInit.call(classDecl.getTag("_name"), ["ctx", "m"])
// OPT: 7. expose class and constructor
}
addApiStructByName(structName: string, destructorName: string | null = null, options?: StructBindingOptions){
const struct = this.api.getStruct(structName)
if(!struct) throw new Error("Struct not in API: "+ structName)
let destructor: ApiFunction | null = null
if(destructorName !== null){
destructor = this.api.getFunction(destructorName)
if(!destructor) throw new Error("Destructor func not in API: "+ destructorName)
}
this.addApiStruct(struct, destructor, options)
}
}

View File

@ -1,63 +0,0 @@
import { ApiStruct, ApiFunction } from "./api";
import { RayLibFunctionListGenerator } from "./functionList";
import { CodeGenerator, ConditionGenerator, FunctionGenerator } from "./generation";
export interface StructBindingOptions {
getters?: string[]
setters?: string[]
}
export class RayLibStructGenerator extends CodeGenerator {
private readonly options: StructBindingOptions;
private readonly funcList: RayLibFunctionListGenerator
public finalizerName = ""
public classDeclarationName = ""
constructor(public readonly classId: string, private struct: ApiStruct, private destructor: ApiFunction | null, options?: StructBindingOptions){
super()
this.options = options || {}
this.funcList = new RayLibFunctionListGenerator(`js_${struct.name}_proto_funcs`)
this.declareFinalizer()
this.breakLine()
this.declareGetterSetter()
this.funcList.addPropertyString("[Symbol.toStringTag]", "Image")
this.child(this.funcList)
this.breakLine()
this.buildClassDeclaration()
this.breakLine()
}
private declareFinalizer(){
this.finalizerName = `js_${this.struct.name}_finalizer`
this.childFuncBody(new FunctionGenerator(this.finalizerName, "void", [
{type: "JSRuntime *", name: "rt"},
{type: "JSValue", name: "val"}], true), body => {
body.statement(`${this.struct.name}* ptr = JS_GetOpaque(val, ${this.classId})`)
body.childFuncBody(new ConditionGenerator("ptr"), cond => {
cond.call("puts", ["\"Finalize "+this.struct.name+"\""])
if(this.destructor) cond.call(this.destructor.name, ["*ptr"])
cond.call("js_free_rt", ["rt","ptr"])
})
})
}
private declareGetterSetter(){
// Add to funList
}
private buildClassDeclaration(){
this.classDeclarationName = "js_declare_" + this.struct.name
this.childFuncBody(new FunctionGenerator(this.classDeclarationName, "int", [{type: "JSContext *", name: "ctx"},{type: "JSModuleDef *", name: "m"}],true), body => {
body.call("JS_NewClassID", ["&"+this.classId])
const classDefName = `js_${this.struct.name}_def`
body.declare(classDefName, "JSClassDef", false, `{ .class_name = "${this.struct.name}", .finalizer = ${this.finalizerName} }`)
body.call("JS_NewClass", ["JS_GetRuntime(ctx)",this.classId,"&"+classDefName])
body.declare("proto", "JSValue", false, "JS_NewObject(ctx)")
body.call("JS_SetPropertyFunctionList", ["ctx", "proto", this.funcList.name, `countof(${this.funcList.name})`])
body.call("JS_SetClassProto", ["ctx",this.classId,"proto"])
body.statement("return 0")
})
}
}

View File

@ -50,116 +50,6 @@ class ApiDescription {
exports.ApiDescription = ApiDescription;
/***/ }),
/***/ "./src/function.ts":
/*!*************************!*\
!*** ./src/function.ts ***!
\*************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.RayLibFunctionGenerator = void 0;
const generation_1 = __webpack_require__(/*! ./generation */ "./src/generation.ts");
class RayLibFunctionGenerator extends generation_1.FunctionGenerator {
constructor(jsName, func) {
super("js_" + jsName, "JSValue", [
{ type: "JSContext *", name: "ctx" },
{ type: "JSValueConst", name: "this_val" },
{ type: "int", name: "argc" },
{ type: "JSValueConst *", name: "argv" },
], true);
this.jsName = jsName;
this.func = func;
this.readParameters();
this.callFunction();
this.cleanUp();
this.returnValue();
}
readParameters() {
for (let i = 0; i < this.func.params.length; i++) {
const para = this.func.params[i];
this.readParameter(para, i);
}
}
callFunction() {
this.body.call(this.func.name, this.func.params.map(x => x.name), this.func.returnType === "void" ? null : { type: this.func.returnType, name: "returnVal" });
}
cleanUp() {
for (const param of this.func.params) {
this.cleanUpParameter(param);
}
}
returnValue() {
if (this.func.returnType === "void") {
this.body.statement("return JS_UNDEFINED");
}
else {
this.body.statement("return retVal");
}
}
readParameter(para, index) {
this.body.inline(`${para.type} ${para.name}`);
switch (para.type) {
case "const char *":
this.body.statement(` = JS_ToCString(ctx, argv[${index}])`);
this.body.statement(`if(${para.name} == NULL) return JS_EXCEPTION`);
break;
case "int":
this.body.statement('');
this.body.statement(`JS_ToInt32(ctx, &${para.name}, argv[${index}])`);
break;
default:
throw new Error("Cannot handle parameter type: " + para.type);
}
}
cleanUpParameter(param) {
switch (param.type) {
case "const char *":
this.body.statement(`JS_FreeCString(ctx, ${param.name})`);
break;
default:
break;
}
}
}
exports.RayLibFunctionGenerator = RayLibFunctionGenerator;
/***/ }),
/***/ "./src/functionList.ts":
/*!*****************************!*\
!*** ./src/functionList.ts ***!
\*****************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.RayLibFunctionListGenerator = void 0;
const generation_1 = __webpack_require__(/*! ./generation */ "./src/generation.ts");
class RayLibFunctionListGenerator extends generation_1.CodeGenerator {
constructor(name) {
super();
this.name = name;
this.entries = new generation_1.CodeGenerator();
this.line("static const JSCFunctionListEntry " + name + "[] = {");
this.indent();
this.child(this.entries);
this.unindent();
this.statement("}");
}
addFunction(jsName, numArgs, cName) {
this.entries.line(`JS_CFUNC_DEF("${jsName}",${numArgs},${cName}),`);
}
addPropertyString(key, value) {
this.entries.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`);
}
}
exports.RayLibFunctionListGenerator = RayLibFunctionListGenerator;
/***/ }),
/***/ "./src/generation.ts":
@ -170,7 +60,7 @@ exports.RayLibFunctionListGenerator = RayLibFunctionListGenerator;
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.FunctionGenerator = exports.CustomFunctionGenerator = exports.HeaderGenerator = exports.ConditionGenerator = exports.CodeGenerator = exports.CodeWriter = exports.StringWriter = void 0;
exports.CodeGenerator = exports.GenericCodeGenerator = exports.CodeWriter = exports.StringWriter = void 0;
class StringWriter {
constructor() {
this.buffer = '';
@ -237,11 +127,18 @@ var Token;
Token[Token["UNINDENT"] = 3] = "UNINDENT";
Token[Token["GOSUB"] = 4] = "GOSUB";
})(Token || (Token = {}));
class CodeGenerator {
class GenericCodeGenerator {
constructor() {
this.children = [];
this.text = [];
this.tokens = [];
this.tags = {};
}
getTag(key) {
return this.tags[key];
}
setTag(key, value) {
this.tags[key] = value;
}
iterateTokens() {
return this.tokens[Symbol.iterator]();
@ -275,16 +172,11 @@ class CodeGenerator {
this.statement("");
}
child(sub) {
if (!sub)
sub = this.createGenerator();
this.tokens.push(Token.GOSUB);
this.children.push(sub);
}
childFunc(sub, func) {
this.child(sub);
func(sub);
}
childFuncBody(sub, func) {
this.child(sub);
func(sub.body);
return sub;
}
inline(str) {
this.tokens.push(Token.STRING);
@ -302,38 +194,12 @@ class CodeGenerator {
unindent() {
this.tokens.push(Token.UNINDENT);
}
}
exports.CodeGenerator = CodeGenerator;
class ConditionGenerator extends CodeGenerator {
constructor(condition) {
super();
this.body = new CodeGenerator();
this.line("if(" + condition + ") {");
this.indent();
this.child(this.body);
this.unindent();
this.line("}");
}
}
exports.ConditionGenerator = ConditionGenerator;
class HeaderGenerator extends CodeGenerator {
guardStart(name) {
this.line("#ifndef " + name);
this.line("#define " + name);
}
guardEnd(name) {
this.line("#endif // " + name);
}
include(name) {
this.line("#include <" + name + ">");
}
}
exports.HeaderGenerator = HeaderGenerator;
class CustomFunctionGenerator extends CodeGenerator {
constructor(name, returnType, args, body, isStatic = false) {
super();
this.name = name;
this.body = body;
function(name, returnType, args, isStatic, func) {
const sub = this.createGenerator();
sub.setTag("_type", "function-body");
sub.setTag("_name", name);
sub.setTag("_isStatic", isStatic);
sub.setTag("_returnType", returnType);
if (isStatic)
this.inline("static ");
this.inline(returnType + " " + name + "(");
@ -341,53 +207,264 @@ class CustomFunctionGenerator extends CodeGenerator {
this.inline(") {");
this.breakLine();
this.indent();
this.child(body);
this.child(sub);
this.unindent();
this.line("}");
this.breakLine();
if (func)
func(sub);
return sub;
}
if(condition, funIf) {
this.line("if(" + condition + ") {");
this.indent();
const sub = this.createGenerator();
sub.setTag("_type", "if-body");
sub.setTag("_condition", condition);
this.child(sub);
this.unindent();
this.line("}");
if (funIf)
funIf(sub);
return sub;
}
else(funElse) {
this.line("else {");
this.indent();
const sub = this.createGenerator();
sub.setTag("_type", "else-body");
this.child(sub);
this.unindent();
this.line("}");
if (funElse)
funElse(sub);
return sub;
}
returnExp(exp) {
this.statement("return " + exp);
}
include(name) {
this.line("#include <" + name + ">");
}
header(guard, fun) {
this.line("#ifndef " + guard);
this.line("#define " + guard);
this.breakLine();
const sub = this.child();
sub.setTag("_type", "header-body");
sub.setTag("_guardName", guard);
this.line("#endif // " + guard);
if (fun)
fun(sub);
return sub;
}
}
exports.CustomFunctionGenerator = CustomFunctionGenerator;
class FunctionGenerator extends CustomFunctionGenerator {
constructor(name, returnType, args, isStatic = false, body = new CodeGenerator()) {
super(name, returnType, args, body, isStatic);
exports.GenericCodeGenerator = GenericCodeGenerator;
class CodeGenerator extends GenericCodeGenerator {
createGenerator() {
return new CodeGenerator();
}
}
exports.FunctionGenerator = FunctionGenerator;
exports.CodeGenerator = CodeGenerator;
/***/ }),
/***/ "./src/header.ts":
/*!***********************!*\
!*** ./src/header.ts ***!
\***********************/
/***/ "./src/quickjs.ts":
/*!************************!*\
!*** ./src/quickjs.ts ***!
\************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.RayLibHeaderGenerator = void 0;
const function_1 = __webpack_require__(/*! ./function */ "./src/function.ts");
const functionList_1 = __webpack_require__(/*! ./functionList */ "./src/functionList.ts");
exports.QuickJsGenerator = exports.GenericQuickJsGenerator = exports.QuickJsHeader = void 0;
const fs_1 = __webpack_require__(/*! fs */ "fs");
const generation_1 = __webpack_require__(/*! ./generation */ "./src/generation.ts");
const struct_1 = __webpack_require__(/*! ./struct */ "./src/struct.ts");
class RayLibHeaderGenerator extends generation_1.HeaderGenerator {
constructor(name, api) {
super();
class QuickJsHeader {
constructor(name) {
this.name = name;
this.api = api;
this.moduleInit = new generation_1.CodeGenerator();
this.moduleEntry = new generation_1.CodeGenerator();
this.declarations = new generation_1.CodeGenerator();
this.body = new generation_1.CodeGenerator();
this.moduleFunctionList = new functionList_1.RayLibFunctionListGenerator("js_" + name + "_funcs");
this.init();
const root = this.root = new QuickJsGenerator();
const body = this.body = root.header("JS_" + this.name + "_GUARD");
const includes = this.includes = body.child();
includes.include("stdio.h");
includes.include("stdlib.h");
includes.include("string.h");
includes.breakLine();
includes.include("quickjs.h");
body.breakLine();
body.line("#ifndef countof");
body.line("#define countof(x) (sizeof(x) / sizeof((x)[0]))");
body.line("#endif");
body.breakLine();
this.declarations = body.child();
body.breakLine();
this.structs = body.child();
this.functions = body.child();
this.moduleFunctionList = body.jsFunctionList("js_" + name + "_funcs");
const moduleInitFunc = body.function("js_" + this.name + "_init", "int", [{ type: "JSContext *", name: "ctx" }, { type: "JSModuleDef *", name: "m" }], true);
const moduleInit = this.moduleInit = moduleInitFunc.child();
moduleInit.statement(`JS_SetModuleExportList(ctx, m,${this.moduleFunctionList.getTag("_name")},countof(${this.moduleFunctionList.getTag("_name")}))`);
moduleInitFunc.returnExp("0");
const moduleEntryFunc = body.function("js_init_module_" + this.name, "JSModuleDef *", [{ type: "JSContext *", name: "ctx" }, { type: "const char *", name: "module_name" }], false);
const moduleEntry = this.moduleEntry = moduleEntryFunc.child();
moduleEntry.statement("JSModuleDef *m");
moduleEntry.statement(`m = JS_NewCModule(ctx, module_name, ${moduleInitFunc.getTag("_name")})`);
moduleEntry.statement("if(!m) return NULL");
moduleEntry.statement(`JS_AddModuleExportList(ctx, m, ${this.moduleFunctionList.getTag("_name")}, countof(${this.moduleFunctionList.getTag("_name")}))`);
moduleEntryFunc.statement("return m");
}
addApiFunction(func, jsName = null) {
const jName = jsName || func.name.charAt(0).toLowerCase() + func.name.slice(1);
const gen = new function_1.RayLibFunctionGenerator(jName, func);
this.body.child(gen);
this.body.breakLine();
this.moduleFunctionList.addFunction(jName, func.argc, gen.name);
writeTo(filename) {
const writer = new generation_1.CodeWriter();
writer.writeGenerator(this.root);
(0, fs_1.writeFileSync)(filename, writer.toString());
}
}
exports.QuickJsHeader = QuickJsHeader;
class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator {
jsBindingFunction(jsName) {
const args = [
{ type: "JSContext *", name: "ctx" },
{ type: "JSValueConst", name: "this_val" },
{ type: "int", name: "argc" },
{ type: "JSValueConst *", name: "argv" },
];
const sub = this.function("js_" + jsName, "JSValue", args, true);
return sub;
}
jsReadParameter(type, name, index) {
this.inline(`${type} ${name}`);
switch (type) {
case "const char *":
this.statement(` = JS_ToCString(ctx, argv[${index}])`);
this.statement(`if(${name} == NULL) return JS_EXCEPTION`);
break;
case "int":
this.statement('');
this.statement(`JS_ToInt32(ctx, &${name}, argv[${index}])`);
break;
default:
throw new Error("Cannot handle parameter type: " + type);
}
}
jsCleanUpParameter(type, name) {
switch (type) {
case "const char *":
this.statement(`JS_FreeCString(ctx, ${name})`);
break;
default:
break;
}
}
jsFunctionList(name) {
this.line("static const JSCFunctionListEntry " + name + "[] = {");
this.indent();
const sub = this.createGenerator();
sub.setTag("_type", "js-function-list");
sub.setTag("_name", name);
this.child(sub);
this.unindent();
this.statement("}");
this.breakLine();
return sub;
}
jsFuncDef(jsName, numArgs, cName) {
this.line(`JS_CFUNC_DEF("${jsName}",${numArgs},${cName}),`);
}
jsClassId(id) {
this.declare(id, "JSClassID", true);
return id;
}
jsPropStringDef(key, value) {
this.line(`JS_PROP_STRING_DEF("${key}","${value}", JS_PROP_CONFIGURABLE),`);
}
jsStructFinalizer(classId, structName, onFinalize) {
const args = [{ type: "JSRuntime *", name: "rt" }, { type: "JSValue", name: "val" }];
const body = this.function(`js_${structName}_finalizer`, "void", args, true);
body.statement(`${structName}* ptr = JS_GetOpaque(val, ${classId})`);
body.if("ptr", cond => {
cond.call("puts", ["\"Finalize " + structName + "\""]);
if (onFinalize)
onFinalize(cond, "ptr");
cond.call("js_free_rt", ["rt", "ptr"]);
});
return body;
}
jsClassDeclaration(structName, classId, finalizerName, funcListName) {
const body = this.function("js_declare_" + structName, "int", [{ type: "JSContext *", name: "ctx" }, { type: "JSModuleDef *", name: "m" }], true);
body.call("JS_NewClassID", ["&" + classId]);
const classDefName = `js_${structName}_def`;
body.declare(classDefName, "JSClassDef", false, `{ .class_name = "${structName}", .finalizer = ${finalizerName} }`);
body.call("JS_NewClass", ["JS_GetRuntime(ctx)", classId, "&" + classDefName]);
body.declare("proto", "JSValue", false, "JS_NewObject(ctx)");
body.call("JS_SetPropertyFunctionList", ["ctx", "proto", funcListName, `countof(${funcListName})`]);
body.call("JS_SetClassProto", ["ctx", classId, "proto"]);
body.statement("return 0");
return body;
}
jsStructGetter(structName, classId, field, type) {
const args = [{ type: "JSContext*", name: "ctx" }, { type: "JSValueConst", name: "this_val" }];
const fun = this.function(`js_${structName}_get_${field}`, "JSValue", args, true);
fun.declare("ptr", structName + "*", false, `JS_GetOpaque2(ctx, this_val, ${classId})`);
fun.if("!ptr", cond => {
cond.returnExp("JS_EXCEPTION");
});
fun.declare(field, type, false, "ptr->" + field);
// TODO: to JS
fun.returnExp("ret");
}
}
exports.GenericQuickJsGenerator = GenericQuickJsGenerator;
class QuickJsGenerator extends GenericQuickJsGenerator {
createGenerator() {
return new QuickJsGenerator();
}
}
exports.QuickJsGenerator = QuickJsGenerator;
/***/ }),
/***/ "./src/raylib-header.ts":
/*!******************************!*\
!*** ./src/raylib-header.ts ***!
\******************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.RayLibHeader = void 0;
const quickjs_1 = __webpack_require__(/*! ./quickjs */ "./src/quickjs.ts");
class RayLibHeader extends quickjs_1.QuickJsHeader {
constructor(name, api) {
super(name);
this.api = api;
this.includes.include("raylib.h");
}
addApiFunction(api, jsName = null) {
const jName = jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1);
const fun = this.functions.jsBindingFunction(jName);
// read parameters
for (let i = 0; i < api.params.length; i++) {
const para = api.params[i];
fun.jsReadParameter(para.type, para.name, i);
}
// call c function
fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : { type: api.returnType, name: "returnVal" });
// clean up parameters
for (const param of api.params) {
fun.jsCleanUpParameter(param.type, param.name);
}
// return result
if (api.returnType === "void") {
fun.statement("return JS_UNDEFINED");
}
else {
// TODO: Convert to JS
fun.statement("return retVal");
}
// add binding to function declaration
this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name"));
}
addApiFunctionByName(name, jsName = null) {
const func = this.api.getFunction(name);
@ -396,11 +473,13 @@ class RayLibHeaderGenerator extends generation_1.HeaderGenerator {
this.addApiFunction(func, jsName);
}
addApiStruct(struct, destructor, options) {
const classIdName = `js_${struct.name}_class_id`;
this.declarations.declare(classIdName, "JSClassID", true);
const gen = new struct_1.RayLibStructGenerator(classIdName, struct, destructor, options);
this.body.child(gen);
this.moduleInit.call(gen.classDeclarationName, ["ctx", "m"]);
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]));
//TODO: declareGetterSetter()
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`);
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image");
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"));
this.moduleInit.call(classDecl.getTag("_name"), ["ctx", "m"]);
// OPT: 7. expose class and constructor
}
addApiStructByName(structName, destructorName = null, options) {
@ -415,118 +494,8 @@ class RayLibHeaderGenerator extends generation_1.HeaderGenerator {
}
this.addApiStruct(struct, destructor, options);
}
init() {
const guardName = "JS_" + this.name + "_GUARD";
this.guardStart(guardName);
this.breakLine();
this.include("stdio.h");
this.include("stdlib.h");
this.include("string.h");
this.breakLine();
this.include("quickjs.h");
this.include("raylib.h");
this.breakLine();
this.line("#ifndef countof");
this.line("#define countof(x) (sizeof(x) / sizeof((x)[0]))");
this.line("#endif");
this.breakLine();
this.child(this.declarations);
this.breakLine();
this.child(this.body);
this.child(this.moduleFunctionList);
this.breakLine();
const moduleInitFunc = new generation_1.FunctionGenerator("js_" + this.name + "_init", "int", [
{ type: "JSContext *", name: "ctx" },
{ type: "JSModuleDef *", name: "m" }
]);
moduleInitFunc.body.statement(`JS_SetModuleExportList(ctx, m,${this.moduleFunctionList.name},countof(${this.moduleFunctionList.name}))`);
moduleInitFunc.body.child(this.moduleInit);
moduleInitFunc.body.statement("return 0");
this.child(moduleInitFunc);
this.breakLine();
const moduleEntryFunc = new generation_1.FunctionGenerator("js_init_module_" + this.name, "JSModuleDef *", [
{ type: "JSContext *", name: "ctx" },
{ type: "const char *", name: "module_name" }
]);
moduleEntryFunc.body.statement("JSModuleDef *m");
moduleEntryFunc.body.statement(`m = JS_NewCModule(ctx, module_name, ${moduleInitFunc.name})`);
moduleEntryFunc.body.statement("if(!m) return NULL");
moduleEntryFunc.body.statement(`JS_AddModuleExportList(ctx, m, ${this.moduleFunctionList.name}, countof(${this.moduleFunctionList.name}))`);
moduleEntryFunc.body.child(this.moduleEntry);
moduleEntryFunc.body.statement("return m");
this.child(moduleEntryFunc);
this.breakLine();
this.guardEnd(guardName);
}
}
exports.RayLibHeaderGenerator = RayLibHeaderGenerator;
/***/ }),
/***/ "./src/struct.ts":
/*!***********************!*\
!*** ./src/struct.ts ***!
\***********************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.RayLibStructGenerator = void 0;
const functionList_1 = __webpack_require__(/*! ./functionList */ "./src/functionList.ts");
const generation_1 = __webpack_require__(/*! ./generation */ "./src/generation.ts");
class RayLibStructGenerator extends generation_1.CodeGenerator {
constructor(classId, struct, destructor, options) {
super();
this.classId = classId;
this.struct = struct;
this.destructor = destructor;
this.finalizerName = "";
this.classDeclarationName = "";
this.options = options || {};
this.funcList = new functionList_1.RayLibFunctionListGenerator(`js_${struct.name}_proto_funcs`);
this.declareFinalizer();
this.breakLine();
this.declareGetterSetter();
this.funcList.addPropertyString("[Symbol.toStringTag]", "Image");
this.child(this.funcList);
this.breakLine();
this.buildClassDeclaration();
this.breakLine();
}
declareFinalizer() {
this.finalizerName = `js_${this.struct.name}_finalizer`;
this.childFuncBody(new generation_1.FunctionGenerator(this.finalizerName, "void", [
{ type: "JSRuntime *", name: "rt" },
{ type: "JSValue", name: "val" }
], true), body => {
body.statement(`${this.struct.name}* ptr = JS_GetOpaque(val, ${this.classId})`);
body.childFuncBody(new generation_1.ConditionGenerator("ptr"), cond => {
cond.call("puts", ["\"Finalize " + this.struct.name + "\""]);
if (this.destructor)
cond.call(this.destructor.name, ["*ptr"]);
cond.call("js_free_rt", ["rt", "ptr"]);
});
});
}
declareGetterSetter() {
// Add to funList
}
buildClassDeclaration() {
this.classDeclarationName = "js_declare_" + this.struct.name;
this.childFuncBody(new generation_1.FunctionGenerator(this.classDeclarationName, "int", [{ type: "JSContext *", name: "ctx" }, { type: "JSModuleDef *", name: "m" }], true), body => {
body.call("JS_NewClassID", ["&" + this.classId]);
const classDefName = `js_${this.struct.name}_def`;
body.declare(classDefName, "JSClassDef", false, `{ .class_name = "${this.struct.name}", .finalizer = ${this.finalizerName} }`);
body.call("JS_NewClass", ["JS_GetRuntime(ctx)", this.classId, "&" + classDefName]);
body.declare("proto", "JSValue", false, "JS_NewObject(ctx)");
body.call("JS_SetPropertyFunctionList", ["ctx", "proto", this.funcList.name, `countof(${this.funcList.name})`]);
body.call("JS_SetClassProto", ["ctx", this.classId, "proto"]);
body.statement("return 0");
});
}
}
exports.RayLibStructGenerator = RayLibStructGenerator;
exports.RayLibHeader = RayLibHeader;
/***/ }),
@ -578,27 +547,20 @@ var exports = __webpack_exports__;
Object.defineProperty(exports, "__esModule", ({ value: true }));
const fs_1 = __webpack_require__(/*! fs */ "fs");
const generation_1 = __webpack_require__(/*! ./generation */ "./src/generation.ts");
const api_1 = __webpack_require__(/*! ./api */ "./src/api.ts");
const header_1 = __webpack_require__(/*! ./header */ "./src/header.ts");
const bindings = JSON.parse((0, fs_1.readFileSync)("bindings.json", 'utf8'));
function writeHeader(header, filename) {
const writer = new generation_1.CodeWriter();
writer.writeGenerator(header);
(0, fs_1.writeFileSync)(filename, writer.toString());
}
const raylib_header_1 = __webpack_require__(/*! ./raylib-header */ "./src/raylib-header.ts");
function main() {
const api = JSON.parse((0, fs_1.readFileSync)("thirdparty/raylib/parser/output/raylib_api.json", 'utf8'));
const apiDesc = new api_1.ApiDescription(api);
const core_gen = new header_1.RayLibHeaderGenerator("raylib_core", apiDesc);
const core_gen = new raylib_header_1.RayLibHeader("raylib_core", apiDesc);
core_gen.addApiFunctionByName("SetWindowTitle");
core_gen.addApiFunctionByName("SetWindowPosition");
core_gen.addApiFunctionByName("BeginDrawing");
core_gen.addApiFunctionByName("EndDrawing");
writeHeader(core_gen, "src/bindings/js_raylib_core.h");
const texture_gen = new header_1.RayLibHeaderGenerator("raylib_texture", apiDesc);
core_gen.writeTo("src/bindings/js_raylib_core.h");
const texture_gen = new raylib_header_1.RayLibHeader("raylib_texture", apiDesc);
texture_gen.addApiStructByName("Image", "UnloadImage");
writeHeader(texture_gen, "src/bindings/js_raylib_texture.h");
texture_gen.writeTo("src/bindings/js_raylib_texture.h");
}
main();

View File

@ -47,7 +47,7 @@ static const JSCFunctionListEntry js_raylib_core_funcs[] = {
JS_CFUNC_DEF("endDrawing",0,js_endDrawing),
};
int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) {
static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) {
JS_SetModuleExportList(ctx, m,js_raylib_core_funcs,countof(js_raylib_core_funcs));
return 0;
}

View File

@ -40,7 +40,7 @@ static int js_declare_Image(JSContext * ctx, JSModuleDef * m) {
static const JSCFunctionListEntry js_raylib_texture_funcs[] = {
};
int js_raylib_texture_init(JSContext * ctx, JSModuleDef * m) {
static int js_raylib_texture_init(JSContext * ctx, JSModuleDef * m) {
JS_SetModuleExportList(ctx, m,js_raylib_texture_funcs,countof(js_raylib_texture_funcs));
js_declare_Image(ctx, m);
return 0;