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