use crate::types::Effect;
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq)]
pub struct SourceLocation {
pub file: PathBuf,
pub start_line: usize,
pub end_line: usize,
}
impl SourceLocation {
pub fn new(file: PathBuf, line: usize) -> Self {
SourceLocation {
file,
start_line: line,
end_line: line,
}
}
pub fn span(file: PathBuf, start_line: usize, end_line: usize) -> Self {
debug_assert!(
start_line <= end_line,
"SourceLocation: start_line ({}) must be <= end_line ({})",
start_line,
end_line
);
SourceLocation {
file,
start_line,
end_line,
}
}
}
impl std::fmt::Display for SourceLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.start_line == self.end_line {
write!(f, "{}:{}", self.file.display(), self.start_line + 1)
} else {
write!(
f,
"{}:{}-{}",
self.file.display(),
self.start_line + 1,
self.end_line + 1
)
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Include {
Std(String),
Relative(String),
Ffi(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct UnionField {
pub name: String,
pub type_name: String, }
#[derive(Debug, Clone, PartialEq)]
pub struct UnionVariant {
pub name: String,
pub fields: Vec<UnionField>,
pub source: Option<SourceLocation>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct UnionDef {
pub name: String,
pub variants: Vec<UnionVariant>,
pub source: Option<SourceLocation>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Pattern {
Variant(String),
VariantWithBindings { name: String, bindings: Vec<String> },
}
#[derive(Debug, Clone, PartialEq)]
pub struct MatchArm {
pub pattern: Pattern,
pub body: Vec<Statement>,
pub span: Option<Span>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Program {
pub includes: Vec<Include>,
pub unions: Vec<UnionDef>,
pub words: Vec<WordDef>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WordDef {
pub name: String,
pub effect: Option<Effect>,
pub body: Vec<Statement>,
pub source: Option<SourceLocation>,
pub allowed_lints: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Span {
pub line: usize,
pub column: usize,
pub length: usize,
}
impl Span {
pub fn new(line: usize, column: usize, length: usize) -> Self {
Span {
line,
column,
length,
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct QuotationSpan {
pub start_line: usize,
pub start_column: usize,
pub end_line: usize,
pub end_column: usize,
}
impl QuotationSpan {
pub fn new(start_line: usize, start_column: usize, end_line: usize, end_column: usize) -> Self {
QuotationSpan {
start_line,
start_column,
end_line,
end_column,
}
}
pub fn contains(&self, line: usize, column: usize) -> bool {
if line < self.start_line || line > self.end_line {
return false;
}
if line == self.start_line && column < self.start_column {
return false;
}
if line == self.end_line && column >= self.end_column {
return false;
}
true
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Statement {
IntLiteral(i64),
FloatLiteral(f64),
BoolLiteral(bool),
StringLiteral(String),
Symbol(String),
WordCall { name: String, span: Option<Span> },
If {
then_branch: Vec<Statement>,
else_branch: Option<Vec<Statement>>,
span: Option<Span>,
},
Quotation {
id: usize,
body: Vec<Statement>,
span: Option<QuotationSpan>,
},
Match {
arms: Vec<MatchArm>,
span: Option<Span>,
},
}