Compare commits
5 Commits
808368d2b9
...
e5467e9e7e
Author | SHA1 | Date | |
---|---|---|---|
|
e5467e9e7e | ||
|
bba3e1e800 | ||
|
b7ff0eda80 | ||
|
5b2fd5e2d7 | ||
|
b12d0e00aa |
|
@ -1,6 +1,10 @@
|
||||||
&&& buffers: shared memory with Rust
|
&&& buffers: shared memory with Rust
|
||||||
|
& use types that are all either empty or any
|
||||||
box console = []
|
box console = []
|
||||||
box input = ""
|
box input = ""
|
||||||
|
box fetch_outbox = ""
|
||||||
|
box fetch_inbox = ()
|
||||||
|
box keys_down = []
|
||||||
|
|
||||||
& the very base: know something's type
|
& the very base: know something's type
|
||||||
fn type {
|
fn type {
|
||||||
|
@ -1244,7 +1248,7 @@ fn alive? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link! {
|
fn link! {
|
||||||
"Creates a 'hard link' between two processes: if either one dies, they both do."
|
"Creates a link between two processes. There are two types of links: `:report`, which sends a message to pid1 when pid2 dies; and `:enforce`, which causes a panic in one when the other dies. The default is `:report`."
|
||||||
(pid1 as :keyword, pid2 as :keyword) -> link! (pid1, pid2, :report)
|
(pid1 as :keyword, pid2 as :keyword) -> link! (pid1, pid2, :report)
|
||||||
(pid1 as :keyword, pid2 as :keyword, :report) -> base :process (:link_report, pid1, pid2)
|
(pid1 as :keyword, pid2 as :keyword, :report) -> base :process (:link_report, pid1, pid2)
|
||||||
(pid1 as :keyword, pid2 as :keyword, :enforce) -> base :process (:link_enforce, pid1, pid2)
|
(pid1 as :keyword, pid2 as :keyword, :enforce) -> base :process (:link_enforce, pid1, pid2)
|
||||||
|
@ -1260,7 +1264,63 @@ fn sleep! {
|
||||||
(ms as :number) -> base :process (:sleep, ms)
|
(ms as :number) -> base :process (:sleep, ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& TODO: make this more robust, to handle multiple pending requests w/o data races
|
||||||
|
fn request_fetch! {
|
||||||
|
(pid as :keyword, url as :string) -> {
|
||||||
|
store! (fetch_outbox, url)
|
||||||
|
request_fetch! (pid)
|
||||||
|
}
|
||||||
|
(pid as :keyword) -> {
|
||||||
|
if empty? (unbox (fetch_inbox))
|
||||||
|
then {
|
||||||
|
yield! ()
|
||||||
|
request_fetch! (pid)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
send (pid, (:reply, unbox (fetch_inbox)))
|
||||||
|
store! (fetch_inbox, ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch {
|
||||||
|
"Requests the contents of the URL passed in. Returns a result tuple of `(:ok, {contents})` or `(:err, {status code})`."
|
||||||
|
(url) -> {
|
||||||
|
let pid = self ()
|
||||||
|
spawn! (fn () -> request_fetch! (pid, url))
|
||||||
|
receive {
|
||||||
|
(:reply, response) -> response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_reader! {
|
||||||
|
(pid as :keyword) -> {
|
||||||
|
if empty? (unbox (input))
|
||||||
|
then {
|
||||||
|
yield! ()
|
||||||
|
input_reader! (pid)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
send (pid, (:reply, unbox (input)))
|
||||||
|
store! (input, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input {
|
||||||
|
"Waits until there is input in the input buffer, and returns it once there is."
|
||||||
|
() -> {
|
||||||
|
let pid = self ()
|
||||||
|
spawn! (fn () -> input_reader! (pid))
|
||||||
|
receive {
|
||||||
|
(:reply, response) -> response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#{
|
#{
|
||||||
|
& completed actor functions
|
||||||
self
|
self
|
||||||
send
|
send
|
||||||
spawn!
|
spawn!
|
||||||
|
@ -1269,11 +1329,20 @@ fn sleep! {
|
||||||
alive?
|
alive?
|
||||||
flush!
|
flush!
|
||||||
|
|
||||||
link!
|
& wip actor functions
|
||||||
|
& link!
|
||||||
|
|
||||||
|
& shared memory w/ rust
|
||||||
console
|
console
|
||||||
input
|
input
|
||||||
|
fetch_outbox
|
||||||
|
fetch_inbox
|
||||||
|
keys_down
|
||||||
|
|
||||||
|
& a fetch fn
|
||||||
|
fetch
|
||||||
|
read_input
|
||||||
|
|
||||||
abs
|
abs
|
||||||
abs
|
abs
|
||||||
add
|
add
|
||||||
|
|
|
@ -1193,17 +1193,17 @@ We've got one bug to address in Firefox before I continue:
|
||||||
After that:
|
After that:
|
||||||
* [ ] implement other verbs beside `console`:
|
* [ ] implement other verbs beside `console`:
|
||||||
- [x] `command`
|
- [x] `command`
|
||||||
- [ ] `input`
|
- [x] `input`
|
||||||
* [ ] js->rust->ludus buffer (in Rust code)
|
* [x] js->rust->ludus buffer (in Rust code)
|
||||||
* [ ] ludus abstractions around this buffer (in Ludus code)
|
* [x] ludus abstractions around this buffer (in Ludus code)
|
||||||
- [ ] `fetch`--request & response
|
- [x] `fetch`--request & response
|
||||||
* [ ] request: ludus->rust->js->net
|
* [x] request: ludus->rust->js->net
|
||||||
* [ ] response: js->rust->ludus
|
* [x] response: js->rust->ludus
|
||||||
- [ ] `keyboard`
|
- [ ] `keyboard`
|
||||||
* [ ] still working on how to represent this
|
* [ ] still working on how to represent this
|
||||||
* [ ] hook this up to `web.ludus.dev`
|
* [ ] hook this up to `web.ludus.dev`
|
||||||
* [ ] do some integration testing
|
* [ ] do some integration testing
|
||||||
- [ ] do synchronous programs still work?
|
- [x] do synchronous programs still work?
|
||||||
- [ ] animations?
|
- [ ] animations?
|
||||||
- [ ] read inputs?
|
- [ ] read inputs?
|
||||||
- [ ] load url text?
|
- [ ] load url text?
|
||||||
|
|
22
pkg/ludus.js
22
pkg/ludus.js
|
@ -13,7 +13,7 @@ let io_interval_id = null
|
||||||
|
|
||||||
worker.onmessage = handle_messages
|
worker.onmessage = handle_messages
|
||||||
|
|
||||||
function handle_messages (e) {
|
async function handle_messages (e) {
|
||||||
let msgs
|
let msgs
|
||||||
try {
|
try {
|
||||||
msgs = JSON.parse(e.data)
|
msgs = JSON.parse(e.data)
|
||||||
|
@ -23,25 +23,32 @@ function handle_messages (e) {
|
||||||
}
|
}
|
||||||
for (const msg of msgs) {
|
for (const msg of msgs) {
|
||||||
switch (msg.verb) {
|
switch (msg.verb) {
|
||||||
case "complete": {
|
case "Complete": {
|
||||||
console.log("Main: ludus completed with => ", msg.data)
|
console.log("Main: ludus completed with => ", msg.data)
|
||||||
ludus_result = msg.data
|
ludus_result = msg.data
|
||||||
running = false
|
running = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// TODO: do more than report these
|
// TODO: do more than report these
|
||||||
case "console": {
|
case "Console": {
|
||||||
console.log("Main: ludus says => ", msg.data)
|
console.log("Main: ludus says => ", msg.data)
|
||||||
ludus_console = ludus_console + msg.data
|
ludus_console = ludus_console + msg.data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "commands": {
|
case "Commands": {
|
||||||
console.log("Main: ludus commands => ", msg.data)
|
console.log("Main: ludus commands => ", msg.data)
|
||||||
for (const command of msg.data) {
|
for (const command of msg.data) {
|
||||||
ludus_commands.push(command)
|
ludus_commands.push(command)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case "Fetch": {
|
||||||
|
console.log("Main: ludus requests => ", msg.data)
|
||||||
|
const res = await fetch(msg.data, {mode: "cors"})
|
||||||
|
const text = await res.text()
|
||||||
|
console.log("Main: js responds => ", text)
|
||||||
|
outbox.push({verb: "Fetch", data: [msg.data, res.status, text]})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,8 +74,9 @@ function start_io_polling () {
|
||||||
export function run (source) {
|
export function run (source) {
|
||||||
if (running) "TODO: handle this? should not be running"
|
if (running) "TODO: handle this? should not be running"
|
||||||
running = true
|
running = true
|
||||||
|
result = null
|
||||||
code = source
|
code = source
|
||||||
outbox = [{verb: "run", data: source}]
|
outbox = [{verb: "Run", data: source}]
|
||||||
start_io_polling()
|
start_io_polling()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,12 +88,12 @@ export function is_running() {
|
||||||
// kills a ludus script
|
// kills a ludus script
|
||||||
export function kill () {
|
export function kill () {
|
||||||
running = false
|
running = false
|
||||||
outbox.push({verb: "kill"})
|
outbox.push({verb: "Kill"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// sends text into ludus (status: not working)
|
// sends text into ludus (status: not working)
|
||||||
export function input (text) {
|
export function input (text) {
|
||||||
outbox.push({verb: "input", data: text})
|
outbox.push({verb: "Input", data: text})
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the contents of the ludus console and resets the console
|
// returns the contents of the ludus console and resets the console
|
||||||
|
|
4
pkg/rudus.d.ts
vendored
4
pkg/rudus.d.ts
vendored
|
@ -14,8 +14,8 @@ export interface InitOutput {
|
||||||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||||
readonly __wbindgen_export_6: WebAssembly.Table;
|
readonly __wbindgen_export_6: WebAssembly.Table;
|
||||||
readonly closure323_externref_shim: (a: number, b: number, c: any) => void;
|
readonly closure328_externref_shim: (a: number, b: number, c: any) => void;
|
||||||
readonly closure336_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
readonly closure341_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||||
readonly __wbindgen_start: () => void;
|
readonly __wbindgen_start: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
pkg/rudus.js
15
pkg/rudus.js
|
@ -146,11 +146,11 @@ export function ludus(src) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function __wbg_adapter_20(arg0, arg1, arg2) {
|
function __wbg_adapter_20(arg0, arg1, arg2) {
|
||||||
wasm.closure323_externref_shim(arg0, arg1, arg2);
|
wasm.closure328_externref_shim(arg0, arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function __wbg_adapter_48(arg0, arg1, arg2, arg3) {
|
function __wbg_adapter_50(arg0, arg1, arg2, arg3) {
|
||||||
wasm.closure336_externref_shim(arg0, arg1, arg2, arg3);
|
wasm.closure341_externref_shim(arg0, arg1, arg2, arg3);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function __wbg_load(module, imports) {
|
async function __wbg_load(module, imports) {
|
||||||
|
@ -229,6 +229,9 @@ function __wbg_get_imports() {
|
||||||
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
|
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
imports.wbg.__wbg_log_9e426f8e841e42d3 = function(arg0, arg1) {
|
||||||
|
console.log(getStringFromWasm0(arg0, arg1));
|
||||||
|
};
|
||||||
imports.wbg.__wbg_log_edeb598b620f1ba2 = function(arg0, arg1) {
|
imports.wbg.__wbg_log_edeb598b620f1ba2 = function(arg0, arg1) {
|
||||||
let deferred0_0;
|
let deferred0_0;
|
||||||
let deferred0_1;
|
let deferred0_1;
|
||||||
|
@ -247,7 +250,7 @@ function __wbg_get_imports() {
|
||||||
const a = state0.a;
|
const a = state0.a;
|
||||||
state0.a = 0;
|
state0.a = 0;
|
||||||
try {
|
try {
|
||||||
return __wbg_adapter_48(a, state0.b, arg0, arg1);
|
return __wbg_adapter_50(a, state0.b, arg0, arg1);
|
||||||
} finally {
|
} finally {
|
||||||
state0.a = a;
|
state0.a = a;
|
||||||
}
|
}
|
||||||
|
@ -325,8 +328,8 @@ function __wbg_get_imports() {
|
||||||
const ret = false;
|
const ret = false;
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper969 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper985 = function(arg0, arg1, arg2) {
|
||||||
const ret = makeMutClosure(arg0, arg1, 324, __wbg_adapter_20);
|
const ret = makeMutClosure(arg0, arg1, 329, __wbg_adapter_20);
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_init_externref_table = function() {
|
imports.wbg.__wbindgen_init_externref_table = function() {
|
||||||
|
|
Binary file not shown.
4
pkg/rudus_bg.wasm.d.ts
vendored
4
pkg/rudus_bg.wasm.d.ts
vendored
|
@ -9,6 +9,6 @@ export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
||||||
export const __wbindgen_malloc: (a: number, b: number) => number;
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
||||||
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||||
export const __wbindgen_export_6: WebAssembly.Table;
|
export const __wbindgen_export_6: WebAssembly.Table;
|
||||||
export const closure323_externref_shim: (a: number, b: number, c: any) => void;
|
export const closure328_externref_shim: (a: number, b: number, c: any) => void;
|
||||||
export const closure336_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
export const closure341_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||||
export const __wbindgen_start: () => void;
|
export const __wbindgen_start: () => void;
|
||||||
|
|
|
@ -36,7 +36,7 @@ async function run(e) {
|
||||||
let msgs = e.data
|
let msgs = e.data
|
||||||
for (const msg of msgs) {
|
for (const msg of msgs) {
|
||||||
// evaluate source if we get some
|
// evaluate source if we get some
|
||||||
if (msg.verb === "run" && typeof msg.data === 'string') {
|
if (msg.verb === "Run" && typeof msg.data === 'string') {
|
||||||
// temporarily stash an empty function so we don't keep calling this one if we receive additional messages
|
// temporarily stash an empty function so we don't keep calling this one if we receive additional messages
|
||||||
onmessage = () => {}
|
onmessage = () => {}
|
||||||
// actually run the ludus--which will call `io`--and replace `run` as the event handler for ipc
|
// actually run the ludus--which will call `io`--and replace `run` as the event handler for ipc
|
||||||
|
|
35
src/io.rs
35
src/io.rs
|
@ -31,7 +31,7 @@ fn make_json_payload(verb: &'static str, data: String) -> String {
|
||||||
pub enum MsgOut {
|
pub enum MsgOut {
|
||||||
Console(Lines),
|
Console(Lines),
|
||||||
Commands(Commands),
|
Commands(Commands),
|
||||||
SlurpRequest(Url),
|
Fetch(Url),
|
||||||
Complete(FinalValue),
|
Complete(FinalValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,28 +46,27 @@ impl MsgOut {
|
||||||
match self {
|
match self {
|
||||||
MsgOut::Complete(value) => match value {
|
MsgOut::Complete(value) => match value {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
log(format!("value is: {}", value.show()));
|
make_json_payload("Complete", serde_json::to_string(&value.show()).unwrap())
|
||||||
make_json_payload("complete", serde_json::to_string(&value.show()).unwrap())
|
|
||||||
},
|
},
|
||||||
Err(_) => make_json_payload("complete", "\"null\"".to_string())
|
Err(_) => make_json_payload("Complete", "\"null\"".to_string())
|
||||||
},
|
},
|
||||||
MsgOut::Commands(commands) => {
|
MsgOut::Commands(commands) => {
|
||||||
let commands = commands.as_list();
|
let commands = commands.as_list();
|
||||||
let vals_json = commands.iter().map(|v| v.to_json().unwrap()).collect::<Vec<_>>().join(",");
|
let vals_json = commands.iter().map(|v| v.to_json().unwrap()).collect::<Vec<_>>().join(",");
|
||||||
let vals_json = format!("[{vals_json}]");
|
let vals_json = format!("[{vals_json}]");
|
||||||
make_json_payload("commands", vals_json)
|
make_json_payload("Commands", vals_json)
|
||||||
}
|
}
|
||||||
MsgOut::SlurpRequest(value) => {
|
MsgOut::Fetch(value) => {
|
||||||
// TODO: do parsing here?
|
// TODO: do parsing here?
|
||||||
// Right now, defer to fetch
|
// Right now, defer to fetch
|
||||||
let url = value.to_json().unwrap();
|
let url = value.to_json().unwrap();
|
||||||
make_json_payload("slurp", url)
|
make_json_payload("Fetch", url)
|
||||||
}
|
}
|
||||||
MsgOut::Console(lines) => {
|
MsgOut::Console(lines) => {
|
||||||
let lines = lines.as_list();
|
let lines = lines.as_list();
|
||||||
let json_lines = lines.iter().map(|line| line.stringify()).collect::<Vec<_>>().join("\\n");
|
let json_lines = lines.iter().map(|line| line.stringify()).collect::<Vec<_>>().join("\\n");
|
||||||
let json_lines = format!("\"{json_lines}\"");
|
let json_lines = format!("\"{json_lines}\"");
|
||||||
make_json_payload("console", json_lines)
|
make_json_payload("Console", json_lines)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +76,7 @@ impl MsgOut {
|
||||||
#[serde(tag = "verb", content = "data")]
|
#[serde(tag = "verb", content = "data")]
|
||||||
pub enum MsgIn {
|
pub enum MsgIn {
|
||||||
Input(String),
|
Input(String),
|
||||||
SlurpResponse(String, String, String),
|
Fetch(String, f64, String),
|
||||||
Kill,
|
Kill,
|
||||||
Keyboard(Vec<String>),
|
Keyboard(Vec<String>),
|
||||||
}
|
}
|
||||||
|
@ -85,8 +84,9 @@ pub enum MsgIn {
|
||||||
impl std::fmt::Display for MsgIn {
|
impl std::fmt::Display for MsgIn {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
MsgIn::Input(str) => write!(f, "input: {str}"),
|
MsgIn::Input(str) => write!(f, "Input: {str}"),
|
||||||
MsgIn::Kill => write!(f, "kill"),
|
MsgIn::Kill => write!(f, "Kill"),
|
||||||
|
MsgIn::Fetch(url, code, text) => write!(f, "Fetch: {url} :: {code} ::\n{text}"),
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,11 +96,15 @@ impl MsgIn {
|
||||||
pub fn to_value(self) -> Value {
|
pub fn to_value(self) -> Value {
|
||||||
match self {
|
match self {
|
||||||
MsgIn::Input(str) => Value::string(str),
|
MsgIn::Input(str) => Value::string(str),
|
||||||
MsgIn::SlurpResponse(url, status, string) => {
|
MsgIn::Fetch(url, status_f64, string) => {
|
||||||
let url = Value::string(url);
|
let url = Value::string(url);
|
||||||
let status = Value::keyword(status);
|
let status = Value::Number(status_f64);
|
||||||
let string = Value::string(string);
|
let text = Value::string(string);
|
||||||
let result_tuple = Value::tuple(vec![status, string]);
|
let result_tuple = if status_f64 == 200.0 {
|
||||||
|
Value::tuple(vec![Value::keyword("ok".to_string()), text])
|
||||||
|
} else {
|
||||||
|
Value::tuple(vec![Value::keyword("err".to_string()), status])
|
||||||
|
};
|
||||||
Value::tuple(vec![url, result_tuple])
|
Value::tuple(vec![url, result_tuple])
|
||||||
}
|
}
|
||||||
MsgIn::Kill => Value::Nothing,
|
MsgIn::Kill => Value::Nothing,
|
||||||
|
@ -124,6 +128,7 @@ pub async fn do_io (msgs: Vec<MsgOut>) -> Vec<MsgIn> {
|
||||||
Err(_) => return vec![]
|
Err(_) => return vec![]
|
||||||
};
|
};
|
||||||
let inbox = inbox.as_string().expect("response should be a string");
|
let inbox = inbox.as_string().expect("response should be a string");
|
||||||
|
// log(format!("got a message: {inbox}"));
|
||||||
let inbox: Vec<MsgIn> = serde_json::from_str(inbox.as_str()).expect("response from js should be valid");
|
let inbox: Vec<MsgIn> = serde_json::from_str(inbox.as_str()).expect("response from js should be valid");
|
||||||
if !inbox.is_empty() {
|
if !inbox.is_empty() {
|
||||||
log("ludus received messages".to_string());
|
log("ludus received messages".to_string());
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -60,9 +60,9 @@ fn prelude() -> HashMap<&'static str, Value> {
|
||||||
.into_output_errors();
|
.into_output_errors();
|
||||||
|
|
||||||
if !parse_errors.is_empty() {
|
if !parse_errors.is_empty() {
|
||||||
println!("ERROR PARSING PRELUDE:");
|
log("ERROR PARSING PRELUDE:");
|
||||||
println!("{:?}", parse_errors);
|
log(format!("{:?}", parse_errors).as_str());
|
||||||
panic!();
|
panic!("parsing errors in prelude");
|
||||||
}
|
}
|
||||||
|
|
||||||
let parsed = parsed.unwrap();
|
let parsed = parsed.unwrap();
|
||||||
|
@ -77,8 +77,9 @@ fn prelude() -> HashMap<&'static str, Value> {
|
||||||
validator.validate();
|
validator.validate();
|
||||||
|
|
||||||
if !validator.errors.is_empty() {
|
if !validator.errors.is_empty() {
|
||||||
println!("VALIDATION ERRORS IN PRLUDE:");
|
log("VALIDATION ERRORS IN PRLUDE:");
|
||||||
report_invalidation(validator.errors);
|
// report_invalidation(validator.errors);
|
||||||
|
log(format!("{:?}", validator.errors).as_str());
|
||||||
panic!("validator errors in prelude");
|
panic!("validator errors in prelude");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
src/value.rs
15
src/value.rs
|
@ -398,6 +398,21 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_string(&self) -> Rc<String> {
|
||||||
|
match self {
|
||||||
|
Value::String(str) => str.clone(),
|
||||||
|
Value::Interned(str) => Rc::new(str.to_string()),
|
||||||
|
_ => unreachable!("expected value to be a string"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_tuple(&self) -> Rc<Vec<Value>> {
|
||||||
|
match self {
|
||||||
|
Value::Tuple(members) => members.clone(),
|
||||||
|
_ => unreachable!("expected value to be a tuple"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn string(str: String) -> Value {
|
pub fn string(str: String) -> Value {
|
||||||
Value::String(Rc::new(str))
|
Value::String(Rc::new(str))
|
||||||
}
|
}
|
||||||
|
|
49
src/world.rs
49
src/world.rs
|
@ -254,8 +254,8 @@ impl Zoo {
|
||||||
pub struct Buffers {
|
pub struct Buffers {
|
||||||
console: Value,
|
console: Value,
|
||||||
commands: Value,
|
commands: Value,
|
||||||
// fetch_outbox: Value,
|
fetch_out: Value,
|
||||||
// fetch_inbox: Value,
|
fetch_in: Value,
|
||||||
input: Value,
|
input: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,8 +264,8 @@ impl Buffers {
|
||||||
Buffers {
|
Buffers {
|
||||||
console: prelude.get("console").unwrap().clone(),
|
console: prelude.get("console").unwrap().clone(),
|
||||||
commands: prelude.get("turtle_commands").unwrap().clone(),
|
commands: prelude.get("turtle_commands").unwrap().clone(),
|
||||||
// fetch_outbox: prelude.get("fetch_outbox").unwrap().clone(),
|
fetch_out: prelude.get("fetch_outbox").unwrap().clone(),
|
||||||
// fetch_inbox: prelude.get("fetch_inbox").unwrap().clone(),
|
fetch_in: prelude.get("fetch_inbox").unwrap().clone(),
|
||||||
input: prelude.get("input").unwrap().clone(),
|
input: prelude.get("input").unwrap().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,12 +282,13 @@ impl Buffers {
|
||||||
self.commands.as_box()
|
self.commands.as_box()
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn fetch_outbox (&self) -> Rc<RefCell<Value>> {
|
pub fn fetch_out (&self) -> Rc<RefCell<Value>> {
|
||||||
// self.fetch_outbox.as_box()
|
self.fetch_out.as_box()
|
||||||
// }
|
}
|
||||||
// pub fn fetch_inbox (&self) -> Rc<RefCell<Value>> {
|
|
||||||
// self.fetch_inbox.as_box()
|
pub fn fetch_in (&self) -> Rc<RefCell<Value>> {
|
||||||
// }
|
self.fetch_in.as_box()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,16 +370,34 @@ impl World {
|
||||||
if let Some(commands) = self.flush_commands() {
|
if let Some(commands) = self.flush_commands() {
|
||||||
outbox.push(commands);
|
outbox.push(commands);
|
||||||
}
|
}
|
||||||
|
if let Some(fetch) = self.make_fetch_happen() {
|
||||||
|
outbox.push(fetch);
|
||||||
|
}
|
||||||
outbox
|
outbox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_fetch_happen(&self) -> Option<MsgOut> {
|
||||||
|
let out = self.buffers.fetch_out();
|
||||||
|
let working = RefCell::new(Value::Interned(""));
|
||||||
|
out.swap(&working);
|
||||||
|
let working = working.borrow();
|
||||||
|
if working.as_string().is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(MsgOut::Fetch(working.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn flush_console(&self) -> Option<MsgOut> {
|
fn flush_console(&self) -> Option<MsgOut> {
|
||||||
let console = self.buffers.console();
|
let console = self.buffers.console();
|
||||||
let working_copy = RefCell::new(Value::new_list());
|
let working_copy = RefCell::new(Value::new_list());
|
||||||
console.swap(&working_copy);
|
console.swap(&working_copy);
|
||||||
let working_value = working_copy.borrow();
|
let working_value = working_copy.borrow();
|
||||||
if working_value.as_list().is_empty() { return None; }
|
if working_value.as_list().is_empty() {
|
||||||
Some(MsgOut::Console(working_value.clone()))
|
None
|
||||||
|
} else {
|
||||||
|
Some(MsgOut::Console(working_value.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_commands(&self) -> Option<MsgOut> {
|
fn flush_commands(&self) -> Option<MsgOut> {
|
||||||
|
@ -422,11 +441,17 @@ impl World {
|
||||||
input.swap(&working);
|
input.swap(&working);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch_reply(&mut self, reply: Value) {
|
||||||
|
let inbox_rc = self.buffers.fetch_in();
|
||||||
|
inbox_rc.replace(reply);
|
||||||
|
}
|
||||||
|
|
||||||
fn fill_buffers(&mut self, inbox: Vec<MsgIn>) {
|
fn fill_buffers(&mut self, inbox: Vec<MsgIn>) {
|
||||||
for msg in inbox {
|
for msg in inbox {
|
||||||
match msg {
|
match msg {
|
||||||
MsgIn::Input(str) => self.fill_input(str),
|
MsgIn::Input(str) => self.fill_input(str),
|
||||||
MsgIn::Kill => self.kill_signal = true,
|
MsgIn::Kill => self.kill_signal = true,
|
||||||
|
MsgIn::Fetch(..) => self.fetch_reply(msg.to_value()),
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user