ucglib/ast/
mod.rs

1// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
2//
3//  Licensed under the Apache License, Version 2.0 (the "License");
4//  you may not use this file except in compliance with the License.
5//  You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14
15//! The definitions of the ucg AST and Tokens.
16use std;
17use std::borrow::Borrow;
18use std::cmp::Eq;
19use std::cmp::Ordering;
20use std::cmp::PartialEq;
21use std::cmp::PartialOrd;
22use std::convert::{Into, TryFrom, TryInto};
23use std::fmt;
24use std::hash::Hash;
25use std::hash::Hasher;
26use std::path::PathBuf;
27use std::rc::Rc;
28
29use abortable_parser;
30
31use crate::build::scope::Scope;
32use crate::build::Val;
33use crate::error::BuildError;
34
35pub mod printer;
36pub mod walk;
37
38pub use walk::Walker;
39
40#[derive(Debug, PartialEq, Clone)]
41pub enum TemplatePart {
42    Str(Vec<char>),
43    PlaceHolder(usize),
44    Expression(Expression),
45}
46
47macro_rules! enum_type_equality {
48    ( $slf:ident, $r:expr, $( $l:pat ),* ) => {
49        match $slf {
50        $(
51            $l => {
52                if let $l = $r {
53                    true
54                } else {
55                    false
56                }
57            }
58        )*
59        }
60    }
61}
62
63/// Represents a line and a column position in UCG code.
64///
65/// It is used for generating error messages mostly. Most all
66/// parts of the UCG AST have a positioned associated with them.
67#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
68pub struct Position {
69    pub file: Option<PathBuf>,
70    pub line: usize,
71    pub column: usize,
72    pub offset: usize,
73}
74
75impl Position {
76    /// Construct a new Position.
77    pub fn new(line: usize, column: usize, offset: usize) -> Self {
78        Position {
79            file: None,
80            line: line,
81            column: column,
82            offset: offset,
83        }
84    }
85
86    pub fn with_file<P: Into<PathBuf>>(mut self, file: P) -> Self {
87        self.file = Some(file.into());
88        self
89    }
90}
91
92impl<'a> From<&'a Position> for Position {
93    fn from(source: &'a Position) -> Self {
94        source.clone()
95    }
96}
97
98impl std::fmt::Display for Position {
99    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
100        if let Some(ref file) = self.file {
101            write!(f, "file: {} ", file.to_string_lossy().to_string())?;
102        }
103        write!(f, "line: {} column: {}", self.line, self.column)
104    }
105}
106
107/// Defines the types of tokens in UCG syntax.
108#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
109pub enum TokenType {
110    EMPTY,
111    BOOLEAN,
112    END,
113    WS,
114    COMMENT,
115    QUOTED,
116    PIPEQUOTE,
117    DIGIT,
118    BAREWORD,
119    PUNCT,
120}
121
122/// Defines a Token representing a building block of UCG syntax.
123///
124/// Token's are passed to the parser stage to be parsed into an AST.
125#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
126pub struct Token {
127    pub typ: TokenType,
128    pub fragment: String,
129    pub pos: Position,
130}
131
132impl Token {
133    /// Constructs a new Token with a type and line and column information.
134    pub fn new<S: Into<String>, P: Into<Position>>(f: S, typ: TokenType, p: P) -> Self {
135        Self::new_with_pos(f, typ, p.into())
136    }
137
138    // Constructs a new Token with a type and a Position.
139    pub fn new_with_pos<S: Into<String>>(f: S, typ: TokenType, pos: Position) -> Self {
140        Token {
141            typ: typ,
142            fragment: f.into(),
143            pos: pos,
144        }
145    }
146}
147
148impl abortable_parser::Positioned for Token {
149    fn line(&self) -> usize {
150        self.pos.line
151    }
152    fn column(&self) -> usize {
153        self.pos.column
154    }
155}
156
157impl Borrow<str> for Token {
158    fn borrow(&self) -> &str {
159        &self.fragment
160    }
161}
162
163/// Helper macro for making a Positioned Value.
164macro_rules! value_node {
165    ($v:expr, $p:expr) => {
166        PositionedItem::new_with_pos($v, $p)
167    };
168}
169
170/// Helper macro for making a Token.
171#[allow(unused_macros)]
172macro_rules! make_tok {
173    (EOF => $i:expr) => {
174        Token::new("", TokenType::END, &$i)
175    };
176
177    (WS => $i:expr) => {
178        Token::new("", TokenType::WS, &$i)
179    };
180
181    (CMT => $e:expr, $i:expr) => {
182        Token::new($e, TokenType::COMMENT, &$i)
183    };
184
185    (QUOT => $e:expr, $i:expr) => {
186        Token::new($e, TokenType::QUOTED, &$i)
187    };
188
189    (PUNCT => $e:expr, $i:expr) => {
190        Token::new($e, TokenType::PUNCT, &$i)
191    };
192
193    (DIGIT => $e:expr, $i:expr) => {
194        Token::new($e, TokenType::DIGIT, &$i)
195    };
196
197    ($e:expr, $i:expr) => {
198        Token::new($e, TokenType::BAREWORD, &$i)
199    };
200}
201
202/// Helper macro for making expressions.
203#[allow(unused_macros)]
204macro_rules! make_expr {
205    ($e:expr, $i:expr) => {
206        Expression::Simple(Value::Symbol(PositionedItem::new_with_pos(
207            $e.to_string(),
208            $i,
209        )))
210    };
211
212    ($e:expr => int, $i:expr) => {
213        Expression::Simple(Value::Int(PositionedItem::new_with_pos($e, $i)))
214    };
215}
216
217/// An ordered list of Name = Value pairs.
218///
219/// This is usually used as the body of a tuple in the UCG AST.
220pub type FieldList = Vec<(Token, Expression)>; // Token is expected to be a symbol
221
222pub type ShapeTuple = Vec<(Token, Shape)>;
223pub type ShapeList = Vec<Shape>;
224
225#[derive(PartialEq, Debug, Clone)]
226pub struct FuncShapeDef {
227    args: Vec<Shape>,
228    ret: Box<Shape>,
229}
230
231#[derive(PartialEq, Debug, Clone)]
232pub struct ModuleShapeDef {
233    items: ShapeTuple,
234    ret: Box<Shape>,
235}
236
237macro_rules! value_enum {
238    ($doc:meta $i:tt, $t:ty, $l:ty, $($extra:tt)*) => {
239        #[$doc]
240        #[derive(PartialEq, Debug, Clone)]
241        pub enum $i {
242            // Simple Values
243            Empty(Position),
244            Boolean(PositionedItem<bool>),
245            Int(PositionedItem<i64>),
246            Float(PositionedItem<f64>),
247            Str(PositionedItem<String>),
248            Symbol(PositionedItem<String>),
249            // Complex Values
250            Tuple(PositionedItem<$t>),
251            List($l),
252            // Extra items
253            $( $extra )*
254        }
255    }
256}
257
258value_enum!(
259    doc="Value types represent the Values that UCG can have."
260    Value,
261    FieldList,
262    ListDef,
263);
264
265value_enum!(
266    doc="Shapes represent the types that UCG values or expressions can have."
267    Shape,
268    ShapeTuple,
269    PositionedItem<ShapeList>,
270    Func(FuncShapeDef),
271    Module(ModuleShapeDef),
272);
273
274impl Value {
275    /// Returns the type name of the Value it is called on as a string.
276    pub fn type_name(&self) -> String {
277        match self {
278            &Value::Empty(_) => "EmptyValue".to_string(),
279            &Value::Boolean(_) => "Boolean".to_string(),
280            &Value::Int(_) => "Integer".to_string(),
281            &Value::Float(_) => "Float".to_string(),
282            &Value::Str(_) => "String".to_string(),
283            &Value::Symbol(_) => "Symbol".to_string(),
284            &Value::Tuple(_) => "Tuple".to_string(),
285            &Value::List(_) => "List".to_string(),
286        }
287    }
288
289    fn fields_to_string(v: &FieldList) -> String {
290        let mut buf = String::new();
291        buf.push_str("{\n");
292        for ref t in v.iter() {
293            buf.push_str("\t");
294            buf.push_str(&t.0.fragment);
295            buf.push_str("\n");
296        }
297        buf.push_str("}");
298        return buf;
299    }
300
301    fn elems_to_string(v: &Vec<Expression>) -> String {
302        return format!("{}", v.len());
303    }
304
305    /// Returns a stringified version of the Value.
306    pub fn to_string(&self) -> String {
307        match self {
308            &Value::Empty(_) => "EmptyValue".to_string(),
309            &Value::Boolean(ref b) => format!("{}", b.val),
310            &Value::Int(ref i) => format!("{}", i.val),
311            &Value::Float(ref f) => format!("{}", f.val),
312            &Value::Str(ref s) => format!("{}", s.val),
313            &Value::Symbol(ref s) => format!("{}", s.val),
314            &Value::Tuple(ref fs) => format!("{}", Self::fields_to_string(&fs.val)),
315            &Value::List(ref def) => format!("[{}]", Self::elems_to_string(&def.elems)),
316        }
317    }
318
319    /// Returns the position for a Value.
320    pub fn pos(&self) -> &Position {
321        match self {
322            &Value::Empty(ref pos) => pos,
323            &Value::Boolean(ref b) => &b.pos,
324            &Value::Int(ref i) => &i.pos,
325            &Value::Float(ref f) => &f.pos,
326            &Value::Str(ref s) => &s.pos,
327            &Value::Symbol(ref s) => &s.pos,
328            &Value::Tuple(ref fs) => &fs.pos,
329            &Value::List(ref def) => &def.pos,
330        }
331    }
332
333    /// Returns true if called on a Value that is the same type as itself.
334    pub fn type_equal(&self, target: &Self) -> bool {
335        enum_type_equality!(
336            self,
337            target,
338            &Value::Empty(_),
339            &Value::Boolean(_),
340            &Value::Int(_),
341            &Value::Float(_),
342            &Value::Str(_),
343            &Value::Symbol(_),
344            &Value::Tuple(_),
345            &Value::List(_)
346        )
347    }
348
349    fn derive_shape(&self) -> Result<Shape, BuildError> {
350        let shape = match self {
351            Value::Empty(p) => Shape::Empty(p.clone()),
352            Value::Boolean(p) => Shape::Boolean(p.clone()),
353            Value::Int(p) => Shape::Int(p.clone()),
354            Value::Float(p) => Shape::Float(p.clone()),
355            Value::Str(p) => Shape::Str(p.clone()),
356            // Symbols in a shape are placeholder. They allow a form of genericity
357            // in the shape. They can be any type and are only refined down.
358            // by their presence in an expression.
359            Value::Symbol(p) => Shape::Symbol(p.clone()),
360            Value::Tuple(flds) => {
361                let mut field_shapes = Vec::new();
362                for &(ref tok, ref expr) in &flds.val {
363                    field_shapes.push((tok.clone(), expr.try_into()?));
364                }
365                Shape::Tuple(PositionedItem::new(field_shapes, flds.pos.clone()))
366            }
367            Value::List(flds) => {
368                let mut field_shapes = Vec::new();
369                for f in &flds.elems {
370                    field_shapes.push(f.try_into()?);
371                }
372                Shape::List(PositionedItem::new(field_shapes, flds.pos.clone()))
373            }
374        };
375        Ok(shape)
376    }
377}
378
379impl TryFrom<&Value> for Shape {
380    type Error = crate::error::BuildError;
381
382    fn try_from(v: &Value) -> Result<Self, Self::Error> {
383        v.derive_shape()
384    }
385}
386
387/// Represents an expansion of a Macro that is expected to already have been
388/// defined.
389#[derive(PartialEq, Debug, Clone)]
390pub struct CallDef {
391    pub funcref: Value,
392    pub arglist: Vec<Expression>,
393    pub pos: Position,
394}
395
396/// The allowable types to which you can perform a primitive cast.
397#[derive(PartialEq, Debug, Clone)]
398pub enum CastType {
399    Int,
400    Float,
401    Str,
402    Bool,
403}
404
405impl fmt::Display for CastType {
406    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
407        write!(
408            w,
409            "{}",
410            match self {
411                CastType::Int => "int",
412                CastType::Float => "float",
413                CastType::Bool => "bool",
414                CastType::Str => "str",
415            }
416        )
417    }
418}
419
420/// Represents a cast of a target to a primitive type.
421#[derive(PartialEq, Debug, Clone)]
422pub struct CastDef {
423    pub cast_type: CastType,
424    pub target: Box<Expression>,
425    pub pos: Position,
426}
427
428/// Encodes a select expression in the UCG AST.
429#[derive(PartialEq, Debug, Clone)]
430pub struct SelectDef {
431    pub val: Box<Expression>,
432    pub default: Option<Box<Expression>>,
433    pub tuple: FieldList,
434    pub pos: Position,
435}
436
437/// Adds position information to any type `T`.
438#[derive(Debug, Clone)]
439pub struct PositionedItem<T> {
440    pub pos: Position,
441    pub val: T,
442}
443
444impl<T: std::fmt::Display> std::fmt::Display for PositionedItem<T> {
445    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
446        write!(f, "{}", self.val)
447    }
448}
449
450impl<T> PositionedItem<T> {
451    /// Constructs a new Positioned<T> with a value, line, and column information.
452    pub fn new<P: Into<Position>>(v: T, p: P) -> Self {
453        Self::new_with_pos(v, p.into())
454    }
455
456    /// Constructs a new Positioned<T> with a value and a Position.
457    pub fn new_with_pos(v: T, pos: Position) -> Self {
458        PositionedItem { pos: pos, val: v }
459    }
460}
461
462impl<T: PartialEq> PartialEq for PositionedItem<T> {
463    fn eq(&self, other: &Self) -> bool {
464        self.val == other.val
465    }
466}
467
468impl<T: Eq> Eq for PositionedItem<T> {}
469
470impl<T: Ord> Ord for PositionedItem<T> {
471    fn cmp(&self, other: &Self) -> Ordering {
472        self.val.cmp(&other.val)
473    }
474}
475
476impl<T: PartialOrd> PartialOrd for PositionedItem<T> {
477    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
478        self.val.partial_cmp(&other.val)
479    }
480}
481
482impl<T: Hash> Hash for PositionedItem<T> {
483    fn hash<H: Hasher>(&self, state: &mut H) {
484        self.val.hash(state);
485    }
486}
487
488impl<'a> From<&'a Token> for PositionedItem<String> {
489    fn from(t: &'a Token) -> PositionedItem<String> {
490        PositionedItem {
491            pos: t.pos.clone(),
492            val: t.fragment.to_string(),
493        }
494    }
495}
496
497impl<'a> From<&'a PositionedItem<String>> for PositionedItem<String> {
498    fn from(t: &PositionedItem<String>) -> PositionedItem<String> {
499        PositionedItem {
500            pos: t.pos.clone(),
501            val: t.val.clone(),
502        }
503    }
504}
505
506/// Encodes a func expression in the UCG AST..
507///
508/// A func is a pure function over a tuple.
509#[derive(PartialEq, Debug, Clone)]
510pub struct FuncDef {
511    pub scope: Option<Scope>,
512    pub argdefs: Vec<PositionedItem<String>>,
513    pub fields: Box<Expression>,
514    pub pos: Position,
515}
516
517/// Specifies the types of binary operations supported in
518/// UCG expression.
519#[derive(Debug, PartialEq, Clone)]
520pub enum BinaryExprType {
521    // Math
522    Add,
523    Sub,
524    Mul,
525    Div,
526    Mod,
527    // Boolean
528    AND,
529    OR,
530    // Comparison
531    Equal,
532    GT,
533    LT,
534    NotEqual,
535    GTEqual,
536    LTEqual,
537    REMatch,
538    NotREMatch,
539    IN,
540    IS,
541    // Selector operator
542    DOT,
543}
544
545impl BinaryExprType {
546    /// Returns the precedence level for the binary operator.
547    ///
548    /// Higher values bind tighter than lower values.
549    pub fn precedence_level(&self) -> u32 {
550        match self {
551            // Equality operators are least tightly bound
552            BinaryExprType::Equal => 1,
553            BinaryExprType::NotEqual => 1,
554            BinaryExprType::GTEqual => 1,
555            BinaryExprType::LTEqual => 1,
556            BinaryExprType::GT => 1,
557            BinaryExprType::LT => 1,
558            BinaryExprType::REMatch => 1,
559            BinaryExprType::NotREMatch => 1,
560            BinaryExprType::IN => 2,
561            BinaryExprType::IS => 2,
562            // Sum operators are next least tightly bound
563            BinaryExprType::Add => 3,
564            BinaryExprType::Sub => 3,
565            // Product operators are next tightly bound
566            BinaryExprType::Mul => 4,
567            BinaryExprType::Div => 4,
568            BinaryExprType::Mod => 4,
569            // Boolean operators bind tighter than math
570            BinaryExprType::AND => 5,
571            BinaryExprType::OR => 5,
572            // Dot operators are most tightly bound.
573            BinaryExprType::DOT => 6,
574        }
575    }
576}
577
578/// Represents an expression with a left and a right side.
579#[derive(Debug, PartialEq, Clone)]
580pub struct BinaryOpDef {
581    pub kind: BinaryExprType,
582    pub left: Box<Expression>,
583    pub right: Box<Expression>,
584    pub pos: Position,
585}
586
587/// Encodes a tuple Copy expression in the UCG AST.
588#[derive(Debug, PartialEq, Clone)]
589pub struct CopyDef {
590    pub selector: Value,
591    pub fields: FieldList,
592    pub pos: Position,
593}
594
595/// Encodes one of two possible forms for format expression arguments.
596#[derive(Debug, PartialEq, Clone)]
597pub enum FormatArgs {
598    List(Vec<Expression>),
599    Single(Box<Expression>),
600}
601
602/// Encodes a format expression in the UCG AST.
603#[derive(Debug, PartialEq, Clone)]
604pub struct FormatDef {
605    pub template: String,
606    pub args: FormatArgs,
607    pub pos: Position,
608}
609
610/// Encodes an import statement in the UCG AST.
611#[derive(Debug, PartialEq, Clone)]
612pub struct IncludeDef {
613    pub pos: Position,
614    pub path: Token,
615    pub typ: Token,
616}
617
618/// Encodes a list expression in the UCG AST.
619#[derive(Debug, PartialEq, Clone)]
620pub struct ListDef {
621    pub elems: Vec<Expression>,
622    pub pos: Position,
623}
624
625#[derive(Debug, PartialEq, Clone)]
626pub enum FuncOpDef {
627    Reduce(ReduceOpDef),
628    Map(MapFilterOpDef),
629    Filter(MapFilterOpDef),
630}
631
632#[derive(Debug, PartialEq, Clone)]
633pub struct ReduceOpDef {
634    pub func: Box<Expression>,
635    pub acc: Box<Expression>,
636    pub target: Box<Expression>,
637    pub pos: Position,
638}
639
640/// MapFilterOpDef implements the list operations in the UCG AST.
641#[derive(Debug, PartialEq, Clone)]
642pub struct MapFilterOpDef {
643    pub func: Box<Expression>,
644    pub target: Box<Expression>,
645    pub pos: Position,
646}
647
648impl FuncOpDef {
649    pub fn pos(&self) -> &Position {
650        match self {
651            FuncOpDef::Map(def) => &def.pos,
652            FuncOpDef::Filter(def) => &def.pos,
653            FuncOpDef::Reduce(def) => &def.pos,
654        }
655    }
656}
657
658#[derive(Debug, PartialEq, Clone)]
659pub struct ModuleDef {
660    pub scope: Option<Scope>,
661    pub pos: Position,
662    pub arg_set: FieldList,
663    pub out_expr: Option<Box<Expression>>,
664    pub arg_tuple: Option<Rc<Val>>,
665    pub statements: Vec<Statement>,
666}
667
668impl ModuleDef {
669    pub fn new<P: Into<Position>>(arg_set: FieldList, stmts: Vec<Statement>, pos: P) -> Self {
670        ModuleDef {
671            scope: None,
672            pos: pos.into(),
673            arg_set: arg_set,
674            out_expr: None,
675            arg_tuple: None,
676            statements: stmts,
677        }
678    }
679
680    pub fn set_out_expr(&mut self, expr: Expression) {
681        self.out_expr = Some(Box::new(expr));
682    }
683}
684
685pub struct Rewriter {
686    base: PathBuf,
687}
688
689impl Rewriter {
690    pub fn new<P: Into<PathBuf>>(base: P) -> Self {
691        Self { base: base.into() }
692    }
693}
694
695fn normalize_path(p: PathBuf) -> PathBuf {
696    let mut normalized = PathBuf::new();
697    for segment in p.components() {
698        normalized.push(segment);
699    }
700    return normalized;
701}
702
703impl walk::Walker for Rewriter {
704    fn visit_expression(&mut self, expr: &mut Expression) {
705        // Rewrite all paths except for stdlib paths to absolute.
706        let main_separator = format!("{}", std::path::MAIN_SEPARATOR);
707        if let Expression::Include(ref mut def) = expr {
708            let path = PathBuf::from(&def.path.fragment);
709            def.path.fragment = normalize_path(self.base.join(path))
710                .to_string_lossy()
711                .to_string();
712        }
713        if let Expression::Import(ref mut def) = expr {
714            let path = PathBuf::from(
715                &def.path
716                    .fragment
717                    .replace("/", &main_separator)
718                    .replace("\\", &main_separator),
719            );
720            // std/ paths are special and do not get made into absolute paths.
721            if path.starts_with(format!("std{}", main_separator)) {
722                return;
723            }
724            def.path.fragment = normalize_path(self.base.join(path))
725                .to_string_lossy()
726                .to_string();
727        }
728    }
729}
730
731/// RangeDef defines a range with optional step.
732#[derive(Debug, PartialEq, Clone)]
733pub struct RangeDef {
734    pub pos: Position,
735    pub start: Box<Expression>,
736    pub step: Option<Box<Expression>>,
737    pub end: Box<Expression>,
738}
739
740/// Encodes an import expression in the UCG AST.
741#[derive(Debug, PartialEq, Clone)]
742pub struct ImportDef {
743    pub pos: Position,
744    pub path: Token,
745}
746
747#[derive(Debug, PartialEq, Clone)]
748pub struct IsDef {
749    pub pos: Position,
750    pub target: Box<Expression>,
751    pub typ: Token,
752}
753
754#[derive(Debug, PartialEq, Clone)]
755pub struct FailDef {
756    pub pos: Position,
757    pub message: Box<Expression>,
758}
759
760#[derive(Debug, PartialEq, Clone)]
761pub struct NotDef {
762    pub pos: Position,
763    pub expr: Box<Expression>,
764}
765
766#[derive(Debug, PartialEq, Clone)]
767pub struct DebugDef {
768    pub pos: Position,
769    pub expr: Box<Expression>,
770}
771
772/// Encodes a ucg expression. Expressions compute a value from.
773#[derive(Debug, PartialEq, Clone)]
774pub enum Expression {
775    // Base Expression
776    Simple(Value),
777    Not(NotDef),
778
779    // Binary expressions
780    Binary(BinaryOpDef),
781
782    // Complex Expressions
783    Copy(CopyDef),
784    Range(RangeDef),
785    Grouped(Box<Expression>, Position),
786    Format(FormatDef),
787    Include(IncludeDef),
788    Import(ImportDef),
789    Call(CallDef),
790    Cast(CastDef),
791    Func(FuncDef),
792    Select(SelectDef),
793    FuncOp(FuncOpDef),
794    Module(ModuleDef),
795
796    // Declarative failure expressions
797    Fail(FailDef),
798    // Debugging assistance
799    Debug(DebugDef),
800}
801
802impl Expression {
803    /// Returns the position of the Expression.
804    pub fn pos(&self) -> &Position {
805        match self {
806            &Expression::Simple(ref v) => v.pos(),
807            &Expression::Binary(ref def) => &def.pos,
808            &Expression::Copy(ref def) => &def.pos,
809            &Expression::Range(ref def) => &def.pos,
810            &Expression::Grouped(_, ref pos) => pos,
811            &Expression::Format(ref def) => &def.pos,
812            &Expression::Call(ref def) => &def.pos,
813            &Expression::Cast(ref def) => &def.pos,
814            &Expression::Func(ref def) => &def.pos,
815            &Expression::Module(ref def) => &def.pos,
816            &Expression::Select(ref def) => &def.pos,
817            &Expression::FuncOp(ref def) => def.pos(),
818            &Expression::Include(ref def) => &def.pos,
819            &Expression::Import(ref def) => &def.pos,
820            &Expression::Fail(ref def) => &def.pos,
821            &Expression::Not(ref def) => &def.pos,
822            &Expression::Debug(ref def) => &def.pos,
823        }
824    }
825
826    fn derive_shape(&self) -> Result<Shape, BuildError> {
827        // FIXME(jwall): Implement this
828        let shape = match self {
829            Expression::Simple(ref v) => v.try_into()?,
830            Expression::Format(def) => {
831                Shape::Str(PositionedItem::new("".to_owned(), def.pos.clone()))
832            }
833            Expression::Not(def) => Shape::Boolean(PositionedItem::new(true, def.pos.clone())),
834            Expression::Grouped(v, _pos) => v.as_ref().try_into()?,
835            _ => Shape::Empty(Position::new(0, 0, 0)),
836        };
837        Ok(shape)
838    }
839}
840
841impl TryFrom<&Expression> for Shape {
842    type Error = crate::error::BuildError;
843
844    fn try_from(e: &Expression) -> Result<Self, Self::Error> {
845        e.derive_shape()
846    }
847}
848
849impl fmt::Display for Expression {
850    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
851        match self {
852            &Expression::Simple(ref v) => {
853                write!(w, "{}", v.to_string())?;
854            }
855            &Expression::Binary(_) => {
856                write!(w, "<Expr>")?;
857            }
858            &Expression::FuncOp(_) => {
859                write!(w, "<Expr>")?;
860            }
861            &Expression::Copy(_) => {
862                write!(w, "<Copy>")?;
863            }
864            &Expression::Range(_) => {
865                write!(w, "<Range>")?;
866            }
867            &Expression::Grouped(_, _) => {
868                write!(w, "(<Expr>)")?;
869            }
870            &Expression::Format(_) => {
871                write!(w, "<Format Expr>")?;
872            }
873            &Expression::Call(_) => {
874                write!(w, "<FuncCall>")?;
875            }
876            &Expression::Cast(_) => {
877                write!(w, "<Cast>")?;
878            }
879            &Expression::Func(_) => {
880                write!(w, "<Func>")?;
881            }
882            &Expression::Module(_) => {
883                write!(w, "<Module>")?;
884            }
885            &Expression::Select(_) => {
886                write!(w, "<Select>")?;
887            }
888            &Expression::Include(_) => {
889                write!(w, "<Include>")?;
890            }
891            &Expression::Import(_) => {
892                write!(w, "<Include>")?;
893            }
894            &Expression::Fail(_) => {
895                write!(w, "<Fail>")?;
896            }
897            &Expression::Not(ref def) => {
898                write!(w, "!{}", def.expr)?;
899            }
900            &Expression::Debug(ref def) => {
901                write!(w, "!{}", def.expr)?;
902            }
903        }
904        Ok(())
905    }
906}
907
908/// Encodes a let statement in the UCG AST.
909#[derive(Debug, PartialEq, Clone)]
910pub struct LetDef {
911    pub pos: Position,
912    pub name: Token,
913    pub value: Expression,
914}
915
916/// Encodes a parsed statement in the UCG AST.
917#[derive(Debug, PartialEq, Clone)]
918pub enum Statement {
919    // simple expression
920    Expression(Expression),
921
922    // Named bindings
923    Let(LetDef),
924
925    // Assert statement
926    Assert(Position, Expression),
927
928    // Identify an Expression for output.
929    Output(Position, Token, Expression),
930
931    // Print the expression to stdout.
932    Print(Position, Token, Expression),
933}
934
935impl Statement {
936    fn pos(&self) -> &Position {
937        match self {
938            Statement::Expression(ref e) => e.pos(),
939            Statement::Let(ref def) => &def.pos,
940            Statement::Assert(ref pos, _) => pos,
941            Statement::Output(ref pos, _, _) => pos,
942            Statement::Print(ref pos, _, _) => pos,
943        }
944    }
945}
946
947#[cfg(test)]
948mod test;