Initial ID & func call stats!
This commit is contained in:
@@ -1,22 +1,23 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
use sl::Form;
|
use sl::Form;
|
||||||
|
|
||||||
grammar;
|
grammar;
|
||||||
|
|
||||||
pub Term: Rc<Form> = {
|
pub Term: Rc<Form> = {
|
||||||
NUM => Rc::new(Form::Int(i32::from_str(<>).unwrap())),
|
NUM => Rc::new(Form::Int(i32::from_str(<>).unwrap())),
|
||||||
SYM => Rc::new(Form::Symbol(<>.to_owned(),None)),
|
SYM => Rc::new(Form::Symbol(<>.to_owned(),RefCell::new(None))),
|
||||||
"(" <ListInside?> ")" => <>.unwrap_or(Rc::new(Form::Nil)),
|
"(" <ListInside?> ")" => <>.unwrap_or(Rc::new(Form::Nil)),
|
||||||
"'" <Term> => Rc::new(Form::Pair(Rc::new(Form::Symbol("quote".to_owned(),None)), Rc::new(Form::Pair(<>, Rc::new(Form::Nil),None)),None)),
|
"'" <Term> => Rc::new(Form::Pair(Rc::new(Form::Symbol("quote".to_owned(),RefCell::new(None))), Rc::new(Form::Pair(<>, Rc::new(Form::Nil),RefCell::new(None))),RefCell::new(None))),
|
||||||
"!" <h: Term> <t: Term> => {
|
"!" <h: Term> <t: Term> => {
|
||||||
h.append(t).unwrap()
|
h.append(t).unwrap()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ListInside: Rc<Form> = {
|
ListInside: Rc<Form> = {
|
||||||
<Term> => Rc::new(Form::Pair(<>, Rc::new(Form::Nil),None)),
|
<Term> => Rc::new(Form::Pair(<>, Rc::new(Form::Nil),RefCell::new(None))),
|
||||||
<h: Term> <t: ListInside> => Rc::new(Form::Pair(h, t,None)),
|
<h: Term> <t: ListInside> => Rc::new(Form::Pair(h, t,RefCell::new(None))),
|
||||||
<a: Term> "." <d: Term> => Rc::new(Form::Pair(a, d,None)),
|
<a: Term> "." <d: Term> => Rc::new(Form::Pair(a, d,RefCell::new(None))),
|
||||||
}
|
}
|
||||||
match {
|
match {
|
||||||
"(",
|
"(",
|
||||||
|
|||||||
105
sl/src/lib.rs
105
sl/src/lib.rs
@@ -5,7 +5,25 @@ use std::cell::RefCell;
|
|||||||
|
|
||||||
use anyhow::{anyhow,bail,Result};
|
use anyhow::{anyhow,bail,Result};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
|
||||||
|
// This first Simple Lisp really is
|
||||||
|
//
|
||||||
|
// No fexprs, no mutation, no continuations, no macros, no strings.
|
||||||
|
// Int/Bool/Nil/Pair/Symbol/Closure/Prim.
|
||||||
|
//
|
||||||
|
// Figuring out GC between a JIT and Rust will be tricky.
|
||||||
|
// Can start with a like tracing-JIT-into-bytecode
|
||||||
|
// Replcing Env with pairs or somesuch would make JIT interop easier I think, because we wouldn't
|
||||||
|
// have to deal with refcell, but then we would again for mutation.
|
||||||
|
// Maybe doing all allocation on the Rust side with #[no_mangle] functions would make things easier
|
||||||
|
// mmmm no let's make our own Box, Rc, maybe Arc
|
||||||
|
// rustonomicon
|
||||||
|
|
||||||
|
// What if we're cute and use the ID
|
||||||
|
// like we will eventually use value tagging
|
||||||
|
// like, use the same encoding
|
||||||
|
// interned symbols and all
|
||||||
|
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
|
||||||
pub struct ID {
|
pub struct ID {
|
||||||
id: i64
|
id: i64
|
||||||
}
|
}
|
||||||
@@ -15,9 +33,9 @@ pub enum Form {
|
|||||||
Nil,
|
Nil,
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
Symbol(String, Option<RefCell<ID>>),
|
Symbol(String, RefCell<Option<ID>>),
|
||||||
Pair(Rc<Form>, Rc<Form>, Option<RefCell<ID>>),
|
Pair(Rc<Form>, Rc<Form>, RefCell<Option<ID>>),
|
||||||
Closure(Vec<String>, Rc<RefCell<Env>>, Rc<Form>, Option<RefCell<ID>>),
|
Closure(Vec<String>, Rc<RefCell<Env>>, Rc<Form>, RefCell<Option<ID>>),
|
||||||
Prim(Prim),
|
Prim(Prim),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +65,7 @@ impl Form {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn new_pair(car: Rc<Form>, cdr: Rc<Form>) -> Rc<Form> {
|
fn new_pair(car: Rc<Form>, cdr: Rc<Form>) -> Rc<Form> {
|
||||||
Rc::new(Form::Pair(car, cdr, None))
|
Rc::new(Form::Pair(car, cdr, RefCell::new(None)))
|
||||||
}
|
}
|
||||||
fn new_nil() -> Rc<Form> {
|
fn new_nil() -> Rc<Form> {
|
||||||
Rc::new(Form::Nil)
|
Rc::new(Form::Nil)
|
||||||
@@ -59,7 +77,7 @@ impl Form {
|
|||||||
Rc::new(Form::Bool(b))
|
Rc::new(Form::Bool(b))
|
||||||
}
|
}
|
||||||
fn new_closure(params: Vec<String>, env: Rc<RefCell<Env>>, body: Rc<Form>) -> Rc<Form> {
|
fn new_closure(params: Vec<String>, env: Rc<RefCell<Env>>, body: Rc<Form>) -> Rc<Form> {
|
||||||
Rc::new(Form::Closure(params, env, body, None))
|
Rc::new(Form::Closure(params, env, body, RefCell::new(None)))
|
||||||
}
|
}
|
||||||
fn truthy(&self) -> bool {
|
fn truthy(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@@ -118,8 +136,8 @@ impl Form {
|
|||||||
}
|
}
|
||||||
pub fn append(&self, x: Rc<Form>) -> Result<Rc<Form>> {
|
pub fn append(&self, x: Rc<Form>) -> Result<Rc<Form>> {
|
||||||
match self {
|
match self {
|
||||||
Form::Pair(car, cdr, _id) => cdr.append(x).map(|x| Rc::new(Form::Pair(Rc::clone(car), x, None))),
|
Form::Pair(car, cdr, _id) => cdr.append(x).map(|x| Rc::new(Form::Pair(Rc::clone(car), x, RefCell::new(None)))),
|
||||||
Form::Nil => Ok(Rc::new(Form::Pair(x, Rc::new(Form::Nil), None))),
|
Form::Nil => Ok(Rc::new(Form::Pair(x, Rc::new(Form::Nil), RefCell::new(None)))),
|
||||||
_ => Err(anyhow!("append to not a pair")),
|
_ => Err(anyhow!("append to not a pair")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,10 +182,50 @@ impl Env {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn define(&mut self, s: String, v: Rc<Form>) {
|
pub fn define(&mut self, s: String, v: Rc<Form>) {
|
||||||
|
// no mutation, shadowing in inner scope ok
|
||||||
|
assert!(!self.m.contains_key(&s));
|
||||||
self.m.insert(s, v);
|
self.m.insert(s, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Stats {
|
||||||
|
id_counter: i64,
|
||||||
|
func_calls: BTreeMap<ID, i64>,
|
||||||
|
}
|
||||||
|
impl Stats {
|
||||||
|
fn new() -> Stats {
|
||||||
|
Stats {
|
||||||
|
id_counter: 0,
|
||||||
|
func_calls: BTreeMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn alloc_id(&mut self) -> ID {
|
||||||
|
self.id_counter += 1;
|
||||||
|
ID { id: self.id_counter }
|
||||||
|
}
|
||||||
|
fn count_call(&mut self, id: &RefCell<Option<ID>>) {
|
||||||
|
// shenanigins for controlling the guard
|
||||||
|
{
|
||||||
|
if id.borrow().is_none() {
|
||||||
|
let new_id = self.alloc_id();
|
||||||
|
id.replace(Some(new_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let id = id.borrow().unwrap();
|
||||||
|
let entry = self.func_calls.entry(id).or_insert(0);
|
||||||
|
*entry += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval(f: Rc<Form>) -> Result<Rc<Form>> {
|
||||||
|
let e = Env::root_env();
|
||||||
|
let mut stats = Stats::new();
|
||||||
|
let to_ret = tree_walker_eval(f, e, &mut stats)?;
|
||||||
|
println!("Stats were {stats:?}");
|
||||||
|
Ok(to_ret)
|
||||||
|
}
|
||||||
|
|
||||||
// add functions
|
// add functions
|
||||||
// variables
|
// variables
|
||||||
// optimized as a function based off side table of id keyed -> opt
|
// optimized as a function based off side table of id keyed -> opt
|
||||||
@@ -175,17 +233,17 @@ impl Env {
|
|||||||
// Symbol ID's could actually be used for environment lookups
|
// Symbol ID's could actually be used for environment lookups
|
||||||
// this is just interning
|
// this is just interning
|
||||||
|
|
||||||
pub fn tree_walker_eval(f: Rc<Form>, e: Rc<RefCell<Env>>) -> Result<Rc<Form>> {
|
fn tree_walker_eval(f: Rc<Form>, e: Rc<RefCell<Env>>, stats: &mut Stats) -> Result<Rc<Form>> {
|
||||||
println!("tree_walker_eval({f})");
|
println!("tree_walker_eval({f})");
|
||||||
Ok(match &*f {
|
Ok(match &*f {
|
||||||
Form::Symbol(s, _id) => e.borrow().lookup(s)?,
|
Form::Symbol(s, _id) => e.borrow().lookup(s)?,
|
||||||
Form::Pair(car, cdr, _id) => {
|
Form::Pair(car, cdr, _id) => {
|
||||||
match &**car {
|
match &**car {
|
||||||
Form::Symbol(s, _id) if s == "if" => {
|
Form::Symbol(s, _id) if s == "if" => {
|
||||||
if tree_walker_eval(cdr.car()?, Rc::clone(&e))?.truthy() {
|
if tree_walker_eval(cdr.car()?, Rc::clone(&e), stats)?.truthy() {
|
||||||
tree_walker_eval(cdr.cdr()?.car()?, e)?
|
tree_walker_eval(cdr.cdr()?.car()?, e, stats)?
|
||||||
} else {
|
} else {
|
||||||
tree_walker_eval(cdr.cdr()?.cdr()?.car()?, e)?
|
tree_walker_eval(cdr.cdr()?.cdr()?.car()?, e, stats)?
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -194,19 +252,19 @@ pub fn tree_walker_eval(f: Rc<Form>, e: Rc<RefCell<Env>>) -> Result<Rc<Form>> {
|
|||||||
let mut traverse = Rc::clone(cdr);
|
let mut traverse = Rc::clone(cdr);
|
||||||
while let Ok((ncar, ncdr)) = traverse.pair() {
|
while let Ok((ncar, ncdr)) = traverse.pair() {
|
||||||
traverse = ncdr;
|
traverse = ncdr;
|
||||||
last_result = tree_walker_eval(ncar, Rc::clone(&e))?;
|
last_result = tree_walker_eval(ncar, Rc::clone(&e), stats)?;
|
||||||
}
|
}
|
||||||
last_result
|
last_result
|
||||||
|
|
||||||
}
|
}
|
||||||
Form::Symbol(s, _id) if s == "debug" => {
|
Form::Symbol(s, _id) if s == "debug" => {
|
||||||
println!("debug: {}", tree_walker_eval(cdr.car()?, e)?);
|
println!("debug: {}", tree_walker_eval(cdr.car()?, e, stats)?);
|
||||||
Form::new_nil()
|
Form::new_nil()
|
||||||
}
|
}
|
||||||
// This is a fast and loose ~simple lisp~, so just go for it
|
// This is a fast and loose ~simple lisp~, so just go for it
|
||||||
// and can have convention that this is always top levelish
|
// and can have convention that this is always top levelish
|
||||||
Form::Symbol(s, _id) if s == "define" => {
|
Form::Symbol(s, _id) if s == "define" => {
|
||||||
let v = tree_walker_eval(cdr.cdr()?.car()?, Rc::clone(&e))?;
|
let v = tree_walker_eval(cdr.cdr()?.car()?, Rc::clone(&e), stats)?;
|
||||||
e.borrow_mut().define(cdr.car()?.sym()?.to_string(), v);
|
e.borrow_mut().define(cdr.car()?.sym()?.to_string(), v);
|
||||||
Form::new_nil()
|
Form::new_nil()
|
||||||
}
|
}
|
||||||
@@ -225,13 +283,14 @@ pub fn tree_walker_eval(f: Rc<Form>, e: Rc<RefCell<Env>>) -> Result<Rc<Form>> {
|
|||||||
Form::new_closure(params_vec, Rc::clone(&e), body)
|
Form::new_closure(params_vec, Rc::clone(&e), body)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let comb = tree_walker_eval(Rc::clone(car), Rc::clone(&e))?;
|
let comb = tree_walker_eval(Rc::clone(car), Rc::clone(&e), stats)?;
|
||||||
match &*comb {
|
match &*comb {
|
||||||
Form::Closure(ps, ie, b, id) => {
|
Form::Closure(ps, ie, b, id) => {
|
||||||
|
stats.count_call(id);
|
||||||
let mut arguments_vec = vec![];
|
let mut arguments_vec = vec![];
|
||||||
let mut arguments = Rc::clone(cdr);
|
let mut arguments = Rc::clone(cdr);
|
||||||
while let Ok((ncar, ncdr)) = arguments.pair() {
|
while let Ok((ncar, ncdr)) = arguments.pair() {
|
||||||
arguments_vec.push(tree_walker_eval(ncar, Rc::clone(&e))?);
|
arguments_vec.push(tree_walker_eval(ncar, Rc::clone(&e), stats)?);
|
||||||
arguments = ncdr;
|
arguments = ncdr;
|
||||||
}
|
}
|
||||||
if ps.len() != arguments_vec.len() {
|
if ps.len() != arguments_vec.len() {
|
||||||
@@ -241,15 +300,15 @@ pub fn tree_walker_eval(f: Rc<Form>, e: Rc<RefCell<Env>>) -> Result<Rc<Form>> {
|
|||||||
for (name, value) in ps.iter().zip(arguments_vec.into_iter()) {
|
for (name, value) in ps.iter().zip(arguments_vec.into_iter()) {
|
||||||
new_env.borrow_mut().define(name.to_string(), value);
|
new_env.borrow_mut().define(name.to_string(), value);
|
||||||
}
|
}
|
||||||
tree_walker_eval(Rc::clone(b), new_env)?
|
tree_walker_eval(Rc::clone(b), new_env, stats)?
|
||||||
},
|
},
|
||||||
Form::Prim(p) => {
|
Form::Prim(p) => {
|
||||||
let a = tree_walker_eval(cdr.car()?, Rc::clone(&e))?;
|
let a = tree_walker_eval(cdr.car()?, Rc::clone(&e), stats)?;
|
||||||
match comb.prim().unwrap() {
|
match comb.prim().unwrap() {
|
||||||
Prim::Car => a.car()?,
|
Prim::Car => a.car()?,
|
||||||
Prim::Cdr => a.cdr()?,
|
Prim::Cdr => a.cdr()?,
|
||||||
_ => {
|
_ => {
|
||||||
let b = tree_walker_eval(cdr.cdr()?.car()?, Rc::clone(&e))?;
|
let b = tree_walker_eval(cdr.cdr()?.car()?, Rc::clone(&e), stats)?;
|
||||||
match comb.prim().unwrap() {
|
match comb.prim().unwrap() {
|
||||||
Prim::Add => Form::new_int(a.int()? + b.int()?),
|
Prim::Add => Form::new_int(a.int()? + b.int()?),
|
||||||
Prim::Sub => Form::new_int(a.int()? - b.int()?),
|
Prim::Sub => Form::new_int(a.int()? - b.int()?),
|
||||||
@@ -275,13 +334,13 @@ pub fn tree_walker_eval(f: Rc<Form>, e: Rc<RefCell<Env>>) -> Result<Rc<Form>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo, strings not symbols?
|
// todo, strings not symbols?
|
||||||
impl From<String> for Form { fn from(item: String) -> Self { Form::Symbol(item, None) } }
|
impl From<String> for Form { fn from(item: String) -> Self { Form::Symbol(item, RefCell::new(None)) } }
|
||||||
impl From<&str> for Form { fn from(item: &str) -> Self { Form::Symbol(item.to_owned(), None) } }
|
impl From<&str> for Form { fn from(item: &str) -> Self { Form::Symbol(item.to_owned(), RefCell::new(None)) } }
|
||||||
impl From<i32> for Form { fn from(item: i32) -> Self { Form::Int(item) } }
|
impl From<i32> for Form { fn from(item: i32) -> Self { Form::Int(item) } }
|
||||||
impl From<bool> for Form { fn from(item: bool) -> Self { Form::Bool(item) } }
|
impl From<bool> for Form { fn from(item: bool) -> Self { Form::Bool(item) } }
|
||||||
impl<A: Into<Form>, B: Into<Form>> From<(A, B)> for Form {
|
impl<A: Into<Form>, B: Into<Form>> From<(A, B)> for Form {
|
||||||
fn from(item: (A, B)) -> Self {
|
fn from(item: (A, B)) -> Self {
|
||||||
Form::Pair(Rc::new(item.0.into()), Rc::new(item.1.into()), None)
|
Form::Pair(Rc::new(item.0.into()), Rc::new(item.1.into()), RefCell::new(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,32 +4,31 @@ lalrpop_mod!(pub grammar);
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use sl::{tree_walker_eval, Env};
|
use sl::eval;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let input = "
|
let input = "
|
||||||
(begin
|
(begin
|
||||||
(debug 1)
|
(debug 1)
|
||||||
(debug (= 1 2))
|
;(debug (= 1 2))
|
||||||
(debug (+ 2 3))
|
;(debug (+ 2 3))
|
||||||
(define a (+ 1 (* 3 4)))
|
;(define a (+ 1 (* 3 4)))
|
||||||
(define fact (lambda (n) (if (= n 1) 1 (* n (fact (- n 1))))))
|
(define fact (lambda (n) (if (= n 1) 1 (* n (fact (- n 1))))))
|
||||||
(debug 'gonna_fact_it)
|
(debug 'gonna_fact_it)
|
||||||
(debug fact)
|
(debug fact)
|
||||||
(debug (fact 5))
|
(debug (fact 5))
|
||||||
(debug a)
|
;(debug a)
|
||||||
(define b (cons 1 (cons 2 (cons 3 nil))))
|
;(define b (cons 1 (cons 2 (cons 3 nil))))
|
||||||
(debug b)
|
;(debug b)
|
||||||
(debug (car b))
|
;(debug (car b))
|
||||||
(debug (cdr b))
|
;(debug (cdr b))
|
||||||
(if (= 1 2) (+ 2 3) (* 2 2))
|
(if (= 1 2) (+ 2 3) (* 2 2))
|
||||||
)
|
)
|
||||||
";
|
";
|
||||||
let parsed_input = Rc::new(grammar::TermParser::new().parse(input)?);
|
let parsed_input = Rc::new(grammar::TermParser::new().parse(input)?);
|
||||||
//println!("Hello, world: {parsed_input:?}");
|
//println!("Hello, world: {parsed_input:?}");
|
||||||
println!("Hello, world: {parsed_input}");
|
println!("Hello, world: {parsed_input}");
|
||||||
let e = Env::root_env();
|
let evaled = eval(Rc::clone(&parsed_input))?;
|
||||||
let tree_walker_evaled = tree_walker_eval(Rc::clone(&parsed_input), e)?;
|
println!("evaled: {evaled}");
|
||||||
println!("tree walker evaled: {tree_walker_evaled}");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user