1use crate::env::TypeEnv;
8use crate::types::*;
9use indexmap::IndexMap;
10
11pub fn module_scope(name: &str, _env: &TypeEnv) -> Option<Ty> {
13 match name {
14 "io" => {
15 let mut fields = IndexMap::new();
16 fields.insert("print".into(), Ty::function(
18 vec![Ty::str()],
19 EffectSet::singleton("io"),
20 Ty::Unit,
21 ));
22 fields.insert("read".into(), Ty::function(
24 vec![Ty::str()],
25 EffectSet::singleton("io"),
26 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
27 ));
28 fields.insert("write".into(), Ty::function(
30 vec![Ty::str(), Ty::str()],
31 EffectSet::singleton("io"),
32 Ty::Con("Result".into(), vec![Ty::Unit, Ty::str()]),
33 ));
34 Some(Ty::Record(fields))
35 }
36 "str" => {
37 let mut fields = IndexMap::new();
38 fields.insert("is_empty".into(), Ty::function(vec![Ty::str()], EffectSet::empty(), Ty::bool()));
39 fields.insert("to_int".into(), Ty::function(vec![Ty::str()], EffectSet::empty(),
40 Ty::Con("Option".into(), vec![Ty::int()])));
41 fields.insert("to_float".into(), Ty::function(vec![Ty::str()], EffectSet::empty(),
42 Ty::Con("Option".into(), vec![Ty::float()])));
43 fields.insert("concat".into(), Ty::function(vec![Ty::str(), Ty::str()], EffectSet::empty(), Ty::str()));
44 fields.insert("len".into(), Ty::function(vec![Ty::str()], EffectSet::empty(), Ty::int()));
45 fields.insert("split".into(), Ty::function(
46 vec![Ty::str(), Ty::str()],
47 EffectSet::empty(),
48 Ty::List(Box::new(Ty::str())),
49 ));
50 fields.insert("join".into(), Ty::function(
51 vec![Ty::List(Box::new(Ty::str())), Ty::str()],
52 EffectSet::empty(),
53 Ty::str(),
54 ));
55 for name in &["starts_with", "ends_with", "contains"] {
57 fields.insert((*name).into(), Ty::function(
58 vec![Ty::str(), Ty::str()],
59 EffectSet::empty(),
60 Ty::bool(),
61 ));
62 }
63 fields.insert("replace".into(), Ty::function(
65 vec![Ty::str(), Ty::str(), Ty::str()],
66 EffectSet::empty(),
67 Ty::str(),
68 ));
69 for name in &["trim", "to_upper", "to_lower"] {
70 fields.insert((*name).into(), Ty::function(
71 vec![Ty::str()], EffectSet::empty(), Ty::str(),
72 ));
73 }
74 for name in &["strip_prefix", "strip_suffix"] {
75 fields.insert((*name).into(), Ty::function(
76 vec![Ty::str(), Ty::str()],
77 EffectSet::empty(),
78 Ty::Con("Option".into(), vec![Ty::str()]),
79 ));
80 }
81 fields.insert("slice".into(), Ty::function(
83 vec![Ty::str(), Ty::int(), Ty::int()],
84 EffectSet::empty(),
85 Ty::str(),
86 ));
87 Some(Ty::Record(fields))
88 }
89 "int" => {
90 let mut fields = IndexMap::new();
91 fields.insert("to_str".into(), Ty::function(vec![Ty::int()], EffectSet::empty(), Ty::str()));
92 fields.insert("to_float".into(), Ty::function(vec![Ty::int()], EffectSet::empty(), Ty::float()));
93 Some(Ty::Record(fields))
94 }
95 "math" => {
96 let mut fields = IndexMap::new();
97 let mat = || Ty::Con("Matrix".into(), Vec::new());
101 for name in &["exp", "log", "sqrt", "abs"] {
103 fields.insert((*name).into(), Ty::function(
104 vec![Ty::float()], EffectSet::empty(), Ty::float(),
105 ));
106 }
107 fields.insert("zeros".into(), Ty::function(
109 vec![Ty::int(), Ty::int()], EffectSet::empty(), mat(),
110 ));
111 fields.insert("ones".into(), Ty::function(
112 vec![Ty::int(), Ty::int()], EffectSet::empty(), mat(),
113 ));
114 fields.insert("from_lists".into(), Ty::function(
115 vec![Ty::List(Box::new(Ty::List(Box::new(Ty::float()))))],
116 EffectSet::empty(),
117 mat(),
118 ));
119 fields.insert("from_flat".into(), Ty::function(
120 vec![Ty::int(), Ty::int(), Ty::List(Box::new(Ty::float()))],
121 EffectSet::empty(),
122 mat(),
123 ));
124 fields.insert("rows".into(), Ty::function(vec![mat()], EffectSet::empty(), Ty::int()));
126 fields.insert("cols".into(), Ty::function(vec![mat()], EffectSet::empty(), Ty::int()));
127 fields.insert("get".into(), Ty::function(
128 vec![mat(), Ty::int(), Ty::int()], EffectSet::empty(), Ty::float(),
129 ));
130 fields.insert("to_flat".into(), Ty::function(
131 vec![mat()], EffectSet::empty(),
132 Ty::List(Box::new(Ty::float())),
133 ));
134 fields.insert("transpose".into(), Ty::function(
136 vec![mat()], EffectSet::empty(), mat(),
137 ));
138 fields.insert("matmul".into(), Ty::function(
139 vec![mat(), mat()], EffectSet::empty(), mat(),
140 ));
141 fields.insert("scale".into(), Ty::function(
142 vec![Ty::float(), mat()], EffectSet::empty(), mat(),
143 ));
144 for name in &["add", "sub"] {
145 fields.insert((*name).into(), Ty::function(
146 vec![mat(), mat()], EffectSet::empty(), mat(),
147 ));
148 }
149 fields.insert("sigmoid".into(), Ty::function(
150 vec![mat()], EffectSet::empty(), mat(),
151 ));
152 Some(Ty::Record(fields))
153 }
154 "float" => {
155 let mut fields = IndexMap::new();
156 fields.insert("to_int".into(), Ty::function(vec![Ty::float()], EffectSet::empty(), Ty::int()));
157 fields.insert("to_str".into(), Ty::function(vec![Ty::float()], EffectSet::empty(), Ty::str()));
158 Some(Ty::Record(fields))
159 }
160 "list" => {
161 let mut fields = IndexMap::new();
164 fields.insert("map".into(), Ty::function(
171 vec![
172 Ty::List(Box::new(Ty::Var(0))),
173 Ty::function(vec![Ty::Var(0)], EffectSet::open_var(2), Ty::Var(1)),
174 ],
175 EffectSet::open_var(2),
176 Ty::List(Box::new(Ty::Var(1))),
177 ));
178 fields.insert("filter".into(), Ty::function(
179 vec![
180 Ty::List(Box::new(Ty::Var(0))),
181 Ty::function(vec![Ty::Var(0)], EffectSet::open_var(3), Ty::bool()),
182 ],
183 EffectSet::open_var(3),
184 Ty::List(Box::new(Ty::Var(0))),
185 ));
186 fields.insert("fold".into(), Ty::function(
187 vec![
188 Ty::List(Box::new(Ty::Var(0))),
189 Ty::Var(1),
190 Ty::function(vec![Ty::Var(1), Ty::Var(0)], EffectSet::open_var(4), Ty::Var(1)),
191 ],
192 EffectSet::open_var(4),
193 Ty::Var(1),
194 ));
195 fields.insert("len".into(), Ty::function(
196 vec![Ty::List(Box::new(Ty::Var(0)))],
197 EffectSet::empty(),
198 Ty::int(),
199 ));
200 fields.insert("is_empty".into(), Ty::function(
201 vec![Ty::List(Box::new(Ty::Var(0)))],
202 EffectSet::empty(),
203 Ty::bool(),
204 ));
205 fields.insert("range".into(), Ty::function(
206 vec![Ty::int(), Ty::int()],
207 EffectSet::empty(),
208 Ty::List(Box::new(Ty::int())),
209 ));
210 fields.insert("head".into(), Ty::function(
211 vec![Ty::List(Box::new(Ty::Var(0)))],
212 EffectSet::empty(),
213 Ty::Con("Option".into(), vec![Ty::Var(0)]),
214 ));
215 fields.insert("tail".into(), Ty::function(
216 vec![Ty::List(Box::new(Ty::Var(0)))],
217 EffectSet::empty(),
218 Ty::List(Box::new(Ty::Var(0))),
219 ));
220 fields.insert("concat".into(), Ty::function(
221 vec![Ty::List(Box::new(Ty::Var(0))), Ty::List(Box::new(Ty::Var(0)))],
222 EffectSet::empty(),
223 Ty::List(Box::new(Ty::Var(0))),
224 ));
225 Some(Ty::Record(fields))
226 }
227 "bytes" => {
228 let mut fields = IndexMap::new();
229 fields.insert("len".into(), Ty::function(
230 vec![Ty::bytes()], EffectSet::empty(), Ty::int(),
231 ));
232 fields.insert("is_empty".into(), Ty::function(
233 vec![Ty::bytes()], EffectSet::empty(), Ty::bool(),
234 ));
235 fields.insert("eq".into(), Ty::function(
236 vec![Ty::bytes(), Ty::bytes()], EffectSet::empty(), Ty::bool(),
237 ));
238 fields.insert("from_str".into(), Ty::function(
239 vec![Ty::str()], EffectSet::empty(), Ty::bytes(),
240 ));
241 fields.insert("to_str".into(), Ty::function(
242 vec![Ty::bytes()], EffectSet::empty(),
243 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
244 ));
245 fields.insert("slice".into(), Ty::function(
246 vec![Ty::bytes(), Ty::int(), Ty::int()],
247 EffectSet::empty(), Ty::bytes(),
248 ));
249 Some(Ty::Record(fields))
250 }
251 "time" => {
252 let mut fields = IndexMap::new();
258 fields.insert("now".into(), Ty::function(
259 vec![],
260 EffectSet::singleton("time"),
261 Ty::int(),
262 ));
263 Some(Ty::Record(fields))
264 }
265 "rand" => {
266 let mut fields = IndexMap::new();
269 fields.insert("int_in".into(), Ty::function(
270 vec![Ty::int(), Ty::int()],
271 EffectSet::singleton("rand"),
272 Ty::int(),
273 ));
274 Some(Ty::Record(fields))
275 }
276 "net" => {
277 let mut fields = IndexMap::new();
278 fields.insert("get".into(), Ty::function(
280 vec![Ty::str()],
281 EffectSet::singleton("net"),
282 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
283 ));
284 fields.insert("post".into(), Ty::function(
285 vec![Ty::str(), Ty::str()],
286 EffectSet::singleton("net"),
287 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
288 ));
289 fields.insert("serve".into(), Ty::function(
293 vec![Ty::int(), Ty::str()],
294 EffectSet::singleton("net"),
295 Ty::Unit,
296 ));
297 fields.insert("serve_tls".into(), Ty::function(
301 vec![Ty::int(), Ty::str(), Ty::str(), Ty::str()],
302 EffectSet::singleton("net"),
303 Ty::Unit,
304 ));
305 fields.insert("serve_ws".into(), Ty::function(
309 vec![Ty::int(), Ty::str()],
310 EffectSet::singleton("net"),
311 Ty::Unit,
312 ));
313 Some(Ty::Record(fields))
314 }
315 "chat" => {
316 let mut fields = IndexMap::new();
317 fields.insert("broadcast".into(), Ty::function(
318 vec![Ty::str(), Ty::str()],
319 EffectSet::singleton("chat"),
320 Ty::Unit,
321 ));
322 fields.insert("send".into(), Ty::function(
323 vec![Ty::int(), Ty::str()],
324 EffectSet::singleton("chat"),
325 Ty::bool(),
326 ));
327 Some(Ty::Record(fields))
328 }
329 "proc" => {
330 let mut fields = IndexMap::new();
339 let mut result_rec = IndexMap::new();
340 result_rec.insert("stdout".into(), Ty::str());
341 result_rec.insert("stderr".into(), Ty::str());
342 result_rec.insert("exit_code".into(), Ty::int());
343 fields.insert("spawn".into(), Ty::function(
345 vec![Ty::str(), Ty::List(Box::new(Ty::str()))],
346 EffectSet::singleton("proc"),
347 Ty::Con("Result".into(), vec![
348 Ty::Record(result_rec),
349 Ty::str(),
350 ]),
351 ));
352 Some(Ty::Record(fields))
353 }
354 "json" => {
355 let mut fields = IndexMap::new();
356 fields.insert("stringify".into(), Ty::function(
358 vec![Ty::Var(0)], EffectSet::empty(), Ty::str(),
359 ));
360 fields.insert("parse".into(), Ty::function(
362 vec![Ty::str()], EffectSet::empty(),
363 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::str()]),
364 ));
365 fields.insert("parse_strict".into(), Ty::function(
371 vec![Ty::str(), Ty::List(Box::new(Ty::str()))], EffectSet::empty(),
372 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::str()]),
373 ));
374 Some(Ty::Record(fields))
375 }
376 "result" => {
377 let mut fields = IndexMap::new();
378 fields.insert("map".into(), Ty::function(
382 vec![
383 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::Var(1)]),
384 Ty::function(vec![Ty::Var(0)], EffectSet::open_var(3), Ty::Var(2)),
385 ],
386 EffectSet::open_var(3),
387 Ty::Con("Result".into(), vec![Ty::Var(2), Ty::Var(1)]),
388 ));
389 fields.insert("and_then".into(), Ty::function(
390 vec![
391 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::Var(1)]),
392 Ty::function(vec![Ty::Var(0)], EffectSet::open_var(4),
393 Ty::Con("Result".into(), vec![Ty::Var(2), Ty::Var(1)])),
394 ],
395 EffectSet::open_var(4),
396 Ty::Con("Result".into(), vec![Ty::Var(2), Ty::Var(1)]),
397 ));
398 fields.insert("map_err".into(), Ty::function(
399 vec![
400 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::Var(1)]),
401 Ty::function(vec![Ty::Var(1)], EffectSet::open_var(5), Ty::Var(2)),
402 ],
403 EffectSet::open_var(5),
404 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::Var(2)]),
405 ));
406 Some(Ty::Record(fields))
407 }
408 "option" => {
409 let mut fields = IndexMap::new();
410 fields.insert("map".into(), Ty::function(
412 vec![
413 Ty::Con("Option".into(), vec![Ty::Var(0)]),
414 Ty::function(vec![Ty::Var(0)], EffectSet::open_var(2), Ty::Var(1)),
415 ],
416 EffectSet::open_var(2),
417 Ty::Con("Option".into(), vec![Ty::Var(1)]),
418 ));
419 fields.insert("unwrap_or".into(), Ty::function(
420 vec![Ty::Con("Option".into(), vec![Ty::Var(0)]), Ty::Var(0)],
421 EffectSet::empty(),
422 Ty::Var(0),
423 ));
424 Some(Ty::Record(fields))
425 }
426 "tuple" => {
427 let mut fields = IndexMap::new();
433 fields.insert("fst".into(), Ty::function(
435 vec![Ty::Tuple(vec![Ty::Var(0), Ty::Var(1)])],
436 EffectSet::empty(),
437 Ty::Var(0),
438 ));
439 fields.insert("snd".into(), Ty::function(
441 vec![Ty::Tuple(vec![Ty::Var(0), Ty::Var(1)])],
442 EffectSet::empty(),
443 Ty::Var(1),
444 ));
445 fields.insert("third".into(), Ty::function(
447 vec![Ty::Tuple(vec![Ty::Var(0), Ty::Var(1), Ty::Var(2)])],
448 EffectSet::empty(),
449 Ty::Var(2),
450 ));
451 fields.insert("len".into(), Ty::function(
453 vec![Ty::Tuple(vec![Ty::Var(0), Ty::Var(1)])],
454 EffectSet::empty(),
455 Ty::int(),
456 ));
457 Some(Ty::Record(fields))
458 }
459 "map" => {
460 let mt = || Ty::Con("Map".into(), vec![Ty::Var(0), Ty::Var(1)]);
467 let pair = || Ty::Tuple(vec![Ty::Var(0), Ty::Var(1)]);
468 let mut fields = IndexMap::new();
469 fields.insert("new".into(), Ty::function(
471 vec![], EffectSet::empty(), mt()));
472 fields.insert("size".into(), Ty::function(
474 vec![mt()], EffectSet::empty(), Ty::int()));
475 fields.insert("has".into(), Ty::function(
477 vec![mt(), Ty::Var(0)], EffectSet::empty(), Ty::bool()));
478 fields.insert("get".into(), Ty::function(
480 vec![mt(), Ty::Var(0)], EffectSet::empty(),
481 Ty::Con("Option".into(), vec![Ty::Var(1)])));
482 fields.insert("set".into(), Ty::function(
484 vec![mt(), Ty::Var(0), Ty::Var(1)],
485 EffectSet::empty(), mt()));
486 fields.insert("delete".into(), Ty::function(
488 vec![mt(), Ty::Var(0)], EffectSet::empty(), mt()));
489 fields.insert("keys".into(), Ty::function(
491 vec![mt()], EffectSet::empty(),
492 Ty::List(Box::new(Ty::Var(0)))));
493 fields.insert("values".into(), Ty::function(
495 vec![mt()], EffectSet::empty(),
496 Ty::List(Box::new(Ty::Var(1)))));
497 fields.insert("entries".into(), Ty::function(
499 vec![mt()], EffectSet::empty(),
500 Ty::List(Box::new(pair()))));
501 fields.insert("from_list".into(), Ty::function(
503 vec![Ty::List(Box::new(pair()))],
504 EffectSet::empty(), mt()));
505 fields.insert("merge".into(), Ty::function(
507 vec![mt(), mt()], EffectSet::empty(), mt()));
508 fields.insert("is_empty".into(), Ty::function(
510 vec![mt()], EffectSet::empty(), Ty::bool()));
511 fields.insert("fold".into(), Ty::function(
516 vec![
517 mt(),
518 Ty::Var(2),
519 Ty::function(
520 vec![Ty::Var(2), Ty::Var(0), Ty::Var(1)],
521 EffectSet::open_var(3),
522 Ty::Var(2),
523 ),
524 ],
525 EffectSet::open_var(3),
526 Ty::Var(2),
527 ));
528 Some(Ty::Record(fields))
529 }
530 "set" => {
531 let st = || Ty::Con("Set".into(), vec![Ty::Var(0)]);
534 let mut fields = IndexMap::new();
535 fields.insert("new".into(), Ty::function(
537 vec![], EffectSet::empty(), st()));
538 fields.insert("size".into(), Ty::function(
540 vec![st()], EffectSet::empty(), Ty::int()));
541 fields.insert("has".into(), Ty::function(
543 vec![st(), Ty::Var(0)], EffectSet::empty(), Ty::bool()));
544 fields.insert("add".into(), Ty::function(
546 vec![st(), Ty::Var(0)], EffectSet::empty(), st()));
547 fields.insert("delete".into(), Ty::function(
549 vec![st(), Ty::Var(0)], EffectSet::empty(), st()));
550 fields.insert("to_list".into(), Ty::function(
552 vec![st()], EffectSet::empty(),
553 Ty::List(Box::new(Ty::Var(0)))));
554 fields.insert("from_list".into(), Ty::function(
556 vec![Ty::List(Box::new(Ty::Var(0)))],
557 EffectSet::empty(), st()));
558 fields.insert("union".into(), Ty::function(
560 vec![st(), st()], EffectSet::empty(), st()));
561 fields.insert("intersect".into(), Ty::function(
563 vec![st(), st()], EffectSet::empty(), st()));
564 fields.insert("diff".into(), Ty::function(
566 vec![st(), st()], EffectSet::empty(), st()));
567 fields.insert("is_empty".into(), Ty::function(
569 vec![st()], EffectSet::empty(), Ty::bool()));
570 fields.insert("is_subset".into(), Ty::function(
572 vec![st(), st()], EffectSet::empty(), Ty::bool()));
573 Some(Ty::Record(fields))
574 }
575 "flow" => {
576 let mut fields = IndexMap::new();
579 fields.insert("sequential".into(), Ty::function(
581 vec![
582 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), Ty::Var(1)),
583 Ty::function(vec![Ty::Var(1)], EffectSet::empty(), Ty::Var(2)),
584 ],
585 EffectSet::empty(),
586 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), Ty::Var(2)),
587 ));
588 fields.insert("branch".into(), Ty::function(
590 vec![
591 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), Ty::bool()),
592 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), Ty::Var(1)),
593 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), Ty::Var(1)),
594 ],
595 EffectSet::empty(),
596 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), Ty::Var(1)),
597 ));
598 let result_ty = Ty::Con("Result".into(), vec![Ty::Var(1), Ty::Var(2)]);
600 fields.insert("retry".into(), Ty::function(
601 vec![
602 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), result_ty.clone()),
603 Ty::int(),
604 ],
605 EffectSet::empty(),
606 Ty::function(vec![Ty::Var(0)], EffectSet::empty(), result_ty),
607 ));
608 fields.insert("parallel".into(), Ty::function(
615 vec![
616 Ty::function(vec![], EffectSet::empty(), Ty::Var(0)),
617 Ty::function(vec![], EffectSet::empty(), Ty::Var(1)),
618 ],
619 EffectSet::empty(),
620 Ty::function(vec![], EffectSet::empty(),
621 Ty::Tuple(vec![Ty::Var(0), Ty::Var(1)])),
622 ));
623 fields.insert("parallel_list".into(), Ty::function(
631 vec![
632 Ty::List(Box::new(
633 Ty::function(vec![], EffectSet::empty(), Ty::Var(0)),
634 )),
635 ],
636 EffectSet::empty(),
637 Ty::List(Box::new(Ty::Var(0))),
638 ));
639 Some(Ty::Record(fields))
640 }
641 "crypto" => {
642 let mut fields = IndexMap::new();
643 for name in &["sha256", "sha512", "md5"] {
645 fields.insert((*name).into(), Ty::function(
646 vec![Ty::bytes()],
647 EffectSet::empty(),
648 Ty::bytes(),
649 ));
650 }
651 for name in &["hmac_sha256", "hmac_sha512"] {
653 fields.insert((*name).into(), Ty::function(
654 vec![Ty::bytes(), Ty::bytes()],
655 EffectSet::empty(),
656 Ty::bytes(),
657 ));
658 }
659 fields.insert("base64_encode".into(), Ty::function(
661 vec![Ty::bytes()], EffectSet::empty(), Ty::str()));
662 fields.insert("base64_decode".into(), Ty::function(
663 vec![Ty::str()], EffectSet::empty(),
664 Ty::Con("Result".into(), vec![Ty::bytes(), Ty::str()])));
665 fields.insert("hex_encode".into(), Ty::function(
666 vec![Ty::bytes()], EffectSet::empty(), Ty::str()));
667 fields.insert("hex_decode".into(), Ty::function(
668 vec![Ty::str()], EffectSet::empty(),
669 Ty::Con("Result".into(), vec![Ty::bytes(), Ty::str()])));
670 fields.insert("constant_time_eq".into(), Ty::function(
672 vec![Ty::bytes(), Ty::bytes()], EffectSet::empty(), Ty::bool()));
673 fields.insert("random".into(), Ty::function(
679 vec![Ty::int()],
680 EffectSet::singleton("random"),
681 Ty::bytes(),
682 ));
683 Some(Ty::Record(fields))
684 }
685 "deque" => {
686 let dt = || Ty::Con("Deque".into(), vec![Ty::Var(0)]);
690 let pair = || Ty::Tuple(vec![Ty::Var(0), dt()]);
691 let mut fields = IndexMap::new();
692 fields.insert("new".into(), Ty::function(
694 vec![], EffectSet::empty(), dt()));
695 fields.insert("size".into(), Ty::function(
697 vec![dt()], EffectSet::empty(), Ty::int()));
698 fields.insert("is_empty".into(), Ty::function(
700 vec![dt()], EffectSet::empty(), Ty::bool()));
701 for n in &["push_back", "push_front"] {
703 fields.insert((*n).into(), Ty::function(
704 vec![dt(), Ty::Var(0)], EffectSet::empty(), dt()));
705 }
706 for n in &["pop_back", "pop_front"] {
708 fields.insert((*n).into(), Ty::function(
709 vec![dt()], EffectSet::empty(),
710 Ty::Con("Option".into(), vec![pair()])));
711 }
712 for n in &["peek_back", "peek_front"] {
714 fields.insert((*n).into(), Ty::function(
715 vec![dt()], EffectSet::empty(),
716 Ty::Con("Option".into(), vec![Ty::Var(0)])));
717 }
718 fields.insert("from_list".into(), Ty::function(
720 vec![Ty::List(Box::new(Ty::Var(0)))],
721 EffectSet::empty(), dt()));
722 fields.insert("to_list".into(), Ty::function(
724 vec![dt()], EffectSet::empty(),
725 Ty::List(Box::new(Ty::Var(0)))));
726 Some(Ty::Record(fields))
727 }
728 "log" => {
729 let result_str = |t: Ty| Ty::Con("Result".into(), vec![t, Ty::str()]);
734 let mut fields = IndexMap::new();
735 for level in &["debug", "info", "warn", "error"] {
736 fields.insert((*level).into(), Ty::function(
737 vec![Ty::str()],
738 EffectSet::singleton("log"),
739 Ty::Unit,
740 ));
741 }
742 fields.insert("set_level".into(), Ty::function(
744 vec![Ty::str()],
745 EffectSet::singleton("io"),
746 result_str(Ty::Unit)));
747 fields.insert("set_format".into(), Ty::function(
749 vec![Ty::str()],
750 EffectSet::singleton("io"),
751 result_str(Ty::Unit)));
752 fields.insert("set_sink".into(), Ty::function(
754 vec![Ty::str()],
755 EffectSet {
756 concrete: ["io".to_string(), "fs_write".to_string()].into_iter().collect(),
757 var: None,
758 },
759 result_str(Ty::Unit)));
760 Some(Ty::Record(fields))
761 }
762 "datetime" => {
763 let inst = || Ty::Con("Instant".into(), vec![]);
776 let dur = || Ty::Con("Duration".into(), vec![]);
777 let tz = || Ty::Con("Tz".into(), vec![]);
778 let result_str = |t: Ty| Ty::Con("Result".into(), vec![t, Ty::str()]);
779 let dt_t = || {
780 let mut fs = IndexMap::new();
781 fs.insert("year".into(), Ty::int());
782 fs.insert("month".into(), Ty::int());
783 fs.insert("day".into(), Ty::int());
784 fs.insert("hour".into(), Ty::int());
785 fs.insert("minute".into(), Ty::int());
786 fs.insert("second".into(), Ty::int());
787 fs.insert("nano".into(), Ty::int());
788 fs.insert("tz_offset_minutes".into(), Ty::int());
789 Ty::Record(fs)
790 };
791 let mut fields = IndexMap::new();
792 fields.insert("now".into(), Ty::function(
793 vec![], EffectSet::singleton("time"), inst()));
794 fields.insert("parse_iso".into(), Ty::function(
795 vec![Ty::str()], EffectSet::empty(), result_str(inst())));
796 fields.insert("format_iso".into(), Ty::function(
797 vec![inst()], EffectSet::empty(), Ty::str()));
798 fields.insert("parse".into(), Ty::function(
799 vec![Ty::str(), Ty::str()], EffectSet::empty(), result_str(inst())));
800 fields.insert("format".into(), Ty::function(
801 vec![inst(), Ty::str()], EffectSet::empty(), Ty::str()));
802 fields.insert("to_components".into(), Ty::function(
803 vec![inst(), tz()], EffectSet::empty(), result_str(dt_t())));
804 fields.insert("from_components".into(), Ty::function(
805 vec![dt_t()], EffectSet::empty(), result_str(inst())));
806 fields.insert("add".into(), Ty::function(
807 vec![inst(), dur()], EffectSet::empty(), inst()));
808 fields.insert("diff".into(), Ty::function(
809 vec![inst(), inst()], EffectSet::empty(), dur()));
810 fields.insert("duration_seconds".into(), Ty::function(
811 vec![Ty::float()], EffectSet::empty(), dur()));
812 fields.insert("duration_minutes".into(), Ty::function(
813 vec![Ty::int()], EffectSet::empty(), dur()));
814 fields.insert("duration_days".into(), Ty::function(
815 vec![Ty::int()], EffectSet::empty(), dur()));
816 Some(Ty::Record(fields))
817 }
818 "process" => {
819 let ph = || Ty::Con("ProcessHandle".into(), vec![]);
823 let result_str = |t: Ty| Ty::Con("Result".into(), vec![t, Ty::str()]);
824 let opts_t = || {
825 let mut fs = IndexMap::new();
826 fs.insert("cwd".into(),
827 Ty::Con("Option".into(), vec![Ty::str()]));
828 fs.insert("env".into(),
829 Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
830 fs.insert("stdin".into(),
831 Ty::Con("Option".into(), vec![Ty::bytes()]));
832 Ty::Record(fs)
833 };
834 let exit_t = || {
835 let mut fs = IndexMap::new();
836 fs.insert("code".into(), Ty::int());
837 fs.insert("signaled".into(), Ty::bool());
838 Ty::Record(fs)
839 };
840 let output_t = || {
841 let mut fs = IndexMap::new();
842 fs.insert("stdout".into(), Ty::str());
843 fs.insert("stderr".into(), Ty::str());
844 fs.insert("exit_code".into(), Ty::int());
845 Ty::Record(fs)
846 };
847 let mut fields = IndexMap::new();
848 fields.insert("spawn".into(), Ty::function(
850 vec![Ty::str(), Ty::List(Box::new(Ty::str())), opts_t()],
851 EffectSet::singleton("proc"),
852 result_str(ph())));
853 for n in &["read_stdout_line", "read_stderr_line"] {
855 fields.insert((*n).into(), Ty::function(
856 vec![ph()], EffectSet::singleton("proc"),
857 Ty::Con("Option".into(), vec![Ty::str()])));
858 }
859 fields.insert("wait".into(), Ty::function(
861 vec![ph()], EffectSet::singleton("proc"), exit_t()));
862 fields.insert("kill".into(), Ty::function(
864 vec![ph(), Ty::str()],
865 EffectSet::singleton("proc"),
866 result_str(Ty::Unit)));
867 fields.insert("run".into(), Ty::function(
872 vec![Ty::str(), Ty::List(Box::new(Ty::str()))],
873 EffectSet::singleton("proc"),
874 result_str(output_t())));
875 Some(Ty::Record(fields))
876 }
877 "fs" => {
878 let stat_t = || {
887 let mut fs = IndexMap::new();
888 fs.insert("size".into(), Ty::int());
889 fs.insert("mtime".into(), Ty::int());
890 fs.insert("is_dir".into(), Ty::bool());
891 fs.insert("is_file".into(), Ty::bool());
892 Ty::Record(fs)
893 };
894 let result_str = |t: Ty| Ty::Con("Result".into(), vec![t, Ty::str()]);
895 let mut fields = IndexMap::new();
896 fields.insert("exists".into(), Ty::function(
898 vec![Ty::str()], EffectSet::singleton("fs_walk"), Ty::bool()));
899 fields.insert("is_file".into(), Ty::function(
900 vec![Ty::str()], EffectSet::singleton("fs_walk"), Ty::bool()));
901 fields.insert("is_dir".into(), Ty::function(
902 vec![Ty::str()], EffectSet::singleton("fs_walk"), Ty::bool()));
903 fields.insert("stat".into(), Ty::function(
904 vec![Ty::str()], EffectSet::singleton("fs_walk"),
905 result_str(stat_t())));
906 fields.insert("list_dir".into(), Ty::function(
907 vec![Ty::str()], EffectSet::singleton("fs_walk"),
908 result_str(Ty::List(Box::new(Ty::str())))));
909 fields.insert("walk".into(), Ty::function(
910 vec![Ty::str()], EffectSet::singleton("fs_walk"),
911 result_str(Ty::List(Box::new(Ty::str())))));
912 fields.insert("glob".into(), Ty::function(
913 vec![Ty::str()], EffectSet::singleton("fs_walk"),
914 result_str(Ty::List(Box::new(Ty::str())))));
915 fields.insert("mkdir_p".into(), Ty::function(
917 vec![Ty::str()], EffectSet::singleton("fs_write"),
918 result_str(Ty::Unit)));
919 fields.insert("remove".into(), Ty::function(
920 vec![Ty::str()], EffectSet::singleton("fs_write"),
921 result_str(Ty::Unit)));
922 fields.insert("copy".into(), Ty::function(
923 vec![Ty::str(), Ty::str()],
924 EffectSet {
925 concrete: ["fs_walk".to_string(), "fs_write".to_string()].into_iter().collect(),
926 var: None,
927 },
928 result_str(Ty::Unit)));
929 Some(Ty::Record(fields))
930 }
931 "kv" => {
932 let kv_t = || Ty::Con("Kv".into(), vec![]);
935 let mut fields = IndexMap::new();
936 fields.insert("open".into(), Ty::function(
938 vec![Ty::str()],
939 EffectSet {
940 concrete: ["kv".to_string(), "fs_write".to_string()].into_iter().collect(),
941 var: None,
942 },
943 Ty::Con("Result".into(), vec![kv_t(), Ty::str()])));
944 fields.insert("close".into(), Ty::function(
946 vec![kv_t()],
947 EffectSet::singleton("kv"),
948 Ty::Unit));
949 fields.insert("get".into(), Ty::function(
951 vec![kv_t(), Ty::str()],
952 EffectSet::singleton("kv"),
953 Ty::Con("Option".into(), vec![Ty::bytes()])));
954 fields.insert("put".into(), Ty::function(
956 vec![kv_t(), Ty::str(), Ty::bytes()],
957 EffectSet::singleton("kv"),
958 Ty::Con("Result".into(), vec![Ty::Unit, Ty::str()])));
959 fields.insert("delete".into(), Ty::function(
961 vec![kv_t(), Ty::str()],
962 EffectSet::singleton("kv"),
963 Ty::Con("Result".into(), vec![Ty::Unit, Ty::str()])));
964 fields.insert("contains".into(), Ty::function(
966 vec![kv_t(), Ty::str()],
967 EffectSet::singleton("kv"),
968 Ty::bool()));
969 fields.insert("list_prefix".into(), Ty::function(
971 vec![kv_t(), Ty::str()],
972 EffectSet::singleton("kv"),
973 Ty::List(Box::new(Ty::str()))));
974 Some(Ty::Record(fields))
975 }
976 "sql" => {
977 let db_t = || Ty::Con("Db".into(), vec![]);
993 let mut fields = IndexMap::new();
994 fields.insert("open".into(), Ty::function(
999 vec![Ty::str()],
1000 EffectSet {
1001 concrete: ["sql".to_string(), "fs_write".to_string()].into_iter().collect(),
1002 var: None,
1003 },
1004 Ty::Con("Result".into(), vec![db_t(), Ty::str()])));
1005 fields.insert("close".into(), Ty::function(
1007 vec![db_t()],
1008 EffectSet::singleton("sql"),
1009 Ty::Unit));
1010 fields.insert("exec".into(), Ty::function(
1014 vec![db_t(), Ty::str(), Ty::List(Box::new(Ty::str()))],
1015 EffectSet::singleton("sql"),
1016 Ty::Con("Result".into(), vec![Ty::int(), Ty::str()])));
1017 fields.insert("query".into(), Ty::function(
1023 vec![db_t(), Ty::str(), Ty::List(Box::new(Ty::str()))],
1024 EffectSet::singleton("sql"),
1025 Ty::Con("Result".into(), vec![
1026 Ty::List(Box::new(Ty::Var(0))),
1027 Ty::str(),
1028 ])));
1029 Some(Ty::Record(fields))
1030 }
1031 "regex" => {
1032 let regex_t = || Ty::Con("Regex".into(), vec![]);
1037 let match_t = || {
1038 let mut fs = IndexMap::new();
1039 fs.insert("text".into(), Ty::str());
1040 fs.insert("start".into(), Ty::int());
1041 fs.insert("end".into(), Ty::int());
1042 fs.insert("groups".into(), Ty::List(Box::new(Ty::str())));
1043 Ty::Record(fs)
1044 };
1045 let mut fields = IndexMap::new();
1046 fields.insert("compile".into(), Ty::function(
1048 vec![Ty::str()], EffectSet::empty(),
1049 Ty::Con("Result".into(), vec![regex_t(), Ty::str()])));
1050 fields.insert("is_match".into(), Ty::function(
1052 vec![regex_t(), Ty::str()], EffectSet::empty(), Ty::bool()));
1053 fields.insert("find".into(), Ty::function(
1055 vec![regex_t(), Ty::str()], EffectSet::empty(),
1056 Ty::Con("Option".into(), vec![match_t()])));
1057 fields.insert("find_all".into(), Ty::function(
1059 vec![regex_t(), Ty::str()], EffectSet::empty(),
1060 Ty::List(Box::new(match_t()))));
1061 fields.insert("replace".into(), Ty::function(
1063 vec![regex_t(), Ty::str(), Ty::str()], EffectSet::empty(), Ty::str()));
1064 fields.insert("replace_all".into(), Ty::function(
1066 vec![regex_t(), Ty::str(), Ty::str()], EffectSet::empty(), Ty::str()));
1067 fields.insert("split".into(), Ty::function(
1069 vec![regex_t(), Ty::str()], EffectSet::empty(),
1070 Ty::List(Box::new(Ty::str()))));
1071 Some(Ty::Record(fields))
1072 }
1073 "http" => {
1074 let req_t = || Ty::Con("HttpRequest".into(), vec![]);
1081 let resp_t = || Ty::Con("HttpResponse".into(), vec![]);
1082 let err_t = || Ty::Con("HttpError".into(), vec![]);
1083 let result_he = |t: Ty| Ty::Con("Result".into(), vec![t, err_t()]);
1084 let str_str_map = || Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]);
1085 let mut fields = IndexMap::new();
1086 fields.insert("send".into(), Ty::function(
1089 vec![req_t()],
1090 EffectSet::singleton("net"),
1091 result_he(resp_t()),
1092 ));
1093 fields.insert("get".into(), Ty::function(
1095 vec![Ty::str()],
1096 EffectSet::singleton("net"),
1097 result_he(resp_t()),
1098 ));
1099 fields.insert("post".into(), Ty::function(
1101 vec![Ty::str(), Ty::bytes(), Ty::str()],
1102 EffectSet::singleton("net"),
1103 result_he(resp_t()),
1104 ));
1105 fields.insert("with_header".into(), Ty::function(
1108 vec![req_t(), Ty::str(), Ty::str()],
1109 EffectSet::empty(),
1110 req_t(),
1111 ));
1112 fields.insert("with_auth".into(), Ty::function(
1116 vec![req_t(), Ty::str(), Ty::str()],
1117 EffectSet::empty(),
1118 req_t(),
1119 ));
1120 fields.insert("with_query".into(), Ty::function(
1124 vec![req_t(), str_str_map()],
1125 EffectSet::empty(),
1126 req_t(),
1127 ));
1128 fields.insert("with_timeout_ms".into(), Ty::function(
1130 vec![req_t(), Ty::int()],
1131 EffectSet::empty(),
1132 req_t(),
1133 ));
1134 fields.insert("json_body".into(), Ty::function(
1138 vec![resp_t()],
1139 EffectSet::empty(),
1140 result_he(Ty::Var(0)),
1141 ));
1142 fields.insert("text_body".into(), Ty::function(
1144 vec![resp_t()],
1145 EffectSet::empty(),
1146 result_he(Ty::str()),
1147 ));
1148 Some(Ty::Record(fields))
1149 }
1150 "yaml" => {
1151 let mut fields = IndexMap::new();
1156 fields.insert("parse".into(), Ty::function(
1157 vec![Ty::str()], EffectSet::empty(),
1158 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::str()]),
1159 ));
1160 fields.insert("parse_strict".into(), Ty::function(
1163 vec![Ty::str(), Ty::List(Box::new(Ty::str()))], EffectSet::empty(),
1164 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::str()]),
1165 ));
1166 fields.insert("stringify".into(), Ty::function(
1167 vec![Ty::Var(0)], EffectSet::empty(),
1168 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
1169 ));
1170 Some(Ty::Record(fields))
1171 }
1172 "dotenv" => {
1173 let mut fields = IndexMap::new();
1178 fields.insert("parse".into(), Ty::function(
1179 vec![Ty::str()], EffectSet::empty(),
1180 Ty::Con("Result".into(), vec![
1181 Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]),
1182 Ty::str(),
1183 ]),
1184 ));
1185 Some(Ty::Record(fields))
1186 }
1187 "csv" => {
1188 let row_ty = Ty::List(Box::new(Ty::str()));
1193 let rows_ty = Ty::List(Box::new(row_ty.clone()));
1194 let mut fields = IndexMap::new();
1195 fields.insert("parse".into(), Ty::function(
1196 vec![Ty::str()], EffectSet::empty(),
1197 Ty::Con("Result".into(), vec![rows_ty.clone(), Ty::str()]),
1198 ));
1199 fields.insert("stringify".into(), Ty::function(
1200 vec![rows_ty], EffectSet::empty(),
1201 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
1202 ));
1203 Some(Ty::Record(fields))
1204 }
1205 "test" => {
1206 let mut fields = IndexMap::new();
1213 let unit_result = || Ty::Con("Result".into(), vec![Ty::Unit, Ty::str()]);
1216 fields.insert("assert_eq".into(), Ty::function(
1217 vec![Ty::Var(0), Ty::Var(0)], EffectSet::empty(), unit_result(),
1218 ));
1219 fields.insert("assert_ne".into(), Ty::function(
1220 vec![Ty::Var(0), Ty::Var(0)], EffectSet::empty(), unit_result(),
1221 ));
1222 fields.insert("assert_true".into(), Ty::function(
1223 vec![Ty::bool()], EffectSet::empty(), unit_result(),
1224 ));
1225 fields.insert("assert_false".into(), Ty::function(
1226 vec![Ty::bool()], EffectSet::empty(), unit_result(),
1227 ));
1228 Some(Ty::Record(fields))
1229 }
1230 "toml" => {
1231 let mut fields = IndexMap::new();
1249 fields.insert("parse".into(), Ty::function(
1251 vec![Ty::str()], EffectSet::empty(),
1252 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::str()]),
1253 ));
1254 fields.insert("parse_strict".into(), Ty::function(
1262 vec![Ty::str(), Ty::List(Box::new(Ty::str()))], EffectSet::empty(),
1263 Ty::Con("Result".into(), vec![Ty::Var(0), Ty::str()]),
1264 ));
1265 fields.insert("stringify".into(), Ty::function(
1271 vec![Ty::Var(0)], EffectSet::empty(),
1272 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
1273 ));
1274 Some(Ty::Record(fields))
1275 }
1276 "agent" => {
1286 let mut fields = IndexMap::new();
1287 fields.insert("local_complete".into(), Ty::function(
1289 vec![Ty::str()],
1290 EffectSet::singleton("llm_local"),
1291 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
1292 ));
1293 fields.insert("cloud_complete".into(), Ty::function(
1295 vec![Ty::str()],
1296 EffectSet::singleton("llm_cloud"),
1297 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
1298 ));
1299 fields.insert("send_a2a".into(), Ty::function(
1302 vec![Ty::str(), Ty::str()],
1303 EffectSet::singleton("a2a"),
1304 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
1305 ));
1306 fields.insert("call_mcp".into(), Ty::function(
1309 vec![Ty::str(), Ty::str(), Ty::str()],
1310 EffectSet::singleton("mcp"),
1311 Ty::Con("Result".into(), vec![Ty::str(), Ty::str()]),
1312 ));
1313 Some(Ty::Record(fields))
1314 }
1315 _ => None,
1316 }
1317}
1318
1319pub fn module_for_import(reference: &str) -> Option<&'static str> {
1321 let suffix = reference.strip_prefix("std.")?;
1322 Some(match suffix {
1323 "io" => "io",
1324 "str" => "str",
1325 "int" => "int",
1326 "float" => "float",
1327 "list" => "list",
1328 "result" => "result",
1329 "option" => "option",
1330 "json" => "json",
1331 "flow" => "flow",
1332 "tuple" => "tuple",
1333 "time" => "time",
1334 "rand" => "rand",
1335 "bytes" => "bytes",
1336 "net" => "net",
1337 "chat" => "chat",
1338 "math" => "math",
1339 "map" => "map",
1340 "set" => "set",
1341 "proc" => "proc",
1342 "crypto" => "crypto",
1343 "regex" => "regex",
1344 "deque" => "deque",
1345 "kv" => "kv",
1346 "sql" => "sql",
1347 "fs" => "fs",
1348 "process" => "process",
1349 "datetime" => "datetime",
1350 "log" => "log",
1351 "http" => "http",
1352 "toml" => "toml",
1353 "yaml" => "yaml",
1354 "dotenv" => "dotenv",
1355 "csv" => "csv",
1356 "test" => "test",
1357 "agent" => "agent",
1358 _ => return None,
1359 })
1360}