use std::fmt::{ self, Display, Formatter };
use std::collections::{ HashMap, BTreeMap, BTreeSet };
use std::cmp::*;
use util::*;
pub type RcType = RcCell<Type>;
pub type WkType = WkCell<Type>;
pub type RcExpr = RcCell<Expr>;
pub type WkExpr = WkCell<Expr>;
#[allow(missing_docs)] #[derive(Debug, Clone, Copy)]
pub struct BuiltinName {
pub bool_name: &'static str,
pub int_name: &'static str,
pub float_name: &'static str,
pub decimal_name: &'static str,
pub string_name: &'static str,
pub blob_name: &'static str,
pub date_name: &'static str,
}
pub static BUILTIN_NAME: BuiltinName = BuiltinName {
bool_name: "bool",
int_name: "int",
float_name: "float",
decimal_name: "Decimal",
string_name: "String",
blob_name: "Blob",
date_name: "Date",
};
#[derive(Debug)]
pub enum Type {
Bool,
Int,
Float,
Decimal {
integral: usize,
fractional: usize,
},
String,
Blob,
Date,
Optional(WkType),
Pointer(WkType),
Array(WkType),
Tuple(Vec<WkType>),
Enum(EnumType),
Struct(StructType),
Class(ClassType),
Function(FunctionType),
Placeholder {
name: String,
kind: PlaceholderKind,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PlaceholderKind {
Struct,
Class,
Enum,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ComplexTypeKind {
Value,
Entity,
Function,
}
#[derive(Debug)]
pub struct EnumType {
pub name: String,
pub variants: BTreeMap<String, WkType>,
}
#[derive(Debug)]
pub struct StructType {
pub name: String,
pub fields: BTreeMap<String, WkType>,
}
#[derive(Debug)]
pub struct ClassType {
pub name: String,
pub fields: BTreeMap<String, WkType>,
}
#[derive(Debug, Clone)]
pub struct FunctionType {
pub arg_types: Vec<WkType>,
pub ret_type: WkType,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RelationSide {
pub entity: RcType,
pub field: Option<String>,
pub cardinality: Cardinality,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Cardinality {
ZeroOrOne,
One,
ZeroOrMore,
OneOrMore,
}
#[derive(Debug, Clone)]
pub struct Relation {
pub lhs: RelationSide,
pub rhs: RelationSide,
}
#[derive(Debug)]
pub struct Expr {
pub ty: RcType, pub value: Value,
pub id: ExprId,
}
#[derive(Debug)]
pub enum Value {
Placeholder,
Nil,
Bool(bool),
Int(u64),
Float(f64),
String(String),
Function(Function),
Call(Call),
Argument {
func: WkExpr,
index: usize,
},
Load(WkExpr),
OptionalWrap(RcExpr),
Ignore(RcExpr),
Neg(RcExpr),
Add(RcExpr, RcExpr),
Sub(RcExpr, RcExpr),
Mul(RcExpr, RcExpr),
Div(RcExpr, RcExpr),
Mod(RcExpr, RcExpr),
Eq(RcExpr, RcExpr),
Neq(RcExpr, RcExpr),
Lt(RcExpr, RcExpr),
LtEq(RcExpr, RcExpr),
Gt(RcExpr, RcExpr),
GtEq(RcExpr, RcExpr),
And(RcExpr, RcExpr),
Or(RcExpr, RcExpr),
Not(RcExpr),
Intersect(RcExpr, RcExpr),
Union(RcExpr, RcExpr),
SetDiff(RcExpr, RcExpr),
Branch(Branch),
Seq(Vec<RcExpr>),
Array(Vec<RcExpr>),
Tuple(Vec<RcExpr>),
Struct(BTreeMap<String, RcExpr>),
Map(Map),
Reduce(Reduce),
Filter(Filter),
Sort(Sort),
Group(Group),
Join,
Insert,
Update,
Project(AttrRef),
GroupBy(AttrRef),
SortBy {
entity: RcType,
fields: Vec<(String, SortDirection)>
},
Sum(AttrRef),
Avg(AttrRef),
Min(AttrRef),
Max(AttrRef),
}
#[derive(Debug)]
pub struct AttrRef {
pub entity: RcType,
pub fields: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SortDirection {
Ascending,
Descending,
}
impl Default for SortDirection {
fn default() -> Self {
SortDirection::Ascending
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ExprId {
Temp(usize),
Local(String),
Global(String),
}
#[derive(Debug, Clone)]
pub struct Function {
pub args: Vec<RcExpr>,
pub body: RcExpr,
}
#[derive(Debug)]
pub struct Call {
pub callee: RcExpr,
pub args: Vec<RcExpr>,
}
#[derive(Debug)]
pub struct Branch {
pub discriminant: RcExpr,
pub arms: Vec<BranchArm>,
}
#[derive(Debug)]
pub struct BranchArm {
pub pattern: RcExpr,
pub value: RcExpr,
}
#[derive(Debug)]
pub struct Map {
pub domain: RcExpr,
pub op: RcExpr,
}
#[derive(Debug)]
pub struct Reduce {
pub domain: RcExpr,
pub zero: RcExpr,
pub op: RcExpr,
}
#[derive(Debug)]
pub struct Filter {
pub domain: RcExpr,
pub pred: RcExpr,
}
#[derive(Debug)]
pub struct Sort {
pub domain: RcExpr,
pub cmp: RcExpr,
}
#[derive(Debug)]
pub struct Group {
pub domain: RcExpr,
pub key: RcExpr,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Sqir {
pub named_types: BTreeMap<String, RcType>,
pub decimal_types: HashMap<(usize, usize), RcType>,
pub optional_types: HashMap<RcType, RcType>,
pub pointer_types: HashMap<RcType, RcType>,
pub array_types: HashMap<RcType, RcType>,
pub tuple_types: HashMap<Vec<RcType>, RcType>,
pub function_types: HashMap<(Vec<RcType>, RcType), RcType>,
pub relations: HashMap<(RcType, String), Relation>,
pub globals: BTreeMap<Option<String>, BTreeMap<String, RcExpr>>,
}
fn write_many_types(f: &mut Formatter, types: &[WkType]) -> fmt::Result {
f.write_str("(")?;
for (index, ty) in types.iter().enumerate() {
let sep = if index > 0 { ", " } else { "" };
write!(f, "{}{}", sep, ty)?
}
f.write_str(")")
}
fn write_decimal_type(f: &mut Formatter, integral: usize, fractional: usize) -> fmt::Result {
write!(
f,
"{}<{}.{}>",
BUILTIN_NAME.decimal_name,
integral,
fractional
)
}
impl Display for Type {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Type::Bool => f.write_str(BUILTIN_NAME.bool_name),
Type::Int => f.write_str(BUILTIN_NAME.int_name),
Type::Float => f.write_str(BUILTIN_NAME.float_name),
Type::String => f.write_str(BUILTIN_NAME.string_name),
Type::Blob => f.write_str(BUILTIN_NAME.blob_name),
Type::Date => f.write_str(BUILTIN_NAME.date_name),
Type::Decimal { integral, fractional } => {
write_decimal_type(f, integral, fractional)
},
Type::Optional(ref wrapped) => {
write!(f, "({})?", wrapped)
},
Type::Pointer(ref pointed) => {
write!(f, "&({})", pointed)
},
Type::Array(ref element) => {
write!(f, "[{}]", element)
},
Type::Function(ref ty) => {
write_many_types(f, &ty.arg_types)?;
write!(f, " -> {}", ty.ret_type)
},
Type::Placeholder { ref name, kind } => {
write!(f, "Placeholder({}, kind: {})", name, kind)
},
Type::Tuple(ref types) => write_many_types(f, types),
Type::Enum(ref e) => f.write_str(&e.name),
Type::Struct(ref s) => f.write_str(&s.name),
Type::Class(ref c) => f.write_str(&c.name),
}
}
}
impl Display for PlaceholderKind {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let s = match *self {
PlaceholderKind::Struct => "struct",
PlaceholderKind::Class => "class",
PlaceholderKind::Enum => "enum",
};
f.write_str(s)
}
}
impl Display for Cardinality {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let s = match *self {
Cardinality::ZeroOrOne => "zero or one",
Cardinality::One => "one",
Cardinality::ZeroOrMore => "zero or more",
Cardinality::OneOrMore => "one or more",
};
f.write_str(s)
}
}
impl PartialOrd for RelationSide {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.cmp(other).into()
}
}
impl Ord for RelationSide {
fn cmp(&self, other: &Self) -> Ordering {
let self_ref = self.entity.borrow().expect("self entity");
let other_ref = other.entity.borrow().expect("other entity");
let self_name = match *self_ref {
Type::Class(ref c) => &c.name,
_ => unreachable!("Non-Class class type?!"),
};
let other_name = match *other_ref {
Type::Class(ref c) => &c.name,
_ => unreachable!("Non-Class class type?!"),
};
let lhs = (self_name, &self.field, self.cardinality);
let rhs = (other_name, &other.field, other.cardinality);
lhs.cmp(&rhs)
}
}
impl PartialEq for Relation {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for Relation {}
impl PartialOrd for Relation {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.cmp(other).into()
}
}
impl Ord for Relation {
fn cmp(&self, other: &Self) -> Ordering {
let self_min = min(&self.lhs, &self.rhs);
let self_max = max(&self.lhs, &self.rhs);
let other_min = min(&other.lhs, &other.rhs);
let other_max = max(&other.lhs, &other.rhs);
Ord::cmp(&(self_min, self_max), &(other_min, other_max))
}
}
impl Sqir {
pub fn new() -> Self {
let named_types = btree_map!{
BUILTIN_NAME.bool_name => Type::Bool,
BUILTIN_NAME.int_name => Type::Int,
BUILTIN_NAME.float_name => Type::Float,
BUILTIN_NAME.string_name => Type::String,
BUILTIN_NAME.blob_name => Type::Blob,
BUILTIN_NAME.date_name => Type::Date,
};
Sqir {
named_types: named_types,
decimal_types: HashMap::new(),
optional_types: HashMap::new(),
pointer_types: HashMap::new(),
array_types: HashMap::new(),
tuple_types: HashMap::new(),
function_types: HashMap::new(),
relations: HashMap::new(),
globals: BTreeMap::new(), }
}
pub fn unique_relations(&self) -> BTreeSet<&Relation> {
self.relations.values().collect()
}
}
impl Default for Sqir {
fn default() -> Self {
Sqir::new()
}
}