From a3a7ce57ee521905531070907f4cb4d53f001455 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Mon, 25 May 2020 10:55:42 -0400 Subject: [PATCH] DEV: The beginnings of some shape Derivation --- src/ast/mod.rs | 39 +++++++++++++++++++--- src/ast/test.rs | 86 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 95 insertions(+), 30 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d5b311a..807091c 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -30,7 +30,7 @@ use abortable_parser; use crate::build::scope::Scope; use crate::build::Val; -use crate::error::BuildError; +use crate::error::{BuildError, ErrorType::TypeFail}; pub mod printer; pub mod walk; @@ -353,7 +353,7 @@ impl Value { Value::Int(p) => Shape::Int(p.clone()), Value::Float(p) => Shape::Float(p.clone()), Value::Str(p) => Shape::Str(p.clone()), - // Symbols in a shape are placeholder. They allow a form of genericity + // Symbols in a shape are placeholders. They allow a form of genericity // in the shape. They can be any type and are only refined down. // by their presence in an expression. Value::Symbol(p) => Shape::Symbol(p.clone()), @@ -826,12 +826,43 @@ impl Expression { fn derive_shape(&self) -> Result { // FIXME(jwall): Implement this let shape = match self { - Expression::Simple(ref v) => v.try_into()?, + Expression::Simple(v) => v.try_into()?, Expression::Format(def) => { Shape::Str(PositionedItem::new("".to_owned(), def.pos.clone())) } - Expression::Not(def) => Shape::Boolean(PositionedItem::new(true, def.pos.clone())), + Expression::Not(def) => { + let shape = def.expr.as_ref().try_into()?; + if let Shape::Boolean(b) = shape { + Shape::Boolean(PositionedItem::new(!b.val, def.pos.clone())) + } else { + // TODO(jwall): Display implementations for shapes. + return Err(BuildError::new( + format!( + "Expected Boolean value in Not expression but got: {:?}", + shape + ), + TypeFail, + )); + } + } Expression::Grouped(v, _pos) => v.as_ref().try_into()?, + Expression::Range(def) => Shape::List(PositionedItem::new( + vec![Shape::Int(PositionedItem::new(0, def.start.pos().clone()))], + def.pos.clone(), + )), + Expression::Cast(def) => match def.cast_type { + CastType::Int => Shape::Int(PositionedItem::new(0, def.pos.clone())), + CastType::Str => Shape::Str(PositionedItem::new("".to_owned(), def.pos.clone())), + CastType::Float => Shape::Float(PositionedItem::new(0.0, def.pos.clone())), + CastType::Bool => Shape::Boolean(PositionedItem::new(true, def.pos.clone())), + }, + Expression::Import(def) => { + // FIXME(jwall): What should this do? + Shape::Symbol(PositionedItem::new( + def.path.fragment.clone(), + def.path.pos.clone(), + )) + } _ => Shape::Empty(Position::new(0, 0, 0)), }; Ok(shape) diff --git a/src/ast/test.rs b/src/ast/test.rs index aef79ca..efb626e 100644 --- a/src/ast/test.rs +++ b/src/ast/test.rs @@ -11,10 +11,37 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use crate::ast::{ - Expression, FormatArgs, FormatDef, ListDef, NotDef, Position, PositionedItem, Shape, Token, - TokenType, Value, -}; +use abortable_parser::iter::SliceIter; +use abortable_parser::Result as ParseResult; + +use crate::ast::{Expression, ListDef, Position, PositionedItem, Shape, Token, TokenType, Value}; +use crate::iter::OffsetStrIter; +use crate::parse::expression; +use crate::tokenizer::tokenize; + +macro_rules! assert_shape { + ($input:expr => $shape:expr) => {{ + let iter = OffsetStrIter::new($input); + let tokenized = match tokenize(iter, None) { + Ok(toks) => toks, + Err(err) => panic!(format!("failed to parse {} with error {}", $input, err)), + }; + let toks = SliceIter::new(&tokenized); + if let ParseResult::Complete(_, ref expr) = expression(toks) { + assert_eq!( + match expr.derive_shape() { + Ok(shape) => shape, + Err(err) => { + panic!(format!("failed to parse {} with error {}", $input, err)) + } + }, + $shape + ); + } else { + assert!(false, format!("failed to parse expression! {:?}", $input)); + }; + }}; +} #[test] fn derive_shape_values() { @@ -89,40 +116,47 @@ fn derive_shape_values() { fn derive_shape_expressions() { let expr_cases = vec![ ( - Expression::Simple(Value::Int(PositionedItem::new(3, Position::new(0, 0, 0)))), + "3;", Shape::Int(PositionedItem::new(3, Position::new(0, 0, 0))), ), ( - Expression::Grouped( - Box::new(Expression::Simple(Value::Int(PositionedItem::new( - 3, - Position::new(0, 0, 0), - )))), - Position::new(0, 0, 0), - ), + "(3);", Shape::Int(PositionedItem::new(3, Position::new(0, 0, 0))), ), ( - Expression::Format(FormatDef { - template: "".to_owned(), - args: FormatArgs::List(Vec::new()), - pos: Position::new(0, 0, 0), - }), + "\"foo {}\" % (1);", Shape::Str(PositionedItem::new("".to_owned(), Position::new(0, 0, 0))), ), ( - Expression::Not(NotDef { - expr: Box::new(Expression::Simple(Value::Boolean(PositionedItem::new( - true, - Position::new(0, 0, 0), - )))), - pos: Position::new(1, 0, 0), - }), - Shape::Boolean(PositionedItem::new(true, Position::new(1, 0, 0))), + "not true;", + Shape::Boolean(PositionedItem::new(false, Position::new(1, 0, 0))), + ), + ( + "0:1;", + Shape::List(PositionedItem::new( + vec![Shape::Int(PositionedItem::new(0, Position::new(0, 0, 0)))], + Position::new(0, 0, 0), + )), + ), + ( + "int(\"1\");", + Shape::Int(PositionedItem::new(0, Position::new(0, 0, 0))), + ), + ( + "float(1);", + Shape::Float(PositionedItem::new(0.0, Position::new(0, 0, 0))), + ), + ( + "str(1);", + Shape::Str(PositionedItem::new("".to_owned(), Position::new(0, 0, 0))), + ), + ( + "bool(\"true\");", + Shape::Boolean(PositionedItem::new(true, Position::new(0, 0, 0))), ), ]; for (expr, shape) in expr_cases { - assert_eq!(expr.derive_shape().unwrap(), shape); + assert_shape!(expr => shape); } }