#![allow(dead_code)]
use std::collections::HashSet;
use std::fmt;
use num::BigInt;
use crate::common::name::*;
use crate::common::score::NodeRef;
use crate::common::source::*;
use crate::op::*;
use crate::scope::Scope;
use crate::score::{
BuiltinOpRef, BuiltinPkgRef, Def, EnumRef, LibRef, ResolvableName, ScopeRef, ScoreBoard,
TypeDeclRef, TypeMarkRef, UnitRef,
};
use crate::ty::*;
lazy_static! {
pub static ref ROOT_SCOPE_REF: ScopeRef = LibRef::alloc().into();
pub static ref STD_LIB_REF: LibRef = LibRef::alloc();
pub static ref STANDARD_PKG_REF: BuiltinPkgRef = BuiltinPkgRef::alloc();
pub static ref TEXTIO_PKG_REF: BuiltinPkgRef = BuiltinPkgRef::alloc();
pub static ref ENV_PKG_REF: BuiltinPkgRef = BuiltinPkgRef::alloc();
pub static ref BOOLEAN_TYPE: BuiltinType = BuiltinType::new_enum("BOOLEAN");
pub static ref BIT_TYPE: BuiltinType = BuiltinType::new_enum("BIT");
pub static ref SEVERITY_LEVEL_TYPE: BuiltinType = BuiltinType::new_enum("SEVERITY_LEVEL");
pub static ref INTEGER_TYPE: BuiltinType = BuiltinType::new("INTEGER", IntTy::new(
Dir::To,
i32::min_value().into(),
i32::max_value().into()
));
pub static ref TIME_TYPE: BuiltinType = {
let id = TypeDeclRef::alloc();
BuiltinType::with_id(id, "TIME", make_time_type(
id,
IntTy::new(
Dir::To,
i64::min_value().into(),
i64::max_value().into(),
)
))
};
pub static ref DELAY_LENGTH_TYPE: BuiltinType = {
let id = TypeDeclRef::alloc();
BuiltinType::with_id(id, "DELAY_LENGTH", make_time_type(
id,
IntTy::new(
Dir::To,
0.into(),
i64::max_value().into(),
)
))
};
pub static ref NATURAL_TYPE: BuiltinType = BuiltinType::new("NATURAL", IntTy::new(
Dir::To,
0.into(),
i32::max_value().into()
));
pub static ref POSITIVE_TYPE: BuiltinType = BuiltinType::new("POSITIVE", IntTy::new(
Dir::To,
1.into(),
i32::max_value().into()
));
pub static ref BOOLEAN_VECTOR_TYPE: BuiltinType = BuiltinType::new("BOOLEAN_VECTOR", ArrayTy::new(
vec![ArrayIndex::Unbounded(Box::new(NATURAL_TYPE.named_ty()))],
Box::new(BOOLEAN_TYPE.named_ty())
));
pub static ref BIT_VECTOR_TYPE: BuiltinType = BuiltinType::new("BIT_VECTOR", ArrayTy::new(
vec![ArrayIndex::Unbounded(Box::new(NATURAL_TYPE.named_ty()))],
Box::new(BIT_TYPE.named_ty())
));
pub static ref INTEGER_VECTOR_TYPE: BuiltinType = BuiltinType::new("INTEGER_VECTOR", ArrayTy::new(
vec![ArrayIndex::Unbounded(Box::new(NATURAL_TYPE.named_ty()))],
Box::new(INTEGER_TYPE.named_ty())
));
pub static ref TIME_VECTOR_TYPE: BuiltinType = BuiltinType::new("TIME_VECTOR", ArrayTy::new(
vec![ArrayIndex::Unbounded(Box::new(NATURAL_TYPE.named_ty()))],
Box::new(TIME_TYPE.named_ty())
));
pub static ref FILE_OPEN_KIND_TYPE: BuiltinType = BuiltinType::new_enum("FILE_OPEN_KIND");
pub static ref FILE_OPEN_STATUS_TYPE: BuiltinType = BuiltinType::new_enum("FILE_OPEN_STATUS");
static ref BUILTIN_UNARY_OPS: Vec<BuiltinUnaryOp> = vec![
BuiltinUnaryOp::new(UnaryOp::Pos),
BuiltinUnaryOp::new(UnaryOp::Neg),
BuiltinUnaryOp::new(UnaryOp::Abs),
BuiltinUnaryOp::new(UnaryOp::Cond),
BuiltinUnaryOp::new(UnaryOp::Not),
BuiltinUnaryOp::new(UnaryOp::Logical(LogicalOp::And)),
BuiltinUnaryOp::new(UnaryOp::Logical(LogicalOp::Or)),
BuiltinUnaryOp::new(UnaryOp::Logical(LogicalOp::Nand)),
BuiltinUnaryOp::new(UnaryOp::Logical(LogicalOp::Nor)),
BuiltinUnaryOp::new(UnaryOp::Logical(LogicalOp::Xor)),
BuiltinUnaryOp::new(UnaryOp::Logical(LogicalOp::Xnor)),
];
static ref BUILTIN_BINARY_OPS: Vec<BuiltinBinaryOp> = vec![
BuiltinBinaryOp::new(BinaryOp::Logical(LogicalOp::And)),
BuiltinBinaryOp::new(BinaryOp::Logical(LogicalOp::Or)),
BuiltinBinaryOp::new(BinaryOp::Logical(LogicalOp::Nand)),
BuiltinBinaryOp::new(BinaryOp::Logical(LogicalOp::Nor)),
BuiltinBinaryOp::new(BinaryOp::Logical(LogicalOp::Xor)),
BuiltinBinaryOp::new(BinaryOp::Logical(LogicalOp::Xnor)),
BuiltinBinaryOp::new(BinaryOp::Rel(RelationalOp::Eq)),
BuiltinBinaryOp::new(BinaryOp::Rel(RelationalOp::Neq)),
BuiltinBinaryOp::new(BinaryOp::Rel(RelationalOp::Lt)),
BuiltinBinaryOp::new(BinaryOp::Rel(RelationalOp::Leq)),
BuiltinBinaryOp::new(BinaryOp::Rel(RelationalOp::Gt)),
BuiltinBinaryOp::new(BinaryOp::Rel(RelationalOp::Geq)),
BuiltinBinaryOp::new(BinaryOp::Match(RelationalOp::Eq)),
BuiltinBinaryOp::new(BinaryOp::Match(RelationalOp::Neq)),
BuiltinBinaryOp::new(BinaryOp::Match(RelationalOp::Lt)),
BuiltinBinaryOp::new(BinaryOp::Match(RelationalOp::Leq)),
BuiltinBinaryOp::new(BinaryOp::Match(RelationalOp::Gt)),
BuiltinBinaryOp::new(BinaryOp::Match(RelationalOp::Geq)),
BuiltinBinaryOp::new(BinaryOp::Shift(ShiftOp::Sll)),
BuiltinBinaryOp::new(BinaryOp::Shift(ShiftOp::Srl)),
BuiltinBinaryOp::new(BinaryOp::Shift(ShiftOp::Sla)),
BuiltinBinaryOp::new(BinaryOp::Shift(ShiftOp::Sra)),
BuiltinBinaryOp::new(BinaryOp::Shift(ShiftOp::Rol)),
BuiltinBinaryOp::new(BinaryOp::Shift(ShiftOp::Ror)),
BuiltinBinaryOp::new(BinaryOp::Add),
BuiltinBinaryOp::new(BinaryOp::Sub),
BuiltinBinaryOp::new(BinaryOp::Concat),
BuiltinBinaryOp::new(BinaryOp::Mul),
BuiltinBinaryOp::new(BinaryOp::Div),
BuiltinBinaryOp::new(BinaryOp::Mod),
BuiltinBinaryOp::new(BinaryOp::Rem),
BuiltinBinaryOp::new(BinaryOp::Pow),
];
static ref STANDARD_BUILTINS: Vec<(Builtin, Vec<Builtin>)> = {
let mut bi = Vec::new();
bi.push(wrapup_type_builtin(&BOOLEAN_TYPE));
bi.push(wrapup_type_builtin(&BIT_TYPE));
bi.push(wrapup_type_builtin(&SEVERITY_LEVEL_TYPE));
bi.push(wrapup_type_builtin(&INTEGER_TYPE));
bi.push(wrapup_type_builtin(&TIME_TYPE));
bi.push(wrapup_type_builtin(&DELAY_LENGTH_TYPE));
bi.push(wrapup_type_builtin(&NATURAL_TYPE));
bi.push(wrapup_type_builtin(&POSITIVE_TYPE));
bi.push(wrapup_type_builtin(&BOOLEAN_VECTOR_TYPE));
bi.push(wrapup_type_builtin(&BIT_VECTOR_TYPE));
bi.push(wrapup_type_builtin(&INTEGER_VECTOR_TYPE));
bi.push(wrapup_type_builtin(&TIME_VECTOR_TYPE));
bi.push(wrapup_type_builtin(&FILE_OPEN_KIND_TYPE));
bi.push(wrapup_type_builtin(&FILE_OPEN_STATUS_TYPE));
bi
};
}
fn define_builtin(scope: &mut Scope, name: ResolvableName, def: Def) {
scope
.defs
.entry(name)
.or_insert_with(|| Vec::new())
.push(Spanned::new(def, INVALID_SPAN));
}
fn define_builtin_ident(scope: &mut Scope, name: &str, def: Def) {
let name = get_name_table().intern(name, false);
define_builtin(scope, name.into(), def)
}
fn define_builtin_bit(scope: &mut Scope, bit: char, def: Def) {
define_builtin(scope, bit.into(), def)
}
fn named_builtin_type<T: Into<TypeMarkRef>>(name: &str, type_ref: T) -> Ty {
let name = get_name_table().intern(name, false);
Ty::Named(name.into(), type_ref.into())
}
fn named_unit(name: &str, abs: usize, rel: Option<(usize, usize)>) -> PhysicalUnit {
let name = get_name_table().intern(name, false);
let abs = BigInt::from(abs);
let rel = rel.map(|(scale, index)| (BigInt::from(scale), index));
PhysicalUnit::new(name, abs, rel)
}
fn define_builtin_op<O>(scope: &mut Scope, op: O, id: BuiltinOpRef)
where
O: Into<Operator>,
{
scope
.defs
.entry(ResolvableName::Operator(op.into()))
.or_insert_with(|| Vec::new())
.push(Spanned::new(Def::BuiltinOp(id), INVALID_SPAN));
}
fn wrapup_type_builtin(bt: &BuiltinType) -> (Builtin, Vec<Builtin>) {
let bi = Builtin::new(Def::Type(bt.id), bt.name).ty(bt.ty.clone());
let mut aux = Vec::new();
match bt.ty {
Ty::Enum(_) => enum_type_builtins(&bt.named_ty(), &mut aux),
Ty::Int(_) => integer_type_builtins(&bt.named_ty(), &mut aux),
Ty::Physical(_) => physical_type_builtins(&bt.named_ty(), &mut aux),
Ty::Array(ref at) => array_type_builtins(&bt.named_ty(), at, &mut aux),
_ => (),
}
if bt.id == BOOLEAN_TYPE.id || bt.id == BIT_TYPE.id {
let unary_ty = SubprogTy::new(
vec![SubprogTyArg::positional(bt.named_ty())],
Some(bt.named_ty()),
);
let binary_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(bt.named_ty()),
SubprogTyArg::positional(bt.named_ty()),
],
Some(bt.named_ty()),
);
aux.push(Builtin::operator(UnaryOp::Not).ty(unary_ty.clone()));
aux.push(Builtin::operator(BinaryOp::Logical(LogicalOp::And)).ty(binary_ty.clone()));
aux.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Or)).ty(binary_ty.clone()));
aux.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Nand)).ty(binary_ty.clone()));
aux.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Nor)).ty(binary_ty.clone()));
aux.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Xor)).ty(binary_ty.clone()));
aux.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Xnor)).ty(binary_ty.clone()));
}
if bt.id == BIT_TYPE.id {
let op_ty = SubprogTy::new(
vec![SubprogTyArg::positional(bt.named_ty())],
Some(BOOLEAN_TYPE.named_ty()),
);
aux.push(Builtin::operator(UnaryOp::Cond).ty(op_ty.clone()));
}
(bi, aux)
}
lazy_static! {
pub static ref ROOT_SCOPE: Scope = {
let mut scope = Scope::new(None);
define_builtin_ident(&mut scope, "STD", Def::Lib(*STD_LIB_REF));
scope.imported_scopes.insert((*STANDARD_PKG_REF).into());
scope
};
pub static ref STD_LIB_SCOPE: Scope = {
let mut scope = Scope::new(Some(*ROOT_SCOPE_REF));
define_builtin_ident(&mut scope, "STANDARD", Def::BuiltinPkg(*STANDARD_PKG_REF));
define_builtin_ident(&mut scope, "TEXTIO", Def::BuiltinPkg(*TEXTIO_PKG_REF));
define_builtin_ident(&mut scope, "ENV", Def::BuiltinPkg(*ENV_PKG_REF));
scope
};
pub static ref STANDARD_PKG_SCOPE: Scope = {
let mut scope = Scope::new(Some((*STD_LIB_REF).into()));
for &(ref bt, ref aux) in &*STANDARD_BUILTINS {
define_builtin(&mut scope, bt.name, bt.def);
for a in aux {
define_builtin(&mut scope, a.name, a.def);
}
}
define_builtin_ident(&mut scope, "FALSE", Def::Enum(EnumRef(BOOLEAN_TYPE.id, 0)));
define_builtin_ident(&mut scope, "TRUE", Def::Enum(EnumRef(BOOLEAN_TYPE.id, 1)));
define_builtin_bit(&mut scope, '0', Def::Enum(EnumRef(BIT_TYPE.id, 0)));
define_builtin_bit(&mut scope, '1', Def::Enum(EnumRef(BIT_TYPE.id, 1)));
define_builtin_ident(&mut scope, "NOTE", Def::Enum(EnumRef(SEVERITY_LEVEL_TYPE.id, 0)));
define_builtin_ident(&mut scope, "WARNING", Def::Enum(EnumRef(SEVERITY_LEVEL_TYPE.id, 1)));
define_builtin_ident(&mut scope, "ERROR", Def::Enum(EnumRef(SEVERITY_LEVEL_TYPE.id, 2)));
define_builtin_ident(&mut scope, "FAILURE", Def::Enum(EnumRef(SEVERITY_LEVEL_TYPE.id, 3)));
define_builtin_ident(&mut scope, "fs", Def::Unit(UnitRef(TIME_TYPE.id, 0)));
define_builtin_ident(&mut scope, "ps", Def::Unit(UnitRef(TIME_TYPE.id, 1)));
define_builtin_ident(&mut scope, "ns", Def::Unit(UnitRef(TIME_TYPE.id, 2)));
define_builtin_ident(&mut scope, "us", Def::Unit(UnitRef(TIME_TYPE.id, 3)));
define_builtin_ident(&mut scope, "ms", Def::Unit(UnitRef(TIME_TYPE.id, 4)));
define_builtin_ident(&mut scope, "sec", Def::Unit(UnitRef(TIME_TYPE.id, 5)));
define_builtin_ident(&mut scope, "min", Def::Unit(UnitRef(TIME_TYPE.id, 6)));
define_builtin_ident(&mut scope, "hr", Def::Unit(UnitRef(TIME_TYPE.id, 7)));
define_builtin_ident(&mut scope, "READ_MODE", Def::Enum(EnumRef(FILE_OPEN_KIND_TYPE.id, 0)));
define_builtin_ident(&mut scope, "WRITE_MODE", Def::Enum(EnumRef(FILE_OPEN_KIND_TYPE.id, 1)));
define_builtin_ident(&mut scope, "APPEND_MODE", Def::Enum(EnumRef(FILE_OPEN_KIND_TYPE.id, 2)));
define_builtin_ident(&mut scope, "OPEN_OK", Def::Enum(EnumRef(FILE_OPEN_STATUS_TYPE.id, 0)));
define_builtin_ident(&mut scope, "STATUS_ERROR", Def::Enum(EnumRef(FILE_OPEN_STATUS_TYPE.id, 1)));
define_builtin_ident(&mut scope, "NAME_ERROR", Def::Enum(EnumRef(FILE_OPEN_STATUS_TYPE.id, 2)));
define_builtin_ident(&mut scope, "MODE_ERROR", Def::Enum(EnumRef(FILE_OPEN_STATUS_TYPE.id, 3)));
scope
};
pub static ref BUILTIN_SCOPES: Vec<(ScopeRef, &'static Scope)> = vec![
(*ROOT_SCOPE_REF, &*ROOT_SCOPE),
((*STD_LIB_REF).into(), &*STD_LIB_SCOPE),
((*STANDARD_PKG_REF).into(), &*STANDARD_PKG_SCOPE),
];
pub static ref BUILTIN_SCOPE_REFS: HashSet<ScopeRef> = (*BUILTIN_SCOPES)
.iter()
.map(|&(id,_)| id)
.collect();
}
pub fn register_builtins<'ast, 'ctx>(sb: &ScoreBoard<'ast, 'ctx>) {
use std::iter::once;
sb.scope2_table.borrow_mut().extend(
(*BUILTIN_SCOPES)
.iter()
.map(|&(id, scope)| (id, scope.clone())),
);
sb.typeval_table.borrow_mut().extend(
(*STANDARD_BUILTINS)
.iter()
.flat_map(|&(ref bi, ref aux)| once(bi).chain(aux.iter()))
.filter_map(|bi| match bi.ty {
Some(ref ty) => Some((bi.def.into(), Ok(sb.intern_ty(ty.clone())))),
None => None,
}),
);
}
fn make_time_type(decl: TypeDeclRef, base: IntTy) -> PhysicalTy {
PhysicalTy::new(
decl,
base,
vec![
named_unit("fs", 1, None),
named_unit("ps", 1_000, Some((1000, 0))),
named_unit("ns", 1_000_000, Some((1000, 1))),
named_unit("us", 1_000_000_000, Some((1000, 2))),
named_unit("ms", 1_000_000_000_000, Some((1000, 3))),
named_unit("sec", 1_000_000_000_000_000, Some((1000, 4))),
named_unit("min", 60_000_000_000_000_000, Some((60, 5))),
named_unit("hr", 3600_000_000_000_000_000, Some((60, 6))),
],
0,
)
}
struct BuiltinUnaryOp {
id: BuiltinOpRef,
op: UnaryOp,
}
impl BuiltinUnaryOp {
fn new(op: UnaryOp) -> BuiltinUnaryOp {
BuiltinUnaryOp {
id: BuiltinOpRef::alloc(),
op: op,
}
}
}
struct BuiltinBinaryOp {
id: BuiltinOpRef,
op: BinaryOp,
}
impl BuiltinBinaryOp {
fn new(op: BinaryOp) -> BuiltinBinaryOp {
BuiltinBinaryOp {
id: BuiltinOpRef::alloc(),
op: op,
}
}
}
pub struct Builtin {
pub def: Def,
pub name: ResolvableName,
pub ty: Option<Ty>,
}
impl Builtin {
pub fn new<N: Into<ResolvableName>>(def: Def, name: N) -> Builtin {
Builtin {
def: def,
name: name.into(),
ty: None,
}
}
pub fn operator<O: Into<Operator>>(op: O) -> Builtin {
Builtin::new(Def::BuiltinOp(BuiltinOpRef::alloc()), op.into())
}
pub fn ty<T: Into<Ty>>(self, ty: T) -> Builtin {
assert!(self.ty.is_none());
Builtin {
ty: Some(ty.into()),
..self
}
}
}
impl fmt::Debug for Builtin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Builtin(`{}`, {:?}", self.name, self.def)?;
if let Some(ref ty) = self.ty {
write!(f, ", {}", ty)?;
}
write!(f, ")")?;
Ok(())
}
}
fn integer_type_builtins(ty: &Ty, into: &mut Vec<Builtin>) {
numerical_type_builtins(ty, into);
equality_builtins(ty, into);
ordering_builtins(ty, into);
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Mul).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Div).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Mod).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Rem).ty(op_ty.clone()));
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(INTEGER_TYPE.named_ty()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Pow).ty(op_ty.clone()));
}
fn real_type_builtins(ty: &Ty, into: &mut Vec<Builtin>) {
numerical_type_builtins(ty, into);
equality_builtins(ty, into);
ordering_builtins(ty, into);
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Mul).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Div).ty(op_ty.clone()));
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(INTEGER_TYPE.named_ty()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Pow).ty(op_ty.clone()));
}
fn physical_type_builtins(ty: &Ty, into: &mut Vec<Builtin>) {
numerical_type_builtins(ty, into);
equality_builtins(ty, into);
ordering_builtins(ty, into);
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Mod).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Rem).ty(op_ty.clone()));
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(INTEGER_TYPE.named_ty()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Mul).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Div).ty(op_ty.clone()));
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(INTEGER_TYPE.named_ty()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Mul).ty(op_ty.clone()));
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(Ty::UniversalInt),
);
into.push(Builtin::operator(BinaryOp::Div).ty(op_ty.clone()));
}
fn enum_type_builtins(ty: &Ty, into: &mut Vec<Builtin>) {
equality_builtins(ty, into);
ordering_builtins(ty, into);
}
fn array_type_builtins(ty: &Ty, aty: &ArrayTy, into: &mut Vec<Builtin>) {
let eid = match *aty.element {
Ty::Named(_, id) => Some(id),
_ => None,
};
let concat_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
let concat_right_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(aty.element.as_ref().clone()),
],
Some(ty.clone()),
);
let concat_left_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(aty.element.as_ref().clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Concat).ty(concat_ty.clone()));
into.push(Builtin::operator(BinaryOp::Concat).ty(concat_right_ty.clone()));
into.push(Builtin::operator(BinaryOp::Concat).ty(concat_left_ty.clone()));
if aty.indices.len() == 1
&& (eid == Some(BOOLEAN_TYPE.id.into()) || eid == Some(BIT_TYPE.id.into()))
{
let reduce_ty = SubprogTy::new(
vec![SubprogTyArg::positional(ty.clone())],
Some(aty.element.as_ref().clone()),
);
into.push(Builtin::operator(UnaryOp::Logical(LogicalOp::And)).ty(reduce_ty.clone()));
into.push(Builtin::operator(UnaryOp::Logical(LogicalOp::Or)).ty(reduce_ty.clone()));
into.push(Builtin::operator(UnaryOp::Logical(LogicalOp::Nand)).ty(reduce_ty.clone()));
into.push(Builtin::operator(UnaryOp::Logical(LogicalOp::Nor)).ty(reduce_ty.clone()));
into.push(Builtin::operator(UnaryOp::Logical(LogicalOp::Xor)).ty(reduce_ty.clone()));
into.push(Builtin::operator(UnaryOp::Logical(LogicalOp::Xnor)).ty(reduce_ty.clone()));
let scalar_right_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(aty.element.as_ref().clone()),
],
Some(ty.clone()),
);
let scalar_left_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(aty.element.as_ref().clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::And)).ty(scalar_right_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Or)).ty(scalar_right_ty.clone()));
into.push(
Builtin::operator(BinaryOp::Logical(LogicalOp::Nand)).ty(scalar_right_ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Nor)).ty(scalar_right_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Xor)).ty(scalar_right_ty.clone()));
into.push(
Builtin::operator(BinaryOp::Logical(LogicalOp::Xnor)).ty(scalar_right_ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::And)).ty(scalar_left_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Or)).ty(scalar_left_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Nand)).ty(scalar_left_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Nor)).ty(scalar_left_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Xor)).ty(scalar_left_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Xnor)).ty(scalar_left_ty.clone()));
let array_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::And)).ty(array_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Or)).ty(array_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Nand)).ty(array_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Nor)).ty(array_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Xor)).ty(array_ty.clone()));
into.push(Builtin::operator(BinaryOp::Logical(LogicalOp::Xnor)).ty(array_ty.clone()));
let shift_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(INTEGER_TYPE.named_ty()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(BinaryOp::Shift(ShiftOp::Sll)).ty(shift_ty.clone()));
into.push(Builtin::operator(BinaryOp::Shift(ShiftOp::Srl)).ty(shift_ty.clone()));
into.push(Builtin::operator(BinaryOp::Shift(ShiftOp::Sla)).ty(shift_ty.clone()));
into.push(Builtin::operator(BinaryOp::Shift(ShiftOp::Sra)).ty(shift_ty.clone()));
into.push(Builtin::operator(BinaryOp::Shift(ShiftOp::Rol)).ty(shift_ty.clone()));
into.push(Builtin::operator(BinaryOp::Shift(ShiftOp::Ror)).ty(shift_ty.clone()));
}
}
fn equality_builtins(ty: &Ty, into: &mut Vec<Builtin>) {
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(BOOLEAN_TYPE.named_ty()),
);
into.push(Builtin::operator(BinaryOp::Rel(RelationalOp::Eq)).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Rel(RelationalOp::Neq)).ty(op_ty.clone()));
}
fn ordering_builtins(ty: &Ty, into: &mut Vec<Builtin>) {
let op_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(BOOLEAN_TYPE.named_ty()),
);
into.push(Builtin::operator(BinaryOp::Rel(RelationalOp::Lt)).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Rel(RelationalOp::Leq)).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Rel(RelationalOp::Gt)).ty(op_ty.clone()));
into.push(Builtin::operator(BinaryOp::Rel(RelationalOp::Geq)).ty(op_ty.clone()));
}
fn numerical_type_builtins(ty: &Ty, into: &mut Vec<Builtin>) {
let unary_ty = SubprogTy::new(vec![SubprogTyArg::positional(ty.clone())], Some(ty.clone()));
let binary_ty = SubprogTy::new(
vec![
SubprogTyArg::positional(ty.clone()),
SubprogTyArg::positional(ty.clone()),
],
Some(ty.clone()),
);
into.push(Builtin::operator(UnaryOp::Pos).ty(unary_ty.clone()));
into.push(Builtin::operator(UnaryOp::Neg).ty(unary_ty.clone()));
into.push(Builtin::operator(UnaryOp::Abs).ty(unary_ty.clone()));
into.push(Builtin::operator(BinaryOp::Add).ty(binary_ty.clone()));
into.push(Builtin::operator(BinaryOp::Sub).ty(binary_ty.clone()));
}
pub struct BuiltinType {
pub id: TypeDeclRef,
pub name: Name,
pub ty: Ty,
pub aux: Vec<Builtin>,
}
impl BuiltinType {
pub fn new<T: Into<Ty>>(name: &str, ty: T) -> BuiltinType {
BuiltinType {
id: TypeDeclRef::alloc(),
name: get_name_table().intern(name, false),
ty: ty.into(),
aux: Vec::new(),
}
}
pub fn with_id<T: Into<Ty>>(id: TypeDeclRef, name: &str, ty: T) -> BuiltinType {
BuiltinType {
id: id,
name: get_name_table().intern(name, false),
ty: ty.into(),
aux: Vec::new(),
}
}
pub fn new_enum(name: &str) -> BuiltinType {
let id = TypeDeclRef::alloc();
BuiltinType {
id: id,
name: get_name_table().intern(name, false),
ty: EnumTy::new(id).into(),
aux: Vec::new(),
}
}
pub fn named_ty(&self) -> Ty {
Ty::Named(self.name.into(), self.id.into())
}
}
struct EnumBuilder {
id: TypeDeclRef,
name: Name,
vars: Vec<ResolvableName>,
}
impl EnumBuilder {
fn new(name: &str) -> EnumBuilder {
EnumBuilder::with_id(name, TypeDeclRef::alloc())
}
fn with_id(name: &str, id: TypeDeclRef) -> EnumBuilder {
EnumBuilder {
id: id,
name: get_name_table().intern(name, false),
vars: Vec::new(),
}
}
fn ident(mut self, name: &str) -> EnumBuilder {
self.vars.push(get_name_table().intern(name, false).into());
self
}
fn bit(mut self, bit: char) -> EnumBuilder {
self.vars.push(bit.into());
self
}
fn build(self) -> BuiltinType {
let ty = EnumTy::new(self.id).into();
let mut aux = Vec::new();
for (i, var) in self.vars.into_iter().enumerate() {
aux.push(Builtin::new(EnumRef(self.id, i).into(), var));
}
enum_type_builtins(&ty, &mut aux);
BuiltinType {
id: self.id,
name: self.name,
ty: ty,
aux: aux,
}
}
}