1use 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#[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 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#[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#[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 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 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
163macro_rules! value_node {
165 ($v:expr, $p:expr) => {
166 PositionedItem::new_with_pos($v, $p)
167 };
168}
169
170#[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#[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
217pub type FieldList = Vec<(Token, Expression)>; pub 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 Empty(Position),
244 Boolean(PositionedItem<bool>),
245 Int(PositionedItem<i64>),
246 Float(PositionedItem<f64>),
247 Str(PositionedItem<String>),
248 Symbol(PositionedItem<String>),
249 Tuple(PositionedItem<$t>),
251 List($l),
252 $( $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 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 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 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 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 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#[derive(PartialEq, Debug, Clone)]
390pub struct CallDef {
391 pub funcref: Value,
392 pub arglist: Vec<Expression>,
393 pub pos: Position,
394}
395
396#[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#[derive(PartialEq, Debug, Clone)]
422pub struct CastDef {
423 pub cast_type: CastType,
424 pub target: Box<Expression>,
425 pub pos: Position,
426}
427
428#[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#[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 pub fn new<P: Into<Position>>(v: T, p: P) -> Self {
453 Self::new_with_pos(v, p.into())
454 }
455
456 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#[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#[derive(Debug, PartialEq, Clone)]
520pub enum BinaryExprType {
521 Add,
523 Sub,
524 Mul,
525 Div,
526 Mod,
527 AND,
529 OR,
530 Equal,
532 GT,
533 LT,
534 NotEqual,
535 GTEqual,
536 LTEqual,
537 REMatch,
538 NotREMatch,
539 IN,
540 IS,
541 DOT,
543}
544
545impl BinaryExprType {
546 pub fn precedence_level(&self) -> u32 {
550 match self {
551 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 BinaryExprType::Add => 3,
564 BinaryExprType::Sub => 3,
565 BinaryExprType::Mul => 4,
567 BinaryExprType::Div => 4,
568 BinaryExprType::Mod => 4,
569 BinaryExprType::AND => 5,
571 BinaryExprType::OR => 5,
572 BinaryExprType::DOT => 6,
574 }
575 }
576}
577
578#[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#[derive(Debug, PartialEq, Clone)]
589pub struct CopyDef {
590 pub selector: Value,
591 pub fields: FieldList,
592 pub pos: Position,
593}
594
595#[derive(Debug, PartialEq, Clone)]
597pub enum FormatArgs {
598 List(Vec<Expression>),
599 Single(Box<Expression>),
600}
601
602#[derive(Debug, PartialEq, Clone)]
604pub struct FormatDef {
605 pub template: String,
606 pub args: FormatArgs,
607 pub pos: Position,
608}
609
610#[derive(Debug, PartialEq, Clone)]
612pub struct IncludeDef {
613 pub pos: Position,
614 pub path: Token,
615 pub typ: Token,
616}
617
618#[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#[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 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 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#[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#[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#[derive(Debug, PartialEq, Clone)]
774pub enum Expression {
775 Simple(Value),
777 Not(NotDef),
778
779 Binary(BinaryOpDef),
781
782 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 Fail(FailDef),
798 Debug(DebugDef),
800}
801
802impl Expression {
803 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 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#[derive(Debug, PartialEq, Clone)]
910pub struct LetDef {
911 pub pos: Position,
912 pub name: Token,
913 pub value: Expression,
914}
915
916#[derive(Debug, PartialEq, Clone)]
918pub enum Statement {
919 Expression(Expression),
921
922 Let(LetDef),
924
925 Assert(Position, Expression),
927
928 Output(Position, Token, Expression),
930
931 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;