things and stuff
This commit is contained in:
parent
333f5c9518
commit
80eb81c6a8
12
Cargo.toml
12
Cargo.toml
|
@ -6,18 +6,18 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ariadne = { git = "https://github.com/zesterer/ariadne" }
|
ariadne = { git = "https://github.com/zesterer/ariadne" }
|
||||||
chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] }
|
chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] }
|
||||||
imbl = "3.0.0"
|
imbl = "3.0.0"
|
||||||
struct_scalpel = "0.1.1"
|
# struct_scalpel = "0.1.1"
|
||||||
ran = "2.0.1"
|
ran = "2.0.1"
|
||||||
rust-embed = "8.5.0"
|
# rust-embed = "8.5.0"
|
||||||
boxing = "0.1.2"
|
# boxing = "0.1.2"
|
||||||
ordered-float = "4.5.0"
|
# ordered-float = "4.5.0"
|
||||||
index_vec = "0.1.4"
|
# index_vec = "0.1.4"
|
||||||
num-derive = "0.4.2"
|
num-derive = "0.4.2"
|
||||||
num-traits = "0.2.19"
|
num-traits = "0.2.19"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
|
|
19
package.json
Normal file
19
package.json
Normal 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": {}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
print! (:foo, :bar, :baz)
|
repeat 1 {
|
||||||
print! ("I wrote something")
|
fd! (100)
|
||||||
let false = true
|
rt! (0.25)
|
||||||
print! (1, 2, 3)
|
}
|
||||||
|
|
23
src/lib.rs
23
src/lib.rs
|
@ -38,7 +38,7 @@ use vm::Vm;
|
||||||
|
|
||||||
const PRELUDE: &str = include_str!("../assets/test_prelude.ld");
|
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 tokens = lexer().parse(PRELUDE).into_output_errors().0.unwrap();
|
||||||
let (parsed, parse_errors) = parser()
|
let (parsed, parse_errors) = parser()
|
||||||
.parse(Stream::from_iter(tokens).map((0..PRELUDE.len()).into(), |(t, s)| (t, s)))
|
.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]
|
#[wasm_bindgen]
|
||||||
pub fn run(src: String) -> String {
|
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();
|
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
||||||
if !lex_errs.is_empty() {
|
if !lex_errs.is_empty() {
|
||||||
return format!("{:?}", lex_errs);
|
return format!("{:?}", lex_errs);
|
||||||
|
@ -163,7 +163,9 @@ pub fn run(src: String) -> String {
|
||||||
let Value::Box(commands) = turtle_commands else {
|
let Value::Box(commands) = turtle_commands else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let commands = commands.borrow().to_json().unwrap();
|
let commands = commands.borrow();
|
||||||
|
dbg!(&commands);
|
||||||
|
let commands = commands.to_json().unwrap();
|
||||||
|
|
||||||
let output = match result {
|
let output = match result {
|
||||||
Ok(val) => val.show(),
|
Ok(val) => val.show(),
|
||||||
|
@ -178,22 +180,11 @@ pub fn run(src: String) -> String {
|
||||||
|
|
||||||
// TODO: use serde_json to make this more robust?
|
// TODO: use serde_json to make this more robust?
|
||||||
format!(
|
format!(
|
||||||
"{{\"result\": \"{output}\",
|
"{{\"result\":\"{output}\",\"io\":{{\"stdout\":{{\"proto\":[\"text-stream\",\"0.1.0\"],\"data\":\"{console}\"}},\"turtle\":{{\"proto\":[\"turtle-graphics\",\"0.1.0\"],\"data\":{commands}}}}}}}"
|
||||||
\"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();
|
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
||||||
if !lex_errs.is_empty() {
|
if !lex_errs.is_empty() {
|
||||||
println!("{:?}", lex_errs);
|
println!("{:?}", lex_errs);
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use crate::lib::run;
|
use rudus::run;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
mod lib;
|
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
env::set_var("RUST_BACKTRACE", "1");
|
env::set_var("RUST_BACKTRACE", "1");
|
||||||
let src = fs::read_to_string("sandbox.ld").unwrap();
|
let src = fs::read_to_string("sandbox.ld").unwrap();
|
||||||
|
|
120
src/parser.rs
120
src/parser.rs
|
@ -1,37 +1,11 @@
|
||||||
|
// TODO: move AST to its own module
|
||||||
|
// TODO: remove StringMatcher cruft
|
||||||
|
// TODO: good error messages?
|
||||||
|
|
||||||
use crate::lexer::*;
|
use crate::lexer::*;
|
||||||
use crate::spans::*;
|
use crate::spans::*;
|
||||||
use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
|
use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
|
||||||
use std::fmt;
|
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)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum StringPart {
|
pub enum StringPart {
|
||||||
|
@ -51,13 +25,7 @@ impl fmt::Display for StringPart {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LFn {
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
name: &'static str,
|
|
||||||
clauses: Vec<Spanned<Ast>>,
|
|
||||||
doc: Option<&'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Dissectible)]
|
|
||||||
pub enum Ast {
|
pub enum Ast {
|
||||||
// a special Error node
|
// a special Error node
|
||||||
// may come in handy?
|
// may come in handy?
|
||||||
|
@ -219,14 +187,11 @@ impl Ast {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n ")
|
.join("\n ")
|
||||||
),
|
),
|
||||||
FnBody(clauses) => format!(
|
FnBody(clauses) => clauses
|
||||||
"{}",
|
|
||||||
clauses
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(clause, _)| clause.show())
|
.map(|(clause, _)| clause.show())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n ")
|
.join("\n "),
|
||||||
),
|
|
||||||
Fn(name, body, doc) => {
|
Fn(name, body, doc) => {
|
||||||
let mut out = format!("fn {name} {{\n");
|
let mut out = format!("fn {name} {{\n");
|
||||||
if let Some(doc) = doc {
|
if let Some(doc) = doc {
|
||||||
|
@ -267,7 +232,7 @@ impl Ast {
|
||||||
.join(", ")
|
.join(", ")
|
||||||
),
|
),
|
||||||
MatchClause(pattern, guard, body) => {
|
MatchClause(pattern, guard, body) => {
|
||||||
let mut out = format!("{}", pattern.0.show());
|
let mut out = pattern.0.show();
|
||||||
if let Some(guard) = guard.as_ref() {
|
if let Some(guard) = guard.as_ref() {
|
||||||
out = format!("{out} if {}", guard.0.show());
|
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 {
|
fn is_word_char(c: char) -> bool {
|
||||||
if c.is_ascii_alphanumeric() {
|
if c.is_ascii_alphanumeric() {
|
||||||
return true;
|
return true;
|
||||||
|
|
39
src/value.rs
39
src/value.rs
|
@ -258,39 +258,50 @@ impl Value {
|
||||||
pub fn to_json(&self) -> Option<String> {
|
pub fn to_json(&self) -> Option<String> {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
match self {
|
match self {
|
||||||
True | False | String(..) | Interned(..) => Some(self.show()),
|
True | False | String(..) | Interned(..) | Number(..) => Some(self.show()),
|
||||||
Keyword(str) => Some(format!("\"{str}\"")),
|
Keyword(str) => Some(format!("\"{str}\"")),
|
||||||
List(members) => {
|
List(members) => {
|
||||||
let mut joined = "".to_string();
|
let mut joined = "".to_string();
|
||||||
for member in members.iter() {
|
let mut members = members.iter();
|
||||||
match member.to_json() {
|
if let Some(member) = members.next() {
|
||||||
Some(json) => joined = format!("{joined}, {json}"),
|
joined = member.to_json()?;
|
||||||
None => return None,
|
|
||||||
}
|
}
|
||||||
|
for member in members {
|
||||||
|
let json = member.to_json()?;
|
||||||
|
joined = format!("{joined},{json}");
|
||||||
}
|
}
|
||||||
Some(format!("[{joined}]"))
|
Some(format!("[{joined}]"))
|
||||||
}
|
}
|
||||||
Tuple(members) => {
|
Tuple(members) => {
|
||||||
let mut joined = "".to_string();
|
let mut joined = "".to_string();
|
||||||
for member in members.iter() {
|
let mut members = members.iter();
|
||||||
match member.to_json() {
|
if let Some(member) = members.next() {
|
||||||
Some(json) => joined = format!("{joined}, {json}"),
|
joined = member.to_json()?;
|
||||||
None => return None,
|
|
||||||
}
|
}
|
||||||
|
for member in members {
|
||||||
|
let json = member.to_json()?;
|
||||||
|
joined = format!("{joined},{json}");
|
||||||
}
|
}
|
||||||
Some(format!("[{joined}]"))
|
Some(format!("[{joined}]"))
|
||||||
}
|
}
|
||||||
Dict(members) => {
|
Dict(members) => {
|
||||||
let mut joined = "".to_string();
|
let mut joined = "".to_string();
|
||||||
for (key, value) in members.iter() {
|
let mut members = members.iter();
|
||||||
match value.to_json() {
|
if let Some((key, value)) = members.next() {
|
||||||
Some(json) => joined = format!("{joined}, \"{key}\": {json}"),
|
let json = value.to_json()?;
|
||||||
None => return None,
|
joined = format!("\"{key}\":{json}")
|
||||||
}
|
}
|
||||||
|
for (key, value) in members {
|
||||||
|
let json = value.to_json()?;
|
||||||
|
joined = format!("{joined},\"{key}\": {json}");
|
||||||
}
|
}
|
||||||
Some(format!("{{{joined}}}"))
|
Some(format!("{{{joined}}}"))
|
||||||
}
|
}
|
||||||
_ => None,
|
not_serializable => {
|
||||||
|
println!("Cannot convert to json:");
|
||||||
|
dbg!(not_serializable);
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user