printer for programs

main
Ziyang Hu 2 years ago
parent 8f347e5099
commit 2f193d105b

@ -1,6 +1,6 @@
use std::cmp::{max, min};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter};
use std::fmt::{Debug, Display, Formatter};
use std::mem;
use itertools::Itertools;
@ -16,7 +16,7 @@ use crate::data::tuple::Tuple;
use crate::data::value::{DataValue, LARGEST_UTF_CHAR};
use crate::parse::SourceSpan;
#[derive(Debug, Clone, PartialEq, Eq, serde_derive::Serialize, serde_derive::Deserialize)]
#[derive(Clone, PartialEq, Eq, serde_derive::Serialize, serde_derive::Deserialize)]
pub(crate) enum Expr {
Binding {
var: Symbol,
@ -45,6 +45,48 @@ pub(crate) enum Expr {
},
}
impl Debug for Expr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl Display for Expr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Binding { var, .. } => {
write!(f, "{}", var.name)
}
Expr::Const { val, .. } => {
write!(f, "{}", val)
}
Expr::Apply { op, args, .. } => {
let mut writer =
f.debug_tuple(op.name.strip_prefix("OP_").unwrap().to_lowercase().as_str());
for arg in args.iter() {
writer.field(arg);
}
writer.finish()
}
Expr::Cond { clauses, .. } => {
let mut writer = f.debug_tuple("cond");
for (cond, expr) in clauses {
writer.field(cond);
writer.field(expr);
}
writer.finish()
}
Expr::Try { clauses, .. } => {
let mut writer = f.debug_tuple("try");
for clause in clauses {
writer.field(clause);
}
writer.finish()
}
}
}
}
#[derive(Debug, Error, Diagnostic)]
#[error("Found value {1:?} where a boolean value is expected")]
#[diagnostic(code(eval::predicate_not_bool))]

@ -1,6 +1,6 @@
use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter};
use std::fmt::{Debug, Display, Formatter};
use either::{Left, Right};
use miette::{ensure, Diagnostic, Result};
@ -11,12 +11,13 @@ use thiserror::Error;
use crate::algo::AlgoHandle;
use crate::data::aggr::Aggregation;
use crate::data::expr::Expr;
use crate::data::relation::StoredRelationMetadata;
use crate::data::symb::{Symbol, PROG_ENTRY};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::stored::StoredRelation;
use crate::runtime::relation::InputRelationHandle;
use crate::runtime::stored::StoredRelation;
use crate::runtime::transact::SessionTx;
pub(crate) type ConstRules = BTreeMap<MagicSymbol, ConstRule>;
@ -34,7 +35,7 @@ pub(crate) enum QueryAssertion {
AssertSome(SourceSpan),
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Clone, Eq, PartialEq)]
pub(crate) struct QueryOutOptions {
pub(crate) limit: Option<usize>,
pub(crate) offset: Option<usize>,
@ -44,6 +45,103 @@ pub(crate) struct QueryOutOptions {
pub(crate) assertion: Option<QueryAssertion>,
}
impl Debug for QueryOutOptions {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl Display for QueryOutOptions {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if let Some(l) = self.limit {
write!(f, ":limit {};\n", l)?;
}
if let Some(l) = self.offset {
write!(f, ":offset {};\n", l)?;
}
if let Some(l) = self.timeout {
write!(f, ":timeout {};\n", l)?;
}
for (symb, dir) in &self.sorters {
write!(f, ":order ")?;
if *dir == SortDir::Dsc {
write!(f, "-")?;
}
write!(f, "{};\n", symb)?;
}
if let Some((
InputRelationHandle {
name,
metadata: StoredRelationMetadata { keys, non_keys },
key_bindings,
dep_bindings,
..
},
op,
)) = &self.store_relation
{
match op {
RelationOp::Create => {
write!(f, ":create ")?;
}
RelationOp::Replace => {
write!(f, ":replace ")?;
}
RelationOp::Put => {
write!(f, ":put ")?;
}
RelationOp::Rm => {
write!(f, ":rm ")?;
}
}
write!(f, "{} {{", name)?;
let mut is_first = true;
for (col, bind) in keys.iter().zip(key_bindings) {
if is_first {
is_first = false
} else {
write!(f, ", ")?;
}
write!(f, "{}: {}", col.name, col.typing)?;
if let Some(gen) = &col.default_gen {
write!(f, " default {}", gen)?;
} else {
write!(f, " = {}", bind)?;
}
}
write!(f, " => ")?;
let mut is_first = true;
for (col, bind) in non_keys.iter().zip(dep_bindings) {
if is_first {
is_first = false
} else {
write!(f, ", ")?;
}
write!(f, "{}: {}", col.name, col.typing)?;
if let Some(gen) = &col.default_gen {
write!(f, " default {}", gen)?;
} else {
write!(f, " = {}", bind)?;
}
}
write!(f, "}};\n")?;
}
if let Some(a) = &self.assertion {
match a {
QueryAssertion::AssertNone(_) => {
write!(f, ":assert none;\n")?;
}
QueryAssertion::AssertSome(_) => {
write!(f, ":assert some;\n")?;
}
}
}
Ok(())
}
}
impl Default for QueryOutOptions {
fn default() -> Self {
Self {
@ -407,7 +505,7 @@ impl Debug for MagicAlgoApply {
}
}
#[derive(Debug, Clone)]
#[derive(Clone)]
pub(crate) enum AlgoRuleArg {
InMem {
name: Symbol,
@ -423,6 +521,36 @@ pub(crate) enum AlgoRuleArg {
name: Symbol,
bindings: BTreeMap<SmartString<LazyCompact>, Symbol>,
span: SourceSpan,
},
}
impl Debug for AlgoRuleArg {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl Display for AlgoRuleArg {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AlgoRuleArg::InMem { name, bindings, .. } => {
write!(f, "{}", name)?;
f.debug_list().entries(bindings).finish()?;
}
AlgoRuleArg::Stored { name, bindings, .. } => {
write!(f, ":{}", name)?;
f.debug_list().entries(bindings).finish()?;
}
AlgoRuleArg::NamedStored { name, bindings, .. } => {
write!(f, ":")?;
let mut sf = f.debug_struct(name);
for (k, v) in bindings {
sf.field(k, v);
}
sf.finish()?;
}
}
Ok(())
}
}
@ -472,6 +600,88 @@ pub(crate) struct InputProgram {
pub(crate) out_opts: QueryOutOptions,
}
impl Display for InputProgram {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for (name, rule) in &self.const_rules {
write!(f, "{}", name.symbol())?;
f.debug_list().entries(&rule.bindings).finish()?;
write!(f, " <- ")?;
f.debug_list().entries(&rule.data).finish()?;
write!(f, ";\n")?;
}
for (name, rules) in &self.prog {
match rules {
InputRulesOrAlgo::Rules { rules, .. } => {
for InputRule {
head, aggr, body, ..
} in rules
{
write!(f, "{}[", name)?;
for (i, (h, a)) in head.iter().zip(aggr).enumerate() {
if i > 0 {
write!(f, ", ")?;
}
if let Some((aggr, aggr_args)) = a {
write!(f, "{}({}", aggr.name, h)?;
for aga in aggr_args {
write!(f, ", {}", aga)?;
}
write!(f, ")")?;
} else {
write!(f, "{}", h)?;
}
}
write!(f, "] := ")?;
for (i, atom) in body.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", atom)?;
}
write!(f, ";\n")?;
}
}
InputRulesOrAlgo::Algo {
algo:
AlgoApply {
algo,
rule_args,
options,
head,
..
},
} => {
write!(f, "{}", name)?;
f.debug_list().entries(head).finish()?;
write!(f, " <~ ")?;
write!(f, "{}(", algo.name)?;
let mut first = true;
for rule_arg in rule_args {
if first {
first = false;
} else {
write!(f, ", ")?;
}
write!(f, "{}", rule_arg)?;
}
for (k, v) in options {
if first {
first = false;
} else {
write!(f, ", ")?;
}
write!(f, "{}: {}", k, v)?;
}
write!(f, ");\n")?;
}
}
}
write!(f, "{}", self.out_opts)?;
Ok(())
}
}
#[derive(Debug, Diagnostic, Error)]
#[error("Entry head not found")]
#[diagnostic(code(parser::no_entry_head))]
@ -842,7 +1052,7 @@ impl MagicRule {
}
}
#[derive(Debug, Clone)]
#[derive(Clone)]
pub(crate) enum InputAtom {
Rule {
inner: InputRuleApplyAtom,
@ -873,6 +1083,81 @@ pub(crate) enum InputAtom {
},
}
impl Debug for InputAtom {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl Display for InputAtom {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
InputAtom::Rule {
inner: InputRuleApplyAtom { name, args, .. },
} => {
write!(f, "{}", name)?;
f.debug_list().entries(args).finish()?;
}
InputAtom::NamedFieldRelation {
inner: InputNamedFieldRelationApplyAtom { name, args, .. },
} => {
f.write_str(":")?;
let mut sf = f.debug_struct(name);
for (k, v) in args {
sf.field(k, v);
}
sf.finish()?;
}
InputAtom::Relation {
inner: InputRelationApplyAtom { name, args, .. },
} => {
write!(f, ":{}", name)?;
f.debug_list().entries(args).finish()?;
}
InputAtom::Predicate { inner } => {
write!(f, "{}", inner)?;
}
InputAtom::Negation { inner, .. } => {
write!(f, "not {}", inner)?;
}
InputAtom::Conjunction { inner, .. } => {
for (i, a) in inner.iter().enumerate() {
if i > 0 {
write!(f, " and ")?;
}
write!(f, "({})", a)?;
}
}
InputAtom::Disjunction { inner, .. } => {
for (i, a) in inner.iter().enumerate() {
if i > 0 {
write!(f, " or ")?;
}
write!(f, "({})", a)?;
}
}
InputAtom::Unification {
inner:
Unification {
binding,
expr,
one_many_unif,
..
},
} => {
write!(f, "{}", binding)?;
if *one_many_unif {
write!(f, " in ")?;
} else {
write!(f, " = ")?;
}
write!(f, "{}", expr)?;
}
}
Ok(())
}
}
impl InputAtom {
pub(crate) fn span(&self) -> SourceSpan {
match self {

@ -5,7 +5,6 @@ use miette::Result;
use rmp_serde::Serializer;
use serde::Serialize;
use crate::data::json::JsonValue;
use crate::data::value::DataValue;
use crate::runtime::relation::RelationId;
@ -16,15 +15,7 @@ pub(crate) struct Tuple(pub(crate) Vec<DataValue>);
impl Debug for Tuple {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
for (i, v) in self.0.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
let j = JsonValue::from(v.clone());
write!(f, "{}", j)?;
}
write!(f, "]")
f.debug_list().entries(&self.0).finish()
}
}

@ -168,7 +168,20 @@ impl Display for Num {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Num::I(i) => write!(f, "{}", i),
Num::F(n) => write!(f, "{}", n),
Num::F(n) => {
if n.is_nan() {
write!(f, r#"to_float("NAN")"#)
} else if n.is_infinite() {
if n.is_sign_negative() {
write!(f, r#"to_float("NEG_INF")"#)
} else {
write!(f, r#"to_float("INF")"#)
}
}
else {
write!(f, "{}", n)
}
},
}
}
}
@ -214,41 +227,38 @@ impl Ord for Num {
}
impl Debug for DataValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl Display for DataValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
DataValue::Null => {
write!(f, "null")
}
DataValue::Bool(b) => {
write!(f, "{}", b)
}
DataValue::Num(i) => {
write!(f, "{}", i)
}
DataValue::Str(s) => {
write!(f, "{:?}", s)
}
DataValue::Regex(r) => {
write!(f, "{:?}", r.0.as_str())
}
DataValue::Null => f.write_str("null"),
DataValue::Bool(b) => write!(f, "{}", b),
DataValue::Num(n) => write!(f, "{}", n),
DataValue::Str(s) => write!(f, "{:?}", s),
DataValue::Bytes(b) => {
write!(f, "bytes(len={})", b.len())
let bs = base64::encode(b);
write!(f, "decode_base64({:?})", bs)
}
DataValue::List(t) => f.debug_list().entries(t.iter()).finish(),
DataValue::Set(t) => f.debug_list().entries(t.iter()).finish(),
DataValue::Rev(v) => {
write!(f, "desc<{:?}>", v)
DataValue::Uuid(u) => {
let us = u.0.to_string();
write!(f, "to_uuid({:?})", us)
}
DataValue::Bot => {
write!(f, "bottom")
DataValue::Regex(rx) => {
write!(f, "regex({:?})", rx.0.as_str())
}
DataValue::Guard => {
write!(f, "guard")
DataValue::List(ls) => f.debug_list().entries(ls).finish(),
DataValue::Set(s) => f.debug_list().entries(s).finish(),
DataValue::Rev(rev) => {
write!(f, "{}", rev.0)
}
DataValue::Uuid(u) => {
let encoded = base64::encode_config(u.0.as_bytes(), base64::URL_SAFE_NO_PAD);
write!(f, "{}", encoded)
DataValue::Guard => {
write!(f, "null")
}
DataValue::Bot => write!(f, "null"),
}
}
}
@ -311,6 +321,8 @@ mod tests {
use std::collections::{BTreeMap, HashMap};
use std::mem::size_of;
use smartstring::SmartString;
use crate::data::symb::Symbol;
use crate::data::value::DataValue;
@ -338,4 +350,23 @@ mod tests {
);
dbg!(s);
}
#[test]
fn display_datavalues() {
println!("{}", DataValue::Null);
println!("{}", DataValue::Bool(true));
println!("{}", DataValue::from(-1));
println!("{}", DataValue::from(-1121212121.331212121));
println!("{}", DataValue::from(f64::NAN));
println!("{}", DataValue::from(f64::NEG_INFINITY));
println!(
"{}",
DataValue::List(vec![
DataValue::Bool(false),
DataValue::Str(SmartString::from(r###"abc"你"好'啊👌"###)),
DataValue::from(f64::NEG_INFINITY)
])
);
}
}

@ -295,6 +295,7 @@ impl Db {
tx: &mut SessionTx,
input_program: InputProgram,
) -> Result<(JsonValue, Vec<(Vec<u8>, Vec<u8>)>)> {
debug!("{}", input_program);
let mut clean_ups = vec![];
if let Some((meta, op)) = &input_program.out_opts.store_relation {
if *op == RelationOp::Create {

Loading…
Cancel
Save