]> Repositorios git - scryer-prolog.git/commitdiff
Allow users to disable optional features. Needed for wasm32 support (see #615).
authorRujia Liu <{ID}+{username}@user.noreply.github.com>
Mon, 21 Aug 2023 02:01:24 +0000 (10:01 +0800)
committerRujia Liu <{ID}+{username}@user.noreply.github.com>
Mon, 21 Aug 2023 02:01:24 +0000 (10:01 +0800)
12 files changed:
Cargo.lock
Cargo.toml
src/arena.rs
src/bin/scryer-prolog.rs
src/lib.rs
src/machine/dispatch.rs
src/machine/machine_errors.rs
src/machine/mock_wam.rs
src/machine/mod.rs
src/machine/streams.rs
src/machine/system_calls.rs
src/read.rs

index b521745238c4d3f738b2a3819b546df307733aee..d3209675c03f0c154065b01e7f17eb3984d8703b 100644 (file)
@@ -742,8 +742,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
 dependencies = [
  "cfg-if",
+ "js-sys",
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -1811,6 +1813,22 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "ring-wasi"
+version = "0.16.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db1418b2535ed5e71a9fc73d3fede8596792fd7cb4b4a0f8ecf412cfddaaedd4"
+dependencies = [
+ "cc",
+ "getrandom",
+ "libc",
+ "once_cell",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi",
+]
+
 [[package]]
 name = "ripemd160"
 version = "0.8.0"
@@ -1944,6 +1962,7 @@ dependencies = [
  "divrem",
  "futures",
  "fxhash",
+ "getrandom",
  "git-version",
  "hostname",
  "http-body-util",
@@ -1965,6 +1984,7 @@ dependencies = [
  "ref_thread_local",
  "reqwest",
  "ring",
+ "ring-wasi",
  "ripemd160",
  "roxmltree",
  "rustyline",
index f4659c46220611c5980f2480987e33ddc47fa1e3..902655324bd8df16208c8b508cb4b90c9aa6e386 100644 (file)
@@ -13,6 +13,12 @@ build = "build/main.rs"
 rust-version = "1.63"
 
 [features]
+default = ["ffi", "repl", "hostname", "tls", "http"]
+ffi = ["dep:libffi"]
+repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"]
+hostname = ["dep:hostname"]
+tls = ["dep:native-tls"]
+http = ["dep:hyper", "dep:reqwest"]
 
 [build-dependencies]
 indexmap = "1.0.2"
@@ -29,28 +35,22 @@ walkdir = "2"
 bit-set = "0.5.3"
 bitvec = "1"
 cpu-time = "1.0.0"
-crossterm = "0.20.0"
 dirs-next = "2.0.0"
 divrem = "0.1.0"
 fxhash = "0.2.1"
 git-version = "0.3.4"
-hostname = "0.3.1"
 indexmap = "1.0.2"
 lazy_static = "1.4.0"
 lexical = "5.2.2"
 libc = "0.2.62"
 modular-bitfield = "0.11.2"
-ctrlc = "3.2.2"
 ordered-float = "2.6.0"
 phf = { version = "0.9", features = ["macros"] }
 ref_thread_local = "0.0.0"
-rustyline = "12.0.0"
-ring = "0.16.13"
 ripemd160 = "0.8.0"
 sha3 = "0.8.2"
 blake2 = "0.8.1"
 crrl = "0.6.0"
-native-tls = "0.2.4"
 chrono = "0.4.11"
 select = "0.6.0"
 roxmltree = "0.11.0"
@@ -58,18 +58,35 @@ base64 = "0.12.3"
 smallvec = "1.8.0"
 static_assertions = "1.1.0"
 ryu = "1.0.9"
-hyper = { version = "1.0.0-rc.3", features = ["full"] }
-tokio = { version = "1.28.2", features = ["full"] }
 futures = "0.3"
 libloading = "0.7"
 derive_deref = "1.1.1"
 http-body-util = "0.1.0-rc.2"
 bytes = "1"
-reqwest = { version = "0.11.18", features = ["blocking"] }
 dashu = { git = "https://github.com/coasys/dashu.git"  }
-libffi = { git = "https://github.com/coasys/libffi-rs.git", branch = "windows-space" }
 rand = "0.8.5"
 
+[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
+libffi = { git = "https://github.com/coasys/libffi-rs.git", branch = "windows-space", optional = true }
+hostname = { version = "0.3.1", optional = true }
+crossterm = { version = "0.20.0", optional = true }
+ctrlc = { version = "3.2.2", optional = true }
+rustyline = { version = "12.0.0", optional = true }
+native-tls = { version = "0.2.4", optional = true }
+hyper = { version = "=1.0.0-rc.3", features = ["full"], optional = true }
+reqwest = { version = "0.11.18", features = ["blocking"], optional = true }
+tokio = { version = "1.28.2", features = ["full"] }
+
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+getrandom = { version = "0.2.10", features = ["js"] }
+tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt", "time"] }
+
+[target.'cfg(target_os = "wasi")'.dependencies]
+ring-wasi = { version = "0.16.25" }
+
+[target.'cfg(not(target_os = "wasi"))'.dependencies]
+ring = { version = "0.16.13" }
+
 [dev-dependencies]
 assert_cmd = "1.0.3"
 predicates-core = "1.0.2"
index 66b5c27b4c15f4b2f42b03da20ee2b74bec368b8..5f5f8a91deb067a0ed196c97a42f6da6d9a6eeea 100644 (file)
@@ -1,3 +1,4 @@
+#[cfg(feature = "http")]
 use crate::http::{HttpListener, HttpResponse};
 use crate::machine::loader::LiveLoadState;
 use crate::machine::machine_indices::*;
@@ -566,6 +567,7 @@ impl ArenaAllocated for TcpListener {
     }
 }
 
+#[cfg(feature = "http")]
 impl ArenaAllocated for HttpListener {
     type PtrToAllocated = TypedArenaPtr<HttpListener>;
 
@@ -588,6 +590,7 @@ impl ArenaAllocated for HttpListener {
     }
 }
 
+#[cfg(feature = "http")]
 impl ArenaAllocated for HttpResponse {
     type PtrToAllocated = TypedArenaPtr<HttpResponse>;
 
@@ -695,12 +698,15 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
             ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTcpStream>>>());
         }
         ArenaHeaderTag::NamedTlsStream => {
+            #[cfg(feature = "tls")]
             ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
         }
         ArenaHeaderTag::HttpReadStream => {
+            #[cfg(feature = "http")]
             ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpReadStream>>>());
         }
            ArenaHeaderTag::HttpWriteStream => {
+            #[cfg(feature = "http")]
                ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpWriteStream>>>());
            }
         ArenaHeaderTag::ReadlineStream => {
@@ -724,9 +730,11 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
             ptr::drop_in_place(value.payload_offset::<TcpListener>());
         }
            ArenaHeaderTag::HttpListener => {
+            #[cfg(feature = "http")]
                ptr::drop_in_place(value.payload_offset::<HttpListener>());
            }
            ArenaHeaderTag::HttpResponse => {
+            #[cfg(feature = "http")]
                ptr::drop_in_place(value.payload_offset::<HttpResponse>());
            }
         ArenaHeaderTag::StandardOutputStream => {
index e15bae144feb28f2b1f8e665f8988c6927ab2515..eb0fd5ff7e3322433c4f9abc0e1fcafe6f5a3230 100644 (file)
@@ -2,6 +2,7 @@ fn main() -> std::process::ExitCode {
     use std::sync::atomic::Ordering;
     use scryer_prolog::*;
 
+    #[cfg(feature = "repl")]
     ctrlc::set_handler(move || {
         scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
     }).unwrap();
index 36f7a45bf096174c3198ea6d7c6f6dcf0a457bcf..acae77ebc187cc1064d5d6c7eaf25d12aa7eee2a 100644 (file)
@@ -15,11 +15,13 @@ mod allocator;
 mod arithmetic;
 pub mod codegen;
 mod debray_allocator;
+#[cfg(feature = "ffi")]
 mod ffi;
 mod variable_records;
 mod forms;
 mod heap_iter;
 pub mod heap_print;
+#[cfg(feature = "http")]
 mod http;
 mod indexing;
 #[macro_use]
@@ -30,6 +32,7 @@ mod iterators;
 pub mod machine;
 mod raw_block;
 pub mod read;
+#[cfg(feature = "repl")]
 mod repl_helper;
 mod targets;
 pub mod types;
index 6eeedb63f103bda78a51ba6accba4973ea96c354..8752522d8f7ef030cd09d78c0d7e260102badc7b 100644 (file)
@@ -4242,58 +4242,72 @@ impl Machine {
                     step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                 }
                 &Instruction::CallHttpOpen => {
+                    #[cfg(feature = "http")]
                     try_or_throw!(self.machine_st, self.http_open());
                     step_or_fail!(self, self.machine_st.p += 1);
                 }
                 &Instruction::ExecuteHttpOpen => {
+                    #[cfg(feature = "http")]
                     try_or_throw!(self.machine_st, self.http_open());
                     step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                 }
                &Instruction::CallHttpListen => {
+            #[cfg(feature = "http")]
                    try_or_throw!(self.machine_st, self.http_listen());
                    step_or_fail!(self, self.machine_st.p += 1);
                }
                &Instruction::ExecuteHttpListen => {
+            #[cfg(feature = "http")]
                    try_or_throw!(self.machine_st, self.http_listen());
                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                }
                &Instruction::CallHttpAccept => {
+            #[cfg(feature = "http")]
                    try_or_throw!(self.machine_st, self.http_accept());
                    step_or_fail!(self, self.machine_st.p += 1);
                }
                &Instruction::ExecuteHttpAccept => {
+            #[cfg(feature = "http")]
                    try_or_throw!(self.machine_st, self.http_accept());
                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                }
                &Instruction::CallHttpAnswer => {
+            #[cfg(feature = "http")]
                    try_or_throw!(self.machine_st, self.http_answer());
                    step_or_fail!(self, self.machine_st.p += 1);
                }
                &Instruction::ExecuteHttpAnswer => {
+            #[cfg(feature = "http")]
                    try_or_throw!(self.machine_st, self.http_answer());
                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                }
                &Instruction::CallLoadForeignLib => {
+            #[cfg(feature = "ffi")]
                    try_or_throw!(self.machine_st, self.load_foreign_lib());
                    step_or_fail!(self, self.machine_st.p += 1);
                }
                &Instruction::ExecuteLoadForeignLib => {
+            #[cfg(feature = "ffi")]
                    try_or_throw!(self.machine_st, self.load_foreign_lib());
                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                }
                &Instruction::CallForeignCall => {
+            #[cfg(feature = "ffi")]
                    try_or_throw!(self.machine_st, self.foreign_call());
                    step_or_fail!(self, self.machine_st.p += 1);
                }
                &Instruction::ExecuteForeignCall => {
+            #[cfg(feature = "ffi")]
                    try_or_throw!(self.machine_st, self.foreign_call());
                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                }
                &Instruction::CallDefineForeignStruct => {
+            #[cfg(feature = "ffi")]
                    try_or_throw!(self.machine_st, self.define_foreign_struct());
                    step_or_fail!(self, self.machine_st.p += 1);
                }
                &Instruction::ExecuteDefineForeignStruct => {
+            #[cfg(feature = "ffi")]
                    try_or_throw!(self.machine_st, self.define_foreign_struct());
                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                }
@@ -4462,18 +4476,22 @@ impl Machine {
                     self.machine_st.p = self.machine_st.cp;
                 }
                 &Instruction::CallTLSAcceptClient => {
+                    #[cfg(feature = "tls")]
                     try_or_throw!(self.machine_st, self.tls_accept_client());
                     step_or_fail!(self, self.machine_st.p += 1);
                 }
                 &Instruction::ExecuteTLSAcceptClient => {
+                    #[cfg(feature = "tls")]
                     try_or_throw!(self.machine_st, self.tls_accept_client());
                     step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                 }
                 &Instruction::CallTLSClientConnect => {
+                    #[cfg(feature = "tls")]
                     try_or_throw!(self.machine_st, self.tls_client_connect());
                     step_or_fail!(self, self.machine_st.p += 1);
                 }
                 &Instruction::ExecuteTLSClientConnect => {
+                    #[cfg(feature = "tls")]
                     try_or_throw!(self.machine_st, self.tls_client_connect());
                     step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                 }
index 936200f059b5db5435564799b4b76d965ea391d5..46c4be2040623563ec644d0785bd0b59ebf9538c 100644 (file)
@@ -2,6 +2,7 @@ use crate::arena::*;
 use crate::atom_table::*;
 use crate::parser::ast::*;
 
+#[cfg(feature = "ffi")]
 use crate::ffi::FFIError;
 use crate::forms::*;
 use crate::machine::heap::*;
@@ -538,6 +539,7 @@ impl MachineState {
         }
     }
 
+    #[cfg(feature = "ffi")]
     pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError {
        let error_atom = match err {
            FFIError::ValueCast => atom!("value_cast"),
index 257735c6680fcbc50b055220a98ed62eeef9ce97..9fda84ecde244b6ec08c8c155de876bb88386a1d 100644 (file)
@@ -244,6 +244,7 @@ impl Machine {
             user_error,
             load_contexts: vec![],
             runtime,
+            #[cfg(feature = "ffi")]
                foreign_function_table: Default::default(),
         };
 
index a3f0a24c2d171e07d46ed7add9e22e49f2e33cde..98db014d767cc13636a32b5704b4c7eba2d883cd 100644 (file)
@@ -28,6 +28,7 @@ use crate::arena::*;
 use crate::arithmetic::*;
 use crate::atom_table::*;
 use crate::forms::*;
+#[cfg(feature = "ffi")]
 use crate::ffi::ForeignFunctionTable;
 use crate::instructions::*;
 use crate::machine::args::*;
@@ -68,6 +69,7 @@ pub struct Machine {
     pub(super) user_error: Stream,
     pub(super) load_contexts: Vec<LoadContext>,
     pub(super) runtime: Runtime,
+    #[cfg(feature = "ffi")]
     pub(super) foreign_function_table: ForeignFunctionTable,
 }
 
@@ -425,8 +427,14 @@ impl Machine {
         let user_output = Stream::stdout(&mut machine_st.arena);
         let user_error = Stream::stderr(&mut machine_st.arena);
 
+        #[cfg(not(target_os = "wasi"))]
         let runtime = tokio::runtime::Runtime::new()
             .unwrap();
+        #[cfg(target_os = "wasi")]
+        let runtime = tokio::runtime::Builder::new_current_thread()
+            .enable_all()
+            .build()
+            .unwrap();
 
         let mut wam = Machine {
             machine_st,
@@ -437,6 +445,7 @@ impl Machine {
             user_error,
             load_contexts: vec![],
             runtime,
+            #[cfg(feature = "ffi")]
                foreign_function_table: Default::default(),
         };
 
index 0ea8591de5af330ce1619f5bbf5b2966211a46c7..e5d9d05fc48fe33eac72ccb10c4cda9d344c4ebd 100644 (file)
@@ -9,6 +9,7 @@ use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
 use crate::types::*;
+#[cfg(feature = "http")]
 use crate::http::HttpResponse;
 
 pub use modular_bitfield::prelude::*;
@@ -26,6 +27,7 @@ use std::net::{TcpStream, Shutdown};
 use std::ops::{Deref, DerefMut};
 use std::ptr;
 
+#[cfg(feature = "tls")]
 use native_tls::TlsStream;
 
 #[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
@@ -232,12 +234,14 @@ impl Write for NamedTcpStream {
     }
 }
 
+#[cfg(feature = "tls")]
 #[derive(Debug)]
 pub struct NamedTlsStream {
     address: Atom,
     tls_stream: TlsStream<Stream>,
 }
 
+#[cfg(feature = "tls")]
 impl Read for NamedTlsStream {
     #[inline]
     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
@@ -245,6 +249,7 @@ impl Read for NamedTlsStream {
     }
 }
 
+#[cfg(feature = "tls")]
 impl Write for NamedTlsStream {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
@@ -257,17 +262,20 @@ impl Write for NamedTlsStream {
     }
 }
 
+#[cfg(feature = "http")]
 pub struct HttpReadStream {
     url: Atom,
     body_reader: Box<dyn BufRead>,
 }
 
+#[cfg(feature = "http")]
 impl Debug for HttpReadStream {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "Http Read Stream [{}]", self.url.as_str())
     }
 }
 
+#[cfg(feature = "http")]
 impl Read for HttpReadStream {
     #[inline]
     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
@@ -275,6 +283,7 @@ impl Read for HttpReadStream {
     }
 }
 
+#[cfg(feature = "http")]
 pub struct HttpWriteStream {
     status_code: u16,
     headers: hyper::HeaderMap,
@@ -282,12 +291,14 @@ pub struct HttpWriteStream {
     buffer: Vec<u8>,
 }
 
+#[cfg(feature = "http")]
 impl Debug for HttpWriteStream {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "Http Write Stream")
     }
 }
 
+#[cfg(feature = "http")]
 impl Write for HttpWriteStream {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
@@ -453,8 +464,11 @@ arena_allocated_impl_for_stream!(CharReader<ByteStream>, ByteStream);
 arena_allocated_impl_for_stream!(CharReader<InputFileStream>, InputFileStream);
 arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream);
 arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream);
+#[cfg(feature = "tls")]
 arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream);
+#[cfg(feature = "http")]
 arena_allocated_impl_for_stream!(CharReader<HttpReadStream>, HttpReadStream);
+#[cfg(feature = "http")]
 arena_allocated_impl_for_stream!(CharReader<HttpWriteStream>, HttpWriteStream);
 arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream);
 arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream);
@@ -468,8 +482,11 @@ pub enum Stream {
     OutputFile(TypedArenaPtr<StreamLayout<OutputFileStream>>),
     StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
     NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
+    #[cfg(feature = "tls")]
     NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
+    #[cfg(feature = "http")]
     HttpRead(TypedArenaPtr<StreamLayout<CharReader<HttpReadStream>>>),
+    #[cfg(feature = "http")]
     HttpWrite(TypedArenaPtr<StreamLayout<CharReader<HttpWriteStream>>>),
     Null(StreamOptions),
     Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
@@ -524,8 +541,11 @@ impl Stream {
                 Stream::OutputFile(TypedArenaPtr::new(ptr as *mut _))
             }
             ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
+            #[cfg(feature = "tls")]
             ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
+            #[cfg(feature = "http")]
             ArenaHeaderTag::HttpReadStream => Stream::HttpRead(TypedArenaPtr::new(ptr as *mut _)),
+            #[cfg(feature = "http")]
                ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)),
             ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
             ArenaHeaderTag::StaticStringStream => {
@@ -578,8 +598,11 @@ impl Stream {
             Stream::OutputFile(ptr) => ptr.header_ptr(),
             Stream::StaticString(ptr) => ptr.header_ptr(),
             Stream::NamedTcp(ptr) => ptr.header_ptr(),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ptr) => ptr.header_ptr(),
+            #[cfg(feature = "http")]
             Stream::HttpRead(ptr) => ptr.header_ptr(),
+            #[cfg(feature = "http")]
                Stream::HttpWrite(ptr) => ptr.header_ptr(),
             Stream::Null(_) => ptr::null(),
             Stream::Readline(ptr) => ptr.header_ptr(),
@@ -595,9 +618,12 @@ impl Stream {
             Stream::OutputFile(ref ptr) => &ptr.options,
             Stream::StaticString(ref ptr) => &ptr.options,
             Stream::NamedTcp(ref ptr) => &ptr.options,
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ref ptr) => &ptr.options,
+            #[cfg(feature = "http")]
             Stream::HttpRead(ref ptr) => &ptr.options,
-               Stream::HttpWrite(ref ptr) => &ptr.options,
+            #[cfg(feature = "http")]
+            Stream::HttpWrite(ref ptr) => &ptr.options,
             Stream::Null(ref options) => options,
             Stream::Readline(ref ptr) => &ptr.options,
             Stream::StandardOutput(ref ptr) => &ptr.options,
@@ -612,8 +638,11 @@ impl Stream {
             Stream::OutputFile(ref mut ptr) => &mut ptr.options,
             Stream::StaticString(ref mut ptr) => &mut ptr.options,
             Stream::NamedTcp(ref mut ptr) => &mut ptr.options,
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ref mut ptr) => &mut ptr.options,
+            #[cfg(feature = "http")]
             Stream::HttpRead(ref mut ptr) => &mut ptr.options,
+            #[cfg(feature = "http")]
             Stream::HttpWrite(ref mut ptr) => &mut ptr.options,
             Stream::Null(ref mut options) => options,
             Stream::Readline(ref mut ptr) => &mut ptr.options,
@@ -630,8 +659,11 @@ impl Stream {
             Stream::OutputFile(ptr) => ptr.lines_read += incr_num_lines_read,
             Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read,
             Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read,
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read,
+            #[cfg(feature = "http")]
             Stream::HttpRead(ptr) => ptr.lines_read += incr_num_lines_read,
+            #[cfg(feature = "http")]
             Stream::HttpWrite(_) => {}
             Stream::Null(_) => {}
             Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read,
@@ -648,8 +680,11 @@ impl Stream {
             Stream::OutputFile(ptr) => ptr.lines_read = value,
             Stream::StaticString(ptr) => ptr.lines_read = value,
             Stream::NamedTcp(ptr) => ptr.lines_read = value,
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ptr) => ptr.lines_read = value,
+            #[cfg(feature = "http")]
             Stream::HttpRead(ptr) => ptr.lines_read = value,
+            #[cfg(feature = "http")]
             Stream::HttpWrite(_) => {}
             Stream::Null(_) => {}
             Stream::Readline(ptr) => ptr.lines_read = value,
@@ -666,8 +701,11 @@ impl Stream {
             Stream::OutputFile(ptr) => ptr.lines_read,
             Stream::StaticString(ptr) => ptr.lines_read,
             Stream::NamedTcp(ptr) => ptr.lines_read,
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ptr) => ptr.lines_read,
+            #[cfg(feature = "http")]
             Stream::HttpRead(ptr) => ptr.lines_read,
+            #[cfg(feature = "http")]
             Stream::HttpWrite(_) => 0,
             Stream::Null(_) => 0,
             Stream::Readline(ptr) => ptr.lines_read,
@@ -682,15 +720,21 @@ impl CharRead for Stream {
         match self {
             Stream::InputFile(file) => (*file).peek_char(),
             Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(),
+            #[cfg(feature = "http")]
             Stream::HttpRead(http_stream) => (*http_stream).peek_char(),
             Stream::Readline(rl_stream) => (*rl_stream).peek_char(),
             Stream::StaticString(src) => (*src).peek_char(),
             Stream::Byte(cursor) => (*cursor).peek_char(),
+            #[cfg(feature = "http")]
+               Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
+                ErrorKind::PermissionDenied,
+                StreamError::ReadFromOutputStream,
+            ))),
             Stream::OutputFile(_) |
             Stream::StandardError(_) |
             Stream::StandardOutput(_) |
-               Stream::HttpWrite(_) |
             Stream::Null(_) => Some(Err(std::io::Error::new(
                 ErrorKind::PermissionDenied,
                 StreamError::ReadFromOutputStream,
@@ -702,15 +746,21 @@ impl CharRead for Stream {
         match self {
             Stream::InputFile(file) => (*file).read_char(),
             Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(tls_stream) => (*tls_stream).read_char(),
+            #[cfg(feature = "http")]
             Stream::HttpRead(http_stream) => (*http_stream).read_char(),
             Stream::Readline(rl_stream) => (*rl_stream).read_char(),
             Stream::StaticString(src) => (*src).read_char(),
             Stream::Byte(cursor) => (*cursor).read_char(),
+            #[cfg(feature = "http")]
+               Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
+                ErrorKind::PermissionDenied,
+                StreamError::ReadFromOutputStream,
+            ))),
             Stream::OutputFile(_) |
             Stream::StandardError(_) |
             Stream::StandardOutput(_) |
-               Stream::HttpWrite(_) |
             Stream::Null(_) => Some(Err(std::io::Error::new(
                 ErrorKind::PermissionDenied,
                 StreamError::ReadFromOutputStream,
@@ -722,15 +772,18 @@ impl CharRead for Stream {
         match self {
             Stream::InputFile(file) => file.put_back_char(c),
             Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c),
+            #[cfg(feature = "http")]
             Stream::HttpRead(http_stream) => http_stream.put_back_char(c),
             Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
             Stream::StaticString(src) => src.put_back_char(c),
             Stream::Byte(cursor) => cursor.put_back_char(c),
+            #[cfg(feature = "http")]
+               Stream::HttpWrite(_) => {}
             Stream::OutputFile(_) |
             Stream::StandardError(_) |
             Stream::StandardOutput(_) |
-               Stream::HttpWrite(_) |
             Stream::Null(_) => {}
         }
     }
@@ -739,15 +792,18 @@ impl CharRead for Stream {
         match self {
             Stream::InputFile(ref mut file) => file.consume(nread),
             Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread),
+            #[cfg(feature = "http")]
             Stream::HttpRead(ref mut http_stream) => http_stream.consume(nread),
             Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread),
             Stream::StaticString(ref mut src) => src.consume(nread),
             Stream::Byte(ref mut cursor) => cursor.consume(nread),
+            #[cfg(feature = "http")]
+               Stream::HttpWrite(_) => {}
             Stream::OutputFile(_) |
             Stream::StandardError(_) |
             Stream::StandardOutput(_) |
-               Stream::HttpWrite(_) |
             Stream::Null(_) => {}
         }
     }
@@ -759,15 +815,21 @@ impl Read for Stream {
         let bytes_read = match self {
             Stream::InputFile(file) => (*file).read(buf),
             Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(tls_stream) => (*tls_stream).read(buf),
+            #[cfg(feature = "http")]
             Stream::HttpRead(http_stream) => (*http_stream).read(buf),
             Stream::Readline(rl_stream) => (*rl_stream).read(buf),
             Stream::StaticString(src) => (*src).read(buf),
             Stream::Byte(cursor) => (*cursor).read(buf),
+            #[cfg(feature = "http")]
+               Stream::HttpWrite(_) => Err(std::io::Error::new(
+                ErrorKind::PermissionDenied,
+                StreamError::ReadFromOutputStream,
+            )),
             Stream::OutputFile(_)
                 | Stream::StandardError(_)
                    | Stream::StandardOutput(_)
-                   | Stream::HttpWrite(_)
                 | Stream::Null(_) => Err(std::io::Error::new(
                     ErrorKind::PermissionDenied,
                     StreamError::ReadFromOutputStream,
@@ -783,12 +845,18 @@ impl Write for Stream {
         match self {
             Stream::OutputFile(ref mut file) => file.write(buf),
             Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.get_mut().write(buf),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ref mut tls_stream) => tls_stream.get_mut().write(buf),
             Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
             Stream::StandardOutput(stream) => stream.write(buf),
             Stream::StandardError(stream) => stream.write(buf),
+            #[cfg(feature = "http")]
                Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
-            Stream::HttpRead(_) |
+            #[cfg(feature = "http")]
+            Stream::HttpRead(_) => Err(std::io::Error::new(
+                ErrorKind::PermissionDenied,
+                StreamError::WriteToInputStream,
+            )),
             Stream::StaticString(_) |
             Stream::Readline(_) |
             Stream::InputFile(..) |
@@ -803,12 +871,18 @@ impl Write for Stream {
         match self {
             Stream::OutputFile(ref mut file) => file.stream.flush(),
             Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.stream.get_mut().flush(),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ref mut tls_stream) => tls_stream.stream.get_mut().flush(),
             Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
             Stream::StandardError(stream) => stream.stream.flush(),
             Stream::StandardOutput(stream) => stream.stream.flush(),
+            #[cfg(feature = "http")]
                Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
-            Stream::HttpRead(_) |
+            #[cfg(feature = "http")] 
+            Stream::HttpRead(_) => Err(std::io::Error::new(
+                ErrorKind::PermissionDenied,
+                StreamError::FlushToInputStream,
+            )),
             Stream::StaticString(_) |
             Stream::Readline(_) |
             Stream::InputFile(_) |
@@ -913,7 +987,12 @@ impl Stream {
             Stream::InputFile(file_stream) => {
                 file_stream.position()
             }
-            Stream::NamedTcp(..) | Stream::NamedTls(..) | Stream::Readline(..) => {
+            #[cfg(feature = "tls")]
+            Stream::NamedTls(..) => {
+                Some(0)
+            }
+            Stream::NamedTcp(..) 
+            | Stream::Readline(..) => {
                 Some(0)
             }
             _ => None,
@@ -951,8 +1030,11 @@ impl Stream {
             Stream::OutputFile(stream) => stream.past_end_of_stream,
             Stream::StaticString(stream) => stream.past_end_of_stream,
             Stream::NamedTcp(stream) => stream.past_end_of_stream,
+            #[cfg(feature = "tls")]
             Stream::NamedTls(stream) => stream.past_end_of_stream,
+            #[cfg(feature = "http")]
             Stream::HttpRead(stream) => stream.past_end_of_stream,
+            #[cfg(feature = "http")]
             Stream::HttpWrite(stream) => stream.past_end_of_stream,
             Stream::Null(_) => false,
             Stream::Readline(stream) => stream.past_end_of_stream,
@@ -974,8 +1056,11 @@ impl Stream {
             Stream::OutputFile(stream) => stream.past_end_of_stream = value,
             Stream::StaticString(stream) => stream.past_end_of_stream = value,
             Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
+            #[cfg(feature = "tls")]
             Stream::NamedTls(stream) => stream.past_end_of_stream = value,
+            #[cfg(feature = "http")]
             Stream::HttpRead(stream) => stream.past_end_of_stream = value,
+            #[cfg(feature = "http")]
             Stream::HttpWrite(stream) => stream.past_end_of_stream = value,
             Stream::Null(_) => {}
             Stream::Readline(stream) => stream.past_end_of_stream = value,
@@ -1054,6 +1139,7 @@ impl Stream {
             Stream::InputFile(file) => Some(file.stream.get_ref().file_name),
             Stream::OutputFile(file) => Some(file.stream.file_name),
             Stream::NamedTcp(tcp) => Some(tcp.stream.get_ref().address),
+            #[cfg(feature = "tls")]
             Stream::NamedTls(tls) => Some(tls.stream.get_ref().address),
             _ => None,
         }
@@ -1062,14 +1148,19 @@ impl Stream {
     #[inline]
     pub(crate) fn mode(&self) -> Atom {
         match self {
+            #[cfg(feature = "http")]
+            Stream::HttpRead(_) => atom!("read"),
+            #[cfg(feature = "tls")]
+            Stream::NamedTls(..) => atom!("read_append"),
             Stream::Byte(_)
                 | Stream::Readline(_)
                 | Stream::StaticString(_)
-                | Stream::HttpRead(_)
                 | Stream::InputFile(..) => atom!("read"),
-            Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
+            Stream::NamedTcp(..) => atom!("read_append"),
             Stream::OutputFile(file) if file.is_append => atom!("append"),
-            Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::HttpWrite(_) => atom!("write"),
+            #[cfg(feature = "http")]
+            Stream::HttpWrite(_) => atom!("write"),
+            Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"),
             Stream::Null(_) => atom!(""),
         }
     }
@@ -1108,6 +1199,7 @@ impl Stream {
         ))
     }
 
+    #[cfg(feature = "tls")]
     #[inline]
     pub(crate) fn from_tls_stream(
         address: Atom,
@@ -1123,6 +1215,7 @@ impl Stream {
         ))
     }
 
+    #[cfg(feature = "http")]
     #[inline]
     pub(crate) fn from_http_stream(
         url: Atom,
@@ -1138,6 +1231,7 @@ impl Stream {
         ))
     }
 
+    #[cfg(feature = "http")]
     #[inline]
     pub(crate) fn from_http_sender(
        response: TypedArenaPtr<HttpResponse>,
@@ -1189,9 +1283,11 @@ impl Stream {
             Stream::NamedTcp(ref mut tcp_stream) => {
                 tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both)
             },
+            #[cfg(feature = "tls")]
             Stream::NamedTls(ref mut tls_stream) => {
                 tls_stream.inner_mut().tls_stream.shutdown()
             }
+            #[cfg(feature = "http")]
             Stream::HttpRead(ref mut http_stream) => {
                 unsafe {
                     http_stream.set_tag(ArenaHeaderTag::Dropped);
@@ -1200,7 +1296,8 @@ impl Stream {
 
                 Ok(())
             }
-           Stream::HttpWrite(ref mut http_stream) => {
+            #[cfg(feature = "http")]
+               Stream::HttpWrite(ref mut http_stream) => {
                 unsafe {
                     http_stream.set_tag(ArenaHeaderTag::Dropped);
                     std::ptr::drop_in_place(&mut http_stream.inner_mut().buffer as *mut _);
@@ -1242,9 +1339,11 @@ impl Stream {
     #[inline]
     pub(crate) fn is_input_stream(&self) -> bool {
         match self {
+            #[cfg(feature = "tls")]
+            Stream::NamedTls(..) => true,
+            #[cfg(feature = "http")]
+            Stream::HttpRead(..) => true,
             Stream::NamedTcp(..)
-                | Stream::NamedTls(..)
-                | Stream::HttpRead(..)
                 | Stream::Byte(_)
                 | Stream::Readline(_)
                 | Stream::StaticString(_)
@@ -1256,11 +1355,13 @@ impl Stream {
     #[inline]
     pub(crate) fn is_output_stream(&self) -> bool {
         match self {
+            #[cfg(feature = "tls")]
+            Stream::NamedTls(..) => true,
+            #[cfg(feature = "http")]
+            Stream::HttpWrite(..) => true,
             Stream::StandardError(_)
                 | Stream::StandardOutput(_)
                 | Stream::NamedTcp(..)
-                   | Stream::NamedTls(..)
-                   | Stream::HttpWrite(..)
                 | Stream::Byte(_)
                 | Stream::OutputFile(..) => true,
             _ => false,
index b09bb93e63d2fba3bdb856e544a53040f40238fb..d68facdedaea7658766a05756dd2a369726c23f9 100644 (file)
@@ -7,9 +7,11 @@ use lazy_static::lazy_static;
 use crate::arena::*;
 use crate::atom_table::*;
 use crate::forms::*;
+#[cfg(feature = "ffi")]
 use crate::ffi::*;
 use crate::heap_iter::*;
 use crate::heap_print::*;
+#[cfg(feature = "http")]
 use crate::http::{HttpService, HttpListener, HttpResponse};
 use crate::instructions::*;
 use crate::machine;
@@ -44,6 +46,7 @@ use std::cmp::Ordering;
 use std::collections::BTreeSet;
 use std::convert::TryFrom;
 use std::env;
+#[cfg(feature = "ffi")]
 use std::ffi::CString;
 use std::fs;
 use std::hash::{BuildHasher, BuildHasherDefault};
@@ -57,10 +60,13 @@ use std::process;
 use std::str::FromStr;
 
 use chrono::{offset::Local, DateTime};
+#[cfg(not(target_os = "wasi"))]
 use cpu_time::ProcessTime;
 use std::time::{Duration, SystemTime};
 
+#[cfg(feature = "repl")]
 use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
+#[cfg(feature = "repl")]
 use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
 
 use blake2::{Blake2b, Blake2s};
@@ -74,19 +80,25 @@ use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
 
 use crrl::{secp256k1, x25519};
 
+#[cfg(feature = "tls")]
 use native_tls::{TlsConnector,TlsAcceptor,Identity};
 
 use base64;
 use roxmltree;
 use select;
 
+#[cfg(feature = "http")]
 use hyper::server::conn::http1;
+#[cfg(feature = "http")]
 use hyper::header::{HeaderValue, HeaderName};
+#[cfg(feature = "http")]
 use hyper::{HeaderMap, Method};
 use http_body_util::BodyExt;
 use bytes::Buf;
+#[cfg(feature = "http")]
 use reqwest::Url;
 
+#[cfg(feature = "repl")]
 pub(crate) fn get_key() -> KeyEvent {
     let key;
     enable_raw_mode().expect("failed to enable raw mode");
@@ -741,7 +753,7 @@ impl MachineState {
             };
 
             if let Some(max_steps) = max_steps_n {
-                if max_steps.abs() as usize <= 1 << 63 {
+                if max_steps.abs() as u64 <= 1 << 63 {
                     if max_steps >= 0 {
                         max_old = max_steps;
                     } else {
@@ -1764,6 +1776,7 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn current_hostname(&mut self) {
+        #[cfg(feature = "hostname")]
         match hostname::get().ok() {
             Some(host) => match host.to_str() {
                 Some(host) => {
@@ -3679,6 +3692,7 @@ impl Machine {
         Ok(())
     }
 
+    #[cfg(feature = "repl")]
     #[inline(always)]
     pub(crate) fn get_single_char(&mut self) -> CallResult {
         let ctrl_c = KeyEvent {
@@ -3702,7 +3716,28 @@ impl Machine {
             KeyCode::Char(c) => c,
             _ => unreachable!(),
         };
+        let a1 = self.deref_register(1);
+        self.machine_st.unify_char(
+            c,
+            a1,
+        );
+
+        Ok(())
+    }
+
+    #[cfg(not(feature = "repl"))]
+    #[inline(always)]
+    pub(crate) fn get_single_char(&mut self) -> CallResult {
+        let mut buffer = [0; 1];
+        // is there a better way?
+        if std::io::stdin().read(&mut buffer).is_err() {
+            let stub = functor_stub(atom!("get_single_char"), 1);
+            let err = self.machine_st.interrupt_error();
+            let err = self.machine_st.error_form(err, stub);
 
+            return Err(err);
+        }
+        let c = buffer[0] as char;
         let a1 = self.deref_register(1);
         self.machine_st.unify_char(
             c,
@@ -4158,6 +4193,7 @@ impl Machine {
         self.machine_st.fail = result;
     }
 
+    #[cfg(not(target_os = "wasi"))]
     #[inline(always)]
     pub(crate) fn cpu_now(&mut self) {
         let secs = ProcessTime::now().as_duration().as_secs_f64();
@@ -4166,6 +4202,12 @@ impl Machine {
         self.machine_st.unify_f64(secs, self.machine_st.registers[1]);
     }
 
+    #[cfg(target_os = "wasi")]
+    #[inline(always)]
+    pub(crate) fn cpu_now(&mut self) {
+        // TODO
+    }
+
     #[inline(always)]
     pub(crate) fn det_length_rundown(&mut self) -> CallResult {
         let stub_gen = || functor_stub(atom!("length"), 2);
@@ -4198,6 +4240,7 @@ impl Machine {
         Ok(())
     }
 
+    #[cfg(feature = "http")]
     #[inline(always)]
     pub(crate) fn http_open(&mut self) -> CallResult {
         let address_sink = self.deref_register(1);
@@ -4316,6 +4359,7 @@ impl Machine {
         Ok(())
     }
 
+    #[cfg(feature = "http")]
     #[inline(always)]
     pub(crate) fn http_listen(&mut self) -> CallResult {
         let address_sink = self.deref_register(1);
@@ -4364,6 +4408,7 @@ impl Machine {
        Ok(())
     }
 
+    #[cfg(feature = "http")]
     #[inline(always)]
     pub(crate) fn http_accept(&mut self) -> CallResult {
        let culprit = self.deref_register(1);
@@ -4447,6 +4492,7 @@ impl Machine {
        Ok(())
     }
 
+    #[cfg(feature = "http")]
     #[inline(always)]
     pub(crate) fn http_answer(&mut self) -> CallResult {
        let culprit = self.deref_register(1);
@@ -4513,6 +4559,7 @@ impl Machine {
        Ok(())
     }
 
+    #[cfg(feature = "ffi")]
     #[inline(always)]
     pub(crate) fn load_foreign_lib(&mut self) -> CallResult {
        let library_name = self.deref_register(1);
@@ -4559,6 +4606,7 @@ impl Machine {
        Ok(())
     }
 
+    #[cfg(feature = "ffi")]
     #[inline(always)]
     pub(crate) fn foreign_call(&mut self) -> CallResult {
        let function_name = self.deref_register(1);
@@ -4634,6 +4682,7 @@ impl Machine {
        Ok(())
     }
 
+    #[cfg(feature = "ffi")]
     fn build_struct(&mut self, name: &str, mut args: Vec<Value>) -> HeapCellValue {
        args.insert(0, Value::CString(CString::new(name).unwrap()));
        let cells: Vec<_> = args.into_iter()
@@ -4654,6 +4703,7 @@ impl Machine {
         )
     }
 
+    #[cfg(feature = "ffi")]
     #[inline(always)]
     pub(crate) fn define_foreign_struct(&mut self) -> CallResult {
        let struct_name = self.deref_register(1);
@@ -6233,6 +6283,7 @@ impl Machine {
         Ok(())
     }
 
+    #[cfg(feature = "tls")]
     #[inline(always)]
     pub(crate) fn tls_client_connect(&mut self) -> CallResult {
         if let Some(hostname) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
@@ -6270,6 +6321,7 @@ impl Machine {
         }
     }
 
+    #[cfg(feature = "tls")]
     #[inline(always)]
     pub(crate) fn tls_accept_client(&mut self) -> CallResult {
         let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
index e23dc3028d4c2444e0860ea78c0e546c32856ba4..40b50e03014e5f2ded7c4597f72b0d0c14b4549d 100644 (file)
@@ -10,14 +10,19 @@ use crate::machine::machine_indices::*;
 use crate::machine::machine_state::MachineState;
 use crate::machine::streams::*;
 use crate::parser::char_reader::*;
+#[cfg(feature = "repl")]
 use crate::repl_helper::Helper;
 use crate::types::*;
 
 use fxhash::FxBuildHasher;
 
 use indexmap::IndexSet;
+
+#[cfg(feature = "repl")]
 use rustyline::error::ReadlineError;
+#[cfg(feature = "repl")]
 use rustyline::history::DefaultHistory;
+#[cfg(feature = "repl")]
 use rustyline::{Config, Editor};
 
 use std::collections::VecDeque;
@@ -102,12 +107,14 @@ fn get_prompt() -> &'static str {
 
 #[derive(Debug)]
 pub struct ReadlineStream {
+    #[cfg(feature = "repl")]
     rl: Editor<Helper, DefaultHistory>,
     pending_input: CharReader<Cursor<String>>,
     add_history: bool,
 }
 
 impl ReadlineStream {
+    #[cfg(feature = "repl")]
     #[inline]
     pub fn new(pending_input: &str, add_history: bool) -> Self {
         let config = Config::builder()
@@ -133,11 +140,25 @@ impl ReadlineStream {
         }
     }
 
+    #[cfg(not(feature = "repl"))]
+    #[inline]
+    pub fn new(pending_input: &str, add_history: bool) -> Self {
+        ReadlineStream {
+            pending_input: CharReader::new(Cursor::new(pending_input.to_owned())),
+            add_history: add_history,
+        }
+    }
+
+    #[cfg(feature = "repl")]
     pub fn set_atoms_for_completion(&mut self, atoms: *const IndexSet<Atom>) {
         let helper = self.rl.helper_mut().unwrap();
         helper.atoms = atoms;
     }
 
+    #[cfg(not(feature = "repl"))]
+    pub fn set_atoms_for_completion(&mut self, atoms: *const IndexSet<Atom>) {
+    }
+
     #[inline]
     pub fn reset(&mut self) {
         self.pending_input.reset_buffer();
@@ -148,6 +169,7 @@ impl ReadlineStream {
         pending_input.set_position(0);
     }
 
+    #[cfg(feature = "repl")]
     fn call_readline(&mut self) -> std::io::Result<usize> {
         match self.rl.readline(get_prompt()) {
             Ok(text) => {
@@ -175,6 +197,12 @@ impl ReadlineStream {
         }
     }
 
+    #[cfg(not(feature = "repl"))]
+    fn call_readline(&mut self) -> std::io::Result<usize> {
+        Ok(0)
+    }
+
+    #[cfg(feature = "repl")]
     fn save_history(&mut self) {
         if !self.add_history {
             return;
@@ -191,6 +219,10 @@ impl ReadlineStream {
         }
     }
 
+    #[cfg(not(feature = "repl"))]
+    fn save_history(&mut self) {
+    }
+
     #[inline]
     pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
         let bytes = self.pending_input.refresh_buffer()?;