1use crate::{
2 fun::{parser::ParseBook, Name},
3 imp::{Definition, Expr, Stmt},
4};
5use indexmap::IndexMap;
6
7impl Definition {
8 pub fn order_kwargs(&mut self, book: &ParseBook) -> Result<(), String> {
11 let use_map = &mut IndexMap::new();
12 self.body.order_kwargs(book, use_map).map_err(|e| format!("In function '{}':\n {}", self.name, e))
13 }
14}
15
16impl Stmt {
17 fn order_kwargs(&mut self, book: &ParseBook, use_map: &mut IndexMap<Name, Name>) -> Result<(), String> {
18 match self {
19 Stmt::LocalDef { def, nxt } => {
20 def.order_kwargs(book)?;
21 nxt.order_kwargs(book, use_map)?;
22 }
23 Stmt::Assign { val, nxt, .. } => {
24 val.order_kwargs(book, use_map)?;
25 if let Some(nxt) = nxt {
26 nxt.order_kwargs(book, use_map)?;
27 }
28 }
29 Stmt::Ask { val, nxt, .. } => {
30 val.order_kwargs(book, use_map)?;
31 if let Some(nxt) = nxt {
32 nxt.order_kwargs(book, use_map)?;
33 }
34 }
35 Stmt::InPlace { val, nxt, .. } => {
36 val.order_kwargs(book, use_map)?;
37 nxt.order_kwargs(book, use_map)?;
38 }
39 Stmt::If { cond, then, otherwise, nxt } => {
40 cond.order_kwargs(book, use_map)?;
41 then.order_kwargs(book, use_map)?;
42 otherwise.order_kwargs(book, use_map)?;
43 if let Some(nxt) = nxt {
44 nxt.order_kwargs(book, use_map)?;
45 }
46 }
47 Stmt::Match { arg, arms, nxt, .. } => {
48 arg.order_kwargs(book, use_map)?;
49 for arm in arms {
50 arm.rgt.order_kwargs(book, use_map)?;
51 }
52 if let Some(nxt) = nxt {
53 nxt.order_kwargs(book, use_map)?;
54 }
55 }
56 Stmt::Switch { arg, arms, nxt, .. } => {
57 arg.order_kwargs(book, use_map)?;
58 for arm in arms {
59 arm.order_kwargs(book, use_map)?;
60 }
61 if let Some(nxt) = nxt {
62 nxt.order_kwargs(book, use_map)?;
63 }
64 }
65 Stmt::Fold { arg, arms, nxt, .. } => {
66 arg.order_kwargs(book, use_map)?;
67 for arm in arms {
68 arm.rgt.order_kwargs(book, use_map)?;
69 }
70 if let Some(nxt) = nxt {
71 nxt.order_kwargs(book, use_map)?;
72 }
73 }
74 Stmt::Bend { bnd: _, arg, cond, step, base, nxt } => {
75 for arg in arg {
76 arg.order_kwargs(book, use_map)?;
77 }
78 cond.order_kwargs(book, use_map)?;
79 step.order_kwargs(book, use_map)?;
80 base.order_kwargs(book, use_map)?;
81 if let Some(nxt) = nxt {
82 nxt.order_kwargs(book, use_map)?;
83 }
84 }
85 Stmt::With { typ: _, bod, nxt } => {
86 bod.order_kwargs(book, use_map)?;
87 if let Some(nxt) = nxt {
88 nxt.order_kwargs(book, use_map)?;
89 }
90 }
91 Stmt::Open { typ: _, var: _, nxt } => {
92 nxt.order_kwargs(book, use_map)?;
93 }
94 Stmt::Use { nam, val: bod, nxt } => {
95 if let Expr::Var { nam: bod } = bod.as_ref() {
96 use_map.insert(nam.clone(), bod.clone());
97 nxt.order_kwargs(book, use_map)?;
98 use_map.pop();
99 } else {
100 bod.order_kwargs(book, use_map)?;
101 nxt.order_kwargs(book, use_map)?;
102 }
103 }
104 Stmt::Return { term } => term.order_kwargs(book, use_map)?,
105 Stmt::Err => {}
106 }
107 Ok(())
108 }
109}
110
111impl Expr {
112 fn order_kwargs(&mut self, book: &ParseBook, use_map: &mut IndexMap<Name, Name>) -> Result<(), String> {
113 match self {
114 Expr::Call { fun, args, kwargs } => {
116 if !kwargs.is_empty() {
117 if let Expr::Var { nam } = fun.as_ref() {
118 if let Some(names) = get_args_def_or_ctr(nam, book, use_map) {
119 go_order_kwargs(&names, args, kwargs)?;
120 } else {
121 return Err(format!(
122 "Named args are only allowed when calling a named function, not when calling variable '{nam}'."
123 ));
124 }
125 } else {
126 return Err(
128 "Named args are only allowed when calling a named function, not when calling an expression."
129 .to_string(),
130 );
131 }
132 }
133 fun.order_kwargs(book, use_map)?;
134 for arg in args {
135 arg.order_kwargs(book, use_map)?;
136 }
137 for (_, arg) in kwargs {
138 arg.order_kwargs(book, use_map)?;
139 }
140 }
141 Expr::Lam { bod, .. } => bod.order_kwargs(book, use_map)?,
142 Expr::Opr { lhs, rhs, .. } => {
143 lhs.order_kwargs(book, use_map)?;
144 rhs.order_kwargs(book, use_map)?;
145 }
146 Expr::Lst { els } | Expr::Tup { els } | Expr::Sup { els } => {
147 for el in els {
148 el.order_kwargs(book, use_map)?;
149 }
150 }
151 Expr::LstMap { term, iter, cond, .. } => {
152 term.order_kwargs(book, use_map)?;
153 iter.order_kwargs(book, use_map)?;
154 if let Some(cond) = cond {
155 cond.order_kwargs(book, use_map)?;
156 }
157 }
158 Expr::Ctr { name, args, kwargs } => match get_args_def_or_ctr(name, book, use_map) {
159 Some(names) => {
160 go_order_kwargs(&names, args, kwargs)?;
161 for arg in args {
162 arg.order_kwargs(book, use_map)?;
163 }
164 }
165 _ => return Err(format!("Constructor '{name}' not found.")),
166 },
167 Expr::Map { entries } => {
168 for entry in entries {
169 entry.1.order_kwargs(book, use_map)?;
170 }
171 }
172 Expr::MapGet { nam: _, key } => {
173 key.order_kwargs(book, use_map)?;
174 }
175 Expr::TreeNode { left, right } => {
176 left.order_kwargs(book, use_map)?;
177 right.order_kwargs(book, use_map)?;
178 }
179 Expr::TreeLeaf { val } => {
180 val.order_kwargs(book, use_map)?;
181 }
182 Expr::Era | Expr::Var { .. } | Expr::Chn { .. } | Expr::Num { .. } | Expr::Str { .. } => {}
183 }
184 Ok(())
185 }
186}
187
188fn go_order_kwargs(
189 names: &[Name],
190 args: &mut Vec<Expr>,
191 kwargs: &mut Vec<(Name, Expr)>,
192) -> Result<(), String> {
193 if args.len() + kwargs.len() != names.len() {
194 return Err(
195 "Named args are only allowed when calling a function with the exact number of arguments.".to_string(),
196 );
197 }
198 let mut kwargs: IndexMap<Name, Expr> = IndexMap::from_iter(kwargs.drain(..));
199 let remaining_names = &names[args.len()..];
200 for name in remaining_names {
201 if let Some(arg) = kwargs.shift_remove(name) {
202 args.push(arg);
203 } else {
204 return Err(format!("Named arg '{name}' is missing."));
205 }
206 }
207 if let Some(name) = kwargs.keys().next() {
208 return Err(format!("Unexpected named arg in function call {}.", name));
209 }
210 Ok(())
211}
212
213fn get_args_def_or_ctr(name: &Name, book: &ParseBook, use_map: &IndexMap<Name, Name>) -> Option<Vec<Name>> {
214 let name = use_map.get(name).unwrap_or(name);
215
216 #[allow(clippy::manual_map)]
217 if let Some(adt_nam) = book.ctrs.get(name) {
218 Some(book.adts[adt_nam].ctrs[name].fields.iter().map(|f| f.nam.clone()).collect())
219 } else if let Some(def) = book.fun_defs.get(name) {
220 Some(def.rules[0].pats.iter().flat_map(|p| p.binds().flatten().cloned()).collect())
221 } else {
222 None
223 }
224}