Skip to content

Commit

Permalink
added tools for generating bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
Glowman554 committed Jan 21, 2024
1 parent 263798f commit c01c883
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 23 deletions.
2 changes: 1 addition & 1 deletion examples/vm/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"mode": "flbb"
},
"dependencies": [
"vm@1.0.0-x64"
"vm@1.0.1-x64"
]
}
1 change: 1 addition & 0 deletions libs/vm/build.sh
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
deno run -A gen.ts
gcc native.c -o native.so -fpic --shared
47 changes: 47 additions & 0 deletions libs/vm/gen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { structGen } from "../../src/tools/structgen.ts";
import { functionGen, addDatatype, finish } from "../../src/tools/bindgen.ts";

const struct = `
struct vm_instance {
void* code;
int64_t* stack;
int stack_ptr;
int max_stack;
int64_t* global_variables;
uint8_t* global_variable_types;
int global_variable_size;
int64_t spark;
};
`;


const struct_bind = await structGen(struct, "struct vm_instance", [
"code",
"stack",
"stack_ptr",
"max_stack",
"global_variables",
"global_variable_types",
"global_variable_size",
"spark"
]);

addDatatype("struct vm_instance*", "int");
addDatatype("vm_instance*", "int");
addDatatype("int64_t", "int");
addDatatype("uint64_t", "int");

functionGen(48327, "void stack_push(struct vm_instance* vm, int64_t value);");
functionGen(48328, "int64_t stack_pop(struct vm_instance* vm);");
functionGen(48329, "void invoke(struct vm_instance* vm, uint64_t location);");
functionGen(48330, "struct vm_instance* vm_load(const char* file);");
functionGen(48331, "void vm_destroy(struct vm_instance* vm);");


const [ fl, c ] = finish(`#include "../../src/flvm/vm.h"\n`);

Deno.writeTextFileSync("vm.fl", struct_bind + fl);
Deno.writeTextFileSync("native.c", c);
7 changes: 0 additions & 7 deletions libs/vm/native.c
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
#include "../../src/flvm/vm.h"

void native_stack_push(struct vm_instance* vm) {
int64_t value = (int64_t) stack_pop(vm);
struct vm_instance* vm2 = (struct vm_instance*) stack_pop(vm);
stack_push(vm2, value);
stack_push(vm, 0);
}

void native_stack_pop(struct vm_instance* vm) {
struct vm_instance* vm2 = (struct vm_instance*) stack_pop(vm);
stack_push(vm, stack_pop(vm2));
}

void native_invoke(struct vm_instance* vm) {
uint64_t location = (uint64_t) stack_pop(vm);
struct vm_instance* vm2 = (struct vm_instance*) stack_pop(vm);
invoke(vm2, location);
stack_push(vm, 0);
}

void native_vm_load(struct vm_instance* vm) {
const char* file = (const char*) stack_pop(vm);
stack_push(vm, vm_load(file));
}

void native_vm_destroy(struct vm_instance* vm) {
struct vm_instance* vm2 = (struct vm_instance*) stack_pop(vm);
vm_destroy(vm2);
stack_push(vm, 0);
}


void init() {
vm_native_register(48327, native_stack_push);
vm_native_register(48328, native_stack_pop);
Expand Down
2 changes: 1 addition & 1 deletion libs/vm/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "vm",
"version": "1.0.0-x64",
"version": "1.0.1-x64",
"type": "module"
}
23 changes: 9 additions & 14 deletions libs/vm/vm.fl
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
$define struct vm_instance_offset_code 0
$define struct vm_instance_offset_stack 8
$define struct vm_instance_offset_stack_ptr 16
$define struct vm_instance_offset_max_stack 20
$define struct vm_instance_offset_global_variables 24
$define struct vm_instance_offset_global_variable_types 32
$define struct vm_instance_offset_global_variable_size 40
$define struct vm_instance_offset_spark 48
$define vm_instance_offset_code 0
$define vm_instance_offset_stack 8
$define vm_instance_offset_stack_ptr 16
$define vm_instance_offset_max_stack 20
$define vm_instance_offset_global_variables 24
$define vm_instance_offset_global_variable_types 32
$define vm_instance_offset_global_variable_size 40
$define vm_instance_offset_spark 48
$define struct vm_instance_size 56

function(assembly) stack_push(int vm, int value) -> void {
"48327"
}

function(assembly) stack_pop(int vm) -> int {
"48328"
}

function(assembly) invoke(int vm, int location) -> void {
"48329"
}

function(assembly) vm_load(str file) -> int {
"48330"
}

function(assembly) vm_destroy(int vm) -> void {
"48331"
}
}
160 changes: 160 additions & 0 deletions src/tools/bindgen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
function split_c_signature(signature: string) {
let return_type = signature.split("(", 1)[0];
let function_name;
let attributes;

if (return_type.split(" ").length == 1) {
function_name = return_type;
return_type = " ";
} else {
const ret_array = return_type.split(" ");
let len = ret_array.length;

function_name = ret_array[len - 1].trim();

ret_array.pop();
len--;

return_type = ret_array[len - 1];
attributes = "";

// loop over the reversed array
let is_ret = true;
for (let i = len - 2; i >= 0; i--) {
const _allowed_return_types = ['short', 'long', 'signed', 'unsigned', 'const', 'restrict', 'restrict', 'mutable'];
if (_allowed_return_types.includes(ret_array[i]) && is_ret) {
return_type = ret_array[i] + " " + return_type;
} else {
is_ret = false;
attributes = ret_array[i] + " " + attributes;
}
}

return_type = return_type.trim();
attributes = attributes.trim();
}

let class_name = "";
if (function_name.split("::", 1).length != 1) {
class_name = function_name.split("::", 1)[0];
function_name = function_name.split("::", 1)[1];
}

if (function_name.startsWith("*")) {
function_name = function_name.substring(1);
return_type = "*";
}

let params = signature.split("(")[1].split(")")[0].split(",").map(p => p.trim());
if (params[0] == "") {
params = [];
}

return {
"return_type": return_type,
"class_name": class_name,
"function_name": function_name,
"attributes": attributes,
"params": params,
"signature": signature
};
}

const datatype_lookup: { [key: string]: string } = {
"void": "void",
"char": "chr",
"const char*": "str",
"uint32_t": "int",
"bool": "int"
};


const translations: {id: number, translation: string}[] = [];
let outfl = "";
let outc = ""

function getDatatype(dt: string) {
if (!datatype_lookup[dt]) {
const newDt = prompt(`No datatype translation found for ${dt}! Translation? `);
datatype_lookup[dt] = newDt as string;
}
return datatype_lookup[dt];
}

export function addDatatype(dt: string, translation: string) {
datatype_lookup[dt] = translation;
}

export function functionGen(id: number, sigStr: string) {
const sig = split_c_signature(sigStr);

let fl = `function(assembly) ${sig.function_name}(`;
for (const param of sig.params) {
const datatype = param.substring(0, param.lastIndexOf(" ")).trim();
const name = param.substring(param.lastIndexOf(" ")).trim();



fl += getDatatype(datatype);
fl += " "
fl += name;
fl += ", ";
}

if (sig.params.length != 0) fl = fl.substring(0, fl.length - 2);
fl += `) -> ${getDatatype(sig.return_type)} {\n "${id}"\n}`;

outfl += fl + "\n";

let c = `void native_${sig.function_name}(struct vm_instance* vm) {\n`;
for (let i = sig.params.length; i--; i > 0) {

const datatype = sig.params[i].substring(0, sig.params[i].lastIndexOf(" ")).trim();
let name = sig.params[i].substring(sig.params[i].lastIndexOf(" ")).trim();
name = name == "vm" ? "vm2" : name;

c += ` ${datatype} ${name} = (${datatype}) stack_pop(vm);\n`;
}

if (sig.return_type != "void") {
c += ` stack_push(vm, ${sig.function_name}(`;
} else {
c += ` ${sig.function_name}(`;
}

for (const param of sig.params) {
let name = param.substring(param.lastIndexOf(" ")).trim();
name = name == "vm" ? "vm2" : name;

c += `${name}, `;
}

if (sig.params.length != 0) c = c.substring(0, c.length - 2);

if (sig.return_type != "void") {
c += `));\n}`;
} else {
c += `);\n stack_push(vm, 0);\n}`;
}


outc += c + "\n";

translations.push({
id: id,
translation: "native_" + sig.function_name
});
}

export function finish(include: string) {
let finalc = include + outc;


finalc += "void init() {\n";
for (const translation of translations) {
finalc += ` vm_native_register(${translation.id}, ${translation.translation});\n`;
}
finalc += "}";

return [outfl, finalc];
}
44 changes: 44 additions & 0 deletions src/tools/structgen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
async function runCommand(command: string) {
// console.log("cmd: " + command);
const proc = Deno.run({
cmd: command.split(" ").filter(v => v != ""),
stderr: "inherit",
stdout: "piped"
});

const status = await proc.status();
const stdout = new TextDecoder().decode(await proc.output());
proc.close();
if (!status.success) {
throw new Error("Could not execute: " + command);
}

return stdout;
}
function genCode(structDefinition: string, structName: string, members: string[]) {
let code = "";

code += "#include <stdbool.h>\n";
code += "#include <stdint.h>\n";
code += "#include <stdio.h>\n";

code += structDefinition + "\n";

code += "int main() {\n";
for (const member of members) {
const name = structName.startsWith("struct ") ? structName.replace("struct ", "") : structName;
code += `\tprintf("$define ${name}_offset_${member} %ld\\n", __builtin_offsetof(${structName}, ${member}));\n`;
}

code += `\tprintf("$define ${structName}_size %ld\\n", sizeof(${structName}));\n`;

code += "}\n";

return code;
}

export async function structGen(structDefinition: string, structName: string, members: string[]) {
Deno.writeTextFileSync("/tmp/struct.c", genCode(structDefinition, structName, members));
await runCommand("gcc /tmp/struct.c -o /tmp/struct.elf");
return await runCommand("/tmp/struct.elf");
}

0 comments on commit c01c883

Please sign in to comment.