WIP: offchain-start #14
Generated
+1
@@ -879,6 +879,7 @@ dependencies = [
|
|||||||
name = "offchain"
|
name = "offchain"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"rand",
|
||||||
"revm",
|
"revm",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ edition = "2021"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
revm = "18.0.0"
|
revm = "18.0.0"
|
||||||
|
rand = "0.8"
|
||||||
@@ -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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expr {
|
pub enum TypedAst {
|
||||||
IntLiteral(i32),
|
IntLiteral(i32),
|
||||||
Instruction(InstructionKind, Vec<Expr>),
|
Instruction(InstructionKind),
|
||||||
// You might have a variant for sublists if needed,
|
|
||||||
// or keep it all in the same structure.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum InstructionKind {
|
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,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
Mult,
|
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![]
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,5 +1 @@
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod bytecode_generator;
|
|
||||||
pub mod bytecode_parser;
|
|
||||||
|
|
||||||
// In the future, we'll define or `pub use` them.
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::compiler::ast::{Expr};
|
// use crate::compiler::ast::{Expr};
|
||||||
|
|
||||||
pub fn crossover(a: &Expr, b: &Expr) -> (Expr, Expr) {
|
// pub fn crossover(a: &Expr, b: &Expr) -> (Expr, Expr) {
|
||||||
// stub
|
// // stub
|
||||||
(a.clone(), b.clone())
|
// (a.clone(), b.clone())
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn mutate(expr: &mut Expr) {
|
// pub fn mutate(expr: &mut Expr) {
|
||||||
// stub
|
// // stub
|
||||||
}
|
// }
|
||||||
|
|||||||
Reference in New Issue
Block a user