mustardscript 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/Cargo.lock +1579 -0
  2. package/Cargo.toml +40 -0
  3. package/LICENSE +201 -0
  4. package/README.md +828 -0
  5. package/SECURITY.md +34 -0
  6. package/crates/mustard/Cargo.toml +31 -0
  7. package/crates/mustard/src/cancellation.rs +28 -0
  8. package/crates/mustard/src/diagnostic.rs +145 -0
  9. package/crates/mustard/src/ir.rs +435 -0
  10. package/crates/mustard/src/lib.rs +21 -0
  11. package/crates/mustard/src/limits.rs +22 -0
  12. package/crates/mustard/src/parser/expressions.rs +723 -0
  13. package/crates/mustard/src/parser/mod.rs +115 -0
  14. package/crates/mustard/src/parser/operators.rs +105 -0
  15. package/crates/mustard/src/parser/patterns.rs +123 -0
  16. package/crates/mustard/src/parser/scope.rs +107 -0
  17. package/crates/mustard/src/parser/statements.rs +298 -0
  18. package/crates/mustard/src/parser/tests/acceptance.rs +339 -0
  19. package/crates/mustard/src/parser/tests/mod.rs +2 -0
  20. package/crates/mustard/src/parser/tests/rejections.rs +107 -0
  21. package/crates/mustard/src/runtime/accounting.rs +613 -0
  22. package/crates/mustard/src/runtime/api.rs +192 -0
  23. package/crates/mustard/src/runtime/async_runtime/mod.rs +5 -0
  24. package/crates/mustard/src/runtime/async_runtime/promises.rs +246 -0
  25. package/crates/mustard/src/runtime/async_runtime/reactions.rs +400 -0
  26. package/crates/mustard/src/runtime/async_runtime/scheduler.rs +224 -0
  27. package/crates/mustard/src/runtime/builtins/arrays.rs +1205 -0
  28. package/crates/mustard/src/runtime/builtins/collections.rs +573 -0
  29. package/crates/mustard/src/runtime/builtins/install.rs +501 -0
  30. package/crates/mustard/src/runtime/builtins/intl.rs +553 -0
  31. package/crates/mustard/src/runtime/builtins/mod.rs +25 -0
  32. package/crates/mustard/src/runtime/builtins/objects.rs +405 -0
  33. package/crates/mustard/src/runtime/builtins/primitives.rs +859 -0
  34. package/crates/mustard/src/runtime/builtins/promises.rs +335 -0
  35. package/crates/mustard/src/runtime/builtins/regexp.rs +356 -0
  36. package/crates/mustard/src/runtime/builtins/strings.rs +803 -0
  37. package/crates/mustard/src/runtime/builtins/support.rs +561 -0
  38. package/crates/mustard/src/runtime/bytecode.rs +123 -0
  39. package/crates/mustard/src/runtime/compiler/assignments.rs +690 -0
  40. package/crates/mustard/src/runtime/compiler/bindings.rs +92 -0
  41. package/crates/mustard/src/runtime/compiler/context.rs +46 -0
  42. package/crates/mustard/src/runtime/compiler/control.rs +342 -0
  43. package/crates/mustard/src/runtime/compiler/expressions.rs +372 -0
  44. package/crates/mustard/src/runtime/compiler/mod.rs +173 -0
  45. package/crates/mustard/src/runtime/compiler/statements.rs +459 -0
  46. package/crates/mustard/src/runtime/conversions/boundary.rs +293 -0
  47. package/crates/mustard/src/runtime/conversions/coercions.rs +217 -0
  48. package/crates/mustard/src/runtime/conversions/errors.rs +118 -0
  49. package/crates/mustard/src/runtime/conversions/mod.rs +14 -0
  50. package/crates/mustard/src/runtime/conversions/operators.rs +334 -0
  51. package/crates/mustard/src/runtime/env.rs +355 -0
  52. package/crates/mustard/src/runtime/exceptions.rs +377 -0
  53. package/crates/mustard/src/runtime/gc.rs +595 -0
  54. package/crates/mustard/src/runtime/mod.rs +318 -0
  55. package/crates/mustard/src/runtime/properties.rs +1762 -0
  56. package/crates/mustard/src/runtime/serialization.rs +127 -0
  57. package/crates/mustard/src/runtime/shared.rs +108 -0
  58. package/crates/mustard/src/runtime/snapshot_validation_tests.rs +93 -0
  59. package/crates/mustard/src/runtime/state.rs +652 -0
  60. package/crates/mustard/src/runtime/tests/async_host.rs +104 -0
  61. package/crates/mustard/src/runtime/tests/collections.rs +50 -0
  62. package/crates/mustard/src/runtime/tests/diagnostics.rs +36 -0
  63. package/crates/mustard/src/runtime/tests/exceptions.rs +122 -0
  64. package/crates/mustard/src/runtime/tests/execution.rs +553 -0
  65. package/crates/mustard/src/runtime/tests/gc.rs +533 -0
  66. package/crates/mustard/src/runtime/tests/mod.rs +56 -0
  67. package/crates/mustard/src/runtime/tests/serialization.rs +170 -0
  68. package/crates/mustard/src/runtime/validation/bytecode.rs +484 -0
  69. package/crates/mustard/src/runtime/validation/mod.rs +14 -0
  70. package/crates/mustard/src/runtime/validation/policy.rs +94 -0
  71. package/crates/mustard/src/runtime/validation/snapshot.rs +406 -0
  72. package/crates/mustard/src/runtime/validation/walk.rs +206 -0
  73. package/crates/mustard/src/runtime/vm.rs +1016 -0
  74. package/crates/mustard/src/span.rs +22 -0
  75. package/crates/mustard/src/structured.rs +107 -0
  76. package/crates/mustard-bridge/Cargo.toml +17 -0
  77. package/crates/mustard-bridge/src/codec.rs +46 -0
  78. package/crates/mustard-bridge/src/dto.rs +99 -0
  79. package/crates/mustard-bridge/src/lib.rs +12 -0
  80. package/crates/mustard-bridge/src/operations.rs +142 -0
  81. package/crates/mustard-node/Cargo.toml +24 -0
  82. package/crates/mustard-node/build.rs +3 -0
  83. package/crates/mustard-node/src/lib.rs +236 -0
  84. package/crates/mustard-sidecar/Cargo.toml +21 -0
  85. package/crates/mustard-sidecar/src/lib.rs +134 -0
  86. package/crates/mustard-sidecar/src/main.rs +36 -0
  87. package/dist/index.js +20 -0
  88. package/dist/install.js +117 -0
  89. package/dist/lib/cancellation.js +124 -0
  90. package/dist/lib/errors.js +46 -0
  91. package/dist/lib/executor.js +555 -0
  92. package/dist/lib/policy.js +292 -0
  93. package/dist/lib/progress.js +356 -0
  94. package/dist/lib/runtime.js +109 -0
  95. package/dist/lib/structured.js +286 -0
  96. package/dist/native-loader.js +227 -0
  97. package/index.d.ts +23 -0
  98. package/mustard.d.ts +220 -0
  99. package/package.json +97 -0
@@ -0,0 +1,192 @@
1
+ use indexmap::IndexMap;
2
+ use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
+
4
+ use crate::{
5
+ cancellation::CancellationToken,
6
+ diagnostic::{DiagnosticKind, MustardError, MustardResult},
7
+ ir::CompiledProgram,
8
+ limits::RuntimeLimits,
9
+ structured::StructuredValue,
10
+ };
11
+
12
+ use super::{
13
+ Runtime,
14
+ bytecode::BytecodeProgram,
15
+ lower_to_bytecode,
16
+ validation::{validate_bytecode_program, validate_snapshot},
17
+ };
18
+
19
+ #[derive(Debug, Clone, Serialize, Deserialize)]
20
+ pub struct ExecutionOptions {
21
+ pub inputs: IndexMap<String, StructuredValue>,
22
+ pub capabilities: Vec<String>,
23
+ pub limits: RuntimeLimits,
24
+ #[serde(skip, default)]
25
+ pub cancellation_token: Option<CancellationToken>,
26
+ }
27
+
28
+ impl Default for ExecutionOptions {
29
+ fn default() -> Self {
30
+ Self {
31
+ inputs: IndexMap::new(),
32
+ capabilities: Vec::new(),
33
+ limits: RuntimeLimits::default(),
34
+ cancellation_token: None,
35
+ }
36
+ }
37
+ }
38
+
39
+ #[derive(Debug, Clone, Serialize, Deserialize)]
40
+ pub struct HostError {
41
+ pub name: String,
42
+ pub message: String,
43
+ pub code: Option<String>,
44
+ pub details: Option<StructuredValue>,
45
+ }
46
+
47
+ #[derive(Debug, Clone, Serialize, Deserialize)]
48
+ pub enum ResumePayload {
49
+ Value(StructuredValue),
50
+ Error(HostError),
51
+ Cancelled,
52
+ }
53
+
54
+ #[derive(Debug, Clone, Serialize, Deserialize)]
55
+ pub struct SnapshotPolicy {
56
+ pub capabilities: Vec<String>,
57
+ pub limits: RuntimeLimits,
58
+ }
59
+
60
+ #[derive(Debug, Clone, Serialize, Deserialize)]
61
+ pub struct SnapshotInspection {
62
+ pub capability: String,
63
+ pub args: Vec<StructuredValue>,
64
+ }
65
+
66
+ #[derive(Debug, Clone, Default)]
67
+ pub struct ResumeOptions {
68
+ pub cancellation_token: Option<CancellationToken>,
69
+ pub snapshot_policy: Option<SnapshotPolicy>,
70
+ }
71
+
72
+ #[derive(Debug, Clone)]
73
+ pub struct ExecutionSnapshot {
74
+ pub(super) runtime: Runtime,
75
+ }
76
+
77
+ #[derive(Debug, Clone, Serialize, Deserialize)]
78
+ pub struct Suspension {
79
+ pub capability: String,
80
+ pub args: Vec<StructuredValue>,
81
+ pub snapshot: ExecutionSnapshot,
82
+ }
83
+
84
+ #[derive(Debug, Clone, Serialize, Deserialize)]
85
+ pub enum ExecutionStep {
86
+ Completed(StructuredValue),
87
+ Suspended(Box<Suspension>),
88
+ }
89
+
90
+ #[derive(Serialize)]
91
+ struct SerializableExecutionSnapshot<'a> {
92
+ runtime: &'a Runtime,
93
+ }
94
+
95
+ #[derive(Deserialize)]
96
+ struct DeserializableExecutionSnapshot {
97
+ runtime: Runtime,
98
+ }
99
+
100
+ impl ExecutionSnapshot {
101
+ pub(in crate::runtime) fn restore_loaded_runtime(runtime: Runtime) -> MustardResult<Self> {
102
+ let mut snapshot = Self { runtime };
103
+ validate_snapshot(&snapshot)?;
104
+ snapshot.runtime.recompute_accounting_after_load()?;
105
+ snapshot.runtime.snapshot_policy_required = true;
106
+ Ok(snapshot)
107
+ }
108
+ }
109
+
110
+ impl Serialize for ExecutionSnapshot {
111
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112
+ where
113
+ S: Serializer,
114
+ {
115
+ SerializableExecutionSnapshot {
116
+ runtime: &self.runtime,
117
+ }
118
+ .serialize(serializer)
119
+ }
120
+ }
121
+
122
+ impl<'de> Deserialize<'de> for ExecutionSnapshot {
123
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
124
+ where
125
+ D: Deserializer<'de>,
126
+ {
127
+ let decoded = DeserializableExecutionSnapshot::deserialize(deserializer)?;
128
+ Self::restore_loaded_runtime(decoded.runtime).map_err(serde::de::Error::custom)
129
+ }
130
+ }
131
+
132
+ pub fn execute(
133
+ program: &CompiledProgram,
134
+ options: ExecutionOptions,
135
+ ) -> MustardResult<StructuredValue> {
136
+ match start(program, options)? {
137
+ ExecutionStep::Completed(value) => Ok(value),
138
+ ExecutionStep::Suspended(suspension) => Err(MustardError::runtime(format!(
139
+ "execution suspended on capability `{}`; use start()/resume() for iterative execution",
140
+ suspension.capability
141
+ ))),
142
+ }
143
+ }
144
+
145
+ pub fn start(program: &CompiledProgram, options: ExecutionOptions) -> MustardResult<ExecutionStep> {
146
+ let bytecode = lower_to_bytecode(program)?;
147
+ start_bytecode(&bytecode, options)
148
+ }
149
+
150
+ pub fn start_bytecode(
151
+ program: &BytecodeProgram,
152
+ options: ExecutionOptions,
153
+ ) -> MustardResult<ExecutionStep> {
154
+ validate_bytecode_program(program)?;
155
+ let mut runtime = Runtime::new(program.clone(), options)?;
156
+ runtime.run_root()
157
+ }
158
+
159
+ pub fn resume(snapshot: ExecutionSnapshot, payload: ResumePayload) -> MustardResult<ExecutionStep> {
160
+ resume_with_options(snapshot, payload, ResumeOptions::default())
161
+ }
162
+
163
+ pub fn resume_with_options(
164
+ snapshot: ExecutionSnapshot,
165
+ payload: ResumePayload,
166
+ options: ResumeOptions,
167
+ ) -> MustardResult<ExecutionStep> {
168
+ let mut runtime = snapshot.runtime;
169
+ runtime.apply_resume_options(options)?;
170
+ runtime.resume(payload)
171
+ }
172
+
173
+ pub fn inspect_snapshot(
174
+ snapshot: &mut ExecutionSnapshot,
175
+ policy: SnapshotPolicy,
176
+ ) -> MustardResult<SnapshotInspection> {
177
+ snapshot.runtime.apply_snapshot_policy(policy)?;
178
+ let request = snapshot
179
+ .runtime
180
+ .suspended_host_call
181
+ .as_ref()
182
+ .ok_or_else(|| MustardError::Message {
183
+ kind: DiagnosticKind::Serialization,
184
+ message: "snapshot is not suspended on a host capability".to_string(),
185
+ span: None,
186
+ traceback: Vec::new(),
187
+ })?;
188
+ Ok(SnapshotInspection {
189
+ capability: request.capability.clone(),
190
+ args: request.args.clone(),
191
+ })
192
+ }
@@ -0,0 +1,5 @@
1
+ use super::*;
2
+
3
+ mod promises;
4
+ mod reactions;
5
+ mod scheduler;
@@ -0,0 +1,246 @@
1
+ use crate::runtime::builtins::PromiseSetupPolicy;
2
+
3
+ use super::*;
4
+
5
+ impl Runtime {
6
+ pub(in crate::runtime) fn current_async_boundary_index(&self) -> Option<usize> {
7
+ self.frames
8
+ .iter()
9
+ .rposition(|frame| frame.async_promise.is_some())
10
+ }
11
+
12
+ pub(in crate::runtime) fn promise_outcome(
13
+ &self,
14
+ promise: PromiseKey,
15
+ ) -> MustardResult<Option<PromiseOutcome>> {
16
+ let promise = self
17
+ .promises
18
+ .get(promise)
19
+ .ok_or_else(|| MustardError::runtime("promise missing"))?;
20
+ Ok(match &promise.state {
21
+ PromiseState::Pending => None,
22
+ PromiseState::Fulfilled(value) => Some(PromiseOutcome::Fulfilled(value.clone())),
23
+ PromiseState::Rejected(rejection) => Some(PromiseOutcome::Rejected(rejection.clone())),
24
+ })
25
+ }
26
+
27
+ pub(in crate::runtime) fn coerce_to_promise(
28
+ &mut self,
29
+ value: Value,
30
+ ) -> MustardResult<PromiseKey> {
31
+ match value {
32
+ Value::Promise(promise) => Ok(promise),
33
+ other => {
34
+ let promise = self.insert_promise(PromiseState::Pending)?;
35
+ self.resolve_promise(promise, other)?;
36
+ Ok(promise)
37
+ }
38
+ }
39
+ }
40
+
41
+ pub(in crate::runtime) fn attach_awaiter(
42
+ &mut self,
43
+ promise: PromiseKey,
44
+ continuation: AsyncContinuation,
45
+ ) -> MustardResult<()> {
46
+ self.promises
47
+ .get_mut(promise)
48
+ .ok_or_else(|| MustardError::runtime("promise missing"))?
49
+ .awaiters
50
+ .push(continuation);
51
+ self.refresh_promise_accounting(promise)
52
+ }
53
+
54
+ pub(in crate::runtime) fn attach_dependent(
55
+ &mut self,
56
+ promise: PromiseKey,
57
+ dependent: PromiseKey,
58
+ ) -> MustardResult<()> {
59
+ self.promises
60
+ .get_mut(promise)
61
+ .ok_or_else(|| MustardError::runtime("promise missing"))?
62
+ .dependents
63
+ .push(dependent);
64
+ self.refresh_promise_accounting(promise)
65
+ }
66
+
67
+ pub(in crate::runtime) fn attach_promise_reaction(
68
+ &mut self,
69
+ promise: PromiseKey,
70
+ reaction: PromiseReaction,
71
+ ) -> MustardResult<()> {
72
+ match self.promise_outcome(promise)? {
73
+ Some(outcome) => self.schedule_promise_reaction(reaction, outcome),
74
+ None => {
75
+ self.promises
76
+ .get_mut(promise)
77
+ .ok_or_else(|| MustardError::runtime("promise missing"))?
78
+ .reactions
79
+ .push(reaction);
80
+ self.refresh_promise_accounting(promise)
81
+ }
82
+ }
83
+ }
84
+
85
+ pub(in crate::runtime) fn schedule_promise_reaction(
86
+ &mut self,
87
+ reaction: PromiseReaction,
88
+ outcome: PromiseOutcome,
89
+ ) -> MustardResult<()> {
90
+ self.microtasks
91
+ .push_back(MicrotaskJob::PromiseReaction { reaction, outcome });
92
+ Ok(())
93
+ }
94
+
95
+ pub(in crate::runtime) fn settle_promise_with_outcome(
96
+ &mut self,
97
+ promise: PromiseKey,
98
+ outcome: PromiseOutcome,
99
+ ) -> MustardResult<()> {
100
+ let (awaiters, dependents, reactions) = {
101
+ let promise_ref = self
102
+ .promises
103
+ .get_mut(promise)
104
+ .ok_or_else(|| MustardError::runtime("promise missing"))?;
105
+ if !matches!(promise_ref.state, PromiseState::Pending) {
106
+ return Ok(());
107
+ }
108
+ promise_ref.state = match &outcome {
109
+ PromiseOutcome::Fulfilled(value) => PromiseState::Fulfilled(value.clone()),
110
+ PromiseOutcome::Rejected(rejection) => PromiseState::Rejected(rejection.clone()),
111
+ };
112
+ promise_ref.driver = None;
113
+ (
114
+ std::mem::take(&mut promise_ref.awaiters),
115
+ std::mem::take(&mut promise_ref.dependents),
116
+ std::mem::take(&mut promise_ref.reactions),
117
+ )
118
+ };
119
+ self.refresh_promise_accounting(promise)?;
120
+ for continuation in awaiters {
121
+ self.microtasks.push_back(MicrotaskJob::ResumeAsync {
122
+ continuation,
123
+ outcome: outcome.clone(),
124
+ });
125
+ }
126
+ for dependent in dependents {
127
+ self.resolve_promise_with_outcome(dependent, outcome.clone())?;
128
+ }
129
+ for reaction in reactions {
130
+ self.schedule_promise_reaction(reaction, outcome.clone())?;
131
+ }
132
+ Ok(())
133
+ }
134
+
135
+ pub(in crate::runtime) fn resolve_promise_with_outcome(
136
+ &mut self,
137
+ promise: PromiseKey,
138
+ outcome: PromiseOutcome,
139
+ ) -> MustardResult<()> {
140
+ match outcome {
141
+ PromiseOutcome::Fulfilled(value) => self.resolve_promise(promise, value),
142
+ PromiseOutcome::Rejected(rejection) => self.reject_promise(promise, rejection),
143
+ }
144
+ }
145
+
146
+ pub(in crate::runtime) fn resolve_promise(
147
+ &mut self,
148
+ promise: PromiseKey,
149
+ value: Value,
150
+ ) -> MustardResult<()> {
151
+ if self.promise_outcome(promise)?.is_some() {
152
+ return Ok(());
153
+ }
154
+ if let Value::Promise(source) = value {
155
+ if source == promise {
156
+ let error_value =
157
+ self.value_from_runtime_message("TypeError: promise cannot resolve to itself")?;
158
+ return self.reject_promise(
159
+ promise,
160
+ PromiseRejection {
161
+ value: error_value,
162
+ span: None,
163
+ traceback: self.traceback_snapshots(),
164
+ },
165
+ );
166
+ }
167
+ match self.promise_outcome(source)? {
168
+ Some(outcome) => self.resolve_promise_with_outcome(promise, outcome),
169
+ None => self.attach_dependent(source, promise),
170
+ }
171
+ } else if let Some(then) = self.promise_thenable_handler(&value)? {
172
+ let tracked_thenable = self
173
+ .promises
174
+ .get(promise)
175
+ .ok_or_else(|| MustardError::runtime("promise missing"))?
176
+ .driver
177
+ .as_ref()
178
+ .and_then(|driver| match driver {
179
+ PromiseDriver::Thenable { value } => Some(value),
180
+ _ => None,
181
+ });
182
+ if tracked_thenable.is_some_and(|tracked| strict_equal(tracked, &value)) {
183
+ let error_value = self
184
+ .value_from_runtime_message("TypeError: thenable cannot resolve to itself")?;
185
+ return self.reject_promise(
186
+ promise,
187
+ PromiseRejection {
188
+ value: error_value,
189
+ span: None,
190
+ traceback: self.traceback_snapshots(),
191
+ },
192
+ );
193
+ }
194
+ self.promises
195
+ .get_mut(promise)
196
+ .ok_or_else(|| MustardError::runtime("promise missing"))?
197
+ .driver = Some(PromiseDriver::Thenable {
198
+ value: value.clone(),
199
+ });
200
+ self.refresh_promise_accounting(promise)?;
201
+ let resolve = self.promise_settler(promise, false);
202
+ let reject = self.promise_settler(promise, true);
203
+ self.call_promise_setup_callback(
204
+ promise,
205
+ then,
206
+ value,
207
+ &[resolve, reject],
208
+ PromiseSetupPolicy {
209
+ non_callable_message: "TypeError: adopted thenable `.then` must be callable",
210
+ host_suspension_message:
211
+ "TypeError: adopted thenables do not support synchronous host suspensions",
212
+ async_message:
213
+ "TypeError: adopted thenables must use synchronous `.then` handlers",
214
+ },
215
+ )
216
+ } else {
217
+ self.settle_promise_with_outcome(promise, PromiseOutcome::Fulfilled(value))
218
+ }
219
+ }
220
+
221
+ pub(in crate::runtime) fn reject_promise(
222
+ &mut self,
223
+ promise: PromiseKey,
224
+ rejection: PromiseRejection,
225
+ ) -> MustardResult<()> {
226
+ self.settle_promise_with_outcome(promise, PromiseOutcome::Rejected(rejection))
227
+ }
228
+
229
+ pub(in crate::runtime) fn suspend_async_await(&mut self, value: Value) -> MustardResult<()> {
230
+ let boundary = self.current_async_boundary_index().ok_or_else(|| {
231
+ MustardError::runtime("await is only supported inside async functions")
232
+ })?;
233
+ let promise = self.coerce_to_promise(value)?;
234
+ let continuation = AsyncContinuation {
235
+ frames: self.frames.split_off(boundary),
236
+ };
237
+ match self.promise_outcome(promise)? {
238
+ Some(outcome) => self.microtasks.push_back(MicrotaskJob::ResumeAsync {
239
+ continuation,
240
+ outcome,
241
+ }),
242
+ None => self.attach_awaiter(promise, continuation)?,
243
+ }
244
+ Ok(())
245
+ }
246
+ }