Expand builder (#20)
* Add bool method * Add proptest * Add some more consts and stuff * Refactor Lambda stuff out * REfactor * Convert bytestring test to prop test * Add string constant * Add char stuff, despite it not being ready * Add unit * Add var * Add delay * Add apply * Add force * Add error * Add builtin * Add example, remove feature * Rename some stuff Co-authored-by: Turner <mitch@tpfs.io>
This commit is contained in:
parent
7f70ae0f74
commit
ada7b00b49
|
@ -40,12 +40,33 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-set"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -91,6 +112,15 @@ dependencies = [
|
||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flat-rs"
|
name = "flat-rs"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
|
@ -99,6 +129,23 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
|
@ -136,6 +183,15 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -157,6 +213,15 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.0.1"
|
version = "6.0.1"
|
||||||
|
@ -190,6 +255,12 @@ version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f"
|
checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pretty"
|
name = "pretty"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
|
@ -235,6 +306,38 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proptest"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set",
|
||||||
|
"bitflags",
|
||||||
|
"byteorder",
|
||||||
|
"lazy_static",
|
||||||
|
"num-traits",
|
||||||
|
"quick-error 2.0.1",
|
||||||
|
"rand",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_xorshift",
|
||||||
|
"regex-syntax",
|
||||||
|
"rusty-fork",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
@ -244,6 +347,81 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_xorshift"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.2.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remove_dir_all"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusty-fork"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"quick-error 1.2.3",
|
||||||
|
"tempfile",
|
||||||
|
"wait-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -261,6 +439,20 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"remove_dir_all",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
@ -322,6 +514,7 @@ dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"peg",
|
"peg",
|
||||||
"pretty",
|
"pretty",
|
||||||
|
"proptest",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -331,6 +524,21 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
|
@ -19,5 +19,9 @@ peg = "0.8.0"
|
||||||
pretty = "0.11.3"
|
pretty = "0.11.3"
|
||||||
thiserror = "1.0.31"
|
thiserror = "1.0.31"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
hex = "0.4.3"
|
||||||
|
proptest = "1.0.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
unstable = []
|
unstable = []
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
use uplc::program_builder::{Builder, WithLambda, WithTerm, WithVar};
|
||||||
|
|
||||||
|
trait WithIdentity: WithTerm + WithLambda + WithVar {
|
||||||
|
fn with_identity(self, name_str: &str) -> Self::Next {
|
||||||
|
self.with_lambda(name_str).with_var(name_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithIdentity for T {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let my_var = "some_var";
|
||||||
|
let program = Builder::start(1, 2, 3).with_identity(my_var).build_named();
|
||||||
|
println!("{:#?}", program);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Seeds for failure cases proptest has generated in the past. It is
|
||||||
|
# automatically read and these particular cases re-run before any
|
||||||
|
# novel cases are generated.
|
||||||
|
#
|
||||||
|
# It is recommended to check this file in to source control so that
|
||||||
|
# everyone who runs the test benefits from these saved cases.
|
||||||
|
cc a6cf04d97e92892f9c9342f5df205d81b7d686231ba69c9f36ba1166bd21d9a7 # shrinks to int = 0
|
||||||
|
cc ccfa96fb2d6133adc65044ad94e69d282fa104c68128782ecfa2badb8c79b12c # shrinks to some_string = "\""
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Seeds for failure cases proptest has generated in the past. It is
|
||||||
|
# automatically read and these particular cases re-run before any
|
||||||
|
# novel cases are generated.
|
||||||
|
#
|
||||||
|
# It is recommended to check this file in to source control so that
|
||||||
|
# everyone who runs the test benefits from these saved cases.
|
||||||
|
cc db95a6ed96ee7cee987ba4b71bc6ffa9cf5abe295fa57a0eade27ed47335c1a3 # shrinks to maj = 0, min = 0, patch = 0
|
|
@ -4,6 +4,4 @@ mod debruijn;
|
||||||
mod flat;
|
mod flat;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
mod pretty;
|
mod pretty;
|
||||||
|
|
||||||
#[cfg(any(feature = "unstable", test))]
|
|
||||||
pub mod program_builder;
|
pub mod program_builder;
|
||||||
|
|
|
@ -1,27 +1,70 @@
|
||||||
#![cfg_attr(test, allow(non_snake_case))]
|
#![cfg_attr(test, allow(non_snake_case))]
|
||||||
|
|
||||||
use crate::ast::{Constant, Name, Program, Term, Unique};
|
use crate::ast::{Name, Program, Term, Unique};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
mod apply;
|
||||||
|
mod builtin;
|
||||||
|
mod constant;
|
||||||
|
mod delay;
|
||||||
|
mod error;
|
||||||
|
mod force;
|
||||||
|
mod lambda;
|
||||||
|
mod var;
|
||||||
|
|
||||||
|
pub use apply::*;
|
||||||
|
pub use builtin::*;
|
||||||
|
pub use constant::*;
|
||||||
|
pub use delay::*;
|
||||||
|
pub use error::*;
|
||||||
|
pub use force::*;
|
||||||
|
pub use lambda::*;
|
||||||
|
pub use var::*;
|
||||||
|
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
version: (usize, usize, usize),
|
version: (usize, usize, usize),
|
||||||
term: Term<Name>,
|
term: Term<Name>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NeedsTerm {
|
struct Context {
|
||||||
version: (usize, usize, usize),
|
next_unique: isize,
|
||||||
// TODO: Hide these two behind interface
|
names: HashMap<String, Unique>,
|
||||||
next_unique: Cell<isize>,
|
|
||||||
names: RefCell<HashMap<String, Unique>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LambdaBuilder<T> {
|
impl Context {
|
||||||
outer: T,
|
pub fn new() -> Context {
|
||||||
parameter_name: Name,
|
Context {
|
||||||
|
next_unique: 0,
|
||||||
|
names: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&mut self, name_str: &str) -> Name {
|
||||||
|
if let Some(unique) = self.names.get(name_str) {
|
||||||
|
Name {
|
||||||
|
text: name_str.to_string(),
|
||||||
|
unique: *unique,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let next_unique = self.next_unique;
|
||||||
|
self.next_unique = next_unique + 1;
|
||||||
|
let unique = Unique::new(next_unique);
|
||||||
|
self.names.insert(name_str.to_string(), unique);
|
||||||
|
Name {
|
||||||
|
text: name_str.to_string(),
|
||||||
|
unique,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Core {
|
||||||
|
version: (usize, usize, usize),
|
||||||
|
ctx: RefCell<Context>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WithTerm
|
pub trait WithTerm
|
||||||
|
@ -32,22 +75,9 @@ where
|
||||||
|
|
||||||
fn next(self, term: Term<Name>) -> Self::Next;
|
fn next(self, term: Term<Name>) -> Self::Next;
|
||||||
fn get_name(&self, name_str: &str) -> Name;
|
fn get_name(&self, name_str: &str) -> Name;
|
||||||
|
|
||||||
fn with_constant_int(self, int: isize) -> Self::Next {
|
|
||||||
let term = Term::Constant(Constant::Integer(int));
|
|
||||||
self.next(term)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_lambda(self, name_str: &str) -> LambdaBuilder<Self> {
|
|
||||||
let parameter_name = self.get_name(name_str);
|
|
||||||
LambdaBuilder {
|
|
||||||
outer: self,
|
|
||||||
parameter_name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WithTerm for NeedsTerm {
|
impl WithTerm for Core {
|
||||||
type Next = Builder;
|
type Next = Builder;
|
||||||
fn next(self, term: Term<Name>) -> Self::Next {
|
fn next(self, term: Term<Name>) -> Self::Next {
|
||||||
Builder {
|
Builder {
|
||||||
|
@ -57,48 +87,17 @@ impl WithTerm for NeedsTerm {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_name(&self, name_str: &str) -> Name {
|
fn get_name(&self, name_str: &str) -> Name {
|
||||||
let mut names = self.names.borrow_mut();
|
let mut ctx = self.ctx.borrow_mut();
|
||||||
if let Some(unique) = names.get(name_str) {
|
ctx.get_name(name_str)
|
||||||
Name {
|
|
||||||
text: name_str.to_string(),
|
|
||||||
unique: *unique,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let next_unique = self.next_unique.get();
|
|
||||||
self.next_unique.set(next_unique + 1);
|
|
||||||
let unique = Unique::new(next_unique);
|
|
||||||
names.insert(name_str.to_string(), unique);
|
|
||||||
Name {
|
|
||||||
text: name_str.to_string(),
|
|
||||||
unique,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WithTerm> WithTerm for LambdaBuilder<T> {
|
|
||||||
type Next = T::Next;
|
|
||||||
|
|
||||||
fn next(self, term: Term<Name>) -> Self::Next {
|
|
||||||
let term = Term::Lambda {
|
|
||||||
parameter_name: self.parameter_name,
|
|
||||||
body: Box::new(term),
|
|
||||||
};
|
|
||||||
self.outer.next(term)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_name(&self, name_str: &str) -> Name {
|
|
||||||
self.outer.get_name(name_str)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
#[allow(clippy::new_ret_no_self)]
|
/// Max: `9223372036854775807`
|
||||||
pub fn new(maj: usize, min: usize, patch: usize) -> NeedsTerm {
|
pub fn start(maj: usize, min: usize, patch: usize) -> Core {
|
||||||
NeedsTerm {
|
Core {
|
||||||
version: (maj, min, patch),
|
version: (maj, min, patch),
|
||||||
next_unique: Cell::new(0),
|
ctx: RefCell::new(Context::new()),
|
||||||
names: RefCell::new(HashMap::new()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
use crate::ast::{Name, Term};
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub struct ApplyBuilderFunction<T> {
|
||||||
|
outer: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ApplyBuilderArgument<T> {
|
||||||
|
outer: T,
|
||||||
|
function: Term<Name>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithTerm for ApplyBuilderFunction<T> {
|
||||||
|
type Next = ApplyBuilderArgument<T>;
|
||||||
|
|
||||||
|
fn next(self, term: Term<Name>) -> Self::Next {
|
||||||
|
ApplyBuilderArgument {
|
||||||
|
outer: self.outer,
|
||||||
|
function: term,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self, name_str: &str) -> Name {
|
||||||
|
self.outer.get_name(name_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithTerm for ApplyBuilderArgument<T> {
|
||||||
|
type Next = T::Next;
|
||||||
|
|
||||||
|
fn next(self, term: Term<Name>) -> Self::Next {
|
||||||
|
let term = Term::Apply {
|
||||||
|
function: Box::new(self.function),
|
||||||
|
argument: Box::new(term),
|
||||||
|
};
|
||||||
|
self.outer.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self, name_str: &str) -> Name {
|
||||||
|
self.outer.get_name(name_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WithApply: WithTerm {
|
||||||
|
fn with_apply(self) -> ApplyBuilderFunction<Self> {
|
||||||
|
ApplyBuilderFunction { outer: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a naive blanket impl. If needed, we can control which states of the builder can
|
||||||
|
// call this by implementing manually.
|
||||||
|
impl<T: WithTerm> WithApply for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::{Builder, WithConstant, WithLambda, WithVar};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_apply() {
|
||||||
|
let my_var = "i_0";
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
[(lam i_0 i_0) (con integer 1)]
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_apply()
|
||||||
|
.with_lambda(my_var)
|
||||||
|
.with_var(my_var)
|
||||||
|
.with_int(1)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_apply__with_lambda_as_arg() {
|
||||||
|
let my_var = "i_0";
|
||||||
|
let their_var = "i_1";
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
[(lam i_0 i_0) (lam i_1 (con integer 1))]
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_apply()
|
||||||
|
.with_lambda(my_var)
|
||||||
|
.with_var(my_var)
|
||||||
|
.with_lambda(their_var)
|
||||||
|
.with_int(1)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
use crate::ast::Term;
|
||||||
|
use crate::builtins::DefaultFunction;
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub trait WithBuiltin: WithTerm {
|
||||||
|
// TODO: Add all the builtin variants explicitly
|
||||||
|
fn with_builtin(self, builtin: DefaultFunction) -> Self::Next {
|
||||||
|
let term = Term::Builtin(builtin);
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithBuiltin for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::Builder;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named() {
|
||||||
|
let code = r"(program
|
||||||
|
11.22.33
|
||||||
|
(builtin addInteger)
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33)
|
||||||
|
.with_builtin(DefaultFunction::AddInteger)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
use crate::ast::{Constant, Term};
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub trait WithConstant: WithTerm {
|
||||||
|
fn with_int(self, int: isize) -> Self::Next {
|
||||||
|
let term = Term::Constant(Constant::Integer(int));
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_byte_string(self, bytes: Vec<u8>) -> Self::Next {
|
||||||
|
let term = Term::Constant(Constant::ByteString(bytes));
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_string(self, string: String) -> Self::Next {
|
||||||
|
let term = Term::Constant(Constant::String(string));
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: After https://github.com/txpipe/aiken/issues/18 is completed
|
||||||
|
// fn with_char(self, a: char) -> Self::Next {
|
||||||
|
// let term = Term::Constant(Constant::Char(a));
|
||||||
|
// self.next(term)
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn with_unit(self) -> Self::Next {
|
||||||
|
let term = Term::Constant(Constant::Unit);
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_bool(self, bool: bool) -> Self::Next {
|
||||||
|
let term = Term::Constant(Constant::Bool(bool));
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a naive blanket impl. If needed, we can control which states of the builder can
|
||||||
|
// call this by implementing manually.
|
||||||
|
impl<T: WithTerm> WithConstant for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::Builder;
|
||||||
|
use proptest::prelude::*;
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_const(
|
||||||
|
int: isize
|
||||||
|
) {
|
||||||
|
let code = format!(r"(program
|
||||||
|
11.22.33
|
||||||
|
(con integer {})
|
||||||
|
)", int);
|
||||||
|
let expected = parser::program(&code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33).with_int(int).build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_bytestring(
|
||||||
|
bytes: Vec<u8>
|
||||||
|
) {
|
||||||
|
let bstring = hex::encode(&bytes);
|
||||||
|
let code = format!(r"(program
|
||||||
|
11.22.33
|
||||||
|
(con bytestring #{})
|
||||||
|
)", bstring);
|
||||||
|
let expected = parser::program(&code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33)
|
||||||
|
.with_byte_string(bytes)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_compose! {
|
||||||
|
fn safe_string()(
|
||||||
|
some_string: String
|
||||||
|
) -> String {
|
||||||
|
some_string.chars().filter(|a| *a != '\"').collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_string(
|
||||||
|
some_string in safe_string()
|
||||||
|
) {
|
||||||
|
let code = format!(
|
||||||
|
r#"(program
|
||||||
|
11.22.33
|
||||||
|
(con string "{}")
|
||||||
|
)"#,
|
||||||
|
&some_string
|
||||||
|
);
|
||||||
|
let expected = parser::program(&code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33)
|
||||||
|
.with_string(some_string)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prop_compose! {
|
||||||
|
// fn some_char()(
|
||||||
|
// some_char: char
|
||||||
|
// ) -> char {
|
||||||
|
// some_char
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO: After https://github.com/txpipe/aiken/issues/18 is completed
|
||||||
|
// proptest! {
|
||||||
|
// #[test]
|
||||||
|
// fn build_named__with_char(
|
||||||
|
// some_char in some_char().prop_filter("Cannot be a double quote", |a| *a != '\"')
|
||||||
|
// ) {
|
||||||
|
// let char_as_string = &some_char.to_string();
|
||||||
|
// let code = format!(
|
||||||
|
// r#"(program
|
||||||
|
// 11.22.33
|
||||||
|
// (con char '{}')
|
||||||
|
// )"#,
|
||||||
|
// char_as_string
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// println!("{:#?}", &code);
|
||||||
|
// let expected = parser::program(&code).unwrap();
|
||||||
|
// let actual = Builder::start(11, 22, 33)
|
||||||
|
// .with_char(some_char)
|
||||||
|
// .build_named();
|
||||||
|
// assert_eq!(expected, actual);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_unit() {
|
||||||
|
let code = r"(program
|
||||||
|
11.22.33
|
||||||
|
(con unit ())
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33).with_unit().build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_true() {
|
||||||
|
let code = r"(program
|
||||||
|
11.22.33
|
||||||
|
(con bool True)
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33).with_bool(true).build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_false() {
|
||||||
|
let code = r"(program
|
||||||
|
11.22.33
|
||||||
|
(con bool False)
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33).with_bool(false).build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
use crate::ast::{Name, Term};
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub struct DelayBuilder<T> {
|
||||||
|
outer: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithTerm for DelayBuilder<T> {
|
||||||
|
type Next = T::Next;
|
||||||
|
|
||||||
|
fn next(self, term: Term<Name>) -> Self::Next {
|
||||||
|
let term = Term::Delay(Box::new(term));
|
||||||
|
self.outer.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self, name_str: &str) -> Name {
|
||||||
|
self.outer.get_name(name_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WithDelay: WithTerm {
|
||||||
|
fn with_delay(self) -> DelayBuilder<Self> {
|
||||||
|
DelayBuilder { outer: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a naive blanket impl. If needed, we can control which states of the builder can
|
||||||
|
// call this by implementing manually.
|
||||||
|
impl<T: WithTerm> WithDelay for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::{Builder, WithConstant, WithLambda};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_delay() {
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
(delay (con integer 1))
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_delay()
|
||||||
|
.with_int(1)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_delay__with_lambda() {
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
(delay (lam i_0 (con integer 1)))
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_delay()
|
||||||
|
.with_lambda("i_0")
|
||||||
|
.with_int(1)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
use crate::ast::Term;
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub trait WithError: WithTerm {
|
||||||
|
fn with_error(self) -> Self::Next {
|
||||||
|
let term = Term::Error;
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithError for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::Builder;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_error() {
|
||||||
|
let code = r"(program
|
||||||
|
11.22.33
|
||||||
|
(error)
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(11, 22, 33).with_error().build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
use crate::ast::{Name, Term};
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub struct ForceBuilder<T> {
|
||||||
|
outer: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithTerm for ForceBuilder<T> {
|
||||||
|
type Next = T::Next;
|
||||||
|
|
||||||
|
fn next(self, term: Term<Name>) -> Self::Next {
|
||||||
|
let term = Term::Force(Box::new(term));
|
||||||
|
self.outer.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self, name_str: &str) -> Name {
|
||||||
|
self.outer.get_name(name_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WithForce: WithTerm {
|
||||||
|
fn with_force(self) -> ForceBuilder<Self> {
|
||||||
|
ForceBuilder { outer: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a naive blanket impl. If needed, we can control which states of the builder can
|
||||||
|
// call this by implementing manually.
|
||||||
|
impl<T: WithTerm> WithForce for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::{Builder, WithConstant, WithLambda};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_force() {
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
(force (lam i_0 (con integer 1)))
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_force()
|
||||||
|
.with_lambda("i_0")
|
||||||
|
.with_int(1)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
use crate::ast::{Name, Term};
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub struct LambdaBuilder<T> {
|
||||||
|
outer: T,
|
||||||
|
parameter_name: Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WithTerm> WithTerm for LambdaBuilder<T> {
|
||||||
|
type Next = T::Next;
|
||||||
|
|
||||||
|
fn next(self, term: Term<Name>) -> Self::Next {
|
||||||
|
let term = Term::Lambda {
|
||||||
|
parameter_name: self.parameter_name,
|
||||||
|
body: Box::new(term),
|
||||||
|
};
|
||||||
|
self.outer.next(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self, name_str: &str) -> Name {
|
||||||
|
self.outer.get_name(name_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WithLambda: WithTerm {
|
||||||
|
fn with_lambda(self, name_str: &str) -> LambdaBuilder<Self> {
|
||||||
|
let parameter_name = self.get_name(name_str);
|
||||||
|
LambdaBuilder {
|
||||||
|
outer: self,
|
||||||
|
parameter_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a naive blanket impl. If needed, we can control which states of the builder can
|
||||||
|
// call this by implementing manually.
|
||||||
|
impl<T: WithTerm> WithLambda for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::constant::WithConstant;
|
||||||
|
use crate::program_builder::Builder;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_lam() {
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
(lam i_0 (con integer 1))
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_lambda("i_0")
|
||||||
|
.with_int(1)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_nested_lam() {
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
(lam i_0 (lam i_1 (con integer 1)))
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_lambda("i_0")
|
||||||
|
.with_lambda("i_1")
|
||||||
|
.with_int(1)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,64 +1,32 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::parser;
|
use crate::parser;
|
||||||
|
use crate::program_builder::constant::WithConstant;
|
||||||
|
use proptest::prelude::*;
|
||||||
|
|
||||||
#[test]
|
prop_compose! {
|
||||||
fn build_named__with_const() {
|
fn arb_version()(
|
||||||
let code = r"(program
|
maj: isize,
|
||||||
11.22.33
|
min: isize,
|
||||||
|
patch: isize,
|
||||||
|
) -> (usize, usize, usize){
|
||||||
|
let maj = maj.abs() as usize;
|
||||||
|
let min = min.abs() as usize;
|
||||||
|
let patch = patch.abs() as usize;
|
||||||
|
(maj, min, patch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_version(
|
||||||
|
(maj, min, patch) in arb_version(),
|
||||||
|
) {
|
||||||
|
let code = format!(r"(program
|
||||||
|
{}.{}.{}
|
||||||
(con integer 11)
|
(con integer 11)
|
||||||
)";
|
)", maj, min, patch);
|
||||||
let expected = parser::program(code).unwrap();
|
let expected = parser::program(&code).unwrap();
|
||||||
let actual = Builder::new(11, 22, 33).with_constant_int(11).build_named();
|
let actual = Builder::start(maj, min, patch).with_int(11).build_named();
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn build_named__with_different_const() {
|
|
||||||
let code = r"(program
|
|
||||||
11.22.33
|
|
||||||
(con integer 22)
|
|
||||||
)";
|
|
||||||
let expected = parser::program(code).unwrap();
|
|
||||||
let actual = Builder::new(11, 22, 33).with_constant_int(22).build_named();
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn build_named__with_const_different_version() {
|
|
||||||
let code = r"(program
|
|
||||||
44.55.66
|
|
||||||
(con integer 11)
|
|
||||||
)";
|
|
||||||
let expected = parser::program(code).unwrap();
|
|
||||||
let actual = Builder::new(44, 55, 66).with_constant_int(11).build_named();
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn build_named__with_lam() {
|
|
||||||
let code = r"(program
|
|
||||||
1.2.3
|
|
||||||
(lam i_0 (con integer 1))
|
|
||||||
)";
|
|
||||||
let expected = parser::program(code).unwrap();
|
|
||||||
let actual = Builder::new(1, 2, 3)
|
|
||||||
.with_lambda("i_0")
|
|
||||||
.with_constant_int(1)
|
|
||||||
.build_named();
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn build_named__with_nested_lam() {
|
|
||||||
let code = r"(program
|
|
||||||
1.2.3
|
|
||||||
(lam i_0 (lam i_1 (con integer 1)))
|
|
||||||
)";
|
|
||||||
let expected = parser::program(code).unwrap();
|
|
||||||
let actual = Builder::new(1, 2, 3)
|
|
||||||
.with_lambda("i_0")
|
|
||||||
.with_lambda("i_1")
|
|
||||||
.with_constant_int(1)
|
|
||||||
.build_named();
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
use crate::ast::Term;
|
||||||
|
use crate::program_builder::WithTerm;
|
||||||
|
|
||||||
|
pub trait WithVar: WithTerm {
|
||||||
|
fn with_var(self, name_str: &str) -> Self::Next {
|
||||||
|
let name = self.get_name(name_str);
|
||||||
|
let term = Term::Var(name);
|
||||||
|
self.next(term)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a naive blanket impl. If needed, we can control which states of the builder can
|
||||||
|
// call this by implementing manually.
|
||||||
|
impl<T: WithTerm> WithVar for T {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser;
|
||||||
|
use crate::program_builder::{Builder, WithLambda};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_named__with_var() {
|
||||||
|
let var_name = "i_0";
|
||||||
|
let code = r"(program
|
||||||
|
1.2.3
|
||||||
|
(lam i_0 i_0)
|
||||||
|
)";
|
||||||
|
let expected = parser::program(code).unwrap();
|
||||||
|
let actual = Builder::start(1, 2, 3)
|
||||||
|
.with_lambda(var_name)
|
||||||
|
.with_var(var_name)
|
||||||
|
.build_named();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue