Skip to content

Commit

Permalink
Continue rewriting the generator.
Browse files Browse the repository at this point in the history
  • Loading branch information
vakaras committed Jan 10, 2020
1 parent 45079ca commit 1848804
Show file tree
Hide file tree
Showing 7 changed files with 406 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2018"

[dependencies]
rustc-hash = "1.0.0"
syn = "1.0.8"
syn = { version = "1.0.8", features = ["extra-traits"] }
proc-macro2 = { version = "1.0.6", features = ["span-locations"] }
quote = "1.0.2"
log = "0.4.8"
Expand Down
9 changes: 9 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ pub enum Arg {
Wildcard,
}

impl Arg {
pub fn to_ident(&self) -> syn::Ident {
match self {
Arg::Ident(ident) => ident.clone(),
Arg::Wildcard => syn::Ident::new("_", proc_macro2::Span::call_site()),
}
}
}

impl fmt::Display for Arg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand Down
134 changes: 104 additions & 30 deletions src/generator_new/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! r(x, y) = in(y, x);
//! ```
//! ``in`` is assumed to be a variable of type ``&Vec<(u32, u32)>``.
//! ```rust
//! ```ignore
//! let r = in.iter().map(|(y, x)| {(x, y)});
//! ```
//!
Expand All @@ -21,7 +21,7 @@
//! r(x, y) = r(x, z), r(z, y);
//! ```
//! ``in`` is assumed to be a variable of type ``&Vec<(u32, u32)>``.
//! ```rust
//! ```ignore
//! let mut iteration = Iteration::new();
//! let r = iteration.variable::<(u32, u32)>("r");
//! let r_1 = iteration.variable::<(u32, u32)>("r_1");
Expand All @@ -34,63 +34,106 @@
//! let r = in.iter().map(|(y, x)| {(x, y)});
//! ```
use std::collections::HashMap;

/// A Datalog variable.
///
/// For example, `x` in the following:
/// ```rust
/// ```ignore
/// r_1.from_map(&r, |(x, z)| {(z, x)});
/// ```
struct DVar {
name: syn::Ident,
#[derive(Debug)]
pub(crate) struct DVar {
pub name: syn::Ident,
}

impl DVar {
pub fn new(name: syn::Ident) -> Self {
Self { name: name }
}
}

/// A flat tuple of `DVar`s. Typically used to represent the user defined types.
struct DVarTuple {
vars: Vec<DVar>,
#[derive(Debug)]
pub(crate) struct DVarTuple {
pub vars: Vec<DVar>,
}

/// A (key, value) representation of `DVar`s. It is used for joins.
struct DVarKeyVal {
key: Vec<DVar>,
value: Vec<DVar>,
#[derive(Debug)]
pub(crate) struct DVarKeyVal {
pub key: Vec<DVar>,
pub value: Vec<DVar>,
}

/// An ordered set of `DVar`s.
enum DVars {
#[derive(Debug)]
pub(crate) enum DVars {
Tuple(DVarTuple),
KeyVal(DVarKeyVal),
}

impl DVars {
pub fn new_tuple(args: Vec<syn::Ident>) -> Self {
DVars::Tuple(DVarTuple {
vars: args.into_iter().map(|ident| DVar::new(ident)).collect(),
})
}
}

/// A type that matches some `DVars`.
#[derive(Debug)]
pub(crate) enum DVarTypes {
Tuple(Vec<syn::Type>),
KeyVal {
key: Vec<syn::Type>,
value: Vec<syn::Type>,
},
}

/// A Datafrog relation.
#[derive(Debug)]
pub(crate) struct RelationDecl {
pub var: Variable,
pub typ: Vec<syn::Type>,
}

/// A Datafrog variable.
///
/// For example, `rule` in the following:
/// ```rust
/// ```ignore
/// let rule = iteration.variable::<(u32, u32)>("rule");
/// ```
struct Variable {
name: syn::Ident,
#[derive(Debug)]
pub(crate) struct VariableDecl {
pub var: Variable,
/// The type by shape must match `DVarKeyVal`.
pub typ: DVarTypes,
pub is_output: bool,
}

struct VariableDecl {
var: Variable,
typ: syn::Type,
is_output: bool,
/// A reference to a Datafrog relation or variable.
#[derive(Debug, Clone)]
pub(crate) struct Variable {
pub name: syn::Ident,
}

/// An operation that reorders and potentially drops Datalog variables.
///
/// It is encoded as a Datafrog `from_map`.
struct ReorderOp {
#[derive(Debug)]
pub(crate) struct ReorderOp {
/// A variable into which we write the result.
output: Variable,
pub output: Variable,
/// A variable from which we read the input.
input: Variable,
input_vars: DVars,
output_vars: DVars,
pub input: Variable,
pub input_vars: DVars,
pub output_vars: DVars,
}

/// An operation that evaluates the given expression and adds it as a last output variable.
struct BindVarOp {
#[derive(Debug)]
pub(crate) struct BindVarOp {
/// A variable into which we write the result.
output: Variable,
/// A variable from which we read the input.
Expand All @@ -102,7 +145,8 @@ struct BindVarOp {
}

/// An operation that joins two variables.
struct JoinOp {
#[derive(Debug)]
pub(crate) struct JoinOp {
/// A variable into which we write the result.
output: Variable,
/// The first variable, which we use in join.
Expand All @@ -118,23 +162,53 @@ struct JoinOp {
}

/// An operation that filters out facts.
struct FilterOp {
#[derive(Debug)]
pub(crate) struct FilterOp {
/// A variable which we want to filter.
variable: Variable,
vars: DVars,
/// A boolean expression used for filtering.
expr: syn::Expr,
}

enum Operation {
#[derive(Debug)]
pub(crate) enum Operation {
Reorder(ReorderOp),
BindVar(BindVarOp),
Join(JoinOp),
Filter(FilterOp),
}

/// A Datafrog iteration.
struct Iteration {
variables: Vec<VariableDecl>,
operations: Vec<Operation>,
#[derive(Debug)]
pub(crate) struct Iteration {
pub relations: HashMap<syn::Ident, RelationDecl>,
pub variables: HashMap<syn::Ident, VariableDecl>,
pub operations: Vec<Operation>,
}

impl Iteration {
pub fn new(relations: Vec<RelationDecl>, variables: Vec<VariableDecl>) -> Self {
Self {
relations: relations
.into_iter()
.map(|decl| (decl.var.name.clone(), decl))
.collect(),
variables: variables
.into_iter()
.map(|decl| (decl.var.name.clone(), decl))
.collect(),
operations: Vec::new(),
}
}
pub fn get_variable(&self, variable_name: &syn::Ident) -> Variable {
if let Some(decl) = self.variables.get(variable_name) {
decl.var.clone()
} else {
self.relations[variable_name].var.clone()
}
}
pub fn add_operation(&mut self, operation: Operation) {
self.operations.push(operation);
}
}
126 changes: 126 additions & 0 deletions src/generator_new/encode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use crate::ast;
use crate::generator_new::ast as gen;

fn encode(program: ast::Program) -> gen::Iteration {
let mut relations = Vec::new();
let mut variables = Vec::new();
for decl in program.decls.values() {
let var = gen::Variable {
name: decl.name.clone(),
};
let typ = decl
.parameters
.iter()
.map(|param| param.typ.clone())
.collect();
match decl.kind {
ast::PredicateKind::Input => {
relations.push(gen::RelationDecl { var: var, typ: typ });
}
ast::PredicateKind::Internal => {
variables.push(gen::VariableDecl {
var: var,
typ: gen::DVarTypes::Tuple(typ),
is_output: false,
});
}
ast::PredicateKind::Output => {
variables.push(gen::VariableDecl {
var: var,
typ: gen::DVarTypes::Tuple(typ),
is_output: true,
});
}
}
}
let mut iteration = gen::Iteration::new(relations, variables);
for rule in &program.rules {
let mut iter = rule.body.iter();
let literal1 = iter.next().unwrap();
if literal1.is_negated {
unimplemented!();
}
let variable = iteration.get_variable(&literal1.predicate);
let args = literal1.args.clone();

// Retrieve the main variable for the head.
// Create a new variable `res` for the rule result.
// {
// if rule.body.len() == 1 {
// res.from_map(rule.body[0], ...)
// } else if rule.body.len() == 2 {
// let first = rule.body[0];
// let second = rule.body[1];
// let (key, first_remainder, second_remainder) = common_args(first, second);
// let new_first = variable::<(key, first_remainder)>;
// let new_second = variable::<(key, second_remainder)>;
// new_first.from_map(first);
// new_second.from_map(second);
// res.from_join(new_first, new_second, ...)
// }
// }

//
// Extend the main variable with the new variable.
// rule.head.extend(res);
let head_variable = iteration.get_variable(&rule.head.predicate);
let reorder_op = gen::ReorderOp {
output: head_variable,
input: variable,
input_vars: args.into(),
output_vars: rule.head.args.clone().into(),
};
iteration.add_operation(gen::Operation::Reorder(reorder_op));
}
iteration
}

impl std::convert::From<Vec<ast::Arg>> for gen::DVars {
fn from(args: Vec<ast::Arg>) -> Self {
gen::DVars::new_tuple(args.into_iter().map(|arg| arg.to_ident()).collect())
}
}

impl std::convert::From<Vec<syn::Ident>> for gen::DVars {
fn from(args: Vec<syn::Ident>) -> Self {
gen::DVars::new_tuple(args)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::parser::parse;
use crate::typechecker::typecheck;
use proc_macro2::TokenStream;
use quote::ToTokens;
use std::str::FromStr;

#[test]
fn encode_simple1() {
let program = parse(
"
input inp(x: u32, y: u32)
output out(x: u32, y: u32)
out(x, y) :- inp(y, x).
",
);
let program = typecheck(program).unwrap();
let iteration = encode(program);
let tokens = iteration.to_token_stream().to_string();
eprintln!("{}", tokens);
let expected_tokens = TokenStream::from_str(
r##"
let mut iteration = datafrog::Iteration::new();
let inp = datafrog::Relation::from_vec:: <(u32, u32,)>(inp);
let out = iteration.variable:: <(u32, u32,)>("out");
while iteration.changed() {
out.from_map(&inp, | &(y, x,)| (x, y,));
}
let out = out.complete();
"##,
)
.unwrap();
assert_eq!(tokens.to_string(), expected_tokens.to_string());
}
}
4 changes: 3 additions & 1 deletion src/generator_new/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
mod ast;
mod ast;
mod encode;
mod to_tokens;
Loading

0 comments on commit 1848804

Please sign in to comment.