Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NORM IO op code #236

Merged
merged 5 commits into from
Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions kdl/normalize.kdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ctr {Pair a b}
racs4 marked this conversation as resolved.
Show resolved Hide resolved

run {
let p = {Pair (!@x (* #2 x) #3) (!@x x @y y)};
(Done p)
}

run {
let p = {Pair (!@x (* #2 x) #3) (!@x x @y y)};
ask norm = (Norm p);
(Done norm)
}


2 changes: 1 addition & 1 deletion kindelia/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
dir = "~/.kindelia/state"

[node.network]
network_id = "0xCAFE0005"
network_id = "0xCAFE0006"
initial_peers = [
"64.227.110.69",
"188.166.3.140",
Expand Down
13 changes: 13 additions & 0 deletions kindelia_core/genesis.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,23 @@ fun (Tick) {
(Tick) = @cont {TICK cont}
}

// GIDX returns the block number and statement index inside the block
// of a function, register or constructor.
// Returns in the form of a U120:
// - most significant 60 bits are the block index
// - less signficiant 60 bits are the statement index
ctr {GIDX name cont}
fun (GetIdx name) {
(GetIdx name) = @cont {GIDX name cont}
}

// STH0 returns the less significant 120 bits hash of the statement at index idx
ctr {STH0 idx cont}
fun (GetStmHash0 idx) {
(GetStmHash0 idx) = @cont {STH0 idx cont}
}

// STH0 returns the less significant 120 bits hash of the statement at index idx
ctr {STH1 idx cont}
fun (GetStmHash1 idx) {
(GetStmHash1 idx) = @cont {STH1 idx cont}
Expand Down Expand Up @@ -116,6 +123,12 @@ fun (Fail err) {
(Fail err) = {FAIL err}
}

// NORM fully normalizes a term
ctr {NORM term cont}
fun (Norm term) {
(Norm term) = @cont {NORM term cont}
}

// LOAD works like TAKE, but clones the state
fun (Load) {
(Load) = @cont {TAKE @x dup x0 x1 = x; {SAVE x0 @~ (!cont x1)}}
Expand Down
78 changes: 77 additions & 1 deletion kindelia_core/src/hvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ const IO_GIDX : u128 = 0x4533a2; // name_to_u128("GIDX")
const IO_STH0 : u128 = 0x75e481; // name_to_u128("STH0")
const IO_STH1 : u128 = 0x75e482; // name_to_u128("STH1")
const IO_FAIL : u128 = 0x40b4d6; // name_to_u128("FAIL")
const IO_NORM : u128 = 0x619717; // name_to_u128("NORM")
// TODO: GRUN -> get run result

// Maximum mana that can be spent in a block
Expand Down Expand Up @@ -1681,6 +1682,71 @@ impl Runtime {
return Ok(done);
}

// Full-reduce a term.
pub fn normalize(&mut self, host: Loc, mana:u64, seen: &mut HashSet<RawCell>) -> Result<RawCell, RuntimeError> {
enum StackItem {
Host(Loc),
Linker(Loc)
Comment on lines +1688 to +1689
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both can be done in a single step, but I'm not going to optimize this now.

}
let mut stack = vec![StackItem::Host(host)];
let mut output = vec![];
while !stack.is_empty() {
let item = stack.pop().unwrap();
match item {
StackItem::Host(host) => {
let term = ask_lnk(self, host);
if seen.contains(&term) {
output.push(term);
}
else {
let term = reduce(self, host, mana)?;
seen.insert(term);
let mut recursive_locs = vec![];
match term.get_tag() {
CellTag::DP0 => {
recursive_locs.push(term.get_loc(2));
},
CellTag::DP1 => {
recursive_locs.push(term.get_loc(2));
},
CellTag::LAM => {
recursive_locs.push(term.get_loc(1));
},
CellTag::APP => {
recursive_locs.push(term.get_loc(0));
recursive_locs.push(term.get_loc(1));
},
CellTag::SUP => {
recursive_locs.push(term.get_loc(0));
recursive_locs.push(term.get_loc(1));
},
CellTag::CTR | CellTag::FUN => {
let name = term.get_name_from_ext();
let arity = self.get_arity(&name).ok_or_else(|| RuntimeError::CtrOrFunNotDefined { name })?;
for i in 0..arity {
recursive_locs.push(term.get_loc(i));
}
},
_ => {}
};
for loc in recursive_locs {
stack.push(StackItem::Linker(loc));
stack.push(StackItem::Host(loc));
// let lnk = self.normalize(loc, mana, seen)?;
// link(self, loc, lnk);
}
output.push(term);
}
},
StackItem::Linker(loc) => {
let lnk = output.pop().unwrap();
link(self, loc, lnk);
},
}
}
Ok(output.pop().unwrap())
}

pub fn show_term(&self, lnk: RawCell) -> String {
return show_term(self, lnk, None);
}
Expand Down Expand Up @@ -1810,6 +1876,16 @@ impl Runtime {
clear(self, term.get_loc(0), 3);
return done;
}
IO_NORM => {
let unnormalized = term.get_loc(0);
let cont = ask_arg(self, term, 1);
let normalized = self.normalize(unnormalized, mana, &mut HashSet::new())?;
let cont = alloc_app(self, cont, normalized);
let done = self.run_io(subject, caller, cont, mana);
clear(self, host, 1);
clear(self, term.get_loc(0), 2);
return done;
}
IO_GIDX => {
let fnid = ask_arg(self, term, 0);
let cont = ask_arg(self, term, 1);
Expand All @@ -1820,7 +1896,7 @@ impl Runtime {
clear(self, host, 1);
clear(self, term.get_loc(0), 2);
return done;
}
}
IO_STH0 => {
let indx = ask_arg(self, term, 0);
let cont = ask_arg(self, term, 1);
Expand Down
33 changes: 33 additions & 0 deletions kindelia_core/src/test/hvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,39 @@ fn operators_cases(#[case] code: &str, #[case] expected: u128) {
})
}

#[rstest]
#[case("{Pair (!@x x #3) (!@x x @y y)}", "{Pair #3 @y y}")]
#[case("{Pair (!(!@x @~ x #3) #4) (!@x x @y y)}", "{Pair #3 @y y}")]
#[case("{Pair (!@x (+ x #2) #1) @y y}", "{Pair #3 @y y}")]
fn normalize_cases(#[case] term: &str, #[case] expected: &str, temp_dir: TempPath) {
let code = format!("
ctr {{Pair a b}}

run {{
let term = {};
ask norm = (Norm term);
(Done norm)
}}
", term);
let mut rt = init_runtime(&temp_dir.path);
let result = rt.run_statements_from_code(&code, true, true);
match result.last().unwrap() {
Ok(StatementInfo::Run { done_term, used_mana , size_diff, end_size }) => {
if let Term::Ctr { name, args } = done_term {
if let [normal] = args.as_slice() {
assert_eq!(*name, Name::from_str("DONE").unwrap());
assert_eq!(format!("{}",normal), expected);
assert_eq!(*size_diff, 0);
}
}
else {
panic!("Not constructor.")
}
}
_ => panic!("Unexpected result.")
};
}

// ===========================================================
// Codes
pub const PRE_COUNTER: &'static str = "
Expand Down