mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-23 09:41:33 +00:00
Switch from failure
to anyhow
(#1851)
This commit switches all of `wasm-bindgen` from the `failure` crate to `anyhow`. The `anyhow` crate should serve all the purposes that we previously used `failure` for but has a few advantages: * It's based on the standard `Error` trait rather than a custom `Fail` trait, improving ecosystem compatibility. * We don't need a `#[derive(Fail)]`, which means that's less code to compile for `wasm-bindgen`. This notably helps the compile time of `web-sys` itself. * Using `Result<()>` in `fn main` with `anyhow::Error` produces human-readable output, so we can use that natively.
This commit is contained in:
@ -93,3 +93,6 @@ wasm-bindgen = { path = '.' }
|
||||
wasm-bindgen-futures = { path = 'crates/futures' }
|
||||
js-sys = { path = 'crates/js-sys' }
|
||||
web-sys = { path = 'crates/web-sys' }
|
||||
|
||||
walrus = { git = 'https://github.com/rustwasm/walrus' }
|
||||
wasm-webidl-bindings = { git = 'https://github.com/rustwasm/wasm-webidl-bindings' }
|
||||
|
@ -12,5 +12,5 @@ Internal anyref transformations for wasm-bindgen
|
||||
edition = '2018'
|
||||
|
||||
[dependencies]
|
||||
failure = "0.1"
|
||||
walrus = "0.12.0"
|
||||
anyhow = "1.0"
|
||||
walrus = "0.13.0"
|
||||
|
@ -15,11 +15,11 @@
|
||||
//! goal at least is to have valid wasm modules coming in that don't use
|
||||
//! `anyref` and valid wasm modules going out which use `anyref` at the fringes.
|
||||
|
||||
use failure::{bail, format_err, Error};
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
use std::cmp;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use walrus::ir::*;
|
||||
use walrus::{ExportId, ImportId, TypeId};
|
||||
use walrus::{ExportId, ImportId, InstrLocId, TypeId};
|
||||
use walrus::{FunctionId, GlobalId, InitExpr, Module, TableId, ValType};
|
||||
|
||||
// must be kept in sync with src/lib.rs and ANYREF_HEAP_START
|
||||
@ -185,9 +185,8 @@ impl Context {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let heap_alloc = heap_alloc.ok_or_else(|| format_err!("failed to find heap alloc"))?;
|
||||
let heap_dealloc =
|
||||
heap_dealloc.ok_or_else(|| format_err!("failed to find heap dealloc"))?;
|
||||
let heap_alloc = heap_alloc.ok_or_else(|| anyhow!("failed to find heap alloc"))?;
|
||||
let heap_dealloc = heap_dealloc.ok_or_else(|| anyhow!("failed to find heap dealloc"))?;
|
||||
|
||||
// Create a shim function that looks like:
|
||||
//
|
||||
@ -624,7 +623,7 @@ impl Transform<'_> {
|
||||
impl VisitorMut for Rewrite<'_, '_> {
|
||||
fn start_instr_seq_mut(&mut self, seq: &mut InstrSeq) {
|
||||
for i in (0..seq.instrs.len()).rev() {
|
||||
let call = match &mut seq.instrs[i] {
|
||||
let call = match &mut seq.instrs[i].0 {
|
||||
Instr::Call(call) => call,
|
||||
_ => continue,
|
||||
};
|
||||
@ -644,24 +643,26 @@ impl Transform<'_> {
|
||||
match intrinsic {
|
||||
Intrinsic::TableGrow => {
|
||||
// Switch this to a `table.grow` instruction...
|
||||
seq.instrs[i] = TableGrow {
|
||||
seq.instrs[i].0 = TableGrow {
|
||||
table: self.xform.table,
|
||||
}
|
||||
.into();
|
||||
// ... and then insert a `ref.null` before the
|
||||
// preceding instruction as the value to grow the
|
||||
// table with.
|
||||
seq.instrs.insert(i - 1, RefNull {}.into());
|
||||
seq.instrs
|
||||
.insert(i - 1, (RefNull {}.into(), InstrLocId::default()));
|
||||
}
|
||||
Intrinsic::TableSetNull => {
|
||||
// Switch this to a `table.set` instruction...
|
||||
seq.instrs[i] = TableSet {
|
||||
seq.instrs[i].0 = TableSet {
|
||||
table: self.xform.table,
|
||||
}
|
||||
.into();
|
||||
// ... and then insert a `ref.null` as the
|
||||
// preceding instruction
|
||||
seq.instrs.insert(i, RefNull {}.into());
|
||||
seq.instrs
|
||||
.insert(i, (RefNull {}.into(), InstrLocId::default()));
|
||||
}
|
||||
Intrinsic::DropRef => call.func = self.xform.heap_dealloc,
|
||||
Intrinsic::CloneRef => call.func = self.xform.clone_ref,
|
||||
|
@ -13,12 +13,12 @@ edition = '2018'
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.9"
|
||||
failure = "0.1.2"
|
||||
anyhow = "1.0"
|
||||
log = "0.4"
|
||||
rustc-demangle = "0.1.13"
|
||||
serde_json = "1.0"
|
||||
tempfile = "3.0"
|
||||
walrus = "0.12.0"
|
||||
walrus = "0.13.0"
|
||||
wasm-bindgen-anyref-xform = { path = '../anyref-xform', version = '=0.2.53' }
|
||||
wasm-bindgen-shared = { path = "../shared", version = '=0.2.53' }
|
||||
wasm-bindgen-multi-value-xform = { path = '../multi-value-xform', version = '=0.2.53' }
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::webidl::{NonstandardIncoming, NonstandardOutgoing};
|
||||
use crate::webidl::{NonstandardWebidlSection, WasmBindgenAux};
|
||||
use failure::Error;
|
||||
use anyhow::Error;
|
||||
use std::collections::HashSet;
|
||||
use walrus::Module;
|
||||
use wasm_bindgen_anyref_xform::Context;
|
||||
|
@ -11,7 +11,7 @@
|
||||
//! functions.
|
||||
|
||||
use crate::descriptor::{Closure, Descriptor};
|
||||
use failure::Error;
|
||||
use anyhow::Error;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use walrus::ImportId;
|
||||
|
@ -8,7 +8,7 @@ use crate::js::incoming;
|
||||
use crate::js::outgoing;
|
||||
use crate::js::Context;
|
||||
use crate::webidl::Binding;
|
||||
use failure::{bail, Error};
|
||||
use anyhow::{bail, Error};
|
||||
use std::collections::HashSet;
|
||||
use wasm_webidl_bindings::ast;
|
||||
|
||||
|
@ -8,7 +8,7 @@ use crate::descriptor::VectorKind;
|
||||
use crate::js::binding::JsBuilder;
|
||||
use crate::js::Context;
|
||||
use crate::webidl::NonstandardIncoming;
|
||||
use failure::{bail, Error};
|
||||
use anyhow::{bail, Error};
|
||||
use wasm_webidl_bindings::ast;
|
||||
|
||||
pub struct Incoming<'a, 'b> {
|
||||
|
@ -5,7 +5,7 @@ use crate::webidl::{AuxEnum, AuxExport, AuxExportKind, AuxImport, AuxStruct};
|
||||
use crate::webidl::{AuxValue, Binding};
|
||||
use crate::webidl::{JsImport, JsImportName, NonstandardWebidlSection, WasmBindgenAux};
|
||||
use crate::{Bindgen, EncodeInto, OutputMode};
|
||||
use failure::{bail, Error, ResultExt};
|
||||
use anyhow::{bail, Context as _, Error};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -1888,7 +1888,7 @@ impl<'a> Context<'a> {
|
||||
check_duplicated_getter_and_setter_names(&pairs)?;
|
||||
for (id, export) in pairs {
|
||||
self.generate_export(*id, export, bindings)
|
||||
.with_context(|_| {
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to generate bindings for Rust export `{}`",
|
||||
export.debug_name,
|
||||
@ -1901,7 +1901,7 @@ impl<'a> Context<'a> {
|
||||
let catch = aux.imports_with_catch.contains(&id);
|
||||
let assert_no_shim = aux.imports_with_assert_no_shim.contains(&id);
|
||||
self.generate_import(*id, import, bindings, variadic, catch, assert_no_shim)
|
||||
.with_context(|_| {
|
||||
.with_context(|| {
|
||||
format!("failed to generate bindings for import `{:?}`", import,)
|
||||
})?;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use crate::descriptor::VectorKind;
|
||||
use crate::js::binding::JsBuilder;
|
||||
use crate::js::Context;
|
||||
use crate::webidl::NonstandardOutgoing;
|
||||
use failure::{bail, Error};
|
||||
use anyhow::{bail, Error};
|
||||
use wasm_webidl_bindings::ast;
|
||||
|
||||
pub struct Outgoing<'a, 'b> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![doc(html_root_url = "https://docs.rs/wasm-bindgen-cli-support/0.2")]
|
||||
|
||||
use failure::{bail, Error, ResultExt};
|
||||
use anyhow::{bail, Context, Error};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
@ -256,7 +256,7 @@ impl Bindgen {
|
||||
}
|
||||
Input::Path(ref path) => {
|
||||
let contents = fs::read(&path)
|
||||
.with_context(|_| format!("failed to read `{}`", path.display()))?;
|
||||
.with_context(|| format!("failed to read `{}`", path.display()))?;
|
||||
let module = walrus::ModuleConfig::new()
|
||||
// Skip validation of the module as LLVM's output is
|
||||
// generally already well-formed and so we won't gain much
|
||||
@ -307,7 +307,7 @@ impl Bindgen {
|
||||
|
||||
self.threads
|
||||
.run(&mut module)
|
||||
.with_context(|_| "failed to prepare module for threading")?;
|
||||
.with_context(|| "failed to prepare module for threading")?;
|
||||
|
||||
// If requested, turn all mangled symbols into prettier unmangled
|
||||
// symbols with the help of `rustc-demangle`.
|
||||
@ -373,10 +373,10 @@ impl Bindgen {
|
||||
.context("failed to transform return pointers into multi-value Wasm")?;
|
||||
}
|
||||
webidl::standard::add_section(&mut module, &aux, &bindings)
|
||||
.with_context(|_| "failed to generate a standard wasm bindings custom section")?;
|
||||
.with_context(|| "failed to generate a standard wasm bindings custom section")?;
|
||||
} else {
|
||||
if self.multi_value {
|
||||
failure::bail!(
|
||||
anyhow::bail!(
|
||||
"Wasm multi-value is currently only available when \
|
||||
Wasm interface types is also enabled"
|
||||
);
|
||||
@ -565,11 +565,11 @@ impl Output {
|
||||
&self.module
|
||||
}
|
||||
|
||||
pub fn emit(&self, out_dir: impl AsRef<Path>) -> Result<(), Error> {
|
||||
pub fn emit(&mut self, out_dir: impl AsRef<Path>) -> Result<(), Error> {
|
||||
self._emit(out_dir.as_ref())
|
||||
}
|
||||
|
||||
fn _emit(&self, out_dir: &Path) -> Result<(), Error> {
|
||||
fn _emit(&mut self, out_dir: &Path) -> Result<(), Error> {
|
||||
let wasm_name = if self.wasm_interface_types {
|
||||
self.stem.clone()
|
||||
} else {
|
||||
@ -579,7 +579,7 @@ impl Output {
|
||||
fs::create_dir_all(out_dir)?;
|
||||
let wasm_bytes = self.module.emit_wasm();
|
||||
fs::write(&wasm_path, wasm_bytes)
|
||||
.with_context(|_| format!("failed to write `{}`", wasm_path.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", wasm_path.display()))?;
|
||||
|
||||
if self.wasm_interface_types {
|
||||
return Ok(());
|
||||
@ -593,7 +593,7 @@ impl Output {
|
||||
let path = out_dir.join("snippets").join(identifier).join(name);
|
||||
fs::create_dir_all(path.parent().unwrap())?;
|
||||
fs::write(&path, js)
|
||||
.with_context(|_| format!("failed to write `{}`", path.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", path.display()))?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,7 +601,7 @@ impl Output {
|
||||
let path = out_dir.join("snippets").join(path);
|
||||
fs::create_dir_all(path.parent().unwrap())?;
|
||||
fs::write(&path, contents)
|
||||
.with_context(|_| format!("failed to write `{}`", path.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", path.display()))?;
|
||||
}
|
||||
|
||||
if self.npm_dependencies.len() > 0 {
|
||||
@ -623,26 +623,26 @@ impl Output {
|
||||
};
|
||||
let js_path = out_dir.join(&self.stem).with_extension(extension);
|
||||
fs::write(&js_path, reset_indentation(&self.js))
|
||||
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", js_path.display()))?;
|
||||
|
||||
if self.typescript {
|
||||
let ts_path = js_path.with_extension("d.ts");
|
||||
fs::write(&ts_path, &self.ts)
|
||||
.with_context(|_| format!("failed to write `{}`", ts_path.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", ts_path.display()))?;
|
||||
}
|
||||
|
||||
if self.mode.nodejs() {
|
||||
let js_path = wasm_path.with_extension(extension);
|
||||
let shim = self.generate_node_wasm_import(&self.module, &wasm_path);
|
||||
fs::write(&js_path, shim)
|
||||
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", js_path.display()))?;
|
||||
}
|
||||
|
||||
if self.typescript {
|
||||
let ts_path = wasm_path.with_extension("d.ts");
|
||||
let ts = wasm2es6js::typescript(&self.module)?;
|
||||
fs::write(&ts_path, ts)
|
||||
.with_context(|_| format!("failed to write `{}`", ts_path.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", ts_path.display()))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1,4 +1,4 @@
|
||||
use failure::{bail, Error};
|
||||
use anyhow::{bail, Error};
|
||||
use std::collections::HashSet;
|
||||
use walrus::Module;
|
||||
|
||||
|
@ -14,7 +14,7 @@ use crate::descriptor::Function;
|
||||
use crate::webidl::incoming::IncomingBuilder;
|
||||
use crate::webidl::outgoing::OutgoingBuilder;
|
||||
use crate::webidl::{Binding, NonstandardWebidlSection};
|
||||
use failure::{format_err, Error};
|
||||
use anyhow::{format_err, Error};
|
||||
use walrus::{FunctionId, Module, ValType};
|
||||
use wasm_webidl_bindings::ast;
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
//! the `outgoing.rs` module.
|
||||
|
||||
use crate::descriptor::{Descriptor, VectorKind};
|
||||
use failure::{bail, format_err, Error};
|
||||
use anyhow::{bail, format_err, Error};
|
||||
use walrus::ValType;
|
||||
use wasm_webidl_bindings::ast;
|
||||
|
||||
|
@ -27,7 +27,7 @@ use crate::decode;
|
||||
use crate::descriptor::{Descriptor, Function};
|
||||
use crate::descriptors::WasmBindgenDescriptorsSection;
|
||||
use crate::intrinsic::Intrinsic;
|
||||
use failure::{bail, format_err, Error};
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
@ -1340,7 +1340,7 @@ impl<'a> Context<'a> {
|
||||
walrus::ExportItem::Function(f) => f == bind.func,
|
||||
_ => false,
|
||||
})
|
||||
.ok_or_else(|| format_err!("missing export function for webidl binding"))?;
|
||||
.ok_or_else(|| anyhow!("missing export function for webidl binding"))?;
|
||||
let id = export.id();
|
||||
self.standard_export(binding, id)?;
|
||||
}
|
||||
@ -1363,7 +1363,7 @@ impl<'a> Context<'a> {
|
||||
let binding: &ast::FunctionBinding = std
|
||||
.bindings
|
||||
.get(bind.binding)
|
||||
.ok_or_else(|| format_err!("bad binding id"))?;
|
||||
.ok_or_else(|| anyhow!("bad binding id"))?;
|
||||
let (wasm_ty, webidl_ty, incoming, outgoing) = match binding {
|
||||
ast::FunctionBinding::Export(e) => (
|
||||
e.wasm_ty,
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
use crate::descriptor::{Descriptor, VectorKind};
|
||||
use crate::webidl::NonstandardWebidlSection;
|
||||
use failure::{bail, format_err, Error};
|
||||
use anyhow::{bail, format_err, Error};
|
||||
use walrus::{Module, ValType};
|
||||
use wasm_webidl_bindings::ast;
|
||||
|
||||
|
@ -20,7 +20,7 @@ use crate::descriptor::VectorKind;
|
||||
use crate::webidl::{AuxExportKind, AuxImport, AuxValue, JsImport, JsImportName};
|
||||
use crate::webidl::{NonstandardIncoming, NonstandardOutgoing};
|
||||
use crate::webidl::{NonstandardWebidlSection, WasmBindgenAux};
|
||||
use failure::{bail, Error, ResultExt};
|
||||
use anyhow::{bail, Context, Error};
|
||||
use walrus::Module;
|
||||
use wasm_bindgen_multi_value_xform as multi_value_xform;
|
||||
use wasm_bindgen_wasm_conventions as wasm_conventions;
|
||||
@ -210,14 +210,14 @@ pub fn add_section(
|
||||
}
|
||||
|
||||
let name = &module.exports.get(*export).name;
|
||||
let params = extract_incoming(&binding.incoming).with_context(|_| {
|
||||
let params = extract_incoming(&binding.incoming).with_context(|| {
|
||||
format!(
|
||||
"failed to map arguments for export `{}` to standard \
|
||||
binding expressions",
|
||||
name
|
||||
)
|
||||
})?;
|
||||
let result = extract_outgoing(&binding.outgoing).with_context(|_| {
|
||||
let result = extract_outgoing(&binding.outgoing).with_context(|| {
|
||||
format!(
|
||||
"failed to map return value for export `{}` to standard \
|
||||
binding expressions",
|
||||
@ -252,14 +252,14 @@ pub fn add_section(
|
||||
let import = module.imports.get(*import);
|
||||
(&import.module, &import.name)
|
||||
};
|
||||
let params = extract_outgoing(&binding.outgoing).with_context(|_| {
|
||||
let params = extract_outgoing(&binding.outgoing).with_context(|| {
|
||||
format!(
|
||||
"failed to map arguments of import `{}::{}` to standard \
|
||||
binding expressions",
|
||||
module_name, name,
|
||||
)
|
||||
})?;
|
||||
let result = extract_incoming(&binding.incoming).with_context(|_| {
|
||||
let result = extract_incoming(&binding.incoming).with_context(|| {
|
||||
format!(
|
||||
"failed to map return value of import `{}::{}` to standard \
|
||||
binding expressions",
|
||||
|
@ -17,14 +17,14 @@ edition = '2018'
|
||||
curl = "0.4.13"
|
||||
docopt = "1.0"
|
||||
env_logger = "0.7"
|
||||
failure = "0.1.2"
|
||||
anyhow = "1.0"
|
||||
log = "0.4"
|
||||
openssl = { version = '0.10.11', optional = true }
|
||||
rouille = { version = "3.0.0", default-features = false }
|
||||
serde = { version = "1.0", features = ['derive'] }
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
walrus = { version = "0.12.0", features = ['parallel'] }
|
||||
walrus = { version = "0.13.0", features = ['parallel'] }
|
||||
wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.53" }
|
||||
wasm-bindgen-shared = { path = "../shared", version = "=0.2.53" }
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::shell::Shell;
|
||||
use anyhow::{bail, format_err, Context, Error};
|
||||
use curl::easy::Easy;
|
||||
use failure::{bail, format_err, Error, ResultExt};
|
||||
use log::{debug, warn};
|
||||
use rouille::url::Url;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -138,8 +138,8 @@ pub fn run(server: &SocketAddr, shell: &Shell) -> Result<(), Error> {
|
||||
// We periodically check the page to see if the output contains a known
|
||||
// string to only be printed when tests have finished running.
|
||||
//
|
||||
// TODO: harness failures aren't well handled here, they always force a
|
||||
// timeout. These sorts of failures could be "you typo'd the path to a
|
||||
// TODO: harness anyhows aren't well handled here, they always force a
|
||||
// timeout. These sorts of anyhows could be "you typo'd the path to a
|
||||
// local script" which is pretty bad to time out for, we should detect
|
||||
// this on the page and look for such output here, printing diagnostic
|
||||
// information.
|
||||
|
@ -11,11 +11,10 @@
|
||||
//! For more documentation about this see the `wasm-bindgen-test` crate README
|
||||
//! and source code.
|
||||
|
||||
use failure::{bail, format_err, Error, ResultExt};
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::thread;
|
||||
use wasm_bindgen_cli_support::Bindgen;
|
||||
|
||||
@ -28,20 +27,8 @@ mod node;
|
||||
mod server;
|
||||
mod shell;
|
||||
|
||||
fn main() {
|
||||
fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
let err = match rmain() {
|
||||
Ok(()) => return,
|
||||
Err(e) => e,
|
||||
};
|
||||
eprintln!("error: {}", err);
|
||||
for cause in err.iter_causes() {
|
||||
eprintln!("\tcaused by: {}", cause);
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
fn rmain() -> Result<(), Error> {
|
||||
let mut args = env::args_os().skip(1);
|
||||
let shell = shell::Shell::new();
|
||||
|
||||
@ -59,7 +46,7 @@ fn rmain() -> Result<(), Error> {
|
||||
.and_then(|p| p.parent()) // chop off `deps`
|
||||
.and_then(|p| p.parent()) // chop off `debug`
|
||||
.map(|p| p.join("wbg-tmp"))
|
||||
.ok_or_else(|| format_err!("file to test doesn't follow the expected Cargo conventions"))?;
|
||||
.ok_or_else(|| anyhow!("file to test doesn't follow the expected Cargo conventions"))?;
|
||||
|
||||
// Make sure there's no stale state from before
|
||||
drop(fs::remove_dir_all(&tmpdir));
|
||||
|
@ -4,7 +4,7 @@ use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use failure::{Error, ResultExt};
|
||||
use anyhow::{Context, Error};
|
||||
|
||||
pub fn execute(
|
||||
module: &str,
|
||||
|
@ -3,7 +3,7 @@ use std::fs;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::Path;
|
||||
|
||||
use failure::{format_err, Error, ResultExt};
|
||||
use anyhow::{anyhow, Context, Error};
|
||||
use rouille::{Request, Response, Server};
|
||||
|
||||
pub fn spawn(
|
||||
@ -90,7 +90,7 @@ pub fn spawn(
|
||||
response.headers.retain(|(k, _)| k != "Cache-Control");
|
||||
return response;
|
||||
})
|
||||
.map_err(|e| format_err!("{}", e))?;
|
||||
.map_err(|e| anyhow!("{}", e))?;
|
||||
return Ok(srv);
|
||||
|
||||
fn try_asset(request: &Request, dir: &Path) -> Response {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use anyhow::{bail, Error};
|
||||
use docopt::Docopt;
|
||||
use failure::{bail, Error};
|
||||
use serde::Deserialize;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
@ -77,10 +77,7 @@ fn main() {
|
||||
Ok(()) => return,
|
||||
Err(e) => e,
|
||||
};
|
||||
eprintln!("error: {}", err);
|
||||
for cause in err.iter_causes() {
|
||||
eprintln!(" caused by: {}", cause);
|
||||
}
|
||||
eprintln!("error: {:?}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
use anyhow::{Context, Error};
|
||||
use docopt::Docopt;
|
||||
use failure::{Error, ResultExt};
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
// no need for jemalloc bloat in this binary (and we don't need speed)
|
||||
#[global_allocator]
|
||||
@ -39,24 +38,12 @@ struct Args {
|
||||
arg_input: PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
.and_then(|d| d.deserialize())
|
||||
.unwrap_or_else(|e| e.exit());
|
||||
let err = match rmain(&args) {
|
||||
Ok(()) => return,
|
||||
Err(e) => e,
|
||||
};
|
||||
eprintln!("error: {}", err);
|
||||
for cause in err.iter_causes() {
|
||||
eprintln!("\tcaused by: {}", cause);
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
fn rmain(args: &Args) -> Result<(), Error> {
|
||||
let wasm = fs::read(&args.arg_input)
|
||||
.with_context(|_| format!("failed to read `{}`", args.arg_input.display()))?;
|
||||
.with_context(|| format!("failed to read `{}`", args.arg_input.display()))?;
|
||||
|
||||
let object = wasm_bindgen_cli_support::wasm2es6js::Config::new()
|
||||
.base64(args.flag_base64)
|
||||
@ -70,9 +57,9 @@ fn rmain(args: &Args) -> Result<(), Error> {
|
||||
|
||||
let (js, wasm) = object.js_and_wasm()?;
|
||||
|
||||
write(args, "js", js.as_bytes(), false)?;
|
||||
write(&args, "js", js.as_bytes(), false)?;
|
||||
if let Some(wasm) = wasm {
|
||||
write(args, "wasm", &wasm, false)?;
|
||||
write(&args, "wasm", &wasm, false)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -81,12 +68,12 @@ fn write(args: &Args, extension: &str, contents: &[u8], print_fallback: bool) ->
|
||||
if let Some(p) = &args.flag_output {
|
||||
let dst = p.with_extension(extension);
|
||||
fs::write(&dst, contents)
|
||||
.with_context(|_| format!("failed to write `{}`", dst.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", dst.display()))?;
|
||||
} else if let Some(p) = &args.flag_out_dir {
|
||||
let filename = args.arg_input.file_name().unwrap();
|
||||
let dst = p.join(filename).with_extension(extension);
|
||||
fs::write(&dst, contents)
|
||||
.with_context(|_| format!("failed to write `{}`", dst.display()))?;
|
||||
.with_context(|| format!("failed to write `{}`", dst.display()))?;
|
||||
} else if print_fallback {
|
||||
println!("{}", String::from_utf8_lossy(contents))
|
||||
}
|
||||
|
@ -12,5 +12,5 @@ Internal multi-value transformations for wasm-bindgen
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
failure = "0.1"
|
||||
walrus = "0.12.0"
|
||||
anyhow = "1.0"
|
||||
walrus = "0.13.0"
|
||||
|
@ -113,7 +113,7 @@ pub fn run(
|
||||
memory: walrus::MemoryId,
|
||||
shadow_stack_pointer: walrus::GlobalId,
|
||||
to_xform: &[(walrus::ExportId, usize, &[walrus::ValType])],
|
||||
) -> Result<(), failure::Error> {
|
||||
) -> Result<(), anyhow::Error> {
|
||||
for &(export, return_pointer_index, results) in to_xform {
|
||||
xform_one(
|
||||
module,
|
||||
@ -140,16 +140,14 @@ fn xform_one(
|
||||
export: walrus::ExportId,
|
||||
return_pointer_index: usize,
|
||||
results: &[walrus::ValType],
|
||||
) -> Result<(), failure::Error> {
|
||||
) -> Result<(), anyhow::Error> {
|
||||
if module.globals.get(shadow_stack_pointer).ty != walrus::ValType::I32 {
|
||||
failure::bail!("shadow stack pointer global does not have type `i32`");
|
||||
anyhow::bail!("shadow stack pointer global does not have type `i32`");
|
||||
}
|
||||
|
||||
let func = match module.exports.get(export).item {
|
||||
walrus::ExportItem::Function(f) => f,
|
||||
_ => {
|
||||
failure::bail!("can only multi-value transform exported functions, found non-function")
|
||||
}
|
||||
_ => anyhow::bail!("can only multi-value transform exported functions, found non-function"),
|
||||
};
|
||||
|
||||
// Compute the total size of all results, potentially with padding to ensure
|
||||
@ -165,7 +163,7 @@ fn xform_one(
|
||||
round_up_to_alignment(results_size, 8) + 8
|
||||
}
|
||||
walrus::ValType::V128 => round_up_to_alignment(results_size, 16) + 16,
|
||||
walrus::ValType::Anyref => failure::bail!(
|
||||
walrus::ValType::Anyref => anyhow::bail!(
|
||||
"cannot multi-value transform functions that return \
|
||||
anyref, since they can't go into linear memory"
|
||||
),
|
||||
@ -179,7 +177,7 @@ fn xform_one(
|
||||
let (ty_params, ty_results) = module.types.params_results(ty);
|
||||
|
||||
if !ty_results.is_empty() {
|
||||
failure::bail!(
|
||||
anyhow::bail!(
|
||||
"can only multi-value transform functions that don't return any \
|
||||
results (since they should be returned on the stack via a pointer)"
|
||||
);
|
||||
@ -187,8 +185,8 @@ fn xform_one(
|
||||
|
||||
match ty_params.get(return_pointer_index) {
|
||||
Some(walrus::ValType::I32) => {}
|
||||
None => failure::bail!("the return pointer parameter doesn't exist"),
|
||||
Some(_) => failure::bail!("the return pointer parameter is not `i32`"),
|
||||
None => anyhow::bail!("the return pointer parameter doesn't exist"),
|
||||
Some(_) => anyhow::bail!("the return pointer parameter is not `i32`"),
|
||||
}
|
||||
|
||||
let new_params: Vec<_> = ty_params
|
||||
|
@ -12,6 +12,6 @@ Support for threading-related transformations in wasm-bindgen
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
failure = "0.1"
|
||||
walrus = "0.12.0"
|
||||
anyhow = "1.0"
|
||||
walrus = "0.13.0"
|
||||
wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.53" }
|
||||
|
@ -3,9 +3,9 @@ use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::mem;
|
||||
|
||||
use failure::{bail, format_err, Error};
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
use walrus::ir::Value;
|
||||
use walrus::{DataId, FunctionId, InitExpr, ValType};
|
||||
use walrus::{DataId, FunctionId, InitExpr, InstrLocId, ValType};
|
||||
use walrus::{ExportItem, GlobalId, GlobalKind, ImportKind, MemoryId, Module};
|
||||
use wasm_bindgen_wasm_conventions as wasm_conventions;
|
||||
|
||||
@ -180,7 +180,7 @@ fn delete_synthetic_export(module: &mut Module, name: &str) -> Result<ExportItem
|
||||
.exports
|
||||
.iter()
|
||||
.find(|e| e.name == name)
|
||||
.ok_or_else(|| format_err!("failed to find `{}`", name))?;
|
||||
.ok_or_else(|| anyhow!("failed to find `{}`", name))?;
|
||||
let ret = item.item;
|
||||
let id = item.id();
|
||||
module.exports.delete(id);
|
||||
@ -452,7 +452,7 @@ fn find_wbindgen_malloc(module: &Module) -> Result<FunctionId, Error> {
|
||||
.exports
|
||||
.iter()
|
||||
.find(|e| e.name == "__wbindgen_malloc")
|
||||
.ok_or_else(|| format_err!("failed to find `__wbindgen_malloc`"))?;
|
||||
.ok_or_else(|| anyhow!("failed to find `__wbindgen_malloc`"))?;
|
||||
match e.item {
|
||||
walrus::ExportItem::Function(f) => Ok(f),
|
||||
_ => bail!("`__wbindgen_malloc` wasn't a funtion"),
|
||||
@ -515,7 +515,7 @@ fn implement_thread_intrinsics(module: &mut Module, globals: &Globals) -> Result
|
||||
});
|
||||
|
||||
impl VisitorMut for Visitor<'_> {
|
||||
fn visit_instr_mut(&mut self, instr: &mut Instr) {
|
||||
fn visit_instr_mut(&mut self, instr: &mut Instr, _loc: &mut InstrLocId) {
|
||||
let call = match instr {
|
||||
Instr::Call(e) => e,
|
||||
_ => return,
|
||||
|
@ -9,8 +9,6 @@ documentation = "https://docs.rs/wasm-bindgen-wasm-conventions"
|
||||
description = "Utilities for working with Wasm codegen conventions (usually established by LLVM/lld)"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
walrus = "0.12.0"
|
||||
failure = "0.1.5"
|
||||
walrus = "0.13.0"
|
||||
anyhow = "1.0"
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#![deny(missing_docs, missing_debug_implementations)]
|
||||
|
||||
use failure::{bail, format_err, Error};
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
use walrus::{GlobalId, GlobalKind, MemoryId, Module, ValType};
|
||||
|
||||
/// Get a Wasm module's canonical linear memory.
|
||||
@ -22,7 +22,7 @@ pub fn get_memory(module: &Module) -> Result<MemoryId, Error> {
|
||||
);
|
||||
}
|
||||
memory.ok_or_else(|| {
|
||||
format_err!(
|
||||
anyhow!(
|
||||
"module does not have a memory; must have a memory \
|
||||
to transform return pointers into Wasm multi-value"
|
||||
)
|
||||
@ -69,9 +69,7 @@ pub fn unexport_shadow_stack_pointer(module: &mut Module) -> Result<(), Error> {
|
||||
.iter()
|
||||
.find(|e| e.name == "__shadow_stack_pointer")
|
||||
.map(|e| e.id())
|
||||
.ok_or_else(|| {
|
||||
format_err!("did not find the `__shadow_stack_pointer` export in the module")
|
||||
})?;
|
||||
.ok_or_else(|| anyhow!("did not find the `__shadow_stack_pointer` export in the module"))?;
|
||||
module.exports.delete(e);
|
||||
Ok(())
|
||||
}
|
||||
@ -85,9 +83,7 @@ pub fn get_shadow_stack_pointer(module: &Module) -> Result<GlobalId, Error> {
|
||||
.exports
|
||||
.iter()
|
||||
.find(|e| e.name == "__shadow_stack_pointer")
|
||||
.ok_or_else(|| {
|
||||
format_err!("did not find the `__shadow_stack_pointer` export in the module")
|
||||
})
|
||||
.ok_or_else(|| anyhow!("did not find the `__shadow_stack_pointer` export in the module"))
|
||||
.and_then(|e| match e.item {
|
||||
walrus::ExportItem::Global(g) => Ok(g),
|
||||
_ => bail!("`__shadow_stack_pointer` export is wrong kind"),
|
||||
|
@ -12,9 +12,9 @@ Micro-interpreter optimized for wasm-bindgen's use case
|
||||
edition = '2018'
|
||||
|
||||
[dependencies]
|
||||
failure = "0.1"
|
||||
anyhow = "1.0"
|
||||
log = "0.4"
|
||||
walrus = "0.12.0"
|
||||
walrus = "0.13.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
@ -65,7 +65,7 @@ impl Interpreter {
|
||||
///
|
||||
/// Note that the `module` passed in to this function must be the same as
|
||||
/// the `module` passed to `interpret` below.
|
||||
pub fn new(module: &Module) -> Result<Interpreter, failure::Error> {
|
||||
pub fn new(module: &Module) -> Result<Interpreter, anyhow::Error> {
|
||||
let mut ret = Interpreter::default();
|
||||
|
||||
// The descriptor functions shouldn't really use all that much memory
|
||||
@ -246,7 +246,7 @@ impl Interpreter {
|
||||
frame.locals.insert(*arg, *val);
|
||||
}
|
||||
|
||||
for instr in block.instrs.iter() {
|
||||
for (instr, _) in block.instrs.iter() {
|
||||
frame.eval(instr);
|
||||
if frame.done {
|
||||
break;
|
||||
|
@ -21,7 +21,7 @@ test = false
|
||||
|
||||
[build-dependencies]
|
||||
env_logger = { version = "0.7.0", optional = true }
|
||||
failure = "0.1.2"
|
||||
anyhow = "1.0"
|
||||
wasm-bindgen-webidl = { path = "../webidl", version = "=0.2.53" }
|
||||
sourcefile = "0.1"
|
||||
|
||||
|
@ -1,26 +1,15 @@
|
||||
use failure::{Fail, ResultExt};
|
||||
use anyhow::{Context, Result};
|
||||
use sourcefile::SourceFile;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{self, PathBuf};
|
||||
use std::process::{self, Command};
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<()> {
|
||||
#[cfg(feature = "env_logger")]
|
||||
env_logger::init();
|
||||
|
||||
if let Err(e) = try_main() {
|
||||
eprintln!("Error: {}", e);
|
||||
for c in e.iter_causes() {
|
||||
eprintln!(" caused by {}", c);
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_main() -> Result<(), failure::Error> {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=webidls/enabled");
|
||||
|
||||
@ -35,7 +24,7 @@ fn try_main() -> Result<(), failure::Error> {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
source = source
|
||||
.add_file(&path)
|
||||
.with_context(|_| format!("reading contents of file \"{}\"", path.display()))?;
|
||||
.with_context(|| format!("reading contents of file \"{}\"", path.display()))?;
|
||||
}
|
||||
|
||||
// Read our manifest, learn all `[feature]` directives with "toml parsing".
|
||||
@ -76,9 +65,9 @@ fn try_main() -> Result<(), failure::Error> {
|
||||
|
||||
let bindings = match wasm_bindgen_webidl::compile(&source.contents, allowed) {
|
||||
Ok(bindings) => bindings,
|
||||
Err(e) => match e.kind() {
|
||||
wasm_bindgen_webidl::ErrorKind::ParsingWebIDLSourcePos(pos) => {
|
||||
if let Some(pos) = source.resolve_offset(pos) {
|
||||
Err(e) => {
|
||||
if let Some(err) = e.downcast_ref::<wasm_bindgen_webidl::WebIDLParseError>() {
|
||||
if let Some(pos) = source.resolve_offset(err.0) {
|
||||
let ctx = format!(
|
||||
"compiling WebIDL into wasm-bindgen bindings in file \
|
||||
\"{}\", line {} column {}",
|
||||
@ -86,19 +75,13 @@ fn try_main() -> Result<(), failure::Error> {
|
||||
pos.line + 1,
|
||||
pos.col + 1
|
||||
);
|
||||
return Err(e.context(ctx).into());
|
||||
return Err(e.context(ctx));
|
||||
} else {
|
||||
return Err(e
|
||||
.context("compiling WebIDL into wasm-bindgen bindings")
|
||||
.into());
|
||||
return Err(e.context("compiling WebIDL into wasm-bindgen bindings"));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(e
|
||||
.context("compiling WebIDL into wasm-bindgen bindings")
|
||||
.into());
|
||||
}
|
||||
},
|
||||
return Err(e.context("compiling WebIDL into wasm-bindgen bindings"));
|
||||
}
|
||||
};
|
||||
|
||||
let out_dir = env::var("OUT_DIR").context("reading OUT_DIR environment variable")?;
|
||||
|
@ -13,7 +13,7 @@ Support for parsing WebIDL specific to wasm-bindgen
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
failure = "0.1.2"
|
||||
anyhow = "1.0"
|
||||
heck = "0.3"
|
||||
log = "0.4.1"
|
||||
proc-macro2 = "1.0"
|
||||
|
@ -1,65 +0,0 @@
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
use std::fmt;
|
||||
|
||||
/// Either `Ok(t)` or `Err(Error)`.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
|
||||
/// The different contexts an error can occur in in this crate.
|
||||
#[derive(Debug, Fail, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub enum ErrorKind {
|
||||
/// Failed to open a WebIDL file.
|
||||
#[fail(display = "opening WebIDL file")]
|
||||
OpeningWebIDLFile,
|
||||
/// Failed to read a WebIDL file.
|
||||
#[fail(display = "reading WebIDL file")]
|
||||
ReadingWebIDLFile,
|
||||
/// Failed to parse a WebIDL file.
|
||||
#[fail(display = "parsing WebIDL source text at {}", _0)]
|
||||
ParsingWebIDLSourcePos(usize),
|
||||
/// Failed to parse a WebIDL file.
|
||||
#[fail(display = "parsing WebIDL source text")]
|
||||
ParsingWebIDLSource,
|
||||
}
|
||||
|
||||
/// The error type for this crate.
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
inner: Context<ErrorKind>,
|
||||
}
|
||||
|
||||
impl Fail for Error {
|
||||
fn cause(&self) -> Option<&dyn Fail> {
|
||||
self.inner.cause()
|
||||
}
|
||||
|
||||
fn backtrace(&self) -> Option<&Backtrace> {
|
||||
self.inner.backtrace()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// The context for this error.
|
||||
pub fn kind(&self) -> ErrorKind {
|
||||
*self.inner.get_context()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorKind> for Error {
|
||||
fn from(kind: ErrorKind) -> Error {
|
||||
Error {
|
||||
inner: Context::new(kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Context<ErrorKind>> for Error {
|
||||
fn from(inner: Context<ErrorKind>) -> Error {
|
||||
Error { inner: inner }
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ emitted for the types and methods described in the WebIDL.
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![doc(html_root_url = "https://docs.rs/wasm-bindgen-webidl/0.2")]
|
||||
|
||||
mod error;
|
||||
mod first_pass;
|
||||
mod idl_type;
|
||||
mod util;
|
||||
@ -21,11 +20,12 @@ use crate::util::{
|
||||
camel_case_ident, mdn_doc, public, shouty_snake_case_ident, snake_case_ident,
|
||||
webidl_const_v_to_backend_const_v, TypePosition,
|
||||
};
|
||||
use failure::format_err;
|
||||
use anyhow::{bail, Result};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
use std::fs;
|
||||
use std::iter::FromIterator;
|
||||
@ -38,22 +38,30 @@ use weedle::attribute::ExtendedAttributeList;
|
||||
use weedle::dictionary::DictionaryMember;
|
||||
use weedle::interface::InterfaceMember;
|
||||
|
||||
pub use crate::error::{Error, ErrorKind, Result};
|
||||
|
||||
struct Program {
|
||||
main: ast::Program,
|
||||
submodules: Vec<(String, ast::Program)>,
|
||||
}
|
||||
|
||||
/// A parse error indicating where parsing failed
|
||||
#[derive(Debug)]
|
||||
pub struct WebIDLParseError(pub usize);
|
||||
|
||||
impl fmt::Display for WebIDLParseError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "failed to parse webidl at byte position {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for WebIDLParseError {}
|
||||
|
||||
/// Parse a string of WebIDL source text into a wasm-bindgen AST.
|
||||
fn parse(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result<Program> {
|
||||
let definitions = match weedle::parse(webidl_source) {
|
||||
Ok(def) => def,
|
||||
Err(e) => {
|
||||
return Err(match &e {
|
||||
weedle::Err::Incomplete(needed) => format_err!("needed {:?} more bytes", needed)
|
||||
.context(ErrorKind::ParsingWebIDLSource)
|
||||
.into(),
|
||||
match &e {
|
||||
weedle::Err::Incomplete(needed) => bail!("needed {:?} more bytes", needed),
|
||||
weedle::Err::Error(cx) | weedle::Err::Failure(cx) => {
|
||||
// Note that #[allow] here is a workaround for Geal/nom#843
|
||||
// because the `Context` type here comes from `nom` and if
|
||||
@ -66,11 +74,10 @@ fn parse(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result<Program>
|
||||
_ => 0,
|
||||
};
|
||||
let pos = webidl_source.len() - remaining;
|
||||
format_err!("failed to parse WebIDL")
|
||||
.context(ErrorKind::ParsingWebIDLSourcePos(pos))
|
||||
.into()
|
||||
|
||||
bail!(WebIDLParseError(pos))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user