on master help sign in
Handle errors better
ee74d88iko
nock/bad.hoonnew file+1
@@ -0,0 +1 @@
1+=/ foo [1 2] +(foo)
nock/src/interpreter.rs+3
@@ -9,6 +9,7 @@ use num_bigint::BigUint;
9use crate::jets::*;
9use crate::jets::*;
10use crate::noun::*;
10use crate::noun::*;
11
11
12+#[derive(Clone)]
12pub struct Nouns {
13pub struct Nouns {
13 pub y: Rc<Noun>,
14 pub y: Rc<Noun>,
14 pub n: Rc<Noun>,
15 pub n: Rc<Noun>,
@@ -23,6 +24,7 @@ pub struct Nouns {
23 pub mean: Rc<Noun>,
24 pub mean: Rc<Noun>,
24}
25}
25
26
27+#[derive(Clone)]
26pub struct BigUints {
28pub struct BigUints {
27 pub zero: BigUint,
29 pub zero: BigUint,
28 pub one: BigUint,
30 pub one: BigUint,
@@ -31,6 +33,7 @@ pub struct BigUints {
31 pub four: BigUint,
33 pub four: BigUint,
32}
34}
33
35
36+#[derive(Clone)]
34pub struct InterpreterContext {
37pub struct InterpreterContext {
35 pub jets: Jets,
38 pub jets: Jets,
36 pub double_jets: DoubleJets,
39 pub double_jets: DoubleJets,
nock/src/lib.rs+37−3
@@ -1,10 +1,11 @@
1#![feature(iter_intersperse)]
1#![feature(iter_intersperse)]
2#![feature(let_chains)]
2#![feature(let_chains)]
3−#![feature(iter_repeat_n)]
4
3
4+use core::str;
5−use std::rc::Rc;
5+use std::{borrow::Borrow, rc::Rc};
6
6
7+use interpreter::{eval_pulled_gate, slam_pulled_gate, tar, InterpreterContext, Tanks};
7−use noun::Noun;
8+use noun::{cell, Noun};
8pub mod cue;
9pub mod cue;
9pub mod interpreter;
10pub mod interpreter;
10pub mod jam;
11pub mod jam;
@@ -12,3 +13,36 @@ mod jets;
12pub mod noun;
13pub mod noun;
13
14
14pub type Vase = (Rc<Noun>, Rc<Noun>);
15pub type Vase = (Rc<Noun>, Rc<Noun>);
16+
17+pub fn wash(ctx: &mut InterpreterContext, urbit: &Rc<Noun>, tanks: Tanks) -> String {
18+ let mut target = String::new();
19+ for (subj, q) in tanks.iter() {
20+ match tar(ctx, subj.clone(), q).unwrap().borrow() {
21+ Noun::Atom(a) => {
22+ target.push_str(str::from_utf8_mut(&mut *a.to_bytes_le()).unwrap());
23+ }
24+ gate @ Noun::Cell { .. } => {
25+ let tank = eval_pulled_gate(ctx, Rc::new(gate.clone())).unwrap();
26+ let mut str = slam_pulled_gate(
27+ ctx,
28+ &urbit,
29+ &cell(
30+ &Rc::new(Noun::from_bytes(b"wash")),
31+ &cell(
32+ &cell(&Rc::new(Noun::from_u32(0)), &Rc::new(Noun::from_u32(80))),
33+ &tank,
34+ ),
35+ ),
36+ )
37+ .unwrap()
38+ .as_atom()
39+ .unwrap()
40+ .to_bytes_le();
41+
42+ target.push_str(str::from_utf8_mut(&mut *str).unwrap())
43+ }
44+ }
45+ }
46+
47+ target
48+}
nock/src/main.rs+39−39
@@ -1,6 +1,7 @@
1use clap::{command, error::Result, Parser, Subcommand};
1use clap::{command, error::Result, Parser, Subcommand};
2use core::str;
2use core::str;
3use nock::interpreter::{eval_pulled_gate, slam_pulled_gate, tar, InterpreterContext, Tanks};
3use nock::interpreter::{eval_pulled_gate, slam_pulled_gate, tar, InterpreterContext, Tanks};
4+use nock::wash;
4use nock::{
5use nock::{
5 cue::cue_bytes,
6 cue::cue_bytes,
6 interpreter::{generate_interpreter_context, slam},
7 interpreter::{generate_interpreter_context, slam},
@@ -8,6 +9,7 @@ use nock::{
8 noun::{cell, Atom, Noun},
9 noun::{cell, Atom, Noun},
9};
10};
10use spinoff::Spinner;
11use spinoff::Spinner;
12+use std::borrow::Borrow;
11use std::cell::LazyCell;
13use std::cell::LazyCell;
12use std::{
14use std::{
13 fs::File,
15 fs::File,
@@ -179,8 +181,14 @@ fn compile_to_nock(
179 ctx,
181 ctx,
180 &urbit,
182 &urbit,
181 &cell(&Rc::new(Noun::from_bytes(b"hoon")), &ctx.nouns.sig),
183 &cell(&Rc::new(Noun::from_bytes(b"hoon")), &ctx.nouns.sig),
182− )
184+ );
183− .unwrap();
185+ let hoon = or_wash_fail(
186+ ctx,
187+ urbit,
188+ hoon,
189+ spinner,
190+ "Failed to read Hoon standard library",
191+ );
184 let (hoon_type, hoon) = hoon.as_cell().unwrap();
192 let (hoon_type, hoon) = hoon.as_cell().unwrap();
185
193
186 spinner.update_text(format!("Compiling {root:#?}"));
194 spinner.update_text(format!("Compiling {root:#?}"));
@@ -197,25 +205,26 @@ fn compile_to_nock(
197 &Rc::new(Noun::Atom(Atom::from_bytes_le(&root_source))),
205 &Rc::new(Noun::Atom(Atom::from_bytes_le(&root_source))),
198 ),
206 ),
199 ),
207 ),
200− )
208+ );
201− .unwrap();
209+ let target = or_wash_fail(ctx, urbit, target, spinner, "Compilation failed");
202
210
203 let (target_type, target_nock) = target.as_cell().unwrap();
211 let (target_type, target_nock) = target.as_cell().unwrap();
204
212
205 spinner.update_text(format!("Combining Nock formulas"));
213 spinner.update_text(format!("Combining Nock formulas"));
206
214
207− Ok(cell(
215+ let combined_nock = slam_pulled_gate(
216+ ctx,
217+ &urbit,
218+ &cell(
219+ &Rc::new(Noun::from_bytes(b"comb")),
220+ &cell(hoon, target_nock),
221+ ),
222+ );
223+ let combined_nock = cell(
208 target_type,
224 target_type,
209− &slam_pulled_gate(
225+ &or_wash_fail(ctx, urbit, combined_nock, spinner, "Failed to combine Nock"),
210− ctx,
211− &urbit,
212− &cell(
213− &Rc::new(Noun::from_bytes(b"comb")),
214− &cell(hoon, target_nock),
215− ),
216− )
226+ );
217− .unwrap(),
227+ Ok(combined_nock)
218− ))
219}
228}
220
229
221fn read_nock_or_compile(
230fn read_nock_or_compile(
@@ -233,29 +242,20 @@ fn read_nock_or_compile(
233 }
242 }
234}
243}
235
244
245+fn or_wash_fail(
236−fn wash(ctx: &mut InterpreterContext, urbit: &Rc<Noun>, tanks: Tanks) -> String {
246+ ctx: &mut InterpreterContext,
237− let mut target = String::new();
247+ urbit: &Rc<Noun>,
238− for (subj, q) in tanks.iter() {
248+ source: Result<Rc<Noun>, Tanks>,
239− let gate = tar(ctx, subj.clone(), q).unwrap();
249+ spinner: &mut Spinner,
240− let tank = eval_pulled_gate(ctx, gate).unwrap();
250+ fail_err: &str,
241− let mut str = slam_pulled_gate(
251+) -> Rc<Noun> {
242− ctx,
252+ match source {
243− &urbit,
253+ Ok(source) => source,
244− &cell(
254+ Err(tanks) => {
245− &Rc::new(Noun::from_bytes(b"wash")),
255+ spinner.fail(fail_err);
246− &cell(
256+ let washed_tanks = wash(ctx, urbit, tanks);
247− &cell(&Rc::new(Noun::from_u32(0)), &Rc::new(Noun::from_u32(80))),
257+ eprintln!("{}", washed_tanks);
248− &tank,
258+ exit(1)
249− ),
259+ }
250− ),
251− )
252− .unwrap()
253− .as_atom()
254− .unwrap()
255− .to_bytes_le();
256−
257− target.push_str(str::from_utf8_mut(&mut *str).unwrap())
258 }
260 }
259−
260− target
261}
261}
wock-web/src/lib.rs+65−24
@@ -1,12 +1,8 @@
1#![feature(iter_collect_into)]
1#![feature(iter_collect_into)]
2mod utils;
2mod utils;
3
3
4−use std::{
4+use core::panic;
5− borrow::BorrowMut,
6− cell::RefCell,
5+use std::{cell::RefCell, rc::Rc};
7− ops::{Deref, DerefMut},
8− rc::Rc,
9−};
10
6
11use dodrio::{
7use dodrio::{
12 bumpalo::{self, Bump},
8 bumpalo::{self, Bump},
@@ -16,10 +12,11 @@ use nock::{
16 cue::cue_bytes,
12 cue::cue_bytes,
17 interpreter::{generate_interpreter_context, slam, InterpreterContext},
13 interpreter::{generate_interpreter_context, slam, InterpreterContext},
18 noun::{cell, Noun},
14 noun::{cell, Noun},
15+ wash,
19};
16};
20use wasm_bindgen::prelude::*;
17use wasm_bindgen::prelude::*;
21−use wasm_bindgen_futures::JsFuture;
18+use wasm_bindgen_futures::{spawn_local, JsFuture};
22−use web_sys::Element;
19+use web_sys::{console::error_1, Element};
23
20
24#[wasm_bindgen]
21#[wasm_bindgen]
25extern "C" {
22extern "C" {
@@ -32,22 +29,51 @@ extern "C" {
32 fn error(s: &str);
29 fn error(s: &str);
33}
30}
34
31
32+#[derive(Clone)]
35struct WockApp {
33struct WockApp {
36 nock: Rc<Noun>,
34 nock: Rc<Noun>,
37 ctx: RefCell<InterpreterContext>,
35 ctx: RefCell<InterpreterContext>,
38 model: Rc<Noun>,
36 model: Rc<Noun>,
37+ urbit: RefCell<Option<Rc<Noun>>>,
38+}
39+
40+impl WockApp {
41+ async fn get_urbit(self: &Self) -> Rc<Noun> {
42+ match self.urbit.borrow().clone() {
43+ Some(urbit) => urbit,
44+ None => {
45+ let urbit = load_nock("/urbit.nock").await.unwrap_or_else(|err| {
46+ error_1(&err);
47+ panic!("Could not load urbit.")
48+ });
49+
50+ self.urbit.replace(Some(urbit.clone()));
51+
52+ urbit
53+ }
54+ }
55+ }
39}
56}
40
57
41impl<'a> Render<'a> for WockApp {
58impl<'a> Render<'a> for WockApp {
42 fn render(&self, cx: &mut dodrio::RenderContext<'a>) -> dodrio::Node<'a> {
59 fn render(&self, cx: &mut dodrio::RenderContext<'a>) -> dodrio::Node<'a> {
43− let sail = slam(
60+ match slam(
44 &mut *self.ctx.borrow_mut(),
61 &mut *self.ctx.borrow_mut(),
45 &self.nock,
62 &self.nock,
46 &cell(&Rc::new(Noun::from_bytes(b"view")), &self.model),
63 &cell(&Rc::new(Noun::from_bytes(b"view")), &self.model),
47− )
64+ ) {
48− .unwrap();
49−
50− render_sail(cx, sail)
65+ Ok(sail) => render_sail(cx, sail),
66+ Err(tanks) => {
67+ let wock_app = self.clone();
68+ let mut ctx = (*self.ctx.borrow()).clone();
69+ spawn_local(async move {
70+ let urbit = wock_app.get_urbit().await;
71+ let str = wash(&mut ctx, &urbit, tanks);
72+ error_1(&JsValue::from_str(&str));
73+ });
74+ panic!("Could not render");
75+ }
76+ }
51 }
77 }
52}
78}
53
79
@@ -151,7 +177,10 @@ fn tape_to_bump_str<'a>(bump: &'a Bump, non: &Rc<Noun>) -> &'a str {
151
177
152#[wasm_bindgen]
178#[wasm_bindgen]
153pub async fn main(path: &str) {
179pub async fn main(path: &str) {
154− let nock = load_nock(path).await;
180+ let nock = load_nock(path).await.unwrap_or_else(|err| {
181+ error_1(&err);
182+ panic!("Could not load nock.")
183+ });
155
184
156 let document = gloo::utils::document();
185 let document = gloo::utils::document();
157 let output_el: Element = document.get_element_by_id("output").unwrap();
186 let output_el: Element = document.get_element_by_id("output").unwrap();
@@ -162,8 +191,20 @@ pub async fn main(path: &str) {
162 &mut ctx,
191 &mut ctx,
163 &nock,
192 &nock,
164 &cell(&Rc::new(Noun::from_bytes(b"init")), &Rc::new(Noun::SIG)),
193 &cell(&Rc::new(Noun::from_bytes(b"init")), &Rc::new(Noun::SIG)),
165− )
194+ );
166− .unwrap();
195+ let model = match model {
196+ Ok(model) => model,
197+ Err(tanks) => {
198+ let urbit = load_nock("/urbit.nock").await.unwrap_or_else(|err| {
199+ error_1(&err);
200+ panic!("Could not load urbit.")
201+ });
202+
203+ let str = wash(&mut ctx, &urbit, tanks);
204+ error_1(&JsValue::from_str(&str));
205+ panic!("Could not load initial model.");
206+ }
207+ };
167
208
168 dodrio::Vdom::new(
209 dodrio::Vdom::new(
169 &output_el,
210 &output_el,
@@ -171,26 +212,26 @@ pub async fn main(path: &str) {
171 nock,
212 nock,
172 model,
213 model,
173 ctx: RefCell::new(ctx),
214 ctx: RefCell::new(ctx),
215+ urbit: RefCell::new(None),
174 },
216 },
175 )
217 )
176 .forget();
218 .forget();
177}
219}
178
220
179−pub async fn load_nock(path: &str) -> Rc<Noun> {
221+pub async fn load_nock(path: &str) -> Result<Rc<Noun>, JsValue> {
180 let window = web_sys::window().unwrap();
222 let window = web_sys::window().unwrap();
181
223
182− let resp = JsFuture::from(window.fetch_with_str(path)).await.unwrap();
224+ let resp = JsFuture::from(window.fetch_with_str(path)).await?;
183 assert!(resp.is_instance_of::<web_sys::Response>());
225 assert!(resp.is_instance_of::<web_sys::Response>());
184− let resp: web_sys::Response = resp.dyn_into().unwrap();
226+ let resp: web_sys::Response = resp.dyn_into()?;
185− let blob = JsFuture::from(resp.blob().unwrap()).await.unwrap();
227+ let blob = JsFuture::from(resp.blob()?).await?;
186 assert!(blob.is_instance_of::<web_sys::Blob>());
228 assert!(blob.is_instance_of::<web_sys::Blob>());
187− let blob: web_sys::Blob = blob.dyn_into().unwrap();
229+ let blob: web_sys::Blob = blob.dyn_into()?;
188
230
189− let nock =
190− js_sys::Uint8Array::new(&JsFuture::from(blob.array_buffer()).await.unwrap()).to_vec();
231+ let nock = js_sys::Uint8Array::new(&JsFuture::from(blob.array_buffer()).await?).to_vec();
191
232
192 let nock = cue_bytes(&*nock);
233 let nock = cue_bytes(&*nock);
193 let (_typ, nok) = nock.as_cell().unwrap();
234 let (_typ, nok) = nock.as_cell().unwrap();
194
235
195− nok.clone()
236+ Ok(nok.clone())
196}
237}