pre-recording backup

This commit is contained in:
2023-05-17 03:49:26 +01:00
parent 126494c63f
commit 330ddbe399
29 changed files with 404 additions and 195 deletions

35
src/external/cpsio/io.rs vendored Normal file
View File

@@ -0,0 +1,35 @@
use std::io::{self, Write, stdin};
use crate::{representations::{interpreted::{ExprInst, Clause}, Primitive, Literal}, atomic_inert, interpreter::{HandlerParm, HandlerRes}, unwrap_or, external::runtime_error::RuntimeError};
#[derive(Clone, Debug)]
pub enum IO {
Print(String, ExprInst),
Readline(ExprInst)
}
atomic_inert!(IO);
pub fn handle(effect: HandlerParm) -> HandlerRes {
let io: &IO = unwrap_or!(
effect.as_any().downcast_ref();
return Err(effect)
);
match io {
IO::Print(str, cont) => {
print!("{}", str);
io::stdout().flush().unwrap();
Ok(Ok(cont.clone()))
},
IO::Readline(cont) => {
let mut buf = String::new();
if let Err(e) = stdin().read_line(&mut buf) {
return Ok(Err(RuntimeError::ext(e.to_string(), "reading from stdin")));
}
buf.pop();
Ok(Ok(Clause::Apply {
f: cont.clone(),
x: Clause::P(Primitive::Literal(Literal::Str(buf))).wrap()
}.wrap()))
}
}
}

View File

@@ -4,6 +4,9 @@ mod print;
mod readline;
mod debug;
mod panic;
mod io;
pub use io::{IO, handle};
pub fn cpsio(i: &Interner) -> ConstTree {
ConstTree::tree([

View File

@@ -1,11 +1,12 @@
use std::fmt::Debug;
use std::io::{self, Write};
use std::rc::Rc;
use crate::external::litconv::with_str;
use crate::representations::PathSet;
use crate::{atomic_impl, atomic_redirect, externfn_impl};
use crate::representations::interpreted::{Clause, ExprInst};
use crate::foreign::{Atomic, AtomicResult, AtomicReturn};
use crate::interpreter::Context;
use crate::{atomic_impl, atomic_redirect, externfn_impl, atomic_defaults};
use crate::representations::interpreted::ExprInst;
use super::io::IO;
/// Print function
///
@@ -22,13 +23,21 @@ externfn_impl!(Print2, |_: &Self, x: ExprInst| Ok(Print1{x}));
#[derive(Debug, Clone)]
pub struct Print1{ x: ExprInst }
atomic_redirect!(Print1, x);
atomic_impl!(Print1, |Self{ x }: &Self, _| {
with_str(x, |s| {
print!("{}", s);
io::stdout().flush().unwrap();
Ok(Clause::Lambda {
args: Some(PathSet{ steps: Rc::new(vec![]), next: None }),
body: Clause::LambdaArg.wrap()
})
atomic_impl!(Print1);
externfn_impl!(Print1, |this: &Self, x: ExprInst| {
with_str(&this.x, |s| {
Ok(Print0{ s: s.clone(), x })
})
});
#[derive(Debug, Clone)]
pub struct Print0{ s: String, x: ExprInst }
impl Atomic for Print0 {
atomic_defaults!();
fn run(&self, ctx: Context) -> AtomicResult {
Ok(AtomicReturn::from_data(
IO::Print(self.s.clone(), self.x.clone()),
ctx
))
}
}

View File

@@ -1,10 +1,11 @@
use std::fmt::Debug;
use std::io::stdin;
use crate::external::runtime_error::RuntimeError;
use crate::{atomic_impl, atomic_redirect, externfn_impl};
use crate::representations::{Primitive, Literal};
use crate::representations::interpreted::{Clause, ExprInst};
use crate::foreign::{Atomic, AtomicResult, AtomicReturn};
use crate::interpreter::Context;
use crate::{externfn_impl, atomic_defaults};
use crate::representations::interpreted::ExprInst;
use super::io::IO;
/// Readln function
///
@@ -20,14 +21,12 @@ externfn_impl!(Readln2, |_: &Self, x: ExprInst| Ok(Readln1{x}));
#[derive(Debug, Clone)]
pub struct Readln1{ x: ExprInst }
atomic_redirect!(Readln1, x);
atomic_impl!(Readln1, |Self{ x }: &Self, _| {
let mut buf = String::new();
stdin().read_line(&mut buf)
.map_err(|e| RuntimeError::ext(e.to_string(), "reading from stdin"))?;
buf.pop();
Ok(Clause::Apply {
f: x.clone(),
x: Clause::P(Primitive::Literal(Literal::Str(buf))).wrap()
})
});
impl Atomic for Readln1 {
atomic_defaults!();
fn run(&self, ctx: Context) -> AtomicResult {
Ok(AtomicReturn::from_data(
IO::Readline(self.x.clone()),
ctx
))
}
}

2
src/external/mod.rs vendored
View File

@@ -7,3 +7,5 @@ mod cpsio;
mod runtime_error;
mod bool;
mod litconv;
pub use cpsio::{IO, handle};

View File

@@ -17,6 +17,16 @@ pub struct AtomicReturn {
pub gas: Option<usize>,
pub inert: bool
}
impl AtomicReturn {
/// Wrap an inert atomic for delivery to the supervisor
pub fn from_data<D: Atomic>(d: D, c: Context) -> Self {
AtomicReturn {
clause: d.to_atom_cls(),
gas: c.gas,
inert: false
}
}
}
// Aliases for concise macros
pub type RcError = Rc<dyn ExternError>;

View File

@@ -5,4 +5,4 @@ mod run;
pub use context::{Context, Return};
pub use error::RuntimeError;
pub use run::{run};
pub use run::{run, run_handler, Handler, HandlerParm, HandlerRes};

View File

@@ -1,4 +1,7 @@
use crate::foreign::AtomicReturn;
use std::mem;
use std::rc::Rc;
use crate::foreign::{AtomicReturn, Atomic, ExternError, Atom};
use crate::representations::Primitive;
use crate::representations::interpreted::{Clause, ExprInst};
@@ -6,9 +9,10 @@ use super::apply::apply;
use super::error::RuntimeError;
use super::context::{Context, Return};
pub fn run(expr: ExprInst, mut ctx: Context)
-> Result<Return, RuntimeError>
{
pub fn run(
expr: ExprInst,
mut ctx: Context
) -> Result<Return, RuntimeError> {
let (state, (gas, inert)) = expr.try_normalize(|cls| -> Result<(Clause, _), RuntimeError> {
let mut i = cls.clone();
while ctx.gas.map(|g| g > 0).unwrap_or(true) {
@@ -39,4 +43,67 @@ pub fn run(expr: ExprInst, mut ctx: Context)
Ok((i, (ctx.gas, false)))
})?;
Ok(Return { state, gas, inert })
}
pub type HandlerParm = Box<dyn Atomic>;
pub type HandlerRes = Result<
Result<ExprInst, Rc<dyn ExternError>>,
HandlerParm
>;
pub trait Handler {
fn resolve(&mut self, data: HandlerParm) -> HandlerRes;
fn then<T: Handler>(self, t: T) -> impl Handler
where Self: Sized {
Pair(self, t)
}
}
impl<F> Handler for F
where F: FnMut(HandlerParm) -> HandlerRes
{
fn resolve(&mut self, data: HandlerParm) -> HandlerRes {
self(data)
}
}
pub struct Pair<T, U>(T, U);
impl<T: Handler, U: Handler> Handler for Pair<T, U> {
fn resolve(&mut self, data: HandlerParm) -> HandlerRes {
match self.0.resolve(data) {
Ok(out) => Ok(out),
Err(data) => self.1.resolve(data)
}
}
}
pub fn run_handler(
mut expr: ExprInst,
mut handler: impl Handler,
mut ctx: Context
) -> Result<Return, RuntimeError> {
loop {
let ret = run(expr.clone(), ctx.clone())?;
if ret.gas == Some(0) {
return Ok(ret)
}
let state_ex = ret.state.expr();
let a = if let Clause::P(Primitive::Atom(a)) = &state_ex.clause {a}
else {
mem::drop(state_ex);
return Ok(ret)
};
let boxed = a.clone().0;
expr = match handler.resolve(boxed) {
Ok(r) => r.map_err(RuntimeError::Extern)?,
Err(e) => return Ok(Return{
gas: ret.gas,
inert: ret.inert,
state: Clause::P(Primitive::Atom(Atom(e))).wrap()
})
};
ctx.gas = ret.gas;
}
}

View File

@@ -10,6 +10,7 @@
#![feature(map_try_insert)]
#![feature(slice_group_by)]
#![feature(trait_alias)]
#![feature(return_position_impl_trait_in_trait)]
mod parse;
mod interner;

View File

@@ -1,7 +1,6 @@
use std::rc::Rc;
use hashbrown::HashMap;
use itertools::Itertools;
use crate::pipeline::error::ProjectError;
use crate::interner::{Token, Interner};

View File

@@ -1,7 +1,9 @@
use std::format;
use std::rc::Rc;
use std::fmt::{Debug, Write};
use hashbrown::HashSet;
use ordered_float::NotNan;
use crate::interner::{Token, Interner, InternedDisplay};
use crate::utils::Substack;
@@ -33,7 +35,7 @@ impl<M: InternedDisplay + Matcher> InternedDisplay for CachedRule<M> {
/// Manages a priority queue of substitution rules and allows to apply them
pub struct Repository<M: Matcher> {
cache: Vec<(CachedRule<M>, HashSet<Token<Vec<Token<String>>>>)>
cache: Vec<(CachedRule<M>, HashSet<Token<Vec<Token<String>>>>, NotNan<f64>)>
}
impl<M: Matcher> Repository<M> {
pub fn new(mut rules: Vec<Rule>, i: &Interner)
@@ -42,6 +44,7 @@ impl<M: Matcher> Repository<M> {
rules.sort_by_key(|r| -r.prio);
let cache = rules.into_iter()
.map(|r| {
let prio = r.prio;
let rule = prepare_rule(r.clone(), i)
.map_err(|e| (r, e))?;
let mut glossary = HashSet::new();
@@ -56,7 +59,7 @@ impl<M: Matcher> Repository<M> {
source: rule.source,
template: rule.target
};
Ok((prep, glossary))
Ok((prep, glossary, prio))
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Self{cache})
@@ -67,7 +70,7 @@ impl<M: Matcher> Repository<M> {
let mut glossary = HashSet::new();
code.visit_names(Substack::Bottom, &mut |op| { glossary.insert(op); });
// println!("Glossary for code: {:?}", print_nname_seq(glossary.iter(), i));
for (rule, deps) in self.cache.iter() {
for (rule, deps, _) in self.cache.iter() {
if !deps.is_subset(&glossary) { continue; }
let product = update_first_seq::expr(code, &mut |exprv| {
let state = rule.matcher.apply(exprv.as_slice())?;
@@ -122,11 +125,17 @@ impl<M: Debug + Matcher> Debug for Repository<M> {
}
}
fn fmt_hex(num: f64) -> String {
let exponent = (num.log2() / 4_f64).floor();
let mantissa = num / 16_f64.powf(exponent);
format!("0x{:x}p{}", mantissa as i64, exponent as i64)
}
impl<M: InternedDisplay + Matcher> InternedDisplay for Repository<M> {
fn fmt_i(&self, f: &mut std::fmt::Formatter<'_>, i: &Interner) -> std::fmt::Result {
writeln!(f, "Repository[")?;
for (item, _) in self.cache.iter() {
write!(f, "\t")?;
for (item, _, p) in self.cache.iter() {
write!(f, "\t{}", fmt_hex(f64::from(*p)))?;
item.fmt_i(f, i)?;
writeln!(f)?;
}

View File

@@ -4,6 +4,7 @@ use std::rc::Rc;
use hashbrown::HashMap;
use itertools::Itertools;
use crate::external::handle;
use crate::interpreter::Return;
use crate::representations::{ast_to_postmacro, postmacro_to_interpreted};
use crate::{external, xloop, interpreter};
@@ -20,30 +21,28 @@ import std::(
concatenate
)
export ...$a + ...$b =1001=> (add (...$a) (...$b))
export ...$a - ...$b:1 =1001=> (subtract (...$a) (...$b))
export ...$a * ...$b =1000=> (multiply (...$a) (...$b))
export ...$a % ...$b:1 =1000=> (remainder (...$a) (...$b))
export ...$a / ...$b:1 =1000=> (divide (...$a) (...$b))
export ...$a == ...$b =1002=> (equals (...$a) (...$b))
export ...$a ++ ...$b =1003=> (concatenate (...$a) (...$b))
export ...$a + ...$b =0x2p36=> (add (...$a) (...$b))
export ...$a - ...$b:1 =0x2p36=> (subtract (...$a) (...$b))
export ...$a * ...$b =0x1p36=> (multiply (...$a) (...$b))
export ...$a % ...$b:1 =0x1p36=> (remainder (...$a) (...$b))
export ...$a / ...$b:1 =0x1p36=> (divide (...$a) (...$b))
export ...$a == ...$b =0x3p36=> (equals (...$a) (...$b))
export ...$a ++ ...$b =0x4p36=> (concatenate (...$a) (...$b))
export do { ...$statement ; ...$rest:1 } =0x2p543=> (
statement (...$statement) do { ...$rest }
)
export do { ...$return } =0x1p543=> (...$return)
export do { ...$statement ; ...$rest:1 } =0x2p130=> statement (...$statement) do { ...$rest }
export do { ...$return } =0x1p130=> ...$return
export statement (let $name = ...$value) ...$next =0x1p1000=> (
export statement (let $name = ...$value) ...$next =0x1p230=> (
(\$name. ...$next) (...$value)
)
export statement (cps $name = ...$operation) ...$next =0x2p1000=> (
export statement (cps $name = ...$operation) ...$next =0x2p230=> (
(...$operation) \$name. ...$next
)
export statement (cps ...$operation) ...$next =0x1p1000=> (
export statement (cps ...$operation) ...$next =0x1p230=> (
(...$operation) (...$next)
)
export if ...$cond then ...$true else ...$false:1 =0x1p320=> (
export if ...$cond then ...$true else ...$false:1 =0x1p84=> (
ifthenelse (...$cond) (...$true) (...$false)
)
@@ -102,7 +101,7 @@ pub fn run_dir(dir: &Path) {
rule.bundle(&i)
)
});
// println!("Repo dump: {}", repo.bundle(&i));
println!("Repo dump: {}", repo.bundle(&i));
let mut exec_table = HashMap::new();
for (name, source) in consts.iter() {
// let nval = entrypoint(&i); let name = &nval; let source = &consts[name];
@@ -114,7 +113,7 @@ pub fn run_dir(dir: &Path) {
match repo.step(&tree) {
None => break tree,
Some(phase) => {
println!("Step {idx}/{macro_timeout}: {}", phase.bundle(&i));
// println!("Step {idx}/{macro_timeout}: {}", phase.bundle(&i));
tree = phase;
},
}
@@ -138,10 +137,11 @@ pub fn run_dir(dir: &Path) {
.join(", ")
)
});
let Return{ gas, state, inert } = interpreter::run(entrypoint.clone(), ctx)
let io_handler = handle;
let ret = interpreter::run_handler(entrypoint.clone(), io_handler, ctx);
let Return{ gas, state, inert } = ret
.unwrap_or_else(|e| panic!("Runtime error: {}", e));
if inert {
println!("Expression not reducible");
println!("Settled at {}", state.expr().clause.bundle(&i));
println!("Remaining gas: {}",
gas.map(|g| g.to_string())
@@ -149,5 +149,4 @@ pub fn run_dir(dir: &Path) {
);
}
if gas == Some(0) {println!("Ran out of gas!")}
else {println!("Expression not reducible.")}
}