pub mod types;
pub use types::Type;
pub type SourceLine = usize;
#[derive(Debug, Clone, Copy, Default)]
pub struct AnnotBool(pub bool);
impl PartialEq for AnnotBool {
fn eq(&self, _: &Self) -> bool {
true
}
}
impl From<bool> for AnnotBool {
fn from(b: bool) -> Self {
Self(b)
}
}
#[derive(Debug)]
pub struct Spanned<T> {
pub node: T,
pub line: SourceLine,
pub ty: std::sync::OnceLock<Type>,
}
impl<T: Clone> Clone for Spanned<T> {
fn clone(&self) -> Self {
let ty = std::sync::OnceLock::new();
if let Some(t) = self.ty.get() {
let _ = ty.set(t.clone());
}
Self {
node: self.node.clone(),
line: self.line,
ty,
}
}
}
impl<T: PartialEq> PartialEq for Spanned<T> {
fn eq(&self, other: &Self) -> bool {
self.node == other.node
}
}
impl<T> Spanned<T> {
pub fn new(node: T, line: SourceLine) -> Self {
Self {
node,
line,
ty: std::sync::OnceLock::new(),
}
}
pub fn bare(node: T) -> Self {
Self::new(node, 0)
}
pub fn set_ty(&self, ty: Type) {
let _ = self.ty.set(ty);
}
pub fn ty(&self) -> Option<&Type> {
self.ty.get()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
Int(i64),
Float(f64),
Str(String),
Bool(bool),
Unit,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Eq,
Neq,
Lt,
Gt,
Lte,
Gte,
}
#[derive(Debug)]
pub struct MatchArm {
pub pattern: Pattern,
pub body: Box<Spanned<Expr>>,
pub binding_slots: std::sync::OnceLock<Vec<u16>>,
}
impl Clone for MatchArm {
fn clone(&self) -> Self {
let binding_slots = std::sync::OnceLock::new();
if let Some(v) = self.binding_slots.get() {
let _ = binding_slots.set(v.clone());
}
Self {
pattern: self.pattern.clone(),
body: self.body.clone(),
binding_slots,
}
}
}
impl PartialEq for MatchArm {
fn eq(&self, other: &Self) -> bool {
self.pattern == other.pattern && self.body == other.body
}
}
impl MatchArm {
pub fn new(pattern: Pattern, body: Spanned<Expr>) -> Self {
Self {
pattern,
body: Box::new(body),
binding_slots: std::sync::OnceLock::new(),
}
}
pub fn new_boxed(pattern: Pattern, body: Box<Spanned<Expr>>) -> Self {
Self {
pattern,
body,
binding_slots: std::sync::OnceLock::new(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Pattern {
Wildcard,
Literal(Literal),
Ident(String),
EmptyList,
Cons(String, String),
Tuple(Vec<Pattern>),
Constructor(String, Vec<String>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum StrPart {
Literal(String),
Parsed(Box<Spanned<Expr>>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct TailCallData {
pub target: String,
pub args: Vec<Spanned<Expr>>,
}
impl TailCallData {
pub fn new(target: String, args: Vec<Spanned<Expr>>) -> Self {
Self { target, args }
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Literal(Literal),
Ident(String),
Attr(Box<Spanned<Expr>>, String),
FnCall(Box<Spanned<Expr>>, Vec<Spanned<Expr>>),
BinOp(BinOp, Box<Spanned<Expr>>, Box<Spanned<Expr>>),
Match {
subject: Box<Spanned<Expr>>,
arms: Vec<MatchArm>,
},
Constructor(String, Option<Box<Spanned<Expr>>>),
ErrorProp(Box<Spanned<Expr>>),
InterpolatedStr(Vec<StrPart>),
List(Vec<Spanned<Expr>>),
Tuple(Vec<Spanned<Expr>>),
MapLiteral(Vec<(Spanned<Expr>, Spanned<Expr>)>),
RecordCreate {
type_name: String,
fields: Vec<(String, Spanned<Expr>)>,
},
RecordUpdate {
type_name: String,
base: Box<Spanned<Expr>>,
updates: Vec<(String, Spanned<Expr>)>,
},
TailCall(Box<TailCallData>),
IndependentProduct(Vec<Spanned<Expr>>, bool),
Resolved {
slot: u16,
name: String,
last_use: AnnotBool,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum Stmt {
Binding(String, Option<String>, Spanned<Expr>),
Expr(Spanned<Expr>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum FnBody {
Block(Vec<Stmt>),
}
impl FnBody {
pub fn from_expr(expr: Spanned<Expr>) -> Self {
Self::Block(vec![Stmt::Expr(expr)])
}
pub fn stmts(&self) -> &[Stmt] {
match self {
Self::Block(stmts) => stmts,
}
}
pub fn stmts_mut(&mut self) -> &mut Vec<Stmt> {
match self {
Self::Block(stmts) => stmts,
}
}
pub fn tail_expr(&self) -> Option<&Spanned<Expr>> {
match self.stmts().last() {
Some(Stmt::Expr(expr)) => Some(expr),
_ => None,
}
}
pub fn tail_expr_mut(&mut self) -> Option<&mut Spanned<Expr>> {
match self.stmts_mut().last_mut() {
Some(Stmt::Expr(expr)) => Some(expr),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FnResolution {
pub local_count: u16,
pub local_slots: std::sync::Arc<std::collections::HashMap<String, u16>>,
pub local_slot_types: std::sync::Arc<Vec<Type>>,
pub aliased_slots: std::sync::Arc<Vec<bool>>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FnDef {
pub name: String,
pub line: usize,
pub params: Vec<(String, String)>,
pub return_type: String,
pub effects: Vec<Spanned<String>>,
pub desc: Option<String>,
pub body: std::sync::Arc<FnBody>,
pub resolution: Option<FnResolution>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Module {
pub name: String,
pub line: usize,
pub depends: Vec<String>,
pub exposes: Vec<String>,
pub exposes_opaque: Vec<String>,
pub exposes_line: Option<usize>,
pub intent: String,
pub effects: Option<Vec<String>>,
pub effects_line: Option<usize>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum VerifyGivenDomain {
IntRange { start: i64, end: i64 },
Explicit(Vec<Spanned<Expr>>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct VerifyGiven {
pub name: String,
pub type_name: String,
pub domain: VerifyGivenDomain,
}
#[derive(Debug, Clone, PartialEq)]
pub struct VerifyLaw {
pub name: String,
pub givens: Vec<VerifyGiven>,
pub when: Option<Spanned<Expr>>,
pub lhs: Spanned<Expr>,
pub rhs: Spanned<Expr>,
pub sample_guards: Vec<Spanned<Expr>>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct SourceSpan {
pub line: usize,
pub col: usize,
pub end_line: usize,
pub end_col: usize,
}
#[derive(Debug, Clone, PartialEq)]
pub enum VerifyKind {
Cases,
Law(Box<VerifyLaw>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct VerifyBlock {
pub fn_name: String,
pub line: usize,
pub cases: Vec<(Spanned<Expr>, Spanned<Expr>)>,
pub case_spans: Vec<SourceSpan>,
pub case_givens: Vec<Vec<(String, Spanned<Expr>)>>,
pub case_hostile_origins: Vec<bool>,
pub case_hostile_profiles: Vec<Vec<(String, String)>>,
pub kind: VerifyKind,
pub trace: bool,
pub cases_givens: Vec<VerifyGiven>,
}
impl VerifyBlock {
pub fn new_unspanned(
fn_name: String,
line: usize,
cases: Vec<(Spanned<Expr>, Spanned<Expr>)>,
kind: VerifyKind,
) -> Self {
let case_spans = vec![SourceSpan::default(); cases.len()];
let case_hostile_origins = vec![false; cases.len()];
let case_hostile_profiles = vec![Vec::new(); cases.len()];
Self {
fn_name,
line,
cases,
case_spans,
case_givens: vec![],
case_hostile_origins,
case_hostile_profiles,
kind,
trace: false,
cases_givens: vec![],
}
}
pub fn iter_cases_with_spans(
&self,
) -> impl Iterator<Item = (&(Spanned<Expr>, Spanned<Expr>), &SourceSpan)> {
debug_assert_eq!(self.cases.len(), self.case_spans.len());
self.cases.iter().zip(&self.case_spans)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct DecisionBlock {
pub name: String,
pub line: usize,
pub date: String,
pub reason: String,
pub chosen: Spanned<DecisionImpact>,
pub rejected: Vec<Spanned<DecisionImpact>>,
pub impacts: Vec<Spanned<DecisionImpact>>,
pub author: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DecisionImpact {
Symbol(String),
Semantic(String),
}
impl DecisionImpact {
pub fn text(&self) -> &str {
match self {
DecisionImpact::Symbol(s) | DecisionImpact::Semantic(s) => s,
}
}
pub fn as_context_string(&self) -> String {
match self {
DecisionImpact::Symbol(s) => s.clone(),
DecisionImpact::Semantic(s) => format!("\"{}\"", s),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TypeVariant {
pub name: String,
pub fields: Vec<String>, }
#[derive(Debug, Clone, PartialEq)]
pub enum TypeDef {
Sum {
name: String,
variants: Vec<TypeVariant>,
line: usize,
},
Product {
name: String,
fields: Vec<(String, String)>,
line: usize,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum TopLevel {
Module(Module),
FnDef(FnDef),
Verify(VerifyBlock),
Decision(DecisionBlock),
Stmt(Stmt),
TypeDef(TypeDef),
}