doge_compiler/
builtins.rs1#[derive(Clone, Copy)]
11pub enum BuiltinShape {
12 Fallible,
15 Infallible,
18 Range,
21 Prompt,
24}
25
26pub struct BuiltinFn {
30 pub name: &'static str,
31 pub runtime_fn: &'static str,
32 pub arities: &'static [usize],
33 pub shape: BuiltinShape,
34 pub hint: &'static str,
35}
36
37impl BuiltinFn {
38 pub fn accepts(&self, argc: usize) -> bool {
40 self.arities.contains(&argc)
41 }
42
43 pub fn arity_phrase(&self) -> String {
46 let counts = self
47 .arities
48 .iter()
49 .map(|n| n.to_string())
50 .collect::<Vec<_>>()
51 .join(" or ");
52 let noun = if self.arities == [1] {
53 "argument"
54 } else {
55 "arguments"
56 };
57 format!("{counts} {noun}")
58 }
59}
60
61pub const BUILTINS: &[BuiltinFn] = &[
62 BuiltinFn {
63 name: "len",
64 runtime_fn: "len",
65 arities: &[1],
66 shape: BuiltinShape::Fallible,
67 hint: "len(thing)",
68 },
69 BuiltinFn {
70 name: "str",
71 runtime_fn: "to_str",
72 arities: &[1],
73 shape: BuiltinShape::Infallible,
74 hint: "str(thing)",
75 },
76 BuiltinFn {
77 name: "int",
78 runtime_fn: "to_int",
79 arities: &[1],
80 shape: BuiltinShape::Fallible,
81 hint: "int(thing)",
82 },
83 BuiltinFn {
84 name: "float",
85 runtime_fn: "to_float",
86 arities: &[1],
87 shape: BuiltinShape::Fallible,
88 hint: "float(thing)",
89 },
90 BuiltinFn {
91 name: "range",
92 runtime_fn: "range",
93 arities: &[1, 2],
94 shape: BuiltinShape::Range,
95 hint: "range(n) or range(a, b)",
96 },
97 BuiltinFn {
98 name: "gib",
99 runtime_fn: "gib",
100 arities: &[0, 1],
101 shape: BuiltinShape::Prompt,
102 hint: "gib() or gib(\"prompt\")",
103 },
104];
105
106pub fn builtin(name: &str) -> Option<&'static BuiltinFn> {
108 BUILTINS.iter().find(|b| b.name == name)
109}
110
111pub fn is_builtin(name: &str) -> bool {
113 builtin(name).is_some()
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn known_names_resolve_and_unknown_do_not() {
122 assert!(is_builtin("len"));
123 assert!(is_builtin("range"));
124 assert!(!is_builtin("nope"));
125 assert!(builtin("str").is_some());
126 }
127
128 #[test]
129 fn arity_phrase_matches_diagnostic_wording() {
130 assert_eq!(builtin("len").unwrap().arity_phrase(), "1 argument");
131 assert_eq!(builtin("range").unwrap().arity_phrase(), "1 or 2 arguments");
132 }
133
134 #[test]
135 fn accepts_reflects_declared_arities() {
136 let range = builtin("range").unwrap();
137 assert!(range.accepts(1));
138 assert!(range.accepts(2));
139 assert!(!range.accepts(3));
140 assert!(!range.accepts(0));
141
142 let len = builtin("len").unwrap();
143 assert!(len.accepts(1));
144 assert!(!len.accepts(2));
145 }
146}