Skip to main content

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::collections::BTreeMap;
23use std::convert::Into;
24use std::fmt;
25use std::hash::Hash;
26use std::hash::Hasher;
27use std::path::PathBuf;
28use std::rc::Rc;
29
30use abortable_parser;
31
32use crate::build::scope::Scope;
33use crate::build::Val;
34
35pub mod printer;
36pub mod rewrite;
37pub mod typecheck;
38pub mod walk;
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,
81            column,
82            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: Rc<str>,
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<Rc<str>>, 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<Rc<str>>>(f: S, typ: TokenType, pos: Position) -> Self {
140        Token {
141            typ,
142            fragment: f.into(),
143            pos,
144        }
145    }
146}
147
148impl<'a> From<&'a Token> for PositionedItem<Rc<str>> {
149    fn from(value: &'a Token) -> Self {
150        Self::new(value.fragment.clone(), value.pos.clone())
151    }
152}
153
154impl abortable_parser::Positioned for Token {
155    fn line(&self) -> usize {
156        self.pos.line
157    }
158    fn column(&self) -> usize {
159        self.pos.column
160    }
161}
162
163impl Borrow<str> for Token {
164    fn borrow(&self) -> &str {
165        &self.fragment
166    }
167}
168
169/// Helper macro for making a Positioned Value.
170macro_rules! value_node {
171    ($v:expr, $p:expr) => {
172        PositionedItem::new_with_pos($v, $p)
173    };
174}
175
176/// Helper macro for making a Token.
177#[allow(unused_macros)]
178macro_rules! make_tok {
179    (EOF => $i:expr) => {
180        Token::new("", TokenType::END, &$i)
181    };
182
183    (WS => $i:expr) => {
184        Token::new("", TokenType::WS, &$i)
185    };
186
187    (CMT => $e:expr, $i:expr) => {
188        Token::new($e, TokenType::COMMENT, &$i)
189    };
190
191    (QUOT => $e:expr, $i:expr) => {
192        Token::new($e, TokenType::QUOTED, &$i)
193    };
194
195    (PUNCT => $e:expr, $i:expr) => {
196        Token::new($e, TokenType::PUNCT, &$i)
197    };
198
199    (DIGIT => $e:expr, $i:expr) => {
200        Token::new($e, TokenType::DIGIT, &$i)
201    };
202
203    ($e:expr, $i:expr) => {
204        Token::new($e, TokenType::BAREWORD, &$i)
205    };
206}
207
208/// Helper macro for making expressions.
209#[allow(unused_macros)]
210macro_rules! make_expr {
211    ($e:expr, $i:expr) => {
212        Expression::Simple(Value::Symbol(PositionedItem::new_with_pos(
213            $e.to_string(),
214            $i,
215        )))
216    };
217
218    ($e:expr => int, $i:expr) => {
219        Expression::Simple(Value::Int(PositionedItem::new_with_pos($e, $i)))
220    };
221}
222
223/// An ordered list of Name = Value pairs.
224///
225/// This is usually used as the body of a tuple in the UCG AST.
226pub type FieldList = Vec<(Token, Option<Expression>, Expression)>; // Token is expected to be a symbol, with optional constraint
227
228pub type TupleShape = Vec<(PositionedItem<Rc<str>>, Shape)>;
229pub type ShapeList = Vec<Shape>;
230
231#[derive(PartialEq, Debug, Clone)]
232pub struct FuncShapeDef {
233    args: BTreeMap<Rc<str>, Shape>,
234    ret: Box<Shape>,
235}
236
237#[derive(PartialEq, Debug, Clone)]
238pub struct ModuleShape {
239    items: TupleShape,
240    ret: Box<Shape>,
241}
242
243#[doc = "Value types represent the Values that UCG can have."]
244#[derive(PartialEq, Debug, Clone)]
245pub enum Value {
246    Empty(Position),
247    Boolean(PositionedItem<bool>),
248    Int(PositionedItem<i64>),
249    Float(PositionedItem<f64>),
250    Str(PositionedItem<Rc<str>>),
251    Symbol(PositionedItem<Rc<str>>),
252    Tuple(PositionedItem<FieldList>),
253    List(ListDef),
254}
255
256#[derive(PartialEq, Debug, Clone)]
257pub enum ImportShape {
258    Resolved(Position, TupleShape),
259    Unresolved(PositionedItem<Rc<str>>),
260}
261
262#[derive(PartialEq, Debug, Clone)]
263pub enum NarrowingShape {
264    Narrowed(Vec<Shape>),
265    Any,
266}
267
268#[derive(PartialEq, Debug, Clone)]
269pub struct NarrowedShape {
270    pub pos: Position,
271    pub types: NarrowingShape,
272}
273
274impl NarrowedShape {
275    pub fn new(types: Vec<Shape>, line: usize, column: usize, offset: usize) -> Self {
276        Self::new_with_pos(types, Position::new(line, column, offset))
277    }
278
279    pub fn new_with_pos(types: Vec<Shape>, pos: Position) -> Self {
280        Self {
281            pos,
282            types: NarrowingShape::Narrowed(types),
283        }
284    }
285
286    pub fn with_pos(mut self, pos: Position) -> Self {
287        self.pos = pos;
288        self
289    }
290
291    pub fn merge_in_shape(&mut self, shape: Shape, symbol_table: &mut BTreeMap<Rc<str>, Shape>) {
292        match &mut self.types {
293            NarrowingShape::Narrowed(ref mut types) => {
294                for s in types.iter() {
295                    if s.equivalent(&shape, symbol_table) {
296                        return;
297                    }
298                }
299                types.push(shape);
300            }
301            NarrowingShape::Any => {
302                self.types = NarrowingShape::Narrowed(vec![shape]);
303            }
304        }
305    }
306}
307
308// TODO(jwall): Display implementations for shapes.
309/// Shapes represent the types that UCG values or expressions can have.
310#[derive(PartialEq, Debug, Clone)]
311pub enum Shape {
312    Boolean(Position),
313    Int(Position),
314    Float(Position),
315    Str(Position),
316    Tuple(PositionedItem<TupleShape>),
317    List(NarrowedShape),
318    Func(FuncShapeDef),
319    Module(ModuleShape),
320    Hole(PositionedItem<Rc<str>>), // A type hole We don't know what this type is yet.
321    Narrowed(NarrowedShape),       // A narrowed type. We know *some* of the possible options.
322    Import(ImportShape),           // A type hole We don't know what this type is yet.
323    TypeErr(Position, String),     // A type hole We don't know what this type is yet.
324}
325
326impl Shape {
327    pub fn equivalent(&self, right: &Shape, symbol_table: &BTreeMap<Rc<str>, Shape>) -> bool {
328        match (self, right) {
329            (Shape::Str(_), Shape::Str(_))
330            | (Shape::Boolean(_), Shape::Boolean(_))
331            | (Shape::Int(_), Shape::Int(_))
332            | (Shape::Hole(_), Shape::Hole(_))
333            | (Shape::Float(_), Shape::Float(_)) => true,
334            (
335                Shape::List(NarrowedShape {
336                    pos: _,
337                    types: NarrowingShape::Any,
338                }),
339                Shape::List(NarrowedShape {
340                    pos: _,
341                    types: NarrowingShape::Any,
342                }),
343            )
344            | (
345                Shape::Narrowed(NarrowedShape {
346                    pos: _,
347                    types: NarrowingShape::Any,
348                }),
349                Shape::Narrowed(NarrowedShape {
350                    pos: _,
351                    types: NarrowingShape::Any,
352                }),
353            ) => true,
354            (
355                Shape::List(NarrowedShape {
356                    pos: _,
357                    types: NarrowingShape::Narrowed(left_slist),
358                }),
359                Shape::List(NarrowedShape {
360                    pos: _,
361                    types: NarrowingShape::Narrowed(right_slist),
362                }),
363            )
364            | (
365                Shape::Narrowed(NarrowedShape {
366                    pos: _,
367                    types: NarrowingShape::Narrowed(left_slist),
368                }),
369                Shape::Narrowed(NarrowedShape {
370                    pos: _,
371                    types: NarrowingShape::Narrowed(right_slist),
372                }),
373            ) => {
374                for ls in left_slist.iter() {
375                    let mut found = false;
376                    for rs in right_slist.iter() {
377                        if ls.equivalent(rs, symbol_table) {
378                            found = true;
379                            break;
380                        }
381                    }
382                    if !found {
383                        return false;
384                    }
385                }
386                true
387            }
388            (
389                Shape::List(NarrowedShape {
390                    pos: _,
391                    types: NarrowingShape::Any,
392                }),
393                Shape::List(NarrowedShape {
394                    pos: _,
395                    types: NarrowingShape::Narrowed(_right_slist),
396                }),
397            )
398            | (
399                Shape::Narrowed(NarrowedShape {
400                    pos: _,
401                    types: NarrowingShape::Any,
402                }),
403                Shape::Narrowed(NarrowedShape {
404                    pos: _,
405                    types: NarrowingShape::Narrowed(_right_slist),
406                }),
407            ) => true,
408            (
409                Shape::List(NarrowedShape {
410                    pos: _pos,
411                    types: NarrowingShape::Narrowed(_left_slist),
412                }),
413                Shape::List(NarrowedShape {
414                    pos: _,
415                    types: NarrowingShape::Any,
416                }),
417            )
418            | (
419                Shape::Narrowed(NarrowedShape {
420                    pos: _pos,
421                    types: NarrowingShape::Narrowed(_left_slist),
422                }),
423                Shape::Narrowed(NarrowedShape {
424                    pos: _,
425                    types: NarrowingShape::Any,
426                }),
427            ) => true,
428            (Shape::Tuple(left_slist), Shape::Tuple(right_slist)) => {
429                for (lt, ls) in left_slist.val.iter() {
430                    let mut found = false;
431                    for (rt, rs) in right_slist.val.iter() {
432                        if lt.val == rt.val && ls.equivalent(rs, symbol_table) {
433                            found = true;
434                        }
435                    }
436                    if !found {
437                        return false;
438                    }
439                }
440                true
441            }
442            (Shape::Func(left_opshape), Shape::Func(right_opshape)) => {
443                if left_opshape.args.len() != right_opshape.args.len() {
444                    return false;
445                }
446                let left_args: Vec<&Shape> = left_opshape.args.values().collect();
447                let right_args: Vec<&Shape> = right_opshape.args.values().collect();
448                for idx in 0..left_args.len() {
449                    let shap = left_args[idx];
450                    if !shap.equivalent(right_args[idx], symbol_table) {
451                        return false;
452                    }
453                }
454                if !&left_opshape
455                    .ret
456                    .equivalent(&right_opshape.ret, symbol_table)
457                {
458                    return false;
459                }
460                true
461            }
462            (Shape::Module(left_opshape), Shape::Module(right_opshape)) => {
463                // Check items have compatible structure
464                for (lt, ls) in left_opshape.items.iter() {
465                    let mut found = false;
466                    for (rt, rs) in right_opshape.items.iter() {
467                        if lt.val == rt.val && ls.equivalent(rs, symbol_table) {
468                            found = true;
469                            break;
470                        }
471                    }
472                    if !found {
473                        return false;
474                    }
475                }
476                // Check return types
477                left_opshape
478                    .ret
479                    .equivalent(&right_opshape.ret, symbol_table)
480            }
481            _ => false,
482        }
483    }
484
485    pub fn narrow(&self, right: &Shape, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Self {
486        match (self, right) {
487            // Propagate TypeErr
488            (Shape::TypeErr(_, _), _) => self.clone(),
489            (_, Shape::TypeErr(_, _)) => right.clone(),
490            // Same-type narrowing
491            (Shape::Str(_), Shape::Str(_))
492            | (Shape::Boolean(_), Shape::Boolean(_))
493            | (Shape::Int(_), Shape::Int(_))
494            | (Shape::Float(_), Shape::Float(_)) => self.clone(),
495            (Shape::Hole(sym), other) | (other, Shape::Hole(sym)) => {
496                if symbol_table.contains_key(&sym.val) {
497                    symbol_table.insert(sym.val.clone(), other.clone().with_pos(sym.pos.clone()));
498                }
499                other.clone()
500            }
501            // Narrowed(Any) is unconstrained - matches anything
502            (
503                Shape::Narrowed(NarrowedShape {
504                    types: NarrowingShape::Any,
505                    ..
506                }),
507                other,
508            )
509            | (
510                other,
511                Shape::Narrowed(NarrowedShape {
512                    types: NarrowingShape::Any,
513                    ..
514                }),
515            ) => other.clone(),
516            // Narrowed with empty candidates acts as unconstrained
517            (
518                Shape::Narrowed(NarrowedShape {
519                    types: NarrowingShape::Narrowed(types),
520                    ..
521                }),
522                other,
523            ) if types.is_empty() => other.clone(),
524            (
525                other,
526                Shape::Narrowed(NarrowedShape {
527                    types: NarrowingShape::Narrowed(types),
528                    ..
529                }),
530            ) if types.is_empty() => other.clone(),
531            // Narrowed with candidates vs concrete type - filter candidates
532            (
533                Shape::Narrowed(NarrowedShape {
534                    pos: _,
535                    types: NarrowingShape::Narrowed(types),
536                }),
537                other,
538            ) => {
539                let compatible: Vec<Shape> = types
540                    .iter()
541                    .filter(|t| {
542                        let result = t.narrow(other, symbol_table);
543                        !matches!(result, Shape::TypeErr(_, _))
544                    })
545                    .cloned()
546                    .collect();
547                if compatible.is_empty() {
548                    Shape::TypeErr(
549                        right.pos().clone(),
550                        format!(
551                            "No narrowed candidate is compatible with {}",
552                            other.type_name()
553                        ),
554                    )
555                } else {
556                    other.clone()
557                }
558            }
559            (
560                other,
561                Shape::Narrowed(NarrowedShape {
562                    pos: _,
563                    types: NarrowingShape::Narrowed(types),
564                }),
565            ) => {
566                let compatible: Vec<Shape> = types
567                    .iter()
568                    .filter(|t| {
569                        let result = other.narrow(t, symbol_table);
570                        !matches!(result, Shape::TypeErr(_, _))
571                    })
572                    .cloned()
573                    .collect();
574                if compatible.is_empty() {
575                    Shape::TypeErr(
576                        right.pos().clone(),
577                        format!(
578                            "No narrowed candidate is compatible with {}",
579                            other.type_name()
580                        ),
581                    )
582                } else {
583                    other.clone()
584                }
585            }
586            (Shape::List(left_slist), Shape::List(right_slist)) => {
587                self.narrow_list_shapes(left_slist, right_slist, right, symbol_table)
588            }
589            (Shape::Tuple(left_slist), Shape::Tuple(right_slist)) => {
590                self.narrow_tuple_shapes(left_slist, right_slist, right, symbol_table)
591            }
592            (Shape::Func(left_opshape), Shape::Func(right_opshape)) => {
593                if left_opshape.args.len() != right_opshape.args.len() {
594                    return Shape::TypeErr(
595                        right.pos().clone(),
596                        format!(
597                            "Function arity mismatch: expected {} args, got {}",
598                            left_opshape.args.len(),
599                            right_opshape.args.len()
600                        ),
601                    );
602                }
603                let left_args: Vec<&Shape> = left_opshape.args.values().collect();
604                let right_args: Vec<&Shape> = right_opshape.args.values().collect();
605                for idx in 0..left_args.len() {
606                    let narrowed = left_args[idx].narrow(right_args[idx], symbol_table);
607                    if let Shape::TypeErr(_, _) = narrowed {
608                        return Shape::TypeErr(
609                            right.pos().clone(),
610                            "Incompatible function argument types".to_owned(),
611                        );
612                    }
613                }
614                let ret_narrowed = left_opshape.ret.narrow(&right_opshape.ret, symbol_table);
615                if let Shape::TypeErr(_, _) = ret_narrowed {
616                    return Shape::TypeErr(
617                        right.pos().clone(),
618                        "Incompatible function return types".to_owned(),
619                    );
620                }
621                self.clone()
622            }
623            (Shape::Module(left_opshape), Shape::Module(right_opshape)) => {
624                // Check items are structurally compatible
625                for (lt, ls) in left_opshape.items.iter() {
626                    let mut found = false;
627                    for (rt, rs) in right_opshape.items.iter() {
628                        if lt.val == rt.val {
629                            let narrowed = ls.narrow(rs, symbol_table);
630                            if let Shape::TypeErr(_, _) = narrowed {
631                                return Shape::TypeErr(
632                                    right.pos().clone(),
633                                    "Incompatible module argument types".to_owned(),
634                                );
635                            }
636                            found = true;
637                            break;
638                        }
639                    }
640                    if !found {
641                        return Shape::TypeErr(
642                            right.pos().clone(),
643                            "Incompatible Module Shapes".to_owned(),
644                        );
645                    }
646                }
647                // Narrow return types
648                let ret_narrowed = left_opshape.ret.narrow(&right_opshape.ret, symbol_table);
649                if let Shape::TypeErr(_, _) = ret_narrowed {
650                    return Shape::TypeErr(
651                        right.pos().clone(),
652                        "Incompatible module return types".to_owned(),
653                    );
654                }
655                self.clone()
656            }
657            _ => Shape::TypeErr(
658                right.pos().clone(),
659                format!(
660                    "Expected {} but got {}",
661                    self.type_name(),
662                    right.type_name()
663                ),
664            ),
665        }
666    }
667
668    fn narrow_tuple_shapes(
669        &self,
670        left_slist: &PositionedItem<Vec<(PositionedItem<Rc<str>>, Shape)>>,
671        right_slist: &PositionedItem<Vec<(PositionedItem<Rc<str>>, Shape)>>,
672        right: &Shape,
673        symbol_table: &mut BTreeMap<Rc<str>, Shape>,
674    ) -> Shape {
675        let left_iter = left_slist.val.iter();
676        let right_iter = right_slist.val.iter();
677        if is_tuple_subset(left_iter, right_slist, symbol_table) {
678            self.clone()
679        } else if is_tuple_subset(right_iter, left_slist, symbol_table) {
680            right.clone()
681        } else {
682            Shape::TypeErr(right.pos().clone(), "Incompatible Tuple Shapes".to_owned())
683        }
684    }
685
686    fn narrow_list_shapes(
687        &self,
688        left_slist: &NarrowedShape,
689        right_slist: &NarrowedShape,
690        right: &Shape,
691        symbol_table: &mut BTreeMap<Rc<str>, Shape>,
692    ) -> Shape {
693        match (&left_slist.types, &right_slist.types) {
694            (
695                NarrowingShape::Narrowed(ref left_types),
696                NarrowingShape::Narrowed(ref right_types),
697            ) => {
698                let left_iter = left_types.iter();
699                let right_iter = right_types.iter();
700                if is_list_subset(left_iter, right_slist, symbol_table) {
701                    self.clone()
702                } else if is_list_subset(right_iter, left_slist, symbol_table) {
703                    right.clone()
704                } else {
705                    Shape::TypeErr(right.pos().clone(), "Incompatible List Shapes".to_owned())
706                }
707            }
708            (NarrowingShape::Narrowed(_), NarrowingShape::Any)
709            | (NarrowingShape::Any, NarrowingShape::Any) => self.clone(),
710            (NarrowingShape::Any, NarrowingShape::Narrowed(_)) => right.clone(),
711        }
712    }
713
714    pub fn type_name(&self) -> &'static str {
715        match self {
716            Shape::Str(_) => "str",
717            Shape::Int(_) => "int",
718            Shape::Float(_) => "float",
719            Shape::Boolean(_) => "boolean",
720            // TODO(jwall): make these type names account for what they contain.
721            Shape::List(_) => "list",
722            Shape::Tuple(_) => "tuple",
723            Shape::Func(_) => "func",
724            Shape::Module(_) => "module",
725            Shape::Narrowed(_) => "narrowed",
726            Shape::Import(_) => "import",
727            Shape::Hole(_) => "type-hole",
728            Shape::TypeErr(_, _) => "type-error",
729        }
730    }
731
732    pub fn pos(&self) -> &Position {
733        match self {
734            Shape::Str(p) => &p,
735            Shape::Int(p) => &p,
736            Shape::Float(p) => &p,
737            Shape::Boolean(p) => &p,
738            Shape::List(lst) => &lst.pos,
739            Shape::Tuple(flds) => &flds.pos,
740            Shape::Func(def) => def.ret.pos(),
741            Shape::Module(def) => def.ret.pos(),
742            Shape::Narrowed(pi) => &pi.pos,
743            Shape::Hole(pi) => &pi.pos,
744            Shape::TypeErr(pos, _) => pos,
745            Shape::Import(ImportShape::Resolved(p, _)) => p,
746            Shape::Import(ImportShape::Unresolved(pi)) => &pi.pos,
747        }
748    }
749
750    pub fn with_pos(self, pos: Position) -> Self {
751        match self {
752            Shape::Str(_) => Shape::Str(pos.clone()),
753            Shape::Int(_) => Shape::Int(pos.clone()),
754            Shape::Float(_) => Shape::Float(pos.clone()),
755            Shape::Boolean(_) => Shape::Boolean(pos.clone()),
756            Shape::List(NarrowedShape {
757                pos: _,
758                types: NarrowingShape::Narrowed(lst),
759            }) => Shape::List(NarrowedShape::new_with_pos(lst, pos)),
760            Shape::List(NarrowedShape {
761                pos: _,
762                types: NarrowingShape::Any,
763            }) => Shape::List(NarrowedShape {
764                pos,
765                types: NarrowingShape::Any,
766            }),
767            Shape::Tuple(flds) => Shape::Tuple(PositionedItem::new(flds.val, pos)),
768            Shape::Func(_) | Shape::Module(_) => self.clone(),
769            Shape::Narrowed(narrowed_shape) => Shape::Narrowed(narrowed_shape.with_pos(pos)),
770            Shape::Hole(pi) => Shape::Hole(pi.with_pos(pos)),
771            Shape::Import(ImportShape::Resolved(_, s)) => {
772                Shape::Import(ImportShape::Resolved(pos, s))
773            }
774            Shape::Import(ImportShape::Unresolved(pi)) => {
775                Shape::Import(ImportShape::Unresolved(pi.with_pos(pos)))
776            }
777            Shape::TypeErr(_, msg) => Shape::TypeErr(pos, msg),
778        }
779    }
780}
781
782fn is_tuple_subset(
783    mut left_iter: std::slice::Iter<(PositionedItem<Rc<str>>, Shape)>,
784    right_slist: &PositionedItem<Vec<(PositionedItem<Rc<str>>, Shape)>>,
785    symbol_table: &mut BTreeMap<Rc<str>, Shape>,
786) -> bool {
787    return loop {
788        if let Some((lt, ls)) = left_iter.next() {
789            let mut matched = false;
790            for (rt, rs) in right_slist.val.iter() {
791                if rt.val == lt.val {
792                    if let Shape::TypeErr(_, _) = ls.narrow(rs, symbol_table) {
793                        // noop
794                    } else {
795                        matched = true;
796                        continue;
797                    }
798                }
799            }
800            if !matched {
801                break false;
802            } else {
803                continue;
804            }
805        }
806        break true;
807    };
808}
809
810fn is_list_subset(
811    mut right_iter: std::slice::Iter<Shape>,
812    left_slist: &NarrowedShape,
813    symbol_table: &mut BTreeMap<Rc<str>, Shape>,
814) -> bool {
815    let left_slist = match &left_slist.types {
816        NarrowingShape::Any => return true,
817        NarrowingShape::Narrowed(ref list) => list,
818    };
819    let right_subset = loop {
820        let mut matches = false;
821        let ls = if let Some(ls) = right_iter.next() {
822            ls
823        } else {
824            break true;
825        };
826        for rs in left_slist.iter() {
827            let s = ls.narrow(rs, symbol_table);
828            if let Shape::TypeErr(_, _) = s {
829                // noop
830            } else {
831                matches = true;
832            }
833        }
834        if !matches {
835            break matches;
836        }
837    };
838    right_subset
839}
840
841impl Value {
842    /// Returns the type name of the Value it is called on as a string.
843    pub fn type_name(&self) -> String {
844        match self {
845            &Value::Empty(_) => "EmptyValue".to_string(),
846            &Value::Boolean(_) => "Boolean".to_string(),
847            &Value::Int(_) => "Integer".to_string(),
848            &Value::Float(_) => "Float".to_string(),
849            &Value::Str(_) => "String".to_string(),
850            &Value::Symbol(_) => "Symbol".to_string(),
851            &Value::Tuple(_) => "Tuple".to_string(),
852            &Value::List(_) => "List".to_string(),
853        }
854    }
855
856    fn fields_to_string(v: &FieldList) -> String {
857        let mut buf = String::new();
858        buf.push_str("{\n");
859        for (tok, _, _) in v.iter() {
860            buf.push_str("\t");
861            buf.push_str(&tok.fragment);
862            buf.push_str("\n");
863        }
864        buf.push_str("}");
865        return buf;
866    }
867
868    fn elems_to_string(v: &Vec<Expression>) -> String {
869        return format!("{}", v.len());
870    }
871
872    /// Returns a stringified version of the Value.
873    pub fn to_string(&self) -> String {
874        match self {
875            &Value::Empty(_) => "EmptyValue".to_string(),
876            &Value::Boolean(ref b) => format!("{}", b.val),
877            &Value::Int(ref i) => format!("{}", i.val),
878            &Value::Float(ref f) => format!("{}", f.val),
879            &Value::Str(ref s) => format!("{}", s.val),
880            &Value::Symbol(ref s) => format!("{}", s.val),
881            &Value::Tuple(ref fs) => format!("{}", Self::fields_to_string(&fs.val)),
882            &Value::List(ref def) => format!("[{}]", Self::elems_to_string(&def.elems)),
883        }
884    }
885
886    /// Returns the position for a Value.
887    pub fn pos(&self) -> &Position {
888        match self {
889            &Value::Empty(ref pos) => pos,
890            &Value::Boolean(ref b) => &b.pos,
891            &Value::Int(ref i) => &i.pos,
892            &Value::Float(ref f) => &f.pos,
893            &Value::Str(ref s) => &s.pos,
894            &Value::Symbol(ref s) => &s.pos,
895            &Value::Tuple(ref fs) => &fs.pos,
896            &Value::List(ref def) => &def.pos,
897        }
898    }
899
900    /// Returns true if called on a Value that is the same type as itself.
901    pub fn type_equal(&self, target: &Self) -> bool {
902        enum_type_equality!(
903            self,
904            target,
905            &Value::Empty(_),
906            &Value::Boolean(_),
907            &Value::Int(_),
908            &Value::Float(_),
909            &Value::Str(_),
910            &Value::Symbol(_),
911            &Value::Tuple(_),
912            &Value::List(_)
913        )
914    }
915}
916
917/// Represents an expansion of a Macro that is expected to already have been
918/// defined.
919#[derive(PartialEq, Debug, Clone)]
920pub struct CallDef {
921    pub funcref: Value,
922    pub arglist: Vec<Expression>,
923    pub pos: Position,
924}
925
926/// The allowable types to which you can perform a primitive cast.
927#[derive(PartialEq, Debug, Clone)]
928pub enum CastType {
929    Int,
930    Float,
931    Str,
932    Bool,
933}
934
935impl fmt::Display for CastType {
936    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
937        write!(
938            w,
939            "{}",
940            match self {
941                CastType::Int => "int",
942                CastType::Float => "float",
943                CastType::Bool => "bool",
944                CastType::Str => "str",
945            }
946        )
947    }
948}
949
950/// Represents a cast of a target to a primitive type.
951#[derive(PartialEq, Debug, Clone)]
952pub struct CastDef {
953    pub cast_type: CastType,
954    pub target: Box<Expression>,
955    pub pos: Position,
956}
957
958/// Encodes a select expression in the UCG AST.
959#[derive(PartialEq, Debug, Clone)]
960pub struct SelectDef {
961    pub val: Box<Expression>,
962    pub default: Option<Box<Expression>>,
963    pub tuple: FieldList,
964    pub pos: Position,
965}
966
967/// Adds position information to any type `T`.
968#[derive(Debug, Clone)]
969pub struct PositionedItem<T> {
970    pub pos: Position,
971    pub val: T,
972}
973
974impl<T: std::fmt::Display> std::fmt::Display for PositionedItem<T> {
975    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
976        write!(f, "{}", self.val)
977    }
978}
979
980impl<T> PositionedItem<T> {
981    /// Constructs a new Positioned<T> with a value, line, and column information.
982    pub fn new<P: Into<Position>>(v: T, p: P) -> Self {
983        Self::new_with_pos(v, p.into())
984    }
985
986    /// Constructs a new Positioned<T> with a value and a Position.
987    pub fn new_with_pos(v: T, pos: Position) -> Self {
988        PositionedItem { pos, val: v }
989    }
990
991    pub fn with_pos(mut self, pos: Position) -> Self {
992        self.pos = pos;
993        self
994    }
995}
996
997impl<T: PartialEq> PartialEq for PositionedItem<T> {
998    fn eq(&self, other: &Self) -> bool {
999        self.val == other.val
1000    }
1001}
1002
1003impl<T: Eq> Eq for PositionedItem<T> {}
1004
1005impl<T: Ord> Ord for PositionedItem<T> {
1006    fn cmp(&self, other: &Self) -> Ordering {
1007        self.val.cmp(&other.val)
1008    }
1009}
1010
1011impl<T: PartialOrd> PartialOrd for PositionedItem<T> {
1012    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1013        self.val.partial_cmp(&other.val)
1014    }
1015}
1016
1017impl<T: Hash> Hash for PositionedItem<T> {
1018    fn hash<H: Hasher>(&self, state: &mut H) {
1019        self.val.hash(state);
1020    }
1021}
1022
1023impl<'a> From<&'a Token> for PositionedItem<String> {
1024    fn from(t: &'a Token) -> PositionedItem<String> {
1025        PositionedItem {
1026            pos: t.pos.clone(),
1027            val: t.fragment.to_string(),
1028        }
1029    }
1030}
1031
1032impl<'a> From<&'a PositionedItem<Rc<str>>> for PositionedItem<Rc<str>> {
1033    fn from(t: &PositionedItem<Rc<str>>) -> PositionedItem<Rc<str>> {
1034        PositionedItem {
1035            pos: t.pos.clone(),
1036            val: t.val.clone(),
1037        }
1038    }
1039}
1040
1041/// Encodes a func expression in the UCG AST..
1042///
1043/// A func is a pure function over a expression.
1044#[derive(PartialEq, Debug, Clone)]
1045pub struct FuncDef {
1046    pub scope: Option<Scope>,
1047    pub argdefs: Vec<(PositionedItem<Rc<str>>, Option<Expression>)>,
1048    pub fields: Box<Expression>,
1049    pub pos: Position,
1050}
1051
1052/// Specifies the types of binary operations supported in
1053/// UCG expression.
1054#[derive(Debug, PartialEq, Clone)]
1055pub enum BinaryExprType {
1056    // Math
1057    Add,
1058    Sub,
1059    Mul,
1060    Div,
1061    Mod,
1062    // Boolean
1063    AND,
1064    OR,
1065    // Comparison
1066    Equal,
1067    GT,
1068    LT,
1069    NotEqual,
1070    GTEqual,
1071    LTEqual,
1072    REMatch,
1073    NotREMatch,
1074    IN,
1075    IS,
1076    // Selector operator
1077    DOT,
1078}
1079
1080impl BinaryExprType {
1081    /// Returns the precedence level for the binary operator.
1082    ///
1083    /// Higher values bind tighter than lower values.
1084    pub fn precedence_level(&self) -> u32 {
1085        match self {
1086            // Equality operators are least tightly bound
1087            BinaryExprType::Equal => 1,
1088            BinaryExprType::NotEqual => 1,
1089            BinaryExprType::GTEqual => 1,
1090            BinaryExprType::LTEqual => 1,
1091            BinaryExprType::GT => 1,
1092            BinaryExprType::LT => 1,
1093            BinaryExprType::REMatch => 1,
1094            BinaryExprType::NotREMatch => 1,
1095            BinaryExprType::IN => 2,
1096            BinaryExprType::IS => 2,
1097            // Sum operators are next least tightly bound
1098            BinaryExprType::Add => 3,
1099            BinaryExprType::Sub => 3,
1100            // Product operators are next tightly bound
1101            BinaryExprType::Mul => 4,
1102            BinaryExprType::Div => 4,
1103            BinaryExprType::Mod => 4,
1104            // Boolean operators bind tighter than math
1105            BinaryExprType::AND => 5,
1106            BinaryExprType::OR => 5,
1107            // Dot operators are most tightly bound.
1108            BinaryExprType::DOT => 6,
1109        }
1110    }
1111}
1112
1113/// Represents an expression with a left and a right side.
1114#[derive(Debug, PartialEq, Clone)]
1115pub struct BinaryOpDef {
1116    pub kind: BinaryExprType,
1117    pub left: Box<Expression>,
1118    pub right: Box<Expression>,
1119    pub pos: Position,
1120}
1121
1122/// Encodes a tuple Copy expression in the UCG AST.
1123#[derive(Debug, PartialEq, Clone)]
1124pub struct CopyDef {
1125    pub selector: Value,
1126    pub fields: FieldList,
1127    pub pos: Position,
1128}
1129
1130/// Encodes one of two possible forms for format expression arguments.
1131#[derive(Debug, PartialEq, Clone)]
1132pub enum FormatArgs {
1133    List(Vec<Expression>),
1134    Single(Box<Expression>),
1135}
1136
1137/// Encodes a format expression in the UCG AST.
1138#[derive(Debug, PartialEq, Clone)]
1139pub struct FormatDef {
1140    pub template: String,
1141    pub args: FormatArgs,
1142    pub pos: Position,
1143}
1144
1145/// Encodes an import statement in the UCG AST.
1146#[derive(Debug, PartialEq, Clone)]
1147pub struct IncludeDef {
1148    pub pos: Position,
1149    pub path: Token,
1150    pub typ: Token,
1151}
1152
1153/// Encodes a list expression in the UCG AST.
1154#[derive(Debug, PartialEq, Clone)]
1155pub struct ListDef {
1156    pub elems: Vec<Expression>,
1157    pub pos: Position,
1158}
1159
1160#[derive(Debug, PartialEq, Clone)]
1161pub enum FuncOpDef {
1162    Reduce(ReduceOpDef),
1163    Map(MapFilterOpDef),
1164    Filter(MapFilterOpDef),
1165}
1166
1167#[derive(Debug, PartialEq, Clone)]
1168pub struct ReduceOpDef {
1169    pub func: Box<Expression>,
1170    pub acc: Box<Expression>,
1171    pub target: Box<Expression>,
1172    pub pos: Position,
1173}
1174
1175/// MapFilterOpDef implements the list operations in the UCG AST.
1176#[derive(Debug, PartialEq, Clone)]
1177pub struct MapFilterOpDef {
1178    pub func: Box<Expression>,
1179    pub target: Box<Expression>,
1180    pub pos: Position,
1181}
1182
1183impl FuncOpDef {
1184    pub fn pos(&self) -> &Position {
1185        match self {
1186            FuncOpDef::Map(def) => &def.pos,
1187            FuncOpDef::Filter(def) => &def.pos,
1188            FuncOpDef::Reduce(def) => &def.pos,
1189        }
1190    }
1191}
1192
1193#[derive(Debug, PartialEq, Clone)]
1194pub struct ModuleDef {
1195    pub scope: Option<Scope>,
1196    pub pos: Position,
1197    pub arg_set: FieldList,
1198    pub out_expr: Option<Box<Expression>>,
1199    pub out_constraint: Option<Box<Expression>>,
1200    pub arg_tuple: Option<Rc<Val>>,
1201    pub statements: Vec<Statement>,
1202}
1203
1204impl ModuleDef {
1205    pub fn new<P: Into<Position>>(arg_set: FieldList, stmts: Vec<Statement>, pos: P) -> Self {
1206        ModuleDef {
1207            scope: None,
1208            pos: pos.into(),
1209            arg_set,
1210            out_expr: None,
1211            out_constraint: None,
1212            arg_tuple: None,
1213            statements: stmts,
1214        }
1215    }
1216
1217    pub fn set_out_expr(&mut self, expr: Expression) {
1218        self.out_expr = Some(Box::new(expr));
1219    }
1220}
1221
1222/// RangeDef defines a range with optional step.
1223#[derive(Debug, PartialEq, Clone)]
1224pub struct RangeDef {
1225    pub pos: Position,
1226    pub start: Box<Expression>,
1227    pub step: Option<Box<Expression>>,
1228    pub end: Box<Expression>,
1229}
1230
1231/// Encodes an import expression in the UCG AST.
1232#[derive(Debug, PartialEq, Clone)]
1233pub struct ImportDef {
1234    pub pos: Position,
1235    pub path: Token,
1236}
1237
1238#[derive(Debug, PartialEq, Clone)]
1239pub struct IsDef {
1240    pub pos: Position,
1241    pub target: Box<Expression>,
1242    pub typ: Token,
1243}
1244
1245#[derive(Debug, PartialEq, Clone)]
1246pub struct FailDef {
1247    pub pos: Position,
1248    pub message: Box<Expression>,
1249}
1250
1251#[derive(Debug, PartialEq, Clone)]
1252pub struct NotDef {
1253    pub pos: Position,
1254    pub expr: Box<Expression>,
1255}
1256
1257#[derive(Debug, PartialEq, Clone)]
1258pub struct DebugDef {
1259    pub pos: Position,
1260    pub expr: Box<Expression>,
1261}
1262
1263/// Encodes a ucg expression. Expressions compute a value from.
1264#[derive(Debug, PartialEq, Clone)]
1265pub enum Expression {
1266    // Base Expression
1267    Simple(Value),
1268    Not(NotDef),
1269
1270    // Binary expressions
1271    Binary(BinaryOpDef),
1272
1273    // Complex Expressions
1274    Copy(CopyDef),
1275    Range(RangeDef),
1276    Grouped(Box<Expression>, Position),
1277    Format(FormatDef),
1278    Include(IncludeDef),
1279    Import(ImportDef),
1280    Call(CallDef),
1281    Cast(CastDef),
1282    Func(FuncDef),
1283    Select(SelectDef),
1284    FuncOp(FuncOpDef),
1285    Module(ModuleDef),
1286
1287    // Declarative failure expressions
1288    Fail(FailDef),
1289    // Debugging assistance
1290    Debug(DebugDef),
1291}
1292
1293impl Expression {
1294    /// Returns the position of the Expression.
1295    pub fn pos(&self) -> &Position {
1296        match self {
1297            &Expression::Simple(ref v) => v.pos(),
1298            &Expression::Binary(ref def) => &def.pos,
1299            &Expression::Copy(ref def) => &def.pos,
1300            &Expression::Range(ref def) => &def.pos,
1301            &Expression::Grouped(_, ref pos) => pos,
1302            &Expression::Format(ref def) => &def.pos,
1303            &Expression::Call(ref def) => &def.pos,
1304            &Expression::Cast(ref def) => &def.pos,
1305            &Expression::Func(ref def) => &def.pos,
1306            &Expression::Module(ref def) => &def.pos,
1307            &Expression::Select(ref def) => &def.pos,
1308            &Expression::FuncOp(ref def) => def.pos(),
1309            &Expression::Include(ref def) => &def.pos,
1310            &Expression::Import(ref def) => &def.pos,
1311            &Expression::Fail(ref def) => &def.pos,
1312            &Expression::Not(ref def) => &def.pos,
1313            &Expression::Debug(ref def) => &def.pos,
1314        }
1315    }
1316}
1317
1318impl fmt::Display for Expression {
1319    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
1320        match self {
1321            &Expression::Simple(ref v) => {
1322                write!(w, "{}", v.to_string())?;
1323            }
1324            &Expression::Binary(_) => {
1325                write!(w, "<Expr>")?;
1326            }
1327            &Expression::FuncOp(_) => {
1328                write!(w, "<Expr>")?;
1329            }
1330            &Expression::Copy(_) => {
1331                write!(w, "<Copy>")?;
1332            }
1333            &Expression::Range(_) => {
1334                write!(w, "<Range>")?;
1335            }
1336            &Expression::Grouped(_, _) => {
1337                write!(w, "(<Expr>)")?;
1338            }
1339            &Expression::Format(_) => {
1340                write!(w, "<Format Expr>")?;
1341            }
1342            &Expression::Call(_) => {
1343                write!(w, "<FuncCall>")?;
1344            }
1345            &Expression::Cast(_) => {
1346                write!(w, "<Cast>")?;
1347            }
1348            &Expression::Func(_) => {
1349                write!(w, "<Func>")?;
1350            }
1351            &Expression::Module(_) => {
1352                write!(w, "<Module>")?;
1353            }
1354            &Expression::Select(_) => {
1355                write!(w, "<Select>")?;
1356            }
1357            &Expression::Include(_) => {
1358                write!(w, "<Include>")?;
1359            }
1360            &Expression::Import(_) => {
1361                write!(w, "<Include>")?;
1362            }
1363            &Expression::Fail(_) => {
1364                write!(w, "<Fail>")?;
1365            }
1366            &Expression::Not(ref def) => {
1367                write!(w, "!{}", def.expr)?;
1368            }
1369            &Expression::Debug(ref def) => {
1370                write!(w, "!{}", def.expr)?;
1371            }
1372        }
1373        Ok(())
1374    }
1375}
1376
1377/// Encodes a let statement in the UCG AST.
1378#[derive(Debug, PartialEq, Clone)]
1379pub struct LetDef {
1380    pub pos: Position,
1381    pub name: Token,
1382    pub constraint: Option<Expression>,
1383    pub value: Expression,
1384}
1385
1386/// Encodes a parsed statement in the UCG AST.
1387#[derive(Debug, PartialEq, Clone)]
1388pub enum Statement {
1389    // simple expression
1390    Expression(Expression),
1391
1392    // Named bindings
1393    Let(LetDef),
1394
1395    // Assert statement
1396    Assert(Position, Expression),
1397
1398    // Identify an Expression for output.
1399    Output(Position, Token, Expression),
1400
1401    // Print the expression to stdout.
1402    Print(Position, Token, Expression),
1403}
1404
1405impl Statement {
1406    fn pos(&self) -> &Position {
1407        match self {
1408            Statement::Expression(ref e) => e.pos(),
1409            Statement::Let(ref def) => &def.pos,
1410            Statement::Assert(ref pos, _) => pos,
1411            Statement::Output(ref pos, _, _) => pos,
1412            Statement::Print(ref pos, _, _) => pos,
1413        }
1414    }
1415}
1416
1417#[cfg(test)]
1418mod test;