summaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rwxr-xr-xsrc/lib.rs227
1 files changed, 94 insertions, 133 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 371d30f..7f65a80 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,116 +4,70 @@ use wasm_bindgen::prelude::*;
pub mod forth;
pub mod robo;
-#[wasm_bindgen]
-pub struct ExportedInstructionPointer {
- pub word: usize,
- pub offset: usize,
-}
+use web_sys::js_sys;
-impl From<&forth::vm::InstructionPointer> for ExportedInstructionPointer {
- fn from(ip: &forth::vm::InstructionPointer) -> Self {
- Self {
- word: ip.word,
- offset: ip.offset,
- }
- }
+fn tr_op(op: &forth::vm::OpCode) -> String {
+ use forth::vm::OpCode::*;
+ let s = match op {
+ If(t, None) => format!("If({t}, none)"),
+ If(t, Some(f)) => format!("If({t}, {f})"),
+ TIf(t, None) => format!("TIf({t}, none)"),
+ TIf(t, Some(f)) => format!("TIf({t}, {f})"),
+ other => format!("{other:?}"),
+ };
+ s.to_string()
}
-// wasm can't wrap Vec<Vec<String>>, so we need a custom type
-// - 23-aug-2025
-#[wasm_bindgen]
-pub struct ExportedByteCode(Vec<String>);
-
-impl ExportedByteCode {
- fn tr_op(op: &forth::vm::OpCode) -> String {
- use forth::vm::OpCode::*;
- let s = match op {
- If(t, None) => format!("If({t}, none)"),
- If(t, Some(f)) => format!("If({t}, {f})"),
- TIf(t, None) => format!("TIf({t}, none)"),
- TIf(t, Some(f)) => format!("TIf({t}, {f})"),
- other => format!("{other:?}"),
- };
- s.to_string()
- }
+fn map_set<T: Into::<JsValue>>(m: &js_sys::Map, k: &str, v: T) {
+ let jk: js_sys::JsString = k.to_string().into();
+ let jv = v.into();
+ m.set(&jk, &jv);
}
-impl From<&forth::vm::ByteCode> for ExportedByteCode {
- fn from(v: &forth::vm::ByteCode) -> Self {
- Self(v.iter().map(Self::tr_op).collect())
- }
-}
-
-#[wasm_bindgen]
-impl ExportedByteCode {
- pub fn len(&self) -> usize {
- self.0.len()
- }
-
- pub fn is_empty(&self) -> bool {
- self.0.is_empty()
- }
+impl From<&forth::vm::InstructionPointer> for js_sys::Map {
+ fn from(ip: &forth::vm::InstructionPointer) -> Self {
+ let res = Self::new();
- pub fn at(&self, offset: usize) -> String {
- self.0[offset].clone()
- }
-}
+ let w: js_sys::JsString = "word".to_string().into();
+ let wv = (ip.word as i32).into();
+ res.set(&w, &wv);
-// ibid.
-#[wasm_bindgen]
-#[derive(Clone)]
-pub struct ExportedAnnotation {
- pub start: usize,
- pub end: usize,
-}
+ let o: js_sys::JsString = "offset".to_string().into();
+ let ov = (ip.offset as i32).into();
+ res.set(&o, &ov);
-impl From<&forth::compiler::Annotation> for ExportedAnnotation {
- fn from(v: &forth::compiler::Annotation) -> Self {
- Self {
- start: v.loc.0,
- end: v.loc.1,
- }
+ res
}
}
-// ibid.
-#[wasm_bindgen]
-#[derive(Clone)]
-pub struct ExportedWordAnnotations(Vec<ExportedAnnotation>);
+impl From<&forth::compiler::Annotation> for js_sys::Map {
+ fn from(anno: &forth::compiler::Annotation) -> Self {
+ let res = Self::new();
-impl FromIterator<ExportedAnnotation> for ExportedWordAnnotations {
- fn from_iter<T: IntoIterator<Item = ExportedAnnotation>>(iter: T) -> Self {
- ExportedWordAnnotations(iter.into_iter().collect())
- }
-}
+ let w: js_sys::JsString = "start".to_string().into();
+ let wv = (anno.loc.0 as i32).into();
+ res.set(&w, &wv);
-#[wasm_bindgen]
-impl ExportedWordAnnotations {
- pub fn len(&self) -> usize {
- self.0.len()
- }
+ let o: js_sys::JsString = "end".to_string().into();
+ let ov = (anno.loc.1 as i32).into();
+ res.set(&o, &ov);
- pub fn is_empty(&self) -> bool {
- self.0.is_empty()
- }
-
- pub fn at(&self, offset: usize) -> ExportedAnnotation {
- self.0[offset].clone()
+ res
}
}
#[wasm_bindgen]
pub struct ExportedVM {
- annos: Vec<ExportedWordAnnotations>,
vm: Option<forth::vm::VM>,
+ annos: Vec<Vec<forth::compiler::Annotation>>,
}
#[wasm_bindgen]
impl ExportedVM {
fn new() -> Self {
Self {
- annos: vec![],
vm: None,
+ annos: vec![],
}
}
@@ -123,15 +77,10 @@ impl ExportedVM {
error!("couldn't compile program text: {e:?}");
return false;
}
- self.annos = comp
- .annotations
- .iter()
- .map(|word_anno| -> ExportedWordAnnotations {
- word_anno.iter().map(|a| a.into()).collect()
- })
- .collect();
+
let vm = forth::vm::VM::new(comp.wordlist);
let _ = self.vm.insert(vm);
+ self.annos = comp.annotations;
true
}
@@ -152,38 +101,6 @@ impl ExportedVM {
vm.run().map_err(|err| format!("runtime error: {err:?}"))
}
- pub fn stack(&self) -> Vec<forth::vm::DataStackType> {
- let Some(vm) = &self.vm else { return vec![] };
-
- vm.stack.0.clone()
- }
-
- pub fn wordlist(&self) -> Vec<ExportedByteCode> {
- let Some(vm) = &self.vm else { return vec![] };
-
- vm.wordlist.iter().map(|bc| bc.into()).collect()
- }
-
- pub fn annotations(&self) -> Vec<ExportedWordAnnotations> {
- self.annos.clone()
- }
-
- pub fn annotation_at(&self, ip: &ExportedInstructionPointer) -> ExportedAnnotation {
- self.annos[ip.word].0[ip.offset].clone()
- }
-
- pub fn callstack(&self) -> Vec<ExportedInstructionPointer> {
- let Some(vm) = &self.vm else { return vec![] };
- vm.callstack.0.iter().map(|ip| ip.into()).collect()
- }
-
- pub fn ip(&self) -> ExportedInstructionPointer {
- let Some(vm) = &self.vm else {
- return ExportedInstructionPointer { word: 0, offset: 0 };
- };
- (&vm.ip).into()
- }
-
pub fn reset_ip(&mut self) {
let Some(vm) = &mut self.vm else {
return;
@@ -199,19 +116,63 @@ impl ExportedVM {
res
}
- pub fn heading(&mut self) -> isize {
- let Some(vm) = &self.vm else { return 0 };
- vm.heading
- }
+ pub fn trans(&mut self) -> js_sys::Object {
+ let Some(vm) = &self.vm else { return js_sys::Object::new() };
- pub fn speed(&mut self) -> isize {
- let Some(vm) = &self.vm else { return 0 };
- vm.speed
- }
+ let res = js_sys::Map::new();
+
+ // wordlist
+ let wl = vm.wordlist.iter().map(
+ |dfn| {
+ let ops =
+ dfn.iter()
+ .map(|op| {
+ Into::<js_sys::JsString>::into(tr_op(op))
+ });
+ js_sys::Array::from_iter(ops)
+ }
+ );
+ map_set(&res, "wordlist", js_sys::Array::from_iter(wl));
+
+ // annotations
+ let annos = self.annos.iter().map(
+ |dfn| {
+ let ops =
+ dfn.iter()
+ .map(|anno| {
+ let a: js_sys::Map = anno.into();
+ let o: js_sys::Object = js_sys::Object::from_entries(&a).expect("can't make object from anno map");
+ o
+ });
+ js_sys::Array::from_iter(ops)
+ }
+ );
+ map_set(&res, "annos", js_sys::Array::from_iter(annos));
+
+ // instruction pointer
+ let ip: js_sys::Map = (&vm.ip).into();
+ let o: js_sys::Object = js_sys::Object::from_entries(&ip).expect("can't make object from ip map");
+ map_set(&res, "ip", o);
+
+ // stack
+ let s = vm.stack.0.iter().map(|v| Into::<JsValue>::into(*v as i32));
+ map_set(&res, "stack", js_sys::Array::from_iter(s));
+
+ // callstack
+ let cs = vm.callstack.0.iter().map(|v| {
+ let ip: js_sys::Map = v.into();
+ let o: js_sys::Object = js_sys::Object::from_entries(&ip).expect("can't make object from ip map");
+ o
+ });
+ map_set(&res, "callstack", js_sys::Array::from_iter(cs));
+
+ let vars = js_sys::Map::new();
+ map_set::<isize>(&vars, "heading", vm.heading.into());
+ map_set::<isize>(&vars, "speed", vm.speed.into());
+ map_set::<isize>(&vars, "doppler", vm.doppler.into());
+ map_set(&res, "vars", js_sys::Object::from_entries(&vars).expect("can't make object from vars map"));
- pub fn doppler(&mut self) -> isize {
- let Some(vm) = &self.vm else { return 0 };
- vm.doppler
+ js_sys::Object::from_entries(&res).expect("can't make object from results map")
}
}