From 50105d7855f69190f235ebd50e261863905ef173 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 14 May 2018 13:02:47 -0400 Subject: [PATCH] Use typescript --- Makefile | 2 +- compiler.ts | 128 ++++++++++++++++++ fs.ts | 18 +++ main.go | 12 +- main.ts | 28 +--- msg.proto | 13 +- .../{hello_world.out => hello_world.js.out} | 0 testdata/hello_world.ts | 1 + testdata/hello_world.ts.out | 1 + util.ts | 8 +- 10 files changed, 177 insertions(+), 34 deletions(-) create mode 100644 compiler.ts create mode 100644 fs.ts rename testdata/{hello_world.out => hello_world.js.out} (100%) create mode 100644 testdata/hello_world.ts create mode 100644 testdata/hello_world.ts.out diff --git a/Makefile b/Makefile index f43c453b6a..25416012b2 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ msg.pb.js: msg.proto node_modules msg.pb.d.ts: msg.pb.js node_modules ./node_modules/.bin/pbts -o msg.pb.d.ts msg.pb.js -dist/main.js: main.ts msg.pb.js msg.pb.d.ts node_modules +dist/main.js: main.ts compiler.ts fs.ts util.ts msg.pb.js msg.pb.d.ts node_modules ./node_modules/.bin/tsc --noEmit # Only for type checking. ./node_modules/.bin/parcel build --out-dir=dist/ --no-minify main.ts diff --git a/compiler.ts b/compiler.ts new file mode 100644 index 0000000000..fdd9dc997a --- /dev/null +++ b/compiler.ts @@ -0,0 +1,128 @@ +import * as ts from "typescript"; +import { assert, globalEval } from "./util"; +import { readFileSync } from "./fs"; + +export function compile(cwd: string, inputFn: string): void { + const options: ts.CompilerOptions = { + "allowJs": true, + "outFile": "out.js", + }; + const host = new CompilerHost(cwd); + + let program = ts.createProgram([inputFn], options, host); + //let sourceFiles = program.getSourceFiles(); + //console.log("rootFileNames", program.getRootFileNames()); + + let emitResult = program.emit(); + assert(!emitResult.emitSkipped); + //console.log("emitResult", emitResult); +} + +export class CompilerHost { + constructor(public cwd: string) {} + + getSourceFile( + fileName: string, + languageVersion: ts.ScriptTarget, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean + ): ts.SourceFile | undefined { + //console.log("getSourceFile", fileName); + let sourceText: string; + if (fileName === "lib.d.ts") { + // TODO this should be compiled into the bindata. + sourceText = readFileSync("node_modules/typescript/lib/lib.d.ts"); + } else { + sourceText = readFileSync(fileName); + } + if (sourceText) { + return ts.createSourceFile(fileName, sourceText, languageVersion); + } else { + return undefined; + } + } + + getSourceFileByPath?( + fileName: string, + path: ts.Path, + languageVersion: ts.ScriptTarget, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean + ): ts.SourceFile | undefined { + console.log("getSourceFileByPath", fileName); + return undefined; + } + + // getCancellationToken?(): CancellationToken; + getDefaultLibFileName(options: ts.CompilerOptions): string { + return ts.getDefaultLibFileName(options); + } + + getDefaultLibLocation(): string { + return "/blah/"; + } + + outFileSource: string; + writeFile( + fileName: string, + data: string, + writeByteOrderMark: boolean, + onError: ((message: string) => void) | undefined, + sourceFiles: ReadonlyArray + ): void { + //console.log("writeFile", fileName); + //console.log("writeFile source", data); + globalEval(data); + //this.outFileSource = data; + } + + getCurrentDirectory(): string { + return this.cwd; + } + + getDirectories(path: string): string[] { + console.log("getDirectories", path); + return []; + } + + getCanonicalFileName(fileName: string): string { + return fileName; + } + + useCaseSensitiveFileNames(): boolean { + return true; + } + + getNewLine(): string { + return "\n"; + } + + resolveModuleNames( + moduleNames: string[], + containingFile: string, + reusedNames?: string[] + ): (ts.ResolvedModule | undefined)[] { + console.log("resolveModuleNames", moduleNames); + return []; + } + + fileExists(fileName: string): boolean { + console.log("fileExists", fileName); + return false; + } + + readFile(fileName: string): string | undefined { + console.log("readFile", fileName); + return undefined; + } + + /** + * This method is a companion for 'resolveModuleNames' and is used to resolve + * 'types' references to actual type declaration files + */ + // resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], + // containingFile: string): (ResolvedTypeReferenceDirective | undefined)[]; + + // getEnvironmentVariable?(name: string): string + // createHash?(data: string): string; +} diff --git a/fs.ts b/fs.ts new file mode 100644 index 0000000000..a3d4c95195 --- /dev/null +++ b/fs.ts @@ -0,0 +1,18 @@ +import { main as pb } from "./msg.pb"; +import { TextDecoder } from "text-encoding"; + +export function readFileSync(filename: string): string { + const msg = pb.Msg.fromObject({ + kind: pb.Msg.MsgKind.READ_FILE_SYNC, + path: filename + }); + const ui8 = pb.Msg.encode(msg).finish(); + const ab = ui8.buffer.slice(ui8.byteOffset, ui8.byteOffset + ui8.byteLength); + const resBuf = V8Worker2.send(ab as ArrayBuffer); + const res = pb.Msg.decode(new Uint8Array(resBuf)); + if (res.error != null && res.error.length > 0) { + throw Error(res.error); + } + const decoder = new TextDecoder("utf8"); + return decoder.decode(res.data); +} diff --git a/main.go b/main.go index 71f296591b..e634a6abe2 100644 --- a/main.go +++ b/main.go @@ -50,11 +50,15 @@ func loadAsset(w *v8worker2.Worker, path string) { func main() { worker := v8worker2.New(recv) loadAsset(worker, "dist/main.js") - loadMsg := &Msg{ - Kind: Msg_LOAD, - Argv: os.Args, + cwd, err := os.Getwd() + if err != nil { + panic(err) } - out, err := proto.Marshal(loadMsg) + out, err := proto.Marshal(&Msg{ + Kind: Msg_START, + Cwd: cwd, + Argv: os.Args, + }) if err != nil { panic(err) } diff --git a/main.ts b/main.ts index f833a3b6cc..bd1b13ed5e 100644 --- a/main.ts +++ b/main.ts @@ -1,35 +1,19 @@ -//import * as ts from "typescript"; import { main as pb } from "./msg.pb"; import "./util"; -import { TextDecoder } from "text-encoding"; +import { compile } from "./compiler"; -function readFileSync(filename: string): string { - const msg = pb.Msg.fromObject({ - kind: pb.Msg.MsgKind.READ_FILE_SYNC, - path: filename - }); - const ui8 = pb.Msg.encode(msg).finish(); - const ab = ui8.buffer.slice(ui8.byteOffset, ui8.byteOffset + ui8.byteLength); - const resBuf = V8Worker2.send(ab as ArrayBuffer); - const res = pb.Msg.decode(new Uint8Array(resBuf)); - if (res.error != null && res.error.length > 0) { - throw Error(res.error); - } - const decoder = new TextDecoder("utf8"); - return decoder.decode(res.data); -} -function load(argv: string[]): void { +function start(cwd: string, argv: string[]): void { + // TODO parse arguments. const inputFn = argv[1]; - const source = readFileSync(inputFn); - console.log("source", source); + compile(cwd, inputFn); } V8Worker2.recv((ab: ArrayBuffer) => { const msg = pb.Msg.decode(new Uint8Array(ab)); switch (msg.kind) { - case pb.Msg.MsgKind.LOAD: - load(msg.argv); + case pb.Msg.MsgKind.START: + start(msg.cwd, msg.argv); break; default: console.log("Unknown message", msg); diff --git a/msg.proto b/msg.proto index 00598ea903..df0b7c102e 100644 --- a/msg.proto +++ b/msg.proto @@ -4,19 +4,20 @@ package main; message Msg { enum MsgKind { - LOAD = 0; + START = 0; READ_FILE_SYNC = 1; DATA_RESPONSE = 2; } MsgKind kind = 10; - // LOAD - repeated string argv = 11; + // START + string cwd = 11; + repeated string argv = 12; // READ_FILE_SYNC - string path = 12; + string path = 20; // DATA_RESPONSE - bytes data = 13; - string error = 14; + bytes data = 30; + string error = 31; } diff --git a/testdata/hello_world.out b/testdata/hello_world.js.out similarity index 100% rename from testdata/hello_world.out rename to testdata/hello_world.js.out diff --git a/testdata/hello_world.ts b/testdata/hello_world.ts new file mode 100644 index 0000000000..accefceba6 --- /dev/null +++ b/testdata/hello_world.ts @@ -0,0 +1 @@ +console.log("Hello World"); diff --git a/testdata/hello_world.ts.out b/testdata/hello_world.ts.out new file mode 100644 index 0000000000..557db03de9 --- /dev/null +++ b/testdata/hello_world.ts.out @@ -0,0 +1 @@ +Hello World diff --git a/util.ts b/util.ts index e92714d99f..f5e5e847e6 100644 --- a/util.ts +++ b/util.ts @@ -3,7 +3,7 @@ // the local scope. This means, for instance, that function declarations create // global functions, and that the code being evaluated doesn't have access to // local variables within the scope where it's being called. -const globalEval = eval; +export const globalEval = eval; // A reference to the global object. const _global = globalEval("this"); @@ -24,3 +24,9 @@ _global["console"] = { print(out.join(" ")); } }; + +export function assert(cond: boolean, msg = "") { + if (!cond) { + throw Error("Assertion failed. " + msg); + } +}