Skip to main content

cemc/ast/
mod.rs

1/**
2Abstract Syntax Tree definitions for Cem
3
4This module defines the core AST types representing Cem programs.
5*/
6pub mod types;
7
8use std::fmt;
9use std::sync::Arc;
10
11/// Source code location for debugging and error messages
12///
13/// Uses Arc<str> for the filename to avoid duplicating it across the AST.
14/// This is important because a large program may have thousands of AST nodes
15/// all referring to the same file.
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct SourceLoc {
18    pub line: usize,
19    pub column: usize,
20    pub file: Arc<str>,
21}
22
23impl SourceLoc {
24    pub fn new(line: usize, column: usize, file: impl Into<Arc<str>>) -> Self {
25        Self {
26            line,
27            column,
28            file: file.into(),
29        }
30    }
31
32    /// Create an unknown/synthetic location (for generated code or tests)
33    pub fn unknown() -> Self {
34        Self {
35            line: 0,
36            column: 0,
37            file: Arc::from("<unknown>"),
38        }
39    }
40
41    /// Create a location with just a file (line/column unknown)
42    pub fn file_only(file: impl Into<Arc<str>>) -> Self {
43        Self {
44            line: 1,
45            column: 1,
46            file: file.into(),
47        }
48    }
49}
50
51impl fmt::Display for SourceLoc {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        write!(f, "{}:{}:{}", self.file, self.line, self.column)
54    }
55}
56
57/// A complete Cem program
58#[derive(Debug, Clone, PartialEq)]
59pub struct Program {
60    pub type_defs: Vec<TypeDef>,
61    pub word_defs: Vec<WordDef>,
62}
63
64/// Type definition (Algebraic Data Type / Sum Type)
65#[derive(Debug, Clone, PartialEq)]
66pub struct TypeDef {
67    pub name: String,
68    pub type_params: Vec<String>,
69    pub variants: Vec<Variant>,
70}
71
72/// A variant of a sum type
73#[derive(Debug, Clone, PartialEq)]
74pub struct Variant {
75    pub name: String,
76    pub fields: Vec<types::Type>,
77}
78
79/// Word (function) definition
80#[derive(Debug, Clone, PartialEq)]
81pub struct WordDef {
82    pub name: String,
83    pub effect: types::Effect,
84    pub body: Vec<Expr>,
85    pub loc: SourceLoc, // Location of the word definition (: word_name line)
86}
87
88/// Expression in the body of a word
89#[derive(Debug, Clone, PartialEq)]
90pub enum Expr {
91    /// Literal integer
92    IntLit(i64, SourceLoc),
93
94    /// Literal boolean
95    BoolLit(bool, SourceLoc),
96
97    /// Literal string
98    StringLit(String, SourceLoc),
99
100    /// Word call (reference to another word)
101    WordCall(String, SourceLoc),
102
103    /// Quotation (code block)
104    Quotation(Vec<Expr>, SourceLoc),
105
106    /// Pattern match expression
107    Match {
108        branches: Vec<MatchBranch>,
109        loc: SourceLoc,
110    },
111
112    /// If expression (condition is top of stack)
113    If {
114        then_branch: Box<Expr>,
115        else_branch: Box<Expr>,
116        loc: SourceLoc,
117    },
118}
119
120impl Expr {
121    /// Get the source location of any expression
122    pub fn loc(&self) -> &SourceLoc {
123        match self {
124            Expr::IntLit(_, loc) => loc,
125            Expr::BoolLit(_, loc) => loc,
126            Expr::StringLit(_, loc) => loc,
127            Expr::WordCall(_, loc) => loc,
128            Expr::Quotation(_, loc) => loc,
129            Expr::Match { loc, .. } => loc,
130            Expr::If { loc, .. } => loc,
131        }
132    }
133}
134
135/// A branch in a pattern match
136#[derive(Debug, Clone, PartialEq)]
137pub struct MatchBranch {
138    pub pattern: Pattern,
139    pub body: Vec<Expr>,
140}
141
142/// Pattern for matching on sum types
143#[derive(Debug, Clone, PartialEq)]
144pub enum Pattern {
145    /// Match a specific variant, binding its fields
146    Variant {
147        name: String,
148        // Field patterns could be added later for nested matching
149    },
150}
151
152impl fmt::Display for Expr {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        match self {
155            Expr::IntLit(n, _) => write!(f, "{}", n),
156            Expr::BoolLit(b, _) => write!(f, "{}", b),
157            Expr::StringLit(s, _) => write!(f, "\"{}\"", s),
158            Expr::WordCall(name, _) => write!(f, "{}", name),
159            Expr::Quotation(exprs, _) => {
160                write!(f, "[ ")?;
161                for expr in exprs {
162                    write!(f, "{} ", expr)?;
163                }
164                write!(f, "]")
165            }
166            Expr::Match { branches, .. } => {
167                writeln!(f, "match")?;
168                for branch in branches {
169                    writeln!(f, "  {:?} => [ ... ]", branch.pattern)?;
170                }
171                write!(f, "end")
172            }
173            Expr::If { .. } => write!(f, "if"),
174        }
175    }
176}