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: "bytes",
92 runtime_fn: "to_bytes",
93 arities: &[1],
94 shape: BuiltinShape::Fallible,
95 hint: "bytes(thing)",
96 },
97 BuiltinFn {
98 name: "dec",
99 runtime_fn: "to_decimal",
100 arities: &[1],
101 shape: BuiltinShape::Fallible,
102 hint: "dec(thing)",
103 },
104 BuiltinFn {
105 name: "range",
106 runtime_fn: "range",
107 arities: &[1, 2],
108 shape: BuiltinShape::Range,
109 hint: "range(n) or range(a, b)",
110 },
111 BuiltinFn {
112 name: "gib",
113 runtime_fn: "gib",
114 arities: &[0, 1],
115 shape: BuiltinShape::Prompt,
116 hint: "gib() or gib(\"prompt\")",
117 },
118];
119
120pub fn builtin(name: &str) -> Option<&'static BuiltinFn> {
122 BUILTINS.iter().find(|b| b.name == name)
123}
124
125pub fn is_builtin(name: &str) -> bool {
127 builtin(name).is_some()
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn known_names_resolve_and_unknown_do_not() {
136 assert!(is_builtin("len"));
137 assert!(is_builtin("range"));
138 assert!(!is_builtin("nope"));
139 assert!(builtin("str").is_some());
140 }
141
142 #[test]
143 fn arity_phrase_matches_diagnostic_wording() {
144 assert_eq!(builtin("len").unwrap().arity_phrase(), "1 argument");
145 assert_eq!(builtin("range").unwrap().arity_phrase(), "1 or 2 arguments");
146 }
147
148 #[test]
149 fn accepts_reflects_declared_arities() {
150 let range = builtin("range").unwrap();
151 assert!(range.accepts(1));
152 assert!(range.accepts(2));
153 assert!(!range.accepts(3));
154 assert!(!range.accepts(0));
155
156 let len = builtin("len").unwrap();
157 assert!(len.accepts(1));
158 assert!(!len.accepts(2));
159 }
160}