mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 00:29:09 -05:00
Native ES modules (#1460)
* Native ES modules This is a major refactor of internal compiler. Before: JS and TS both were sent through the typescript compiler where their imports were parsed and handled. Both compiled to AMD JS and finally sent to V8 Now: JS is sent directly into V8. TS is sent through the typescript compiler, but tsc generates ES modules now instead of AMD. This generated JS is then dumped into V8. This should much faster for pure JS code. It may improve TS compilation speed. In the future this allows us to separate TS out of the runtime heap and into its own dedicated snapshot. This will result in a smaller runtime heap, and thus should be faster. Some tests were unfortunately disabled to ease landing this patch: 1. compiler_tests.ts which I intend to bring back in later commits. 2. Some text_encoding_test.ts tests which made the file invalid utf8. See PR for a discussion. Also worth noting that this is necessary to support WASM
This commit is contained in:
parent
3afdae165d
commit
0ceb554343
22 changed files with 300 additions and 312 deletions
240
js/compiler.ts
240
js/compiler.ts
|
@ -3,34 +3,20 @@ import * as ts from "typescript";
|
||||||
import { MediaType } from "gen/msg_generated";
|
import { MediaType } from "gen/msg_generated";
|
||||||
import { assetSourceCode } from "./assets";
|
import { assetSourceCode } from "./assets";
|
||||||
import * as os from "./os";
|
import * as os from "./os";
|
||||||
// tslint:disable-next-line:no-circular-imports
|
|
||||||
import * as deno from "./deno";
|
|
||||||
import { globalEval } from "./global_eval";
|
|
||||||
import { assert, log, notImplemented } from "./util";
|
import { assert, log, notImplemented } from "./util";
|
||||||
|
|
||||||
const window = globalEval("this");
|
// tslint:disable-next-line:no-circular-imports
|
||||||
|
// import * as deno from "./deno";
|
||||||
|
|
||||||
const EOL = "\n";
|
const EOL = "\n";
|
||||||
const ASSETS = "$asset$";
|
const ASSETS = "$asset$";
|
||||||
const LIB_RUNTIME = "lib.deno_runtime.d.ts";
|
const LIB_RUNTIME = "lib.deno_runtime.d.ts";
|
||||||
|
|
||||||
// tslint:disable:no-any
|
|
||||||
type AmdCallback = (...args: any[]) => void;
|
|
||||||
type AmdErrback = (err: any) => void;
|
|
||||||
export type AmdFactory = (...args: any[]) => object | void;
|
|
||||||
// tslint:enable:no-any
|
|
||||||
export type AmdDefine = (deps: ModuleSpecifier[], factory: AmdFactory) => void;
|
|
||||||
type AMDRequire = (
|
|
||||||
deps: ModuleSpecifier[],
|
|
||||||
callback: AmdCallback,
|
|
||||||
errback: AmdErrback
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
/** The location that a module is being loaded from. This could be a directory,
|
/** The location that a module is being loaded from. This could be a directory,
|
||||||
* like `.`, or it could be a module specifier like
|
* like `.`, or it could be a module specifier like
|
||||||
* `http://gist.github.com/somefile.ts`
|
* `http://gist.github.com/somefile.ts`
|
||||||
*/
|
*/
|
||||||
type ContainingFile = string;
|
export type ContainingFile = string;
|
||||||
/** The internal local filename of a compiled module. It will often be something
|
/** The internal local filename of a compiled module. It will often be something
|
||||||
* like `/home/ry/.deno/gen/f7b4605dfbc4d3bb356e98fda6ceb1481e4a8df5.js`
|
* like `/home/ry/.deno/gen/f7b4605dfbc4d3bb356e98fda6ceb1481e4a8df5.js`
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +28,7 @@ type ModuleId = string;
|
||||||
/** The external name of a module - could be a URL or could be a relative path.
|
/** The external name of a module - could be a URL or could be a relative path.
|
||||||
* Examples `http://gist.github.com/somefile.ts` or `./somefile.ts`
|
* Examples `http://gist.github.com/somefile.ts` or `./somefile.ts`
|
||||||
*/
|
*/
|
||||||
type ModuleSpecifier = string;
|
export type ModuleSpecifier = string;
|
||||||
/** The compiled source code which is cached in `.deno/gen/` */
|
/** The compiled source code which is cached in `.deno/gen/` */
|
||||||
type OutputCode = string;
|
type OutputCode = string;
|
||||||
/** The original source code */
|
/** The original source code */
|
||||||
|
@ -78,7 +64,6 @@ export interface Ts {
|
||||||
export class ModuleMetaData implements ts.IScriptSnapshot {
|
export class ModuleMetaData implements ts.IScriptSnapshot {
|
||||||
public deps?: ModuleFileName[];
|
public deps?: ModuleFileName[];
|
||||||
public exports = {};
|
public exports = {};
|
||||||
public factory?: AmdFactory;
|
|
||||||
public gatheringDeps = false;
|
public gatheringDeps = false;
|
||||||
public hasRun = false;
|
public hasRun = false;
|
||||||
public scriptVersion = "";
|
public scriptVersion = "";
|
||||||
|
@ -149,8 +134,6 @@ export class DenoCompiler
|
||||||
ContainingFile,
|
ContainingFile,
|
||||||
Map<ModuleSpecifier, ModuleFileName>
|
Map<ModuleSpecifier, ModuleFileName>
|
||||||
>();
|
>();
|
||||||
// A reference to global eval, so it can be monkey patched during testing
|
|
||||||
private _globalEval = globalEval;
|
|
||||||
// A reference to the log utility, so it can be monkey patched during testing
|
// A reference to the log utility, so it can be monkey patched during testing
|
||||||
private _log = log;
|
private _log = log;
|
||||||
// A map of module file names to module meta data
|
// A map of module file names to module meta data
|
||||||
|
@ -163,7 +146,7 @@ export class DenoCompiler
|
||||||
private readonly _options: ts.CompilerOptions = {
|
private readonly _options: ts.CompilerOptions = {
|
||||||
allowJs: true,
|
allowJs: true,
|
||||||
checkJs: true,
|
checkJs: true,
|
||||||
module: ts.ModuleKind.AMD,
|
module: ts.ModuleKind.ESNext,
|
||||||
outDir: "$deno$",
|
outDir: "$deno$",
|
||||||
resolveJsonModule: true,
|
resolveJsonModule: true,
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
|
@ -173,9 +156,6 @@ export class DenoCompiler
|
||||||
// A reference to the `./os.ts` module, so it can be monkey patched during
|
// A reference to the `./os.ts` module, so it can be monkey patched during
|
||||||
// testing
|
// testing
|
||||||
private _os: Os = os;
|
private _os: Os = os;
|
||||||
// Contains a queue of modules that have been resolved, but not yet
|
|
||||||
// run
|
|
||||||
private _runQueue: ModuleMetaData[] = [];
|
|
||||||
// Used to contain the script file we are currently running
|
// Used to contain the script file we are currently running
|
||||||
private _scriptFileNames: string[] = [];
|
private _scriptFileNames: string[] = [];
|
||||||
// A reference to the TypeScript LanguageService instance so it can be
|
// A reference to the TypeScript LanguageService instance so it can be
|
||||||
|
@ -184,84 +164,9 @@ export class DenoCompiler
|
||||||
// A reference to `typescript` module so it can be monkey patched during
|
// A reference to `typescript` module so it can be monkey patched during
|
||||||
// testing
|
// testing
|
||||||
private _ts: Ts = ts;
|
private _ts: Ts = ts;
|
||||||
// A reference to the global scope so it can be monkey patched during
|
|
||||||
// testing
|
|
||||||
private _window = window;
|
|
||||||
// Flags forcing recompilation of TS code
|
// Flags forcing recompilation of TS code
|
||||||
public recompile = false;
|
public recompile = false;
|
||||||
|
|
||||||
/** Drain the run queue, retrieving the arguments for the module
|
|
||||||
* factory and calling the module's factory.
|
|
||||||
*/
|
|
||||||
private _drainRunQueue(): void {
|
|
||||||
this._log(
|
|
||||||
"compiler._drainRunQueue",
|
|
||||||
this._runQueue.map(metaData => metaData.fileName)
|
|
||||||
);
|
|
||||||
let moduleMetaData: ModuleMetaData | undefined;
|
|
||||||
while ((moduleMetaData = this._runQueue.shift())) {
|
|
||||||
assert(
|
|
||||||
moduleMetaData.factory != null,
|
|
||||||
"Cannot run module without factory."
|
|
||||||
);
|
|
||||||
assert(moduleMetaData.hasRun === false, "Module has already been run.");
|
|
||||||
// asserts not tracked by TypeScripts, so using not null operator
|
|
||||||
const exports = moduleMetaData.factory!(
|
|
||||||
...this._getFactoryArguments(moduleMetaData)
|
|
||||||
);
|
|
||||||
// For JSON module support and potential future features.
|
|
||||||
// TypeScript always imports `exports` and mutates it directly, but the
|
|
||||||
// AMD specification allows values to be returned from the factory.
|
|
||||||
if (exports != null) {
|
|
||||||
moduleMetaData.exports = exports;
|
|
||||||
}
|
|
||||||
moduleMetaData.hasRun = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the dependencies for a given module, but don't run the module,
|
|
||||||
* just add the module factory to the run queue.
|
|
||||||
*/
|
|
||||||
private _gatherDependencies(moduleMetaData: ModuleMetaData): void {
|
|
||||||
this._log("compiler._resolveDependencies", moduleMetaData.fileName);
|
|
||||||
|
|
||||||
// if the module has already run, we can short circuit.
|
|
||||||
// it is intentional though that if we have already resolved dependencies,
|
|
||||||
// we won't short circuit, as something may have changed, or we might have
|
|
||||||
// only collected the dependencies to be able to able to obtain the graph of
|
|
||||||
// dependencies
|
|
||||||
if (moduleMetaData.hasRun) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._window.define = this._makeDefine(moduleMetaData);
|
|
||||||
this._globalEval(this.compile(moduleMetaData));
|
|
||||||
this._window.define = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieve the arguments to pass a module's factory function. */
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
private _getFactoryArguments(moduleMetaData: ModuleMetaData): any[] {
|
|
||||||
if (!moduleMetaData.deps) {
|
|
||||||
throw new Error("Cannot get arguments until dependencies resolved.");
|
|
||||||
}
|
|
||||||
return moduleMetaData.deps.map(dep => {
|
|
||||||
if (dep === "require") {
|
|
||||||
return this._makeLocalRequire(moduleMetaData);
|
|
||||||
}
|
|
||||||
if (dep === "exports") {
|
|
||||||
return moduleMetaData.exports;
|
|
||||||
}
|
|
||||||
if (dep in DenoCompiler._builtins) {
|
|
||||||
return DenoCompiler._builtins[dep];
|
|
||||||
}
|
|
||||||
const dependencyMetaData = this._getModuleMetaData(dep);
|
|
||||||
assert(dependencyMetaData != null, `Missing dependency "${dep}".`);
|
|
||||||
// TypeScript does not track assert, therefore using not null operator
|
|
||||||
return dependencyMetaData!.exports;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The TypeScript language service often refers to the resolved fileName of
|
/** The TypeScript language service often refers to the resolved fileName of
|
||||||
* a module, this is a shortcut to avoid unnecessary module resolution logic
|
* a module, this is a shortcut to avoid unnecessary module resolution logic
|
||||||
* for modules that may have been initially resolved by a `moduleSpecifier`
|
* for modules that may have been initially resolved by a `moduleSpecifier`
|
||||||
|
@ -270,9 +175,7 @@ export class DenoCompiler
|
||||||
* TypeScript compiler, but the TypeScript compiler shouldn't be asking about
|
* TypeScript compiler, but the TypeScript compiler shouldn't be asking about
|
||||||
* external modules that we haven't told it about yet.
|
* external modules that we haven't told it about yet.
|
||||||
*/
|
*/
|
||||||
private _getModuleMetaData(
|
getModuleMetaData(fileName: ModuleFileName): ModuleMetaData | undefined {
|
||||||
fileName: ModuleFileName
|
|
||||||
): ModuleMetaData | undefined {
|
|
||||||
return this._moduleMetaDataMap.has(fileName)
|
return this._moduleMetaDataMap.has(fileName)
|
||||||
? this._moduleMetaDataMap.get(fileName)
|
? this._moduleMetaDataMap.get(fileName)
|
||||||
: fileName.startsWith(ASSETS)
|
: fileName.startsWith(ASSETS)
|
||||||
|
@ -280,66 +183,6 @@ export class DenoCompiler
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a localized AMD `define` function and return it. */
|
|
||||||
private _makeDefine(moduleMetaData: ModuleMetaData): AmdDefine {
|
|
||||||
return (deps: ModuleSpecifier[], factory: AmdFactory): void => {
|
|
||||||
this._log("compiler.localDefine", moduleMetaData.fileName);
|
|
||||||
moduleMetaData.factory = factory;
|
|
||||||
// when there are circular dependencies, we need to skip recursing the
|
|
||||||
// dependencies
|
|
||||||
moduleMetaData.gatheringDeps = true;
|
|
||||||
// we will recursively resolve the dependencies for any modules
|
|
||||||
moduleMetaData.deps = deps.map(dep => {
|
|
||||||
if (
|
|
||||||
dep === "require" ||
|
|
||||||
dep === "exports" ||
|
|
||||||
dep in DenoCompiler._builtins
|
|
||||||
) {
|
|
||||||
return dep;
|
|
||||||
}
|
|
||||||
const dependencyMetaData = this.resolveModule(
|
|
||||||
dep,
|
|
||||||
moduleMetaData.fileName
|
|
||||||
);
|
|
||||||
if (!dependencyMetaData.gatheringDeps) {
|
|
||||||
this._gatherDependencies(dependencyMetaData);
|
|
||||||
}
|
|
||||||
return dependencyMetaData.fileName;
|
|
||||||
});
|
|
||||||
moduleMetaData.gatheringDeps = false;
|
|
||||||
if (!this._runQueue.includes(moduleMetaData)) {
|
|
||||||
this._runQueue.push(moduleMetaData);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a require that specifically handles the resolution of a transpiled
|
|
||||||
* emit of a dynamic ES `import()` from TypeScript.
|
|
||||||
*/
|
|
||||||
private _makeLocalRequire(moduleMetaData: ModuleMetaData): AMDRequire {
|
|
||||||
return (
|
|
||||||
deps: ModuleSpecifier[],
|
|
||||||
callback: AmdCallback,
|
|
||||||
errback: AmdErrback
|
|
||||||
): void => {
|
|
||||||
log("localRequire", deps);
|
|
||||||
assert(
|
|
||||||
deps.length === 1,
|
|
||||||
"Local require requires exactly one dependency."
|
|
||||||
);
|
|
||||||
const [moduleSpecifier] = deps;
|
|
||||||
try {
|
|
||||||
const requiredMetaData = this.run(
|
|
||||||
moduleSpecifier,
|
|
||||||
moduleMetaData.fileName
|
|
||||||
);
|
|
||||||
callback(requiredMetaData.exports);
|
|
||||||
} catch (e) {
|
|
||||||
errback(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Given a `moduleSpecifier` and `containingFile` retrieve the cached
|
/** Given a `moduleSpecifier` and `containingFile` retrieve the cached
|
||||||
* `fileName` for a given module. If the module has yet to be resolved
|
* `fileName` for a given module. If the module has yet to be resolved
|
||||||
* this will return `undefined`.
|
* this will return `undefined`.
|
||||||
|
@ -468,32 +311,11 @@ export class DenoCompiler
|
||||||
return moduleMetaData ? moduleMetaData.sourceMap : "";
|
return moduleMetaData ? moduleMetaData.sourceMap : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** For a given module specifier and containing file, return a list of
|
getOutput(filename: ModuleFileName): OutputCode {
|
||||||
* absolute identifiers for dependent modules that are required by this
|
const moduleMetaData = this.getModuleMetaData(filename)!;
|
||||||
* module.
|
assert(moduleMetaData != null, `Module not loaded: "${filename}"`);
|
||||||
*/
|
this._scriptFileNames = [moduleMetaData.fileName];
|
||||||
getModuleDependencies(
|
return this.compile(moduleMetaData);
|
||||||
moduleSpecifier: ModuleSpecifier,
|
|
||||||
containingFile: ContainingFile
|
|
||||||
): ModuleFileName[] {
|
|
||||||
assert(
|
|
||||||
this._runQueue.length === 0,
|
|
||||||
"Cannot get dependencies with modules queued to be run."
|
|
||||||
);
|
|
||||||
const moduleMetaData = this.resolveModule(moduleSpecifier, containingFile);
|
|
||||||
assert(
|
|
||||||
!moduleMetaData.hasRun,
|
|
||||||
"Cannot get dependencies for a module that has already been run."
|
|
||||||
);
|
|
||||||
this._gatherDependencies(moduleMetaData);
|
|
||||||
const dependencies = this._runQueue.map(
|
|
||||||
moduleMetaData => moduleMetaData.moduleId
|
|
||||||
);
|
|
||||||
// empty the run queue, to free up references to factories we have collected
|
|
||||||
// and to ensure that if there is a further invocation of `.run()` the
|
|
||||||
// factories don't get called
|
|
||||||
this._runQueue = [];
|
|
||||||
return dependencies;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Given a `moduleSpecifier` and `containingFile`, resolve the module and
|
/** Given a `moduleSpecifier` and `containingFile`, resolve the module and
|
||||||
|
@ -543,6 +365,7 @@ export class DenoCompiler
|
||||||
}
|
}
|
||||||
assert(moduleId != null, "No module ID.");
|
assert(moduleId != null, "No module ID.");
|
||||||
assert(fileName != null, "No file name.");
|
assert(fileName != null, "No file name.");
|
||||||
|
assert(sourceCode ? sourceCode.length > 0 : false, "No source code.");
|
||||||
assert(
|
assert(
|
||||||
mediaType !== MediaType.Unknown,
|
mediaType !== MediaType.Unknown,
|
||||||
`Unknown media type for: "${moduleSpecifier}" from "${containingFile}".`
|
`Unknown media type for: "${moduleSpecifier}" from "${containingFile}".`
|
||||||
|
@ -581,13 +404,23 @@ export class DenoCompiler
|
||||||
this._log("compiler.run", { moduleSpecifier, containingFile });
|
this._log("compiler.run", { moduleSpecifier, containingFile });
|
||||||
const moduleMetaData = this.resolveModule(moduleSpecifier, containingFile);
|
const moduleMetaData = this.resolveModule(moduleSpecifier, containingFile);
|
||||||
this._scriptFileNames = [moduleMetaData.fileName];
|
this._scriptFileNames = [moduleMetaData.fileName];
|
||||||
if (!moduleMetaData.deps) {
|
|
||||||
this._gatherDependencies(moduleMetaData);
|
|
||||||
}
|
|
||||||
this._drainRunQueue();
|
|
||||||
return moduleMetaData;
|
return moduleMetaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSource(filename: ModuleFileName): SourceCode {
|
||||||
|
const moduleMetaData = this.getModuleMetaData(filename)!;
|
||||||
|
assert(moduleMetaData != null, `Module not loaded: "${filename}"`);
|
||||||
|
return moduleMetaData.sourceCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
getJavaScriptSource(filename: ModuleFileName): OutputCode {
|
||||||
|
let s = this.getOutput(filename);
|
||||||
|
if (!s) {
|
||||||
|
s = this.getSource(filename);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
// TypeScript Language Service and Format Diagnostic Host API
|
// TypeScript Language Service and Format Diagnostic Host API
|
||||||
|
|
||||||
getCanonicalFileName(fileName: string): string {
|
getCanonicalFileName(fileName: string): string {
|
||||||
|
@ -613,7 +446,7 @@ export class DenoCompiler
|
||||||
|
|
||||||
getScriptKind(fileName: ModuleFileName): ts.ScriptKind {
|
getScriptKind(fileName: ModuleFileName): ts.ScriptKind {
|
||||||
this._log("getScriptKind()", fileName);
|
this._log("getScriptKind()", fileName);
|
||||||
const moduleMetaData = this._getModuleMetaData(fileName);
|
const moduleMetaData = this.getModuleMetaData(fileName);
|
||||||
if (moduleMetaData) {
|
if (moduleMetaData) {
|
||||||
switch (moduleMetaData.mediaType) {
|
switch (moduleMetaData.mediaType) {
|
||||||
case MediaType.TypeScript:
|
case MediaType.TypeScript:
|
||||||
|
@ -632,13 +465,13 @@ export class DenoCompiler
|
||||||
|
|
||||||
getScriptVersion(fileName: ModuleFileName): string {
|
getScriptVersion(fileName: ModuleFileName): string {
|
||||||
this._log("getScriptVersion()", fileName);
|
this._log("getScriptVersion()", fileName);
|
||||||
const moduleMetaData = this._getModuleMetaData(fileName);
|
const moduleMetaData = this.getModuleMetaData(fileName);
|
||||||
return (moduleMetaData && moduleMetaData.scriptVersion) || "";
|
return (moduleMetaData && moduleMetaData.scriptVersion) || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
getScriptSnapshot(fileName: ModuleFileName): ts.IScriptSnapshot | undefined {
|
getScriptSnapshot(fileName: ModuleFileName): ts.IScriptSnapshot | undefined {
|
||||||
this._log("getScriptSnapshot()", fileName);
|
this._log("getScriptSnapshot()", fileName);
|
||||||
return this._getModuleMetaData(fileName);
|
return this.getModuleMetaData(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentDirectory(): string {
|
getCurrentDirectory(): string {
|
||||||
|
@ -664,7 +497,7 @@ export class DenoCompiler
|
||||||
}
|
}
|
||||||
|
|
||||||
fileExists(fileName: string): boolean {
|
fileExists(fileName: string): boolean {
|
||||||
const moduleMetaData = this._getModuleMetaData(fileName);
|
const moduleMetaData = this.getModuleMetaData(fileName);
|
||||||
const exists = moduleMetaData != null;
|
const exists = moduleMetaData != null;
|
||||||
this._log("fileExists()", fileName, exists);
|
this._log("fileExists()", fileName, exists);
|
||||||
return exists;
|
return exists;
|
||||||
|
@ -704,19 +537,6 @@ export class DenoCompiler
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deno specific static properties and methods
|
|
||||||
|
|
||||||
/** Built in modules which can be returned to external modules
|
|
||||||
*
|
|
||||||
* Placed as a private static otherwise we get use before
|
|
||||||
* declared with the `DenoCompiler`
|
|
||||||
*/
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
private static _builtins: { [mid: string]: any } = {
|
|
||||||
typescript: ts,
|
|
||||||
deno
|
|
||||||
};
|
|
||||||
|
|
||||||
private static _instance: DenoCompiler | undefined;
|
private static _instance: DenoCompiler | undefined;
|
||||||
|
|
||||||
/** Returns the instance of `DenoCompiler` or creates a new instance. */
|
/** Returns the instance of `DenoCompiler` or creates a new instance. */
|
||||||
|
|
44
js/main.ts
44
js/main.ts
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
// We need to make sure this module loads, for its side effects.
|
import { window } from "./globals";
|
||||||
import "./globals";
|
|
||||||
|
|
||||||
import * as flatbuffers from "./flatbuffers";
|
import * as flatbuffers from "./flatbuffers";
|
||||||
import * as msg from "gen/msg_generated";
|
import * as msg from "gen/msg_generated";
|
||||||
|
@ -13,7 +12,8 @@ import { sendSync, handleAsyncMsgFromRust } from "./dispatch";
|
||||||
import { replLoop } from "./repl";
|
import { replLoop } from "./repl";
|
||||||
import { version } from "typescript";
|
import { version } from "typescript";
|
||||||
|
|
||||||
const compiler = DenoCompiler.instance();
|
// builtin modules
|
||||||
|
import * as deno from "./deno";
|
||||||
|
|
||||||
function sendStart(): msg.StartRes {
|
function sendStart(): msg.StartRes {
|
||||||
const builder = flatbuffers.createBuilder();
|
const builder = flatbuffers.createBuilder();
|
||||||
|
@ -27,10 +27,37 @@ function sendStart(): msg.StartRes {
|
||||||
return startRes;
|
return startRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { postMessage } from "./workers";
|
||||||
|
import { TextDecoder, TextEncoder } from "./text_encoding";
|
||||||
|
import { ModuleSpecifier, ContainingFile } from "./compiler";
|
||||||
|
type CompilerLookup = { specifier: ModuleSpecifier; referrer: ContainingFile };
|
||||||
|
|
||||||
|
function compilerMain() {
|
||||||
|
// workerMain should have already been called since a compiler is a worker.
|
||||||
|
const compiler = DenoCompiler.instance();
|
||||||
|
// compiler.recompile = startResMsg.recompileFlag();
|
||||||
|
window.onmessage = (e: { data: Uint8Array }) => {
|
||||||
|
const json = new TextDecoder().decode(e.data);
|
||||||
|
const lookup = JSON.parse(json) as CompilerLookup;
|
||||||
|
|
||||||
|
const moduleMetaData = compiler.run(lookup.specifier, lookup.referrer);
|
||||||
|
moduleMetaData.outputCode = compiler.compile(moduleMetaData);
|
||||||
|
|
||||||
|
const responseJson = JSON.stringify(moduleMetaData);
|
||||||
|
const response = new TextEncoder().encode(responseJson);
|
||||||
|
postMessage(response);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
window["compilerMain"] = compilerMain;
|
||||||
|
|
||||||
/* tslint:disable-next-line:no-default-export */
|
/* tslint:disable-next-line:no-default-export */
|
||||||
export default function denoMain() {
|
export default function denoMain() {
|
||||||
libdeno.recv(handleAsyncMsgFromRust);
|
libdeno.recv(handleAsyncMsgFromRust);
|
||||||
|
|
||||||
|
libdeno.builtinModules["deno"] = deno;
|
||||||
|
// libdeno.builtinModules["typescript"] = typescript;
|
||||||
|
Object.freeze(libdeno.builtinModules);
|
||||||
|
|
||||||
// First we send an empty "Start" message to let the privileged side know we
|
// First we send an empty "Start" message to let the privileged side know we
|
||||||
// are ready. The response should be a "StartRes" message containing the CLI
|
// are ready. The response should be a "StartRes" message containing the CLI
|
||||||
// args and other info.
|
// args and other info.
|
||||||
|
@ -40,6 +67,7 @@ export default function denoMain() {
|
||||||
|
|
||||||
// handle `--types`
|
// handle `--types`
|
||||||
if (startResMsg.typesFlag()) {
|
if (startResMsg.typesFlag()) {
|
||||||
|
const compiler = DenoCompiler.instance();
|
||||||
const defaultLibFileName = compiler.getDefaultLibFileName();
|
const defaultLibFileName = compiler.getDefaultLibFileName();
|
||||||
const defaultLibModule = compiler.resolveModule(defaultLibFileName, "");
|
const defaultLibModule = compiler.resolveModule(defaultLibFileName, "");
|
||||||
console.log(defaultLibModule.sourceCode);
|
console.log(defaultLibModule.sourceCode);
|
||||||
|
@ -64,13 +92,9 @@ export default function denoMain() {
|
||||||
}
|
}
|
||||||
log("args", args);
|
log("args", args);
|
||||||
Object.freeze(args);
|
Object.freeze(args);
|
||||||
|
|
||||||
const inputFn = args[0];
|
const inputFn = args[0];
|
||||||
|
if (!inputFn) {
|
||||||
compiler.recompile = startResMsg.recompileFlag();
|
|
||||||
|
|
||||||
if (inputFn) {
|
|
||||||
compiler.run(inputFn, `${cwd}/`);
|
|
||||||
} else {
|
|
||||||
replLoop();
|
replLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,6 @@ test(function btoaFailed() {
|
||||||
assertEqual(err.name, "InvalidInput");
|
assertEqual(err.name, "InvalidInput");
|
||||||
});
|
});
|
||||||
|
|
||||||
test(function textDecoder() {
|
|
||||||
// prettier-ignore
|
|
||||||
const fixture = new Uint8Array([
|
|
||||||
0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd,
|
|
||||||
0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd,
|
|
||||||
0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd
|
|
||||||
]);
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
assertEqual(decoder.decode(fixture), "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
|
||||||
});
|
|
||||||
|
|
||||||
test(function textDecoder2() {
|
test(function textDecoder2() {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const fixture = new Uint8Array([
|
const fixture = new Uint8Array([
|
||||||
|
@ -65,17 +54,6 @@ test(function textDecoderErrorEncoding() {
|
||||||
assert(didThrow);
|
assert(didThrow);
|
||||||
});
|
});
|
||||||
|
|
||||||
test(function textEncoder() {
|
|
||||||
const fixture = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
// prettier-ignore
|
|
||||||
assertEqual(Array.from(encoder.encode(fixture)), [
|
|
||||||
0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd,
|
|
||||||
0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd,
|
|
||||||
0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test(function textEncoder2() {
|
test(function textEncoder2() {
|
||||||
const fixture = "𝓽𝓮𝔁𝓽";
|
const fixture = "𝓽𝓮𝔁𝓽";
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
import "./blob_test.ts";
|
import "./blob_test.ts";
|
||||||
import "./buffer_test.ts";
|
import "./buffer_test.ts";
|
||||||
import "./chmod_test.ts";
|
import "./chmod_test.ts";
|
||||||
import "./compiler_test.ts";
|
// import "./compiler_test.ts";
|
||||||
import "./console_test.ts";
|
import "./console_test.ts";
|
||||||
import "./copy_file_test.ts";
|
import "./copy_file_test.ts";
|
||||||
import "./dir_test.ts";
|
import "./dir_test.ts";
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
import * as dispatch from "./dispatch";
|
import * as dispatch from "./dispatch";
|
||||||
import { libdeno } from "./libdeno";
|
|
||||||
import * as msg from "gen/msg_generated";
|
import * as msg from "gen/msg_generated";
|
||||||
import * as flatbuffers from "./flatbuffers";
|
import * as flatbuffers from "./flatbuffers";
|
||||||
import { assert, log } from "./util";
|
import { assert, log } from "./util";
|
||||||
|
@ -53,7 +52,6 @@ export function workerClose(): void {
|
||||||
|
|
||||||
export async function workerMain() {
|
export async function workerMain() {
|
||||||
log("workerMain");
|
log("workerMain");
|
||||||
libdeno.recv(dispatch.handleAsyncMsgFromRust);
|
|
||||||
|
|
||||||
// TODO avoid using globalEval to get Window. But circular imports if getting
|
// TODO avoid using globalEval to get Window. But circular imports if getting
|
||||||
// it from globals.ts
|
// it from globals.ts
|
||||||
|
|
156
src/compiler.rs
Normal file
156
src/compiler.rs
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
|
use isolate::Buf;
|
||||||
|
use isolate::IsolateState;
|
||||||
|
use msg;
|
||||||
|
use resources;
|
||||||
|
use resources::Resource;
|
||||||
|
use resources::ResourceId;
|
||||||
|
use workers;
|
||||||
|
|
||||||
|
use futures::Future;
|
||||||
|
use serde_json;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref c_rid: Mutex<Option<ResourceId>> = Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This corresponds to JS ModuleMetaData.
|
||||||
|
// TODO Rename one or the other so they correspond.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CodeFetchOutput {
|
||||||
|
pub module_name: String,
|
||||||
|
pub filename: String,
|
||||||
|
pub media_type: msg::MediaType,
|
||||||
|
pub source_code: String,
|
||||||
|
pub maybe_output_code: Option<String>,
|
||||||
|
pub maybe_source_map: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeFetchOutput {
|
||||||
|
pub fn js_source<'a>(&'a self) -> String {
|
||||||
|
if self.media_type == msg::MediaType::Json {
|
||||||
|
return String::from(format!("export default {};", self.source_code));
|
||||||
|
}
|
||||||
|
match self.maybe_output_code {
|
||||||
|
None => self.source_code.clone(),
|
||||||
|
Some(ref output_code) => output_code.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeFetchOutput {
|
||||||
|
// TODO Use serde_derive? Use flatbuffers?
|
||||||
|
fn from_json(json_str: &str) -> Option<Self> {
|
||||||
|
match serde_json::from_str::<serde_json::Value>(json_str) {
|
||||||
|
Ok(serde_json::Value::Object(map)) => {
|
||||||
|
let module_name = match map["moduleId"].as_str() {
|
||||||
|
None => return None,
|
||||||
|
Some(s) => s.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let filename = match map["fileName"].as_str() {
|
||||||
|
None => return None,
|
||||||
|
Some(s) => s.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let source_code = match map["sourceCode"].as_str() {
|
||||||
|
None => return None,
|
||||||
|
Some(s) => s.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let maybe_output_code =
|
||||||
|
map["outputCode"].as_str().map(|s| s.to_string());
|
||||||
|
|
||||||
|
let maybe_source_map = map["sourceMap"].as_str().map(|s| s.to_string());
|
||||||
|
|
||||||
|
Some(CodeFetchOutput {
|
||||||
|
module_name,
|
||||||
|
filename,
|
||||||
|
media_type: msg::MediaType::JavaScript, // TODO
|
||||||
|
source_code,
|
||||||
|
maybe_output_code,
|
||||||
|
maybe_source_map,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lazy_start(parent_state: &Arc<IsolateState>) -> Resource {
|
||||||
|
let mut cell = c_rid.lock().unwrap();
|
||||||
|
let rid = cell.get_or_insert_with(|| {
|
||||||
|
let resource =
|
||||||
|
workers::spawn(parent_state.clone(), "compilerMain()".to_string());
|
||||||
|
resource.rid
|
||||||
|
});
|
||||||
|
Resource { rid: *rid }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn req(specifier: &str, referrer: &str) -> Buf {
|
||||||
|
json!({
|
||||||
|
"specifier": specifier,
|
||||||
|
"referrer": referrer,
|
||||||
|
}).to_string()
|
||||||
|
.into_boxed_str()
|
||||||
|
.into_boxed_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_sync(
|
||||||
|
parent_state: &Arc<IsolateState>,
|
||||||
|
specifier: &str,
|
||||||
|
referrer: &str,
|
||||||
|
) -> Option<CodeFetchOutput> {
|
||||||
|
let req_msg = req(specifier, referrer);
|
||||||
|
|
||||||
|
let compiler = lazy_start(parent_state);
|
||||||
|
|
||||||
|
let send_future = resources::worker_post_message(compiler.rid, req_msg);
|
||||||
|
send_future.wait().unwrap();
|
||||||
|
|
||||||
|
let recv_future = resources::worker_recv_message(compiler.rid);
|
||||||
|
let res_msg = recv_future.wait().unwrap().unwrap();
|
||||||
|
|
||||||
|
let res_json = std::str::from_utf8(&res_msg).unwrap();
|
||||||
|
CodeFetchOutput::from_json(res_json)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compile_sync() {
|
||||||
|
let cwd = std::env::current_dir().unwrap();
|
||||||
|
let cwd_string = cwd.to_str().unwrap().to_owned();
|
||||||
|
|
||||||
|
let specifier = "./tests/002_hello.ts";
|
||||||
|
let referrer = cwd_string + "/";
|
||||||
|
|
||||||
|
let cfo =
|
||||||
|
compile_sync(&IsolateState::mock(), specifier, &referrer).unwrap();
|
||||||
|
let output_code = cfo.maybe_output_code.unwrap();
|
||||||
|
assert!(output_code.starts_with("console.log(\"Hello World\");"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn code_fetch_output_from_json() {
|
||||||
|
let json = r#"{
|
||||||
|
"moduleId":"/Users/rld/src/deno/tests/002_hello.ts",
|
||||||
|
"fileName":"/Users/rld/src/deno/tests/002_hello.ts",
|
||||||
|
"mediaType":1,
|
||||||
|
"sourceCode":"console.log(\"Hello World\");\n",
|
||||||
|
"outputCode":"yyy",
|
||||||
|
"sourceMap":"xxx",
|
||||||
|
"scriptVersion":"1"
|
||||||
|
}"#;
|
||||||
|
let actual = CodeFetchOutput::from_json(json).unwrap();
|
||||||
|
assert_eq!(actual.filename, "/Users/rld/src/deno/tests/002_hello.ts");
|
||||||
|
assert_eq!(actual.module_name, "/Users/rld/src/deno/tests/002_hello.ts");
|
||||||
|
assert_eq!(actual.source_code, "console.log(\"Hello World\");\n");
|
||||||
|
assert_eq!(actual.maybe_output_code, Some("yyy".to_string()));
|
||||||
|
assert_eq!(actual.maybe_source_map, Some("xxx".to_string()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
|
use compiler::CodeFetchOutput;
|
||||||
use dirs;
|
use dirs;
|
||||||
use errors;
|
use errors;
|
||||||
use errors::DenoError;
|
use errors::DenoError;
|
||||||
|
@ -19,25 +20,6 @@ use std::result::Result;
|
||||||
use url;
|
use url;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CodeFetchOutput {
|
|
||||||
pub module_name: String,
|
|
||||||
pub filename: String,
|
|
||||||
pub media_type: msg::MediaType,
|
|
||||||
pub source_code: String,
|
|
||||||
pub maybe_output_code: Option<String>,
|
|
||||||
pub maybe_source_map: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CodeFetchOutput {
|
|
||||||
pub fn js_source<'a>(&'a self) -> &'a String {
|
|
||||||
match self.maybe_output_code {
|
|
||||||
None => &self.source_code,
|
|
||||||
Some(ref output_code) => output_code,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets corresponding MediaType given extension
|
/// Gets corresponding MediaType given extension
|
||||||
fn extmap(ext: &str) -> msg::MediaType {
|
fn extmap(ext: &str) -> msg::MediaType {
|
||||||
match ext {
|
match ext {
|
||||||
|
@ -319,6 +301,10 @@ impl DenoDir {
|
||||||
|
|
||||||
out.source_code = filter_shebang(out.source_code);
|
out.source_code = filter_shebang(out.source_code);
|
||||||
|
|
||||||
|
if out.media_type != msg::MediaType::TypeScript {
|
||||||
|
return Ok(out);
|
||||||
|
}
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.load_cache(out.filename.as_str(), out.source_code.as_str());
|
self.load_cache(out.filename.as_str(), out.source_code.as_str());
|
||||||
match result {
|
match result {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
// Do not use FlatBuffers in this module.
|
// Do not use FlatBuffers in this module.
|
||||||
// TODO Currently this module uses Tokio, but it would be nice if they were
|
// TODO Currently this module uses Tokio, but it would be nice if they were
|
||||||
// decoupled.
|
// decoupled.
|
||||||
|
@ -253,13 +252,14 @@ impl Isolate {
|
||||||
|
|
||||||
/// Executes the provided JavaScript module.
|
/// Executes the provided JavaScript module.
|
||||||
pub fn execute_mod(&self, js_filename: &str) -> Result<(), JSError> {
|
pub fn execute_mod(&self, js_filename: &str) -> Result<(), JSError> {
|
||||||
let out = self.state.dir.code_fetch(js_filename, ".").unwrap();
|
let out =
|
||||||
debug!("module_resolve complete {}", out.filename);
|
code_fetch_and_maybe_compile(&self.state, js_filename, ".").unwrap();
|
||||||
|
|
||||||
let filename = CString::new(js_filename).unwrap();
|
let filename = CString::new(out.filename.clone()).unwrap();
|
||||||
let filename_ptr = filename.as_ptr() as *const i8;
|
let filename_ptr = filename.as_ptr() as *const i8;
|
||||||
|
|
||||||
let js_source = CString::new(out.js_source().clone()).unwrap();
|
let js_source = CString::new(out.js_source().clone()).unwrap();
|
||||||
|
let js_source = CString::new(js_source).unwrap();
|
||||||
let js_source_ptr = js_source.as_ptr() as *const i8;
|
let js_source_ptr = js_source.as_ptr() as *const i8;
|
||||||
|
|
||||||
let r = unsafe {
|
let r = unsafe {
|
||||||
|
@ -364,6 +364,25 @@ impl Drop for Isolate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use compiler::compile_sync;
|
||||||
|
use compiler::CodeFetchOutput;
|
||||||
|
use msg;
|
||||||
|
fn code_fetch_and_maybe_compile(
|
||||||
|
state: &Arc<IsolateState>,
|
||||||
|
specifier: &str,
|
||||||
|
referrer: &str,
|
||||||
|
) -> Result<CodeFetchOutput, DenoError> {
|
||||||
|
let mut out = state.dir.code_fetch(specifier, referrer)?;
|
||||||
|
if out.media_type == msg::MediaType::TypeScript
|
||||||
|
&& out.maybe_output_code.is_none()
|
||||||
|
{
|
||||||
|
debug!(">>>>> compile_sync START");
|
||||||
|
out = compile_sync(state, specifier, &referrer).unwrap();
|
||||||
|
debug!(">>>>> compile_sync END");
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" fn resolve_cb(
|
extern "C" fn resolve_cb(
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
specifier_ptr: *const c_char,
|
specifier_ptr: *const c_char,
|
||||||
|
@ -378,16 +397,21 @@ extern "C" fn resolve_cb(
|
||||||
debug!("module_resolve callback {} {}", specifier, referrer);
|
debug!("module_resolve callback {} {}", specifier, referrer);
|
||||||
let isolate = unsafe { Isolate::from_raw_ptr(user_data) };
|
let isolate = unsafe { Isolate::from_raw_ptr(user_data) };
|
||||||
|
|
||||||
let out = isolate.state.dir.code_fetch(specifier, referrer).unwrap();
|
let out =
|
||||||
debug!("module_resolve complete {}", out.filename);
|
code_fetch_and_maybe_compile(&isolate.state, specifier, referrer).unwrap();
|
||||||
|
|
||||||
|
let filename = CString::new(out.filename.clone()).unwrap();
|
||||||
|
let filename_ptr = filename.as_ptr() as *const i8;
|
||||||
|
|
||||||
// TODO js_source is not null terminated, therefore the clone.
|
|
||||||
let js_source = CString::new(out.js_source().clone()).unwrap();
|
let js_source = CString::new(out.js_source().clone()).unwrap();
|
||||||
let filename = out.filename.as_ptr() as *const i8;
|
|
||||||
let js_source_ptr = js_source.as_ptr() as *const i8;
|
let js_source_ptr = js_source.as_ptr() as *const i8;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
libdeno::deno_resolve_ok(isolate.libdeno_isolate, filename, js_source_ptr)
|
libdeno::deno_resolve_ok(
|
||||||
|
isolate.libdeno_isolate,
|
||||||
|
filename_ptr,
|
||||||
|
js_source_ptr,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -10,7 +10,6 @@ extern crate rand;
|
||||||
extern crate remove_dir_all;
|
extern crate remove_dir_all;
|
||||||
extern crate ring;
|
extern crate ring;
|
||||||
extern crate rustyline;
|
extern crate rustyline;
|
||||||
extern crate serde_json;
|
|
||||||
extern crate source_map_mappings;
|
extern crate source_map_mappings;
|
||||||
extern crate tempfile;
|
extern crate tempfile;
|
||||||
extern crate tokio;
|
extern crate tokio;
|
||||||
|
@ -27,7 +26,10 @@ extern crate lazy_static;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
pub mod compiler;
|
||||||
pub mod deno_dir;
|
pub mod deno_dir;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod flags;
|
pub mod flags;
|
||||||
|
@ -47,7 +49,7 @@ pub mod snapshot;
|
||||||
mod tokio_util;
|
mod tokio_util;
|
||||||
mod tokio_write;
|
mod tokio_write;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
mod workers;
|
pub mod workers;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod eager_unix;
|
mod eager_unix;
|
||||||
|
@ -100,10 +102,21 @@ fn main() {
|
||||||
let state = Arc::new(isolate::IsolateState::new(flags, rest_argv, None));
|
let state = Arc::new(isolate::IsolateState::new(flags, rest_argv, None));
|
||||||
let snapshot = snapshot::deno_snapshot();
|
let snapshot = snapshot::deno_snapshot();
|
||||||
let isolate = isolate::Isolate::new(snapshot, state, ops::dispatch);
|
let isolate = isolate::Isolate::new(snapshot, state, ops::dispatch);
|
||||||
|
|
||||||
tokio_util::init(|| {
|
tokio_util::init(|| {
|
||||||
|
// Setup runtime.
|
||||||
isolate
|
isolate
|
||||||
.execute("denoMain();")
|
.execute("denoMain();")
|
||||||
.unwrap_or_else(print_err_and_exit);
|
.unwrap_or_else(print_err_and_exit);
|
||||||
|
|
||||||
|
// Execute input file.
|
||||||
|
if isolate.state.argv.len() > 1 {
|
||||||
|
let input_filename = &isolate.state.argv[1];
|
||||||
|
isolate
|
||||||
|
.execute_mod(input_filename)
|
||||||
|
.unwrap_or_else(print_err_and_exit);
|
||||||
|
}
|
||||||
|
|
||||||
isolate.event_loop().unwrap_or_else(print_err_and_exit);
|
isolate.event_loop().unwrap_or_else(print_err_and_exit);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,13 @@ enum MediaType: byte {
|
||||||
Unknown
|
Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table Shared {
|
||||||
|
lock: bool;
|
||||||
|
head: int;
|
||||||
|
tail: int;
|
||||||
|
ring: [Base];
|
||||||
|
}
|
||||||
|
|
||||||
table Base {
|
table Base {
|
||||||
cmd_id: uint32;
|
cmd_id: uint32;
|
||||||
sync: bool = false;
|
sync: bool = false;
|
||||||
|
|
|
@ -672,7 +672,7 @@ fn op_close(
|
||||||
let rid = inner.rid();
|
let rid = inner.rid();
|
||||||
match resources::lookup(rid) {
|
match resources::lookup(rid) {
|
||||||
None => odd_future(errors::bad_resource()),
|
None => odd_future(errors::bad_resource()),
|
||||||
Some(mut resource) => {
|
Some(resource) => {
|
||||||
resource.close();
|
resource.close();
|
||||||
ok_future(empty_buf())
|
ok_future(empty_buf())
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,6 @@ pub fn table_entries() -> Vec<(u32, String)> {
|
||||||
fn test_table_entries() {
|
fn test_table_entries() {
|
||||||
let mut entries = table_entries();
|
let mut entries = table_entries();
|
||||||
entries.sort();
|
entries.sort();
|
||||||
assert_eq!(entries.len(), 3);
|
|
||||||
assert_eq!(entries[0], (0, String::from("stdin")));
|
assert_eq!(entries[0], (0, String::from("stdin")));
|
||||||
assert_eq!(entries[1], (1, String::from("stdout")));
|
assert_eq!(entries[1], (1, String::from("stdout")));
|
||||||
assert_eq!(entries[2], (2, String::from("stderr")));
|
assert_eq!(entries[2], (2, String::from("stderr")));
|
||||||
|
@ -173,7 +172,7 @@ impl Resource {
|
||||||
|
|
||||||
// close(2) is done by dropping the value. Therefore we just need to remove
|
// close(2) is done by dropping the value. Therefore we just need to remove
|
||||||
// the resource from the RESOURCE_TABLE.
|
// the resource from the RESOURCE_TABLE.
|
||||||
pub fn close(&mut self) {
|
pub fn close(&self) {
|
||||||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||||
let r = table.remove(&self.rid);
|
let r = table.remove(&self.rid);
|
||||||
assert!(r.is_some());
|
assert!(r.is_some());
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use isolate::Buf;
|
use isolate::Buf;
|
||||||
use isolate::Isolate;
|
use isolate::Isolate;
|
||||||
use isolate::IsolateState;
|
use isolate::IsolateState;
|
||||||
|
@ -53,7 +50,10 @@ impl Worker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn(state: Arc<IsolateState>, js_source: String) -> resources::Resource {
|
pub fn spawn(
|
||||||
|
state: Arc<IsolateState>,
|
||||||
|
js_source: String,
|
||||||
|
) -> resources::Resource {
|
||||||
// TODO This function should return a Future, so that the caller can retrieve
|
// TODO This function should return a Future, so that the caller can retrieve
|
||||||
// the JSError if one is thrown. Currently it just prints to stderr and calls
|
// the JSError if one is thrown. Currently it just prints to stderr and calls
|
||||||
// exit(1).
|
// exit(1).
|
||||||
|
@ -64,11 +64,12 @@ fn spawn(state: Arc<IsolateState>, js_source: String) -> resources::Resource {
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
let (worker, external_channels) = Worker::new(&state);
|
let (worker, external_channels) = Worker::new(&state);
|
||||||
|
|
||||||
let mut resource = resources::add_worker(external_channels);
|
let resource = resources::add_worker(external_channels);
|
||||||
p.send(resource.clone()).unwrap();
|
p.send(resource.clone()).unwrap();
|
||||||
|
|
||||||
tokio_util::init(|| {
|
tokio_util::init(|| {
|
||||||
(|| -> Result<(), JSError> {
|
(|| -> Result<(), JSError> {
|
||||||
|
worker.execute("denoMain()")?;
|
||||||
worker.execute("workerMain()")?;
|
worker.execute("workerMain()")?;
|
||||||
worker.execute(&js_source)?;
|
worker.execute(&js_source)?;
|
||||||
worker.event_loop()?;
|
worker.event_loop()?;
|
||||||
|
@ -142,7 +143,8 @@ mod tests {
|
||||||
|
|
||||||
// TODO Need a way to get a future for when a resource closes.
|
// TODO Need a way to get a future for when a resource closes.
|
||||||
// For now, just sleep for a bit.
|
// For now, just sleep for a bit.
|
||||||
thread::sleep(std::time::Duration::from_millis(100));
|
// resource.close();
|
||||||
|
thread::sleep(std::time::Duration::from_millis(1000));
|
||||||
assert_eq!(resources::get_type(resource.rid), None);
|
assert_eq!(resources::get_type(resource.rid), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import * as config from "./subdir/config.json";
|
import * as config from "./subdir/config.json";
|
||||||
|
// TODO Shouldn't need 'default'
|
||||||
console.log(JSON.stringify(config));
|
console.log(JSON.stringify(config["default"]));
|
||||||
|
|
|
@ -3,8 +3,4 @@ before error
|
||||||
world
|
world
|
||||||
Error: error
|
Error: error
|
||||||
at foo ([WILDCARD]tests/async_error.ts:4:9)
|
at foo ([WILDCARD]tests/async_error.ts:4:9)
|
||||||
at eval ([WILDCARD]tests/async_error.ts:7:1)
|
at [WILDCARD]tests/async_error.ts:7:1
|
||||||
at _gatherDependencies ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at run ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at denoMain ([WILDCARD]/js/main.ts:[WILDCARD])
|
|
||||||
at <anonymous>:1:1
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
[WILDCARD]Error: bad
|
[WILDCARD]Error: bad
|
||||||
at foo (file://[WILDCARD]tests/error_001.ts:2:9)
|
at foo (file://[WILDCARD]tests/error_001.ts:2:9)
|
||||||
at bar (file://[WILDCARD]tests/error_001.ts:6:3)
|
at bar (file://[WILDCARD]tests/error_001.ts:6:3)
|
||||||
at eval (file://[WILDCARD]tests/error_001.ts:9:1)
|
at file://[WILDCARD]tests/error_001.ts:9:1
|
||||||
at _gatherDependencies ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at run ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at denoMain ([WILDCARD]/js/main.ts:[WILDCARD])
|
|
||||||
at <anonymous>:1:1
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
[WILDCARD]Error: exception from mod1
|
[WILDCARD]Error: exception from mod1
|
||||||
at throwsError (file://[WILDCARD]/tests/subdir/mod1.ts:16:9)
|
at throwsError (file://[WILDCARD]/tests/subdir/mod1.ts:16:9)
|
||||||
at foo (file://[WILDCARD]/tests/error_002.ts:4:3)
|
at foo (file://[WILDCARD]/tests/error_002.ts:4:3)
|
||||||
at eval (file://[WILDCARD]/tests/error_002.ts:7:1)
|
at file://[WILDCARD]/tests/error_002.ts:7:1
|
||||||
at _drainRunQueue ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at run ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at denoMain ([WILDCARD]/js/main.ts:[WILDCARD])
|
|
||||||
at <anonymous>:1:1
|
|
||||||
|
|
|
@ -1,10 +1,2 @@
|
||||||
[96m[WILDCARD]/tests/error_008_checkjs.js[WILDCARD] - [91merror[0m[90m TS2552: [0mCannot find name 'consol'. Did you mean 'console'?
|
ReferenceError: consol is not defined
|
||||||
|
at [WILDCARD]tests/error_008_checkjs.js:2:1
|
||||||
[WILDCARD] consol.log("hello world!");
|
|
||||||
[WILDCARD]~~~~~~[0m
|
|
||||||
|
|
||||||
[96m$asset$/lib.deno_runtime.d.ts[WILDCARD]
|
|
||||||
[WILDCARD]declare const console: consoleTypes.Console;
|
|
||||||
[WILDCARD]~~~~~~~[0m
|
|
||||||
[WILDCARD]'console' is declared here.
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
args: tests/error_008_checkjs.js --reload
|
args: tests/error_008_checkjs.js --reload
|
||||||
|
check_stderr: true
|
||||||
exit_code: 1
|
exit_code: 1
|
||||||
output: tests/error_008_checkjs.js.out
|
output: tests/error_008_checkjs.js.out
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
console.log("hello!");
|
console.log("hello!");
|
||||||
export = {};
|
export default {};
|
||||||
|
|
Loading…
Reference in a new issue