DEV: The beginnings of some shape Derivation

This commit is contained in:
Jeremy Wall 2020-05-25 10:55:42 -04:00 committed by Jeremy Wall
parent 5ae4b91004
commit a3a7ce57ee
2 changed files with 95 additions and 30 deletions

View File

@ -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<Shape, BuildError> {
// 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)

View File

@ -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,
"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),
)))),
pos: Position::new(1, 0, 0),
}),
Shape::Boolean(PositionedItem::new(true, Position::new(1, 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);
}
}