1mod failure;
2mod lists;
3mod numbers;
4mod program;
5mod strings;
6mod text;
7
8pub use failure::FailureDescription;
9
10use std::cmp::Ordering;
11
12use super::arguments::Arguments;
13use super::{CompileTimeHost, Value};
14use crate::core::{Builtin, Declaration};
15use crate::diagnostic::Diagnostic;
16use crate::reader::{Form, FormKind, Number, NumberValue};
17use crate::source::Span;
18use lists::ListOperations;
19use numbers::NumberOperations;
20use program::ProgramOperations;
21use strings::StringOperations;
22use text::TextOperations;
23
24pub struct BuiltinCall {
25 builtin: Builtin,
26 arguments: Arguments,
27 call_site: Span,
28}
29
30impl BuiltinCall {
31 const IMPLEMENTATIONS: [(Builtin, Implementation); 63] = [
32 (Builtin::First, |operations, _| operations.lists.first()),
33 (Builtin::Rest, |operations, _| operations.lists.rest()),
34 (Builtin::List, |operations, _| operations.lists.list()),
35 (Builtin::Prepend, |operations, _| operations.lists.prepend()),
36 (Builtin::Concat, |operations, _| operations.lists.concat()),
37 (Builtin::Len, |operations, _| operations.lists.len()),
38 (Builtin::IsEmpty, |operations, _| {
39 operations.lists.is_empty()
40 }),
41 (Builtin::Nth, |operations, _| operations.lists.nth()),
42 (Builtin::Take, |operations, _| operations.lists.take()),
43 (Builtin::Drop, |operations, _| operations.lists.drop()),
44 (Builtin::IsSymbol, |operations, _| {
45 operations
46 .text
47 .is_kind(|kind| matches!(kind, FormKind::Symbol(_)))
48 }),
49 (Builtin::IsKeyword, |operations, _| {
50 operations.text.is_keyword()
51 }),
52 (Builtin::IsList, |operations, _| operations.text.is_list()),
53 (Builtin::IsString, |operations, _| {
54 operations
55 .text
56 .is_kind(|kind| matches!(kind, FormKind::String(_)))
57 }),
58 (Builtin::IsNumber, |operations, _| {
59 operations
60 .text
61 .is_kind(|kind| matches!(kind, FormKind::Number(_)))
62 }),
63 (Builtin::SymbolName, |operations, _| {
64 operations.text.symbol_name()
65 }),
66 (Builtin::KeywordName, |operations, _| {
67 operations.text.keyword_name()
68 }),
69 (Builtin::KeywordField, |operations, _| {
70 operations.text.keyword_field()
71 }),
72 (Builtin::FieldKeyword, |operations, _| {
73 operations.text.field_keyword()
74 }),
75 (Builtin::KeywordTrimEnd, |operations, _| {
76 operations.text.keyword_trim_end()
77 }),
78 (Builtin::MakeSymbol, |operations, _| {
79 operations.text.make_symbol()
80 }),
81 (Builtin::MakeString, |operations, _| {
82 operations.text.make_string()
83 }),
84 (Builtin::SameBinding, |operations, host| {
85 operations.text.same_binding(host)
86 }),
87 (Builtin::IsPatternHead, |operations, host| {
88 operations.text.is_pattern_head(host)
89 }),
90 (Builtin::DefinitionSymbol, |operations, host| {
91 operations.text.definition_symbol(host)
92 }),
93 (Builtin::TypeDefinitionSymbol, |operations, host| {
94 operations.text.type_definition_symbol(host)
95 }),
96 (Builtin::DefinitionCall, |operations, host| {
97 operations.text.definition_call(host)
98 }),
99 (Builtin::TypeDefinitionCall, |operations, host| {
100 operations.text.type_definition_call(host)
101 }),
102 (Builtin::ExpandCall, |operations, host| {
103 operations.text.expand_call(host)
104 }),
105 (Builtin::ClosestName, |operations, _| {
106 operations.text.closest_name()
107 }),
108 (Builtin::SortedNames, |operations, _| {
109 operations.text.sorted_names()
110 }),
111 (Builtin::Fail, |operations, _| operations.text.fail()),
112 (Builtin::NumberAdd, |operations, _| operations.numbers.add()),
113 (Builtin::NumberSub, |operations, _| {
114 operations.numbers.subtract()
115 }),
116 (Builtin::NumberLt, |operations, _| {
117 operations.numbers.compare(Ordering::is_lt)
118 }),
119 (Builtin::NumberLe, |operations, _| {
120 operations.numbers.compare(Ordering::is_le)
121 }),
122 (Builtin::NumberGt, |operations, _| {
123 operations.numbers.compare(Ordering::is_gt)
124 }),
125 (Builtin::NumberGe, |operations, _| {
126 operations.numbers.compare(Ordering::is_ge)
127 }),
128 (Builtin::ValueEq, |operations, _| operations.text.value_eq()),
129 (Builtin::BoolNot, |operations, _| operations.text.not()),
130 (Builtin::EscapeString, |operations, _| {
131 operations.text.escape_string()
132 }),
133 (Builtin::EscapeChar, |operations, _| {
134 operations.text.escape_char()
135 }),
136 (Builtin::EscapeFormat, |operations, _| {
137 operations.text.escape_format()
138 }),
139 (Builtin::StringStripSuffix, |operations, _| {
140 operations.text.string_strip_suffix()
141 }),
142 (Builtin::StringStripPrefix, |operations, _| {
143 operations.text.string_strip_prefix()
144 }),
145 (Builtin::StringLines, |operations, _| {
146 operations.strings.lines()
147 }),
148 (Builtin::StringTrimStart, |operations, _| {
149 operations.strings.trim_start()
150 }),
151 (Builtin::StringLength, |operations, _| {
152 operations.strings.length()
153 }),
154 (Builtin::StringDrop, |operations, _| {
155 operations.strings.drop()
156 }),
157 (Builtin::StringLowercase, |operations, _| {
158 operations.strings.lowercase()
159 }),
160 (Builtin::StringContains, |operations, _| {
161 operations.strings.contains()
162 }),
163 (Builtin::AddModuleNote, |operations, host| {
164 operations.text.add_module_note(host)
165 }),
166 (Builtin::ModuleNotes, |operations, host| {
167 operations.text.module_notes(host)
168 }),
169 (Builtin::DeclareDefinition, |operations, host| {
170 operations.text.declare_definition(host, Declaration::Value)
171 }),
172 (Builtin::DeclareTypeDefinition, |operations, host| {
173 operations.text.declare_definition(host, Declaration::Type)
174 }),
175 (Builtin::DeclareMacroDefinition, |operations, host| {
176 operations.text.declare_definition(host, Declaration::Macro)
177 }),
178 (Builtin::FormLocation, |operations, host| {
179 operations.program.form_location(host)
180 }),
181 (Builtin::ProgramModules, |operations, host| {
182 operations.program.program_modules(host)
183 }),
184 (Builtin::ModuleExports, |operations, host| {
185 operations.program.module_exports(host)
186 }),
187 (Builtin::ModuleDefinitions, |operations, host| {
188 operations.program.module_definitions(host)
189 }),
190 (Builtin::CurrentModule, |operations, host| {
191 operations.program.current_module(host)
192 }),
193 (Builtin::ModuleSymbol, |operations, host| {
194 operations.program.module_symbol(host)
195 }),
196 (Builtin::ProjectFileName, |operations, _| {
197 operations.program.project_file_name()
198 }),
199 ];
200
201 pub fn new(builtin: Builtin, values: Vec<Value>, span: Span, call_site: Span) -> Self {
202 Self {
203 builtin,
204 arguments: Arguments::new(builtin.name(), values, span),
205 call_site,
206 }
207 }
208
209 pub fn run(self, host: &mut dyn CompileTimeHost) -> Result<Value, Diagnostic> {
210 let operations = Operations::new(&self.arguments, self.call_site);
211 Self::implementation(self.builtin)(&operations, host)
212 }
213
214 fn implementation(builtin: Builtin) -> Implementation {
215 let (_, implementation) = Self::IMPLEMENTATIONS[builtin.position()];
216 implementation
217 }
218}
219
220type Implementation =
221 for<'a> fn(&Operations<'a>, &mut dyn CompileTimeHost) -> Result<Value, Diagnostic>;
222
223struct Operations<'a> {
224 lists: ListOperations<'a>,
225 numbers: NumberOperations<'a>,
226 program: ProgramOperations<'a>,
227 strings: StringOperations<'a>,
228 text: TextOperations<'a>,
229}
230
231impl<'a> Operations<'a> {
232 fn new(arguments: &'a Arguments, call_site: Span) -> Self {
233 Self {
234 lists: ListOperations::new(arguments, call_site),
235 numbers: NumberOperations::new(arguments, call_site),
236 program: ProgramOperations::new(arguments, call_site),
237 strings: StringOperations::new(arguments, call_site),
238 text: TextOperations::new(arguments, call_site),
239 }
240 }
241}
242
243struct Forms;
244
245impl Forms {
246 fn list(items: Vec<Form>, span: Span) -> Value {
247 Value::Form(Form::new(FormKind::List(items), span))
248 }
249
250 fn count(count: usize, span: Span) -> Value {
251 let number = Number::new(count.to_string(), NumberValue::Integer(count as i128));
252 Value::Form(Form::new(FormKind::Number(number), span))
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::BuiltinCall;
259 use crate::core::Builtin;
260
261 #[test]
262 fn each_builtin_finds_its_own_implementation_row() {
263 for builtin in Builtin::all() {
264 let (implemented, _) = BuiltinCall::IMPLEMENTATIONS[builtin.position()];
265 assert_eq!(implemented, builtin);
266 }
267 }
268}