Skip to content
This repository was archived by the owner on Aug 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
"README.md"
],
"license": "MIT",
"devDependencies": {},
"devDependencies": {
"@types/node": "^18.11.9"
},
"dependencies": {
"commander": "^9.4.1",
"jacscript-compiler": "0.0.0"
}
}
}
77 changes: 77 additions & 0 deletions cli/src/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { join } from "node:path"
import { readFileSync, writeFileSync } from "node:fs"

import { compile, jacdacDefaultSpecifications, JacsDiagnostic } from "jacscript-compiler"
import { CmdOptions } from "./command"

function jacsFactory() {
let d = require("jacscript-vm")
try {
require("websocket-polyfill")
// @ts-ignore
global.Blob = require("buffer").Blob
} catch {
console.log("can't load websocket-polyfill")
}
return d()
}

async function getHost(options: BuildOptions) {
const inst = options.noVerify ? undefined : await jacsFactory()
inst?.jacsInit()

const jacsHost = {
write: (fn: string, cont: string) => {
const p = join(options.outDir || "built", fn)
if (options.verbose) console.debug(`write ${p}`)
writeFileSync(p, cont)
if (
fn.endsWith(".jasm") &&
typeof cont == "string" &&
cont.indexOf("???oops") >= 0
)
throw new Error("bad disassembly")
},
log: (msg: string) => {
if (options.verbose) console.log(msg)
},
error: (err: JacsDiagnostic) => {
console.error(err)
},
mainFileName: () => options.mainFileName || "",
getSpecs: () => jacdacDefaultSpecifications,
verifyBytecode: (buf: Uint8Array) => {
if (!inst) return
const res = inst.jacsDeploy(buf)
if (res != 0) throw new Error("verification error: " + res)
},
}
return jacsHost
}

async function compileBuf(buf: Buffer, options: BuildOptions) {
const host = await getHost(options)
const res = compile(buf.toString("utf8"), {
host,
isLibrary: options.library,
})
if (!res.success) throw new Error("compilation failed")
return res.binary
}

export interface BuildOptions extends CmdOptions {
noVerify?: boolean
library?: boolean
outDir?: string

mainFileName?: string
}

export async function build(file: string, options: BuildOptions) {
try {
const buf = readFileSync(file)
await compileBuf(buf, { ...options, mainFileName: file })
} catch (e) {
console.error(e.stack)
}
}
98 changes: 13 additions & 85 deletions cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,97 +1,25 @@
import { join } from "node:path"
import { readFileSync, writeFileSync } from "node:fs"

import { program as commander } from "commander"
import { compile, Host, jacdacDefaultSpecifications } from "jacscript-compiler"

interface CmdOptions {
verbose?: boolean
noVerify?: boolean
library?: boolean
_file?: string
}

let options: CmdOptions

const distPath = "built"

function jacsFactory() {
let d = require("jacscript-vm")
try {
require("websocket-polyfill")
// @ts-ignore
global.Blob = require("buffer").Blob
} catch {
console.log("can't load websocket-polyfill")
}
return d()
}

let jacsHost: Host
async function getHost() {
if (jacsHost) return jacsHost
const inst = await jacsFactory()
inst.jacsInit()
jacsHost = {
write: (fn, cont) => {
const p = join(distPath, fn)
console.log(`write ${p}`)
writeFileSync(p, cont)
if (
fn.endsWith(".jasm") &&
typeof cont == "string" &&
cont.indexOf("???oops") >= 0
)
throw new Error("bad disassembly")
},
log: msg => {
if (options.verbose) console.log(msg)
},
mainFileName: () => options._file || "",
getSpecs: () => jacdacDefaultSpecifications,
verifyBytecode: buf => {
if (options.noVerify) return
const res = inst.jacsDeploy(buf)
if (res != 0) throw new Error("verification error: " + res)
},
}
return jacsHost
}

async function compileBuf(buf: Buffer) {
const host = await getHost()
const res = compile(buf.toString("utf8"), {
host,
isLibrary: options.library,
})
if (!res.success) throw new Error("compilation failed")
return res.binary
}
const program = require("commander")
import { build } from "./build"
import pkg from "../package.json"

export async function mainCli() {
const pkg = require("../package.json")
commander
program
.name("jacscript")
.description("build and run Jacscript program https://aka.ms/jacscript")
.version(pkg.version)
.option("-v, --verbose", "more logging")

program
.command("build", { isDefault: true })
.description("build a jacscript file")
.option("-l, --library", "build library")
.option("--no-verify", "don't verify resulting bytecode")
.option("-o", "--out-dir", "output directory, default is 'built'")
.arguments("<file.ts>")
.parse(process.argv)

options = commander as CmdOptions

if (commander.args.length != 1) {
console.error("exactly one argument expected")
process.exit(1)
}

options._file = commander.args[0]
.action(build)

try {
await compileBuf(readFileSync(options._file))
} catch (e) {
console.error(e.stack)
}
program.parse(process.argv)
}

if (require.main === module) mainCli()
5 changes: 5 additions & 0 deletions cli/src/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface CmdOptions {
verbose?: boolean
noVerify?: boolean
library?: boolean
}
35 changes: 35 additions & 0 deletions cli/src/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"compilerOptions": {
"moduleResolution": "node",
"target": "es2017",
"module": "es2015",
"lib": [
"es2015",
"es2016",
"es2017",
"dom"
],
"strict": false,
"strictNullChecks": false,
"strictFunctionTypes": true,
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"preserveConstEnums": true,
"noImplicitThis": true,
"isolatedModules": true,
"noImplicitAny": true,
"esModuleInterop": true,
"declarationDir": "../built/types",
"resolveJsonModule": true,
"outDir": "../built",
"pretty": true,
"newLine": "LF",
"types": ["node"]
},
"include": [
"."
]
}
5 changes: 4 additions & 1 deletion compiler/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ async function main() {
}
console.log("bundle done")
copyCompiler()
if (!fast) await runTSC(["-b", "src"])
if (!fast) {
await runTSC(["-b", "src"])
await runTSC(["-b", "../cli/src"])
}
} catch (e) {
console.error(e)
}
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
resolved "https://registry.yarnpkg.com/@types/emscripten/-/emscripten-1.39.6.tgz#698b90fe60d44acf93c31064218fbea93fbfd85a"
integrity sha512-H90aoynNhhkQP6DRweEjJp5vfUVdIj7tdPLsu7pq89vODD/lcugKfZOsfgwpvM6XUewEp2N5dCg1Uf3Qe55Dcg==

"@types/node@^18.11.9":
version "18.11.9"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==

bufferutil@^4.0.1:
version "4.0.7"
resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad"
Expand Down