From f56fc33e7bd5ea80e7c28344b54ac781bd822fd3 Mon Sep 17 00:00:00 2001 From: Connor White Date: Sun, 15 Oct 2023 11:46:37 -0500 Subject: [PATCH 1/3] generate rust types --- package.json | 4 +++ preload.ts | 2 +- src/loader.ts | 9 ++++-- src/loaders/rs.ts | 21 ------------- src/loaders/rs/index.ts | 37 ++++++++++++++++++++++ src/loaders/rs/parse.js | 70 +++++++++++++++++++++++++++++++++++++++++ src/types.ts | 1 + 7 files changed, 120 insertions(+), 24 deletions(-) delete mode 100644 src/loaders/rs.ts create mode 100644 src/loaders/rs/index.ts create mode 100644 src/loaders/rs/parse.js diff --git a/package.json b/package.json index 14fcbc1..dba2dd8 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,10 @@ "url": "https://github.com/tr1ckydev/hyperimport/issues" }, "homepage": "https://github.com/tr1ckydev/hyperimport#readme", + "dependencies": { + "tree-sitter": "^0.20.5", + "tree-sitter-rust": "^0.20.4" + }, "devDependencies": { "bun-types": "latest" } diff --git a/preload.ts b/preload.ts index e0d9a9a..2640e20 100644 --- a/preload.ts +++ b/preload.ts @@ -7,7 +7,7 @@ const config: HyperImportConfig = (await import(`${cwd}/bunfig.toml`)).default.h debugLog(config.debug, 3, "registering loaders..."); for (const loader of config.loaders ?? []) { - await import(`./src/loaders/${loader}.ts`).then(async l => { + await import(`./src/loaders/${loader}`).then(async l => { const plugin = await new l.default(cwd).toPlugin(); Bun.plugin(plugin); debugLog(config.debug, 2, plugin.name, "has been registered."); diff --git a/src/loader.ts b/src/loader.ts index e59ef3f..15e4f4a 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -46,8 +46,12 @@ export default class { Bun.write(`${this.cwd}/@types/${filename}/lastModified`, lastModified(this.config.importPath)); const configWriter = Bun.file(`${this.cwd}/@types/${filename}/config.ts`).writer(); configWriter.write(`import { LoaderConfig, T } from "hyperimport";\nexport default {\n\tbuildCommand: ${JSON.stringify(this.config.buildCommand)},\n\toutDir: "${this.config.outDir}",\n\tsymbols: {`); - for (const symbol of nm(this.config.libPath)) { - configWriter.write(`\n\t\t${symbol}: {\n\t\t\targs: [],\n\t\t\treturns: T.void\n\t\t},`); + const symbols = nm(this.config.libPath); + const types = this._config.parseTypes?.(this.config.importPath, symbols); + for (const symbol of symbols) { + const type = types?.[symbol] ?? { args: [], returns: "T.void" }; + const args = type.args.join(", "); + configWriter.write(`\n\t\t${symbol}: {\n\t\t\targs: [${args}],\n\t\t\treturns: ${type.returns}\n\t\t},`); } configWriter.write(`\n\t}\n} satisfies LoaderConfig.Main;`); configWriter.end(); @@ -77,6 +81,7 @@ export default class { const lmfile = `${this.cwd}/@types/${basename(this.config.importPath)}/lastModified`; if (lm !== await Bun.file(lmfile).text()) { await this.build(); + await this.initConfigTypes(); Bun.write(lmfile, lm); } } diff --git a/src/loaders/rs.ts b/src/loaders/rs.ts deleted file mode 100644 index d7b82a0..0000000 --- a/src/loaders/rs.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { basename } from "path"; -import Loader from "../loader"; - -export default class extends Loader { - constructor() { - super("Rust Loader", - { - extension: "rs", - buildCommand: (importPath, outDir) => [ - "rustc", - "--crate-type", - "cdylib", - importPath, - "--out-dir", - outDir - ], - outDir: importPath => `build/${basename(importPath)}` - } - ); - } -} \ No newline at end of file diff --git a/src/loaders/rs/index.ts b/src/loaders/rs/index.ts new file mode 100644 index 0000000..514ab8a --- /dev/null +++ b/src/loaders/rs/index.ts @@ -0,0 +1,37 @@ +import { basename, join } from "path"; +import Loader from "../../loader"; + +export default class extends Loader { + constructor() { + super("Rust Loader", + { + extension: "rs", + buildCommand: (importPath, outDir) => [ + "rustc", + "--crate-type", + "cdylib", + importPath, + "--out-dir", + outDir + ], + outDir: importPath => `build/${basename(importPath)}`, + parseTypes: (importPath, targets) => { + // Use Node to run tree-sitter due to Bun issue: + // https://github.com/oven-sh/bun/issues/4188 + const types = Bun.spawnSync([ + "node", + join(import.meta.dir, "parse.js"), + importPath, + ...targets + ]).stdout.toString(); + try { + const result = JSON.parse(types); + return result; + } catch(e) { + return undefined; + } + } + } + ); + } +} diff --git a/src/loaders/rs/parse.js b/src/loaders/rs/parse.js new file mode 100644 index 0000000..b2c7151 --- /dev/null +++ b/src/loaders/rs/parse.js @@ -0,0 +1,70 @@ +const fs = require("fs"); +const Parser = require("tree-sitter"); +const Rust = require("tree-sitter-rust"); + +const path = process.argv[2]; +const targets = process.argv.slice(3); + +const parser = new Parser(); +parser.setLanguage(Rust); + +const source = fs.readFileSync(path, "utf8"); +const tree = parser.parse(source); + +const typeMap = { + "()": "T.void", + "bool": "T.bool", + "u8": "T.u8", + "u16": "T.u16", + "u32": "T.u32", + "u64": "T.u64", + "i8": "T.i8", + "i16": "T.i16", + "i32": "T.i32", + "i64": "T.i64", + "f32": "T.f32", + "f64": "T.f64", + "usize": "T.ptr", + "isize": "T.ptr", + "char": "T.u32" +}; + +function mapType(type) { + if(typeMap[type]) { + return typeMap[type]; + } + return type; +} + +const types = tree.rootNode.children.reduce((acc, node) => { + if(node.type === "function_item") { + const fnNameNode = node.children.find(child => child.type === "identifier"); + if(fnNameNode && targets.includes(fnNameNode.text)) { + const parameters = node.children.find(child => child.type === "parameters"); + const parameterTypes = parameters.children + .filter((child) => child.type === "parameter") + .map((child) => { + const primitiveType = child.children.find((child) => child.type === "primitive_type"); + if(primitiveType) { + return mapType(primitiveType.text); + } + const pointerType = child.children.find((child) => child.type === "pointer_type"); + if(pointerType) { + return "T.ptr"; + } + const functionType = child.children.find((child) => child.type === "function_type"); + if(functionType) { + return "T.function"; + } + }); + const returnType = node.children.find(child => child.type === "primitive_type" || child.type === "unit_type").text; + acc[fnNameNode.text] = { + args: parameterTypes, + returns: mapType(returnType) + }; + } + } + return acc; +}, {}); + +process.stdout.write(JSON.stringify(types)); diff --git a/src/types.ts b/src/types.ts index d33c43a..38ab6e7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,6 +20,7 @@ export namespace LoaderConfig { extension: string, buildCommand?: (importPath: string, outDir: string) => string[], outDir?: (importPath: string) => string, + parseTypes?: (importPath: string, targets: string[]) => Record | undefined, } export interface Internal { From b7e63e332ca9ca4e532ff252ecfe9c7cf3c51a58 Mon Sep 17 00:00:00 2001 From: Connor White Date: Sun, 22 Oct 2023 12:52:34 -0500 Subject: [PATCH 2/3] set correct usize/isize types based on architecture --- package.json | 1 + src/loaders/rs/parse.js | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index dba2dd8..510fb7a 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ }, "homepage": "https://github.com/tr1ckydev/hyperimport#readme", "dependencies": { + "arch": "^2.2.0", "tree-sitter": "^0.20.5", "tree-sitter-rust": "^0.20.4" }, diff --git a/src/loaders/rs/parse.js b/src/loaders/rs/parse.js index b2c7151..19455a7 100644 --- a/src/loaders/rs/parse.js +++ b/src/loaders/rs/parse.js @@ -1,4 +1,5 @@ const fs = require("fs"); +const arch = require("arch"); const Parser = require("tree-sitter"); const Rust = require("tree-sitter-rust"); @@ -11,6 +12,8 @@ parser.setLanguage(Rust); const source = fs.readFileSync(path, "utf8"); const tree = parser.parse(source); +const size = arch() === "x64" ? "64" : "32"; + const typeMap = { "()": "T.void", "bool": "T.bool", @@ -24,8 +27,8 @@ const typeMap = { "i64": "T.i64", "f32": "T.f32", "f64": "T.f64", - "usize": "T.ptr", - "isize": "T.ptr", + "usize": `T.u${size}`, + "isize": `T.i${size}`, "char": "T.u32" }; From e2d5d31fce4e915c17fa7fc4714361b5fb90cffb Mon Sep 17 00:00:00 2001 From: Connor White Date: Sun, 22 Oct 2023 12:53:04 -0500 Subject: [PATCH 3/3] add tree-sitter, tree-sitter-rust to trusted dependencies --- package.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 510fb7a..39cf412 100644 --- a/package.json +++ b/package.json @@ -32,5 +32,9 @@ }, "devDependencies": { "bun-types": "latest" - } -} \ No newline at end of file + }, + "trustedDependencies": [ + "tree-sitter", + "tree-sitter-rust" + ] +}