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

Abstract Core #28

Merged
merged 35 commits into from Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e677a81
Begin shifting to new architecture; add abstract machine, inst, exec_…
WilfredTA Apr 26, 2022
15315eb
Implement exec on abstract machine
WilfredTA Apr 26, 2022
f8e3a3c
remove todo when exec halts
WilfredTA Apr 26, 2022
538328a
Add transpile from symstack::Constraint to solver-specific ast
WilfredTA Apr 26, 2022
557a622
Implement transpile from generic constraints to z3; define simple lan…
WilfredTA Apr 27, 2022
c5f54b0
Add github actions workflow
WilfredTA May 4, 2022
1bafb11
Add abstract value for representing interchangeable values
WilfredTA May 4, 2022
1311dba
cleaned compiler warnings; ported ADD instruction (#18)
williamberman May 23, 2022
16285f1
more concrete instructions; removed prev val from mem op (#19)
williamberman May 24, 2022
b1302b4
Instructions as Singletons; Modularize AbstractMachine
williamberman Jun 1, 2022
696614e
Minor fixes; add test for concrete execution
WilfredTA Jun 3, 2022
6576eed
Add new abstract val to replace all other vals; ops on val construct …
WilfredTA Jun 3, 2022
a243da5
Construct AST during execution
WilfredTA Jun 6, 2022
c0284af
Split value into smaller modules; define constrained traits
WilfredTA Jun 6, 2022
8587a14
fix arith naming conflict
WilfredTA Jun 6, 2022
9788f1b
move environment to its own package in core (#21)
williamberman Jun 14, 2022
884b37f
remove instructions val and dependencies
williamberman Jun 16, 2022
f8fcb9f
Merge pull request #22 from williamberman/will/remove-instructions-val
WilfredTA Jun 19, 2022
f7678e7
Add better val repr with ast & visitor
WilfredTA Jun 23, 2022
0a3d84c
remove generic from stack (#24)
williamberman Jun 28, 2022
f6917f0
Simplify AST; add interpreter skeleton with pre and post hooks to fac…
WilfredTA Jun 29, 2022
1c27549
Add symbolic bool
WilfredTA Jun 29, 2022
639420c
Add Final hook, simplify pre and post hooks in interpreter
WilfredTA Jun 29, 2022
2fe0b8c
remove memory generic (#25)
williamberman Jun 29, 2022
87866ac
Enum as inner to basic vals, test with hooks
WilfredTA Jun 29, 2022
82e2097
Make test slightly nicer; add comments
WilfredTA Jun 29, 2022
a4b22f1
remove env generic (#26)
williamberman Jul 1, 2022
4894d0f
update interpreter module; fix contrib dep
WilfredTA Jul 1, 2022
93ccadc
remove generic from constraint (#27)
williamberman Jul 1, 2022
85b85bd
fmt
WilfredTA Jul 14, 2022
b101982
Use ast for intermediate representation
WilfredTA Jul 14, 2022
84e1aa3
Remove deprecated value types
WilfredTA Jul 14, 2022
77771fd
Fix some linter warnings
WilfredTA Jul 14, 2022
161c0c8
Fix some linter warnings
WilfredTA Jul 14, 2022
fd6cf62
fmt
WilfredTA Jul 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/general.yml
@@ -0,0 +1,28 @@
on: pull_request

name: Tests

jobs:
tests:
name: Check
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy

- name: cargo test
run: cargo test

- name: cargo fmt
run: cargo fmt --all -- --check

- name: cargo clippy
run: cargo clippy -- -D warnings
13 changes: 9 additions & 4 deletions Cargo.toml
Expand Up @@ -7,7 +7,12 @@ authors = ["Tannr Allard <tannr@hey.com>"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
byteorder = "1.4.3"
hex = "0.4.3"
thiserror = "1.0.30"
z3 = "0.11.2"
symbolic-stack-machines-core = {path = "./core", optional = true}
symbolic-stack-machines-contrib = {path = "./contrib", optional = true}

[workspace]
members = ["core", "contrib"]

[features]
core = ["symbolic-stack-machines-core"]
full = ["symbolic-stack-machines-core", "symbolic-stack-machines-contrib"]
10 changes: 10 additions & 0 deletions contrib/Cargo.toml
@@ -0,0 +1,10 @@
[package]
name = "symbolic-stack-machines-contrib"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
symbolic-stack-machines-core = {path = "../core"}
z3 = "0.11.2"
1 change: 1 addition & 0 deletions contrib/src/constraints/mod.rs
@@ -0,0 +1 @@
pub mod z3;
228 changes: 228 additions & 0 deletions contrib/src/constraints/z3.rs
@@ -0,0 +1,228 @@
use symbolic_stack_machines_core::constraint::*;
use symbolic_stack_machines_core::value::Number as AbstractInt;
use z3::ast::Int;
use z3::{Config, Context, Model, Solver as Z3InnerSolver};

pub type ValInt = AbstractInt;

pub struct Z3SolverBuilder {
ctx: Option<Context>,
}

impl<'a> Z3SolverBuilder {
pub fn new() -> Self {
Self { ctx: None }
}

pub fn ctx(mut self, cfg: Option<Config>) -> Self {
self.ctx = Some(Context::new(&cfg.unwrap_or_default()));
self
}

pub fn build(self) -> Z3Solver<'a> {
Z3Solver {
inner: None,
constraints: vec![],
ctx: self.ctx.unwrap(),
}
}
}
pub struct Z3Solver<'a> {
inner: Option<Z3InnerSolver<'a>>,
constraints: Vec<Constraint>,
ctx: Context,
}

impl<'a> Z3Solver<'a> {
pub fn inner(&self) -> &Z3InnerSolver<'a> {
assert!(self.inner.is_some());
self.inner.as_ref().unwrap()
}
pub fn get_ctx(&self) -> &'a Context {
self.inner().get_context()
}

pub fn get_constraints(&self) -> &Vec<Constraint> {
&self.constraints
}

pub fn set_solver(&'a mut self) {
self.inner = Some(Z3InnerSolver::new(&self.ctx));
}
}

pub fn z3_int<'a>(i: u64, ctxt: &'a Context) -> z3::ast::Int<'a> {
Int::from_u64(ctxt, i)
}

pub fn z3_int_var<'a>(i: &str, ctxt: &'a Context) -> z3::ast::Int<'a> {
Int::new_const(ctxt, i)
}

impl<'a> Constrained for Z3Solver<'a> {
type Model = Model<'a>;

fn check(&self) -> SatResult<Self::Model> {
todo!()
}
}

// impl<'a> Solver<ValInt, Int<'a>> for Z3Solver<'a> {
// fn solve(&self) -> SatResult<Self::Model> {
// match self.inner().check() {
// Z3SatResult::Sat => SatResult::Sat(self.inner().get_model().unwrap()),
// Z3SatResult::Unsat => SatResult::Unsat,
// Z3SatResult::Unknown => SatResult::Unknown,
// }
// }

// fn generic_assert(&mut self, constraint: &Constraint) {
// self.inner().assert(&self.transpile(constraint));
// }
// }

// impl<'a> Solver<u64, Int<'a>> for Z3Solver<'a> {
// fn solve(&self) -> SatResult<Self::Model> {
// match self.inner().check() {
// Z3SatResult::Sat => SatResult::Sat(self.inner().get_model().unwrap()),
// Z3SatResult::Unsat => SatResult::Unsat,
// Z3SatResult::Unknown => SatResult::Unknown,
// }
// }

// fn generic_assert(&mut self, constraint: &Constraint) {
// self.inner().assert(&self.transpile(constraint));
// }
// }

// TO DO: Generic impl

// impl<'a, T, A> Transpile<T, Bool<'a>, A> for Z3Solver<'a, T>
// where A: From<T> + Ast<'a>
// {

// }

// TODO(tannr): Impl Transpile from

// impl<'a> Transpile<u64, Int<'a>> for Z3Solver<'a> {
// fn val_to_ground_type(&self, v: u64) -> Int<'a> {
// z3_int(v, self.get_ctx())
// }

// fn ground_type_to_val(&self, g: Int<'a>) -> u64 {
// g.as_u64().unwrap()
// }

// fn assert(&self, c: Bool<'a>) -> Bool<'a> {
// self.inner().assert(&c);
// c
// }

// fn and(&self, l: Bool<'a>, r: Bool<'a>) -> Bool<'a> {
// z3::ast::Bool::and(l.get_ctx(), &vec![&l, &r])
// }

// fn not(&self, c: Bool<'a>) -> Bool<'a> {
// z3::ast::Bool::not(&c)
// }

// fn or(&self, l: Bool<'a>, r: Bool<'a>) -> Bool<'a> {
// z3::ast::Bool::or(l.get_ctx(), &vec![&l, &r])
// }

// fn gt(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.gt(&r)
// }

// fn lt(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.lt(&r)
// }

// fn lte(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.le(&r)
// }

// fn gte(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.ge(&r)
// }

// fn eq(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l._eq(&r)
// }

// fn neq(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// self.not(self.eq(l, r))
// }

// fn true_(&self) -> Bool<'a> {
// Bool::from_bool(&self.get_ctx(), true)
// }

// fn false_(&self) -> Bool<'a> {
// Bool::from_bool(&self.get_ctx(), false)
// }
// }

// impl<'a> Transpile<Bool<'a>, Int<'a>> for Z3Solver<'a> {
// fn val_to_ground_type(&self, v: ValInt) -> Int<'a> {
// if let Some(val) = v.inner() {
// z3_int(val, self.get_ctx())
// } else {
// z3_int_var(v.id(), self.get_ctx())
// }
// }

// fn ground_type_to_val(&self, g: Int<'a>) -> ValInt {
// ValInt::new(g.as_u64().unwrap(), Some(g.to_string()))
// }

// fn assert(&self, c: Bool<'a>) -> Bool<'a> {
// self.inner().assert(&c);
// c
// }

// fn and(&self, l: Bool<'a>, r: Bool<'a>) -> Bool<'a> {
// z3::ast::Bool::and(l.get_ctx(), &vec![&l, &r])
// }

// fn not(&self, c: Bool<'a>) -> Bool<'a> {
// z3::ast::Bool::not(&c)
// }

// fn or(&self, l: Bool<'a>, r: Bool<'a>) -> Bool<'a> {
// z3::ast::Bool::or(l.get_ctx(), &vec![&l, &r])
// }

// fn gt(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.gt(&r)
// }

// fn lt(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.lt(&r)
// }

// fn lte(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.le(&r)
// }

// fn gte(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l.ge(&r)
// }

// fn eq(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// l._eq(&r)
// }

// fn neq(&self, l: Int<'a>, r: Int<'a>) -> Bool<'a> {
// self.not(self.eq(l, r))
// }

// fn true_(&self) -> Bool<'a> {
// Bool::from_bool(&self.get_ctx(), true)
// }

// fn false_(&self) -> Bool<'a> {
// Bool::from_bool(&self.get_ctx(), false)
// }
// }
60 changes: 60 additions & 0 deletions contrib/src/instructions/arith.rs
@@ -0,0 +1,60 @@
use symbolic_stack_machines_core::{
environment::Env,
instructions::{AbstractExecRecord, AbstractInstruction, InstructionResult},
memory::Memory,
stack::{Stack, StackOpRecord, StackRecord},
};

pub struct ADD;

impl AbstractInstruction<AbstractExecRecord> for ADD {
fn exec(
&self,
stack: &Stack,
_mem: &Memory,
_ext: &Env,
) -> InstructionResult<AbstractExecRecord> {
let mut change_log = AbstractExecRecord::default();

let op_1 = stack.peek(0).unwrap();
let op_2 = stack.peek(1).unwrap();
let res = *op_1 + *op_2;

change_log.stack_diff = Some(StackRecord {
changed: vec![
StackOpRecord::Pop,
StackOpRecord::Pop,
StackOpRecord::Push(res),
],
});

Ok(change_log)
}
}

pub struct SUB;

impl AbstractInstruction<AbstractExecRecord> for SUB {
fn exec(
&self,
stack: &Stack,
_mem: &Memory,
_ext: &Env,
) -> InstructionResult<AbstractExecRecord> {
let mut change_log = AbstractExecRecord::default();

let op_1 = stack.peek(0).unwrap();
let op_2 = stack.peek(1).unwrap();
let res = *op_1 - *op_2;

change_log.stack_diff = Some(StackRecord {
changed: vec![
StackOpRecord::Pop,
StackOpRecord::Pop,
StackOpRecord::Push(res),
],
});

Ok(change_log)
}
}
29 changes: 29 additions & 0 deletions contrib/src/instructions/bitwise.rs
@@ -0,0 +1,29 @@
use symbolic_stack_machines_core::{
environment::Env,
instructions::{AbstractExecRecord, AbstractInstruction, InstructionResult},
memory::Memory,
stack::{Stack, StackOpRecord, StackRecord, ONE, ZERO},
};

pub struct ISZERO;

impl AbstractInstruction<AbstractExecRecord> for ISZERO {
fn exec(
&self,
stack: &Stack,
_memory: &Memory,
_ext: &Env,
) -> InstructionResult<AbstractExecRecord> {
let mut change_log = AbstractExecRecord::default();

let op = stack.peek(0).unwrap();

let rv = op._eq(&ZERO).ite(ONE, ZERO);

change_log.stack_diff = Some(StackRecord {
changed: vec![StackOpRecord::Pop, StackOpRecord::Push(rv)],
});

Ok(change_log)
}
}