1use crate::{
2 Visibility,
3 context::Context,
4 function::{Function, FunctionBody, FunctionParameter, FunctionQuery, FunctionSignature},
5 meta::Meta,
6 registry::Registry,
7 types::{
8 TypeQuery,
9 enum_type::{EnumVariant, RuntimeEnumBuilder},
10 struct_type::{RuntimeStructBuilder, StructField},
11 },
12};
13use std::{
14 collections::HashMap,
15 error::Error,
16 path::{Path, PathBuf},
17 sync::Arc,
18};
19
20pub type ScriptHandle<'a, SE> = Arc<Script<'a, SE>>;
21pub type Script<'a, SE> = Vec<ScriptOperation<'a, SE>>;
22
23pub trait ScriptExpression: Send + Sync {
24 fn evaluate(&self, context: &mut Context, registry: &Registry);
25}
26
27impl ScriptExpression for () {
28 fn evaluate(&self, _: &mut Context, _: &Registry) {}
29}
30
31#[allow(clippy::type_complexity)]
32pub struct InlineExpression(Arc<dyn Fn(&mut Context, &Registry) + Send + Sync>);
33
34impl InlineExpression {
35 pub fn copied<T: Copy + Send + Sync + 'static>(value: T) -> Self {
36 Self(Arc::new(move |context, _| {
37 context.stack().push(value);
38 }))
39 }
40
41 pub fn cloned<T: Clone + Send + Sync + 'static>(value: T) -> Self {
42 Self(Arc::new(move |context, _| {
43 context.stack().push(value.clone());
44 }))
45 }
46
47 pub fn closure<F: Fn(&mut Context, &Registry) + Send + Sync + 'static>(f: F) -> Self {
48 Self(Arc::new(f))
49 }
50}
51
52impl ScriptExpression for InlineExpression {
53 fn evaluate(&self, context: &mut Context, registry: &Registry) {
54 (self.0)(context, registry);
55 }
56}
57
58#[derive(Debug)]
59pub enum ScriptOperation<'a, SE: ScriptExpression> {
60 None,
61 Expression {
62 expression: SE,
63 },
64 DefineRegister {
65 query: TypeQuery<'a>,
66 },
67 DropRegister {
68 index: usize,
69 },
70 PushFromRegister {
71 index: usize,
72 },
73 PopToRegister {
74 index: usize,
75 },
76 MoveRegister {
77 from: usize,
78 to: usize,
79 },
80 CallFunction {
81 query: FunctionQuery<'a>,
82 },
83 BranchScope {
84 scope_success: ScriptHandle<'a, SE>,
85 scope_failure: Option<ScriptHandle<'a, SE>>,
86 },
87 LoopScope {
88 scope: ScriptHandle<'a, SE>,
89 },
90 PushScope {
91 scope: ScriptHandle<'a, SE>,
92 },
93 PopScope,
94 ContinueScopeConditionally,
95}
96
97impl<SE: ScriptExpression> ScriptOperation<'_, SE> {
98 pub fn label(&self) -> &str {
99 match self {
100 Self::None => "None",
101 Self::Expression { .. } => "Expression",
102 Self::DefineRegister { .. } => "DefineRegister",
103 Self::DropRegister { .. } => "DropRegister",
104 Self::PushFromRegister { .. } => "PushFromRegister",
105 Self::PopToRegister { .. } => "PopToRegister",
106 Self::MoveRegister { .. } => "MoveRegister",
107 Self::CallFunction { .. } => "CallFunction",
108 Self::BranchScope { .. } => "BranchScope",
109 Self::LoopScope { .. } => "LoopScope",
110 Self::PushScope { .. } => "PushScope",
111 Self::PopScope => "PopScope",
112 Self::ContinueScopeConditionally => "ContinueScopeConditionally",
113 }
114 }
115}
116
117pub struct ScriptBuilder<'a, SE: ScriptExpression>(Script<'a, SE>);
118
119impl<SE: ScriptExpression> Default for ScriptBuilder<'_, SE> {
120 fn default() -> Self {
121 Self(vec![])
122 }
123}
124
125impl<'a, SE: ScriptExpression> ScriptBuilder<'a, SE> {
126 pub fn build(self) -> ScriptHandle<'a, SE> {
127 ScriptHandle::new(self.0)
128 }
129
130 pub fn expression(mut self, expression: SE) -> Self {
131 self.0.push(ScriptOperation::Expression { expression });
132 self
133 }
134
135 pub fn define_register(mut self, query: TypeQuery<'a>) -> Self {
136 self.0.push(ScriptOperation::DefineRegister { query });
137 self
138 }
139
140 pub fn drop_register(mut self, index: usize) -> Self {
141 self.0.push(ScriptOperation::DropRegister { index });
142 self
143 }
144
145 pub fn push_from_register(mut self, index: usize) -> Self {
146 self.0.push(ScriptOperation::PushFromRegister { index });
147 self
148 }
149
150 pub fn pop_to_register(mut self, index: usize) -> Self {
151 self.0.push(ScriptOperation::PopToRegister { index });
152 self
153 }
154
155 pub fn move_register(mut self, from: usize, to: usize) -> Self {
156 self.0.push(ScriptOperation::MoveRegister { from, to });
157 self
158 }
159
160 pub fn call_function(mut self, query: FunctionQuery<'a>) -> Self {
161 self.0.push(ScriptOperation::CallFunction { query });
162 self
163 }
164
165 pub fn branch_scope(
166 mut self,
167 scope_success: ScriptHandle<'a, SE>,
168 scope_failure: Option<ScriptHandle<'a, SE>>,
169 ) -> Self {
170 self.0.push(ScriptOperation::BranchScope {
171 scope_success,
172 scope_failure,
173 });
174 self
175 }
176
177 pub fn loop_scope(mut self, scope: ScriptHandle<'a, SE>) -> Self {
178 self.0.push(ScriptOperation::LoopScope { scope });
179 self
180 }
181
182 pub fn push_scope(mut self, scope: ScriptHandle<'a, SE>) -> Self {
183 self.0.push(ScriptOperation::PushScope { scope });
184 self
185 }
186
187 pub fn pop_scope(mut self) -> Self {
188 self.0.push(ScriptOperation::PopScope);
189 self
190 }
191
192 pub fn continue_scope_conditionally(mut self) -> Self {
193 self.0.push(ScriptOperation::ContinueScopeConditionally);
194 self
195 }
196}
197
198#[derive(Debug)]
199pub struct ScriptFunctionParameter<'a> {
200 pub meta: Option<Meta>,
201 pub name: String,
202 pub type_query: TypeQuery<'a>,
203}
204
205impl ScriptFunctionParameter<'_> {
206 pub fn build(&self, registry: &Registry) -> FunctionParameter {
207 FunctionParameter {
208 meta: self.meta.to_owned(),
209 name: self.name.to_owned(),
210 type_handle: registry
211 .types()
212 .find(|type_| self.type_query.is_valid(type_))
213 .unwrap()
214 .clone(),
215 }
216 }
217}
218
219#[derive(Debug)]
220pub struct ScriptFunctionSignature<'a> {
221 pub meta: Option<Meta>,
222 pub name: String,
223 pub module_name: Option<String>,
224 pub type_query: Option<TypeQuery<'a>>,
225 pub visibility: Visibility,
226 pub inputs: Vec<ScriptFunctionParameter<'a>>,
227 pub outputs: Vec<ScriptFunctionParameter<'a>>,
228}
229
230impl ScriptFunctionSignature<'_> {
231 pub fn build(&self, registry: &Registry) -> FunctionSignature {
232 FunctionSignature {
233 meta: self.meta.to_owned(),
234 name: self.name.to_owned(),
235 module_name: self.module_name.to_owned(),
236 type_handle: self.type_query.as_ref().map(|type_query| {
237 registry
238 .types()
239 .find(|type_| type_query.is_valid(type_))
240 .unwrap()
241 .clone()
242 }),
243 visibility: self.visibility,
244 inputs: self
245 .inputs
246 .iter()
247 .map(|parameter| parameter.build(registry))
248 .collect(),
249 outputs: self
250 .outputs
251 .iter()
252 .map(|parameter| parameter.build(registry))
253 .collect(),
254 }
255 }
256}
257
258#[derive(Debug)]
259pub struct ScriptFunction<'a, SE: ScriptExpression> {
260 pub signature: ScriptFunctionSignature<'a>,
261 pub script: ScriptHandle<'a, SE>,
262}
263
264impl<SE: ScriptExpression> ScriptFunction<'static, SE> {
265 pub fn install<SFG: ScriptFunctionGenerator<SE>>(
266 &self,
267 registry: &mut Registry,
268 input: SFG::Input,
269 ) -> Option<SFG::Output> {
270 let (function, output) = SFG::generate_function(self, registry, input)?;
271 registry.add_function(function);
272 Some(output)
273 }
274}
275
276pub trait ScriptFunctionGenerator<SE: ScriptExpression> {
277 type Input;
278 type Output;
279
280 fn generate_function_body(
281 script: ScriptHandle<'static, SE>,
282 input: Self::Input,
283 ) -> Option<(FunctionBody, Self::Output)>;
284
285 fn generate_function(
286 function: &ScriptFunction<'static, SE>,
287 registry: &Registry,
288 input: Self::Input,
289 ) -> Option<(Function, Self::Output)> {
290 let (body, output) = Self::generate_function_body(function.script.clone(), input)?;
291 Some((
292 Function::new(function.signature.build(registry), body),
293 output,
294 ))
295 }
296}
297
298#[derive(Debug)]
299pub struct ScriptStructField<'a> {
300 pub meta: Option<Meta>,
301 pub name: String,
302 pub visibility: Visibility,
303 pub type_query: TypeQuery<'a>,
304}
305
306impl ScriptStructField<'_> {
307 pub fn build(&self, registry: &Registry) -> StructField {
308 let mut result = StructField::new(
309 &self.name,
310 registry
311 .types()
312 .find(|type_| self.type_query.is_valid(type_))
313 .unwrap()
314 .clone(),
315 )
316 .with_visibility(self.visibility);
317 result.meta.clone_from(&self.meta);
318 result
319 }
320}
321
322#[derive(Debug)]
323pub struct ScriptStruct<'a> {
324 pub meta: Option<Meta>,
325 pub name: String,
326 pub module_name: Option<String>,
327 pub visibility: Visibility,
328 pub fields: Vec<ScriptStructField<'a>>,
329}
330
331impl ScriptStruct<'_> {
332 pub fn declare(&self, registry: &mut Registry) {
333 let mut builder = RuntimeStructBuilder::new(&self.name);
334 builder = builder.visibility(self.visibility);
335 if let Some(module_name) = self.module_name.as_ref() {
336 builder = builder.module_name(module_name);
337 }
338 if let Some(meta) = self.meta.as_ref() {
339 builder = builder.meta(meta.to_owned());
340 }
341 registry.add_type(builder.build());
342 }
343
344 pub fn define(&self, registry: &mut Registry) {
345 let query = TypeQuery {
346 name: Some(self.name.as_str().into()),
347 module_name: self
348 .module_name
349 .as_ref()
350 .map(|module_name| module_name.into()),
351 ..Default::default()
352 };
353 if let Some(handle) = registry.find_type(query) {
354 let mut builder = RuntimeStructBuilder::new(&self.name);
355 builder = builder.visibility(self.visibility);
356 if let Some(module_name) = self.module_name.as_ref() {
357 builder = builder.module_name(module_name);
358 }
359 if let Some(meta) = self.meta.as_ref() {
360 builder = builder.meta(meta.to_owned());
361 }
362 for field in &self.fields {
363 builder = builder.field(field.build(registry));
364 }
365 unsafe {
366 let type_ = Arc::as_ptr(&handle).cast_mut();
367 *type_ = builder.build().into();
368 }
369 }
370 }
371
372 pub fn install(&self, registry: &mut Registry) {
373 let mut builder = RuntimeStructBuilder::new(&self.name);
374 builder = builder.visibility(self.visibility);
375 if let Some(module_name) = self.module_name.as_ref() {
376 builder = builder.module_name(module_name);
377 }
378 for field in &self.fields {
379 builder = builder.field(field.build(registry));
380 }
381 registry.add_type(builder.build());
382 }
383}
384
385#[derive(Debug)]
386pub struct ScriptEnumVariant<'a> {
387 pub meta: Option<Meta>,
388 pub name: String,
389 pub fields: Vec<ScriptStructField<'a>>,
390 pub discriminant: Option<u8>,
391}
392
393impl ScriptEnumVariant<'_> {
394 pub fn build(&self, registry: &Registry) -> EnumVariant {
395 let mut result = EnumVariant::new(&self.name);
396 result.fields = self
397 .fields
398 .iter()
399 .map(|field| field.build(registry))
400 .collect();
401 result.meta.clone_from(&self.meta);
402 result
403 }
404}
405
406#[derive(Debug)]
407pub struct ScriptEnum<'a> {
408 pub meta: Option<Meta>,
409 pub name: String,
410 pub module_name: Option<String>,
411 pub visibility: Visibility,
412 pub variants: Vec<ScriptEnumVariant<'a>>,
413 pub default_variant: Option<u8>,
414}
415
416impl ScriptEnum<'_> {
417 pub fn declare(&self, registry: &mut Registry) {
418 let mut builder = RuntimeEnumBuilder::new(&self.name);
419 if let Some(discriminant) = self.default_variant {
420 builder = builder.set_default_variant(discriminant);
421 }
422 builder = builder.visibility(self.visibility);
423 if let Some(module_name) = self.module_name.as_ref() {
424 builder = builder.module_name(module_name);
425 }
426 if let Some(meta) = self.meta.as_ref() {
427 builder = builder.meta(meta.to_owned());
428 }
429 registry.add_type(builder.build());
430 }
431
432 pub fn define(&self, registry: &mut Registry) {
433 let query = TypeQuery {
434 name: Some(self.name.as_str().into()),
435 module_name: self
436 .module_name
437 .as_ref()
438 .map(|module_name| module_name.into()),
439 ..Default::default()
440 };
441 if let Some(handle) = registry.find_type(query) {
442 let mut builder = RuntimeEnumBuilder::new(&self.name);
443 if let Some(discriminant) = self.default_variant {
444 builder = builder.set_default_variant(discriminant);
445 }
446 builder = builder.visibility(self.visibility);
447 if let Some(module_name) = self.module_name.as_ref() {
448 builder = builder.module_name(module_name);
449 }
450 if let Some(meta) = self.meta.as_ref() {
451 builder = builder.meta(meta.to_owned());
452 }
453 for variant in &self.variants {
454 if let Some(discriminant) = variant.discriminant {
455 builder =
456 builder.variant_with_discriminant(variant.build(registry), discriminant);
457 } else {
458 builder = builder.variant(variant.build(registry));
459 }
460 }
461 unsafe {
462 let type_ = Arc::as_ptr(&handle).cast_mut();
463 *type_ = builder.build().into();
464 }
465 }
466 }
467
468 pub fn install(&self, registry: &mut Registry) {
469 let mut builder = RuntimeEnumBuilder::new(&self.name);
470 if let Some(discriminant) = self.default_variant {
471 builder = builder.set_default_variant(discriminant);
472 }
473 builder = builder.visibility(self.visibility);
474 if let Some(module_name) = self.module_name.as_ref() {
475 builder = builder.module_name(module_name);
476 }
477 for variant in &self.variants {
478 if let Some(discriminant) = variant.discriminant {
479 builder = builder.variant_with_discriminant(variant.build(registry), discriminant);
480 } else {
481 builder = builder.variant(variant.build(registry));
482 }
483 }
484 registry.add_type(builder.build());
485 }
486}
487
488#[derive(Debug, Default)]
489pub struct ScriptModule<'a, SE: ScriptExpression> {
490 pub name: String,
491 pub structs: Vec<ScriptStruct<'a>>,
492 pub enums: Vec<ScriptEnum<'a>>,
493 pub functions: Vec<ScriptFunction<'a, SE>>,
494}
495
496impl<SE: ScriptExpression> ScriptModule<'_, SE> {
497 pub fn fix_module_names(&mut self) {
498 for type_ in &mut self.structs {
499 type_.module_name = Some(self.name.to_owned());
500 }
501 for type_ in &mut self.enums {
502 type_.module_name = Some(self.name.to_owned());
503 }
504 for function in &mut self.functions {
505 function.signature.module_name = Some(self.name.to_owned());
506 }
507 }
508
509 pub fn declare_types(&self, registry: &mut Registry) {
510 for type_ in &self.structs {
511 type_.declare(registry);
512 }
513 for type_ in &self.enums {
514 type_.declare(registry);
515 }
516 }
517
518 pub fn define_types(&self, registry: &mut Registry) {
519 for type_ in &self.structs {
520 type_.define(registry);
521 }
522 for type_ in &self.enums {
523 type_.define(registry);
524 }
525 }
526
527 pub fn install_types(&self, registry: &mut Registry) {
528 self.declare_types(registry);
529 self.define_types(registry);
530 }
531}
532
533impl<SE: ScriptExpression> ScriptModule<'static, SE> {
534 pub fn install_functions<SFG: ScriptFunctionGenerator<SE>>(
535 &self,
536 registry: &mut Registry,
537 input: SFG::Input,
538 ) where
539 SFG::Input: Clone,
540 {
541 for function in &self.functions {
542 function.install::<SFG>(registry, input.clone());
543 }
544 }
545}
546
547#[derive(Debug, Default)]
548pub struct ScriptPackage<'a, SE: ScriptExpression> {
549 pub modules: Vec<ScriptModule<'a, SE>>,
550}
551
552impl<SE: ScriptExpression> ScriptPackage<'static, SE> {
553 pub fn install<SFG: ScriptFunctionGenerator<SE>>(
554 &self,
555 registry: &mut Registry,
556 input: SFG::Input,
557 ) where
558 SFG::Input: Clone,
559 {
560 for module in &self.modules {
561 module.install_types(registry);
562 }
563 for module in &self.modules {
564 module.install_functions::<SFG>(registry, input.clone());
565 }
566 }
567}
568
569pub struct ScriptContent<T> {
570 pub path: String,
571 pub name: String,
572 pub data: Result<Option<T>, Box<dyn Error>>,
573}
574
575pub trait ScriptContentProvider<T> {
576 fn load(&mut self, path: &str) -> Result<Option<T>, Box<dyn Error>>;
577
578 fn unpack_load(&mut self, path: &str) -> Result<Vec<ScriptContent<T>>, Box<dyn Error>> {
579 Ok(vec![ScriptContent {
580 path: path.to_owned(),
581 name: path.to_owned(),
582 data: self.load(path),
583 }])
584 }
585
586 fn sanitize_path(&self, path: &str) -> Result<String, Box<dyn Error>> {
587 Ok(path.to_owned())
588 }
589
590 fn join_paths(&self, parent: &str, relative: &str) -> Result<String, Box<dyn Error>>;
591}
592
593pub struct ExtensionContentProvider<S> {
594 default_extension: Option<String>,
595 extension_providers: HashMap<String, Box<dyn ScriptContentProvider<S>>>,
596}
597
598impl<S> Default for ExtensionContentProvider<S> {
599 fn default() -> Self {
600 Self {
601 default_extension: None,
602 extension_providers: Default::default(),
603 }
604 }
605}
606
607impl<S> ExtensionContentProvider<S> {
608 pub fn default_extension(mut self, extension: impl ToString) -> Self {
609 self.default_extension = Some(extension.to_string());
610 self
611 }
612
613 pub fn extension(
614 mut self,
615 extension: &str,
616 content_provider: impl ScriptContentProvider<S> + 'static,
617 ) -> Self {
618 self.extension_providers
619 .insert(extension.to_owned(), Box::new(content_provider));
620 self
621 }
622}
623
624impl<S> ScriptContentProvider<S> for ExtensionContentProvider<S> {
625 fn load(&mut self, _: &str) -> Result<Option<S>, Box<dyn Error>> {
626 Ok(None)
627 }
628
629 fn unpack_load(&mut self, path: &str) -> Result<Vec<ScriptContent<S>>, Box<dyn Error>> {
630 let extension = match Path::new(path).extension() {
631 Some(extension) => extension.to_string_lossy().to_string(),
632 None => match &self.default_extension {
633 Some(extension) => extension.to_owned(),
634 None => return Err(Box::new(ExtensionContentProviderError::NoDefaultExtension)),
635 },
636 };
637 if let Some(content_provider) = self.extension_providers.get_mut(&extension) {
638 content_provider.unpack_load(path)
639 } else {
640 Err(Box::new(
641 ExtensionContentProviderError::ContentProviderForExtensionNotFound(extension),
642 ))
643 }
644 }
645
646 fn sanitize_path(&self, path: &str) -> Result<String, Box<dyn Error>> {
647 let extension = match Path::new(path).extension() {
648 Some(extension) => extension.to_string_lossy().to_string(),
649 None => match &self.default_extension {
650 Some(extension) => extension.to_owned(),
651 None => return Err(Box::new(ExtensionContentProviderError::NoDefaultExtension)),
652 },
653 };
654 if let Some(content_provider) = self.extension_providers.get(&extension) {
655 content_provider.sanitize_path(path)
656 } else {
657 Err(Box::new(
658 ExtensionContentProviderError::ContentProviderForExtensionNotFound(extension),
659 ))
660 }
661 }
662
663 fn join_paths(&self, parent: &str, relative: &str) -> Result<String, Box<dyn Error>> {
664 let extension = match Path::new(relative).extension() {
665 Some(extension) => extension.to_string_lossy().to_string(),
666 None => match &self.default_extension {
667 Some(extension) => extension.to_owned(),
668 None => return Err(Box::new(ExtensionContentProviderError::NoDefaultExtension)),
669 },
670 };
671 if let Some(content_provider) = self.extension_providers.get(&extension) {
672 content_provider.join_paths(parent, relative)
673 } else {
674 Err(Box::new(
675 ExtensionContentProviderError::ContentProviderForExtensionNotFound(extension),
676 ))
677 }
678 }
679}
680
681#[derive(Debug)]
682pub enum ExtensionContentProviderError {
683 NoDefaultExtension,
684 ContentProviderForExtensionNotFound(String),
685}
686
687impl std::fmt::Display for ExtensionContentProviderError {
688 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
689 match self {
690 ExtensionContentProviderError::NoDefaultExtension => {
691 write!(f, "No default extension set")
692 }
693 ExtensionContentProviderError::ContentProviderForExtensionNotFound(extension) => {
694 write!(
695 f,
696 "Could not find content provider for extension: `{extension}`"
697 )
698 }
699 }
700 }
701}
702
703impl Error for ExtensionContentProviderError {}
704
705pub struct IgnoreContentProvider;
706
707impl<S> ScriptContentProvider<S> for IgnoreContentProvider {
708 fn load(&mut self, _: &str) -> Result<Option<S>, Box<dyn Error>> {
709 Ok(None)
710 }
711
712 fn join_paths(&self, parent: &str, relative: &str) -> Result<String, Box<dyn Error>> {
713 Ok(format!("{parent}/{relative}"))
714 }
715}
716
717pub trait BytesContentParser<T> {
718 fn parse(&self, bytes: Vec<u8>) -> Result<T, Box<dyn Error>>;
719}
720
721pub struct FileContentProvider<T> {
722 extension: String,
723 parser: Box<dyn BytesContentParser<T>>,
724}
725
726impl<T> FileContentProvider<T> {
727 pub fn new(extension: impl ToString, parser: impl BytesContentParser<T> + 'static) -> Self {
728 Self {
729 extension: extension.to_string(),
730 parser: Box::new(parser),
731 }
732 }
733}
734
735impl<T> ScriptContentProvider<T> for FileContentProvider<T> {
736 fn load(&mut self, path: &str) -> Result<Option<T>, Box<dyn Error>> {
737 Ok(Some(self.parser.parse(std::fs::read(path)?)?))
738 }
739
740 fn sanitize_path(&self, path: &str) -> Result<String, Box<dyn Error>> {
741 let mut result = PathBuf::from(path);
742 if result.extension().is_none() {
743 result.set_extension(&self.extension);
744 }
745 Ok(result.canonicalize()?.to_string_lossy().into_owned())
746 }
747
748 fn join_paths(&self, parent: &str, relative: &str) -> Result<String, Box<dyn Error>> {
749 let mut path = PathBuf::from(parent);
750 path.pop();
751 Ok(path.join(relative).to_string_lossy().into_owned())
752 }
753}