diff --git a/src/commands/macros.rs b/src/commands/macros.rs index bb5e96d0..5a47ffe0 100644 --- a/src/commands/macros.rs +++ b/src/commands/macros.rs @@ -262,7 +262,9 @@ macro_rules! command { Extract { $($extract:tt)* { use std::convert::TryInto; - $args.expect_nth($($positional_count)*)?.try_into()? + let value = $args.expect_nth($($positional_count)*)?; + let value = $param_kind.check(value)?; + value.extract() } } ); diff --git a/src/commands/open.rs b/src/commands/open.rs index a37f5f37..34a6490d 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,7 +1,6 @@ use crate::errors::ShellError; use crate::object::{Primitive, Switch, Value}; use crate::parser::parse::span::Span; -use crate::parser::registry::NamedType; use crate::prelude::*; use mime::Mime; use std::path::{Path, PathBuf}; diff --git a/src/commands/where_.rs b/src/commands/where_.rs index dca4816a..9ea08b4f 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -1,5 +1,5 @@ use crate::errors::ShellError; -use crate::object::Block; +use crate::object::types::*; use crate::prelude::*; use futures::future::ready; use log::trace; diff --git a/src/object/base.rs b/src/object/base.rs index 1125cc5a..54693314 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -149,11 +149,6 @@ impl Deserialize<'de> for Block { D: Deserializer<'de>, { unimplemented!("deserialize block") - // let s = "\"unimplemented deserialize block\""; - // Ok(Block::new( - // TokenTreeBuilder::spanned_string((1, s.len() - 1), (0, s.len())), - // Text::from(s), - // )) } } diff --git a/src/object/types.rs b/src/object/types.rs index 34055e0b..3d026772 100644 --- a/src/object/types.rs +++ b/src/object/types.rs @@ -1,7 +1,86 @@ +use crate::object::base as value; +use crate::parser::hir; +use crate::prelude::*; use derive_new::new; use serde_derive::{Deserialize, Serialize}; -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] -pub enum Type { - Any, +pub trait Type: std::fmt::Debug + Send { + fn name(&self) -> &'static str; + fn check(&self, value: Spanned) -> Result, ShellError>; + fn coerce(&self) -> Option { + None + } +} + +pub trait ExtractType: Type { + fn extract(value: Value) -> T; +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] +pub struct Any; + +impl Type for Any { + fn name(&self) -> &'static str { + "Any" + } + + fn check(&self, value: Spanned) -> Result, ShellError> { + Ok(value) + } +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] +pub struct Integer; + +impl Type for Integer { + fn name(&self) -> &'static str { + "Integer" + } + + fn check(&self, value: Spanned) -> Result, ShellError> { + match value { + v @ Spanned { + item: Value::Primitive(Primitive::Int(_)), + .. + } => Ok(v), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), + } + } +} + +impl ExtractType for Integer { + fn extract(value: Value) -> i64 { + match value { + Value::Primitive(Primitive::Int(int)) => int, + _ => unreachable!("invariant: must check before extract"), + } + } +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] +pub struct Block; + +impl Type for Block { + fn name(&self) -> &'static str { + "Block" + } + + fn check(&self, value: Spanned) -> Result, ShellError> { + match value { + v @ Spanned { + item: Value::Block(_), + .. + } => Ok(v), + other => Err(ShellError::type_error("Block", other.spanned_type_name())), + } + } +} + +impl ExtractType for Block { + fn extract(value: Value) -> value::Block { + match value { + Value::Block(block) => block, + _ => unreachable!("invariant: must check before extract"), + } + } } diff --git a/src/prelude.rs b/src/prelude.rs index 7a9db241..9c79787c 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -40,7 +40,9 @@ crate use crate::context::Context; crate use crate::env::host::handle_unexpected; crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; +crate use crate::object::types::{ExtractType, Type}; crate use crate::object::{Primitive, Value}; +crate use crate::parser::{Span, Spanned}; crate use crate::stream::{InputStream, OutputStream}; crate use crate::Text; crate use futures::stream::BoxStream;