summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml8
-rw-r--r--BUILD.gn35
-rw-r--r--js/assets.ts51
-rw-r--r--js/main.ts17
-rw-r--r--js/os.ts32
-rw-r--r--js/runtime.ts43
-rw-r--r--js/util.ts2
-rw-r--r--src/binding.cc12
-rw-r--r--src/handlers.h8
-rw-r--r--src/handlers.rs233
-rw-r--r--src/internal.h3
-rw-r--r--src/main.cc104
-rw-r--r--src/main.rs10
-rw-r--r--src/reply.cc120
-rw-r--r--src/reply.h29
-rw-r--r--testdata/001_hello.js1
-rw-r--r--testdata/002_hello.ts1
17 files changed, 509 insertions, 200 deletions
diff --git a/.travis.yml b/.travis.yml
index 2d978997a..1549df3f4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -47,7 +47,7 @@ script:
- ./tools/lint.py
- $BUILD_PATH/test_cc
- $BUILD_PATH/handlers_test
- - $BUILD_PATH/deno_cc foo bar
- - $BUILD_PATH/deno_cc_nosnapshot foo bar
- - $BUILD_PATH/deno meow
- - $BUILD_PATH/deno_nosnapshot meow
+ - $BUILD_PATH/deno ./testdata/001_hello.js
+ - $BUILD_PATH/deno ./testdata/002_hello.ts
+ - $BUILD_PATH/deno_nosnapshot ./testdata/001_hello.js
+ - $BUILD_PATH/deno_nosnapshot ./testdata/002_hello.ts
diff --git a/BUILD.gn b/BUILD.gn
index e77f6bd01..33cb4f7bd 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -8,8 +8,6 @@ group("all") {
testonly = true
deps = [
":deno",
- ":deno_cc",
- ":deno_cc_nosnapshot",
":deno_nosnapshot",
":handlers_test",
":test_cc",
@@ -61,35 +59,6 @@ rust_test("handlers_test") {
]
}
-executable("deno_cc") {
- sources = [
- "src/main.cc",
- ]
- deps = [
- ":flatbufferjs",
- ":handlers",
- ":libdeno",
- ":msg_cpp",
- ]
- configs += [ ":deno_config" ]
-}
-
-# This target is for fast incremental development.
-# When modifying the javascript runtime, this target will not go through the
-# extra process of building a snapshot and instead load the bundle from disk.
-executable("deno_cc_nosnapshot") {
- sources = [
- "src/main.cc",
- ]
- deps = [
- ":flatbufferjs",
- ":handlers",
- ":libdeno_nosnapshot",
- ":msg_cpp",
- ]
- configs += [ ":deno_config" ]
-}
-
executable("test_cc") {
testonly = true
sources = [
@@ -154,9 +123,12 @@ v8_source_set("deno_bindings") {
sources = [
"src/flatbuffer_builder.cc",
"src/flatbuffer_builder.h",
+ "src/reply.cc",
+ "src/reply.h",
]
deps = [
":deno_base",
+ ":handlers",
":msg_cpp",
]
public_deps = [
@@ -184,6 +156,7 @@ flatbuffer("msg_cpp") {
run_node("bundle") {
out_dir = "$target_gen_dir/bundle/"
sources = [
+ "js/assets.ts",
"js/console.ts",
"js/deno.d.ts",
"js/dispatch.ts",
diff --git a/js/assets.ts b/js/assets.ts
new file mode 100644
index 000000000..850fc6c72
--- /dev/null
+++ b/js/assets.ts
@@ -0,0 +1,51 @@
+// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
+// All rights reserved. MIT License.
+
+// This file is formatted as it is because we are using the fact that Parcel
+// statically evaluates fs.readFileSync.
+import { readFileSync } from "fs";
+
+// tslint:disable:max-line-length
+// prettier-ignore
+export const assetSourceCode: { [key: string]: string } = {
+ "deno.d.ts": readFileSync(__dirname + "/deno.d.ts", "utf8"),
+ "lib.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.d.ts", "utf8"),
+ //"lib.dom.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.dom.d.ts", "utf8"),
+ "lib.dom.iterable.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.dom.iterable.d.ts", "utf8"),
+ "lib.es2015.collection.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.collection.d.ts", "utf8"),
+ "lib.es2015.core.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.core.d.ts", "utf8"),
+ //"lib.es2015.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.d.ts", "utf8"),
+ "lib.es2015.generator.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.generator.d.ts", "utf8"),
+ "lib.es2015.iterable.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.iterable.d.ts", "utf8"),
+ "lib.es2015.promise.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.promise.d.ts", "utf8"),
+ "lib.es2015.proxy.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.proxy.d.ts", "utf8"),
+ "lib.es2015.reflect.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.reflect.d.ts", "utf8"),
+ "lib.es2015.symbol.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.symbol.d.ts", "utf8"),
+ "lib.es2015.symbol.wellknown.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts", "utf8"),
+ "lib.es2016.array.include.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2016.array.include.d.ts", "utf8"),
+ //"lib.es2016.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2016.d.ts", "utf8"),
+ //"lib.es2016.full.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2016.full.d.ts", "utf8"),
+ //"lib.es2017.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2017.d.ts", "utf8"),
+ //"lib.es2017.full.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2017.full.d.ts", "utf8"),
+ "lib.es2017.intl.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2017.intl.d.ts", "utf8"),
+ "lib.es2017.object.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2017.object.d.ts", "utf8"),
+ "lib.es2017.sharedmemory.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts", "utf8"),
+ "lib.es2017.string.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2017.string.d.ts", "utf8"),
+ "lib.es2017.typedarrays.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts", "utf8"),
+ "lib.es2018.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2018.d.ts", "utf8"),
+ //"lib.es2018.full.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2018.full.d.ts", "utf8"),
+ "lib.es2018.promise.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2018.promise.d.ts", "utf8"),
+ "lib.es2018.regexp.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es2018.regexp.d.ts", "utf8"),
+ //"lib.es5.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es5.d.ts", "utf8"),
+ //"lib.es6.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.es6.d.ts", "utf8"),
+ "lib.esnext.array.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.esnext.array.d.ts", "utf8"),
+ "lib.esnext.asynciterable.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.esnext.asynciterable.d.ts", "utf8"),
+ "lib.esnext.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.esnext.d.ts", "utf8"),
+ //"lib.esnext.full.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.esnext.full.d.ts", "utf8"),
+ //"lib.scripthost.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.scripthost.d.ts", "utf8"),
+ //"lib.webworker.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/lib.webworker.d.ts", "utf8"),
+ //"protocol.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/protocol.d.ts", "utf8"),
+ //"tsserverlibrary.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/tsserverlibrary.d.ts", "utf8"),
+ "typescript.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/typescript.d.ts", "utf8"),
+ //"typescriptServices.d.ts": readFileSync(__dirname + "/../third_party/node_modules/typescript/lib/typescriptServices.d.ts", "utf8"),
+};
diff --git a/js/main.ts b/js/main.ts
index 379b69c97..c140304ef 100644
--- a/js/main.ts
+++ b/js/main.ts
@@ -1,12 +1,9 @@
// tslint:disable-next-line:no-reference
/// <reference path="deno.d.ts" />
-import * as ts from "typescript";
-
import { flatbuffers } from "flatbuffers";
import { deno as fbs } from "./msg_generated";
-import { assert } from "./util";
-
-// import * as runtime from "./runtime";
+import { assert, log } from "./util";
+import * as runtime from "./runtime";
const globalEval = eval;
const window = globalEval("this");
@@ -31,8 +28,6 @@ function startMsg(cmdId: number): Uint8Array {
}
window["denoMain"] = () => {
- deno.print(`ts.version: ${ts.version}`);
-
// First we send an empty "Start" message to let the privlaged side know we
// are ready. The response should be a "StartRes" message containing the CLI
// argv and other info.
@@ -55,17 +50,15 @@ window["denoMain"] = () => {
assert(base.msg(startResMsg) != null);
const cwd = startResMsg.cwd();
- deno.print(`cwd: ${cwd}`);
+ log("cwd", cwd);
const argv: string[] = [];
for (let i = 0; i < startResMsg.argvLength(); i++) {
argv.push(startResMsg.argv(i));
}
- deno.print(`argv ${argv}`);
+ log("argv", argv);
- /* TODO(ry) Uncomment to test further message passing.
- const inputFn = argv[0];
+ const inputFn = argv[1];
const mod = runtime.resolveModule(inputFn, `${cwd}/`);
mod.compileAndRun();
- */
};
diff --git a/js/os.ts b/js/os.ts
index 0c8ebede9..e4263009f 100644
--- a/js/os.ts
+++ b/js/os.ts
@@ -2,7 +2,8 @@
// All rights reserved. MIT License.
import { ModuleInfo } from "./types";
import { deno as fbs } from "./msg_generated";
-import { assert, typedArrayToArrayBuffer } from "./util";
+import { assert } from "./util";
+import * as util from "./util";
import { flatbuffers } from "flatbuffers";
export function exit(exitCode = 0): void {
@@ -19,8 +20,7 @@ export function codeFetch(
moduleSpecifier: string,
containingFile: string
): ModuleInfo {
- console.log("Hello from codeFetch");
-
+ util.log("os.ts codeFetch", moduleSpecifier, containingFile);
// Send CodeFetch message
const builder = new flatbuffers.Builder();
const moduleSpecifier_ = builder.createString(moduleSpecifier);
@@ -33,23 +33,23 @@ export function codeFetch(
fbs.Base.addMsg(builder, msg);
fbs.Base.addMsgType(builder, fbs.Any.CodeFetch);
builder.finish(fbs.Base.endBase(builder));
- const payload = typedArrayToArrayBuffer(builder.asUint8Array());
- const resBuf = deno.send("x", payload);
-
- console.log("CodeFetch sent");
-
+ const resBuf = deno.send(builder.asUint8Array());
// Process CodeFetchRes
const bb = new flatbuffers.ByteBuffer(new Uint8Array(resBuf));
const baseRes = fbs.Base.getRootAsBase(bb);
+ if (fbs.Any.NONE === baseRes.msgType()) {
+ throw Error(baseRes.error());
+ }
assert(fbs.Any.CodeFetchRes === baseRes.msgType());
const codeFetchRes = new fbs.CodeFetchRes();
assert(baseRes.msg(codeFetchRes) != null);
- return {
+ const r = {
moduleName: codeFetchRes.moduleName(),
filename: codeFetchRes.filename(),
sourceCode: codeFetchRes.sourceCode(),
outputCode: codeFetchRes.outputCode()
};
+ return r;
}
export function codeCache(
@@ -57,28 +57,22 @@ export function codeCache(
sourceCode: string,
outputCode: string
): void {
+ util.log("os.ts codeCache", filename, sourceCode, outputCode);
const builder = new flatbuffers.Builder();
-
const filename_ = builder.createString(filename);
const sourceCode_ = builder.createString(sourceCode);
const outputCode_ = builder.createString(outputCode);
-
fbs.CodeCache.startCodeCache(builder);
fbs.CodeCache.addFilename(builder, filename_);
fbs.CodeCache.addSourceCode(builder, sourceCode_);
fbs.CodeCache.addOutputCode(builder, outputCode_);
const msg = fbs.CodeCache.endCodeCache(builder);
-
fbs.Base.startBase(builder);
fbs.Base.addMsg(builder, msg);
+ fbs.Base.addMsgType(builder, fbs.Any.CodeCache);
builder.finish(fbs.Base.endBase(builder));
-
- // Maybe need to do another step?
- // Base.finishBaseBuffer(builder, base);
-
- const payload = typedArrayToArrayBuffer(builder.asUint8Array());
- const resBuf = deno.send("x", payload);
- assert(resBuf === null);
+ const resBuf = deno.send(builder.asUint8Array());
+ assert(resBuf == null);
}
export function readFileSync(filename: string): Uint8Array {
diff --git a/js/runtime.ts b/js/runtime.ts
index 9570dda1c..d234cdd85 100644
--- a/js/runtime.ts
+++ b/js/runtime.ts
@@ -11,6 +11,7 @@
import * as ts from "typescript";
import * as util from "./util";
import { log } from "./util";
+import { assetSourceCode } from "./assets";
import * as os from "./os";
//import * as sourceMaps from "./v8_source_maps";
import { window, globalEval } from "./globals";
@@ -22,9 +23,14 @@ const EOL = "\n";
export type AmdFactory = (...args: any[]) => undefined | object;
export type AmdDefine = (deps: string[], factory: AmdFactory) => void;
-/*
// Uncaught exceptions are sent to window.onerror by the privlaged binding.
-window.onerror = (message, source, lineno, colno, error) => {
+window.onerror = (
+ message: string,
+ source: string,
+ lineno: number,
+ colno: number,
+ error: Error
+) => {
// TODO Currently there is a bug in v8_source_maps.ts that causes a segfault
// if it is used within window.onerror. To workaround we uninstall the
// Error.prepareStackTrace handler. Users will get unmapped stack traces on
@@ -33,7 +39,6 @@ window.onerror = (message, source, lineno, colno, error) => {
console.log(error.message, error.stack);
os.exit(1);
};
-*/
/*
export function setup(mainJs: string, mainMap: string): void {
@@ -147,11 +152,31 @@ export function resolveModule(
): null | FileModule {
util.log("resolveModule", { moduleSpecifier, containingFile });
util.assert(moduleSpecifier != null && moduleSpecifier.length > 0);
- // We ask golang to sourceCodeFetch. It will load the sourceCode and if
- // there is any outputCode cached, it will return that as well.
- const fetchResponse = os.codeFetch(moduleSpecifier, containingFile);
- const { filename, sourceCode, outputCode } = fetchResponse;
- if (sourceCode.length === 0) {
+ let filename: string, sourceCode: string, outputCode: string;
+ if (
+ moduleSpecifier.startsWith("/$asset$/") ||
+ containingFile.startsWith("/$asset$/")
+ ) {
+ // Assets are compiled into the runtime javascript bundle.
+ const assetName = moduleSpecifier.split("/").pop();
+ sourceCode = assetSourceCode[assetName];
+ filename = "/$asset$/" + assetName;
+ } else {
+ // We query Rust with a CodeFetch message. It will load the sourceCode, and
+ // if there is any outputCode cached, will return that as well.
+ let fetchResponse;
+ try {
+ fetchResponse = os.codeFetch(moduleSpecifier, containingFile);
+ } catch (e) {
+ // TODO Only catch "no such file or directory" errors. Need error codes.
+ util.log("os.codeFetch error ignored", e.message);
+ return null;
+ }
+ filename = fetchResponse.filename;
+ sourceCode = fetchResponse.sourceCode;
+ outputCode = fetchResponse.outputCode;
+ }
+ if (sourceCode == null || sourceCode.length === 0) {
return null;
}
util.log("resolveModule sourceCode length ", sourceCode.length);
@@ -293,7 +318,7 @@ class TypeScriptHost implements ts.LanguageServiceHost {
}
getDefaultLibFileName(options: ts.CompilerOptions): string {
- const fn = ts.getDefaultLibFileName(options);
+ const fn = "lib.d.ts"; // ts.getDefaultLibFileName(options);
util.log("getDefaultLibFileName", fn);
const m = resolveModule(fn, "/$asset$/");
return m.fileName;
diff --git a/js/util.ts b/js/util.ts
index 9f87ab63d..7216f9491 100644
--- a/js/util.ts
+++ b/js/util.ts
@@ -2,7 +2,7 @@
// All rights reserved. MIT License.
//import { debug } from "./main";
-const debug = true;
+const debug = false;
import { TypedArray } from "./types";
diff --git a/src/binding.cc b/src/binding.cc
index 2c4b6f722..2067f1023 100644
--- a/src/binding.cc
+++ b/src/binding.cc
@@ -301,8 +301,20 @@ void deno_init() {
const char* deno_v8_version() { return v8::V8::GetVersion(); }
+// TODO(ry) Remove these when we call deno_reply_start from Rust.
+static char** global_argv;
+static int global_argc;
+char** deno_argv() { return global_argv; }
+int deno_argc() { return global_argc; }
+
void deno_set_flags(int* argc, char** argv) {
v8::V8::SetFlagsFromCommandLine(argc, argv, true);
+ // TODO(ry) Remove these when we call deno_reply_start from Rust.
+ global_argc = *argc;
+ global_argv = reinterpret_cast<char**>(malloc(*argc * sizeof(char*)));
+ for (int i = 0; i < *argc; i++) {
+ global_argv[i] = strdup(argv[i]);
+ }
}
const char* deno_last_exception(Deno* d) { return d->last_exception.c_str(); }
diff --git a/src/handlers.h b/src/handlers.h
index b398eca61..a95bc7265 100644
--- a/src/handlers.h
+++ b/src/handlers.h
@@ -2,10 +2,12 @@
// All rights reserved. MIT License.
#ifndef HANDLERS_H_
#define HANDLERS_H_
-extern "C" {
+
#include <stdint.h>
+#include "deno.h"
-void handle_code_fetch(uint32_t cmd_id, const char* module_specifier,
+extern "C" {
+void handle_code_fetch(Deno* d, uint32_t cmd_id, const char* module_specifier,
const char* containing_file);
-}
+} // extern "C"
#endif // HANDLERS_H_
diff --git a/src/handlers.rs b/src/handlers.rs
index 5e386df31..4c4a791ea 100644
--- a/src/handlers.rs
+++ b/src/handlers.rs
@@ -1,36 +1,247 @@
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
// All rights reserved. MIT License.
extern crate libc;
+#[macro_use]
+extern crate log;
extern crate url;
use libc::c_char;
+use libc::uint32_t;
use std::ffi::CStr;
+use std::ffi::CString;
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
use url::Url;
-fn string_from_ptr(ptr: *const c_char) -> String {
- let cstr = unsafe { CStr::from_ptr(ptr as *const i8) };
- String::from(cstr.to_str().unwrap())
+// TODO(ry) Share this with the def in src/main.rs.
+#[repr(C)]
+pub struct DenoC {
+ _unused: [u8; 0],
+}
+
+// TODO(ry) Share this extern block with those in main.rs.
+// See src/reply.h
+extern "C" {
+ pub fn deno_reply_error(d: *const DenoC, cmd_id: uint32_t, msg: *const c_char);
+ pub fn deno_reply_null(d: *const DenoC, cmd_id: uint32_t);
+ pub fn deno_reply_code_fetch(
+ d: *const DenoC,
+ cmd_id: uint32_t,
+ module_name: *const c_char,
+ filename: *const c_char,
+ source_code: *const c_char,
+ output_code: *const c_char,
+ );
}
+// TODO(ry) SRC_DIR is just a placeholder for future caching functionality.
+static SRC_DIR: &str = "/Users/rld/.deno/src/";
+const ASSET_PREFIX: &str = "/$asset$/";
+
#[test]
fn test_url() {
let issue_list_url = Url::parse("https://github.com/rust-lang").unwrap();
assert!(issue_list_url.scheme() == "https");
}
+fn string_from_ptr(ptr: *const c_char) -> String {
+ let cstr = unsafe { CStr::from_ptr(ptr as *const i8) };
+ String::from(cstr.to_str().unwrap())
+}
+
+fn as_cstring(s: &String) -> CString {
+ CString::new(s.as_str()).unwrap()
+}
+
+// Prototype: https://github.com/ry/deno/blob/golang/os.go#L56-L68
+#[allow(dead_code)]
+fn src_file_to_url<P: AsRef<Path>>(filename: P) -> String {
+ assert!(SRC_DIR.len() > 0, "SRC_DIR shouldn't be empty");
+
+ let filename = filename.as_ref().to_path_buf();
+ let src = (SRC_DIR.as_ref() as &Path).to_path_buf();
+
+ if filename.starts_with(&src) {
+ let rest = filename.strip_prefix(&src).unwrap();
+ "http://".to_string() + rest.to_str().unwrap()
+ } else {
+ String::from(filename.to_str().unwrap())
+ }
+}
+
+#[test]
+fn test_src_file_to_url() {
+ assert_eq!("hello", src_file_to_url("hello"));
+ assert_eq!("/hello", src_file_to_url("/hello"));
+ let x = SRC_DIR.to_string() + "hello";
+ assert_eq!("http://hello", src_file_to_url(&x));
+ let x = SRC_DIR.to_string() + "/hello";
+ assert_eq!("http://hello", src_file_to_url(&x));
+}
+
+// Prototype: https://github.com/ry/deno/blob/golang/os.go#L70-L98
+// Returns (module name, local filename)
+fn resolve_module(
+ module_specifier: &String,
+ containing_file: &String,
+) -> Result<(String, String), url::ParseError> {
+ info!(
+ "resolve_module before module_specifier {} containing_file {}",
+ module_specifier, containing_file
+ );
+
+ //let module_specifier = src_file_to_url(module_specifier);
+ //let containing_file = src_file_to_url(containing_file);
+ //let base_url = Url::parse(&containing_file)?;
+
+ let j: Url = if containing_file.as_str().ends_with("/") {
+ let base = Url::from_directory_path(&containing_file).unwrap();
+ base.join(module_specifier)?
+ } else if containing_file == "." {
+ Url::from_file_path(module_specifier).unwrap()
+ } else {
+ let base = Url::from_file_path(&containing_file).unwrap();
+ base.join(module_specifier)?
+ };
+
+ let p = j.to_file_path()
+ .unwrap()
+ .into_os_string()
+ .into_string()
+ .unwrap();
+
+ let module_name = p.to_string();
+ let filename = p.to_string();
+
+ Ok((module_name, filename))
+}
+
+// https://github.com/ry/deno/blob/golang/os_test.go#L16-L87
+#[test]
+fn test_resolve_module() {
+ let test_cases = [
+ (
+ "./subdir/print_hello.ts",
+ "/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts",
+ "/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts",
+ "/Users/rld/go/src/github.com/ry/deno/testdata/subdir/print_hello.ts",
+ ),
+ (
+ "testdata/001_hello.js",
+ "/Users/rld/go/src/github.com/ry/deno/",
+ "/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js",
+ "/Users/rld/go/src/github.com/ry/deno/testdata/001_hello.js",
+ ),
+ (
+ "/Users/rld/src/deno/hello.js",
+ ".",
+ "/Users/rld/src/deno/hello.js",
+ "/Users/rld/src/deno/hello.js",
+ ),
+ /*
+ (
+ "http://localhost:4545/testdata/subdir/print_hello.ts",
+ "/Users/rld/go/src/github.com/ry/deno/testdata/006_url_imports.ts",
+ "http://localhost:4545/testdata/subdir/print_hello.ts",
+ path.Join(SrcDir, "localhost:4545/testdata/subdir/print_hello.ts"),
+ ),
+ (
+ path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"),
+ ".",
+ "http://unpkg.com/liltest@0.0.5/index.ts",
+ path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"),
+ ),
+ (
+ "./util",
+ path.Join(SrcDir, "unpkg.com/liltest@0.0.5/index.ts"),
+ "http://unpkg.com/liltest@0.0.5/util",
+ path.Join(SrcDir, "unpkg.com/liltest@0.0.5/util"),
+ ),
+ */
+ ];
+ for &test in test_cases.iter() {
+ let module_specifier = String::from(test.0);
+ let containing_file = String::from(test.1);
+ let (module_name, filename) = resolve_module(&module_specifier, &containing_file).unwrap();
+ assert_eq!(module_name, test.2);
+ assert_eq!(filename, test.3);
+ }
+}
+
+// https://github.com/ry/deno/blob/golang/os.go#L100-L154
#[no_mangle]
pub extern "C" fn handle_code_fetch(
+ d: *const DenoC,
cmd_id: u32,
- module_specifier: *const c_char,
- containing_file: *const c_char,
+ module_specifier_: *const c_char,
+ containing_file_: *const c_char,
) {
- let module_specifier = string_from_ptr(module_specifier);
- let containing_file = string_from_ptr(containing_file);
+ // TODO(ry) Move this to main.
+ log::set_max_level(log::LevelFilter::Debug);
+
+ let module_specifier = string_from_ptr(module_specifier_);
+ let containing_file = string_from_ptr(containing_file_);
+
+ let result = resolve_module(&module_specifier, &containing_file);
+ if result.is_err() {
+ let err = result.unwrap_err();
+ let errmsg = format!("{} {} {}", err, module_specifier, containing_file);
+ let errmsg_c = as_cstring(&errmsg);
+ unsafe { deno_reply_error(d, cmd_id, errmsg_c.as_ptr()) };
+ return;
+ }
+ let (module_name, filename) = result.unwrap();
+
+ let mut source_code = String::new();
- println!(
- "handle_code_fetch. cmd_id = {} module_specifier = {} containing_file = {}",
- cmd_id, module_specifier, containing_file
+ debug!(
+ "code_fetch. module_name = {} module_specifier = {} containing_file = {} filename = {}",
+ module_name, module_specifier, containing_file, filename
);
- unimplemented!();
+ if is_remote(&module_name) {
+ unimplemented!();
+ } else if module_name.starts_with(ASSET_PREFIX) {
+ assert!(false, "Asset resolution should be done in JS, not Rust.");
+ } else {
+ assert!(
+ module_name == filename,
+ "if a module isn't remote, it should have the same filename"
+ );
+ let result = File::open(&filename);
+ if result.is_err() {
+ let err = result.unwrap_err();
+ let errmsg = format!("{} {}", err, filename);
+ let errmsg_c = as_cstring(&errmsg);
+ unsafe { deno_reply_error(d, cmd_id, errmsg_c.as_ptr()) };
+ return;
+ }
+ let mut f = result.unwrap();
+ let result = f.read_to_string(&mut source_code);
+ if result.is_err() {
+ let err = result.unwrap_err();
+ let errmsg = format!("{} {}", err, filename);
+ let errmsg_c = as_cstring(&errmsg);
+ unsafe { deno_reply_error(d, cmd_id, errmsg_c.as_ptr()) };
+ return;
+ }
+ }
+
+ let output_code = String::new(); //load_output_code_cache(filename, source_code);
+
+ unsafe {
+ deno_reply_code_fetch(
+ d,
+ cmd_id,
+ as_cstring(&module_name).as_ptr(),
+ as_cstring(&filename).as_ptr(),
+ as_cstring(&source_code).as_ptr(),
+ as_cstring(&output_code).as_ptr(),
+ )
+ }
+}
+
+fn is_remote(_module_name: &String) -> bool {
+ false
}
diff --git a/src/internal.h b/src/internal.h
index 0ec0ea416..914079d9a 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -18,6 +18,9 @@ struct deno_s {
deno_recv_cb cb;
void* data;
};
+// TODO(ry) Remove these when we call deno_reply_start from Rust.
+char** deno_argv();
+int deno_argc();
}
namespace deno {
diff --git a/src/main.cc b/src/main.cc
deleted file mode 100644
index 81b8a2710..000000000
--- a/src/main.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
-// All rights reserved. MIT License.
-#include <stdio.h>
-#include <stdlib.h>
-#include <string>
-
-#ifdef _WIN32
-#include <direct.h>
-#else
-#include <unistd.h>
-#endif
-
-#include "deno.h"
-#include "flatbuffer_builder.h"
-#include "flatbuffers/flatbuffers.h"
-#include "src/handlers.h"
-#include "src/msg_generated.h"
-#include "third_party/v8/src/base/logging.h"
-
-namespace deno {
-
-static char** global_argv;
-static int global_argc;
-
-// Sends StartRes message
-void HandleStart(Deno* d, uint32_t cmd_id) {
- deno::FlatBufferBuilder builder;
-
- char cwdbuf[1024];
- // TODO(piscisaureus): support unicode on windows.
- getcwd(cwdbuf, sizeof(cwdbuf));
- auto start_cwd = builder.CreateString(cwdbuf);
-
- std::vector<flatbuffers::Offset<flatbuffers::String>> args;
- for (int i = 0; i < global_argc; ++i) {
- args.push_back(builder.CreateString(global_argv[i]));
- }
-
- auto start_argv = builder.CreateVector(args);
- auto start_msg = CreateStartRes(builder, start_cwd, start_argv);
- auto base = CreateBase(builder, cmd_id, 0, Any_StartRes, start_msg.Union());
- builder.Finish(base);
- deno_set_response(d, builder.ExportBuf());
-}
-
-void HandleCodeFetch(Deno* d, uint32_t cmd_id, const CodeFetch* msg) {
- auto module_specifier = msg->module_specifier()->c_str();
- auto containing_file = msg->containing_file()->c_str();
- printf("HandleCodeFetch module_specifier = %s containing_file = %s\n",
- module_specifier, containing_file);
- // Call into rust.
- handle_code_fetch(cmd_id, module_specifier, containing_file);
-}
-
-void MessagesFromJS(Deno* d, deno_buf buf) {
- flatbuffers::Verifier verifier(buf.data_ptr, buf.data_len);
- DCHECK(verifier.VerifyBuffer<Base>());
-
- auto base = flatbuffers::GetRoot<Base>(buf.data_ptr);
- auto cmd_id = base->cmdId();
- auto msg_type = base->msg_type();
- const char* msg_type_name = EnumNamesAny()[msg_type];
- printf("MessagesFromJS cmd_id = %d, msg_type = %d, msg_type_name = %s\n",
- cmd_id, msg_type, msg_type_name);
- switch (msg_type) {
- case Any_Start:
- HandleStart(d, base->cmdId());
- break;
-
- case Any_CodeFetch:
- HandleCodeFetch(d, base->cmdId(), base->msg_as_CodeFetch());
- break;
-
- case Any_NONE:
- CHECK(false && "Got message with msg_type == Any_NONE");
- break;
-
- default:
- printf("Unhandled message %s\n", msg_type_name);
- CHECK(false && "Unhandled message");
- break;
- }
-}
-
-int deno_main(int argc, char** argv) {
- deno_init();
-
- deno_set_flags(&argc, argv);
- global_argv = argv;
- global_argc = argc;
-
- Deno* d = deno_new(NULL, MessagesFromJS);
- bool r = deno_execute(d, "deno_main.js", "denoMain();");
- if (!r) {
- printf("%s\n", deno_last_exception(d));
- exit(1);
- }
- deno_delete(d);
- return 0;
-}
-
-} // namespace deno
-
-int main(int argc, char** argv) { return deno::deno_main(argc, argv); }
diff --git a/src/main.rs b/src/main.rs
index 030859d5e..10b1aef81 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,7 +20,7 @@ struct DenoC {
_unused: [u8; 0],
}
-type DenoRecvCb = extern "C" fn(d: *const DenoC, buf: deno_buf);
+type DenoRecvCb = unsafe extern "C" fn(d: *const DenoC, buf: deno_buf);
#[link(name = "deno", kind = "static")]
extern "C" {
@@ -36,6 +36,8 @@ extern "C" {
fn deno_set_response(d: *const DenoC, buf: deno_buf);
fn deno_execute(d: *const DenoC, js_filename: *const c_char, js_source: *const c_char)
-> c_int;
+
+ fn deno_handle_msg_from_js(d: *const DenoC, buf: deno_buf);
}
// Pass the command line arguments to v8.
@@ -73,10 +75,6 @@ fn set_flags() -> Vec<String> {
.collect::<Vec<_>>()
}
-extern "C" fn on_message(_d: *const DenoC, _buf: deno_buf) {
- println!("got message in rust");
-}
-
type DenoException<'a> = &'a str;
struct Deno {
@@ -85,7 +83,7 @@ struct Deno {
impl Deno {
fn new() -> Deno {
- let ptr = unsafe { deno_new(ptr::null(), on_message) };
+ let ptr = unsafe { deno_new(ptr::null(), deno_handle_msg_from_js) };
Deno { ptr: ptr }
}
diff --git a/src/reply.cc b/src/reply.cc
new file mode 100644
index 000000000..7043292fd
--- /dev/null
+++ b/src/reply.cc
@@ -0,0 +1,120 @@
+// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
+// All rights reserved. MIT License.
+
+// When Rust Flatbuffer support is complete this file should be ported
+// to Rust and removed: https://github.com/google/flatbuffers/pull/3894
+#include <vector>
+// getcwd
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "flatbuffers/flatbuffers.h"
+#include "src/deno.h"
+#include "src/flatbuffer_builder.h"
+#include "src/handlers.h"
+#include "src/internal.h"
+#include "src/msg_generated.h"
+#include "src/reply.h"
+#include "third_party/v8/src/base/logging.h"
+
+extern "C" {
+
+void deno_reply_error(Deno* d, uint32_t cmd_id, const char* error_msg) {
+ // printf("deno_reply_error: %s\n", error_msg);
+ deno::FlatBufferBuilder builder;
+ auto error_msg_ = error_msg ? builder.CreateString(error_msg) : 0;
+ auto base = deno::CreateBase(builder, cmd_id, error_msg_);
+ builder.Finish(base);
+ deno_set_response(d, builder.ExportBuf());
+}
+
+void deno_reply_null(Deno* d, uint32_t cmd_id) {
+ deno_reply_error(d, cmd_id, nullptr);
+}
+
+void deno_reply_code_fetch(Deno* d, uint32_t cmd_id, const char* module_name,
+ const char* filename, const char* source_code,
+ const char* output_code) {
+ deno::FlatBufferBuilder builder;
+ auto module_name_ = builder.CreateString(module_name);
+ auto filename_ = builder.CreateString(filename);
+ auto source_code_ = builder.CreateString(source_code);
+ auto output_code_ = builder.CreateString(output_code);
+ auto code_fetch_res = deno::CreateCodeFetchRes(
+ builder, module_name_, filename_, source_code_, output_code_);
+ auto base = deno::CreateBase(builder, cmd_id, 0, deno::Any_CodeFetchRes,
+ code_fetch_res.Union());
+ builder.Finish(base);
+ deno_set_response(d, builder.ExportBuf());
+}
+
+void deno_reply_start(Deno* d, uint32_t cmd_id, int argc, char* argv[],
+ char* cwd) {
+ deno::FlatBufferBuilder builder;
+ auto start_cwd = builder.CreateString(cwd);
+ std::vector<flatbuffers::Offset<flatbuffers::String>> args;
+ for (int i = 0; i < argc; ++i) {
+ args.push_back(builder.CreateString(argv[i]));
+ }
+ auto start_argv = builder.CreateVector(args);
+ auto start_msg = deno::CreateStartRes(builder, start_cwd, start_argv);
+ auto base = deno::CreateBase(builder, cmd_id, 0, deno::Any_StartRes,
+ start_msg.Union());
+ builder.Finish(base);
+ deno_set_response(d, builder.ExportBuf());
+}
+
+void deno_handle_msg_from_js(Deno* d, deno_buf buf) {
+ flatbuffers::Verifier verifier(buf.data_ptr, buf.data_len);
+ DCHECK(verifier.VerifyBuffer<deno::Base>());
+
+ auto base = flatbuffers::GetRoot<deno::Base>(buf.data_ptr);
+ auto cmd_id = base->cmdId();
+ auto msg_type = base->msg_type();
+ const char* msg_type_name = deno::EnumNamesAny()[msg_type];
+ switch (msg_type) {
+ case deno::Any_Start: {
+ char cwdbuf[1024];
+ // TODO(piscisaureus): support unicode on windows.
+ getcwd(cwdbuf, sizeof(cwdbuf));
+ deno_reply_start(d, cmd_id, deno_argc(), deno_argv(), cwdbuf);
+ break;
+ }
+
+ case deno::Any_CodeFetch: {
+ auto msg = base->msg_as_CodeFetch();
+ auto module_specifier = msg->module_specifier()->c_str();
+ auto containing_file = msg->containing_file()->c_str();
+ handle_code_fetch(d, cmd_id, module_specifier, containing_file);
+ break;
+ }
+
+ case deno::Any_CodeCache: {
+ // TODO(ry) Call into rust.
+ /*
+ auto filename = msg->filename()->c_str();
+ auto source_code = msg->source_code()->c_str();
+ auto output_code = msg->output_code()->c_str();
+ printf(
+ "HandleCodeCache (not implemeneted) filename %s source_code %s "
+ "output_code %s\n",
+ filename, source_code, output_code);
+ */
+ break;
+ }
+
+ case deno::Any_NONE:
+ CHECK(false && "Got message with msg_type == Any_NONE");
+ break;
+
+ default:
+ printf("Unhandled message %s\n", msg_type_name);
+ CHECK(false && "Unhandled message");
+ break;
+ }
+}
+
+} // extern "C"
diff --git a/src/reply.h b/src/reply.h
new file mode 100644
index 000000000..aa2e61f8c
--- /dev/null
+++ b/src/reply.h
@@ -0,0 +1,29 @@
+// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
+// All rights reserved. MIT License.
+
+// TODO(ry) This library handles parsing and sending Flatbuffers. It's written
+// in C++ because flatbuffer support for Rust is not quite there. However, once
+// flatbuffers are supported in Rust, all of this code should be ported back to
+// Rust.
+
+#ifndef REPLY_H_
+#define REPLY_H_
+
+#include <stdint.h>
+#include "deno.h"
+
+extern "C" {
+
+void deno_reply_null(Deno* d, uint32_t cmd_id);
+void deno_reply_error(Deno* d, uint32_t cmd_id, const char* error_msg);
+
+void deno_reply_start(Deno* d, uint32_t cmd_id, int argc, char* argv[],
+ char* cwd);
+void deno_reply_code_fetch(Deno* d, uint32_t cmd_id, const char* module_name,
+ const char* filename, const char* source_code,
+ const char* output_code);
+
+// Parse incoming messages with C++ Flatbuffers, call into rust handlers.
+void deno_handle_msg_from_js(Deno* d, deno_buf buf);
+}
+#endif // REPLY_H_
diff --git a/testdata/001_hello.js b/testdata/001_hello.js
new file mode 100644
index 000000000..accefceba
--- /dev/null
+++ b/testdata/001_hello.js
@@ -0,0 +1 @@
+console.log("Hello World");
diff --git a/testdata/002_hello.ts b/testdata/002_hello.ts
new file mode 100644
index 000000000..accefceba
--- /dev/null
+++ b/testdata/002_hello.ts
@@ -0,0 +1 @@
+console.log("Hello World");