things and stuff

This commit is contained in:
Scott Richmond 2025-06-25 17:43:30 -04:00
parent 333f5c9518
commit 80eb81c6a8
7 changed files with 76 additions and 161 deletions

View File

@ -6,18 +6,18 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
crate-type = ["cdylib", "rlib"]
[dependencies]
ariadne = { git = "https://github.com/zesterer/ariadne" }
chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] }
imbl = "3.0.0"
struct_scalpel = "0.1.1"
# struct_scalpel = "0.1.1"
ran = "2.0.1"
rust-embed = "8.5.0"
boxing = "0.1.2"
ordered-float = "4.5.0"
index_vec = "0.1.4"
# rust-embed = "8.5.0"
# boxing = "0.1.2"
# ordered-float = "4.5.0"
# index_vec = "0.1.4"
num-derive = "0.4.2"
num-traits = "0.2.19"
regex = "1.11.1"

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "@ludus/rudus",
"version": "0.1.1",
"description": "A Rust-based Ludus bytecode interpreter.",
"type": "common",
"main": "pkg/ludus.js",
"directories": {},
"keywords": [],
"author": "Scott Richmond",
"license": "GPL-3.0",
"files": [
"pkg/rudus.js",
"pkg/ludus.js",
"pkg/rudus_bg.wasm",
"pkg/rudus_bg.wasm.d.ts",
"pkg/rudus.d.ts"
],
"devDependencies": {}
}

View File

@ -1,4 +1,4 @@
print! (:foo, :bar, :baz)
print! ("I wrote something")
let false = true
print! (1, 2, 3)
repeat 1 {
fd! (100)
rt! (0.25)
}

View File

@ -38,7 +38,7 @@ use vm::Vm;
const PRELUDE: &str = include_str!("../assets/test_prelude.ld");
pub fn prelude() -> HashMap<&'static str, Value> {
fn prelude() -> HashMap<&'static str, 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)))
@ -91,7 +91,7 @@ pub fn prelude() -> HashMap<&'static str, Value> {
#[wasm_bindgen]
pub fn run(src: String) -> String {
let src = src.leak();
let src = src.to_string().leak();
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if !lex_errs.is_empty() {
return format!("{:?}", lex_errs);
@ -163,7 +163,9 @@ pub fn run(src: String) -> String {
let Value::Box(commands) = turtle_commands else {
unreachable!()
};
let commands = commands.borrow().to_json().unwrap();
let commands = commands.borrow();
dbg!(&commands);
let commands = commands.to_json().unwrap();
let output = match result {
Ok(val) => val.show(),
@ -178,22 +180,11 @@ pub fn run(src: String) -> String {
// TODO: use serde_json to make this more robust?
format!(
"{{\"result\": \"{output}\",
\"io\": {{
\"stdout\": {{
\"proto\": [\"text-stream\", \"0.1.0\"],
\"data\": \"{console}\"
}},
\"turtle\": {{
\"proto\": [\"turtle-graphics\", \"0.1.0\"],
\"data\": {commands}
}}
}}
}}"
"{{\"result\":\"{output}\",\"io\":{{\"stdout\":{{\"proto\":[\"text-stream\",\"0.1.0\"],\"data\":\"{console}\"}},\"turtle\":{{\"proto\":[\"turtle-graphics\",\"0.1.0\"],\"data\":{commands}}}}}}}"
)
}
pub fn ld_fmt(src: &'static str) -> Result<String, String> {
pub fn fmt(src: &'static str) -> Result<String, String> {
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if !lex_errs.is_empty() {
println!("{:?}", lex_errs);

View File

@ -1,9 +1,7 @@
use crate::lib::run;
use rudus::run;
use std::env;
use std::fs;
mod lib;
pub fn main() {
env::set_var("RUST_BACKTRACE", "1");
let src = fs::read_to_string("sandbox.ld").unwrap();

View File

@ -1,37 +1,11 @@
// TODO: move AST to its own module
// TODO: remove StringMatcher cruft
// TODO: good error messages?
use crate::lexer::*;
use crate::spans::*;
use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
use std::fmt;
use struct_scalpel::Dissectible;
// #[derive(Clone, Debug, PartialEq)]
// pub struct WhenClause {
// pub cond: Spanned<Ast>,
// pub body: Spanned<Ast>,
// }
// impl fmt::Display for WhenClause {
// fn fmt(self: &WhenClause, f: &mut fmt::Formatter) -> fmt::Result {
// write!(f, "cond: {}, body: {}", self.cond.0, self.body.0)
// }
// }
// #[derive(Clone, Debug, PartialEq)]
// pub struct MatchClause {
// pub patt: Spanned<Pattern>,
// pub guard: Option<Spanned<Ast>>,
// pub body: Spanned<Ast>,
// }
// impl fmt::Display for MatchClause {
// fn fmt(self: &MatchClause, f: &mut fmt::Formatter) -> fmt::Result {
// write!(
// f,
// "pattern: {}, guard: {:?} body: {}",
// self.patt.0, self.guard, self.body.0
// )
// }
// }
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StringPart {
@ -51,13 +25,7 @@ impl fmt::Display for StringPart {
}
}
pub struct LFn {
name: &'static str,
clauses: Vec<Spanned<Ast>>,
doc: Option<&'static str>,
}
#[derive(Clone, Debug, PartialEq, Dissectible)]
#[derive(Clone, Debug, PartialEq)]
pub enum Ast {
// a special Error node
// may come in handy?
@ -219,14 +187,11 @@ impl Ast {
.collect::<Vec<_>>()
.join("\n ")
),
FnBody(clauses) => format!(
"{}",
clauses
FnBody(clauses) => clauses
.iter()
.map(|(clause, _)| clause.show())
.collect::<Vec<_>>()
.join("\n ")
),
.join("\n "),
Fn(name, body, doc) => {
let mut out = format!("fn {name} {{\n");
if let Some(doc) = doc {
@ -267,7 +232,7 @@ impl Ast {
.join(", ")
),
MatchClause(pattern, guard, body) => {
let mut out = format!("{}", pattern.0.show());
let mut out = pattern.0.show();
if let Some(guard) = guard.as_ref() {
out = format!("{out} if {}", guard.0.show());
}
@ -523,75 +488,6 @@ impl fmt::Debug for StringMatcher {
}
}
// #[derive(Clone, Debug, PartialEq)]
// pub enum Pattern {
// Nil,
// Boolean(bool),
// Number(f64),
// String(&'static str),
// Interpolated(Vec<Spanned<StringPart>>, StringMatcher),
// Keyword(&'static str),
// Word(&'static str),
// As(&'static str, &'static str),
// Splattern(Box<Spanned<Self>>),
// Placeholder,
// Tuple(Vec<Spanned<Self>>),
// List(Vec<Spanned<Self>>),
// Pair(&'static str, Box<Spanned<Self>>),
// Dict(Vec<Spanned<Self>>),
// }
// impl fmt::Display for Pattern {
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// match self {
// Pattern::Nil => write!(f, "nil"),
// Pattern::Boolean(b) => write!(f, "{}", b),
// Pattern::Number(n) => write!(f, "{}", n),
// Pattern::String(s) => write!(f, "{}", s),
// Pattern::Keyword(k) => write!(f, ":{}", k),
// Pattern::Word(w) => write!(f, "{}", w),
// Pattern::As(w, t) => write!(f, "{} as {}", w, t),
// Pattern::Splattern(p) => write!(f, "...{}", p.0),
// Pattern::Placeholder => write!(f, "_"),
// Pattern::Tuple(t) => write!(
// f,
// "({})",
// t.iter()
// .map(|x| x.0.to_string())
// .collect::<Vec<_>>()
// .join(", ")
// ),
// Pattern::List(l) => write!(
// f,
// "({})",
// l.iter()
// .map(|x| x.0.to_string())
// .collect::<Vec<_>>()
// .join(", ")
// ),
// Pattern::Dict(entries) => write!(
// f,
// "#{{{}}}",
// entries
// .iter()
// .map(|(pair, _)| pair.to_string())
// .collect::<Vec<_>>()
// .join(", ")
// ),
// Pattern::Pair(key, value) => write!(f, ":{} {}", key, value.0),
// Pattern::Interpolated(strprts, _) => write!(
// f,
// "interpolated: \"{}\"",
// strprts
// .iter()
// .map(|part| part.0.to_string())
// .collect::<Vec<_>>()
// .join("")
// ),
// }
// }
// }
fn is_word_char(c: char) -> bool {
if c.is_ascii_alphanumeric() {
return true;

View File

@ -258,39 +258,50 @@ impl Value {
pub fn to_json(&self) -> Option<String> {
use Value::*;
match self {
True | False | String(..) | Interned(..) => Some(self.show()),
True | False | String(..) | Interned(..) | Number(..) => Some(self.show()),
Keyword(str) => Some(format!("\"{str}\"")),
List(members) => {
let mut joined = "".to_string();
for member in members.iter() {
match member.to_json() {
Some(json) => joined = format!("{joined}, {json}"),
None => return None,
let mut members = members.iter();
if let Some(member) = members.next() {
joined = member.to_json()?;
}
for member in members {
let json = member.to_json()?;
joined = format!("{joined},{json}");
}
Some(format!("[{joined}]"))
}
Tuple(members) => {
let mut joined = "".to_string();
for member in members.iter() {
match member.to_json() {
Some(json) => joined = format!("{joined}, {json}"),
None => return None,
let mut members = members.iter();
if let Some(member) = members.next() {
joined = member.to_json()?;
}
for member in members {
let json = member.to_json()?;
joined = format!("{joined},{json}");
}
Some(format!("[{joined}]"))
}
Dict(members) => {
let mut joined = "".to_string();
for (key, value) in members.iter() {
match value.to_json() {
Some(json) => joined = format!("{joined}, \"{key}\": {json}"),
None => return None,
let mut members = members.iter();
if let Some((key, value)) = members.next() {
let json = value.to_json()?;
joined = format!("\"{key}\":{json}")
}
for (key, value) in members {
let json = value.to_json()?;
joined = format!("{joined},\"{key}\": {json}");
}
Some(format!("{{{joined}}}"))
}
_ => None,
not_serializable => {
println!("Cannot convert to json:");
dbg!(not_serializable);
None
}
}
}