use crate::rules::*;
use crate::sources::*;
use crate::terms::*;
use crate::traces::*;
pub use display::*;
pub use to_polar::*;
impl Trace {
pub fn draw(&self, vm: &crate::vm::PolarVirtualMachine) -> String {
let mut res = String::new();
self.draw_trace(vm, 0, &mut res);
res
}
fn draw_trace(&self, vm: &crate::vm::PolarVirtualMachine, nest: usize, res: &mut String) {
if matches!(&self.node, Node::Term(term)
if matches!(term.value(), Value::Expression(Operation { operator: Operator::And, ..})))
{
for c in &self.children {
c.draw_trace(vm, nest + 1, res);
}
} else {
let polar_str = match self.node {
Node::Rule(ref r) => vm.rule_source(r),
Node::Term(ref t) => vm.term_source(t, false),
};
let indented = polar_str
.split('\n')
.map(|s| " ".repeat(nest) + s)
.collect::<Vec<String>>()
.join("\n");
res.push_str(&indented);
res.push_str(" [");
if !self.children.is_empty() {
res.push('\n');
for c in &self.children {
c.draw_trace(vm, nest + 1, res);
}
for _ in 0..nest {
res.push_str(" ");
}
}
res.push_str("]\n");
}
}
}
pub fn source_lines(source: &Source, offset: usize, num_lines: usize) -> String {
let max_lines = num_lines * 2 + 2;
let push_line = |lines: &mut Vec<String>, line: String| {
if lines.len() == max_lines {
lines.remove(0);
}
lines.push(line);
};
let mut index = 0;
let mut lines = Vec::new();
let mut target = None;
let prefix_len = "123: ".len();
for (lineno, line) in source.src.lines().enumerate() {
push_line(&mut lines, format!("{:03}: {}", lineno + 1, line));
let end = index + line.len() + 1;
if target.is_none() && end >= offset {
target = Some(lineno);
let spaces = " ".repeat(offset - index + prefix_len);
push_line(&mut lines, format!("{}^", spaces));
}
index = end;
if target.is_some() && lineno == target.unwrap() + num_lines {
break;
}
}
lines.join("\n")
}
pub fn format_args(op: Operator, args: &[Term], sep: &str) -> String {
args.iter()
.map(|t| to_polar_parens(op, t))
.collect::<Vec<String>>()
.join(sep)
}
pub fn format_params(args: &[Parameter], sep: &str) -> String {
args.iter()
.map(|parameter| parameter.to_polar())
.collect::<Vec<String>>()
.join(sep)
}
#[allow(clippy::ptr_arg)]
pub fn format_rules(rules: &Rules, sep: &str) -> String {
rules
.iter()
.map(|rule| rule.to_polar())
.collect::<Vec<String>>()
.join(sep)
}
fn has_lower_pred(op: Operator, t: &Term) -> bool {
match t.value() {
Value::Expression(Operation {
operator: other, ..
}) => op.precedence() > other.precedence(),
_ => false,
}
}
pub fn to_polar_parens(op: Operator, t: &Term) -> String {
if has_lower_pred(op, t) {
format!("({})", t.to_polar())
} else {
t.to_polar()
}
}
pub mod display {
use crate::formatting::{format_args, format_params};
use std::fmt;
use std::sync::Arc;
use super::ToPolarString;
use crate::numerics::Numeric;
use crate::rules::Rule;
use crate::terms::{Operation, Operator, Symbol, Term, Value};
use crate::vm::*;
impl fmt::Display for Binding {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "{} = {}", self.0.to_polar(), self.1.to_polar())
}
}
impl fmt::Display for Symbol {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "{}", self.0)
}
}
impl fmt::Display for Term {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "{}", self.to_polar())
}
}
impl fmt::Display for Choice {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
fmt,
"[{}] ++ [{}]",
self.goals
.iter()
.map(|g| g.to_string())
.collect::<Vec<String>>()
.join(", "),
self.alternatives
.iter()
.map(|alt| format!(
"[{}]",
alt.iter()
.map(|g| g.to_string())
.collect::<Vec<String>>()
.join(",")
))
.collect::<Vec<String>>()
.join(", ")
)
}
}
impl fmt::Display for Goal {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt_rules(rules: &[Arc<Rule>]) -> String {
rules
.iter()
.map(|rule| rule.to_polar())
.collect::<Vec<String>>()
.join(" ")
}
match self {
Goal::Isa { left, right } => {
write!(fmt, "Isa({}, {})", left.to_polar(), right.to_polar())
}
Goal::IsMoreSpecific { left, right, args } => write!(
fmt,
"IsMoreSpecific({} {} ({}))",
left.to_polar(),
right.to_polar(),
args.iter()
.map(|a| a.to_polar())
.collect::<Vec<String>>()
.join(", ")
),
Goal::IsSubspecializer {
left, right, arg, ..
} => write!(
fmt,
"IsSubspecializer({}, {}, {})",
left.to_polar(),
right.to_polar(),
arg.to_polar()
),
Goal::Lookup { dict, field, value } => write!(
fmt,
"Lookup({}.{} = {})",
dict.to_polar(),
field.to_polar(),
value.to_polar()
),
Goal::LookupExternal {
instance, field, ..
} => write!(
fmt,
"LookupExternal({}.{})",
instance.to_polar(),
field.to_polar(),
),
Goal::PopQuery { term } => write!(fmt, "PopQuery({})", term.to_polar()),
Goal::Query { term } => write!(fmt, "Query({})", term.to_polar()),
Goal::FilterRules {
applicable_rules,
unfiltered_rules,
..
} => write!(
fmt,
"FilterRules([{}], [{}])",
fmt_rules(applicable_rules),
fmt_rules(unfiltered_rules),
),
Goal::SortRules {
rules,
outer,
inner,
..
} => write!(
fmt,
"SortRules([{}], outer={}, inner={})",
fmt_rules(rules),
outer,
inner,
),
Goal::TraceRule { trace: _ } => write!(
fmt,
"TraceRule(...)"
),
Goal::Unify { left, right } => {
write!(fmt, "Unify({}, {})", left.to_polar(), right.to_polar())
}
g => write!(fmt, "{:?}", g),
}
}
}
impl fmt::Display for Rule {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match &self.body.value() {
Value::Expression(Operation {
operator: Operator::And,
args,
}) => {
if args.is_empty() {
write!(
fmt,
"{}({});",
self.name.to_polar(),
format_params(&self.params, ", ")
)
} else {
write!(
fmt,
"{}({}) if {};",
self.name.to_polar(),
format_params(&self.params, ", "),
format_args(Operator::And, &args, ",\n "),
)
}
}
_ => panic!("Not any sorta rule I parsed"),
}
}
}
impl fmt::Display for Numeric {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Integer(i) => write!(f, "{}", i),
Self::Float(float) => write!(f, "{}", float),
}
}
}
}
pub mod to_polar {
use crate::formatting::{format_args, format_params, to_polar_parens};
use crate::rules::*;
use crate::terms::*;
pub trait ToPolarString {
fn to_polar(&self) -> String;
}
impl ToPolarString for Dictionary {
fn to_polar(&self) -> String {
let fields = self
.fields
.iter()
.map(|(k, v)| format!("{}: {}", k.to_polar(), v.to_polar()))
.collect::<Vec<String>>()
.join(", ");
format!("{{{}}}", fields)
}
}
impl ToPolarString for ExternalInstance {
fn to_polar(&self) -> String {
if let Some(ref repr) = self.repr {
repr.clone()
} else {
format!("^{{id: {}}}", self.instance_id)
}
}
}
impl ToPolarString for InstanceLiteral {
fn to_polar(&self) -> String {
format!("{}{}", self.tag.to_polar(), self.fields.to_polar())
}
}
impl ToPolarString for Operator {
fn to_polar(&self) -> String {
use Operator::*;
match self {
Not => "not",
Mul => "*",
Div => "/",
Add => "+",
Sub => "-",
Eq => "==",
Geq => ">=",
Leq => "<=",
Neq => "!=",
Gt => ">",
Lt => "<",
Or => "or",
And => "and",
New => "new",
Dot => ".",
Unify => "=",
Assign => ":=",
In => "in",
Cut => "cut",
ForAll => "forall",
Debug => "debug",
Print => "print",
Isa => "matches",
}
.to_string()
}
}
impl ToPolarString for Operation {
fn to_polar(&self) -> String {
use Operator::*;
match self.operator {
Debug => "debug()".to_owned(),
Print => format!("print({})", format_args(self.operator, &self.args, ", ")),
Cut => "cut".to_owned(),
ForAll => format!(
"forall({}, {})",
self.args[0].to_polar(),
self.args[1].to_polar()
),
New => {
if self.args.len() == 1 {
format!("new {}", to_polar_parens(self.operator, &self.args[0]))
} else {
format!(
"new ({}, {})",
to_polar_parens(self.operator, &self.args[0]),
self.args[1].to_polar()
)
}
}
Dot => {
if self.args.len() == 2 {
let call_term = if let Value::String(s) = self.args[1].value() {
s.to_string()
} else {
self.args[1].to_polar()
};
format!("{}.{}", self.args[0].to_polar(), call_term)
} else {
format!(".({})", format_args(self.operator, &self.args, ", "))
}
}
Not => format!(
"{} {}",
self.operator.to_polar(),
to_polar_parens(self.operator, &self.args[0])
),
Mul | Div | Add | Sub | Eq | Geq | Leq | Neq | Gt | Lt | Unify | Isa | In
| Assign => format!(
"{} {} {}",
to_polar_parens(self.operator, &self.args[0]),
self.operator.to_polar(),
to_polar_parens(self.operator, &self.args[1])
),
And => format_args(
self.operator,
&self.args,
&format!(" {} ", self.operator.to_polar()),
),
Or => format_args(
self.operator,
&self.args,
&format!(" {} ", self.operator.to_polar()),
),
}
}
}
impl ToPolarString for Parameter {
fn to_polar(&self) -> String {
match &self.specializer {
None => self.parameter.to_polar(),
Some(specializer) => {
format!("{}: {}", self.parameter.to_polar(), specializer.to_polar())
}
}
}
}
impl ToPolarString for Call {
fn to_polar(&self) -> String {
let args = format_args(Operator::And, &self.args, ", ");
let combined_args = match &self.kwargs {
Some(dict) => {
let kwargs = dict
.iter()
.map(|(k, v)| format!("{}: {}", k.to_polar(), v.to_polar()))
.collect::<Vec<String>>()
.join(", ");
if args.is_empty() {
kwargs
} else {
vec![args, kwargs].join(", ")
}
}
None => args,
};
format!("{}({})", self.name.to_polar(), combined_args)
}
}
impl ToPolarString for Rule {
fn to_polar(&self) -> String {
match &self.body.value() {
Value::Expression(Operation {
operator: Operator::And,
args,
}) => {
if args.is_empty() {
format!(
"{}({});",
self.name.to_polar(),
format_params(&self.params, ", ")
)
} else {
format!(
"{}({}) if {};",
self.name.to_polar(),
format_params(&self.params, ", "),
format_args(Operator::And, &args, " and "),
)
}
}
_ => panic!("Not any sorta rule I parsed"),
}
}
}
impl ToPolarString for Symbol {
fn to_polar(&self) -> String {
self.0.to_string()
}
}
impl ToPolarString for Term {
fn to_polar(&self) -> String {
self.value().to_polar()
}
}
impl ToPolarString for Pattern {
fn to_polar(&self) -> String {
match self {
Pattern::Dictionary(d) => d.to_polar(),
Pattern::Instance(i) => i.to_polar(),
}
}
}
impl ToPolarString for Value {
fn to_polar(&self) -> String {
match self {
Value::Number(i) => format!("{}", i),
Value::String(s) => format!("\"{}\"", s),
Value::Boolean(b) => {
if *b {
"true".to_string()
} else {
"false".to_string()
}
}
Value::InstanceLiteral(i) => i.to_polar(),
Value::Dictionary(i) => i.to_polar(),
Value::Pattern(i) => i.to_polar(),
Value::ExternalInstance(i) => i.to_polar(),
Value::Call(c) => c.to_polar(),
Value::List(l) => format!("[{}]", format_args(Operator::And, l, ", "),),
Value::Variable(s) => s.to_polar(),
Value::RestVariable(s) => format!("*{}", s.to_polar()),
Value::Expression(e) => e.to_polar(),
}
}
}
}