diff --git a/Cargo.lock b/Cargo.lock index 0168fe9..eef6e70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,6 +29,54 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "ariadne" version = "0.4.0" @@ -65,12 +113,68 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9c28d4e5dd9a9262a38b231153591da6ce1471b818233f4727985d3dd0ed93c" dependencies = [ "hashbrown", - "regex-automata", + "regex-automata 0.3.9", "serde", "stacker", "unicode-ident", ] +[[package]] +name = "clap" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "concolor" version = "0.1.1" @@ -97,6 +201,32 @@ version = "0.5.0" dependencies = [ "ariadne", "chumsky", + "clap", + "colored", + "env_logger", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", ] [[package]] @@ -109,12 +239,24 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "is-terminal" version = "0.4.12" @@ -126,12 +268,24 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + [[package]] name = "memchr" version = "2.7.1" @@ -171,6 +325,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", +] + [[package]] name = "regex-automata" version = "0.3.9" @@ -179,7 +345,18 @@ checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", ] [[package]] @@ -188,6 +365,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "serde" version = "1.0.197" @@ -221,6 +404,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "syn" version = "2.0.50" @@ -244,6 +433,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "version_check" version = "0.9.4" @@ -281,6 +476,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -305,6 +509,21 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.0" @@ -326,6 +545,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" @@ -338,6 +563,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.0" @@ -350,6 +581,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.0" @@ -362,6 +599,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.0" @@ -374,6 +617,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.0" @@ -386,6 +635,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" @@ -398,6 +653,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index b94fde4..b29a433 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,6 @@ opt-level = 3 [dependencies] ariadne = { version = "0.4.0", features = ["auto-color"] } chumsky = { version = "1.0.0-alpha.6", features = ["pratt", "label"] } +clap = { version = "4.5.2", features = ["derive"] } +colored = "2.1.0" +env_logger = "0.11.3" diff --git a/src/error.rs b/src/error.rs index 9b55da2..db6295b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,29 +1,69 @@ use std::sync::PoisonError; -use chumsky::prelude::Rich; +use ariadne::{Color, Label, Report, ReportKind}; +use chumsky::{prelude::Rich, span::SimpleSpan}; use crate::{abstract_tree::Type, lexer::Token}; #[derive(Debug, PartialEq)] -pub enum Error<'src> { - Parse(Vec>>), - Lex(Vec>), +pub enum Error { + Parse { + expected: String, + found: Option, + span: SimpleSpan, + }, + Lex { + expected: String, + found: Option, + span: SimpleSpan, + }, Runtime(RuntimeError), } -impl<'src> From>>> for Error<'src> { - fn from(errors: Vec>>) -> Self { - Error::Parse(errors) +impl Error { + pub fn report(&self, source: &str) -> Report { + match self { + Error::Parse { + expected, + found, + span, + } => Report::build(ReportKind::Custom("Parsing Error", Color::Red), (), 0).finish(), + Error::Lex { + expected, + found, + span, + } => Report::build(ReportKind::Custom("Lexing Error", Color::Red), (), 0) + .with_label(Label::new(span.start..span.end).with_message(format!( + "Exptected {expected} but found {}.", + found.unwrap_or(' '), + ))) + .finish(), + Error::Runtime(_) => todo!(), + } } } -impl<'src> From>> for Error<'src> { - fn from(errors: Vec>) -> Self { - Error::Lex(errors) +impl From> for Error { + fn from(error: Rich<'_, char>) -> Self { + Error::Lex { + expected: error.expected().map(|error| error.to_string()).collect(), + found: error.reason().found().map(|c| c.clone()), + span: error.span().clone(), + } } } -impl<'src> From for Error<'src> { +impl<'src> From>> for Error { + fn from(error: Rich<'_, Token<'src>>) -> Self { + Error::Parse { + expected: error.expected().map(|error| error.to_string()).collect(), + found: error.reason().found().map(|c| c.to_string()), + span: error.span().clone(), + } + } +} + +impl From for Error { fn from(error: RuntimeError) -> Self { Error::Runtime(error) } diff --git a/src/lexer.rs b/src/lexer.rs index 80d3bda..b302679 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -31,11 +31,11 @@ impl<'src> Display for Token<'src> { } } -pub fn lex<'src>(source: &'src str) -> Result, Error<'src>> { +pub fn lex<'src>(source: &'src str) -> Result, SimpleSpan)>, Vec> { lexer() .parse(source) .into_result() - .map_err(|error| Error::Lex(error)) + .map_err(|errors| errors.into_iter().map(|error| error.into()).collect()) } pub fn lexer<'src>() -> impl Parser< diff --git a/src/lib.rs b/src/lib.rs index 8c550bd..ab09e0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,30 +5,35 @@ pub mod lexer; pub mod parser; pub mod value; -use abstract_tree::Statement; -use chumsky::{prelude::*, Parser}; +use abstract_tree::AbstractTree; use context::Context; use error::Error; +use lexer::lex; +pub use parser::{parse, parser, DustParser}; pub use value::Value; -pub struct Interpreter

{ - _parser: P, - _context: Context, +pub struct Interpreter { + context: Context, } -impl<'src, P> Interpreter

-where - P: Parser<'src, &'src str, Statement<'src>, extra::Err>>, -{ - pub fn run(&self, _source: &'src str) -> Result> { - todo!(); +impl Interpreter { + pub fn new(context: Context) -> Self { + Interpreter { context } + } - // let final_value = self - // .parser - // .parse(source) - // .into_result()? - // .run(&self.context)?; + pub fn run(&mut self, source: &str) -> Result> { + let tokens = lex(source)?; + let statements = parse(&tokens)?; - // Ok(final_value) + let mut value = Value::none(); + + for (statement, _span) in statements { + value = match statement.run(&self.context) { + Ok(value) => value, + Err(runtime_error) => return Err(vec![Error::Runtime(runtime_error)]), + } + } + + Ok(value) } } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..49f9baf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,61 @@ +//! Command line interface for the dust programming language. + +use ariadne::Source; +use clap::Parser; +use colored::Colorize; + +use std::{fs::read_to_string, io::Write}; + +use dust_lang::{context::Context, Interpreter}; + +/// Command-line arguments to be parsed. +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Dust source code to evaluate. + #[arg(short, long)] + command: Option, + + /// Location of the file to run. + path: Option, +} + +fn main() { + env_logger::Builder::from_env("DUST_LOG") + .format(|buffer, record| { + let args = record.args(); + let log_level = record.level().to_string().bold(); + let timestamp = buffer.timestamp_seconds().to_string().dimmed(); + + writeln!(buffer, "[{log_level} {timestamp}] {args}") + }) + .init(); + + let args = Args::parse(); + let context = Context::new(); + + let source = if let Some(path) = &args.path { + read_to_string(path).unwrap() + } else if let Some(command) = args.command { + command + } else { + String::with_capacity(0) + }; + + let mut interpreter = Interpreter::new(context); + + let eval_result = interpreter.run(&source); + + match eval_result { + Ok(value) => { + if !value.is_none() { + println!("{value}") + } + } + Err(errors) => { + for error in errors { + error.report(&source).eprint(Source::from(&source)).unwrap(); + } + } + } +} diff --git a/src/parser.rs b/src/parser.rs index d7b7a44..373ffca 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -4,24 +4,27 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*}; use crate::{abstract_tree::*, error::Error, lexer::Token}; -type ParserInput<'tokens, 'src> = - SpannedInput, SimpleSpan, &'tokens [(Token<'src>, SimpleSpan)]>; +pub type DustParser<'src> = Boxed< + 'src, + 'src, + ParserInput<'src>, + Vec<(Statement<'src>, SimpleSpan)>, + extra::Err, SimpleSpan>>, +>; -pub fn parse<'tokens, 'src: 'tokens>( - tokens: &'tokens [(Token<'src>, SimpleSpan)], -) -> Result, SimpleSpan)>, Error<'tokens>> { +pub type ParserInput<'src> = + SpannedInput, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>; + +pub fn parse<'src>( + tokens: &'src [(Token<'src>, SimpleSpan)], +) -> Result, SimpleSpan)>, Vec> { parser() - .parse(tokens.spanned((0..0).into())) + .parse(tokens.spanned((tokens.len()..tokens.len()).into())) .into_result() - .map_err(|error| Error::Parse(error)) + .map_err(|errors| errors.into_iter().map(|error| error.into()).collect()) } -fn parser<'tokens, 'src: 'tokens>() -> impl Parser< - 'tokens, - ParserInput<'tokens, 'src>, - Vec<(Statement<'src>, SimpleSpan)>, - extra::Err, SimpleSpan>>, -> { +pub fn parser<'src>() -> DustParser<'src> { let identifiers: RefCell> = RefCell::new(HashMap::new()); let identifier = select! { @@ -185,6 +188,7 @@ fn parser<'tokens, 'src: 'tokens>() -> impl Parser< .map_with(|item, state| (item, state.span())) .repeated() .collect() + .boxed() } #[cfg(test)] @@ -512,7 +516,8 @@ mod tests { fn positive_integer() { for i in 0..10 { let source = i.to_string(); - let statements = parse(&lex(&source).unwrap()).unwrap(); + let tokens = lex(&source).unwrap(); + let statements = parse(&tokens).unwrap(); assert_eq!( statements[0].0, @@ -537,7 +542,8 @@ mod tests { fn negative_integer() { for i in -9..1 { let source = i.to_string(); - let statements = parse(&lex(&source).unwrap()).unwrap(); + let tokens = lex(&source).unwrap(); + let statements = parse(&tokens).unwrap(); assert_eq!( statements[0].0, diff --git a/src/value.rs b/src/value.rs index 75e70c7..98136a3 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,6 +1,7 @@ use std::{ cmp::Ordering, collections::BTreeMap, + fmt::{self, Display, Formatter}, ops::Range, sync::{Arc, OnceLock}, }; @@ -9,6 +10,15 @@ use crate::{abstract_tree::Identifier, error::ValidationError}; pub static NONE: OnceLock = OnceLock::new(); +fn get_none<'a>() -> &'a Value { + NONE.get_or_init(|| { + Value(Arc::new(ValueInner::Enum( + Identifier::new("Option"), + Identifier::new("None"), + ))) + }) +} + #[derive(Clone, Debug, PartialEq)] pub struct Value(Arc); @@ -18,13 +28,7 @@ impl Value { } pub fn none() -> Self { - NONE.get_or_init(|| { - Value(Arc::new(ValueInner::Enum( - Identifier::new("Option"), - Identifier::new("None"), - ))) - }) - .clone() + get_none().clone() } pub fn boolean(boolean: bool) -> Self { @@ -66,6 +70,27 @@ impl Value { Err(ValidationError::ExpectedBoolean) } + + pub fn is_none(&self) -> bool { + self == get_none() + } +} + +impl Display for Value { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + use ValueInner::*; + + match self.inner().as_ref() { + Boolean(boolean) => write!(f, "{boolean}"), + Float(float) => write!(f, "{float}"), + Integer(integer) => write!(f, "{integer}"), + List(_) => todo!(), + Map(_) => todo!(), + Range(_) => todo!(), + String(_) => todo!(), + Enum(_, _) => todo!(), + } + } } impl Eq for Value {}