240 lines
5.2 KiB
Rust
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,
|
|
}
|