lila/src/ast/mod.rs

240 lines
5.2 KiB
Rust

pub mod expr;
pub use expr::{BinaryExpression, Expr, SExpr};
use crate::typing::Type;
use ariadne;
use std::{fmt::Display, path::Path};
#[derive(Debug, PartialEq, Clone)]
pub enum BinaryOperator {
// Logic
And,
Or,
// Arithmetic
Add,
Sub,
Mul,
Div,
Modulo,
Equal,
NotEqual,
}
impl Display for BinaryOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
BinaryOperator::And => "&&",
BinaryOperator::Or => "||",
BinaryOperator::Add => "+",
BinaryOperator::Sub => "-",
BinaryOperator::Mul => "*",
BinaryOperator::Div => "/",
BinaryOperator::Modulo => "%",
BinaryOperator::Equal => "==",
BinaryOperator::NotEqual => "!=",
})
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum UnaryOperator {
Not,
}
pub type Identifier = String;
pub type SourceId = u32;
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Span {
pub source: SourceId,
pub start: usize,
pub end: usize,
}
impl ariadne::Span for Span {
type SourceId = SourceId;
fn source(&self) -> &Self::SourceId {
&self.source
}
fn start(&self) -> usize {
self.start
}
fn end(&self) -> usize {
self.end
}
}
#[derive(Debug, PartialEq, Clone, Default, Eq, Hash)]
pub struct ModulePath {
components: Vec<String>,
}
impl ModulePath {
pub fn concat(lhs: &ModulePath, rhs: &ModulePath) -> ModulePath {
ModulePath {
components: Vec::from_iter(
lhs.components
.iter()
.chain(rhs.components.iter())
.map(Clone::clone),
),
}
}
}
impl std::fmt::Display for ModulePath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.components.join("::")))
}
}
impl From<&Path> for ModulePath {
fn from(path: &Path) -> Self {
let meta = std::fs::metadata(path).unwrap();
ModulePath {
components: path
.components()
.map(|component| match component {
std::path::Component::Normal(n) => {
if meta.is_file() {
n.to_str().unwrap().split('.').nth(0).unwrap().to_string()
} else if meta.is_dir() {
n.to_str().unwrap().to_string()
} else {
// XXX: symlinks?
unreachable!()
}
}
_ => unreachable!(),
})
.collect(),
}
}
}
impl From<&str> for ModulePath {
fn from(string: &str) -> Self {
ModulePath {
components: string.split("::").map(|c| c.to_string()).collect(),
}
}
}
#[derive(Eq, PartialEq, Debug)]
pub struct Import(pub String);
#[derive(Debug, PartialEq)]
pub struct ReturnStatement {
pub expr: Option<SExpr>,
pub span: Span,
}
#[derive(Debug, PartialEq)]
pub enum Statement {
DeclareStatement {
lhs: Identifier,
rhs: Box<SExpr>,
span: Span,
},
AssignStatement {
lhs: Identifier,
rhs: Box<SExpr>,
span: Span,
},
ReturnStatement(ReturnStatement),
CallStatement {
call: Box<Call>,
span: Span,
},
UseStatement {
import: Box<Import>,
span: Span,
},
IfStatement {
condition: Box<SExpr>,
then_block: Box<Block>,
span: Span,
},
WhileStatement {
condition: Box<SExpr>,
loop_block: Box<Block>,
span: Span,
},
}
#[derive(Debug, PartialEq)]
pub struct Block {
pub statements: Vec<Statement>,
pub value: Option<SExpr>,
pub typ: Type,
pub span: Option<Span>,
}
impl Block {
pub fn empty() -> Block {
Block {
typ: Type::Unit,
statements: Vec::with_capacity(0),
value: None,
span: None,
}
}
}
#[derive(Debug, PartialEq)]
pub enum Definition {
FunctionDefinition(FunctionDefinition),
}
#[derive(Debug, PartialEq)]
pub struct FunctionDefinition {
pub name: Identifier,
pub parameters: Vec<Parameter>,
pub return_type: Option<Type>,
pub return_type_span: Option<Span>,
pub body: Box<Block>,
pub span: Span,
}
#[derive(Debug, PartialEq, Default)]
pub struct Module {
pub file: Option<std::path::PathBuf>,
pub path: ModulePath,
pub functions: Vec<FunctionDefinition>,
pub imports: Vec<Import>,
}
impl Module {
pub fn new(path: ModulePath) -> Self {
Self {
path,
..Default::default()
}
}
pub fn full_func_path(&self, func: usize) -> ModulePath {
ModulePath::concat(
&self.path,
&ModulePath::from(self.functions[func].name.as_str()),
)
}
}
#[derive(Debug, PartialEq)]
pub struct Call {
pub callee: Box<SExpr>,
pub args: Vec<SExpr>,
pub typ: Type,
}
#[derive(Debug, PartialEq)]
pub struct Parameter {
pub name: Identifier,
pub typ: Type,
}