1use crate::ast;
17use crate::error::*;
18use crate::lexer::Pos;
19use crate::log;
20use crate::stablemapset::{StableMap, StableSet};
21use std::collections::hash_map::Entry;
22use std::collections::BTreeMap;
23use std::collections::BTreeSet;
24use std::collections::HashMap;
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}
393
394impl TermFlags {
395 pub fn on_lhs(mut self) -> Self {
397 self.pure = true;
398 self.partial = true;
399 self
400 }
401}
402
403#[derive(Clone, Debug, PartialEq, Eq)]
405pub enum TermKind {
406 EnumVariant {
408 variant: VariantId,
411 },
412 Decl {
414 flags: TermFlags,
416 constructor_kind: Option<ConstructorKind>,
418 extractor_kind: Option<ExtractorKind>,
420 },
421}
422
423#[derive(Clone, Debug, PartialEq, Eq)]
425pub enum ConstructorKind {
426 InternalConstructor,
429 ExternalConstructor {
431 name: Sym,
433 },
434}
435
436#[derive(Clone, Debug, PartialEq, Eq)]
438pub enum ExtractorKind {
439 InternalExtractor {
443 template: ast::Pattern,
445 },
446 ExternalExtractor {
448 name: Sym,
450 infallible: bool,
452 pos: Pos,
454 },
455}
456
457#[derive(Clone, Copy, Debug, Eq, PartialEq)]
459pub enum ReturnKind {
460 Plain,
462 Option,
464 Iterator,
466}
467
468#[derive(Clone, Debug)]
470pub struct ExternalSig {
471 pub func_name: String,
473 pub full_name: String,
475 pub param_tys: Vec<TypeId>,
477 pub ret_tys: Vec<TypeId>,
479 pub ret_kind: ReturnKind,
481}
482
483impl Term {
484 pub fn ty(&self) -> TypeId {
486 self.ret_ty
487 }
488
489 fn check_args_count<T>(&self, args: &[T], tyenv: &mut TypeEnv, pos: Pos, sym: &ast::Ident) {
490 if self.arg_tys.len() != args.len() {
491 tyenv.report_error(
492 pos,
493 format!(
494 "Incorrect argument count for term '{}': got {}, expect {}",
495 sym.0,
496 args.len(),
497 self.arg_tys.len()
498 ),
499 );
500 }
501 }
502
503 pub fn is_enum_variant(&self) -> bool {
505 matches!(self.kind, TermKind::EnumVariant { .. })
506 }
507
508 pub fn is_partial(&self) -> bool {
510 matches!(
511 self.kind,
512 TermKind::Decl {
513 flags: TermFlags { partial: true, .. },
514 ..
515 }
516 )
517 }
518
519 pub fn has_constructor(&self) -> bool {
521 matches!(
522 self.kind,
523 TermKind::EnumVariant { .. }
524 | TermKind::Decl {
525 constructor_kind: Some(_),
526 ..
527 }
528 )
529 }
530
531 pub fn has_extractor(&self) -> bool {
533 matches!(
534 self.kind,
535 TermKind::EnumVariant { .. }
536 | TermKind::Decl {
537 extractor_kind: Some(_),
538 ..
539 }
540 )
541 }
542
543 pub fn has_external_extractor(&self) -> bool {
545 matches!(
546 self.kind,
547 TermKind::Decl {
548 extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
549 ..
550 }
551 )
552 }
553
554 pub fn has_external_constructor(&self) -> bool {
556 matches!(
557 self.kind,
558 TermKind::Decl {
559 constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }),
560 ..
561 }
562 )
563 }
564
565 pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
567 match &self.kind {
568 TermKind::Decl {
569 flags,
570 extractor_kind:
571 Some(ExtractorKind::ExternalExtractor {
572 name, infallible, ..
573 }),
574 ..
575 } => {
576 let ret_kind = if flags.multi {
577 ReturnKind::Iterator
578 } else if *infallible {
579 ReturnKind::Plain
580 } else {
581 ReturnKind::Option
582 };
583 Some(ExternalSig {
584 func_name: tyenv.syms[name.index()].clone(),
585 full_name: format!("C::{}", tyenv.syms[name.index()]),
586 param_tys: vec![self.ret_ty],
587 ret_tys: self.arg_tys.clone(),
588 ret_kind,
589 })
590 }
591 _ => None,
592 }
593 }
594
595 pub fn constructor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
597 match &self.kind {
598 TermKind::Decl {
599 constructor_kind: Some(kind),
600 flags,
601 ..
602 } => {
603 let (func_name, full_name) = match kind {
604 ConstructorKind::InternalConstructor => {
605 let name = format!("constructor_{}", tyenv.syms[self.name.index()]);
606 (name.clone(), name)
607 }
608 ConstructorKind::ExternalConstructor { name } => (
609 tyenv.syms[name.index()].clone(),
610 format!("C::{}", tyenv.syms[name.index()]),
611 ),
612 };
613 let ret_kind = if flags.multi {
614 ReturnKind::Iterator
615 } else if flags.partial {
616 ReturnKind::Option
617 } else {
618 ReturnKind::Plain
619 };
620 Some(ExternalSig {
621 func_name,
622 full_name,
623 param_tys: self.arg_tys.clone(),
624 ret_tys: vec![self.ret_ty],
625 ret_kind,
626 })
627 }
628 _ => None,
629 }
630 }
631}
632
633#[derive(Clone, Debug)]
635pub struct Rule {
636 pub id: RuleId,
638 pub root_term: TermId,
640 pub args: Vec<Pattern>,
642 pub iflets: Vec<IfLet>,
644 pub rhs: Expr,
647 pub vars: Vec<BoundVar>,
649 pub prio: i64,
651 pub pos: Pos,
653 pub name: Option<Sym>,
655}
656
657#[derive(Clone, Debug)]
659pub struct BoundVar {
660 pub id: VarId,
662 pub name: Sym,
664 pub ty: TypeId,
666 scope: usize,
669}
670
671#[derive(Clone, Debug)]
674pub struct IfLet {
675 pub lhs: Pattern,
678 pub rhs: Expr,
681}
682
683#[derive(Clone, Debug, PartialEq, Eq)]
685pub enum Pattern {
686 BindPattern(TypeId, VarId, Box<Pattern>),
690
691 Var(TypeId, VarId),
694
695 ConstBool(TypeId, bool),
697
698 ConstInt(TypeId, i128),
701
702 ConstPrim(TypeId, Sym),
705
706 Term(TypeId, TermId, Vec<Pattern>),
709
710 Wildcard(TypeId),
712
713 And(TypeId, Vec<Pattern>),
715}
716
717#[derive(Clone, Debug, PartialEq, Eq)]
719pub enum Expr {
720 Term(TypeId, TermId, Vec<Expr>),
722 Var(TypeId, VarId),
724 ConstBool(TypeId, bool),
726 ConstInt(TypeId, i128),
728 ConstPrim(TypeId, Sym),
730 Let {
733 ty: TypeId,
735 bindings: Vec<(VarId, TypeId, Box<Expr>)>,
737 body: Box<Expr>,
739 },
740}
741
742pub trait PatternVisitor {
745 type PatternId: Copy;
747
748 fn add_match_equal(&mut self, a: Self::PatternId, b: Self::PatternId, ty: TypeId);
750 fn add_match_bool(&mut self, input: Self::PatternId, ty: TypeId, bool_val: bool);
752 fn add_match_int(&mut self, input: Self::PatternId, ty: TypeId, int_val: i128);
754 fn add_match_prim(&mut self, input: Self::PatternId, ty: TypeId, val: Sym);
756
757 fn add_match_variant(
760 &mut self,
761 input: Self::PatternId,
762 input_ty: TypeId,
763 arg_tys: &[TypeId],
764 variant: VariantId,
765 ) -> Vec<Self::PatternId>;
766
767 fn add_extract(
771 &mut self,
772 input: Self::PatternId,
773 input_ty: TypeId,
774 output_tys: Vec<TypeId>,
775 term: TermId,
776 infallible: bool,
777 multi: bool,
778 ) -> Vec<Self::PatternId>;
779}
780
781impl Pattern {
782 pub fn ty(&self) -> TypeId {
784 match *self {
785 Self::BindPattern(t, ..) => t,
786 Self::Var(t, ..) => t,
787 Self::ConstBool(t, ..) => t,
788 Self::ConstInt(t, ..) => t,
789 Self::ConstPrim(t, ..) => t,
790 Self::Term(t, ..) => t,
791 Self::Wildcard(t, ..) => t,
792 Self::And(t, ..) => t,
793 }
794 }
795
796 pub fn visit<V: PatternVisitor>(
798 &self,
799 visitor: &mut V,
800 input: V::PatternId,
801 termenv: &TermEnv,
802 vars: &mut HashMap<VarId, V::PatternId>,
803 ) {
804 match *self {
805 Pattern::BindPattern(_ty, var, ref subpat) => {
806 assert!(!vars.contains_key(&var));
808 vars.insert(var, input);
809 subpat.visit(visitor, input, termenv, vars);
810 }
811 Pattern::Var(ty, var) => {
812 let var_val = vars
814 .get(&var)
815 .copied()
816 .expect("Variable should already be bound");
817 visitor.add_match_equal(input, var_val, ty);
818 }
819 Pattern::ConstBool(ty, value) => visitor.add_match_bool(input, ty, value),
820 Pattern::ConstInt(ty, value) => visitor.add_match_int(input, ty, value),
821 Pattern::ConstPrim(ty, value) => visitor.add_match_prim(input, ty, value),
822 Pattern::Term(ty, term, ref args) => {
823 let termdata = &termenv.terms[term.index()];
825 let arg_values = match &termdata.kind {
826 TermKind::EnumVariant { variant } => {
827 visitor.add_match_variant(input, ty, &termdata.arg_tys, *variant)
828 }
829 TermKind::Decl {
830 extractor_kind: None,
831 ..
832 } => {
833 panic!("Pattern invocation of undefined term body")
834 }
835 TermKind::Decl {
836 extractor_kind: Some(ExtractorKind::InternalExtractor { .. }),
837 ..
838 } => {
839 panic!("Should have been expanded away")
840 }
841 TermKind::Decl {
842 flags,
843 extractor_kind: Some(ExtractorKind::ExternalExtractor { infallible, .. }),
844 ..
845 } => {
846 let output_tys = args.iter().map(|arg| arg.ty()).collect();
848
849 visitor.add_extract(
851 input,
852 termdata.ret_ty,
853 output_tys,
854 term,
855 *infallible && !flags.multi,
856 flags.multi,
857 )
858 }
859 };
860 for (pat, val) in args.iter().zip(arg_values) {
861 pat.visit(visitor, val, termenv, vars);
862 }
863 }
864 Pattern::And(_ty, ref children) => {
865 for child in children {
866 child.visit(visitor, input, termenv, vars);
867 }
868 }
869 Pattern::Wildcard(_ty) => {
870 }
872 }
873 }
874}
875
876pub trait ExprVisitor {
879 type ExprId: Copy;
881
882 fn add_const_bool(&mut self, ty: TypeId, val: bool) -> Self::ExprId;
884 fn add_const_int(&mut self, ty: TypeId, val: i128) -> Self::ExprId;
886 fn add_const_prim(&mut self, ty: TypeId, val: Sym) -> Self::ExprId;
888
889 fn add_create_variant(
891 &mut self,
892 inputs: Vec<(Self::ExprId, TypeId)>,
893 ty: TypeId,
894 variant: VariantId,
895 ) -> Self::ExprId;
896
897 fn add_construct(
899 &mut self,
900 inputs: Vec<(Self::ExprId, TypeId)>,
901 ty: TypeId,
902 term: TermId,
903 pure: bool,
904 infallible: bool,
905 multi: bool,
906 ) -> Self::ExprId;
907}
908
909impl Expr {
910 pub fn ty(&self) -> TypeId {
912 match *self {
913 Self::Term(t, ..) => t,
914 Self::Var(t, ..) => t,
915 Self::ConstBool(t, ..) => t,
916 Self::ConstInt(t, ..) => t,
917 Self::ConstPrim(t, ..) => t,
918 Self::Let { ty: t, .. } => t,
919 }
920 }
921
922 pub fn visit<V: ExprVisitor>(
924 &self,
925 visitor: &mut V,
926 termenv: &TermEnv,
927 vars: &HashMap<VarId, V::ExprId>,
928 ) -> V::ExprId {
929 log!("Expr::visit: expr {:?}", self);
930 match *self {
931 Expr::ConstBool(ty, val) => visitor.add_const_bool(ty, val),
932 Expr::ConstInt(ty, val) => visitor.add_const_int(ty, val),
933 Expr::ConstPrim(ty, val) => visitor.add_const_prim(ty, val),
934 Expr::Let {
935 ty: _ty,
936 ref bindings,
937 ref body,
938 } => {
939 let mut vars = vars.clone();
940 for &(var, _var_ty, ref var_expr) in bindings {
941 let var_value = var_expr.visit(visitor, termenv, &vars);
942 vars.insert(var, var_value);
943 }
944 body.visit(visitor, termenv, &vars)
945 }
946 Expr::Var(_ty, var_id) => *vars.get(&var_id).unwrap(),
947 Expr::Term(ty, term, ref arg_exprs) => {
948 let termdata = &termenv.terms[term.index()];
949 let arg_values_tys = arg_exprs
950 .iter()
951 .map(|arg_expr| arg_expr.visit(visitor, termenv, vars))
952 .zip(termdata.arg_tys.iter().copied())
953 .collect();
954 match &termdata.kind {
955 TermKind::EnumVariant { variant } => {
956 visitor.add_create_variant(arg_values_tys, ty, *variant)
957 }
958 TermKind::Decl {
959 constructor_kind: Some(_),
960 flags,
961 ..
962 } => {
963 visitor.add_construct(
964 arg_values_tys,
965 ty,
966 term,
967 flags.pure,
968 !flags.partial,
969 flags.multi,
970 )
971 }
972 TermKind::Decl {
973 constructor_kind: None,
974 ..
975 } => panic!("Should have been caught by typechecking"),
976 }
977 }
978 }
979 }
980
981 fn visit_in_rule<V: RuleVisitor>(
982 &self,
983 visitor: &mut V,
984 termenv: &TermEnv,
985 vars: &HashMap<VarId, <V::PatternVisitor as PatternVisitor>::PatternId>,
986 ) -> V::Expr {
987 let var_exprs = vars
988 .iter()
989 .map(|(&var, &val)| (var, visitor.pattern_as_expr(val)))
990 .collect();
991 visitor.add_expr(|visitor| VisitedExpr {
992 ty: self.ty(),
993 value: self.visit(visitor, termenv, &var_exprs),
994 })
995 }
996}
997
998#[derive(Clone, Copy)]
1000pub struct VisitedExpr<V: ExprVisitor> {
1001 pub ty: TypeId,
1003 pub value: V::ExprId,
1005}
1006
1007pub trait RuleVisitor {
1010 type PatternVisitor: PatternVisitor;
1012 type ExprVisitor: ExprVisitor;
1014 type Expr;
1017
1018 fn add_arg(
1020 &mut self,
1021 index: usize,
1022 ty: TypeId,
1023 ) -> <Self::PatternVisitor as PatternVisitor>::PatternId;
1024
1025 fn add_pattern<F>(&mut self, visitor: F)
1029 where
1030 F: FnOnce(&mut Self::PatternVisitor);
1031
1032 fn add_expr<F>(&mut self, visitor: F) -> Self::Expr
1034 where
1035 F: FnOnce(&mut Self::ExprVisitor) -> VisitedExpr<Self::ExprVisitor>;
1036
1037 fn expr_as_pattern(
1040 &mut self,
1041 expr: Self::Expr,
1042 ) -> <Self::PatternVisitor as PatternVisitor>::PatternId;
1043
1044 fn pattern_as_expr(
1047 &mut self,
1048 pattern: <Self::PatternVisitor as PatternVisitor>::PatternId,
1049 ) -> <Self::ExprVisitor as ExprVisitor>::ExprId;
1050}
1051
1052impl Rule {
1053 pub fn visit<V: RuleVisitor>(&self, visitor: &mut V, termenv: &TermEnv) -> V::Expr {
1057 let mut vars = HashMap::new();
1058
1059 let termdata = &termenv.terms[self.root_term.index()];
1061 for (i, (subpat, &arg_ty)) in self.args.iter().zip(termdata.arg_tys.iter()).enumerate() {
1062 let value = visitor.add_arg(i, arg_ty);
1063 visitor.add_pattern(|visitor| subpat.visit(visitor, value, termenv, &mut vars));
1064 }
1065
1066 for iflet in self.iflets.iter() {
1068 let subexpr = iflet.rhs.visit_in_rule(visitor, termenv, &vars);
1069 let value = visitor.expr_as_pattern(subexpr);
1070 visitor.add_pattern(|visitor| iflet.lhs.visit(visitor, value, termenv, &mut vars));
1071 }
1072
1073 self.rhs.visit_in_rule(visitor, termenv, &vars)
1075 }
1076}
1077
1078macro_rules! unwrap_or_continue {
1086 ($e:expr) => {
1087 match $e {
1088 Some(x) => x,
1089 None => continue,
1090 }
1091 };
1092}
1093
1094impl Default for TypeEnv {
1095 fn default() -> Self {
1096 Self {
1097 syms: BuiltinType::ALL
1098 .iter()
1099 .map(|bt| String::from(bt.name()))
1100 .collect(),
1101 sym_map: BuiltinType::ALL
1102 .iter()
1103 .enumerate()
1104 .map(|(idx, bt)| (String::from(bt.name()), Sym(idx)))
1105 .collect(),
1106 types: BuiltinType::ALL
1107 .iter()
1108 .map(|bt| Type::Builtin(*bt))
1109 .collect(),
1110 type_map: BuiltinType::ALL
1111 .iter()
1112 .enumerate()
1113 .map(|(idx, _)| (Sym(idx), TypeId(idx)))
1114 .collect(),
1115 const_types: StableMap::new(),
1116 errors: vec![],
1117 }
1118 }
1119}
1120
1121impl TypeEnv {
1122 pub fn from_ast(defs: &[ast::Def]) -> Result<TypeEnv, Vec<Error>> {
1124 let mut tyenv = TypeEnv::default();
1125
1126 for def in defs {
1129 match def {
1130 &ast::Def::Type(ref td) => {
1131 let tid = TypeId(tyenv.type_map.len());
1132 let name = tyenv.intern_mut(&td.name);
1133
1134 if let Some(existing) = tyenv.type_map.get(&name).copied() {
1135 tyenv.report_error(
1136 td.pos,
1137 format!("Type with name '{}' defined more than once", td.name.0),
1138 );
1139 let pos = unwrap_or_continue!(tyenv.types.get(existing.index())).pos();
1140 match pos {
1141 Some(pos) => tyenv.report_error(
1142 pos,
1143 format!("Type with name '{}' already defined here", td.name.0),
1144 ),
1145 None => tyenv.report_error(
1146 td.pos,
1147 format!("Type with name '{}' is a built-in type", td.name.0),
1148 ),
1149 }
1150 continue;
1151 }
1152
1153 tyenv.type_map.insert(name, tid);
1154 }
1155 _ => {}
1156 }
1157 }
1158
1159 for def in defs {
1163 match def {
1164 &ast::Def::Type(ref td) => {
1165 let tid = tyenv.types.len();
1166 if let Some(ty) = tyenv.type_from_ast(TypeId(tid), td) {
1167 tyenv.types.push(ty);
1168 }
1169 }
1170 _ => {}
1171 }
1172 }
1173
1174 for def in defs {
1176 if let &ast::Def::Extern(ast::Extern::Const {
1177 ref name,
1178 ref ty,
1179 pos,
1180 }) = def
1181 {
1182 let ty = match tyenv.get_type_by_name(ty) {
1183 Some(ty) => ty,
1184 None => {
1185 tyenv.report_error(pos, "Unknown type for constant");
1186 continue;
1187 }
1188 };
1189 let name = tyenv.intern_mut(name);
1190 tyenv.const_types.insert(name, ty);
1191 }
1192 }
1193
1194 tyenv.return_errors()?;
1195
1196 Ok(tyenv)
1197 }
1198
1199 fn return_errors(&mut self) -> Result<(), Vec<Error>> {
1200 if self.errors.is_empty() {
1201 Ok(())
1202 } else {
1203 Err(std::mem::take(&mut self.errors))
1204 }
1205 }
1206
1207 fn type_from_ast(&mut self, tid: TypeId, ty: &ast::Type) -> Option<Type> {
1208 let name = self.intern(&ty.name).unwrap();
1209 match &ty.ty {
1210 &ast::TypeValue::Primitive(ref id, ..) => {
1211 if ty.is_nodebug {
1212 self.report_error(ty.pos, "primitive types cannot be marked `nodebug`");
1213 return None;
1214 }
1215 if ty.is_extern {
1216 self.report_error(ty.pos, "primitive types cannot be marked `extern`");
1217 return None;
1218 }
1219 Some(Type::Primitive(tid, self.intern_mut(id), ty.pos))
1220 }
1221 &ast::TypeValue::Enum(ref ty_variants, ..) => {
1222 if ty.is_extern && ty.is_nodebug {
1223 self.report_error(ty.pos, "external types cannot be marked `nodebug`");
1224 return None;
1225 }
1226
1227 let mut variants = vec![];
1228 for variant in ty_variants {
1229 let combined_ident =
1230 ast::Ident(format!("{}.{}", ty.name.0, variant.name.0), variant.name.1);
1231 let fullname = self.intern_mut(&combined_ident);
1232 let name = self.intern_mut(&variant.name);
1233 let id = VariantId(variants.len());
1234 if variants.iter().any(|v: &Variant| v.name == name) {
1235 self.report_error(
1236 variant.pos,
1237 format!("Duplicate variant name in type: '{}'", variant.name.0),
1238 );
1239 return None;
1240 }
1241 let mut fields = vec![];
1242 for field in &variant.fields {
1243 let field_name = self.intern_mut(&field.name);
1244 if fields.iter().any(|f: &Field| f.name == field_name) {
1245 self.report_error(
1246 field.pos,
1247 format!(
1248 "Duplicate field name '{}' in variant '{}' of type",
1249 field.name.0, variant.name.0
1250 ),
1251 );
1252 return None;
1253 }
1254 let field_tid = match self.get_type_by_name(&field.ty) {
1255 Some(tid) => tid,
1256 None => {
1257 self.report_error(
1258 field.ty.1,
1259 format!(
1260 "Unknown type '{}' for field '{}' in variant '{}'",
1261 field.ty.0, field.name.0, variant.name.0
1262 ),
1263 );
1264 return None;
1265 }
1266 };
1267 fields.push(Field {
1268 name: field_name,
1269 id: FieldId(fields.len()),
1270 ty: field_tid,
1271 });
1272 }
1273 variants.push(Variant {
1274 name,
1275 fullname,
1276 id,
1277 fields,
1278 });
1279 }
1280 Some(Type::Enum {
1281 name,
1282 id: tid,
1283 is_extern: ty.is_extern,
1284 is_nodebug: ty.is_nodebug,
1285 variants,
1286 pos: ty.pos,
1287 })
1288 }
1289 }
1290 }
1291
1292 fn error(&self, pos: Pos, msg: impl Into<String>) -> Error {
1293 Error::TypeError {
1294 msg: msg.into(),
1295 span: Span::new_single(pos),
1296 }
1297 }
1298
1299 fn report_error(&mut self, pos: Pos, msg: impl Into<String>) {
1300 let err = self.error(pos, msg);
1301 self.errors.push(err);
1302 }
1303
1304 fn intern_mut(&mut self, ident: &ast::Ident) -> Sym {
1305 if let Some(s) = self.sym_map.get(&ident.0).copied() {
1306 s
1307 } else {
1308 let s = Sym(self.syms.len());
1309 self.syms.push(ident.0.clone());
1310 self.sym_map.insert(ident.0.clone(), s);
1311 s
1312 }
1313 }
1314
1315 fn intern(&self, ident: &ast::Ident) -> Option<Sym> {
1316 self.sym_map.get(&ident.0).copied()
1317 }
1318
1319 pub fn get_type_by_name(&self, sym: &ast::Ident) -> Option<TypeId> {
1321 self.intern(sym)
1322 .and_then(|sym| self.type_map.get(&sym))
1323 .copied()
1324 }
1325}
1326
1327#[derive(Clone, Debug, Default)]
1328struct Bindings {
1329 seen: Vec<BoundVar>,
1332 next_scope: usize,
1334 in_scope: Vec<usize>,
1336}
1337
1338impl Bindings {
1339 fn enter_scope(&mut self) {
1340 self.in_scope.push(self.next_scope);
1341 self.next_scope += 1;
1342 }
1343
1344 fn exit_scope(&mut self) {
1345 self.in_scope.pop();
1346 }
1347
1348 fn add_var(&mut self, name: Sym, ty: TypeId) -> VarId {
1349 let id = VarId(self.seen.len());
1350 let var = BoundVar {
1351 id,
1352 name,
1353 ty,
1354 scope: *self
1355 .in_scope
1356 .last()
1357 .expect("enter_scope should be called before add_var"),
1358 };
1359 log!("binding var {:?}", var);
1360 self.seen.push(var);
1361 id
1362 }
1363
1364 fn lookup(&self, name: Sym) -> Option<&BoundVar> {
1365 self.seen
1366 .iter()
1367 .rev()
1368 .find(|binding| binding.name == name && self.in_scope.contains(&binding.scope))
1369 }
1370}
1371
1372impl TermEnv {
1373 pub fn from_ast(
1375 tyenv: &mut TypeEnv,
1376 defs: &[ast::Def],
1377 expand_internal_extractors: bool,
1378 ) -> Result<TermEnv, Vec<Error>> {
1379 let mut env = TermEnv {
1380 terms: vec![],
1381 term_map: StableMap::new(),
1382 rules: vec![],
1383 converters: StableMap::new(),
1384 expand_internal_extractors,
1385 };
1386
1387 env.collect_pragmas(defs);
1388 env.collect_term_sigs(tyenv, defs);
1389 env.collect_enum_variant_terms(tyenv);
1390 tyenv.return_errors()?;
1391 env.collect_constructors(tyenv, defs);
1392 env.collect_extractor_templates(tyenv, defs);
1393 tyenv.return_errors()?;
1394 env.collect_converters(tyenv, defs);
1395 tyenv.return_errors()?;
1396 env.collect_externs(tyenv, defs);
1397 tyenv.return_errors()?;
1398 env.collect_rules(tyenv, defs);
1399 env.check_for_undefined_decls(tyenv, defs);
1400 env.check_for_expr_terms_without_constructors(tyenv, defs);
1401 tyenv.return_errors()?;
1402
1403 Ok(env)
1404 }
1405
1406 fn collect_pragmas(&mut self, _: &[ast::Def]) {
1407 return;
1409 }
1410
1411 fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1412 for def in defs {
1413 match def {
1414 &ast::Def::Decl(ref decl) => {
1415 let name = tyenv.intern_mut(&decl.term);
1416 if let Some(tid) = self.term_map.get(&name) {
1417 tyenv.report_error(
1418 decl.pos,
1419 format!("Duplicate decl for '{}'", decl.term.0),
1420 );
1421 tyenv.report_error(
1422 self.terms[tid.index()].decl_pos,
1423 format!("Duplicate decl for '{}'", decl.term.0),
1424 );
1425 }
1426
1427 if decl.multi && decl.partial {
1428 tyenv.report_error(
1429 decl.pos,
1430 format!("Term '{}' can't be both multi and partial", decl.term.0),
1431 );
1432 }
1433
1434 let arg_tys = decl
1435 .arg_tys
1436 .iter()
1437 .map(|id| {
1438 tyenv.get_type_by_name(id).ok_or_else(|| {
1439 tyenv.report_error(id.1, format!("Unknown arg type: '{}'", id.0));
1440 })
1441 })
1442 .collect::<Result<Vec<_>, _>>();
1443 let arg_tys = match arg_tys {
1444 Ok(a) => a,
1445 Err(_) => {
1446 continue;
1447 }
1448 };
1449 let ret_ty = match tyenv.get_type_by_name(&decl.ret_ty) {
1450 Some(t) => t,
1451 None => {
1452 tyenv.report_error(
1453 decl.ret_ty.1,
1454 format!("Unknown return type: '{}'", decl.ret_ty.0),
1455 );
1456 continue;
1457 }
1458 };
1459
1460 let tid = TermId(self.terms.len());
1461 self.term_map.insert(name, tid);
1462 let flags = TermFlags {
1463 pure: decl.pure,
1464 multi: decl.multi,
1465 partial: decl.partial,
1466 };
1467 self.terms.push(Term {
1468 id: tid,
1469 decl_pos: decl.pos,
1470 name,
1471 arg_tys,
1472 ret_ty,
1473 kind: TermKind::Decl {
1474 flags,
1475 constructor_kind: None,
1476 extractor_kind: None,
1477 },
1478 });
1479 }
1480 _ => {}
1481 }
1482 }
1483 }
1484
1485 fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) {
1486 'types: for i in 0..tyenv.types.len() {
1487 let ty = &tyenv.types[i];
1488 match ty {
1489 &Type::Enum {
1490 pos,
1491 id,
1492 ref variants,
1493 ..
1494 } => {
1495 for variant in variants {
1496 if self.term_map.contains_key(&variant.fullname) {
1497 let variant_name = tyenv.syms[variant.fullname.index()].clone();
1498 tyenv.report_error(
1499 pos,
1500 format!("Duplicate enum variant constructor: '{variant_name}'",),
1501 );
1502 continue 'types;
1503 }
1504 let tid = TermId(self.terms.len());
1505 let arg_tys = variant.fields.iter().map(|fld| fld.ty).collect::<Vec<_>>();
1506 let ret_ty = id;
1507 self.terms.push(Term {
1508 id: tid,
1509 decl_pos: pos,
1510 name: variant.fullname,
1511 arg_tys,
1512 ret_ty,
1513 kind: TermKind::EnumVariant {
1514 variant: variant.id,
1515 },
1516 });
1517 self.term_map.insert(variant.fullname, tid);
1518 }
1519 }
1520 _ => {}
1521 }
1522 }
1523 }
1524
1525 fn collect_constructors(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1526 for def in defs {
1527 log!("collect_constructors from def: {:?}", def);
1528 match def {
1529 &ast::Def::Rule(ref rule) => {
1530 let pos = rule.pos;
1531 let term = match rule.pattern.root_term() {
1532 Some(t) => t,
1533 None => {
1534 tyenv.report_error(
1535 pos,
1536 "Rule does not have a term at the LHS root".to_string(),
1537 );
1538 continue;
1539 }
1540 };
1541 let term = match self.get_term_by_name(tyenv, &term) {
1542 Some(tid) => tid,
1543 None => {
1544 tyenv
1545 .report_error(pos, "Rule LHS root term is not defined".to_string());
1546 continue;
1547 }
1548 };
1549 let termdata = &mut self.terms[term.index()];
1550 match &mut termdata.kind {
1551 TermKind::Decl {
1552 constructor_kind, ..
1553 } => {
1554 match constructor_kind {
1555 None => {
1556 *constructor_kind = Some(ConstructorKind::InternalConstructor);
1557 }
1558 Some(ConstructorKind::InternalConstructor) => {
1559 }
1562 Some(ConstructorKind::ExternalConstructor { .. }) => {
1563 tyenv.report_error(
1564 pos,
1565 "Rule LHS root term is incorrect kind; cannot \
1566 be external constructor"
1567 .to_string(),
1568 );
1569 continue;
1570 }
1571 }
1572 }
1573 TermKind::EnumVariant { .. } => {
1574 tyenv.report_error(
1575 pos,
1576 "Rule LHS root term is incorrect kind; cannot be enum variant"
1577 .to_string(),
1578 );
1579 continue;
1580 }
1581 }
1582 }
1583 _ => {}
1584 }
1585 }
1586 }
1587
1588 fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1589 let mut extractor_call_graph = BTreeMap::new();
1590
1591 for def in defs {
1592 if let &ast::Def::Extractor(ref ext) = def {
1593 let term = match self.get_term_by_name(tyenv, &ext.term) {
1594 Some(x) => x,
1595 None => {
1596 tyenv.report_error(
1597 ext.pos,
1598 "Extractor macro body definition on a non-existent term".to_string(),
1599 );
1600 return;
1601 }
1602 };
1603
1604 let template = ext.template.make_macro_template(&ext.args[..]);
1605 log!("extractor def: {:?} becomes template {:?}", def, template);
1606
1607 let mut callees = BTreeSet::new();
1608 template.terms(&mut |pos, t| {
1609 if let Some(term) = self.get_term_by_name(tyenv, t) {
1610 callees.insert(term);
1611 } else {
1612 tyenv.report_error(
1613 pos,
1614 format!(
1615 "`{}` extractor definition references unknown term `{}`",
1616 ext.term.0, t.0
1617 ),
1618 );
1619 }
1620 });
1621 extractor_call_graph.insert(term, callees);
1622
1623 let termdata = &mut self.terms[term.index()];
1624 match &mut termdata.kind {
1625 TermKind::EnumVariant { .. } => {
1626 tyenv.report_error(
1627 ext.pos,
1628 "Extractor macro body defined on term of incorrect kind; cannot be an \
1629 enum variant",
1630 );
1631 continue;
1632 }
1633 TermKind::Decl {
1634 flags,
1635 extractor_kind,
1636 ..
1637 } => match extractor_kind {
1638 None => {
1639 if flags.multi {
1640 tyenv.report_error(
1641 ext.pos,
1642 "A term declared with `multi` cannot have an internal extractor.".to_string());
1643 continue;
1644 }
1645 *extractor_kind = Some(ExtractorKind::InternalExtractor { template });
1646 }
1647 Some(ext_kind) => {
1648 tyenv.report_error(
1649 ext.pos,
1650 "Duplicate extractor definition".to_string(),
1651 );
1652 let pos = match ext_kind {
1653 ExtractorKind::InternalExtractor { template } => template.pos(),
1654 ExtractorKind::ExternalExtractor { pos, .. } => *pos,
1655 };
1656 tyenv.report_error(
1657 pos,
1658 "Extractor was already defined here".to_string(),
1659 );
1660 continue;
1661 }
1662 },
1663 }
1664 }
1665 }
1666
1667 let mut stack = vec![];
1669 'outer: for root in extractor_call_graph.keys().copied() {
1670 stack.clear();
1671 stack.push((root, vec![root], StableSet::new()));
1672
1673 while let Some((caller, path, mut seen)) = stack.pop() {
1674 let is_new = seen.insert(caller);
1675 if is_new {
1676 if let Some(callees) = extractor_call_graph.get(&caller) {
1677 stack.extend(callees.iter().map(|callee| {
1678 let mut path = path.clone();
1679 path.push(*callee);
1680 (*callee, path, seen.clone())
1681 }));
1682 }
1683 } else {
1684 let pos = match &self.terms[caller.index()].kind {
1685 TermKind::Decl {
1686 extractor_kind: Some(ExtractorKind::InternalExtractor { template }),
1687 ..
1688 } => template.pos(),
1689 _ => {
1690 assert!(!tyenv.errors.is_empty());
1692 continue 'outer;
1693 }
1694 };
1695
1696 let path: Vec<_> = path
1697 .iter()
1698 .map(|sym| tyenv.syms[sym.index()].as_str())
1699 .collect();
1700 let msg = format!(
1701 "`{}` extractor definition is recursive: {}",
1702 tyenv.syms[root.index()],
1703 path.join(" -> ")
1704 );
1705 tyenv.report_error(pos, msg);
1706 continue 'outer;
1707 }
1708 }
1709 }
1710 }
1711
1712 fn collect_converters(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1713 for def in defs {
1714 match def {
1715 &ast::Def::Converter(ast::Converter {
1716 ref term,
1717 ref inner_ty,
1718 ref outer_ty,
1719 pos,
1720 }) => {
1721 let inner_ty_id = match tyenv.get_type_by_name(inner_ty) {
1722 Some(ty) => ty,
1723 None => {
1724 tyenv.report_error(
1725 inner_ty.1,
1726 format!("Unknown inner type for converter: '{}'", inner_ty.0),
1727 );
1728 continue;
1729 }
1730 };
1731
1732 let outer_ty_id = match tyenv.get_type_by_name(outer_ty) {
1733 Some(ty) => ty,
1734 None => {
1735 tyenv.report_error(
1736 outer_ty.1,
1737 format!("Unknown outer type for converter: '{}'", outer_ty.0),
1738 );
1739 continue;
1740 }
1741 };
1742
1743 let term_id = match self.get_term_by_name(tyenv, term) {
1744 Some(term_id) => term_id,
1745 None => {
1746 tyenv.report_error(
1747 term.1,
1748 format!("Unknown term for converter: '{}'", term.0),
1749 );
1750 continue;
1751 }
1752 };
1753
1754 match self.converters.entry((inner_ty_id, outer_ty_id)) {
1755 Entry::Vacant(v) => {
1756 v.insert(term_id);
1757 }
1758 Entry::Occupied(_) => {
1759 tyenv.report_error(
1760 pos,
1761 format!(
1762 "Converter already exists for this type pair: '{}', '{}'",
1763 inner_ty.0, outer_ty.0
1764 ),
1765 );
1766 continue;
1767 }
1768 }
1769 }
1770 _ => {}
1771 }
1772 }
1773 }
1774
1775 fn collect_externs(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1776 for def in defs {
1777 match def {
1778 &ast::Def::Extern(ast::Extern::Constructor {
1779 ref term,
1780 ref func,
1781 pos,
1782 }) => {
1783 let func_sym = tyenv.intern_mut(func);
1784 let term_id = match self.get_term_by_name(tyenv, term) {
1785 Some(term) => term,
1786 None => {
1787 tyenv.report_error(
1788 pos,
1789 format!("Constructor declared on undefined term '{}'", term.0),
1790 );
1791 continue;
1792 }
1793 };
1794 let termdata = &mut self.terms[term_id.index()];
1795 match &mut termdata.kind {
1796 TermKind::Decl {
1797 constructor_kind, ..
1798 } => match constructor_kind {
1799 None => {
1800 *constructor_kind =
1801 Some(ConstructorKind::ExternalConstructor { name: func_sym });
1802 }
1803 Some(ConstructorKind::InternalConstructor) => {
1804 tyenv.report_error(
1805 pos,
1806 format!(
1807 "External constructor declared on term that already has rules: {}",
1808 term.0,
1809 ),
1810 );
1811 }
1812 Some(ConstructorKind::ExternalConstructor { .. }) => {
1813 tyenv.report_error(
1814 pos,
1815 "Duplicate external constructor definition".to_string(),
1816 );
1817 }
1818 },
1819 TermKind::EnumVariant { .. } => {
1820 tyenv.report_error(
1821 pos,
1822 format!(
1823 "External constructor cannot be defined on enum variant: {}",
1824 term.0,
1825 ),
1826 );
1827 }
1828 }
1829 }
1830 &ast::Def::Extern(ast::Extern::Extractor {
1831 ref term,
1832 ref func,
1833 pos,
1834 infallible,
1835 }) => {
1836 let func_sym = tyenv.intern_mut(func);
1837 let term_id = match self.get_term_by_name(tyenv, term) {
1838 Some(term) => term,
1839 None => {
1840 tyenv.report_error(
1841 pos,
1842 format!("Extractor declared on undefined term '{}'", term.0),
1843 );
1844 continue;
1845 }
1846 };
1847
1848 let termdata = &mut self.terms[term_id.index()];
1849
1850 match &mut termdata.kind {
1851 TermKind::Decl { extractor_kind, .. } => match extractor_kind {
1852 None => {
1853 *extractor_kind = Some(ExtractorKind::ExternalExtractor {
1854 name: func_sym,
1855 infallible,
1856 pos,
1857 });
1858 }
1859 Some(ExtractorKind::ExternalExtractor { pos: pos2, .. }) => {
1860 tyenv.report_error(
1861 pos,
1862 "Duplicate external extractor definition".to_string(),
1863 );
1864 tyenv.report_error(
1865 *pos2,
1866 "External extractor already defined".to_string(),
1867 );
1868 continue;
1869 }
1870 Some(ExtractorKind::InternalExtractor { template }) => {
1871 tyenv.report_error(
1872 pos,
1873 "Cannot define external extractor for term that already has an \
1874 internal extractor macro body defined"
1875 .to_string(),
1876 );
1877 tyenv.report_error(
1878 template.pos(),
1879 "Internal extractor macro body already defined".to_string(),
1880 );
1881 continue;
1882 }
1883 },
1884 TermKind::EnumVariant { .. } => {
1885 tyenv.report_error(
1886 pos,
1887 format!("Cannot define extractor for enum variant '{}'", term.0),
1888 );
1889 continue;
1890 }
1891 }
1892 }
1893 _ => {}
1894 }
1895 }
1896 }
1897
1898 fn collect_rules(&mut self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1899 for def in defs {
1900 match def {
1901 &ast::Def::Rule(ref rule) => {
1902 let pos = rule.pos;
1903 let mut bindings = Bindings::default();
1904 bindings.enter_scope();
1905
1906 let (sym, args) = if let ast::Pattern::Term { sym, args, .. } = &rule.pattern {
1907 (sym, args)
1908 } else {
1909 tyenv.report_error(
1910 pos,
1911 "Rule does not have a term at the root of its left-hand side"
1912 .to_string(),
1913 );
1914 continue;
1915 };
1916
1917 let root_term = if let Some(term) = self.get_term_by_name(tyenv, sym) {
1918 term
1919 } else {
1920 tyenv.report_error(
1921 pos,
1922 "Cannot define a rule for an unknown term".to_string(),
1923 );
1924 continue;
1925 };
1926
1927 let termdata = &self.terms[root_term.index()];
1928
1929 let flags = match &termdata.kind {
1930 TermKind::Decl { flags, .. } => *flags,
1931 _ => {
1932 tyenv.report_error(
1933 pos,
1934 "Cannot define a rule on a left-hand-side that is an enum variant"
1935 .to_string(),
1936 );
1937 continue;
1938 }
1939 };
1940
1941 termdata.check_args_count(args, tyenv, pos, sym);
1942 let args = self.translate_args(args, termdata, tyenv, &mut bindings);
1943
1944 let iflets = rule
1945 .iflets
1946 .iter()
1947 .filter_map(|iflet| {
1948 self.translate_iflet(tyenv, iflet, &mut bindings, flags)
1949 })
1950 .collect();
1951 let rhs = unwrap_or_continue!(self.translate_expr(
1952 tyenv,
1953 &rule.expr,
1954 Some(termdata.ret_ty),
1955 &mut bindings,
1956 flags,
1957 ));
1958
1959 bindings.exit_scope();
1960
1961 let prio = if let Some(prio) = rule.prio {
1962 if flags.multi {
1963 tyenv.report_error(
1964 pos,
1965 "Cannot set rule priorities in multi-terms".to_string(),
1966 );
1967 }
1968 prio
1969 } else {
1970 0
1971 };
1972
1973 let rid = RuleId(self.rules.len());
1974 self.rules.push(Rule {
1975 id: rid,
1976 root_term,
1977 args,
1978 iflets,
1979 rhs,
1980 vars: bindings.seen,
1981 prio,
1982 pos,
1983 name: rule.name.as_ref().map(|i| tyenv.intern_mut(i)),
1984 });
1985 }
1986 _ => {}
1987 }
1988 }
1989 }
1990
1991 fn check_for_undefined_decls(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
1992 for def in defs {
1993 if let ast::Def::Decl(decl) = def {
1994 let term = self.get_term_by_name(tyenv, &decl.term).unwrap();
1995 let term = &self.terms[term.index()];
1996 if !term.has_constructor() && !term.has_extractor() {
1997 tyenv.report_error(
1998 decl.pos,
1999 format!(
2000 "no rules, extractor, or external definition for declaration '{}'",
2001 decl.term.0
2002 ),
2003 );
2004 }
2005 }
2006 }
2007 }
2008
2009 fn check_for_expr_terms_without_constructors(&self, tyenv: &mut TypeEnv, defs: &[ast::Def]) {
2010 for def in defs {
2011 if let ast::Def::Rule(rule) = def {
2012 rule.expr.terms(&mut |pos, ident| {
2013 let term = match self.get_term_by_name(tyenv, ident) {
2014 None => {
2015 debug_assert!(!tyenv.errors.is_empty());
2016 return;
2017 }
2018 Some(t) => t,
2019 };
2020 let term = &self.terms[term.index()];
2021 if !term.has_constructor() {
2022 tyenv.report_error(
2023 pos,
2024 format!(
2025 "term `{}` cannot be used in an expression because \
2026 it does not have a constructor",
2027 ident.0
2028 ),
2029 )
2030 }
2031 });
2032 }
2033 }
2034 }
2035
2036 fn maybe_implicit_convert_pattern(
2037 &self,
2038 tyenv: &mut TypeEnv,
2039 pattern: &ast::Pattern,
2040 inner_ty: TypeId,
2041 outer_ty: TypeId,
2042 ) -> Option<ast::Pattern> {
2043 if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) {
2044 if self.terms[converter_term.index()].has_extractor() {
2045 let converter_term_ident = ast::Ident(
2051 tyenv.syms[self.terms[converter_term.index()].name.index()].clone(),
2052 pattern.pos(),
2053 );
2054 let expanded_pattern = ast::Pattern::Term {
2055 sym: converter_term_ident,
2056 pos: pattern.pos(),
2057 args: vec![pattern.clone()],
2058 };
2059
2060 return Some(expanded_pattern);
2061 }
2062 }
2063 None
2064 }
2065
2066 fn translate_pattern(
2067 &self,
2068 tyenv: &mut TypeEnv,
2069 pat: &ast::Pattern,
2070 expected_ty: TypeId,
2071 bindings: &mut Bindings,
2072 ) -> Option<Pattern> {
2073 log!("translate_pattern: {:?}", pat);
2074 log!("translate_pattern: bindings = {:?}", bindings);
2075 match pat {
2076 &ast::Pattern::ConstInt { val, pos } => {
2078 let ty = &tyenv.types[expected_ty.index()];
2079 if !ty.is_int() && !ty.is_prim() {
2080 tyenv.report_error(
2081 pos,
2082 format!(
2083 "expected non-integer type {}, but found integer literal '{}'",
2084 ty.name(tyenv),
2085 val,
2086 ),
2087 );
2088 }
2089 Some(Pattern::ConstInt(expected_ty, val))
2090 }
2091 &ast::Pattern::ConstBool { val, pos } => {
2092 if expected_ty != TypeId::BOOL {
2093 tyenv.report_error(
2094 pos,
2095 format!(
2096 "Boolean literal '{val}' has type {} but we need {} in context",
2097 BuiltinType::Bool.name(),
2098 tyenv.types[expected_ty.index()].name(tyenv)
2099 ),
2100 )
2101 }
2102 Some(Pattern::ConstBool(TypeId::BOOL, val))
2103 }
2104 &ast::Pattern::ConstPrim { ref val, pos } => {
2105 let val = tyenv.intern_mut(val);
2106 let const_ty = match tyenv.const_types.get(&val) {
2107 Some(ty) => *ty,
2108 None => {
2109 tyenv.report_error(pos, "Unknown constant");
2110 return None;
2111 }
2112 };
2113 if expected_ty != const_ty {
2114 tyenv.report_error(pos, "Type mismatch for constant");
2115 }
2116 Some(Pattern::ConstPrim(const_ty, val))
2117 }
2118 &ast::Pattern::Wildcard { .. } => Some(Pattern::Wildcard(expected_ty)),
2119 &ast::Pattern::And { ref subpats, .. } => {
2120 let children = subpats
2124 .iter()
2125 .filter_map(|subpat| {
2126 self.translate_pattern(tyenv, subpat, expected_ty, bindings)
2127 })
2128 .collect();
2129 Some(Pattern::And(expected_ty, children))
2130 }
2131 &ast::Pattern::BindPattern {
2132 ref var,
2133 ref subpat,
2134 pos,
2135 } => {
2136 let subpat = self.translate_pattern(tyenv, subpat, expected_ty, bindings)?;
2137
2138 let ty = subpat.ty();
2143
2144 let name = tyenv.intern_mut(var);
2145 if bindings.lookup(name).is_some() {
2146 tyenv.report_error(
2147 pos,
2148 format!("Re-bound variable name in LHS pattern: '{}'", var.0),
2149 );
2150 }
2152 let id = bindings.add_var(name, ty);
2153 Some(Pattern::BindPattern(ty, id, Box::new(subpat)))
2154 }
2155 &ast::Pattern::Var { ref var, pos } => {
2156 let name = tyenv.intern_mut(var);
2162 match bindings.lookup(name) {
2163 None => {
2164 let id = bindings.add_var(name, expected_ty);
2165 Some(Pattern::BindPattern(
2166 expected_ty,
2167 id,
2168 Box::new(Pattern::Wildcard(expected_ty)),
2169 ))
2170 }
2171 Some(bv) => {
2172 if expected_ty != bv.ty {
2173 tyenv.report_error(
2174 pos,
2175 format!(
2176 "Mismatched types: pattern expects type '{}' but already-bound var '{}' has type '{}'",
2177 tyenv.types[expected_ty.index()].name(tyenv),
2178 var.0,
2179 tyenv.types[bv.ty.index()].name(tyenv),
2180 ),
2181 );
2182 }
2184 Some(Pattern::Var(bv.ty, bv.id))
2185 }
2186 }
2187 }
2188 &ast::Pattern::Term {
2189 ref sym,
2190 ref args,
2191 pos,
2192 } => {
2193 let tid = match self.get_term_by_name(tyenv, sym) {
2195 Some(t) => t,
2196 None => {
2197 tyenv.report_error(pos, format!("Unknown term in pattern: '{}'", sym.0));
2198 return None;
2199 }
2200 };
2201
2202 let termdata = &self.terms[tid.index()];
2203
2204 let ret_ty = termdata.ret_ty;
2209 if expected_ty != ret_ty {
2210 if let Some(expanded_pattern) =
2216 self.maybe_implicit_convert_pattern(tyenv, pat, ret_ty, expected_ty)
2217 {
2218 return self.translate_pattern(
2219 tyenv,
2220 &expanded_pattern,
2221 expected_ty,
2222 bindings,
2223 );
2224 }
2225
2226 tyenv.report_error(
2227 pos,
2228 format!(
2229 "Mismatched types: pattern expects type '{}' but term has return type '{}'",
2230 tyenv.types[expected_ty.index()].name(tyenv),
2231 tyenv.types[ret_ty.index()].name(tyenv),
2232 ),
2233 );
2234 }
2236
2237 termdata.check_args_count(args, tyenv, pos, sym);
2238
2239 match &termdata.kind {
2242 TermKind::EnumVariant { .. } => {}
2243 TermKind::Decl {
2244 extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
2245 ..
2246 } => {}
2247 TermKind::Decl {
2248 extractor_kind: Some(ExtractorKind::InternalExtractor { template }),
2249 ..
2250 } => {
2251 if self.expand_internal_extractors {
2252 log!("internal extractor macro args = {:?}", args);
2257 let pat = template.subst_macro_args(&args)?;
2258 return self.translate_pattern(tyenv, &pat, expected_ty, bindings);
2259 }
2260 }
2261 TermKind::Decl {
2262 extractor_kind: None,
2263 ..
2264 } => {
2265 tyenv.report_error(
2266 pos,
2267 format!(
2268 "Cannot use term '{}' that does not have a defined extractor in a \
2269 left-hand side pattern",
2270 sym.0
2271 ),
2272 );
2273 }
2274 }
2275
2276 let subpats = self.translate_args(args, termdata, tyenv, bindings);
2277 Some(Pattern::Term(ret_ty, tid, subpats))
2278 }
2279 &ast::Pattern::MacroArg { .. } => unreachable!(),
2280 }
2281 }
2282
2283 fn translate_args(
2284 &self,
2285 args: &Vec<ast::Pattern>,
2286 termdata: &Term,
2287 tyenv: &mut TypeEnv,
2288 bindings: &mut Bindings,
2289 ) -> Vec<Pattern> {
2290 args.iter()
2291 .zip(termdata.arg_tys.iter())
2292 .filter_map(|(arg, &arg_ty)| self.translate_pattern(tyenv, arg, arg_ty, bindings))
2293 .collect()
2294 }
2295
2296 fn maybe_implicit_convert_expr(
2297 &self,
2298 tyenv: &mut TypeEnv,
2299 expr: &ast::Expr,
2300 inner_ty: TypeId,
2301 outer_ty: TypeId,
2302 ) -> Option<ast::Expr> {
2303 if let Some(converter_term) = self.converters.get(&(inner_ty, outer_ty)) {
2305 if self.terms[converter_term.index()].has_constructor() {
2306 let converter_ident = ast::Ident(
2307 tyenv.syms[self.terms[converter_term.index()].name.index()].clone(),
2308 expr.pos(),
2309 );
2310 return Some(ast::Expr::Term {
2311 sym: converter_ident,
2312 pos: expr.pos(),
2313 args: vec![expr.clone()],
2314 });
2315 }
2316 }
2317 None
2318 }
2319
2320 fn translate_expr(
2321 &self,
2322 tyenv: &mut TypeEnv,
2323 expr: &ast::Expr,
2324 ty: Option<TypeId>,
2325 bindings: &mut Bindings,
2326 root_flags: TermFlags,
2327 ) -> Option<Expr> {
2328 log!("translate_expr: {:?}", expr);
2329 match expr {
2330 &ast::Expr::Term {
2331 ref sym,
2332 ref args,
2333 pos,
2334 } => {
2335 let name = tyenv.intern_mut(&sym);
2337 let tid = match self.term_map.get(&name) {
2338 Some(&t) => t,
2339 None => {
2340 if bindings.lookup(name).is_some() {
2343 tyenv.report_error(
2344 pos,
2345 format!(
2346 "Unknown term in expression: '{}'. Variable binding under this name exists; try removing the parens?", sym.0));
2347 } else {
2348 tyenv.report_error(
2349 pos,
2350 format!("Unknown term in expression: '{}'", sym.0),
2351 );
2352 }
2353 return None;
2354 }
2355 };
2356 let termdata = &self.terms[tid.index()];
2357
2358 let ret_ty = termdata.ret_ty;
2364 let ty = if ty.is_some() && ret_ty != ty.unwrap() {
2365 if let Some(expanded_expr) =
2367 self.maybe_implicit_convert_expr(tyenv, expr, ret_ty, ty.unwrap())
2368 {
2369 return self.translate_expr(
2370 tyenv,
2371 &expanded_expr,
2372 ty,
2373 bindings,
2374 root_flags,
2375 );
2376 }
2377
2378 tyenv.report_error(
2379 pos,
2380 format!("Mismatched types: expression expects type '{}' but term has return type '{}'",
2381 tyenv.types[ty.unwrap().index()].name(tyenv),
2382 tyenv.types[ret_ty.index()].name(tyenv)));
2383
2384 ret_ty
2386 } else {
2387 ret_ty
2388 };
2389
2390 if let TermKind::Decl { flags, .. } = &termdata.kind {
2391 let pure_required = root_flags.pure;
2394 if pure_required && !flags.pure {
2395 tyenv.report_error(
2396 pos,
2397 format!(
2398 "Used non-pure constructor '{}' in pure expression context",
2399 sym.0
2400 ),
2401 );
2402 }
2403
2404 if !root_flags.multi && flags.multi {
2406 tyenv.report_error(
2407 pos,
2408 format!(
2409 "Used multi-constructor '{}' but this rule is not in a multi-term",
2410 sym.0
2411 ),
2412 );
2413 }
2414
2415 let partial_allowed = root_flags.partial;
2418 if !partial_allowed && flags.partial {
2419 tyenv.report_error(
2420 pos,
2421 format!(
2422 "Rule can't use partial constructor '{}' on RHS; \
2423 try moving it to if-let{}",
2424 sym.0,
2425 if root_flags.multi {
2426 ""
2427 } else {
2428 " or make this rule's term partial too"
2429 }
2430 ),
2431 );
2432 }
2433 }
2434
2435 termdata.check_args_count(args, tyenv, pos, sym);
2436
2437 let subexprs = args
2439 .iter()
2440 .zip(termdata.arg_tys.iter())
2441 .filter_map(|(arg, &arg_ty)| {
2442 self.translate_expr(tyenv, arg, Some(arg_ty), bindings, root_flags)
2443 })
2444 .collect();
2445
2446 Some(Expr::Term(ty, tid, subexprs))
2447 }
2448 &ast::Expr::Var { ref name, pos } => {
2449 let sym = tyenv.intern_mut(name);
2450 let bv = match bindings.lookup(sym) {
2452 None => {
2453 tyenv.report_error(pos, format!("Unknown variable '{}'", name.0));
2454 return None;
2455 }
2456 Some(bv) => bv,
2457 };
2458
2459 if ty.is_some() && bv.ty != ty.unwrap() {
2461 if let Some(expanded_expr) =
2463 self.maybe_implicit_convert_expr(tyenv, expr, bv.ty, ty.unwrap())
2464 {
2465 return self.translate_expr(
2466 tyenv,
2467 &expanded_expr,
2468 ty,
2469 bindings,
2470 root_flags,
2471 );
2472 }
2473
2474 tyenv.report_error(
2475 pos,
2476 format!(
2477 "Variable '{}' has type {} but we need {} in context",
2478 name.0,
2479 tyenv.types[bv.ty.index()].name(tyenv),
2480 tyenv.types[ty.unwrap().index()].name(tyenv)
2481 ),
2482 );
2483 }
2484
2485 Some(Expr::Var(bv.ty, bv.id))
2486 }
2487 &ast::Expr::ConstBool { val, pos } => {
2488 match ty {
2489 Some(ty) if ty != TypeId::BOOL => tyenv.report_error(
2490 pos,
2491 format!(
2492 "Boolean literal '{val}' has type {} but we need {} in context",
2493 BuiltinType::Bool.name(),
2494 tyenv.types[ty.index()].name(tyenv)
2495 ),
2496 ),
2497 Some(..) | None => {}
2498 };
2499 Some(Expr::ConstBool(TypeId::BOOL, val))
2500 }
2501 &ast::Expr::ConstInt { val, pos } => {
2502 let Some(ty) = ty else {
2503 tyenv.report_error(
2504 pos,
2505 "integer literal in a context that needs an explicit type".to_string(),
2506 );
2507 return None;
2508 };
2509
2510 let typ = &tyenv.types[ty.index()];
2511
2512 if !typ.is_int() && !typ.is_prim() {
2513 tyenv.report_error(
2514 pos,
2515 format!(
2516 "expected non-integer type {}, but found integer literal '{}'",
2517 tyenv.types[ty.index()].name(tyenv),
2518 val,
2519 ),
2520 );
2521 }
2522 Some(Expr::ConstInt(ty, val))
2523 }
2524 &ast::Expr::ConstPrim { ref val, pos } => {
2525 let val = tyenv.intern_mut(val);
2526 let const_ty = match tyenv.const_types.get(&val) {
2527 Some(ty) => *ty,
2528 None => {
2529 tyenv.report_error(pos, "Unknown constant");
2530 return None;
2531 }
2532 };
2533 if ty.is_some() && const_ty != ty.unwrap() {
2534 tyenv.report_error(
2535 pos,
2536 format!(
2537 "Constant '{}' has wrong type: expected {}, but is actually {}",
2538 tyenv.syms[val.index()],
2539 tyenv.types[ty.unwrap().index()].name(tyenv),
2540 tyenv.types[const_ty.index()].name(tyenv)
2541 ),
2542 );
2543 return None;
2544 }
2545 Some(Expr::ConstPrim(const_ty, val))
2546 }
2547 &ast::Expr::Let {
2548 ref defs,
2549 ref body,
2550 pos,
2551 } => {
2552 bindings.enter_scope();
2553
2554 let mut let_defs = vec![];
2556 for def in defs {
2557 let name = tyenv.intern_mut(&def.var);
2559
2560 let tid = match tyenv.get_type_by_name(&def.ty) {
2562 Some(tid) => tid,
2563 None => {
2564 tyenv.report_error(
2565 pos,
2566 format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0),
2567 );
2568 continue;
2569 }
2570 };
2571
2572 let val = Box::new(unwrap_or_continue!(self.translate_expr(
2574 tyenv,
2575 &def.val,
2576 Some(tid),
2577 bindings,
2578 root_flags,
2579 )));
2580
2581 let id = bindings.add_var(name, tid);
2583 let_defs.push((id, tid, val));
2584 }
2585
2586 let body = Box::new(self.translate_expr(tyenv, body, ty, bindings, root_flags)?);
2588 let body_ty = body.ty();
2589
2590 bindings.exit_scope();
2592
2593 Some(Expr::Let {
2594 ty: body_ty,
2595 bindings: let_defs,
2596 body,
2597 })
2598 }
2599 }
2600 }
2601
2602 fn translate_iflet(
2603 &self,
2604 tyenv: &mut TypeEnv,
2605 iflet: &ast::IfLet,
2606 bindings: &mut Bindings,
2607 root_flags: TermFlags,
2608 ) -> Option<IfLet> {
2609 let rhs = self.translate_expr(tyenv, &iflet.expr, None, bindings, root_flags.on_lhs())?;
2612 let lhs = self.translate_pattern(tyenv, &iflet.pattern, rhs.ty(), bindings)?;
2613
2614 Some(IfLet { lhs, rhs })
2615 }
2616
2617 pub fn get_term_by_name(&self, tyenv: &TypeEnv, sym: &ast::Ident) -> Option<TermId> {
2619 tyenv
2620 .intern(sym)
2621 .and_then(|sym| self.term_map.get(&sym))
2622 .copied()
2623 }
2624}
2625
2626#[cfg(test)]
2627mod test {
2628 use super::*;
2629 use crate::ast::Ident;
2630 use crate::lexer::Lexer;
2631 use crate::parser::parse;
2632
2633 #[test]
2634 fn build_type_env() {
2635 let text = r"
2636 (type UImm8 (primitive UImm8))
2637 (type A extern (enum (B (f1 u32) (f2 u32)) (C (f1 u32))))
2638 ";
2639 let ast = parse(Lexer::new(0, text).unwrap()).expect("should parse");
2640 let tyenv = TypeEnv::from_ast(&ast).expect("should not have type-definition errors");
2641
2642 let sym_a = tyenv
2643 .intern(&Ident("A".to_string(), Default::default()))
2644 .unwrap();
2645 let sym_b = tyenv
2646 .intern(&Ident("B".to_string(), Default::default()))
2647 .unwrap();
2648 let sym_c = tyenv
2649 .intern(&Ident("C".to_string(), Default::default()))
2650 .unwrap();
2651 let sym_a_b = tyenv
2652 .intern(&Ident("A.B".to_string(), Default::default()))
2653 .unwrap();
2654 let sym_a_c = tyenv
2655 .intern(&Ident("A.C".to_string(), Default::default()))
2656 .unwrap();
2657 let sym_uimm8 = tyenv
2658 .intern(&Ident("UImm8".to_string(), Default::default()))
2659 .unwrap();
2660 let sym_f1 = tyenv
2661 .intern(&Ident("f1".to_string(), Default::default()))
2662 .unwrap();
2663 let sym_f2 = tyenv
2664 .intern(&Ident("f2".to_string(), Default::default()))
2665 .unwrap();
2666
2667 assert_eq!(tyenv.type_map.get(&sym_uimm8).unwrap(), &TypeId(13));
2668 assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(14));
2669
2670 let expected_types = vec![
2671 Type::Primitive(
2672 TypeId(13),
2673 sym_uimm8,
2674 Pos {
2675 file: 0,
2676 offset: 19,
2677 },
2678 ),
2679 Type::Enum {
2680 name: sym_a,
2681 id: TypeId(14),
2682 is_extern: true,
2683 is_nodebug: false,
2684 variants: vec![
2685 Variant {
2686 name: sym_b,
2687 fullname: sym_a_b,
2688 id: VariantId(0),
2689 fields: vec![
2690 Field {
2691 name: sym_f1,
2692 id: FieldId(0),
2693 ty: TypeId::U32,
2694 },
2695 Field {
2696 name: sym_f2,
2697 id: FieldId(1),
2698 ty: TypeId::U32,
2699 },
2700 ],
2701 },
2702 Variant {
2703 name: sym_c,
2704 fullname: sym_a_c,
2705 id: VariantId(1),
2706 fields: vec![Field {
2707 name: sym_f1,
2708 id: FieldId(0),
2709 ty: TypeId::U32,
2710 }],
2711 },
2712 ],
2713 pos: Pos {
2714 file: 0,
2715 offset: 62,
2716 },
2717 },
2718 ];
2719
2720 assert_eq!(
2721 tyenv.types.len(),
2722 expected_types.len() + BuiltinType::ALL.len()
2723 );
2724 for (i, (actual, expected)) in tyenv
2725 .types
2726 .iter()
2727 .skip(BuiltinType::ALL.len())
2728 .zip(&expected_types)
2729 .enumerate()
2730 {
2731 assert_eq!(expected, actual, "`{i}`th type is not equal!");
2732 }
2733 }
2734}