petr_ast/
ast.rs

1use std::rc::Rc;
2
3use petr_utils::{Identifier, Path, SpannedItem};
4
5use crate::comments::Commented;
6
7// todo rename to parse tree or parsed program
8pub struct Ast {
9    pub modules: Vec<Module>,
10}
11
12impl std::fmt::Debug for Ast {
13    fn fmt(
14        &self,
15        f: &mut std::fmt::Formatter<'_>,
16    ) -> std::fmt::Result {
17        writeln!(f, "AST")?;
18        for module in self.modules.iter() {
19            let path = module.name.iter().map(|x| format!("{}", x.id)).collect::<Vec<_>>().join(".");
20            writeln!(f, "Module: {path}")?;
21            for node in module.nodes.iter() {
22                match node.item() {
23                    AstNode::FunctionDeclaration(fun) => writeln!(f, "  Function: {}", fun.item().name.id)?,
24                    AstNode::TypeDeclaration(ty) => writeln!(f, "  Type: {}", ty.item().name.id)?,
25                    AstNode::ImportStatement(i) => writeln!(
26                        f,
27                        "  Import: {}",
28                        i.item().path.iter().map(|x| format!("{}", x.id)).collect::<Vec<_>>().join(".")
29                    )?,
30                }
31            }
32        }
33        Ok(())
34    }
35}
36
37pub struct Module {
38    pub name:  Path,
39    pub nodes: Vec<SpannedItem<AstNode>>,
40}
41impl Module {
42    fn span_pointing_to_beginning_of_module(&self) -> petr_utils::Span {
43        let first = self.nodes.first().expect("Module was empty");
44        let span = first.span();
45        // make this span just point to a single character
46        span.zero_length()
47    }
48}
49
50impl Ast {
51    pub fn new(nodes: Vec<Module>) -> Ast {
52        Self { modules: nodes }
53    }
54
55    /// Generates a one-character span pointing to the beginning of this AST
56    pub fn span_pointing_to_beginning_of_ast(&self) -> petr_utils::Span {
57        let first = self.modules.first().expect("AST was empty");
58        first.span_pointing_to_beginning_of_module()
59    }
60}
61
62pub enum AstNode {
63    FunctionDeclaration(Commented<FunctionDeclaration>),
64    TypeDeclaration(Commented<TypeDeclaration>),
65    ImportStatement(Commented<ImportStatement>),
66}
67
68pub struct ImportStatement {
69    pub path:       Path,
70    pub alias:      Option<Identifier>,
71    pub visibility: Visibility,
72}
73impl ImportStatement {
74    pub fn is_exported(&self) -> bool {
75        self.visibility == Visibility::Exported
76    }
77}
78
79#[derive(Clone)]
80pub struct TypeDeclaration {
81    pub name:       Identifier,
82    pub variants:   Box<[SpannedItem<TypeVariant>]>,
83    pub visibility: Visibility,
84}
85
86impl TypeDeclaration {
87    pub fn is_exported(&self) -> bool {
88        self.visibility == Visibility::Exported
89    }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub enum Visibility {
94    Local,
95    Exported,
96}
97
98#[derive(Clone)]
99pub struct TypeVariant {
100    pub name:   Identifier,
101    pub fields: Box<[SpannedItem<TypeField>]>,
102}
103
104#[derive(Clone)]
105pub struct TypeField {
106    pub name: Identifier,
107    pub ty:   Ty,
108}
109
110#[derive(Clone)]
111pub struct FunctionDeclaration {
112    pub name:        Identifier,
113    pub parameters:  Box<[FunctionParameter]>,
114    pub return_type: Ty,
115    pub body:        SpannedItem<Expression>,
116    pub visibility:  Visibility,
117}
118impl FunctionDeclaration {
119    pub fn is_exported(&self) -> bool {
120        self.visibility == Visibility::Exported
121    }
122}
123
124#[derive(Clone)]
125pub enum Expression {
126    Literal(Literal),
127    List(List),
128    Operator(Box<OperatorExpression>),
129    FunctionCall(FunctionCall),
130    Variable(Identifier),
131    IntrinsicCall(IntrinsicCall),
132    Binding(ExpressionWithBindings),
133    TypeConstructor(petr_utils::TypeId, Box<[SpannedItem<Expression>]>),
134}
135
136#[derive(Clone)]
137pub struct ExpressionWithBindings {
138    pub bindings:   Vec<Binding>,
139    pub expression: Box<SpannedItem<Expression>>,
140    pub expr_id:    ExprId,
141}
142
143#[derive(Clone, Debug, PartialOrd, Ord, Eq, PartialEq, Copy)]
144pub struct ExprId(pub usize);
145
146#[derive(Clone)]
147pub struct Binding {
148    pub name: Identifier,
149    pub val:  SpannedItem<Expression>,
150}
151
152#[derive(Clone)]
153pub struct IntrinsicCall {
154    pub intrinsic: Intrinsic,
155    pub args:      Box<[SpannedItem<Expression>]>,
156}
157
158impl std::fmt::Display for Intrinsic {
159    fn fmt(
160        &self,
161        f: &mut std::fmt::Formatter<'_>,
162    ) -> std::fmt::Result {
163        match self {
164            Intrinsic::Puts => write!(f, "puts"),
165            Intrinsic::Add => write!(f, "add"),
166            Intrinsic::Subtract => write!(f, "subtract"),
167            Intrinsic::Multiply => write!(f, "multiply"),
168            Intrinsic::Divide => write!(f, "divide"),
169            Intrinsic::Malloc => write!(f, "malloc"),
170        }
171    }
172}
173
174#[derive(Clone, Debug)]
175pub enum Intrinsic {
176    /// intrinsic for `libc` puts
177    Puts,
178    Add,
179    Subtract,
180    Multiply,
181    Divide,
182    Malloc,
183}
184
185#[derive(Clone)]
186pub struct FunctionCall {
187    pub func_name: Path,
188    pub args: Box<[SpannedItem<Expression>]>,
189    // used for the formatter, primarily
190    pub args_were_parenthesized: bool,
191}
192
193#[derive(Clone)]
194pub struct VariableExpression {
195    pub name: Identifier,
196}
197#[derive(Clone)]
198pub struct List {
199    pub elements: Box<[Commented<SpannedItem<Expression>>]>,
200}
201
202#[derive(Clone, Debug)]
203pub enum Literal {
204    Integer(i64),
205    Boolean(bool),
206    String(Rc<str>),
207}
208
209impl std::fmt::Display for Literal {
210    fn fmt(
211        &self,
212        f: &mut std::fmt::Formatter<'_>,
213    ) -> std::fmt::Result {
214        match self {
215            Literal::Integer(i) => write!(f, "{}", i),
216            Literal::Boolean(b) => write!(f, "{}", b),
217            Literal::String(s) => write!(f, "\"{}\"", s),
218        }
219    }
220}
221
222#[derive(Clone)]
223pub struct OperatorExpression {
224    pub lhs: SpannedItem<Expression>,
225    pub rhs: SpannedItem<Expression>,
226    pub op:  SpannedItem<Operator>,
227}
228
229#[derive(Clone, Debug, Copy)]
230pub struct FunctionParameter {
231    pub name: Identifier,
232    pub ty:   Ty,
233}
234
235#[derive(Clone, Copy, Debug)]
236pub enum Ty {
237    Int,
238    Bool,
239    Named(Identifier),
240    String,
241    Unit,
242}
243
244#[derive(Clone)]
245pub enum Operator {
246    Plus,
247    Minus,
248    Star,
249    Slash,
250}
251
252impl Operator {
253    pub fn as_str(&self) -> &'static str {
254        match self {
255            Operator::Plus => "+",
256            Operator::Minus => "-",
257            Operator::Star => "*",
258            Operator::Slash => "/",
259        }
260    }
261}
262
263#[derive(Clone)]
264pub struct Comment {
265    pub content: Rc<str>,
266}
267
268impl Comment {
269    pub fn new(item: impl AsRef<str>) -> Self {
270        Self {
271            content: Rc::from(item.as_ref()),
272        }
273    }
274}