mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
DEV: AST enum for a shape.
This commit is contained in:
parent
2b835e5886
commit
3d34355fe7
114
src/ast/mod.rs
114
src/ast/mod.rs
@ -19,7 +19,7 @@ use std::cmp::Eq;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::cmp::PartialOrd;
|
use std::cmp::PartialOrd;
|
||||||
use std::convert::Into;
|
use std::convert::{Into, TryFrom, TryInto};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
@ -30,6 +30,7 @@ use abortable_parser;
|
|||||||
|
|
||||||
use crate::build::scope::Scope;
|
use crate::build::scope::Scope;
|
||||||
use crate::build::Val;
|
use crate::build::Val;
|
||||||
|
use crate::error::BuildError;
|
||||||
|
|
||||||
pub mod printer;
|
pub mod printer;
|
||||||
pub mod walk;
|
pub mod walk;
|
||||||
@ -218,10 +219,27 @@ macro_rules! make_expr {
|
|||||||
/// This is usually used as the body of a tuple in the UCG AST.
|
/// 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
|
pub type FieldList = Vec<(Token, Expression)>; // Token is expected to be a symbol
|
||||||
|
|
||||||
/// Represents a Value in the UCG parsed AST.
|
pub type ShapeTuple = Vec<(Token, Shape)>;
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
pub type ShapeList = Vec<Shape>;
|
||||||
pub enum Value {
|
|
||||||
// Constant Values
|
#[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),
|
Empty(Position),
|
||||||
Boolean(PositionedItem<bool>),
|
Boolean(PositionedItem<bool>),
|
||||||
Int(PositionedItem<i64>),
|
Int(PositionedItem<i64>),
|
||||||
@ -229,10 +247,30 @@ pub enum Value {
|
|||||||
Str(PositionedItem<String>),
|
Str(PositionedItem<String>),
|
||||||
Symbol(PositionedItem<String>),
|
Symbol(PositionedItem<String>),
|
||||||
// Complex Values
|
// Complex Values
|
||||||
Tuple(PositionedItem<FieldList>),
|
Tuple(PositionedItem<$t>),
|
||||||
List(ListDef),
|
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 {
|
impl Value {
|
||||||
/// Returns the type name of the Value it is called on as a string.
|
/// Returns the type name of the Value it is called on as a string.
|
||||||
pub fn type_name(&self) -> String {
|
pub fn type_name(&self) -> String {
|
||||||
@ -307,6 +345,43 @@ impl Value {
|
|||||||
&Value::List(_)
|
&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
|
/// 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,
|
&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 {
|
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) => {
|
Expression::Func(def) => {
|
||||||
ops.push(Op::InitList, def.pos.clone());
|
ops.push(Op::InitList, def.pos.clone());
|
||||||
for b in def.argdefs {
|
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::Sym(b.val), b.pos.clone());
|
||||||
ops.push(Op::Element, b.pos);
|
ops.push(Op::Element, b.pos);
|
||||||
}
|
}
|
||||||
@ -460,6 +462,8 @@ impl AST {
|
|||||||
// Init our module tuple bindings
|
// Init our module tuple bindings
|
||||||
ops.push(Op::InitTuple, def.pos.clone());
|
ops.push(Op::InitTuple, def.pos.clone());
|
||||||
for (t, e) in argset {
|
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());
|
ops.push(Op::Sym(t.fragment), t.pos.clone());
|
||||||
Self::translate_expr(e, &mut ops, root);
|
Self::translate_expr(e, &mut ops, root);
|
||||||
ops.push(Op::Field, t.pos);
|
ops.push(Op::Field, t.pos);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user