Skip to content
Open
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
9a8e037
trying out making the classic compiler functions generic
prozacchiwawa Jul 23, 2026
030c2db
tests compile
prozacchiwawa Jul 23, 2026
d8f4504
working tests
prozacchiwawa Jul 24, 2026
408cf6d
Merge remote-tracking branch 'origin/main' into 20260722-generic-clvm
prozacchiwawa Jul 24, 2026
2061fa0
fmt
prozacchiwawa Jul 24, 2026
5a8805e
clippy
prozacchiwawa Jul 24, 2026
4eb95ac
remove change menat for another branch
prozacchiwawa Jul 24, 2026
30e51a4
fix
prozacchiwawa Jul 24, 2026
a50e981
fmt
prozacchiwawa Jul 24, 2026
7905ac3
Add modern frontend classic codegen dialect
cursoragent Jul 29, 2026
5a409e4
Clean up recursive location test
cursoragent Jul 29, 2026
d3a3cb8
mark point where we need to assemble com's first argument in modern mode
prozacchiwawa Jul 30, 2026
b380a11
Assemble modern classic compiler operators
cursoragent Jul 30, 2026
7341909
Support rest tails in classic function calls
cursoragent Jul 30, 2026
b718bce
Support environment pseudo-variable in classic codegen
cursoragent Jul 30, 2026
b5fdbe1
Reconstruct complex inline environments
cursoragent Jul 30, 2026
8ed3dfc
Cover rest tails in inline environment test
cursoragent Jul 30, 2026
b289e2e
Keep variadic environment coverage source-based
cursoragent Jul 30, 2026
f87c3a8
Add a smoke test
prozacchiwawa Jul 31, 2026
7c43c95
Fix neoclassic let code generation
cursoragent Jul 31, 2026
ba41f10
Add simple if smoke test
prozacchiwawa Jul 31, 2026
265f722
Expand modern com forms before classic codegen
cursoragent Jul 31, 2026
b7d6414
Allow testing with other sigils
prozacchiwawa Jul 31, 2026
91b0fa4
Fix classic codegen let environments
cursoragent Jul 31, 2026
4a89b08
Exercise Mandelbrot through cldb runner
cursoragent Jul 31, 2026
8f4226c
Compare run and cldb Mandelbrot output
cursoragent Jul 31, 2026
65f18f1
Match Mandelbrot test command options
cursoragent Jul 31, 2026
1c528d2
new test
prozacchiwawa Jul 31, 2026
5817ffa
Preserve numeric atoms in classic codegen
cursoragent Jul 31, 2026
95209d2
merge
prozacchiwawa Aug 4, 2026
7a04932
test function interpretation of com
prozacchiwawa Aug 4, 2026
4343043
Set up to find cause
prozacchiwawa Aug 5, 2026
695660e
Revert "Set up to find cause"
cursoragent Aug 5, 2026
2a77574
Translate com forms throughout classic codegen inputs
cursoragent Aug 5, 2026
bc9263b
Run modern optimization before classic codegen
cursoragent Aug 5, 2026
5436582
Keep classic let helpers out of modern deinline
cursoragent Aug 5, 2026
9765e1e
Keep nested classic let helpers non-inline
cursoragent Aug 5, 2026
0556b10
fmt + clippy
prozacchiwawa Aug 5, 2026
299c335
install yaml
prozacchiwawa Aug 5, 2026
5299534
yaml -> pyyaml
prozacchiwawa Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ jobs:
pip install --no-index --find-links target/wheels/ chialisp
pip install clvm_rs
pip install clvm_tools
pip install yaml
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
cd resources/tests
python test_clvm_step.py
python mandelbrot-cldb.py
Expand Down
38 changes: 34 additions & 4 deletions resources/tests/mandelbrot-cldb.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
#!/usr/bin/env python

import subprocess
import argparse
import yaml
import io

command = ['../../target/debug/cldb', '-p', './mandelbrot/mandelbrot.clsp', '(-192 -128 -144 -96 8)']
want_output = """---
parser = argparse.ArgumentParser()
parser.add_argument('-sigil', default=None)
args = parser.parse_args()

infile = './mandelbrot/mandelbrot.clsp'
if args.sigil:
mb = open(infile).read()
infile = f'{infile}.sigil'
with open(infile, 'w') as outf:
outf.write(mb.replace('*standard-cl-21*', args.sigil))

command = ['../../target/debug/cldb', '-p', infile, '(-192 -128 -144 -96 8)']
want_output = f"""---
- Print: ((escape-at -152 -104) 14)
- Print: ((escape-at -160 -104) 14)
- Print: ((escape-at -168 -104) 14)
Expand All @@ -30,8 +44,24 @@
- Print: ((escape-at -192 -128) 5)
- Print: "(\\"result\\" \\"||567AAC|68DEEE|78EEEE|78BEEE\\")"
- Final: "3356114000950459963475899699747220812557867594760040767593731831711045"
Final-Location: "./mandelbrot/mandelbrot.clsp(8):43"
Final-Location: "{infile}(8):43"
"""

have_output = subprocess.check_output(command).decode('utf8')
assert have_output == want_output
parsed_have = yaml.safe_load(io.StringIO(have_output))
parsed_want = yaml.safe_load(io.StringIO(want_output))

def dequote(kv):
result = {}
for k in kv.keys():
result[k] = kv[k].replace('"','')
return result

if args.sigil:
if 'Final-Location' in parsed_have[-1]:
del parsed_have[-1]['Final-Location']
del parsed_want[-1]['Final-Location']
parsed_have = list(map(dequote, parsed_have))
parsed_want = list(map(dequote, parsed_want))

assert parsed_have == parsed_want
171 changes: 103 additions & 68 deletions src/classic/clvm/sexp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use clvm_rs::error::EvalErr;

use crate::classic::clvm::__type_compatibility__::{Bytes, BytesFromType, Stream};
use crate::classic::clvm::serialize::sexp_to_stream;
use crate::classic::clvm_tools::stages::stage_2::abstraction::{ASExp, ClError, ClassicAllocator};
use crate::compiler::srcloc::Srcloc;
use crate::util::{u8_from_number, Number};

#[derive(Debug)]
Expand Down Expand Up @@ -344,21 +346,28 @@ pub fn non_nil(allocator: &Allocator, sexp: NodePtr) -> bool {
}
}

pub fn first(allocator: &Allocator, sexp: NodePtr) -> Result<NodePtr, EvalErr> {
match allocator.sexp(sexp) {
SExp::Pair(f, _) => Ok(f),
_ => Err(EvalErr::InternalError(
sexp,
"first of non-cons".to_string(),
)),
pub fn first<A: ClassicAllocator>(allocator: &A, sexp: &A::NodePtr) -> Result<A::NodePtr, ClError> {
let exported = allocator.export(sexp);
if let ASExp::Pair(f, _) = allocator.sexp(sexp) {
return Ok(f);
}

Err(ClError(
allocator.loc(sexp),
EvalErr::InternalError(exported, "first of non-cons".to_string()),
))
}

pub fn rest(allocator: &Allocator, sexp: NodePtr) -> Result<NodePtr, EvalErr> {
match allocator.sexp(sexp) {
SExp::Pair(_, r) => Ok(r),
_ => Err(EvalErr::InternalError(sexp, "rest of non-cons".to_string())),
pub fn rest<A: ClassicAllocator>(allocator: &A, sexp: &A::NodePtr) -> Result<A::NodePtr, ClError> {
let exported = allocator.export(sexp);
if let ASExp::Pair(_, r) = allocator.sexp(sexp) {
return Ok(r);
}

Err(ClError(
allocator.loc(sexp),
EvalErr::InternalError(exported, "rest of non-cons".to_string()),
))
}

pub fn atom(allocator: &Allocator, sexp: NodePtr) -> Result<Vec<u8>, EvalErr> {
Expand All @@ -372,19 +381,26 @@ pub fn atom(allocator: &Allocator, sexp: NodePtr) -> Result<Vec<u8>, EvalErr> {
}
}

pub fn proper_list(allocator: &Allocator, sexp: NodePtr, store: bool) -> Option<Vec<NodePtr>> {
pub fn proper_list<A: ClassicAllocator>(
allocator: &A,
sexp: &A::NodePtr,
store: bool,
) -> Option<Vec<A::NodePtr>>
where
A::NodePtr: Clone,
{
let mut args = vec![];
let mut args_sexp = sexp;
let mut args_sexp = sexp.clone();
loop {
match allocator.sexp(args_sexp) {
SExp::Atom => {
if !non_nil(allocator, args_sexp) {
match allocator.sexp(&args_sexp) {
ASExp::Atom => {
if allocator.is_nil(&args_sexp) {
return Some(args);
} else {
return None;
}
}
SExp::Pair(f, r) => {
ASExp::Pair(f, r) => {
if store {
args.push(f);
}
Expand All @@ -394,21 +410,31 @@ pub fn proper_list(allocator: &Allocator, sexp: NodePtr, store: bool) -> Option<
}
}

pub fn enlist(allocator: &mut Allocator, vec: &[NodePtr]) -> Result<NodePtr, EvalErr> {
let mut built = NodePtr::NIL;
pub fn enlist<A: ClassicAllocator>(
allocator: &mut A,
vec: &[A::NodePtr],
) -> Result<A::NodePtr, ClError>
where
A::NodePtr: Clone,
{
let mut built = allocator.import(Srcloc::start("*nil*"), NodePtr::NIL)?;

for i_reverse in 0..vec.len() {
let i = vec.len() - i_reverse - 1;
built = allocator.new_pair(vec[i], built)?;
let loc = allocator.loc(&vec[i]);
built = allocator.new_pair(loc, &vec[i], &built)?;
}
Ok(built)
}

pub fn map_m<T>(
allocator: &mut Allocator,
type MapMTransform<'a, A, T> =
&'a dyn Fn(&mut A, T) -> Result<<A as ClassicAllocator>::NodePtr, ClError>;

pub fn map_m<'a, T, A: ClassicAllocator>(
allocator: &mut A,
iter: &mut impl Iterator<Item = T>,
f: &dyn Fn(&mut Allocator, T) -> Result<NodePtr, EvalErr>,
) -> Result<Vec<NodePtr>, EvalErr> {
f: MapMTransform<'a, A, T>,
) -> Result<Vec<A::NodePtr>, ClError> {
let mut result = Vec::new();
loop {
match iter.next() {
Expand All @@ -427,9 +453,9 @@ pub fn map_m<T>(
}
}

pub fn fold_m<A, B, E>(
allocator: &mut Allocator,
f: &dyn Fn(&mut Allocator, A, B) -> Result<A, E>,
pub fn fold_m<A, B, E, CA: ClassicAllocator>(
allocator: &mut CA,
f: &dyn Fn(&mut CA, A, B) -> Result<A, E>,
start_: A,
iter: &mut impl Iterator<Item = B>,
) -> Result<A, E> {
Expand All @@ -451,21 +477,28 @@ pub fn fold_m<A, B, E>(
}
}

pub fn equal_to(allocator: &mut Allocator, first_: NodePtr, second_: NodePtr) -> bool {
let mut first = first_;
let mut second = second_;
pub fn equal_to<A: ClassicAllocator>(
allocator: &mut A,
first_: &A::NodePtr,
second_: &A::NodePtr,
) -> bool
where
A::NodePtr: Clone,
{
let mut first = first_.clone();
let mut second = second_.clone();

loop {
if first == second {
if allocator.node_equal(&first, &second) {
return true;
}
match (allocator.sexp(first), allocator.sexp(second)) {
(SExp::Atom, SExp::Atom) => {
match (allocator.sexp(&first), allocator.sexp(&second)) {
(ASExp::Atom, ASExp::Atom) => {
// two atoms in scope, both are used
return allocator.atom(first) == allocator.atom(second);
return allocator.atom(&first) == allocator.atom(&second);
}
(SExp::Pair(ff, fr), SExp::Pair(rf, rr)) => {
if !equal_to(allocator, ff, rf) {
(ASExp::Pair(ff, fr), ASExp::Pair(rf, rr)) => {
if !equal_to(allocator, &ff, &rf) {
return false;
}
first = fr;
Expand All @@ -478,19 +511,25 @@ pub fn equal_to(allocator: &mut Allocator, first_: NodePtr, second_: NodePtr) ->
}
}

pub fn flatten(allocator: &mut Allocator, tree_: NodePtr, res: &mut Vec<NodePtr>) {
let mut tree = tree_;
pub fn flatten<A: ClassicAllocator>(
allocator: &mut A,
tree_: &A::NodePtr,
res: &mut Vec<A::NodePtr>,
) where
A::NodePtr: Clone,
{
let mut tree = tree_.clone();

loop {
match allocator.sexp(tree) {
SExp::Atom => {
if non_nil(allocator, tree) {
res.push(tree);
match allocator.sexp(&tree) {
ASExp::Atom => {
if !allocator.is_nil(&tree) {
res.push(tree.clone());
}
return;
}
SExp::Pair(l, r) => {
flatten(allocator, l, res);
ASExp::Pair(l, r) => {
flatten(allocator, &l, res);
tree = r;
}
}
Expand All @@ -501,10 +540,10 @@ pub fn flatten(allocator: &mut Allocator, tree_: NodePtr, res: &mut Vec<NodePtr>
// the classic chialisp code.
pub fn nonempty_last<X>(nil: NodePtr, lst: &[X]) -> Result<X, EvalErr>
where
X: Copy,
X: Clone,
{
lst.last()
.copied()
.cloned()
.ok_or_else(|| EvalErr::InternalError(nil, "alist is empty and shouldn't be".to_string()))
}

Expand Down Expand Up @@ -533,57 +572,53 @@ pub enum ThisNode {
Here,
}

pub trait SelectNode<T> {
fn select_nodes(&self, allocator: &mut Allocator, n: NodePtr) -> Result<T, EvalErr>;
pub trait SelectNode<T, A: ClassicAllocator> {
fn select_nodes(&self, allocator: &mut A, n: A::NodePtr) -> Result<T, ClError>;
}

impl SelectNode<NodePtr> for ThisNode {
fn select_nodes(&self, _allocator: &mut Allocator, n: NodePtr) -> Result<NodePtr, EvalErr> {
impl<A: ClassicAllocator> SelectNode<A::NodePtr, A> for ThisNode {
fn select_nodes(&self, _allocator: &mut A, n: A::NodePtr) -> Result<A::NodePtr, ClError> {
Ok(n)
}
}

impl SelectNode<()> for () {
fn select_nodes(&self, _allocator: &mut Allocator, _n: NodePtr) -> Result<(), EvalErr> {
impl<A: ClassicAllocator> SelectNode<(), A> for () {
fn select_nodes(&self, _allocator: &mut A, _n: A::NodePtr) -> Result<(), ClError> {
Ok(())
}
}

impl<R, T> SelectNode<First<T>> for First<R>
impl<R, T, A: ClassicAllocator> SelectNode<First<T>, A> for First<R>
where
R: SelectNode<T> + Clone,
R: SelectNode<T, A> + Clone,
{
fn select_nodes(&self, allocator: &mut Allocator, n: NodePtr) -> Result<First<T>, EvalErr> {
fn select_nodes(&self, allocator: &mut A, n: A::NodePtr) -> Result<First<T>, ClError> {
let First::Here(f) = &self;
let NodeSel::Cons(first, ()) = NodeSel::Cons(f.clone(), ()).select_nodes(allocator, n)?;
Ok(First::Here(first))
}
}

impl<R, T> SelectNode<Rest<T>> for Rest<R>
impl<R, T, A: ClassicAllocator> SelectNode<Rest<T>, A> for Rest<R>
where
R: SelectNode<T> + Clone,
R: SelectNode<T, A> + Clone,
{
fn select_nodes(&self, allocator: &mut Allocator, n: NodePtr) -> Result<Rest<T>, EvalErr> {
fn select_nodes(&self, allocator: &mut A, n: A::NodePtr) -> Result<Rest<T>, ClError> {
let Rest::Here(f) = &self;
let NodeSel::Cons((), rest) = NodeSel::Cons((), f.clone()).select_nodes(allocator, n)?;
Ok(Rest::Here(rest))
}
}

impl<R, S, T, U> SelectNode<NodeSel<T, U>> for NodeSel<R, S>
impl<R, S, T, U, A: ClassicAllocator> SelectNode<NodeSel<T, U>, A> for NodeSel<R, S>
where
R: SelectNode<T>,
S: SelectNode<U>,
R: SelectNode<T, A>,
S: SelectNode<U, A>,
{
fn select_nodes(
&self,
allocator: &mut Allocator,
n: NodePtr,
) -> Result<NodeSel<T, U>, EvalErr> {
fn select_nodes(&self, allocator: &mut A, n: A::NodePtr) -> Result<NodeSel<T, U>, ClError> {
let NodeSel::Cons(my_left, my_right) = &self;
let l = first(allocator, n)?;
let r = rest(allocator, n)?;
let l = first(allocator, &n)?;
let r = rest(allocator, &n)?;
let first = my_left.select_nodes(allocator, l)?;
let rest = my_right.select_nodes(allocator, r)?;
Ok(NodeSel::Cons(first, rest))
Expand Down
2 changes: 1 addition & 1 deletion src/classic/clvm_tools/cmds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,7 @@ fn fix_log(

for (i, entry) in log_result.to_vec().iter().enumerate() {
update_map.get(entry).and_then(|v| *v).map(|v| {
proper_list(allocator, *entry, true).map(|list| {
proper_list(allocator, entry, true).map(|list| {
let mut updated = list.to_vec();
updated.push(v);
log_result[i] = enlist(allocator, &updated).unwrap();
Expand Down
Loading
Loading