WIP: offchain-start #14

Draft
GlowingOutlaw wants to merge 10 commits from offchain-start into main
7 changed files with 115 additions and 32 deletions
Showing only changes of commit 73f3bca656 - Show all commits
+1
View File
@@ -879,6 +879,7 @@ dependencies = [
name = "offchain"
version = "0.1.0"
dependencies = [
"rand",
"revm",
"serde",
"serde_json",
+2 -1
View File
@@ -6,4 +6,5 @@ edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
revm = "18.0.0"
revm = "18.0.0"
rand = "0.8"
+104 -5
View File
@@ -1,15 +1,114 @@
pub trait Push3Ast {
/// Convert this AST into a bytecode array (Push3 tokens).
fn to_bytecode(&self) -> Vec<u8>;
/// Parse an AST from bytecode (the "decompiler"), if possible.
/// Possibly returns a Result in case of partial/invalid parse.
fn from_bytecode(data: &[u8]) -> Self
where
Self: Sized;
/// Randomly mutate this AST in-place (GP mutation).
fn mutate(&mut self, rng: &mut impl rand::Rng);
/// Possibly a "crossover" method, or we do it externally.
// fn crossover(&self, other: &Self, rng: &mut impl rand::Rng) -> Self;
/// Evaluate the AST with some input(s).
/// Optionally do we want this or do we always run in EVM?
/// We can stub it or do an interpret approach for local test.
fn interpret_locally(&self, inputs: &[i32]) -> Vec<i32>;
}
#[derive(Debug, Clone)]
pub enum Expr {
pub enum TypedAst {
IntLiteral(i32),
Instruction(InstructionKind, Vec<Expr>),
// You might have a variant for sublists if needed,
// or keep it all in the same structure.
Instruction(InstructionKind),
}
#[derive(Debug, Clone)]
pub enum InstructionKind {
// e.g. Plus, Minus, Mult, etc.
Plus(Box<TypedAst>, Box<TypedAst>),
Minus(Box<TypedAst>, Box<TypedAst>),
Mult(Box<TypedAst>, Box<TypedAst>),
Dup, // 0 children
Pop, // 0 children
}
impl Push3Ast for TypedAst {
fn to_bytecode(&self) -> Vec<u8> {
// do typed encoding:
// - for Plus(e1, e2): e1 -> bytecode, e2 -> bytecode, then PLUS opcode
unimplemented!()
}
fn from_bytecode(data: &[u8]) -> Self {
// parse in a strictly typed manner; might fail or panic
// if the code doesn't line up properly
unimplemented!()
}
fn mutate(&mut self, rng: &mut impl rand::Rng) {
// e.g. randomly pick a node, replace it with something
// that respects the typed structure
unimplemented!()
}
fn interpret_locally(&self, inputs: &[i32]) -> Vec<i32> {
// do a normal expression evaluation. If a node is "Plus(a,b)",
// interpret (a) + interpret(b).
unimplemented!()
}
}
#[derive(Debug, Clone)]
pub enum UntypedAst {
/// A single token in a list-based approach, e.g. "Integer literal"
IntLiteral(i32),
/// "Instruction" might be a simple variant with no children,
/// because the stack-based evaluation decides how many arguments it consumes.
Instruction(OpCode),
/// A sublist of tokens, e.g. "( 2 3 DUP + )"
Sublist(Vec<UntypedAst>),
}
/// Possibly an enum for OpCode:
#[derive(Debug, Clone)]
pub enum OpCode {
Noop,
Plus,
Minus,
Mult,
Dup,
Pop,
// maybe Unknown => treat as no-op
}
impl Push3Ast for UntypedAst {
fn to_bytecode(&self) -> Vec<u8> {
// flatten out sublists vs instructions
unimplemented!()
}
fn from_bytecode(data: &[u8]) -> Self {
// parse "0x02 => INT_LITERAL => read next 4 bytes"
// instructions might have no subchildren
unimplemented!()
}
fn mutate(&mut self, rng: &mut impl rand::Rng) {
// can randomly insert unknown tokens, reorder sublists, etc.
// possibly produce "invalid ops => noops"
unimplemented!()
}
fn interpret_locally(&self, inputs: &[i32]) -> Vec<i32> {
// push-based interpretation:
// sublist => interpret each item in sequence
// if an instruction sees insufficient args => no-op
unimplemented!()
}
}
@@ -1,7 +0,0 @@
use super::ast::{Expr, InstructionKind};
pub fn ast_to_bytecode(expr: &Expr) -> Vec<u8> {
// for now, just a stub
// eventually we produce push3 tokens
vec![]
}
-7
View File
@@ -1,7 +0,0 @@
use super::ast::{Expr};
pub fn bytecode_to_ast(data: &[u8]) -> Expr {
// parse tokens, produce expr
// stub for now
Expr::IntLiteral(0)
}
-4
View File
@@ -1,5 +1 @@
pub mod ast;
pub mod bytecode_generator;
pub mod bytecode_parser;
// In the future, we'll define or `pub use` them.
+8 -8
View File
@@ -1,10 +1,10 @@
use crate::compiler::ast::{Expr};
// use crate::compiler::ast::{Expr};
pub fn crossover(a: &Expr, b: &Expr) -> (Expr, Expr) {
// stub
(a.clone(), b.clone())
}
// pub fn crossover(a: &Expr, b: &Expr) -> (Expr, Expr) {
// // stub
// (a.clone(), b.clone())
// }
pub fn mutate(expr: &mut Expr) {
// stub
}
// pub fn mutate(expr: &mut Expr) {
// // stub
// }