Remove wasm target from langserver

This commit is contained in:
Tad Hardesty 2019-11-10 17:47:00 -08:00
parent b1fd93f5c5
commit 174e7c0c50
6 changed files with 69 additions and 140 deletions

View file

@ -8,7 +8,7 @@ use dm::ast::PathOp;
use dm::annotation::Annotation;
use dm::objtree::{TypeRef, TypeVar, TypeProc, ProcValue};
use {Engine, Span, io, is_constructor_name, ignore_root};
use {Engine, Span, is_constructor_name, ignore_root};
use symbol_search::contains;
pub fn item_var(ty: TypeRef, name: &str, var: &TypeVar) -> CompletionItem {
@ -126,7 +126,7 @@ pub fn combine_tree_path<'a, I>(iter: &I, mut absolute: bool, mut parts: &'a [St
prefix_parts.iter().chain(parts).map(|x| &**x)
}
impl<'a, W: io::ResponseWrite> Engine<'a, W> {
impl<'a> Engine<'a> {
pub fn follow_type_path<'b, I>(&'b self, iter: &I, mut parts: &'b [(PathOp, String)]) -> Option<TypePathResult<'b>>
where
I: Iterator<Item = (Span, &'a Annotation)> + Clone,

View file

@ -1,15 +1,59 @@
//! Pluggable backends for input/output handling.
//! I/O backend for standard targets.
//!
//! JSON-RPC over stdin/stdout with Content-Length headers.
pub trait RequestRead {
fn read(&self) -> Option<String>;
use std::io::{self, Read, Write};
pub fn run_forever<F: FnMut(&str)>(mut f: F) -> ! {
loop {
let message = read().expect("request bad read");
f(&message);
}
}
pub trait ResponseWrite {
fn write(&self, output: String);
fn read() -> Option<String> {
macro_rules! check {
($exp:expr) => {
match $exp {
Ok(x) => x,
Err(e) => {
eprintln!("{:?}", e);
return None;
}
}
};
}
// read the content-length
let mut buffer = String::new();
check!(io::stdin().read_line(&mut buffer));
if buffer.is_empty() {
return None;
}
let size = {
let parts: Vec<&str> = buffer.split(' ').collect();
if parts.len() != 2 {
return None;
}
if !parts[0].eq_ignore_ascii_case("content-length:") {
return None;
}
check!(usize::from_str_radix(parts[1].trim(), 10))
};
// skip blank line
buffer.clear();
check!(io::stdin().read_line(&mut buffer));
// read content
let mut content = vec![0; size];
check!(io::stdin().read_exact(&mut content));
Some(check!(String::from_utf8(content)))
}
#[cfg_attr(target_arch="wasm32", path="wasm.rs")]
#[cfg_attr(not(target_arch="wasm32"), path="stdio.rs")]
mod system;
pub use self::system::*;
pub fn write(output: String) {
let stdout = io::stdout();
let mut stdout_lock = stdout.lock();
write!(stdout_lock, "Content-Length: {}\r\n\r\n{}", output.len(), output).unwrap();
stdout_lock.flush().unwrap();
}

View file

@ -1,70 +0,0 @@
//! I/O backend for standard targets.
//!
//! JSON-RPC over stdin/stdout with Content-Length headers.
use Engine;
use io::{RequestRead, ResponseWrite};
use std::io::{self, Read, Write};
pub fn io_main() {
let stdio = StdIo;
let context = Default::default();
let mut engine = Engine::new(&stdio, &context);
loop {
let message = stdio.read().expect("request bad read");
engine.handle_input(&message);
}
}
struct StdIo;
impl RequestRead for StdIo {
fn read(&self) -> Option<String> {
macro_rules! check {
($exp:expr) => {
match $exp {
Ok(x) => x,
Err(e) => {
eprintln!("{:?}", e);
return None;
}
}
};
}
// read the content-length
let mut buffer = String::new();
check!(io::stdin().read_line(&mut buffer));
if buffer.is_empty() {
return None;
}
let size = {
let parts: Vec<&str> = buffer.split(' ').collect();
if parts.len() != 2 {
return None;
}
if !parts[0].eq_ignore_ascii_case("content-length:") {
return None;
}
check!(usize::from_str_radix(parts[1].trim(), 10))
};
// skip blank line
buffer.clear();
check!(io::stdin().read_line(&mut buffer));
// read content
let mut content = vec![0; size];
check!(io::stdin().read_exact(&mut content));
Some(check!(String::from_utf8(content)))
}
}
impl ResponseWrite for StdIo {
fn write(&self, output: String) {
let stdout = io::stdout();
let mut stdout_lock = stdout.lock();
write!(stdout_lock, "Content-Length: {}\r\n\r\n{}", output.len(), output).unwrap();
stdout_lock.flush().unwrap();
}
}

View file

@ -1,44 +0,0 @@
//! I/O backend for WebAssembly target.
//!
//! `main()` creates an engine that will respond to calls to `handle_input()`,
//! which will then call `handle_output()` with output messages.
#![allow(unsafe_code)]
use Engine;
use super::ResponseWrite;
pub fn io_main() {
let wasmio = Box::leak(Box::new(WasmIo));
let context = Box::leak(Box::new(Default::default()));
let engine = Box::new(Engine::new(wasmio, context));
unsafe {
ENGINE_PTR = Box::into_raw(engine);
return_into_js();
}
}
static mut ENGINE_PTR: *mut Engine<WasmIo> = 0 as *mut Engine<WasmIo>;
#[no_mangle]
pub unsafe extern fn handle_input(ptr: *const u8, len: usize) {
assert!(!ENGINE_PTR.is_null());
let engine = &mut *ENGINE_PTR;
let slice = std::slice::from_raw_parts(ptr, len);
let text = std::str::from_utf8(slice).expect("input is not utf-8");
engine.handle_input(text);
}
struct WasmIo;
impl ResponseWrite for WasmIo {
fn write(&self, output: String) {
unsafe {
handle_output(output.as_ptr(), output.len());
}
}
}
extern {
fn handle_output(ptr: *const u8, len: usize);
fn return_into_js() -> !;
}

View file

@ -7,7 +7,7 @@ pub mod all_notifications {
macro_rules! handle_method_call {
($(on $what:ident(&mut $self:ident, $p:pat) $b:block)*) => {
impl<'a, W: io::ResponseWrite> Engine<'a, W> {
impl<'a> Engine<'a> {
fn handle_method_call(&mut self, call: jsonrpc::MethodCall) -> Result<serde_json::Value, jsonrpc::Error> {
use langserver::request::*;
@ -57,7 +57,7 @@ macro_rules! handle_method_call {
macro_rules! handle_notification {
($(on $what:ident(&mut $self:ident, $p:pat) $b:block)*) => {
impl<'a, W: io::ResponseWrite> Engine<'a, W> {
impl<'a> Engine<'a> {
fn handle_notification(&mut self, notification: jsonrpc::Notification) -> Result<(), jsonrpc::Error> {
use macros::all_notifications::*;

View file

@ -62,7 +62,9 @@ fn main() {
Err(e) => eprintln!("dir check failure: {}", e),
}
io::io_main();
let context = dm::Context::default();
let mut engine = Engine::new(&context);
io::run_forever(|message| engine.handle_input(message));
}
const VERSION: Option<jsonrpc::Version> = Some(jsonrpc::Version::V2);
@ -116,8 +118,7 @@ impl ClientCaps {
}
}
struct Engine<'a, W: 'a> {
write: &'a W,
struct Engine<'a> {
docs: document::DocumentStore,
status: InitStatus,
@ -135,10 +136,9 @@ struct Engine<'a, W: 'a> {
client_caps: ClientCaps,
}
impl<'a, W: io::ResponseWrite> Engine<'a, W> {
fn new(write: &'a W, context: &'a dm::Context) -> Self {
impl<'a> Engine<'a> {
fn new(context: &'a dm::Context) -> Self {
Engine {
write,
docs: Default::default(),
status: InitStatus::Starting,
@ -165,7 +165,7 @@ impl<'a, W: io::ResponseWrite> Engine<'a, W> {
T: langserver::notification::Notification,
T::Params: serde::Serialize,
{
issue_notification::<_, T>(self.write, params)
issue_notification::<T>(params)
}
fn show_message<S>(&mut self, typ: MessageType, message: S) where
@ -512,8 +512,7 @@ impl<'a, W: io::ResponseWrite> Engine<'a, W> {
}
}
issue_notification::<_, langserver::notification::PublishDiagnostics>(
self.write,
issue_notification::<langserver::notification::PublishDiagnostics>(
langserver::PublishDiagnosticsParams {
uri: url.to_owned(),
diagnostics,
@ -677,7 +676,7 @@ impl<'a, W: io::ResponseWrite> Engine<'a, W> {
_ => Response::Batch(outputs),
};
self.write.write(serde_json::to_string(&response).expect("response bad to_string"));
io::write(serde_json::to_string(&response).expect("response bad to_string"));
}
fn handle_call(&mut self, call: Call) -> Option<Output> {
@ -1707,7 +1706,7 @@ fn span_to_range(range: ::std::ops::Range<dm::Location>) -> langserver::Range {
langserver::Range::new(location_to_position(range.start), location_to_position(range.end))
}
fn issue_notification<W: io::ResponseWrite, T>(write: &W, params: T::Params)
fn issue_notification<T>(params: T::Params)
where
T: langserver::notification::Notification,
T::Params: serde::Serialize,
@ -1718,7 +1717,7 @@ where
method: T::METHOD.to_owned(),
params: value_to_params(params),
}));
write.write(serde_json::to_string(&request).expect("notification bad to_string"))
io::write(serde_json::to_string(&request).expect("notification bad to_string"))
}
fn component_to_source(component: dm::Component) -> Option<String> {