2018-04-16 20:04:17 -05:00
|
|
|
// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
//! The definitions of the ucg AST and Tokens.
|
2018-05-22 18:02:44 -05:00
|
|
|
use std;
|
|
|
|
use std::borrow::Borrow;
|
|
|
|
use std::cmp::Eq;
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
use std::cmp::PartialEq;
|
|
|
|
use std::cmp::PartialOrd;
|
2020-04-26 12:16:20 -04:00
|
|
|
use std::convert::{Into, TryFrom, TryInto};
|
2018-11-05 21:34:12 -06:00
|
|
|
use std::fmt;
|
2018-05-22 18:02:44 -05:00
|
|
|
use std::hash::Hash;
|
|
|
|
use std::hash::Hasher;
|
2018-11-23 12:50:47 -06:00
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::rc::Rc;
|
2018-05-22 18:02:44 -05:00
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
use abortable_parser;
|
2018-05-30 22:07:25 -05:00
|
|
|
|
2019-01-14 18:23:39 -06:00
|
|
|
use crate::build::scope::Scope;
|
2018-12-06 12:23:52 -06:00
|
|
|
use crate::build::Val;
|
2020-04-26 12:16:20 -04:00
|
|
|
use crate::error::BuildError;
|
2018-11-23 12:50:47 -06:00
|
|
|
|
2019-05-14 20:18:58 -05:00
|
|
|
pub mod printer;
|
2019-01-13 09:37:44 -06:00
|
|
|
pub mod walk;
|
|
|
|
|
2019-05-14 20:18:58 -05:00
|
|
|
pub use walk::Walker;
|
|
|
|
|
2019-08-12 22:07:26 -05:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum TemplatePart {
|
|
|
|
Str(Vec<char>),
|
|
|
|
PlaceHolder(usize),
|
|
|
|
Expression(Expression),
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
macro_rules! enum_type_equality {
|
|
|
|
( $slf:ident, $r:expr, $( $l:pat ),* ) => {
|
|
|
|
match $slf {
|
|
|
|
$(
|
|
|
|
$l => {
|
|
|
|
if let $l = $r {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents a line and a column position in UCG code.
|
|
|
|
///
|
|
|
|
/// It is used for generating error messages mostly. Most all
|
|
|
|
/// parts of the UCG AST have a positioned associated with them.
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
|
|
|
pub struct Position {
|
2019-01-23 20:02:35 -06:00
|
|
|
pub file: Option<PathBuf>,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub line: usize,
|
|
|
|
pub column: usize,
|
2018-11-05 21:34:12 -06:00
|
|
|
pub offset: usize,
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Position {
|
|
|
|
/// Construct a new Position.
|
2018-11-05 21:34:12 -06:00
|
|
|
pub fn new(line: usize, column: usize, offset: usize) -> Self {
|
2018-05-22 18:02:44 -05:00
|
|
|
Position {
|
2019-01-23 20:02:35 -06:00
|
|
|
file: None,
|
2018-05-22 18:02:44 -05:00
|
|
|
line: line,
|
|
|
|
column: column,
|
2018-11-05 21:34:12 -06:00
|
|
|
offset: offset,
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
}
|
2019-02-19 17:16:36 -06:00
|
|
|
|
|
|
|
pub fn with_file<P: Into<PathBuf>>(mut self, file: P) -> Self {
|
|
|
|
self.file = Some(file.into());
|
|
|
|
self
|
|
|
|
}
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<'a> From<&'a Position> for Position {
|
|
|
|
fn from(source: &'a Position) -> Self {
|
|
|
|
source.clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-26 19:08:41 -05:00
|
|
|
impl std::fmt::Display for Position {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
if let Some(ref file) = self.file {
|
2019-09-01 19:21:02 -05:00
|
|
|
write!(f, "file: {} ", file.to_string_lossy().to_string())?;
|
2019-04-26 19:08:41 -05:00
|
|
|
}
|
|
|
|
write!(f, "line: {} column: {}", self.line, self.column)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Defines the types of tokens in UCG syntax.
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
|
|
|
pub enum TokenType {
|
|
|
|
EMPTY,
|
|
|
|
BOOLEAN,
|
|
|
|
END,
|
|
|
|
WS,
|
|
|
|
COMMENT,
|
|
|
|
QUOTED,
|
2018-08-20 22:51:55 -05:00
|
|
|
PIPEQUOTE,
|
2018-05-22 18:02:44 -05:00
|
|
|
DIGIT,
|
|
|
|
BAREWORD,
|
|
|
|
PUNCT,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Defines a Token representing a building block of UCG syntax.
|
|
|
|
///
|
|
|
|
/// Token's are passed to the parser stage to be parsed into an AST.
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
|
|
|
pub struct Token {
|
|
|
|
pub typ: TokenType,
|
|
|
|
pub fragment: String,
|
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Token {
|
|
|
|
/// Constructs a new Token with a type and line and column information.
|
2018-11-05 21:34:12 -06:00
|
|
|
pub fn new<S: Into<String>, P: Into<Position>>(f: S, typ: TokenType, p: P) -> Self {
|
|
|
|
Self::new_with_pos(f, typ, p.into())
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Constructs a new Token with a type and a Position.
|
|
|
|
pub fn new_with_pos<S: Into<String>>(f: S, typ: TokenType, pos: Position) -> Self {
|
|
|
|
Token {
|
|
|
|
typ: typ,
|
|
|
|
fragment: f.into(),
|
|
|
|
pos: pos,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl abortable_parser::Positioned for Token {
|
|
|
|
fn line(&self) -> usize {
|
|
|
|
self.pos.line
|
|
|
|
}
|
|
|
|
fn column(&self) -> usize {
|
|
|
|
self.pos.column
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
impl Borrow<str> for Token {
|
|
|
|
fn borrow(&self) -> &str {
|
|
|
|
&self.fragment
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper macro for making a Positioned Value.
|
|
|
|
macro_rules! value_node {
|
|
|
|
($v:expr, $p:expr) => {
|
2018-11-05 21:34:12 -06:00
|
|
|
PositionedItem::new_with_pos($v, $p)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper macro for making a Token.
|
|
|
|
#[allow(unused_macros)]
|
|
|
|
macro_rules! make_tok {
|
2018-11-05 21:34:12 -06:00
|
|
|
(EOF => $i:expr) => {
|
|
|
|
Token::new("", TokenType::END, &$i)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
(WS => $i:expr) => {
|
|
|
|
Token::new("", TokenType::WS, &$i)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
(CMT => $e:expr, $i:expr) => {
|
|
|
|
Token::new($e, TokenType::COMMENT, &$i)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
(QUOT => $e:expr, $i:expr) => {
|
|
|
|
Token::new($e, TokenType::QUOTED, &$i)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
(PUNCT => $e:expr, $i:expr) => {
|
|
|
|
Token::new($e, TokenType::PUNCT, &$i)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
(DIGIT => $e:expr, $i:expr) => {
|
|
|
|
Token::new($e, TokenType::DIGIT, &$i)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
($e:expr, $i:expr) => {
|
|
|
|
Token::new($e, TokenType::BAREWORD, &$i)
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper macro for making expressions.
|
|
|
|
#[allow(unused_macros)]
|
|
|
|
macro_rules! make_expr {
|
2018-11-05 21:34:12 -06:00
|
|
|
($e:expr, $i:expr) => {
|
|
|
|
Expression::Simple(Value::Symbol(PositionedItem::new_with_pos(
|
|
|
|
$e.to_string(),
|
|
|
|
$i,
|
|
|
|
)))
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
($e:expr => int, $i:expr) => {
|
|
|
|
Expression::Simple(Value::Int(PositionedItem::new_with_pos($e, $i)))
|
2018-05-22 18:02:44 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An ordered list of Name = Value pairs.
|
|
|
|
///
|
|
|
|
/// 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
|
|
|
|
|
2020-04-26 12:16:20 -04:00
|
|
|
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 )*
|
|
|
|
}
|
|
|
|
}
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
2020-04-26 12:16:20 -04:00
|
|
|
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),
|
|
|
|
);
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
impl Value {
|
|
|
|
/// Returns the type name of the Value it is called on as a string.
|
|
|
|
pub fn type_name(&self) -> String {
|
|
|
|
match self {
|
|
|
|
&Value::Empty(_) => "EmptyValue".to_string(),
|
|
|
|
&Value::Boolean(_) => "Boolean".to_string(),
|
|
|
|
&Value::Int(_) => "Integer".to_string(),
|
|
|
|
&Value::Float(_) => "Float".to_string(),
|
2018-06-10 14:13:08 -05:00
|
|
|
&Value::Str(_) => "String".to_string(),
|
2018-05-22 18:02:44 -05:00
|
|
|
&Value::Symbol(_) => "Symbol".to_string(),
|
|
|
|
&Value::Tuple(_) => "Tuple".to_string(),
|
|
|
|
&Value::List(_) => "List".to_string(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fields_to_string(v: &FieldList) -> String {
|
|
|
|
let mut buf = String::new();
|
|
|
|
buf.push_str("{\n");
|
|
|
|
for ref t in v.iter() {
|
|
|
|
buf.push_str("\t");
|
|
|
|
buf.push_str(&t.0.fragment);
|
|
|
|
buf.push_str("\n");
|
|
|
|
}
|
|
|
|
buf.push_str("}");
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn elems_to_string(v: &Vec<Expression>) -> String {
|
|
|
|
return format!("{}", v.len());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a stringified version of the Value.
|
|
|
|
pub fn to_string(&self) -> String {
|
|
|
|
match self {
|
|
|
|
&Value::Empty(_) => "EmptyValue".to_string(),
|
|
|
|
&Value::Boolean(ref b) => format!("{}", b.val),
|
|
|
|
&Value::Int(ref i) => format!("{}", i.val),
|
|
|
|
&Value::Float(ref f) => format!("{}", f.val),
|
2018-06-10 14:13:08 -05:00
|
|
|
&Value::Str(ref s) => format!("{}", s.val),
|
2018-05-22 18:02:44 -05:00
|
|
|
&Value::Symbol(ref s) => format!("{}", s.val),
|
|
|
|
&Value::Tuple(ref fs) => format!("{}", Self::fields_to_string(&fs.val)),
|
|
|
|
&Value::List(ref def) => format!("[{}]", Self::elems_to_string(&def.elems)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the position for a Value.
|
|
|
|
pub fn pos(&self) -> &Position {
|
|
|
|
match self {
|
|
|
|
&Value::Empty(ref pos) => pos,
|
|
|
|
&Value::Boolean(ref b) => &b.pos,
|
|
|
|
&Value::Int(ref i) => &i.pos,
|
|
|
|
&Value::Float(ref f) => &f.pos,
|
2018-06-10 14:13:08 -05:00
|
|
|
&Value::Str(ref s) => &s.pos,
|
2018-05-22 18:02:44 -05:00
|
|
|
&Value::Symbol(ref s) => &s.pos,
|
|
|
|
&Value::Tuple(ref fs) => &fs.pos,
|
|
|
|
&Value::List(ref def) => &def.pos,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if called on a Value that is the same type as itself.
|
|
|
|
pub fn type_equal(&self, target: &Self) -> bool {
|
|
|
|
enum_type_equality!(
|
|
|
|
self,
|
|
|
|
target,
|
|
|
|
&Value::Empty(_),
|
|
|
|
&Value::Boolean(_),
|
|
|
|
&Value::Int(_),
|
|
|
|
&Value::Float(_),
|
2018-06-10 14:13:08 -05:00
|
|
|
&Value::Str(_),
|
2018-05-22 18:02:44 -05:00
|
|
|
&Value::Symbol(_),
|
|
|
|
&Value::Tuple(_),
|
2018-12-28 19:02:37 -06:00
|
|
|
&Value::List(_)
|
2018-05-22 18:02:44 -05:00
|
|
|
)
|
|
|
|
}
|
2020-04-26 12:16:20 -04:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents an expansion of a Macro that is expected to already have been
|
|
|
|
/// defined.
|
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
|
|
|
pub struct CallDef {
|
2019-01-24 20:04:40 -06:00
|
|
|
pub funcref: Value,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub arglist: Vec<Expression>,
|
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
2019-11-11 20:06:17 -06:00
|
|
|
/// The allowable types to which you can perform a primitive cast.
|
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
|
|
|
pub enum CastType {
|
|
|
|
Int,
|
|
|
|
Float,
|
|
|
|
Str,
|
|
|
|
Bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CastType {
|
|
|
|
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(
|
|
|
|
w,
|
|
|
|
"{}",
|
|
|
|
match self {
|
|
|
|
CastType::Int => "int",
|
|
|
|
CastType::Float => "float",
|
|
|
|
CastType::Bool => "bool",
|
|
|
|
CastType::Str => "str",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents a cast of a target to a primitive type.
|
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
|
|
|
pub struct CastDef {
|
|
|
|
pub cast_type: CastType,
|
|
|
|
pub target: Box<Expression>,
|
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Encodes a select expression in the UCG AST.
|
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
|
|
|
pub struct SelectDef {
|
|
|
|
pub val: Box<Expression>,
|
2019-03-01 16:52:08 -06:00
|
|
|
pub default: Option<Box<Expression>>,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub tuple: FieldList,
|
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds position information to any type `T`.
|
|
|
|
#[derive(Debug, Clone)]
|
2018-11-05 21:34:12 -06:00
|
|
|
pub struct PositionedItem<T> {
|
2018-05-22 18:02:44 -05:00
|
|
|
pub pos: Position,
|
|
|
|
pub val: T,
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<T: std::fmt::Display> std::fmt::Display for PositionedItem<T> {
|
2018-05-22 18:02:44 -05:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
write!(f, "{}", self.val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<T> PositionedItem<T> {
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Constructs a new Positioned<T> with a value, line, and column information.
|
2018-11-05 21:34:12 -06:00
|
|
|
pub fn new<P: Into<Position>>(v: T, p: P) -> Self {
|
|
|
|
Self::new_with_pos(v, p.into())
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a new Positioned<T> with a value and a Position.
|
|
|
|
pub fn new_with_pos(v: T, pos: Position) -> Self {
|
2018-11-05 21:34:12 -06:00
|
|
|
PositionedItem { pos: pos, val: v }
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<T: PartialEq> PartialEq for PositionedItem<T> {
|
2018-05-22 18:02:44 -05:00
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.val == other.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<T: Eq> Eq for PositionedItem<T> {}
|
2018-05-22 18:02:44 -05:00
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<T: Ord> Ord for PositionedItem<T> {
|
2018-05-22 18:02:44 -05:00
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
self.val.cmp(&other.val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<T: PartialOrd> PartialOrd for PositionedItem<T> {
|
2018-05-22 18:02:44 -05:00
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
self.val.partial_cmp(&other.val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<T: Hash> Hash for PositionedItem<T> {
|
2018-05-22 18:02:44 -05:00
|
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
|
|
self.val.hash(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<'a> From<&'a Token> for PositionedItem<String> {
|
|
|
|
fn from(t: &'a Token) -> PositionedItem<String> {
|
|
|
|
PositionedItem {
|
2018-05-22 18:02:44 -05:00
|
|
|
pos: t.pos.clone(),
|
|
|
|
val: t.fragment.to_string(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 21:34:12 -06:00
|
|
|
impl<'a> From<&'a PositionedItem<String>> for PositionedItem<String> {
|
|
|
|
fn from(t: &PositionedItem<String>) -> PositionedItem<String> {
|
|
|
|
PositionedItem {
|
2018-05-22 18:02:44 -05:00
|
|
|
pos: t.pos.clone(),
|
|
|
|
val: t.val.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-24 20:04:40 -06:00
|
|
|
/// Encodes a func expression in the UCG AST..
|
2018-05-22 18:02:44 -05:00
|
|
|
///
|
2019-01-24 20:04:40 -06:00
|
|
|
/// A func is a pure function over a tuple.
|
2018-05-22 18:02:44 -05:00
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
2019-01-24 20:04:40 -06:00
|
|
|
pub struct FuncDef {
|
2019-01-14 18:23:39 -06:00
|
|
|
pub scope: Option<Scope>,
|
2018-11-05 21:34:12 -06:00
|
|
|
pub argdefs: Vec<PositionedItem<String>>,
|
2019-01-16 19:07:03 -06:00
|
|
|
pub fields: Box<Expression>,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Specifies the types of binary operations supported in
|
|
|
|
/// UCG expression.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum BinaryExprType {
|
2018-12-28 19:02:37 -06:00
|
|
|
// Math
|
2018-05-22 18:02:44 -05:00
|
|
|
Add,
|
|
|
|
Sub,
|
|
|
|
Mul,
|
|
|
|
Div,
|
2019-02-18 21:09:42 -06:00
|
|
|
Mod,
|
2019-01-17 19:20:01 -06:00
|
|
|
// Boolean
|
|
|
|
AND,
|
|
|
|
OR,
|
2018-12-25 14:04:12 -06:00
|
|
|
// Comparison
|
2018-05-22 18:02:44 -05:00
|
|
|
Equal,
|
|
|
|
GT,
|
|
|
|
LT,
|
|
|
|
NotEqual,
|
|
|
|
GTEqual,
|
|
|
|
LTEqual,
|
2019-01-07 19:27:29 -06:00
|
|
|
REMatch,
|
|
|
|
NotREMatch,
|
2019-01-03 11:42:11 -06:00
|
|
|
IN,
|
2019-01-19 10:34:58 -06:00
|
|
|
IS,
|
2018-12-28 19:02:37 -06:00
|
|
|
// Selector operator
|
|
|
|
DOT,
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
2018-12-28 21:56:11 -06:00
|
|
|
impl BinaryExprType {
|
|
|
|
/// Returns the precedence level for the binary operator.
|
|
|
|
///
|
|
|
|
/// Higher values bind tighter than lower values.
|
|
|
|
pub fn precedence_level(&self) -> u32 {
|
|
|
|
match self {
|
|
|
|
// Equality operators are least tightly bound
|
|
|
|
BinaryExprType::Equal => 1,
|
|
|
|
BinaryExprType::NotEqual => 1,
|
|
|
|
BinaryExprType::GTEqual => 1,
|
|
|
|
BinaryExprType::LTEqual => 1,
|
|
|
|
BinaryExprType::GT => 1,
|
|
|
|
BinaryExprType::LT => 1,
|
2019-01-07 19:27:29 -06:00
|
|
|
BinaryExprType::REMatch => 1,
|
|
|
|
BinaryExprType::NotREMatch => 1,
|
2019-01-19 10:34:58 -06:00
|
|
|
BinaryExprType::IN => 2,
|
|
|
|
BinaryExprType::IS => 2,
|
2018-12-28 21:56:11 -06:00
|
|
|
// Sum operators are next least tightly bound
|
2019-01-19 10:34:58 -06:00
|
|
|
BinaryExprType::Add => 3,
|
|
|
|
BinaryExprType::Sub => 3,
|
2018-12-28 21:56:11 -06:00
|
|
|
// Product operators are next tightly bound
|
2019-01-19 10:34:58 -06:00
|
|
|
BinaryExprType::Mul => 4,
|
|
|
|
BinaryExprType::Div => 4,
|
2019-02-18 21:09:42 -06:00
|
|
|
BinaryExprType::Mod => 4,
|
2019-01-17 19:20:01 -06:00
|
|
|
// Boolean operators bind tighter than math
|
2019-01-19 10:34:58 -06:00
|
|
|
BinaryExprType::AND => 5,
|
|
|
|
BinaryExprType::OR => 5,
|
2018-12-28 21:56:11 -06:00
|
|
|
// Dot operators are most tightly bound.
|
2019-01-19 10:34:58 -06:00
|
|
|
BinaryExprType::DOT => 6,
|
2018-12-28 21:56:11 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Represents an expression with a left and a right side.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct BinaryOpDef {
|
|
|
|
pub kind: BinaryExprType,
|
|
|
|
pub left: Box<Expression>,
|
|
|
|
pub right: Box<Expression>,
|
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Encodes a tuple Copy expression in the UCG AST.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct CopyDef {
|
2018-12-28 19:02:37 -06:00
|
|
|
pub selector: Value,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub fields: FieldList,
|
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
2019-01-28 21:22:23 -06:00
|
|
|
/// Encodes one of two possible forms for format expression arguments.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum FormatArgs {
|
|
|
|
List(Vec<Expression>),
|
|
|
|
Single(Box<Expression>),
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Encodes a format expression in the UCG AST.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct FormatDef {
|
|
|
|
pub template: String,
|
2019-01-28 21:22:23 -06:00
|
|
|
pub args: FormatArgs,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
2019-01-04 10:01:49 -06:00
|
|
|
/// Encodes an import statement in the UCG AST.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct IncludeDef {
|
|
|
|
pub pos: Position,
|
|
|
|
pub path: Token,
|
|
|
|
pub typ: Token,
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Encodes a list expression in the UCG AST.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct ListDef {
|
|
|
|
pub elems: Vec<Expression>,
|
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2019-01-06 20:56:08 -06:00
|
|
|
pub enum FuncOpDef {
|
|
|
|
Reduce(ReduceOpDef),
|
|
|
|
Map(MapFilterOpDef),
|
|
|
|
Filter(MapFilterOpDef),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct ReduceOpDef {
|
2019-01-30 20:23:35 -06:00
|
|
|
pub func: Box<Expression>,
|
2019-01-06 20:56:08 -06:00
|
|
|
pub acc: Box<Expression>,
|
|
|
|
pub target: Box<Expression>,
|
|
|
|
pub pos: Position,
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
2019-01-06 20:56:08 -06:00
|
|
|
/// MapFilterOpDef implements the list operations in the UCG AST.
|
2018-05-22 18:02:44 -05:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2019-01-06 20:56:08 -06:00
|
|
|
pub struct MapFilterOpDef {
|
2019-01-30 20:23:35 -06:00
|
|
|
pub func: Box<Expression>,
|
2018-08-21 23:05:06 -05:00
|
|
|
pub target: Box<Expression>,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub pos: Position,
|
|
|
|
}
|
|
|
|
|
2019-01-06 20:56:08 -06:00
|
|
|
impl FuncOpDef {
|
|
|
|
pub fn pos(&self) -> &Position {
|
|
|
|
match self {
|
|
|
|
FuncOpDef::Map(def) => &def.pos,
|
|
|
|
FuncOpDef::Filter(def) => &def.pos,
|
|
|
|
FuncOpDef::Reduce(def) => &def.pos,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-23 12:50:47 -06:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct ModuleDef {
|
2019-01-14 18:23:39 -06:00
|
|
|
pub scope: Option<Scope>,
|
2018-11-23 12:50:47 -06:00
|
|
|
pub pos: Position,
|
|
|
|
pub arg_set: FieldList,
|
2019-02-21 19:39:30 -06:00
|
|
|
pub out_expr: Option<Box<Expression>>,
|
2018-11-23 12:50:47 -06:00
|
|
|
pub arg_tuple: Option<Rc<Val>>,
|
|
|
|
pub statements: Vec<Statement>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ModuleDef {
|
|
|
|
pub fn new<P: Into<Position>>(arg_set: FieldList, stmts: Vec<Statement>, pos: P) -> Self {
|
|
|
|
ModuleDef {
|
2019-01-14 18:23:39 -06:00
|
|
|
scope: None,
|
2018-11-23 12:50:47 -06:00
|
|
|
pos: pos.into(),
|
|
|
|
arg_set: arg_set,
|
2019-02-21 19:39:30 -06:00
|
|
|
out_expr: None,
|
2018-11-23 12:50:47 -06:00
|
|
|
arg_tuple: None,
|
|
|
|
statements: stmts,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-21 19:39:30 -06:00
|
|
|
pub fn set_out_expr(&mut self, expr: Expression) {
|
|
|
|
self.out_expr = Some(Box::new(expr));
|
|
|
|
}
|
2020-05-25 11:56:41 -04:00
|
|
|
}
|
2019-02-21 19:39:30 -06:00
|
|
|
|
2020-05-25 11:56:41 -04:00
|
|
|
pub struct Rewriter {
|
|
|
|
base: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Rewriter {
|
|
|
|
pub fn new<P: Into<PathBuf>>(base: P) -> Self {
|
|
|
|
Self { base: base.into() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-10 20:45:06 -05:00
|
|
|
fn normalize_path(p: PathBuf) -> PathBuf {
|
|
|
|
let mut normalized = PathBuf::new();
|
|
|
|
for segment in p.components() {
|
|
|
|
normalized.push(segment);
|
|
|
|
}
|
|
|
|
return normalized;
|
|
|
|
}
|
|
|
|
|
2020-05-25 11:56:41 -04:00
|
|
|
impl walk::Walker for Rewriter {
|
|
|
|
fn visit_expression(&mut self, expr: &mut Expression) {
|
|
|
|
// Rewrite all paths except for stdlib paths to absolute.
|
|
|
|
let main_separator = format!("{}", std::path::MAIN_SEPARATOR);
|
|
|
|
if let Expression::Include(ref mut def) = expr {
|
|
|
|
let path = PathBuf::from(&def.path.fragment);
|
2021-03-10 20:45:06 -05:00
|
|
|
def.path.fragment = normalize_path(self.base.join(path))
|
|
|
|
.to_string_lossy()
|
|
|
|
.to_string();
|
2020-05-25 11:56:41 -04:00
|
|
|
}
|
|
|
|
if let Expression::Import(ref mut def) = expr {
|
|
|
|
let path = PathBuf::from(
|
|
|
|
&def.path
|
|
|
|
.fragment
|
|
|
|
.replace("/", &main_separator)
|
|
|
|
.replace("\\", &main_separator),
|
|
|
|
);
|
|
|
|
// std/ paths are special and do not get made into absolute paths.
|
|
|
|
if path.starts_with(format!("std{}", main_separator)) {
|
|
|
|
return;
|
|
|
|
}
|
2021-03-10 20:45:06 -05:00
|
|
|
def.path.fragment = normalize_path(self.base.join(path))
|
|
|
|
.to_string_lossy()
|
|
|
|
.to_string();
|
2018-11-23 12:50:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-10 18:38:14 -06:00
|
|
|
/// RangeDef defines a range with optional step.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct RangeDef {
|
|
|
|
pub pos: Position,
|
|
|
|
pub start: Box<Expression>,
|
|
|
|
pub step: Option<Box<Expression>>,
|
|
|
|
pub end: Box<Expression>,
|
|
|
|
}
|
|
|
|
|
2019-01-13 09:37:44 -06:00
|
|
|
/// Encodes an import expression in the UCG AST.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct ImportDef {
|
|
|
|
pub pos: Position,
|
|
|
|
pub path: Token,
|
|
|
|
}
|
|
|
|
|
2019-01-18 18:44:29 -06:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct IsDef {
|
|
|
|
pub pos: Position,
|
|
|
|
pub target: Box<Expression>,
|
|
|
|
pub typ: Token,
|
|
|
|
}
|
|
|
|
|
2019-01-19 11:18:24 -06:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct FailDef {
|
|
|
|
pub pos: Position,
|
|
|
|
pub message: Box<Expression>,
|
|
|
|
}
|
|
|
|
|
2019-01-24 16:53:02 -06:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct NotDef {
|
|
|
|
pub pos: Position,
|
|
|
|
pub expr: Box<Expression>,
|
|
|
|
}
|
|
|
|
|
2019-04-26 19:08:41 -05:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct DebugDef {
|
|
|
|
pub pos: Position,
|
|
|
|
pub expr: Box<Expression>,
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Encodes a ucg expression. Expressions compute a value from.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum Expression {
|
|
|
|
// Base Expression
|
|
|
|
Simple(Value),
|
2019-01-24 16:53:02 -06:00
|
|
|
Not(NotDef),
|
2018-05-22 18:02:44 -05:00
|
|
|
|
|
|
|
// Binary expressions
|
|
|
|
Binary(BinaryOpDef),
|
|
|
|
|
|
|
|
// Complex Expressions
|
|
|
|
Copy(CopyDef),
|
2019-01-10 18:38:14 -06:00
|
|
|
Range(RangeDef),
|
2019-03-26 20:44:35 -04:00
|
|
|
Grouped(Box<Expression>, Position),
|
2018-05-22 18:02:44 -05:00
|
|
|
Format(FormatDef),
|
2019-01-04 10:01:49 -06:00
|
|
|
Include(IncludeDef),
|
2019-01-13 09:37:44 -06:00
|
|
|
Import(ImportDef),
|
2018-05-22 18:02:44 -05:00
|
|
|
Call(CallDef),
|
2019-11-11 20:06:17 -06:00
|
|
|
Cast(CastDef),
|
2019-01-24 20:04:40 -06:00
|
|
|
Func(FuncDef),
|
2018-05-22 18:02:44 -05:00
|
|
|
Select(SelectDef),
|
2019-01-06 20:56:08 -06:00
|
|
|
FuncOp(FuncOpDef),
|
2018-11-23 12:50:47 -06:00
|
|
|
Module(ModuleDef),
|
2019-01-19 11:18:24 -06:00
|
|
|
|
|
|
|
// Declarative failure expressions
|
|
|
|
Fail(FailDef),
|
2019-04-26 19:08:41 -05:00
|
|
|
// Debugging assistance
|
|
|
|
Debug(DebugDef),
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Expression {
|
|
|
|
/// Returns the position of the Expression.
|
|
|
|
pub fn pos(&self) -> &Position {
|
|
|
|
match self {
|
|
|
|
&Expression::Simple(ref v) => v.pos(),
|
|
|
|
&Expression::Binary(ref def) => &def.pos,
|
|
|
|
&Expression::Copy(ref def) => &def.pos,
|
2019-01-10 18:38:14 -06:00
|
|
|
&Expression::Range(ref def) => &def.pos,
|
2019-03-26 20:44:35 -04:00
|
|
|
&Expression::Grouped(_, ref pos) => pos,
|
2018-05-22 18:02:44 -05:00
|
|
|
&Expression::Format(ref def) => &def.pos,
|
|
|
|
&Expression::Call(ref def) => &def.pos,
|
2019-11-11 20:06:17 -06:00
|
|
|
&Expression::Cast(ref def) => &def.pos,
|
2019-01-24 20:04:40 -06:00
|
|
|
&Expression::Func(ref def) => &def.pos,
|
2018-11-23 12:50:47 -06:00
|
|
|
&Expression::Module(ref def) => &def.pos,
|
2018-05-22 18:02:44 -05:00
|
|
|
&Expression::Select(ref def) => &def.pos,
|
2019-01-06 20:56:08 -06:00
|
|
|
&Expression::FuncOp(ref def) => def.pos(),
|
2019-01-04 10:01:49 -06:00
|
|
|
&Expression::Include(ref def) => &def.pos,
|
2019-01-13 09:37:44 -06:00
|
|
|
&Expression::Import(ref def) => &def.pos,
|
2019-01-19 11:18:24 -06:00
|
|
|
&Expression::Fail(ref def) => &def.pos,
|
2019-01-24 16:53:02 -06:00
|
|
|
&Expression::Not(ref def) => &def.pos,
|
2019-04-26 19:08:41 -05:00
|
|
|
&Expression::Debug(ref def) => &def.pos,
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
}
|
2020-04-26 12:16:20 -04:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
|
|
|
|
2018-05-30 22:07:25 -05:00
|
|
|
impl fmt::Display for Expression {
|
|
|
|
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
&Expression::Simple(ref v) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "{}", v.to_string())?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
|
|
|
&Expression::Binary(_) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "<Expr>")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
2019-01-06 20:56:08 -06:00
|
|
|
&Expression::FuncOp(_) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "<Expr>")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
|
|
|
&Expression::Copy(_) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "<Copy>")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
2019-01-10 18:38:14 -06:00
|
|
|
&Expression::Range(_) => {
|
|
|
|
write!(w, "<Range>")?;
|
|
|
|
}
|
2019-03-26 20:44:35 -04:00
|
|
|
&Expression::Grouped(_, _) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "(<Expr>)")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
|
|
|
&Expression::Format(_) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "<Format Expr>")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
|
|
|
&Expression::Call(_) => {
|
2019-11-11 20:06:17 -06:00
|
|
|
write!(w, "<FuncCall>")?;
|
|
|
|
}
|
|
|
|
&Expression::Cast(_) => {
|
|
|
|
write!(w, "<Cast>")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
2019-01-24 20:04:40 -06:00
|
|
|
&Expression::Func(_) => {
|
|
|
|
write!(w, "<Func>")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
2018-11-23 12:50:47 -06:00
|
|
|
&Expression::Module(_) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "<Module>")?;
|
2018-11-23 12:50:47 -06:00
|
|
|
}
|
2018-05-30 22:07:25 -05:00
|
|
|
&Expression::Select(_) => {
|
2018-12-06 12:46:47 -06:00
|
|
|
write!(w, "<Select>")?;
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
2019-01-04 10:01:49 -06:00
|
|
|
&Expression::Include(_) => {
|
|
|
|
write!(w, "<Include>")?;
|
|
|
|
}
|
2019-01-13 09:37:44 -06:00
|
|
|
&Expression::Import(_) => {
|
|
|
|
write!(w, "<Include>")?;
|
|
|
|
}
|
2019-01-19 11:18:24 -06:00
|
|
|
&Expression::Fail(_) => {
|
|
|
|
write!(w, "<Fail>")?;
|
|
|
|
}
|
2019-01-24 16:53:02 -06:00
|
|
|
&Expression::Not(ref def) => {
|
|
|
|
write!(w, "!{}", def.expr)?;
|
|
|
|
}
|
2019-04-26 19:08:41 -05:00
|
|
|
&Expression::Debug(ref def) => {
|
|
|
|
write!(w, "!{}", def.expr)?;
|
|
|
|
}
|
2018-05-30 22:07:25 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:44 -05:00
|
|
|
/// Encodes a let statement in the UCG AST.
|
2018-11-23 12:50:47 -06:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2018-05-22 18:02:44 -05:00
|
|
|
pub struct LetDef {
|
2019-05-21 20:34:42 -05:00
|
|
|
pub pos: Position,
|
2018-05-22 18:02:44 -05:00
|
|
|
pub name: Token,
|
|
|
|
pub value: Expression,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Encodes a parsed statement in the UCG AST.
|
2018-11-23 12:50:47 -06:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2018-05-22 18:02:44 -05:00
|
|
|
pub enum Statement {
|
|
|
|
// simple expression
|
|
|
|
Expression(Expression),
|
|
|
|
|
|
|
|
// Named bindings
|
|
|
|
Let(LetDef),
|
|
|
|
|
2018-05-30 23:00:50 -05:00
|
|
|
// Assert statement
|
2019-05-21 20:34:42 -05:00
|
|
|
Assert(Position, Expression),
|
2018-08-13 20:37:58 -05:00
|
|
|
|
|
|
|
// Identify an Expression for output.
|
2019-02-06 21:06:05 -06:00
|
|
|
Output(Position, Token, Expression),
|
2019-06-19 22:16:37 -05:00
|
|
|
|
|
|
|
// Print the expression to stdout.
|
|
|
|
Print(Position, Token, Expression),
|
2018-05-22 18:02:44 -05:00
|
|
|
}
|
2019-05-21 20:34:42 -05:00
|
|
|
|
|
|
|
impl Statement {
|
|
|
|
fn pos(&self) -> &Position {
|
|
|
|
match self {
|
|
|
|
Statement::Expression(ref e) => e.pos(),
|
|
|
|
Statement::Let(ref def) => &def.pos,
|
|
|
|
Statement::Assert(ref pos, _) => pos,
|
|
|
|
Statement::Output(ref pos, _, _) => pos,
|
2019-06-19 22:16:37 -05:00
|
|
|
Statement::Print(ref pos, _, _) => pos,
|
2019-05-21 20:34:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-26 12:16:20 -04:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test;
|