-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbasic.rs
More file actions
169 lines (151 loc) · 5.44 KB
/
basic.rs
File metadata and controls
169 lines (151 loc) · 5.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! Basic Zapcode example — execute TypeScript from Rust.
//!
//! Run with: cargo run --example basic
use zapcode_core::{ZapcodeRun, ResourceLimits, Value, VmState};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// --- 1. Simple expression ---
let runner = ZapcodeRun::new(
"1 + 2 * 3".to_string(),
vec![],
vec![],
ResourceLimits::default(),
)?;
let result = runner.run_simple()?;
println!("1 + 2 * 3 = {:?}", result); // Int(7)
// --- 2. Using inputs ---
let runner = ZapcodeRun::new(
r#"
const greeting = `Hello, ${name}! You are ${age} years old.`;
greeting
"#
.to_string(),
vec!["name".to_string(), "age".to_string()],
vec![],
ResourceLimits::default(),
)?;
let result = runner.run(vec![
("name".to_string(), Value::String("Zapcode".into())),
("age".to_string(), Value::Int(30)),
])?;
println!("Greeting: {:?}", result.state); // Complete("Hello, Zapcode! You are 30 years old.")
// --- 3. External function (snapshot/resume) ---
let runner = ZapcodeRun::new(
r#"
const weather = await getWeather(city);
const summary = `Weather in ${city}: ${weather.condition}, ${weather.temp}°C`;
summary
"#
.to_string(),
vec!["city".to_string()],
vec!["getWeather".to_string()],
ResourceLimits::default(),
)?;
// Start execution — suspends at getWeather()
let state = runner.start(vec![
("city".to_string(), Value::String("London".into())),
])?;
match state {
VmState::Suspended {
function_name,
args,
snapshot,
} => {
println!("Suspended on: {}({:?})", function_name, args);
// In a real app, you'd call an actual weather API here.
// For this example, we return a mock response.
let weather_data = Value::Object(indexmap::indexmap! {
"condition".into() => Value::String("Partly cloudy".into()),
"temp".into() => Value::Int(18),
});
// Resume with the mock result
let final_state = snapshot.resume(weather_data)?;
match final_state {
VmState::Complete(value) => {
println!("Result: {:?}", value);
// "Weather in London: Partly cloudy, 18°C"
}
_ => println!("Unexpected second suspension"),
}
}
VmState::Complete(value) => {
println!("Completed immediately: {:?}", value);
}
}
// --- 4. Snapshot serialization (store and resume later) ---
let runner = ZapcodeRun::new(
r#"
const data = await fetchData(url);
data.length
"#
.to_string(),
vec!["url".to_string()],
vec!["fetchData".to_string()],
ResourceLimits::default(),
)?;
let state = runner.start(vec![
("url".to_string(), Value::String("https://example.com".into())),
])?;
if let VmState::Suspended { snapshot, .. } = state {
// Serialize to bytes — store in a database, send over the network, etc.
let bytes = snapshot.dump()?;
println!("Snapshot size: {} bytes", bytes.len());
// Later (possibly in a different process): restore and resume
let restored = zapcode_core::ZapcodeSnapshot::load(&bytes)?;
let final_state = restored.resume(Value::String("hello world".into()))?;
if let VmState::Complete(value) = final_state {
println!("Restored result: {:?}", value); // Int(11)
}
}
// --- 5. Async map with multiple external calls ---
// arr.map(async fn => await external()) now works —
// each external call suspends/resumes sequentially.
let runner = ZapcodeRun::new(
r#"
const cities = ["London", "Tokyo", "Paris"];
const results = cities.map(async (city) => {
const weather = await getWeather(city);
return weather;
});
results
"#
.to_string(),
vec![],
vec!["getWeather".to_string()],
ResourceLimits::default(),
)?;
let mut state = runner.start(vec![])?;
// The VM suspends once per city — resolve each one
let mock_data = vec![
("London", "Rainy, 12°C"),
("Tokyo", "Clear, 26°C"),
("Paris", "Sunny, 22°C"),
];
for (expected_city, weather) in &mock_data {
match state {
VmState::Suspended {
function_name,
args,
snapshot,
} => {
println!(
" -> {}({}) = {}",
function_name,
args[0].to_js_string(),
weather
);
assert_eq!(function_name, "getWeather");
assert_eq!(args[0].to_js_string(), *expected_city);
state = snapshot.resume(Value::String((*weather).into()))?;
}
VmState::Complete(_) => panic!("expected suspension for {}", expected_city),
}
}
match state {
VmState::Complete(value) => {
println!("Async map result: {:?}", value);
// Array(["Rainy, 12°C", "Clear, 26°C", "Sunny, 22°C"])
}
_ => println!("Unexpected suspension after all cities resolved"),
}
Ok(())
}