Skip to main content

knave_expand/interpret/builtins/
mod.rs

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}