1use crate::ast;
17use crate::error::*;
18use crate::lexer::Pos;
19use crate::log;
20use crate::stablemapset::{StableMap, StableSet};
21use std::collections::BTreeMap;
22use std::collections::BTreeSet;
23use std::collections::HashMap;
24use std::collections::hash_map::Entry;
25use std::fmt;
26
27declare_id!(
28 Sym
30);
31declare_id!(
32 TypeId
34);
35declare_id!(
36 VariantId
38);
39declare_id!(
40 FieldId
42);
43declare_id!(
44 TermId
46);
47declare_id!(
48 RuleId
50);
51declare_id!(
52 VarId
54);
55
56#[derive(Debug)]
60pub struct TypeEnv {
61 pub syms: Vec<String>,
65
66 pub sym_map: StableMap<String, Sym>,
68
69 pub types: Vec<Type>,
73
74 pub type_map: StableMap<Sym, TypeId>,
76
77 pub const_types: StableMap<Sym, TypeId>,
79
80 pub errors: Vec<Error>,
82}
83
84#[derive(Copy, Clone, Debug, PartialEq, Eq)]
86#[repr(u8)]
87pub enum BuiltinType {
88 Bool,
90 Int(IntType),
92}
93
94#[derive(Copy, Clone, Debug, PartialEq, Eq)]
96pub enum IntType {
97 U8,
99 U16,
101 U32,
103 U64,
105 U128,
107 USize,
109 I8,
111 I16,
113 I32,
115 I64,
117 I128,
119 ISize,
121}
122
123impl IntType {
124 pub fn name(&self) -> &'static str {
126 match self {
127 IntType::U8 => "u8",
128 IntType::U16 => "u16",
129 IntType::U32 => "u32",
130 IntType::U64 => "u64",
131 IntType::U128 => "u128",
132 IntType::USize => "usize",
133 IntType::I8 => "i8",
134 IntType::I16 => "i16",
135 IntType::I32 => "i32",
136 IntType::I64 => "i64",
137 IntType::I128 => "i128",
138 IntType::ISize => "isize",
139 }
140 }
141
142 pub fn is_signed(&self) -> bool {
144 match self {
145 IntType::U8
146 | IntType::U16
147 | IntType::U32
148 | IntType::U64
149 | IntType::U128
150 | IntType::USize => false,
151
152 IntType::I8
153 | IntType::I16
154 | IntType::I32
155 | IntType::I64
156 | IntType::I128
157 | IntType::ISize => true,
158 }
159 }
160}
161
162impl fmt::Display for IntType {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 write!(f, "{}", self.name())
165 }
166}
167
168impl BuiltinType {
169 pub const ALL: &'static [Self] = &[
171 Self::Bool,
172 Self::Int(IntType::U8),
173 Self::Int(IntType::U16),
174 Self::Int(IntType::U32),
175 Self::Int(IntType::U64),
176 Self::Int(IntType::U128),
177 Self::Int(IntType::USize),
178 Self::Int(IntType::I8),
179 Self::Int(IntType::I16),
180 Self::Int(IntType::I32),
181 Self::Int(IntType::I64),
182 Self::Int(IntType::I128),
183 Self::Int(IntType::ISize),
184 ];
185
186 pub fn name(&self) -> &'static str {
188 match self {
189 BuiltinType::Bool => "bool",
190 BuiltinType::Int(it) => it.name(),
191 }
192 }
193
194 const fn to_usize(&self) -> usize {
195 match self {
196 Self::Bool => 0,
197 Self::Int(ty) => *ty as usize + 1,
198 }
199 }
200}
201
202impl TypeId {
203 const fn builtin(builtin: BuiltinType) -> Self {
204 Self(builtin.to_usize())
205 }
206
207 pub const BOOL: Self = Self::builtin(BuiltinType::Bool);
209
210 pub const U8: Self = Self::builtin(BuiltinType::Int(IntType::U8));
212 pub const U16: Self = Self::builtin(BuiltinType::Int(IntType::U16));
214 pub const U32: Self = Self::builtin(BuiltinType::Int(IntType::U32));
216 pub const U64: Self = Self::builtin(BuiltinType::Int(IntType::U64));
218 pub const U128: Self = Self::builtin(BuiltinType::Int(IntType::U128));
220 pub const USIZE: Self = Self::builtin(BuiltinType::Int(IntType::USize));
222
223 pub const I8: Self = Self::builtin(BuiltinType::Int(IntType::I8));
225 pub const I16: Self = Self::builtin(BuiltinType::Int(IntType::I16));
227 pub const I32: Self = Self::builtin(BuiltinType::Int(IntType::I32));
229 pub const I64: Self = Self::builtin(BuiltinType::Int(IntType::I64));
231 pub const I128: Self = Self::builtin(BuiltinType::Int(IntType::I128));
233 pub const ISIZE: Self = Self::builtin(BuiltinType::Int(IntType::ISize));
235}
236
237#[derive(Clone, Debug, PartialEq, Eq)]
239pub enum Type {
240 Builtin(BuiltinType),
242
243 Primitive(TypeId, Sym, Pos),
248
249 Enum {
253 name: Sym,
255 id: TypeId,
257 is_extern: bool,
262 is_nodebug: bool,
266 variants: Vec<Variant>,
268 pos: Pos,
270 },
271}
272
273impl Type {
274 pub fn name<'a>(&self, tyenv: &'a TypeEnv) -> &'a str {
276 match self {
277 Self::Builtin(ty) => ty.name(),
278 Self::Primitive(_, name, _) | Self::Enum { name, .. } => &tyenv.syms[name.index()],
279 }
280 }
281
282 pub fn pos(&self) -> Option<Pos> {
284 match self {
285 Self::Builtin(..) => None,
286 Self::Primitive(_, _, pos) | Self::Enum { pos, .. } => Some(*pos),
287 }
288 }
289
290 pub fn is_prim(&self) -> bool {
292 matches!(self, Type::Primitive(..))
293 }
294
295 pub fn is_int(&self) -> bool {
297 matches!(self, Self::Builtin(BuiltinType::Int(_)))
298 }
299}
300
301#[derive(Clone, Debug, PartialEq, Eq)]
303pub struct Variant {
304 pub name: Sym,
306
307 pub fullname: Sym,
312
313 pub id: VariantId,
316
317 pub fields: Vec<Field>,
319}
320
321#[derive(Clone, Debug, PartialEq, Eq)]
323pub struct Field {
324 pub name: Sym,
326 pub id: FieldId,
328 pub ty: TypeId,
330}
331
332#[derive(Clone, Debug)]
338pub struct TermEnv {
339 pub terms: Vec<Term>,
343
344 pub term_map: StableMap<Sym, TermId>,
346
347 pub rules: Vec<Rule>,
351
352 pub converters: StableMap<(TypeId, TypeId), TermId>,
356
357 pub expand_internal_extractors: bool,
360}
361
362#[derive(Clone, Debug, PartialEq, Eq)]
368pub struct Term {
369 pub id: TermId,
371 pub decl_pos: Pos,
373 pub name: Sym,
375 pub arg_tys: Vec<TypeId>,
377 pub ret_ty: TypeId,
379 pub kind: TermKind,
381}
382
383#[derive(Copy, Clone, Debug, PartialEq, Eq)]
385pub struct TermFlags {
386 pub pure: bool,
388 pub multi: bool,
390 pub partial: bool,
392 pub rec: bool,
394}
395
396impl TermFlags {
397 pub fn on_lhs(mut self) -> Self {
399 self.pure = true;
400 self.partial = true;
401 self
402 }
403}
404
405#[derive(Clone, Debug, PartialEq, Eq)]
407pub enum TermKind {
408 EnumVariant {
410 variant: VariantId,
413 },
414 Decl {
416 flags: TermFlags,
418 constructor_kind: Option<ConstructorKind>,
420 extractor_kind: Option<ExtractorKind>,
422 },
423}
424
425#[derive(Clone, Debug, PartialEq, Eq)]
427pub enum ConstructorKind {
428 InternalConstructor,
431 ExternalConstructor {
433 name: Sym,
435 },
436}
437
438#[derive(Clone, Debug, PartialEq, Eq)]
440pub enum ExtractorKind {
441 InternalExtractor {
445 template: ast::Pattern,
447 },
448 ExternalExtractor {
450 name: Sym,
452 infallible: bool,
454 pos: Pos,
456 },
457}
458
459#[derive(Clone, Copy, Debug, Eq, PartialEq)]
461pub enum ReturnKind {
462 Plain,
464 Option,
466 Iterator,
468}
469
470#[derive(Clone, Debug)]
472pub struct ExternalSig {
473 pub func_name: String,
475 pub full_name: String,
477 pub param_tys: Vec<TypeId>,
479 pub ret_tys: Vec<TypeId>,
481 pub ret_kind: ReturnKind,
483}
484
485impl Term {
486 pub fn ty(&self) -> TypeId {
488 self.ret_ty
489 }
490
491 fn check_args_count<T>(&self, args: &[T], tyenv: &mut TypeEnv, pos: Pos, sym: &ast::Ident) {
492 if self.arg_tys.len() != args.len() {
493 tyenv.report_error(
494 pos,
495 format!(
496 "Incorrect argument count for term '{}': got {}, expect {}",
497 sym.0,
498 args.len(),
499 self.arg_tys.len()
500 ),
501 );
502 }
503 }
504
505 pub fn is_enum_variant(&self) -> bool {
507 matches!(self.kind, TermKind::EnumVariant { .. })
508 }
509
510 pub fn is_partial(&self) -> bool {
512 matches!(
513 self.kind,
514 TermKind::Decl {
515 flags: TermFlags { partial: true, .. },
516 ..
517 }
518 )
519 }
520
521 pub fn is_recursive(&self) -> bool {
523 matches!(
524 self.kind,
525 TermKind::Decl {
526 flags: TermFlags { rec: true, .. },
527 ..
528 }
529 )
530 }
531
532 pub fn has_constructor(&self) -> bool {
534 matches!(
535 self.kind,
536 TermKind::EnumVariant { .. }
537 | TermKind::Decl {
538 constructor_kind: Some(_),
539 ..
540 }
541 )
542 }
543
544 pub fn has_extractor(&self) -> bool {
546 matches!(
547 self.kind,
548 TermKind::EnumVariant { .. }
549 | TermKind::Decl {
550 extractor_kind: Some(_),
551 ..
552 }
553 )
554 }
555
556 pub fn has_external_extractor(&self) -> bool {
558 matches!(
559 self.kind,
560 TermKind::Decl {
561 extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
562 ..
563 }
564 )
565 }
566
567 pub fn has_external_constructor(&self) -> bool {
569 matches!(
570 self.kind,
571 TermKind::Decl {
572 constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }),
573 ..
574 }
575 )
576 }
577
578 pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
580 match &self.kind {
581 TermKind::Decl {
582 flags,
583 extractor_kind:
584 Some(ExtractorKind::ExternalExtractor {
585 name, infallible, ..
586 }),
587 ..
588 } => {
589 let ret_kind = if flags.multi {
590 ReturnKind::Iterator
591 } else if *infallible {
592 ReturnKind::Plain
593 } else {
594 ReturnKind::Option
595 };
596 Some(ExternalSig {
597 func_name: tyenv.syms[name.index()].clone(),
598 full_name: format!("C::{}", tyenv.syms[name.index()]),
599 param_tys: vec![self.ret_ty],
600 ret_tys: self.arg_tys.clone(),
601 ret_kind,
602 })
603 }
604 _ => None,
605 }
606 }
607
608 pub fn constructor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
610 match &self.kind {
611 TermKind::Decl {
612 constructor_kind: Some(kind),
613 flags,
614 ..
615 } => {
616 let (func_name, full_name) = match kind {
617 ConstructorKind::InternalConstructor => {
618 let name = format!("constructor_{}", tyenv.syms[self.name.index()]);
619 (name.clone(), name)
620 }
621 ConstructorKind::ExternalConstructor { name } => (
622 tyenv.syms[name.index()].clone(),
623 format!("C::{}", tyenv.syms[name.index()]),
624 ),
625 };
626 let ret_kind = if flags.multi {
627 ReturnKind::Iterator
628 } else if flags.partial {
629 ReturnKind::Option
630 } else {
631 ReturnKind::Plain
632 };
633 Some(ExternalSig {
634 func_name,
635 full_name,
636 param_tys: self.arg_tys.clone(),
637 ret_tys: vec![self.ret_ty],
638 ret_kind,
639 })
640 }
641 _ => None,
642 }
643 }
644}
645
646#[derive(Clone, Debug)]
648pub struct Rule {
649 pub id: RuleId,
651 pub root_term: TermId,
653 pub args: Vec<Pattern>,
655 pub iflets: Vec<IfLet>,
657 pub rhs: Expr,
660 pub vars: Vec<BoundVar>,
662 pub prio: i64,
664 pub pos: Pos,
666 pub name: Option<Sym>,
668}
669
670#[derive(Clone, Debug)]
672pub struct BoundVar {
673 pub id: VarId,
675 pub name: Sym,
677 pub ty: TypeId,
679 scope: usize,
682}
683
684#[derive(Clone, Debug)]
687pub struct IfLet {
688 pub lhs: Pattern,
691 pub rhs: Expr,
694}
695
696#[derive(Clone, Debug, PartialEq, Eq)]
698pub enum Pattern {
699 BindPattern(TypeId, VarId, Box<Pattern>),
703
704 Var(TypeId, VarId),
707
708 ConstBool(TypeId, bool),
710
711 ConstInt(TypeId, i128),
714
715 ConstPrim(TypeId, Sym),
718
719 Term(TypeId, TermId, Vec<Pattern>),
722
723 Wildcard(TypeId),
725
726 And(TypeId, Vec<Pattern>),
728}
729
730#[derive(Clone, Debug, PartialEq, Eq)]
732pub enum Expr {
733 Term(TypeId, TermId, Vec<Expr>),
735 Var(TypeId, VarId),
737 ConstBool(TypeId, bool),
739 ConstInt(TypeId, i128),
741 ConstPrim(TypeId, Sym),
743 Let {
746 ty: TypeId,
748 bindings: Vec<(VarId, TypeId, Box<Expr>)>,
750 body: Box<Expr>,
752 },
753}
754
755pub trait PatternVisitor {
758 type PatternId: Copy;
760
761 fn add_match_equal(&mut self, a: Self::PatternId, b: Self::PatternId, ty: TypeId);
763 fn add_match_bool(&mut self, input: Self::PatternId, ty: TypeId, bool_val: bool);
765 fn add_match_int(&mut self, input: Self::PatternId, ty: TypeId, int_val: i128);
767 fn add_match_prim(&mut self, input: Self::PatternId, ty: TypeId, val: Sym);
769
770 fn add_match_variant(
773 &mut self,
774 input: Self::PatternId,
775 input_ty: TypeId,
776 arg_tys: &[TypeId],
777 variant: VariantId,
778 ) -> Vec<Self::PatternId>;
779
780 fn add_extract(
784 &mut self,
785 input: Self::PatternId,
786 input_ty: TypeId,
787 output_tys: Vec<TypeId>,
788 term: TermId,
789 infallible: bool,
790 multi: bool,
791 ) -> Vec<Self::PatternId>;
792}
793
794impl Pattern {
795 pub fn ty(&self) -> TypeId {
797 match *self {
798 Self::BindPattern(t, ..) => t,
799 Self::Var(t, ..) => t,
800 Self::ConstBool(t, ..) => t,
801 Self::ConstInt(t, ..) => t,
802 Self::ConstPrim(t, ..) => t,
803 Self::Term(t, ..) => t,
804 Self::Wildcard(t, ..) => t,
805 Self::And(t, ..) => t,
806 }
807 }
808
809 pub fn visit<V: PatternVisitor>(
811 &self,
812 visitor: &mut V,
813 input: V::PatternId,
814 termenv: &TermEnv,
815 vars: &mut HashMap<VarId, V::PatternId>,
816 ) {
817 match *self {
818 Pattern::BindPattern(_ty, var, ref subpat) => {
819 assert!(!vars.contains_key(&var));
821 vars.insert(var, input);
822 subpat.visit(visitor, input, termenv, vars);
823 }
824 Pattern::Var(ty, var) => {
825 let var_val = vars
827 .get(&var)
828 .copied()
829 .expect("Variable should already be bound");
830 visitor.add_match_equal(input, var_val, ty);
831 }
832 Pattern::ConstBool(ty, value) => visitor.add_match_bool(input, ty, value),
833 Pattern::ConstInt(ty, value) => visitor.add_match_int(input, ty, value),
834 Pattern::ConstPrim(ty, value) => visitor.add_match_prim(input, ty, value),
835 Pattern::Term(ty, term, ref args) => {
836 let termdata = &termenv.terms[term.index()];
838 let arg_values = match &termdata.kind {
839 TermKind::EnumVariant { variant } => {
840 visitor.add_match_variant(input, ty, &termdata.arg_tys, *variant)
841 }
842 TermKind::Decl {
843 extractor_kind: None,
844 ..
845 } => {
846 panic!("Pattern invocation of undefined term body")
847 }
848 TermKind::Decl {
849 extractor_kind: Some(ExtractorKind::InternalExtractor { .. }),
850 ..
851 } => {
852 panic!("Should have been expanded away")
853 }
854 TermKind::Decl {
855 flags,
856 extractor_kind: Some(ExtractorKind::ExternalExtractor { infallible, .. }),
857 ..
858 } => {
859 let output_tys = args.iter().map(|arg| arg.ty()).collect();
861
862 visitor.add_extract(
864 input,
865 termdata.ret_ty,
866 output_tys,
867 term,
868 *infallible && !flags.multi,
869 flags.multi,
870 )
871 }
872 };
873 for (pat, val) in args.iter().zip(arg_values) {
874 pat.visit(visitor, val, termenv, vars);
875 }
876 }
877 Pattern::And(_ty, ref children) => {
878 for child in children {
879 child.visit(visitor, input, termenv, vars);
880 }
881 }
882 Pattern::Wildcard(_ty) => {
883 }
885 }
886 }
887}
888
889pub trait ExprVisitor {
892 type ExprId: Copy;
894
895 fn add_const_bool(&mut self, ty: TypeId, val: bool) -> Self::ExprId;
897 fn add_const_int(&mut self, ty: TypeId, val: i128) -> Self::ExprId;
899 fn add_const_prim(&mut self, ty: TypeId, val: Sym) -> Self::ExprId;
901
902 fn add_create_variant(
904 &mut self,
905 inputs: Vec<(Self::ExprId, TypeId)>,
906 ty: TypeId,
907 variant: VariantId,
908 ) -> Self::ExprId;
909
910 fn add_construct(
912 &mut self,
913 inputs: Vec<(Self::ExprId, TypeId)>,
914 ty: TypeId,
915 term: TermId,
916 pure: bool,
917 infallible: bool,
918 multi: bool,
919 rec: bool,
920 ) -> Self::ExprId;
921}
922
923impl Expr {
924 pub fn ty(&self) -> TypeId {
926 match *self {
927 Self::Term(t, ..) => t,
928 Self::Var(t, ..) => t,
929 Self::ConstBool(t, ..) => t,
930 Self::ConstInt(t, ..) => t,
931 Self::ConstPrim(t, ..) => t,
932 Self::Let { ty: t, .. } => t,
933 }
934 }
935
936 pub fn visit<V: ExprVisitor>(
938 &self,
939 visitor: &mut V,
940 termenv: &TermEnv,
941 vars: &HashMap<VarId, V::ExprId>,
942 ) -> V::ExprId {
943 log!("Expr::visit: expr {:?}", self);
944 match *self {
945 Expr::ConstBool(ty, val) => visitor.add_const_bool(ty, val),
946 Expr::ConstInt(ty, val) => visitor.add_const_int(ty, val),
947 Expr::ConstPrim(ty, val) => visitor.add_const_prim(ty, val),
948 Expr::Let {
949 ty: _ty,
950 ref bindings,
951 ref body,
952 } => {
953 let mut vars = vars.clone();
954 for &(var, _var_ty, ref var_expr) in bindings {
955 let var_value = var_expr.visit(visitor, termenv, &vars);
956 vars.insert(var, var_value);
957 }
958 body.visit(visitor, termenv, &vars)
959 }
960 Expr::Var(_ty, var_id) => *vars.get(&var_id).unwrap(),
961 Expr::Term(ty, term, ref arg_exprs) => {
962 let termdata = &termenv.terms[term.index()];
963 let arg_values_tys = arg_exprs
964 .iter()
965 .map(|arg_expr| arg_expr.visit(visitor, termenv, vars))
966 .zip(termdata.arg_tys.iter().copied())
967 .collect();
968 match &termdata.kind {
969 TermKind::EnumVariant { variant } => {
970 visitor.add_create_variant(arg_values_tys, ty, *variant)
971 }
972 TermKind::Decl {
973 constructor_kind: Some(_),
974 flags,
975 ..
976 } => {
977 visitor.add_construct(
978 arg_values_tys,
979 ty,
980 term,
981 flags.pure,
982 !flags.partial,
983 flags.multi,
984 flags.rec,
985 )
986 }
987 TermKind::Decl {
988 constructor_kind: None,
989 ..
990 } => panic!("Should have been caught by typechecking"),
991 }
992 }
993 }
994 }
995
996 fn visit_in_rule<V: RuleVisitor>(
997 &self,
998 visitor: &mut V,
999 termenv: &TermEnv,
1000 vars: &HashMap<VarId, <V::PatternVisitor as PatternVisitor>::PatternId>,
1001 ) -> V::Expr {
1002 let var_exprs = vars
1003 .iter()
1004 .map(|(&var, &val)| (var, visitor.pattern_as_expr(val)))
1005 .collect();
1006 visitor.add_expr(|visitor| VisitedExpr {
1007 ty: self.ty(),
1008 value: self.visit(visitor, termenv, &var_exprs),
1009 })
1010 }
1011}
1012
1013#[derive(Clone, Copy)]
1015pub struct VisitedExpr<V: ExprVisitor> {
1016 pub ty: TypeId,
1018 pub value: V::ExprId,
1020}
1021
1022pub trait RuleVisitor {
1025 type PatternVisitor: PatternVisitor;
1027 type ExprVisitor: ExprVisitor;
1029 type Expr;
1032
1033 fn add_arg(
1035 &mut self,
1036 index: usize,
1037 ty: TypeId,
1038 ) -> <Self::PatternVisitor as PatternVisitor>::PatternId;
1039
1040 fn add_pattern<F>(&mut self, visitor: F)
1044 where
1045 F: FnOnce(&mut Self::PatternVisitor);
1046
1047 fn add_expr<F>(&mut self, visitor: F) -> Self::Expr
1049 where
1050 F: FnOnce(&mut Self::ExprVisitor) -> VisitedExpr<Self::ExprVisitor>;
1051
1052 fn expr_as_pattern(
1055 &mut self,
1056 expr: Self::Expr,
1057 ) -> <Self::PatternVisitor as PatternVisitor>::PatternId;
1058
1059 fn pattern_as_expr(
1062 &mut self,
1063 pattern: <Self::PatternVisitor as PatternVisitor>::PatternId,
1064 ) -> <Self::ExprVisitor as ExprVisitor>::ExprId;
1065}
1066
1067impl Rule {
1068 pub fn visit<V: RuleVisitor>(&self, visitor: &mut V, termenv: &TermEnv) -> V::Expr {
1072 let mut vars = HashMap::new();
1073
1074 let termdata = &termenv.terms[self.root_term.index()];
1076 for (i, (subpat, &arg_ty)) in self.args.iter().zip(termdata.arg_tys.iter()).enumerate() {
1077 let value = visitor.add_arg(i, arg_ty);
1078 visitor.add_pattern(|visitor| subpat.visit(visitor, value, termenv, &mut vars));
1079 }
1080
1081 for iflet in self.iflets.iter() {
1083 let subexpr = iflet.rhs.visit_in_rule(visitor, termenv, &vars);
1084 let value = visitor.expr_as_pattern(subexpr);
1085 visitor.add_pattern(|visitor| iflet.lhs.visit(visitor, value, termenv, &mut vars));
1086 }
1087
1088 self.rhs.visit_in_rule(visitor, termenv, &vars)
1090 }
1091}
1092
1093macro_rules! unwrap_or_continue {
1101 ($e:expr) => {
1102 match $e {
1103 Some(x) => x,
1104 None => continue,
1105 }
1106 };
1107}
1108
1109impl Default for TypeEnv {
1110 fn default() -> Self {
1111 Self {
1112 syms: BuiltinType::ALL
1113 .iter()
1114 .map(|bt| String::from(bt.name()))
1115 .collect(),
1116 sym_map: BuiltinType::ALL
1117 .iter()
1118 .enumerate()
1119 .map(|(idx, bt)| (String::from(bt.name()), Sym(idx)))
1120 .collect(),
1121 types: BuiltinType::ALL
1122 .iter()
1123 .map(|bt| Type::Builtin(*bt))
1124 .collect(),
1125 type_map: BuiltinType::ALL
1126 .iter()
1127 .enumerate()
1128 .map(|(idx, _)| (Sym(idx), TypeId(idx)))
1129 .collect(),
1130 const_types: StableMap::new(),
1131 errors: vec![],
1132 }
1133 }
1134}
1135
1136impl TypeEnv {
1137 pub fn from_ast(defs: &[ast::Def]) -> Result<TypeEnv, Vec<Error>> {
1139 let mut tyenv = TypeEnv::default();
1140
1141 for def in defs {
1144 match def {
1145 &ast::Def::Type(ref td) => {
1146 let tid = TypeId(tyenv.type_map.len());
1147 let name = tyenv.intern_mut(&td.name);
1148
1149 if let Some(existing) = tyenv.type_map.get(&name).copied() {
1150 tyenv.report_error(
1151 td.pos,
1152 format!("Type with name '{}' defined more than once", td.name.0),
1153 );
1154 let pos = unwrap_or_continue!(tyenv.types.get(existing.index())).pos();
1155 match pos {
1156 Some(pos) => tyenv.report_error(
1157 pos,
1158 format!("Type with name '{}' already defined here", td.name.0),
1159 ),
1160 None => tyenv.report_error(
1161 td.pos,
1162 format!("Type with name '{}' is a built-in type", td.name.0),
1163 ),
1164 }
1165 continue;
1166 }
1167
1168 tyenv.type_map.insert(name, tid);
1169 }
1170 _ => {}
1171 }
1172 }
1173
1174 for def in defs {
1178 match def {
1179 &ast::Def::Type(ref td) => {
1180 let tid = tyenv.types.len();
1181 if let Some(ty) = tyenv.type_from_ast(TypeId(tid), td) {
1182 tyenv.types.push(ty);
1183 }
1184 }
1185 _ => {}
1186 }
1187 }
1188
1189 for def in defs {
1191 if let &ast::Def::Extern(ast::Extern::Const {
1192 ref name,
1193 ref ty,
1194 pos,
1195 }) = def
1196 {
1197 let ty = match tyenv.get_type_by_name(ty) {
1198 Some(ty) => ty,
1199 None => {
1200 tyenv.report_error(pos, "Unknown type for constant");
1201 continue;
1202 }
1203 };
1204 let name = tyenv.intern_mut(name);
1205 tyenv.const_types.insert(name, ty);
1206 }
1207 }
1208
1209 tyenv.return_errors()?;
1210
1211 Ok(tyenv)
1212 }
1213
1214 fn return_errors(&mut self) -> Result<(), Vec<Error>> {
1215 if self.errors.is_empty() {
1216 Ok(())
1217 } else {
1218 Err(std::mem::take(&mut self.errors))
1219 }
1220 }
1221
1222 fn type_from_ast(&mut self, tid: TypeId, ty: &ast::Type) -> Option<Type> {
1223 let name = self.intern(&ty.name).unwrap();
1224 match &ty.ty {
1225 &ast::TypeValue::Primitive(ref id, ..) => {
1226 if ty.is_nodebug {
1227 self.report_error(ty.pos, "primitive types cannot be marked `nodebug`");
1228 return None;
1229 }
1230 if ty.is_extern {
1231 self.report_error(ty.pos, "primitive types cannot be marked `extern`");
1232 return None;
1233 }
1234 Some(Type::Primitive(tid, self.intern_mut(id), ty.pos))
1235 }
1236 &ast::TypeValue::Enum(ref ty_variants, ..) => {
1237 if ty.is_extern && ty.is_nodebug {
1238 self.report_error(ty.pos, "external types cannot be marked `nodebug`");
1239 return None;
1240 }
1241
1242 let mut variants = vec![];
1243 for variant in ty_variants {
1244 let combined_ident =
1245 ast::Ident(format!("{}.{}", ty.name.0, variant.name.0), variant.name.1);
1246 let fullname = self.intern_mut(&combined_ident);
1247 let name = self.intern_mut(&variant.name);
1248 let id = VariantId(variants.len());
1249 if variants.iter().any(|v: &Variant| v.name == name) {
1250 self.report_error(
1251 variant.pos,
1252 format!("Duplicate variant name in type: '{}'", variant.name.0),
1253 );
1254 return None;
1255 }
1256 let mut fields = vec![];
1257 for field in &variant.fields {
1258 let field_name = self.intern_mut(&field.name);
1259 if fields.iter().any(|f: &Field| f.name == field_name) {
1260 self.report_error(
1261 field.pos,
1262 format!(
1263 "Duplicate field name '{}' in variant '{}' of type",
1264 field.name.0, variant.name.0
1265 ),
1266 );
1267 return None;
1268 }
1269 let field_tid = match self.get_type_by_name(&field.ty) {
1270 Some(tid) => tid,
1271 None => {
1272 self.report_error(
1273 field.ty.1,
1274 format!(
1275 "Unknown type '{}' for field '{}' in variant '{}'",
1276 field.ty.0, field.name.0, variant.name.0
1277 ),
1278 );
1279 return None;
1280 }
1281 };
1282 fields.push(Field {
1283 name: field_name,
1284 id: FieldId(fields.len()),
1285 ty: field_tid,
1286 });
1287 }
1288 variants.push(Variant {
1289 name,
1290 fullname,
1291 id,
1292 fields,
1293 });
1294 }
1295 Some(Type::Enum {
1296 name,
1297 id: tid,
1298 is_extern: ty.is_extern,
1299 is_nodebug: ty.is_nodebug,
1300 variants,
1301 pos: ty.pos,
1302 })
1303 }
1304 }
1305 }
1306
1307 fn error(&self, pos: Pos, msg: impl Into<String>) -> Error {
1308 Error::TypeError {
1309 msg: msg.into(),
1310 span: Span::new_single(pos),
1311 }
1312 }
1313
1314 fn report_error(&mut self, pos: Pos, msg: impl Into<String>) {
1315 let err = self.error(pos, msg);
1316 self.errors.push(err);
1317 }
1318
1319 fn intern_mut(&mut self, ident: &ast::Ident) -> Sym {
1320 if let Some(s) = self.sym_map.get(&ident.0).copied() {
1321 s
1322 } else {
1323 let s = Sym(self.syms.len());
1324 self.syms.push(ident.0.clone());
1325 self.sym_map.insert(ident.0.clone(), s);
1326 s
1327 }
1328 }
1329
1330 fn intern(&self, ident: &ast::Ident) -> Option<Sym> {
1331 self.sym_map.get(&ident.0).copied()
1332 }
1333
1334 pub fn get_type_by_name(&self, sym: &ast::Ident) -> Option<TypeId> {
1336 self.intern(sym)
1337 .and_then(|sym| self.type_map.get(&sym))
1338 .copied()
1339 }
1340}
1341
1342#[derive(Clone, Debug, Default)]
1343struct Bindings {
1344 seen: Vec<BoundVar>,
1347 next_scope: usize,
1349 in_scope: Vec<usize>,
1351}
1352
1353impl Bindings {
1354 fn enter_scope(&mut self) {
1355 self.in_scope.push(self.next_scope);
1356 self.next_scope += 1;
1357 }
1358
1359 fn exit_scope(&mut self) {
1360 self.in_scope.pop();
1361 }
1362
1363 fn add_var(&mut self, name: Sym, ty: TypeId) -> VarId {
1364 let id = VarId(self.seen.len());
1365 let var = BoundVar {
1366 id,
1367 name,
1368 ty,
1369 scope: *self
1370 .in_scope
1371 .last()
1372 .expect("enter_scope should be called before add_var"),
1373 };
1374 log!("binding var {:?}", var);
1375 self.seen.push(var);
1376 id
1377 }
1378
1379 fn lookup(&self, name: Sym) -> Option<&BoundVar> {
1380 self.seen
1381 .iter()
1382 .rev()
1383 .find(|binding| binding.name == name && self.in_scope.contains(&binding.scope))
1384 }
1385}
1386
1387impl TermEnv {
1388 pub fn from_ast(
1390 tyenv: &mut TypeEnv,
1391 defs: &[ast::Def],
1392 expand_internal_extractors: bool,
1393 ) -> Result<TermEnv, Vec<Error>> {
1394 let mut env = TermEnv {
1395 terms: vec![],
1396 term_map: StableMap::new(),
1397 rules: vec![],
1398 converters: StableMap::new(),
1399 expand_internal_extractors,
1400 };
1401
1402 env.collect_pragmas(defs);
1403 env.collect_term_sigs(tyenv, defs);
1404 env.collect_enum_variant_terms(tyenv);
1405 tyenv.return_errors()?;
1406 env.collect_constructors(tyenv, defs);
1407 env.collect_extractor_templates(tyenv, defs);
1408 tyenv.return_errors()?;
1409 env.collect_converters(tyenv, defs);
1410 tyenv.return_errors()?;
1411 env.collect_externs(tyenv, defs);
1412 tyenv.return_errors()?;
1413 env.collect_rules(tyenv, defs);
1414 env.check_for_undefined_decls(tyenv, defs);
1415 env.check_for_expr_terms_without_constructors(tyenv, defs);
1416 tyenv.return_errors()?;
1417
1418 Ok(env)
1419 }
1420
1421 fn collect_pragmas(&mut self, _: &[ast::Def]) {
1422 return;
1424 }
1425
1426 fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1427 for def in defs {
1428 match def {
1429 &ast::Def::Decl(ref decl) => {
1430 let name = tyenv.intern_mut(&decl.term);
1431 if let Some(tid) = self.term_map.get(&name) {
1432 tyenv.report_error(
1433 decl.pos,
1434 format!("Duplicate decl for '{}'", decl.term.0),
1435 );
1436 tyenv.report_error(
1437 self.terms[tid.index()].decl_pos,
1438 format!("Duplicate decl for '{}'", decl.term.0),
1439 );
1440 }
1441
1442 if decl.multi && decl.partial {
1443 tyenv.report_error(
1444 decl.pos,
1445 format!("Term '{}' can't be both multi and partial", decl.term.0),
1446 );
1447 }
1448
1449 let arg_tys = decl
1450 .arg_tys
1451 .iter()
1452 .map(|id| {
1453 tyenv.get_type_by_name(id).ok_or_else(|| {
1454 tyenv.report_error(id.1, format!("Unknown arg type: '{}'", id.0));
1455 })
1456 })
1457 .collect::<Result<Vec<_>, _>>();
1458 let arg_tys = match arg_tys {
1459 Ok(a) => a,
1460 Err(_) => {
1461 continue;
1462 }
1463 };
1464 let ret_ty = match tyenv.get_type_by_name(&decl.ret_ty) {
1465 Some(t) => t,
1466 None => {
1467 tyenv.report_error(
1468 decl.ret_ty.1,
1469 format!("Unknown return type: '{}'", decl.ret_ty.0),
1470 );
1471 continue;
1472 }
1473 };
1474
1475 let tid = TermId(self.terms.len());
1476 self.term_map.insert(name, tid);
1477 let flags = TermFlags {
1478 pure: decl.pure,
1479 multi: decl.multi,
1480 partial: decl.partial,
1481 rec: decl.rec,
1482 };
1483 self.terms.push(Term {
1484 id: tid,
1485 decl_pos: decl.pos,
1486 name,
1487 arg_tys,
1488 ret_ty,
1489 kind: TermKind::Decl {
1490 flags,
1491 constructor_kind: None,
1492 extractor_kind: None,
1493 },
1494 });
1495 }
1496 _ => {}
1497 }
1498 }
1499 }
1500
1501 fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) {
1502 'types: for i in 0..tyenv.types.len() {
1503 let ty = &tyenv.types[i];
1504 match ty {
1505 &Type::Enum {
1506 pos,
1507 id,
1508 ref variants,
1509 ..
1510 } => {
1511 for variant in variants {
1512 if self.term_map.contains_key(&variant.fullname) {
1513 let variant_name = tyenv.syms[variant.fullname.index()].clone();
1514 tyenv.report_error(
1515 pos,
1516 format!("Duplicate enum variant constructor: '{variant_name}'",),
1517 );
1518 continue 'types;
1519 }
1520 let tid = TermId(self.terms.len());
1521 let arg_tys = variant.fields.iter().map(|fld| fld.ty).collect::<Vec<_>>();
1522 let ret_ty = id;
1523 self.terms.push(Term {
1524 id: tid,
1525 decl_pos: pos,
1526 name: variant.fullname,
1527 arg_tys,
1528 ret_ty,
1529 kind: TermKind::EnumVariant {
1530 variant: variant.id,
1531 },
1532 });
1533 self.term_map.insert(variant.fullname, tid);
1534 }
1535 }
1536 _ => {}
1537 }
1538 }
1539 }
1540
1541 fn collect_constructors(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1542 for def in defs {
1543 log!("collect_constructors from def: {:?}", def);
1544 match def {
1545 &ast::Def::Rule(ref rule) => {
1546 let pos = rule.pos;
1547 let term = match rule.pattern.root_term() {
1548 Some(t) => t,
1549 None => {
1550 tyenv.report_error(
1551 pos,
1552 "Rule does not have a term at the LHS root".to_string(),
1553 );
1554 continue;
1555 }
1556 };
1557 let term = match self.get_term_by_name(tyenv, &term) {
1558 Some(tid) => tid,
1559 None => {
1560 tyenv
1561 .report_error(pos, "Rule LHS root term is not defined".to_string());
1562 continue;
1563 }
1564 };
1565 let termdata = &mut self.terms[term.index()];
1566 match &mut termdata.kind {
1567 TermKind::Decl {
1568 constructor_kind, ..
1569 } => {
1570 match constructor_kind {
1571 None => {
1572 *constructor_kind = Some(ConstructorKind::InternalConstructor);
1573 }
1574 Some(ConstructorKind::InternalConstructor) => {
1575 }
1578 Some(ConstructorKind::ExternalConstructor { .. }) => {
1579 tyenv.report_error(
1580 pos,
1581 "Rule LHS root term is incorrect kind; cannot \
1582 be external constructor"
1583 .to_string(),
1584 );
1585 continue;
1586 }
1587 }
1588 }
1589 TermKind::EnumVariant { .. } => {
1590 tyenv.report_error(
1591 pos,
1592 "Rule LHS root term is incorrect kind; cannot be enum variant"
1593 .to_string(),
1594 );
1595 continue;
1596 }
1597 }
1598 }
1599 _ => {}
1600 }
1601 }
1602 }
1603
1604 fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1605 let mut extractor_call_graph = BTreeMap::new();
1606
1607 for def in defs {
1608 if let &ast::Def::Extractor(ref ext) = def {
1609 let term = match self.get_term_by_name(tyenv, &ext.term) {
1610 Some(x) => x,
1611 None => {
1612 tyenv.report_error(
1613 ext.pos,
1614 "Extractor macro body definition on a non-existent term".to_string(),
1615 );
1616 return;
1617 }
1618 };
1619
1620 let template = ext.template.make_macro_template(&ext.args[..]);
1621 log!("extractor def: {:?} becomes template {:?}", def, template);
1622
1623 let mut callees = BTreeSet::new();
1624 template.terms(&mut |pos, t| {
1625 if let Some(term) = self.get_term_by_name(tyenv, t) {
1626 callees.insert(term);
1627 } else {
1628 tyenv.report_error(
1629 pos,
1630 format!(
1631 "`{}` extractor definition references unknown term `{}`",
1632 ext.term.0, t.0
1633 ),
1634 );
1635 }
1636 });
1637 extractor_call_graph.insert(term, callees);
1638
1639 let termdata = &mut self.terms[term.index()];
1640 match &mut termdata.kind {
1641 TermKind::EnumVariant { .. } => {
1642 tyenv.report_error(
1643 ext.pos,
1644 "Extractor macro body defined on term of incorrect kind; cannot be an \
1645 enum variant",
1646 );
1647 continue;
1648 }
1649 TermKind::Decl {
1650 flags,
1651 extractor_kind,
1652 ..
1653 } => match extractor_kind {
1654 None => {
1655 if flags.multi {
1656 tyenv.report_error(
1657 ext.pos,
1658 "A term declared with `multi` cannot have an internal extractor.".to_string());
1659 continue;
1660 }
1661 *extractor_kind = Some(ExtractorKind::InternalExtractor { template });
1662 }
1663 Some(ext_kind) => {
1664 tyenv.report_error(
1665 ext.pos,
1666 "Duplicate extractor definition".to_string(),
1667 );
1668 let pos = match ext_kind {
1669 ExtractorKind::InternalExtractor { template } => template.pos(),
1670 ExtractorKind::ExternalExtractor { pos, .. } => *pos,
1671 };
1672 tyenv.report_error(
1673 pos,
1674 "Extractor was already defined here".to_string(),
1675 );
1676 continue;
1677 }
1678 },
1679 }
1680 }
1681 }
1682
1683 let mut stack = vec![];
1685 'outer: for root in extractor_call_graph.keys().copied() {
1686 stack.clear();
1687 stack.push((root, vec![root], StableSet::new()));
1688
1689 while let Some((caller, path, mut seen)) = stack.pop() {
1690 let is_new = seen.insert(caller);
1691 if is_new {
1692 if let Some(callees) = extractor_call_graph.get(&caller) {
1693 stack.extend(callees.iter().map(|callee| {
1694 let mut path = path.clone();
1695 path.push(*callee);
1696 (*callee, path, seen.clone())
1697 }));
1698 }
1699 } else {
1700 let pos = match &self.terms[caller.index()].kind {
1701 TermKind::Decl {
1702 extractor_kind: Some(ExtractorKind::InternalExtractor { template }),
1703 ..
1704 } => template.pos(),
1705 _ => {
1706 assert!(!tyenv.errors.is_empty());
1708 continue 'outer;
1709 }
1710 };
1711
1712 let path: Vec<_> = path
1713 .iter()
1714 .map(|sym| tyenv.syms[sym.index()].as_str())
1715 .collect();
1716 let msg = format!(
1717 "`{}` extractor definition is recursive: {}",
1718 tyenv.syms[root.index()],
1719 path.join(" -> ")
1720 );
1721 tyenv.report_error(pos, msg);
1722 continue 'outer;
1723 }
1724 }
1725 }
1726 }
1727
1728 fn collect_converters(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1729 for def in defs {
1730 match def {
1731 &ast::Def::Converter(ast::Converter {
1732 ref term,
1733 ref inner_ty,
1734 ref outer_ty,
1735 pos,
1736 }) => {
1737 let inner_ty_id = match tyenv.get_type_by_name(inner_ty) {
1738 Some(ty) => ty,
1739 None => {
1740 tyenv.report_error(
1741 inner_ty.1,
1742 format!("Unknown inner type for converter: '{}'", inner_ty.0),
1743 );
1744 continue;
1745 }
1746 };
1747
1748 let outer_ty_id = match tyenv.get_type_by_name(outer_ty) {
1749 Some(ty) => ty,
1750 None => {
1751 tyenv.report_error(
1752 outer_ty.1,
1753 format!("Unknown outer type for converter: '{}'", outer_ty.0),
1754 );
1755 continue;
1756 }
1757 };
1758
1759 let term_id = match self.get_term_by_name(tyenv, term) {
1760 Some(term_id) => term_id,
1761 None => {
1762 tyenv.report_error(
1763 term.1,
1764 format!("Unknown term for converter: '{}'", term.0),
1765 );
1766 continue;
1767 }
1768 };
1769
1770 match self.converters.entry((inner_ty_id, outer_ty_id)) {
1771 Entry::Vacant(v) => {
1772 v.insert(term_id);
1773 }
1774 Entry::Occupied(_) => {
1775 tyenv.report_error(
1776 pos,
1777 format!(
1778 "Converter already exists for this type pair: '{}', '{}'",
1779 inner_ty.0, outer_ty.0
1780 ),
1781 );
1782 continue;
1783 }
1784 }
1785 }
1786 _ => {}
1787 }
1788 }
1789 }
1790
1791 fn collect_externs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1792 for def in defs {
1793 match def {
1794 &ast::Def::Extern(ast::Extern::Constructor {
1795 ref term,
1796 ref func,
1797 pos,
1798 }) => {
1799 let func_sym = tyenv.intern_mut(func);
1800 let term_id = match self.get_term_by_name(tyenv, term) {
1801 Some(term) => term,
1802 None => {
1803 tyenv.report_error(
1804 pos,
1805 format!("Constructor declared on undefined term '{}'", term.0),
1806 );
1807 continue;
1808 }
1809 };
1810 let termdata = &mut self.terms[term_id.index()];
1811 match &mut termdata.kind {
1812 TermKind::Decl {
1813 constructor_kind, ..
1814 } => match constructor_kind {
1815 None => {
1816 *constructor_kind =
1817 Some(ConstructorKind::ExternalConstructor { name: func_sym });
1818 }
1819 Some(ConstructorKind::InternalConstructor) => {
1820 tyenv.report_error(
1821 pos,
1822 format!(
1823 "External constructor declared on term that already has rules: {}",
1824 term.0,
1825 ),
1826 );
1827 }
1828 Some(ConstructorKind::ExternalConstructor { .. }) => {
1829 tyenv.report_error(
1830 pos,
1831 "Duplicate external constructor definition".to_string(),
1832 );
1833 }
1834 },
1835 TermKind::EnumVariant { .. } => {
1836 tyenv.report_error(
1837 pos,
1838 format!(
1839 "External constructor cannot be defined on enum variant: {}",
1840 term.0,
1841 ),
1842 );
1843 }
1844 }
1845 }
1846 &ast::Def::Extern(ast::Extern::Extractor {
1847 ref term,
1848 ref func,
1849 pos,
1850 infallible,
1851 }) => {
1852 let func_sym = tyenv.intern_mut(func);
1853 let term_id = match self.get_term_by_name(tyenv, term) {
1854 Some(term) => term,
1855 None => {
1856 tyenv.report_error(
1857 pos,
1858 format!("Extractor declared on undefined term '{}'", term.0),
1859 );
1860 continue;
1861 }
1862 };
1863
1864 let termdata = &mut self.terms[term_id.index()];
1865
1866 match &mut termdata.kind {
1867 TermKind::Decl { extractor_kind, .. } => match extractor_kind {
1868 None => {
1869 *extractor_kind = Some(ExtractorKind::ExternalExtractor {
1870 name: func_sym,
1871 infallible,
1872 pos,
1873 });
1874 }
1875 Some(ExtractorKind::ExternalExtractor { pos: pos2, .. }) => {
1876 tyenv.report_error(
1877 pos,
1878 "Duplicate external extractor definition".to_string(),
1879 );
1880 tyenv.report_error(
1881 *pos2,
1882 "External extractor already defined".to_string(),
1883 );
1884 continue;
1885 }
1886 Some(ExtractorKind::InternalExtractor { template }) => {
1887 tyenv.report_error(
1888 pos,
1889 "Cannot define external extractor for term that already has an \
1890 internal extractor macro body defined"
1891 .to_string(),
1892 );
1893 tyenv.report_error(
1894 template.pos(),
1895 "Internal extractor macro body already defined".to_string(),
1896 );
1897 continue;
1898 }
1899 },
1900 TermKind::EnumVariant { .. } => {
1901 tyenv.report_error(
1902 pos,
1903 format!("Cannot define extractor for enum variant '{}'", term.0),
1904 );
1905 continue;
1906 }
1907 }
1908 }
1909 _ => {}
1910 }
1911 }
1912 }
1913
1914 fn collect_rules(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1915 for def in defs {
1916 match def {
1917 &ast::Def::Rule(ref rule) => {
1918 let pos = rule.pos;
1919 let mut bindings = Bindings::default();
1920 bindings.enter_scope();
1921
1922 let (sym, args) = if let ast::Pattern::Term { sym, args, .. } = &rule.pattern {
1923 (sym, args)
1924 } else {
1925 tyenv.report_error(
1926 pos,
1927 "Rule does not have a term at the root of its left-hand side"
1928 .to_string(),
1929 );
1930 continue;
1931 };
1932
1933 let root_term = if let Some(term) = self.get_term_by_name(tyenv, sym) {
1934 term
1935 } else {
1936 tyenv.report_error(
1937 pos,
1938 "Cannot define a rule for an unknown term".to_string(),
1939 );
1940 continue;
1941 };
1942
1943 let termdata = &self.terms[root_term.index()];
1944
1945 let flags = match &termdata.kind {
1946 TermKind::Decl { flags, .. } => *flags,
1947 _ => {
1948 tyenv.report_error(
1949 pos,
1950 "Cannot define a rule on a left-hand-side that is an enum variant"
1951 .to_string(),
1952 );
1953 continue;
1954 }
1955 };
1956
1957 termdata.check_args_count(args, tyenv, pos, sym);
1958 let args = self.translate_args(args, termdata, tyenv, &mut bindings);
1959
1960 let iflets = rule
1961 .iflets
1962 .iter()
1963 .filter_map(|iflet| {
1964 self.translate_iflet(tyenv, iflet, &mut bindings, flags)
1965 })
1966 .collect();
1967 let rhs = unwrap_or_continue!(self.translate_expr(
1968 tyenv,
1969 &rule.expr,
1970 Some(termdata.ret_ty),
1971 &mut bindings,
1972 flags,
1973 ));
1974
1975 bindings.exit_scope();
1976
1977 let prio = if let Some(prio) = rule.prio {
1978 if flags.multi {
1979 tyenv.report_error(
1980 pos,
1981 "Cannot set rule priorities in multi-terms".to_string(),
1982 );
1983 }
1984 prio
1985 } else {
1986 0
1987 };
1988
1989 let rid = RuleId(self.rules.len());
1990 self.rules.push(Rule {
1991 id: rid,
1992 root_term,
1993 args,
1994 iflets,
1995 rhs,
1996 vars: bindings.seen,
1997 prio,
1998 pos,
1999 name: rule.name.as_ref().map(|i| tyenv.intern_mut(i)),
2000 });
2001 }
2002 _ => {}
2003 }
2004 }
2005 }
2006
2007 fn check_for_undefined_decls(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
2008 for def in defs {
2009 if let ast::Def::Decl(decl) = def {
2010 let term = self.get_term_by_name(tyenv, &decl.term).unwrap();
2011 let term = &self.terms[term.index()];
2012 if !term.has_constructor() && !term.has_extractor() {
2013 tyenv.report_error(
2014 decl.pos,
2015 format!(
2016 "no rules, extractor, or external definition for declaration '{}'",
2017 decl.term.0
2018 ),
2019 );
2020 }
2021 }
2022 }
2023 }
2024
2025 fn check_for_expr_terms_without_constructors(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
2026 for def in defs {
2027 if let ast::Def::Rule(rule) = def {
2028 rule.expr.terms(&mut |pos, ident| {
2029 let term = match self.get_term_by_name(tyenv, ident) {
2030 None => {
2031 debug_assert!(!tyenv.errors.is_empty());
2032 return;
2033 }
2034 Some(t) => t,
2035 };
2036 let term = &self.terms[term.index()];
2037 if !term.has_constructor() {
2038 tyenv.report_error(
2039 pos,
2040 format!(
2041 "term `{}` cannot be used in an expression because \
2042 it does not have a constructor",
2043 ident.0
2044 ),
2045 )
2046 }
2047 });
2048 }
2049 }
2050 }
2051
2052 fn maybe_implicit_convert_pattern(
2053 &self,
2054 tyenv: &mut TypeEnv,
2055 pattern: &ast::Pattern,
2056 inner_ty: TypeId,
2057 outer_ty: TypeId,
2058 ) -> Option<ast::Pattern> {
2059 if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) {
2060 if self.terms[converter_term.index()].has_extractor() {
2061 let converter_term_ident = ast::Ident(
2067 tyenv.syms[self.terms[converter_term.index()].name.index()].clone(),
2068 pattern.pos(),
2069 );
2070 let expanded_pattern = ast::Pattern::Term {
2071 sym: converter_term_ident,
2072 pos: pattern.pos(),
2073 args: vec![pattern.clone()],
2074 };
2075
2076 return Some(expanded_pattern);
2077 }
2078 }
2079 None
2080 }
2081
2082 fn translate_pattern(
2083 &self,
2084 tyenv: &mut TypeEnv,
2085 pat: &ast::Pattern,
2086 expected_ty: TypeId,
2087 bindings: &mut Bindings,
2088 ) -> Option<Pattern> {
2089 log!("translate_pattern: {:?}", pat);
2090 log!("translate_pattern: bindings = {:?}", bindings);
2091 match pat {
2092 &ast::Pattern::ConstInt { val, pos } => {
2094 let ty = &tyenv.types[expected_ty.index()];
2095 if !ty.is_int() && !ty.is_prim() {
2096 tyenv.report_error(
2097 pos,
2098 format!(
2099 "expected non-integer type {}, but found integer literal '{}'",
2100 ty.name(tyenv),
2101 val,
2102 ),
2103 );
2104 }
2105 Some(Pattern::ConstInt(expected_ty, val))
2106 }
2107 &ast::Pattern::ConstBool { val, pos } => {
2108 if expected_ty != TypeId::BOOL {
2109 tyenv.report_error(
2110 pos,
2111 format!(
2112 "Boolean literal '{val}' has type {} but we need {} in context",
2113 BuiltinType::Bool.name(),
2114 tyenv.types[expected_ty.index()].name(tyenv)
2115 ),
2116 )
2117 }
2118 Some(Pattern::ConstBool(TypeId::BOOL, val))
2119 }
2120 &ast::Pattern::ConstPrim { ref val, pos } => {
2121 let val = tyenv.intern_mut(val);
2122 let const_ty = match tyenv.const_types.get(&val) {
2123 Some(ty) => *ty,
2124 None => {
2125 tyenv.report_error(pos, "Unknown constant");
2126 return None;
2127 }
2128 };
2129 if expected_ty != const_ty {
2130 tyenv.report_error(pos, "Type mismatch for constant");
2131 }
2132 Some(Pattern::ConstPrim(const_ty, val))
2133 }
2134 &ast::Pattern::Wildcard { .. } => Some(Pattern::Wildcard(expected_ty)),
2135 &ast::Pattern::And { ref subpats, .. } => {
2136 let children = subpats
2140 .iter()
2141 .filter_map(|subpat| {
2142 self.translate_pattern(tyenv, subpat, expected_ty, bindings)
2143 })
2144 .collect();
2145 Some(Pattern::And(expected_ty, children))
2146 }
2147 &ast::Pattern::BindPattern {
2148 ref var,
2149 ref subpat,
2150 pos,
2151 } => {
2152 let subpat = self.translate_pattern(tyenv, subpat, expected_ty, bindings)?;
2153
2154 let ty = subpat.ty();
2159
2160 let name = tyenv.intern_mut(var);
2161 if bindings.lookup(name).is_some() {
2162 tyenv.report_error(
2163 pos,
2164 format!("Re-bound variable name in LHS pattern: '{}'", var.0),
2165 );
2166 }
2168 let id = bindings.add_var(name, ty);
2169 Some(Pattern::BindPattern(ty, id, Box::new(subpat)))
2170 }
2171 &ast::Pattern::Var { ref var, pos } => {
2172 let name = tyenv.intern_mut(var);
2178 match bindings.lookup(name) {
2179 None => {
2180 let id = bindings.add_var(name, expected_ty);
2181 Some(Pattern::BindPattern(
2182 expected_ty,
2183 id,
2184 Box::new(Pattern::Wildcard(expected_ty)),
2185 ))
2186 }
2187 Some(bv) => {
2188 if expected_ty != bv.ty {
2189 tyenv.report_error(
2190 pos,
2191 format!(
2192 "Mismatched types: pattern expects type '{}' but already-bound var '{}' has type '{}'",
2193 tyenv.types[expected_ty.index()].name(tyenv),
2194 var.0,
2195 tyenv.types[bv.ty.index()].name(tyenv),
2196 ),
2197 );
2198 }
2200 Some(Pattern::Var(bv.ty, bv.id))
2201 }
2202 }
2203 }
2204 &ast::Pattern::Term {
2205 ref sym,
2206 ref args,
2207 pos,
2208 } => {
2209 let tid = match self.get_term_by_name(tyenv, sym) {
2211 Some(t) => t,
2212 None => {
2213 tyenv.report_error(pos, format!("Unknown term in pattern: '{}'", sym.0));
2214 return None;
2215 }
2216 };
2217
2218 let termdata = &self.terms[tid.index()];
2219
2220 let ret_ty = termdata.ret_ty;
2225 if expected_ty != ret_ty {
2226 if let Some(expanded_pattern) =
2232 self.maybe_implicit_convert_pattern(tyenv, pat, ret_ty, expected_ty)
2233 {
2234 return self.translate_pattern(
2235 tyenv,
2236 &expanded_pattern,
2237 expected_ty,
2238 bindings,
2239 );
2240 }
2241
2242 tyenv.report_error(
2243 pos,
2244 format!(
2245 "Mismatched types: pattern expects type '{}' but term has return type '{}'",
2246 tyenv.types[expected_ty.index()].name(tyenv),
2247 tyenv.types[ret_ty.index()].name(tyenv),
2248 ),
2249 );
2250 }
2252
2253 termdata.check_args_count(args, tyenv, pos, sym);
2254
2255 match &termdata.kind {
2258 TermKind::EnumVariant { .. } => {}
2259 TermKind::Decl {
2260 extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
2261 ..
2262 } => {}
2263 TermKind::Decl {
2264 extractor_kind: Some(ExtractorKind::InternalExtractor { template }),
2265 ..
2266 } => {
2267 if self.expand_internal_extractors {
2268 log!("internal extractor macro args = {:?}", args);
2273 let pat = template.subst_macro_args(&args)?;
2274 return self.translate_pattern(tyenv, &pat, expected_ty, bindings);
2275 }
2276 }
2277 TermKind::Decl {
2278 extractor_kind: None,
2279 ..
2280 } => {
2281 tyenv.report_error(
2282 pos,
2283 format!(
2284 "Cannot use term '{}' that does not have a defined extractor in a \
2285 left-hand side pattern",
2286 sym.0
2287 ),
2288 );
2289 }
2290 }
2291
2292 let subpats = self.translate_args(args, termdata, tyenv, bindings);
2293 Some(Pattern::Term(ret_ty, tid, subpats))
2294 }
2295 &ast::Pattern::MacroArg { .. } => unreachable!(),
2296 }
2297 }
2298
2299 fn translate_args(
2300 &self,
2301 args: &Vec<ast::Pattern>,
2302 termdata: &Term,
2303 tyenv: &mut TypeEnv,
2304 bindings: &mut Bindings,
2305 ) -> Vec<Pattern> {
2306 args.iter()
2307 .zip(termdata.arg_tys.iter())
2308 .filter_map(|(arg, &arg_ty)| self.translate_pattern(tyenv, arg, arg_ty, bindings))
2309 .collect()
2310 }
2311
2312 fn maybe_implicit_convert_expr(
2313 &self,
2314 tyenv: &mut TypeEnv,
2315 expr: &ast::Expr,
2316 inner_ty: TypeId,
2317 outer_ty: TypeId,
2318 ) -> Option<ast::Expr> {
2319 if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) {
2321 if self.terms[converter_term.index()].has_constructor() {
2322 let converter_ident = ast::Ident(
2323 tyenv.syms[self.terms[converter_term.index()].name.index()].clone(),
2324 expr.pos(),
2325 );
2326 return Some(ast::Expr::Term {
2327 sym: converter_ident,
2328 pos: expr.pos(),
2329 args: vec![expr.clone()],
2330 });
2331 }
2332 }
2333 None
2334 }
2335
2336 fn translate_expr(
2337 &self,
2338 tyenv: &mut TypeEnv,
2339 expr: &ast::Expr,
2340 ty: Option<TypeId>,
2341 bindings: &mut Bindings,
2342 root_flags: TermFlags,
2343 ) -> Option<Expr> {
2344 log!("translate_expr: {:?}", expr);
2345 match expr {
2346 &ast::Expr::Term {
2347 ref sym,
2348 ref args,
2349 pos,
2350 } => {
2351 let name = tyenv.intern_mut(&sym);
2353 let tid = match self.term_map.get(&name) {
2354 Some(&t) => t,
2355 None => {
2356 if bindings.lookup(name).is_some() {
2359 tyenv.report_error(
2360 pos,
2361 format!(
2362 "Unknown term in expression: '{}'. Variable binding under this name exists; try removing the parens?", sym.0));
2363 } else {
2364 tyenv.report_error(
2365 pos,
2366 format!("Unknown term in expression: '{}'", sym.0),
2367 );
2368 }
2369 return None;
2370 }
2371 };
2372 let termdata = &self.terms[tid.index()];
2373
2374 let ret_ty = termdata.ret_ty;
2380 let ty = if ty.is_some() && ret_ty != ty.unwrap() {
2381 if let Some(expanded_expr) =
2383 self.maybe_implicit_convert_expr(tyenv, expr, ret_ty, ty.unwrap())
2384 {
2385 return self.translate_expr(
2386 tyenv,
2387 &expanded_expr,
2388 ty,
2389 bindings,
2390 root_flags,
2391 );
2392 }
2393
2394 tyenv.report_error(
2395 pos,
2396 format!("Mismatched types: expression expects type '{}' but term has return type '{}'",
2397 tyenv.types[ty.unwrap().index()].name(tyenv),
2398 tyenv.types[ret_ty.index()].name(tyenv)));
2399
2400 ret_ty
2402 } else {
2403 ret_ty
2404 };
2405
2406 if let TermKind::Decl { flags, .. } = &termdata.kind {
2407 let pure_required = root_flags.pure;
2410 if pure_required && !flags.pure {
2411 tyenv.report_error(
2412 pos,
2413 format!(
2414 "Used non-pure constructor '{}' in pure expression context",
2415 sym.0
2416 ),
2417 );
2418 }
2419
2420 if !root_flags.multi && flags.multi {
2422 tyenv.report_error(
2423 pos,
2424 format!(
2425 "Used multi-constructor '{}' but this rule is not in a multi-term",
2426 sym.0
2427 ),
2428 );
2429 }
2430
2431 let partial_allowed = root_flags.partial;
2434 if !partial_allowed && flags.partial {
2435 tyenv.report_error(
2436 pos,
2437 format!(
2438 "Rule can't use partial constructor '{}' on RHS; \
2439 try moving it to if-let{}",
2440 sym.0,
2441 if root_flags.multi {
2442 ""
2443 } else {
2444 " or make this rule's term partial too"
2445 }
2446 ),
2447 );
2448 }
2449 }
2450
2451 termdata.check_args_count(args, tyenv, pos, sym);
2452
2453 let subexprs = args
2455 .iter()
2456 .zip(termdata.arg_tys.iter())
2457 .filter_map(|(arg, &arg_ty)| {
2458 self.translate_expr(tyenv, arg, Some(arg_ty), bindings, root_flags)
2459 })
2460 .collect();
2461
2462 Some(Expr::Term(ty, tid, subexprs))
2463 }
2464 &ast::Expr::Var { ref name, pos } => {
2465 let sym = tyenv.intern_mut(name);
2466 let bv = match bindings.lookup(sym) {
2468 None => {
2469 tyenv.report_error(pos, format!("Unknown variable '{}'", name.0));
2470 return None;
2471 }
2472 Some(bv) => bv,
2473 };
2474
2475 if ty.is_some() && bv.ty != ty.unwrap() {
2477 if let Some(expanded_expr) =
2479 self.maybe_implicit_convert_expr(tyenv, expr, bv.ty, ty.unwrap())
2480 {
2481 return self.translate_expr(
2482 tyenv,
2483 &expanded_expr,
2484 ty,
2485 bindings,
2486 root_flags,
2487 );
2488 }
2489
2490 tyenv.report_error(
2491 pos,
2492 format!(
2493 "Variable '{}' has type {} but we need {} in context",
2494 name.0,
2495 tyenv.types[bv.ty.index()].name(tyenv),
2496 tyenv.types[ty.unwrap().index()].name(tyenv)
2497 ),
2498 );
2499 }
2500
2501 Some(Expr::Var(bv.ty, bv.id))
2502 }
2503 &ast::Expr::ConstBool { val, pos } => {
2504 match ty {
2505 Some(ty) if ty != TypeId::BOOL => tyenv.report_error(
2506 pos,
2507 format!(
2508 "Boolean literal '{val}' has type {} but we need {} in context",
2509 BuiltinType::Bool.name(),
2510 tyenv.types[ty.index()].name(tyenv)
2511 ),
2512 ),
2513 Some(..) | None => {}
2514 };
2515 Some(Expr::ConstBool(TypeId::BOOL, val))
2516 }
2517 &ast::Expr::ConstInt { val, pos } => {
2518 let Some(ty) = ty else {
2519 tyenv.report_error(
2520 pos,
2521 "integer literal in a context that needs an explicit type".to_string(),
2522 );
2523 return None;
2524 };
2525
2526 let typ = &tyenv.types[ty.index()];
2527
2528 if !typ.is_int() && !typ.is_prim() {
2529 tyenv.report_error(
2530 pos,
2531 format!(
2532 "expected non-integer type {}, but found integer literal '{}'",
2533 tyenv.types[ty.index()].name(tyenv),
2534 val,
2535 ),
2536 );
2537 }
2538 Some(Expr::ConstInt(ty, val))
2539 }
2540 &ast::Expr::ConstPrim { ref val, pos } => {
2541 let val = tyenv.intern_mut(val);
2542 let const_ty = match tyenv.const_types.get(&val) {
2543 Some(ty) => *ty,
2544 None => {
2545 tyenv.report_error(pos, "Unknown constant");
2546 return None;
2547 }
2548 };
2549 if ty.is_some() && const_ty != ty.unwrap() {
2550 tyenv.report_error(
2551 pos,
2552 format!(
2553 "Constant '{}' has wrong type: expected {}, but is actually {}",
2554 tyenv.syms[val.index()],
2555 tyenv.types[ty.unwrap().index()].name(tyenv),
2556 tyenv.types[const_ty.index()].name(tyenv)
2557 ),
2558 );
2559 return None;
2560 }
2561 Some(Expr::ConstPrim(const_ty, val))
2562 }
2563 &ast::Expr::Let {
2564 ref defs,
2565 ref body,
2566 pos,
2567 } => {
2568 bindings.enter_scope();
2569
2570 let mut let_defs = vec![];
2572 for def in defs {
2573 let name = tyenv.intern_mut(&def.var);
2575
2576 let tid = match tyenv.get_type_by_name(&def.ty) {
2578 Some(tid) => tid,
2579 None => {
2580 tyenv.report_error(
2581 pos,
2582 format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0),
2583 );
2584 continue;
2585 }
2586 };
2587
2588 let val = Box::new(unwrap_or_continue!(self.translate_expr(
2590 tyenv,
2591 &def.val,
2592 Some(tid),
2593 bindings,
2594 root_flags,
2595 )));
2596
2597 let id = bindings.add_var(name, tid);
2599 let_defs.push((id, tid, val));
2600 }
2601
2602 let body = Box::new(self.translate_expr(tyenv, body, ty, bindings, root_flags)?);
2604 let body_ty = body.ty();
2605
2606 bindings.exit_scope();
2608
2609 Some(Expr::Let {
2610 ty: body_ty,
2611 bindings: let_defs,
2612 body,
2613 })
2614 }
2615 }
2616 }
2617
2618 fn translate_iflet(
2619 &self,
2620 tyenv: &mut TypeEnv,
2621 iflet: &ast::IfLet,
2622 bindings: &mut Bindings,
2623 root_flags: TermFlags,
2624 ) -> Option<IfLet> {
2625 let rhs = self.translate_expr(tyenv, &iflet.expr, None, bindings, root_flags.on_lhs())?;
2628 let lhs = self.translate_pattern(tyenv, &iflet.pattern, rhs.ty(), bindings)?;
2629
2630 Some(IfLet { lhs, rhs })
2631 }
2632
2633 pub fn get_term_by_name(&self, tyenv: &TypeEnv, sym: &ast::Ident) -> Option<TermId> {
2635 tyenv
2636 .intern(sym)
2637 .and_then(|sym| self.term_map.get(&sym))
2638 .copied()
2639 }
2640}
2641
2642#[cfg(test)]
2643mod test {
2644 use super::*;
2645 use crate::ast::Ident;
2646 use crate::lexer::Lexer;
2647 use crate::parser::parse;
2648
2649 #[test]
2650 fn build_type_env() {
2651 let text = r"
2652 (type UImm8 (primitive UImm8))
2653 (type A extern (enum (B (f1 u32) (f2 u32)) (C (f1 u32))))
2654 ";
2655 let ast = parse(Lexer::new(0, text).unwrap()).expect("should parse");
2656 let tyenv = TypeEnv::from_ast(&ast).expect("should not have type-definition errors");
2657
2658 let sym_a = tyenv
2659 .intern(&Ident("A".to_string(), Default::default()))
2660 .unwrap();
2661 let sym_b = tyenv
2662 .intern(&Ident("B".to_string(), Default::default()))
2663 .unwrap();
2664 let sym_c = tyenv
2665 .intern(&Ident("C".to_string(), Default::default()))
2666 .unwrap();
2667 let sym_a_b = tyenv
2668 .intern(&Ident("A.B".to_string(), Default::default()))
2669 .unwrap();
2670 let sym_a_c = tyenv
2671 .intern(&Ident("A.C".to_string(), Default::default()))
2672 .unwrap();
2673 let sym_uimm8 = tyenv
2674 .intern(&Ident("UImm8".to_string(), Default::default()))
2675 .unwrap();
2676 let sym_f1 = tyenv
2677 .intern(&Ident("f1".to_string(), Default::default()))
2678 .unwrap();
2679 let sym_f2 = tyenv
2680 .intern(&Ident("f2".to_string(), Default::default()))
2681 .unwrap();
2682
2683 assert_eq!(tyenv.type_map.get(&sym_uimm8).unwrap(), &TypeId(13));
2684 assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(14));
2685
2686 let expected_types = vec![
2687 Type::Primitive(
2688 TypeId(13),
2689 sym_uimm8,
2690 Pos {
2691 file: 0,
2692 offset: 19,
2693 },
2694 ),
2695 Type::Enum {
2696 name: sym_a,
2697 id: TypeId(14),
2698 is_extern: true,
2699 is_nodebug: false,
2700 variants: vec![
2701 Variant {
2702 name: sym_b,
2703 fullname: sym_a_b,
2704 id: VariantId(0),
2705 fields: vec![
2706 Field {
2707 name: sym_f1,
2708 id: FieldId(0),
2709 ty: TypeId::U32,
2710 },
2711 Field {
2712 name: sym_f2,
2713 id: FieldId(1),
2714 ty: TypeId::U32,
2715 },
2716 ],
2717 },
2718 Variant {
2719 name: sym_c,
2720 fullname: sym_a_c,
2721 id: VariantId(1),
2722 fields: vec![Field {
2723 name: sym_f1,
2724 id: FieldId(0),
2725 ty: TypeId::U32,
2726 }],
2727 },
2728 ],
2729 pos: Pos {
2730 file: 0,
2731 offset: 62,
2732 },
2733 },
2734 ];
2735
2736 assert_eq!(
2737 tyenv.types.len(),
2738 expected_types.len() + BuiltinType::ALL.len()
2739 );
2740 for (i, (actual, expected)) in tyenv
2741 .types
2742 .iter()
2743 .skip(BuiltinType::ALL.len())
2744 .zip(&expected_types)
2745 .enumerate()
2746 {
2747 assert_eq!(expected, actual, "`{i}`th type is not equal!");
2748 }
2749 }
2750}