diff --git a/kindelia_core/genesis.kdl b/kindelia_core/genesis.kdl index 58672365..4c0260d0 100644 --- a/kindelia_core/genesis.kdl +++ b/kindelia_core/genesis.kdl @@ -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} @@ -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)}} diff --git a/kindelia_core/src/hvm.rs b/kindelia_core/src/hvm.rs index 9c3f7c73..15fde9a7 100644 --- a/kindelia_core/src/hvm.rs +++ b/kindelia_core/src/hvm.rs @@ -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 @@ -1681,6 +1682,52 @@ impl Runtime { return Ok(done); } + // Full-reduce a term. + // TODO: rewrite as stack based? not needed? + pub fn normalize(&mut self, host: Loc, mana:u64, seen: &mut HashSet) -> Result { + let term = ask_lnk(self, host); + if seen.contains(&term) { + Ok(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(0)); + }, + CellTag::SUP => { + recursive_locs.push(term.get_loc(0)); + recursive_locs.push(term.get_loc(0)); + }, + 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 { + let lnk = self.normalize(loc, mana, seen)?; + link(self, loc, lnk); + } + Ok(term) + } + } + pub fn show_term(&self, lnk: RawCell) -> String { return show_term(self, lnk, None); } @@ -1810,6 +1857,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); @@ -1820,7 +1877,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);