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, } 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, pub span: Span, } #[derive(Debug, PartialEq)] pub enum Statement { DeclareStatement { lhs: Identifier, rhs: Box, span: Span, }, AssignStatement { lhs: Identifier, rhs: Box, span: Span, }, ReturnStatement(ReturnStatement), CallStatement { call: Box, span: Span, }, UseStatement { import: Box, span: Span, }, IfStatement { condition: Box, then_block: Box, span: Span, }, WhileStatement { condition: Box, loop_block: Box, span: Span, }, } #[derive(Debug, PartialEq)] pub struct Block { pub statements: Vec, pub value: Option, pub typ: Type, pub span: Option, } 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, pub return_type: Option, pub return_type_span: Option, pub body: Box, pub span: Span, } #[derive(Debug, PartialEq, Default)] pub struct Module { pub file: Option, pub path: ModulePath, pub functions: Vec, pub imports: Vec, } 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, pub args: Vec, pub typ: Type, } #[derive(Debug, PartialEq)] pub struct Parameter { pub name: Identifier, pub typ: Type, }