string keys on dicts now fully work
This commit is contained in:
parent
659fdd3506
commit
9f9f59b33b
|
@ -17,3 +17,4 @@ wasm-bindgen-futures = "0.4.50"
|
|||
serde = {version = "1.0", features = ["derive"]}
|
||||
serde_json = "1.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
struct_scalpel = "0.1.1"
|
||||
|
|
|
@ -879,6 +879,12 @@ fn get {
|
|||
nil -> default
|
||||
val -> val
|
||||
}
|
||||
(k as :string) -> get (k, _)
|
||||
(k as :string, d as :dict) -> base :get (d, k)
|
||||
(k as :string, d as :dict, default) -> match base :get (d, k) with {
|
||||
nil -> default
|
||||
val -> val
|
||||
}
|
||||
}
|
||||
|
||||
fn update {
|
||||
|
|
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_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly __wbindgen_export_6: WebAssembly.Table;
|
||||
readonly closure346_externref_shim: (a: number, b: number, c: any) => void;
|
||||
readonly closure370_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly closure347_externref_shim: (a: number, b: number, c: any) => void;
|
||||
readonly closure371_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly __wbindgen_start: () => void;
|
||||
}
|
||||
|
||||
|
|
|
@ -240,13 +240,13 @@ function _assertNum(n) {
|
|||
function __wbg_adapter_20(arg0, arg1, arg2) {
|
||||
_assertNum(arg0);
|
||||
_assertNum(arg1);
|
||||
wasm.closure346_externref_shim(arg0, arg1, arg2);
|
||||
wasm.closure347_externref_shim(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
function __wbg_adapter_50(arg0, arg1, arg2, arg3) {
|
||||
_assertNum(arg0);
|
||||
_assertNum(arg1);
|
||||
wasm.closure370_externref_shim(arg0, arg1, arg2, arg3);
|
||||
wasm.closure371_externref_shim(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
|
@ -425,8 +425,8 @@ function __wbg_get_imports() {
|
|||
_assertBoolean(ret);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper7819 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 347, __wbg_adapter_20);
|
||||
imports.wbg.__wbindgen_closure_wrapper7945 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 348, __wbg_adapter_20);
|
||||
return ret;
|
||||
}, arguments) };
|
||||
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
|
||||
|
|
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_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
export const __wbindgen_export_6: WebAssembly.Table;
|
||||
export const closure346_externref_shim: (a: number, b: number, c: any) => void;
|
||||
export const closure370_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
export const closure347_externref_shim: (a: number, b: number, c: any) => void;
|
||||
export const closure371_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
export const __wbindgen_start: () => void;
|
||||
|
|
23
src/ast.rs
23
src/ast.rs
|
@ -4,7 +4,7 @@ use std::fmt;
|
|||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum StringPart {
|
||||
Data(String),
|
||||
Word(String),
|
||||
Word(&'static str),
|
||||
Inline(String),
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,8 @@ pub enum Ast {
|
|||
Do(Vec<Spanned<Self>>),
|
||||
Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>),
|
||||
Splat(&'static str),
|
||||
Pair(&'static str, Box<Spanned<Self>>),
|
||||
StringPair(&'static str, Box<Spanned<Self>>),
|
||||
KeywordPair(&'static str, Box<Spanned<Self>>),
|
||||
Loop(Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
||||
Recur(Vec<Spanned<Self>>),
|
||||
|
||||
|
@ -80,7 +81,8 @@ pub enum Ast {
|
|||
PlaceholderPattern,
|
||||
TuplePattern(Vec<Spanned<Self>>),
|
||||
ListPattern(Vec<Spanned<Self>>),
|
||||
PairPattern(&'static str, Box<Spanned<Self>>),
|
||||
StrPairPattern(&'static str, Box<Spanned<Self>>),
|
||||
KeyPairPattern(&'static str, Box<Spanned<Self>>),
|
||||
DictPattern(Vec<Spanned<Self>>),
|
||||
}
|
||||
|
||||
|
@ -212,7 +214,12 @@ impl Ast {
|
|||
Splat(word) => format!("...{}", word),
|
||||
Splattern(pattern) => format!("...{}", pattern.0.show()),
|
||||
AsPattern(word, type_keyword) => format!("{word} as :{type_keyword}"),
|
||||
Pair(key, value) | PairPattern(key, value) => format!(":{key} {}", value.0.show()),
|
||||
KeywordPair(key, value) | KeyPairPattern(key, value) => {
|
||||
format!(":{key} {}", value.0.show())
|
||||
}
|
||||
StringPair(key, value) | StrPairPattern(key, value) => {
|
||||
format!("\"{key}\" {}", value.0.show())
|
||||
}
|
||||
Loop(init, body) => format!(
|
||||
"loop {} with {{\n {}\n}}",
|
||||
init.0.show(),
|
||||
|
@ -377,8 +384,11 @@ impl fmt::Display for Ast {
|
|||
Splat(word) => {
|
||||
write!(f, "splat: {}", word)
|
||||
}
|
||||
Pair(k, v) => {
|
||||
write!(f, "pair: {} {}", k, v.0)
|
||||
KeywordPair(k, v) | KeyPairPattern(k, v) => {
|
||||
write!(f, "key_pair: {} {}", k, v.0)
|
||||
}
|
||||
StringPair(k, v) | StrPairPattern(k, v) => {
|
||||
write!(f, "str_pair: {k} {}", v.0)
|
||||
}
|
||||
Loop(init, body) => {
|
||||
write!(
|
||||
|
@ -446,7 +456,6 @@ impl fmt::Display for Ast {
|
|||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
PairPattern(key, value) => write!(f, ":{} {}", key, value.0),
|
||||
InterpolatedPattern(strprts) => write!(
|
||||
f,
|
||||
"interpolated: \"{}\"",
|
||||
|
|
167
src/base.rs
167
src/base.rs
|
@ -612,64 +612,133 @@ pub fn r#mod(x: &Value, y: &Value) -> Value {
|
|||
|
||||
pub fn make_base() -> Value {
|
||||
let members = vec![
|
||||
("add", Value::BaseFn(BaseFn::Binary("add", add))),
|
||||
("append", Value::BaseFn(BaseFn::Binary("append", append))),
|
||||
("assoc", Value::BaseFn(BaseFn::Ternary("assoc", assoc))),
|
||||
("at", Value::BaseFn(BaseFn::Binary("at", at))),
|
||||
("atan_2", Value::BaseFn(BaseFn::Binary("atan_2", atan_2))),
|
||||
("bool", Value::BaseFn(BaseFn::Unary("bool", r#bool))),
|
||||
("ceil", Value::BaseFn(BaseFn::Unary("ceil", ceil))),
|
||||
("chars", Value::BaseFn(BaseFn::Unary("chars", chars))),
|
||||
("concat", Value::BaseFn(BaseFn::Binary("concat", concat))),
|
||||
("cos", Value::BaseFn(BaseFn::Unary("cos", cos))),
|
||||
("count", Value::BaseFn(BaseFn::Unary("count", count))),
|
||||
("dec", Value::BaseFn(BaseFn::Unary("dec", dec))),
|
||||
("dissoc", Value::BaseFn(BaseFn::Binary("dissoc", dissoc))),
|
||||
("div", Value::BaseFn(BaseFn::Binary("div", div))),
|
||||
("doc!", Value::BaseFn(BaseFn::Unary("doc!", doc))),
|
||||
("add", Value::BaseFn(Box::new(BaseFn::Binary("add", add)))),
|
||||
(
|
||||
"append",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("append", append))),
|
||||
),
|
||||
(
|
||||
"assoc",
|
||||
Value::BaseFn(Box::new(BaseFn::Ternary("assoc", assoc))),
|
||||
),
|
||||
("at", Value::BaseFn(Box::new(BaseFn::Binary("at", at)))),
|
||||
(
|
||||
"atan_2",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("atan_2", atan_2))),
|
||||
),
|
||||
(
|
||||
"bool",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("bool", r#bool))),
|
||||
),
|
||||
("ceil", Value::BaseFn(Box::new(BaseFn::Unary("ceil", ceil)))),
|
||||
(
|
||||
"chars",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("chars", chars))),
|
||||
),
|
||||
(
|
||||
"concat",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("concat", concat))),
|
||||
),
|
||||
("cos", Value::BaseFn(Box::new(BaseFn::Unary("cos", cos)))),
|
||||
(
|
||||
"count",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("count", count))),
|
||||
),
|
||||
("dec", Value::BaseFn(Box::new(BaseFn::Unary("dec", dec)))),
|
||||
(
|
||||
"dissoc",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("dissoc", dissoc))),
|
||||
),
|
||||
("div", Value::BaseFn(Box::new(BaseFn::Binary("div", div)))),
|
||||
("doc!", Value::BaseFn(Box::new(BaseFn::Unary("doc!", doc)))),
|
||||
(
|
||||
"downcase",
|
||||
Value::BaseFn(BaseFn::Unary("downcase", downcase)),
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("downcase", downcase))),
|
||||
),
|
||||
("eq?", Value::BaseFn(Box::new(BaseFn::Binary("eq?", eq)))),
|
||||
(
|
||||
"first",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("first", first))),
|
||||
),
|
||||
(
|
||||
"floor",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("floor", floor))),
|
||||
),
|
||||
("get", Value::BaseFn(Box::new(BaseFn::Binary("get", get)))),
|
||||
("gt?", Value::BaseFn(Box::new(BaseFn::Binary("gt?", gt)))),
|
||||
("gte?", Value::BaseFn(Box::new(BaseFn::Binary("gte?", gte)))),
|
||||
("inc", Value::BaseFn(Box::new(BaseFn::Unary("inc", inc)))),
|
||||
("last", Value::BaseFn(Box::new(BaseFn::Unary("last", last)))),
|
||||
("list", Value::BaseFn(Box::new(BaseFn::Unary("list", list)))),
|
||||
("lt?", Value::BaseFn(Box::new(BaseFn::Binary("lt?", lt)))),
|
||||
("lte?", Value::BaseFn(Box::new(BaseFn::Binary("lte?", lte)))),
|
||||
("mod", Value::BaseFn(Box::new(BaseFn::Binary("mod", r#mod)))),
|
||||
(
|
||||
"mult",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("mult", mult))),
|
||||
),
|
||||
(
|
||||
"number",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("number", number))),
|
||||
),
|
||||
("eq?", Value::BaseFn(BaseFn::Binary("eq?", eq))),
|
||||
("first", Value::BaseFn(BaseFn::Unary("first", first))),
|
||||
("floor", Value::BaseFn(BaseFn::Unary("floor", floor))),
|
||||
("get", Value::BaseFn(BaseFn::Binary("get", get))),
|
||||
("gt?", Value::BaseFn(BaseFn::Binary("gt?", gt))),
|
||||
("gte?", Value::BaseFn(BaseFn::Binary("gte?", gte))),
|
||||
("inc", Value::BaseFn(BaseFn::Unary("inc", inc))),
|
||||
("last", Value::BaseFn(BaseFn::Unary("last", last))),
|
||||
("list", Value::BaseFn(BaseFn::Unary("list", list))),
|
||||
("lt?", Value::BaseFn(BaseFn::Binary("lt?", lt))),
|
||||
("lte?", Value::BaseFn(BaseFn::Binary("lte?", lte))),
|
||||
("mod", Value::BaseFn(BaseFn::Binary("mod", r#mod))),
|
||||
("mult", Value::BaseFn(BaseFn::Binary("mult", mult))),
|
||||
("number", Value::BaseFn(BaseFn::Unary("number", number))),
|
||||
("pi", Value::Number(std::f64::consts::PI)),
|
||||
("print!", Value::BaseFn(BaseFn::Unary("print!", print))),
|
||||
(
|
||||
"print!",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("print!", print))),
|
||||
),
|
||||
("process", Value::Process),
|
||||
(
|
||||
"random",
|
||||
Value::BaseFn(BaseFn::Nullary("random", base_random)),
|
||||
Value::BaseFn(Box::new(BaseFn::Nullary("random", base_random))),
|
||||
),
|
||||
("range", Value::BaseFn(BaseFn::Binary("range", range))),
|
||||
("rest", Value::BaseFn(BaseFn::Unary("rest", rest))),
|
||||
("round", Value::BaseFn(BaseFn::Unary("round", round))),
|
||||
("show", Value::BaseFn(BaseFn::Unary("show", show))),
|
||||
("sin", Value::BaseFn(BaseFn::Unary("sin", sin))),
|
||||
("slice", Value::BaseFn(BaseFn::Ternary("slice", slice))),
|
||||
("split", Value::BaseFn(BaseFn::Binary("split", split))),
|
||||
("sqrt", Value::BaseFn(BaseFn::Unary("sqrt", sqrt))),
|
||||
(
|
||||
"range",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("range", range))),
|
||||
),
|
||||
("rest", Value::BaseFn(Box::new(BaseFn::Unary("rest", rest)))),
|
||||
(
|
||||
"round",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("round", round))),
|
||||
),
|
||||
("show", Value::BaseFn(Box::new(BaseFn::Unary("show", show)))),
|
||||
("sin", Value::BaseFn(Box::new(BaseFn::Unary("sin", sin)))),
|
||||
(
|
||||
"slice",
|
||||
Value::BaseFn(Box::new(BaseFn::Ternary("slice", slice))),
|
||||
),
|
||||
(
|
||||
"split",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("split", split))),
|
||||
),
|
||||
("sqrt", Value::BaseFn(Box::new(BaseFn::Unary("sqrt", sqrt)))),
|
||||
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
|
||||
("store!", Value::BaseFn(BaseFn::Binary("store!", store))),
|
||||
("sub", Value::BaseFn(BaseFn::Binary("sub", sub))),
|
||||
("tan", Value::BaseFn(BaseFn::Unary("tan", tan))),
|
||||
("trim", Value::BaseFn(BaseFn::Unary("trim", trim))),
|
||||
("triml", Value::BaseFn(BaseFn::Unary("triml", triml))),
|
||||
("trimr", Value::BaseFn(BaseFn::Unary("trimr", trimr))),
|
||||
("type", Value::BaseFn(BaseFn::Unary("type", r#type))),
|
||||
("unbox", Value::BaseFn(BaseFn::Unary("unbox", unbox))),
|
||||
("upcase", Value::BaseFn(BaseFn::Unary("upcase", upcase))),
|
||||
(
|
||||
"store!",
|
||||
Value::BaseFn(Box::new(BaseFn::Binary("store!", store))),
|
||||
),
|
||||
("sub", Value::BaseFn(Box::new(BaseFn::Binary("sub", sub)))),
|
||||
("tan", Value::BaseFn(Box::new(BaseFn::Unary("tan", tan)))),
|
||||
("trim", Value::BaseFn(Box::new(BaseFn::Unary("trim", trim)))),
|
||||
(
|
||||
"triml",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("triml", triml))),
|
||||
),
|
||||
(
|
||||
"trimr",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("trimr", trimr))),
|
||||
),
|
||||
(
|
||||
"type",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("type", r#type))),
|
||||
),
|
||||
(
|
||||
"unbox",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("unbox", unbox))),
|
||||
),
|
||||
(
|
||||
"upcase",
|
||||
Value::BaseFn(Box::new(BaseFn::Unary("upcase", upcase))),
|
||||
),
|
||||
];
|
||||
let members = members
|
||||
.iter()
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use crate::op::Op;
|
||||
use crate::value::Value;
|
||||
use crate::value::{Key, Value};
|
||||
use imbl::HashMap;
|
||||
use num_traits::FromPrimitive;
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StrPattern {
|
||||
pub words: Vec<String>,
|
||||
pub words: Vec<&'static str>,
|
||||
pub re: Regex,
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub struct Chunk {
|
|||
pub bytecode: Vec<u8>,
|
||||
pub keywords: Vec<&'static str>,
|
||||
pub string_patterns: Vec<StrPattern>,
|
||||
pub env: HashMap<&'static str, Value>,
|
||||
pub env: HashMap<Key, Value>,
|
||||
pub msgs: Vec<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ impl Compiler {
|
|||
name: &'static str,
|
||||
src: &'static str,
|
||||
depth: usize,
|
||||
env: imbl::HashMap<&'static str, Value>,
|
||||
env: imbl::HashMap<Key, Value>,
|
||||
debug: bool,
|
||||
) -> Compiler {
|
||||
let chunk = Chunk {
|
||||
|
@ -703,10 +703,12 @@ impl Compiler {
|
|||
let match_depth = self.match_depth;
|
||||
self.match_depth = 0;
|
||||
for pair in pairs.iter().take(pairs_len) {
|
||||
let (PairPattern(key, pattern), _) = pair else {
|
||||
unreachable!()
|
||||
let (key, pattern) = match &pair.0 {
|
||||
KeyPairPattern(key, pattern) => (Value::Keyword(key), pattern),
|
||||
StrPairPattern(key, pattern) => (Value::Interned(key), pattern),
|
||||
_ => unreachable!("expected key to be keyword or string"),
|
||||
};
|
||||
self.emit_constant(Value::Keyword(key));
|
||||
self.emit_constant(key);
|
||||
self.emit_op(Op::LoadDictValue);
|
||||
self.emit_byte(dict_stack_pos);
|
||||
self.visit(pattern);
|
||||
|
@ -721,7 +723,7 @@ impl Compiler {
|
|||
self.stack_depth += 1;
|
||||
|
||||
for pair in pairs.iter().take(pairs_len) {
|
||||
let (PairPattern(key, _), _) = pair else {
|
||||
let (KeyPairPattern(key, _), _) = pair else {
|
||||
unreachable!()
|
||||
};
|
||||
self.emit_constant(Value::Keyword(key));
|
||||
|
@ -785,9 +787,8 @@ impl Compiler {
|
|||
self.emit_byte(pattern_idx);
|
||||
|
||||
for word in moar_words {
|
||||
let name: &'static str = std::string::String::leak(word);
|
||||
let binding = Binding {
|
||||
name,
|
||||
name: word,
|
||||
depth: self.scope_depth,
|
||||
stack_pos: self.stack_depth,
|
||||
};
|
||||
|
@ -797,7 +798,7 @@ impl Compiler {
|
|||
|
||||
self.patch_jump(jnm_idx, self.len() - jnm_idx - 3);
|
||||
}
|
||||
PairPattern(_, _) => unreachable!(),
|
||||
KeyPairPattern(..) | StrPairPattern(..) => unreachable!(),
|
||||
Tuple(members) => {
|
||||
self.tail_pos = false;
|
||||
for member in members {
|
||||
|
@ -842,7 +843,12 @@ impl Compiler {
|
|||
}
|
||||
}
|
||||
}
|
||||
Pair(key, value) => {
|
||||
StringPair(key, value) => {
|
||||
self.tail_pos = false;
|
||||
self.emit_constant(Value::Interned(key));
|
||||
self.visit(value);
|
||||
}
|
||||
KeywordPair(key, value) => {
|
||||
self.tail_pos = false;
|
||||
self.emit_constant(Value::Keyword(key));
|
||||
self.visit(value);
|
||||
|
|
|
@ -46,15 +46,15 @@ mod op;
|
|||
mod compiler;
|
||||
use crate::compiler::Compiler;
|
||||
|
||||
mod value;
|
||||
use value::Value;
|
||||
pub mod value;
|
||||
use value::{Value, Key};
|
||||
|
||||
mod vm;
|
||||
use vm::Creature;
|
||||
|
||||
const PRELUDE: &str = include_str!("../assets/test_prelude.ld");
|
||||
|
||||
fn prelude() -> HashMap<&'static str, Value> {
|
||||
fn prelude() -> HashMap<Key, Value> {
|
||||
let tokens = lexer().parse(PRELUDE).into_output_errors().0.unwrap();
|
||||
let (parsed, parse_errors) = parser()
|
||||
.parse(Stream::from_iter(tokens).map((0..PRELUDE.len()).into(), |(t, s)| (t, s)))
|
||||
|
@ -71,7 +71,7 @@ fn prelude() -> HashMap<&'static str, Value> {
|
|||
|
||||
let base = base::make_base();
|
||||
let mut base_env = imbl::HashMap::new();
|
||||
base_env.insert("base", base.clone());
|
||||
base_env.insert(Key::Keyword("base"), base.clone());
|
||||
|
||||
let mut validator = Validator::new(ast, span, "prelude", PRELUDE, base_env);
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use rudus::ludus;
|
||||
use rudus::value::Value;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use struct_scalpel::print_dissection_info;
|
||||
|
||||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = fs::read_to_string("sandbox.ld").unwrap();
|
||||
let json = ludus(src);
|
||||
// println!("{json}");
|
||||
print_dissection_info::<Value>();
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ fn parse_string(s: &'static str, span: SimpleSpan) -> Result<Vec<Spanned<StringP
|
|||
'}' => {
|
||||
if is_word {
|
||||
parts.push((
|
||||
StringPart::Word(current_part.clone()),
|
||||
StringPart::Word(current_part.leak()),
|
||||
SimpleSpan::new(span.context(), start..start + i),
|
||||
));
|
||||
current_part = String::new();
|
||||
|
@ -209,19 +209,24 @@ where
|
|||
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
|
||||
.map_with(|list, e| (ListPattern(list), e.span()));
|
||||
|
||||
let pair_pattern = select! {Token::Keyword(k) => k}
|
||||
let key_pair_pattern = select! {Token::Keyword(k) => k}
|
||||
.then(pattern.clone())
|
||||
.map_with(|(key, patt), e| (PairPattern(key, Box::new(patt)), e.span()));
|
||||
.map_with(|(key, patt), e| (KeyPairPattern(key, Box::new(patt)), e.span()));
|
||||
|
||||
let shorthand_pattern = select! {Token::Word(w) => w}.map_with(|w, e| {
|
||||
(
|
||||
PairPattern(w, Box::new((WordPattern(w), e.span()))),
|
||||
KeyPairPattern(w, Box::new((WordPattern(w), e.span()))),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
|
||||
let dict_pattern = pair_pattern
|
||||
let str_pair_pattern = select! {Token::String(s) => s}
|
||||
.then(pattern.clone())
|
||||
.map_with(|(key, patt), e| (StrPairPattern(key, Box::new(patt)), e.span()));
|
||||
|
||||
let dict_pattern = key_pair_pattern
|
||||
.or(shorthand_pattern)
|
||||
.or(str_pair_pattern)
|
||||
.or(splattern.clone())
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
|
@ -334,15 +339,20 @@ where
|
|||
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
|
||||
.map_with(|list, e| (List(list), e.span()));
|
||||
|
||||
let pair = select! {Token::Keyword(k) => k}
|
||||
let key_pair = select! {Token::Keyword(k) => k}
|
||||
.then(simple.clone())
|
||||
.map_with(|(key, value), e| (Pair(key, Box::new(value)), e.span()));
|
||||
.map_with(|(key, value), e| (KeywordPair(key, Box::new(value)), e.span()));
|
||||
|
||||
let shorthand = select! {Token::Word(w) => w}
|
||||
.map_with(|w, e| (Pair(w, Box::new((Word(w), e.span()))), e.span()));
|
||||
.map_with(|w, e| (KeywordPair(w, Box::new((Word(w), e.span()))), e.span()));
|
||||
|
||||
let dict = pair
|
||||
let str_pair = select! {Token::String(s) => s}
|
||||
.then(simple.clone())
|
||||
.map_with(|(key, value), e| (StringPair(key, Box::new(value)), e.span()));
|
||||
|
||||
let dict = key_pair
|
||||
.or(shorthand)
|
||||
.or(str_pair)
|
||||
.or(splat.clone())
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use crate::ast::{Ast, StringPart};
|
||||
use crate::spans::{Span, Spanned};
|
||||
use crate::value::Value;
|
||||
use crate::value::{Key, Value};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -61,7 +61,7 @@ fn match_arities(arities: &HashSet<Arity>, num_args: u8) -> bool {
|
|||
#[derive(Debug, PartialEq)]
|
||||
pub struct Validator<'a> {
|
||||
pub locals: Vec<(String, &'a Span, FnInfo)>,
|
||||
pub prelude: imbl::HashMap<&'static str, Value>,
|
||||
pub prelude: imbl::HashMap<Key, Value>,
|
||||
pub input: &'static str,
|
||||
pub src: &'static str,
|
||||
pub ast: &'a Ast,
|
||||
|
@ -77,7 +77,7 @@ impl<'a> Validator<'a> {
|
|||
span: &'a Span,
|
||||
input: &'static str,
|
||||
src: &'static str,
|
||||
prelude: imbl::HashMap<&'static str, Value>,
|
||||
prelude: imbl::HashMap<Key, Value>,
|
||||
) -> Validator<'a> {
|
||||
Validator {
|
||||
input,
|
||||
|
@ -113,9 +113,12 @@ impl<'a> Validator<'a> {
|
|||
self.locals[i] = new_binding;
|
||||
}
|
||||
|
||||
fn resolved(&self, name: &str) -> bool {
|
||||
fn resolved(&self, name: &'static str) -> bool {
|
||||
self.locals.iter().any(|(bound, ..)| name == bound.as_str())
|
||||
|| self.prelude.iter().any(|(bound, _)| name == *bound)
|
||||
|| self
|
||||
.prelude
|
||||
.iter()
|
||||
.any(|(bound, _)| Key::Keyword(name) == *bound)
|
||||
}
|
||||
|
||||
fn bound(&self, name: &str) -> Option<&(String, &Span, FnInfo)> {
|
||||
|
@ -172,7 +175,7 @@ impl<'a> Validator<'a> {
|
|||
for part in parts {
|
||||
if let (StringPart::Word(name), span) = part {
|
||||
self.span = span;
|
||||
if !self.resolved(name.as_str()) {
|
||||
if !self.resolved(name) {
|
||||
self.err(format!("unbound name `{name}`"));
|
||||
} else {
|
||||
self.use_name(name.to_string());
|
||||
|
@ -267,7 +270,7 @@ impl<'a> Validator<'a> {
|
|||
|
||||
self.status.tail_position = tailpos;
|
||||
}
|
||||
Pair(_, value) => self.visit(value.as_ref()),
|
||||
KeywordPair(_, value) | StringPair(_, value) => self.visit(value.as_ref()),
|
||||
Dict(dict) => {
|
||||
if dict.is_empty() {
|
||||
return;
|
||||
|
@ -592,7 +595,7 @@ impl<'a> Validator<'a> {
|
|||
self.visit(last);
|
||||
self.status.last_term = false;
|
||||
}
|
||||
PairPattern(_, patt) => self.visit(patt.as_ref()),
|
||||
KeyPairPattern(_, patt) | StrPairPattern(_, patt) => self.visit(patt.as_ref()),
|
||||
// terminals can never be invalid
|
||||
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) | And | Or | Method(..) => (),
|
||||
// terminal patterns can never be invalid
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::chunk::Chunk;
|
|||
use imbl::{HashMap, Vector};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use struct_scalpel::Dissectible;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum LFn {
|
||||
|
@ -141,14 +142,14 @@ impl Key {
|
|||
pub fn from_value(value: Value) -> Key {
|
||||
match value {
|
||||
Value::Keyword(s) => Key::Keyword(s),
|
||||
Value::Interned(s) => Key::Keyword(s),
|
||||
Value::Interned(s) => Key::Interned(s),
|
||||
Value::String(s) => Key::String(s.clone()),
|
||||
_ => unreachable!("dict keys must be keywords or strings"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Dissectible)]
|
||||
pub enum Value {
|
||||
Nothing,
|
||||
Nil,
|
||||
|
@ -163,7 +164,7 @@ pub enum Value {
|
|||
Dict(Box<HashMap<Key, Value>>),
|
||||
Box(Rc<RefCell<Value>>),
|
||||
Fn(Rc<LFn>),
|
||||
BaseFn(BaseFn),
|
||||
BaseFn(Box<BaseFn>),
|
||||
Partial(Rc<Partial>),
|
||||
Process,
|
||||
}
|
||||
|
@ -233,7 +234,7 @@ impl std::fmt::Display for Value {
|
|||
Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()),
|
||||
Fn(lfn) => write!(f, "fn {}", lfn.name()),
|
||||
BaseFn(inner) => {
|
||||
let name = match inner {
|
||||
let name = match **inner {
|
||||
crate::base::BaseFn::Nullary(name, _)
|
||||
| crate::base::BaseFn::Unary(name, _)
|
||||
| crate::base::BaseFn::Binary(name, _)
|
||||
|
|
45
src/vm.rs
45
src/vm.rs
|
@ -3,7 +3,7 @@ use crate::base::BaseFn;
|
|||
use crate::chunk::Chunk;
|
||||
use crate::op::Op;
|
||||
use crate::spans::Spanned;
|
||||
use crate::value::{LFn, Value};
|
||||
use crate::value::{Key, LFn, Value};
|
||||
use crate::world::Zoo;
|
||||
use imbl::{HashMap, Vector};
|
||||
use num_traits::FromPrimitive;
|
||||
|
@ -477,7 +477,7 @@ impl Creature {
|
|||
let Value::Keyword(name) = key else {
|
||||
unreachable!("internal Ludus error: expected key for global resolution")
|
||||
};
|
||||
let value = self.chunk().env.get(name).unwrap();
|
||||
let value = self.chunk().env.get(&Key::Keyword(name)).unwrap();
|
||||
self.push(value.clone());
|
||||
}
|
||||
Store => {
|
||||
|
@ -700,9 +700,7 @@ impl Creature {
|
|||
}
|
||||
AppendDict => {
|
||||
let value = self.pop();
|
||||
let Value::Keyword(key) = self.pop() else {
|
||||
unreachable!()
|
||||
};
|
||||
let key = Key::from_value(self.pop());
|
||||
let Value::Dict(mut dict) = self.pop() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
@ -731,9 +729,7 @@ impl Creature {
|
|||
unreachable!("expected dict, got {value}")
|
||||
}
|
||||
};
|
||||
let Value::Keyword(key) = self.pop() else {
|
||||
unreachable!("expected keyword, got something else")
|
||||
};
|
||||
let key = Key::from_value(self.pop());
|
||||
let value = dict.get(&key).unwrap_or(&Value::Nil);
|
||||
self.push(value.clone());
|
||||
}
|
||||
|
@ -756,13 +752,11 @@ impl Creature {
|
|||
}
|
||||
}
|
||||
DropDictEntry => {
|
||||
let Value::Keyword(key_to_drop) = self.pop() else {
|
||||
unreachable!()
|
||||
};
|
||||
let key_to_drop = Key::from_value(self.pop());
|
||||
let Value::Dict(mut dict) = self.pop() else {
|
||||
unreachable!()
|
||||
};
|
||||
dict.remove(key_to_drop);
|
||||
dict.remove(&key_to_drop);
|
||||
self.push(Value::Dict(dict));
|
||||
}
|
||||
PushBox => {
|
||||
|
@ -770,13 +764,10 @@ impl Creature {
|
|||
self.push(Value::Box(Rc::new(RefCell::new(val))));
|
||||
}
|
||||
GetKey => {
|
||||
let key = self.pop();
|
||||
let Value::Keyword(idx) = key else {
|
||||
unreachable!()
|
||||
};
|
||||
let key = Key::from_value(self.pop());
|
||||
let dict = self.pop();
|
||||
let value = match dict {
|
||||
Value::Dict(d) => d.as_ref().get(&idx).unwrap_or(&Value::Nil).clone(),
|
||||
Value::Dict(d) => d.get(&key).unwrap_or(&Value::Nil).clone(),
|
||||
_ => Value::Nil,
|
||||
};
|
||||
self.push(value);
|
||||
|
@ -899,13 +890,17 @@ impl Creature {
|
|||
}
|
||||
Get => {
|
||||
let key = self.pop();
|
||||
if !matches!(
|
||||
key,
|
||||
Value::Keyword(_) | Value::String(_) | Value::Interned(_)
|
||||
) {
|
||||
return self.panic("keys must be keywords");
|
||||
}
|
||||
let key = Key::from_value(key);
|
||||
let dict = self.pop();
|
||||
let value = match (key, dict) {
|
||||
(Value::Keyword(k), Value::Dict(d)) => {
|
||||
d.as_ref().get(&k).unwrap_or(&Value::Nil).clone()
|
||||
}
|
||||
(Value::Keyword(_), _) => Value::Nil,
|
||||
_ => return self.panic("keys must be keywords"),
|
||||
let value = match dict {
|
||||
Value::Dict(d) => d.get(&key).unwrap_or(&Value::Nil).clone(),
|
||||
_ => Value::Nil.clone(),
|
||||
};
|
||||
self.push(value);
|
||||
}
|
||||
|
@ -1042,7 +1037,7 @@ impl Creature {
|
|||
self.ip = 0;
|
||||
}
|
||||
Value::BaseFn(base_fn) => {
|
||||
let value = match (arity, base_fn) {
|
||||
let value = match (arity, *base_fn) {
|
||||
(0, BaseFn::Nullary(_, f)) => f(),
|
||||
(1, BaseFn::Unary(_, f)) => f(&self.pop()),
|
||||
(2, BaseFn::Binary(_, f)) => {
|
||||
|
@ -1149,7 +1144,7 @@ impl Creature {
|
|||
self.ip = 0;
|
||||
}
|
||||
Value::BaseFn(base_fn) => {
|
||||
let value = match (arity, base_fn) {
|
||||
let value = match (arity, *base_fn) {
|
||||
(0, BaseFn::Nullary(_, f)) => f(),
|
||||
(1, BaseFn::Unary(_, f)) => f(&self.pop()),
|
||||
(2, BaseFn::Binary(_, f)) => {
|
||||
|
|
16
src/world.rs
16
src/world.rs
|
@ -1,5 +1,5 @@
|
|||
use crate::chunk::Chunk;
|
||||
use crate::value::Value;
|
||||
use crate::value::{Value, Key};
|
||||
use crate::vm::{Creature, Panic};
|
||||
use crate::io::{MsgOut, MsgIn, do_io};
|
||||
use std::cell::RefCell;
|
||||
|
@ -260,13 +260,13 @@ pub struct Buffers {
|
|||
}
|
||||
|
||||
impl Buffers {
|
||||
pub fn new (prelude: imbl::HashMap<&'static str, Value>) -> Buffers {
|
||||
pub fn new (prelude: imbl::HashMap<Key, Value>) -> Buffers {
|
||||
Buffers {
|
||||
console: prelude.get("console").unwrap().clone(),
|
||||
commands: prelude.get("turtle_commands").unwrap().clone(),
|
||||
fetch_out: prelude.get("fetch_outbox").unwrap().clone(),
|
||||
fetch_in: prelude.get("fetch_inbox").unwrap().clone(),
|
||||
input: prelude.get("input").unwrap().clone(),
|
||||
console: prelude.get(&Key::Keyword("console")).unwrap().clone(),
|
||||
commands: prelude.get(&Key::Keyword("turtle_commands")).unwrap().clone(),
|
||||
fetch_out: prelude.get(&Key::Keyword("fetch_outbox")).unwrap().clone(),
|
||||
fetch_in: prelude.get(&Key::Keyword("fetch_inbox")).unwrap().clone(),
|
||||
input: prelude.get(&Key::Keyword("input")).unwrap().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +304,7 @@ pub struct World {
|
|||
}
|
||||
|
||||
impl World {
|
||||
pub fn new(chunk: Chunk, prelude: imbl::HashMap<&'static str, Value>, debug: bool) -> World {
|
||||
pub fn new(chunk: Chunk, prelude: imbl::HashMap<Key, Value>, debug: bool) -> World {
|
||||
let zoo = Rc::new(RefCell::new(Zoo::new()));
|
||||
let main = Creature::new(chunk, zoo.clone(), debug);
|
||||
let id = zoo.borrow_mut().put(main);
|
||||
|
|
Loading…
Reference in New Issue
Block a user