mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-21 18:10:42 -04:00
DEV: AST enum for a shape.
This commit is contained in:
parent
2b835e5886
commit
3d34355fe7
128
src/ast/mod.rs
128
src/ast/mod.rs
@ -19,7 +19,7 @@ use std::cmp::Eq;
|
||||
use std::cmp::Ordering;
|
||||
use std::cmp::PartialEq;
|
||||
use std::cmp::PartialOrd;
|
||||
use std::convert::Into;
|
||||
use std::convert::{Into, TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
@ -30,6 +30,7 @@ use abortable_parser;
|
||||
|
||||
use crate::build::scope::Scope;
|
||||
use crate::build::Val;
|
||||
use crate::error::BuildError;
|
||||
|
||||
pub mod printer;
|
||||
pub mod walk;
|
||||
@ -218,21 +219,58 @@ macro_rules! make_expr {
|
||||
/// This is usually used as the body of a tuple in the UCG AST.
|
||||
pub type FieldList = Vec<(Token, Expression)>; // Token is expected to be a symbol
|
||||
|
||||
/// Represents a Value in the UCG parsed AST.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Value {
|
||||
// Constant Values
|
||||
Empty(Position),
|
||||
Boolean(PositionedItem<bool>),
|
||||
Int(PositionedItem<i64>),
|
||||
Float(PositionedItem<f64>),
|
||||
Str(PositionedItem<String>),
|
||||
Symbol(PositionedItem<String>),
|
||||
// Complex Values
|
||||
Tuple(PositionedItem<FieldList>),
|
||||
List(ListDef),
|
||||
pub type ShapeTuple = Vec<(Token, Shape)>;
|
||||
pub type ShapeList = Vec<Shape>;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct FuncShapeDef {
|
||||
args: Vec<Shape>,
|
||||
ret: Box<Shape>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct ModuleShapeDef {
|
||||
items: ShapeTuple,
|
||||
ret: Box<Shape>,
|
||||
}
|
||||
|
||||
macro_rules! value_enum {
|
||||
($doc:meta $i:tt, $t:ty, $l:ty, $($extra:tt)*) => {
|
||||
#[$doc]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum $i {
|
||||
// Simple Values
|
||||
Empty(Position),
|
||||
Boolean(PositionedItem<bool>),
|
||||
Int(PositionedItem<i64>),
|
||||
Float(PositionedItem<f64>),
|
||||
Str(PositionedItem<String>),
|
||||
Symbol(PositionedItem<String>),
|
||||
// Complex Values
|
||||
Tuple(PositionedItem<$t>),
|
||||
List($l),
|
||||
// Extra items
|
||||
$( $extra )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value_enum!(
|
||||
doc="Value types represent the Values that UCG can have."
|
||||
Value,
|
||||
FieldList,
|
||||
ListDef,
|
||||
);
|
||||
|
||||
value_enum!(
|
||||
doc="Shapes represent the types that UCG values or expressions can have."
|
||||
Shape,
|
||||
ShapeTuple,
|
||||
PositionedItem<ShapeList>,
|
||||
Func(FuncShapeDef),
|
||||
Module(ModuleShapeDef),
|
||||
);
|
||||
|
||||
impl Value {
|
||||
/// Returns the type name of the Value it is called on as a string.
|
||||
pub fn type_name(&self) -> String {
|
||||
@ -307,6 +345,43 @@ impl Value {
|
||||
&Value::List(_)
|
||||
)
|
||||
}
|
||||
|
||||
fn derive_shape(&self) -> Result<Shape, BuildError> {
|
||||
let shape = match self {
|
||||
Value::Empty(p) => Shape::Empty(p.clone()),
|
||||
Value::Boolean(p) => Shape::Boolean(p.clone()),
|
||||
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
|
||||
// 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()),
|
||||
Value::Tuple(flds) => {
|
||||
let mut field_shapes = Vec::new();
|
||||
for &(ref tok, ref expr) in &flds.val {
|
||||
field_shapes.push((tok.clone(), expr.try_into()?));
|
||||
}
|
||||
Shape::Tuple(PositionedItem::new(field_shapes, flds.pos.clone()))
|
||||
}
|
||||
Value::List(flds) => {
|
||||
let mut field_shapes = Vec::new();
|
||||
for f in &flds.elems {
|
||||
field_shapes.push(f.try_into()?);
|
||||
}
|
||||
Shape::List(PositionedItem::new(field_shapes, flds.pos.clone()))
|
||||
}
|
||||
};
|
||||
Ok(shape)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Value> for Shape {
|
||||
type Error = crate::error::BuildError;
|
||||
|
||||
fn try_from(v: &Value) -> Result<Self, Self::Error> {
|
||||
v.derive_shape()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an expansion of a Macro that is expected to already have been
|
||||
@ -769,6 +844,28 @@ impl Expression {
|
||||
&Expression::Debug(ref def) => &def.pos,
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_shape(&self) -> Result<Shape, BuildError> {
|
||||
// FIXME(jwall): Implement this
|
||||
let shape = match self {
|
||||
Expression::Simple(ref 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::Grouped(v, _pos) => v.as_ref().try_into()?,
|
||||
_ => Shape::Empty(Position::new(0, 0, 0)),
|
||||
};
|
||||
Ok(shape)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Expression> for Shape {
|
||||
type Error = crate::error::BuildError;
|
||||
|
||||
fn try_from(e: &Expression) -> Result<Self, Self::Error> {
|
||||
e.derive_shape()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Expression {
|
||||
@ -868,3 +965,6 @@ impl Statement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
128
src/ast/test.rs
Normal file
128
src/ast/test.rs
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2020 Jeremy Wall
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// 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,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn derive_shape_values() {
|
||||
let value_cases = vec![
|
||||
(
|
||||
Value::Empty(Position::new(0, 0, 0)),
|
||||
Shape::Empty(Position::new(0, 0, 0)),
|
||||
),
|
||||
(
|
||||
Value::Boolean(PositionedItem::new(false, Position::new(0, 1, 2))),
|
||||
Shape::Boolean(PositionedItem::new(false, Position::new(0, 1, 2))),
|
||||
),
|
||||
(
|
||||
Value::Boolean(PositionedItem::new(true, Position::new(0, 1, 2))),
|
||||
Shape::Boolean(PositionedItem::new(true, Position::new(0, 1, 2))),
|
||||
),
|
||||
(
|
||||
Value::Int(PositionedItem::new(1, Position::new(0, 1, 2))),
|
||||
Shape::Int(PositionedItem::new(1, Position::new(0, 1, 2))),
|
||||
),
|
||||
(
|
||||
Value::Float(PositionedItem::new(2.0, Position::new(0, 1, 2))),
|
||||
Shape::Float(PositionedItem::new(2.0, Position::new(0, 1, 2))),
|
||||
),
|
||||
(
|
||||
Value::Str(PositionedItem::new(
|
||||
"foo".to_owned(),
|
||||
Position::new(0, 1, 2),
|
||||
)),
|
||||
Shape::Str(PositionedItem::new(
|
||||
"foo".to_owned(),
|
||||
Position::new(0, 1, 2),
|
||||
)),
|
||||
),
|
||||
(
|
||||
Value::Tuple(PositionedItem::new(
|
||||
vec![(
|
||||
Token::new("foo", TokenType::BAREWORD, Position::new(0, 0, 0)),
|
||||
Expression::Simple(Value::Int(PositionedItem::new(3, Position::new(0, 0, 0)))),
|
||||
)],
|
||||
Position::new(0, 0, 0),
|
||||
)),
|
||||
Shape::Tuple(PositionedItem::new(
|
||||
vec![(
|
||||
Token::new("foo", TokenType::BAREWORD, Position::new(0, 0, 0)),
|
||||
Shape::Int(PositionedItem::new(3, Position::new(0, 0, 0))),
|
||||
)],
|
||||
Position::new(0, 0, 0),
|
||||
)),
|
||||
),
|
||||
(
|
||||
Value::List(ListDef {
|
||||
elems: vec![Expression::Simple(Value::Int(PositionedItem::new(
|
||||
3,
|
||||
Position::new(0, 0, 0),
|
||||
)))],
|
||||
pos: Position::new(0, 0, 0),
|
||||
}),
|
||||
Shape::List(PositionedItem::new(
|
||||
vec![Shape::Int(PositionedItem::new(3, Position::new(0, 0, 0)))],
|
||||
Position::new(0, 0, 0),
|
||||
)),
|
||||
),
|
||||
];
|
||||
|
||||
for (val, shape) in value_cases {
|
||||
assert_eq!(val.derive_shape().unwrap(), shape);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_shape_expressions() {
|
||||
let expr_cases = vec![
|
||||
(
|
||||
Expression::Simple(Value::Int(PositionedItem::new(3, Position::new(0, 0, 0)))),
|
||||
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),
|
||||
),
|
||||
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),
|
||||
}),
|
||||
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))),
|
||||
),
|
||||
];
|
||||
|
||||
for (expr, shape) in expr_cases {
|
||||
assert_eq!(expr.derive_shape().unwrap(), shape);
|
||||
}
|
||||
}
|
@ -402,6 +402,8 @@ impl AST {
|
||||
Expression::Func(def) => {
|
||||
ops.push(Op::InitList, def.pos.clone());
|
||||
for b in def.argdefs {
|
||||
// FIXME(jwall): if there is a projection
|
||||
// then add the projection check here?
|
||||
ops.push(Op::Sym(b.val), b.pos.clone());
|
||||
ops.push(Op::Element, b.pos);
|
||||
}
|
||||
@ -460,6 +462,8 @@ impl AST {
|
||||
// Init our module tuple bindings
|
||||
ops.push(Op::InitTuple, def.pos.clone());
|
||||
for (t, e) in argset {
|
||||
// FIXME(jwall): if there is a projection
|
||||
// then add the projection check here?
|
||||
ops.push(Op::Sym(t.fragment), t.pos.clone());
|
||||
Self::translate_expr(e, &mut ops, root);
|
||||
ops.push(Op::Field, t.pos);
|
||||
|
Loading…
x
Reference in New Issue
Block a user