1use crate::token::Op;
2use crate::types::{FnDef, LocalBinding, Resolution, Type, Typed};
3use std::fmt;
4
5pub trait ASTSpec {
23 type CallCargo: fmt::Debug + PartialEq + Eq + Clone;
24 type IdentCargo: fmt::Debug + PartialEq + Eq + Clone;
25 type ExprCargo: fmt::Debug + PartialEq + Eq + Clone;
26 type ParamCargo: fmt::Debug + PartialEq + Eq + Clone;
27 type FuncCargo: fmt::Debug + PartialEq + Eq + Clone;
28 type LetCargo: fmt::Debug + PartialEq + Eq + Clone;
29 type BinaryCargo: fmt::Debug + PartialEq + Eq + Clone;
30 type ProgramCargo: fmt::Debug + PartialEq + Eq + Clone;
31}
32
33#[derive(Debug, PartialEq, Eq, Clone)]
34pub struct UntypedAST;
35
36impl ASTSpec for UntypedAST {
37 type CallCargo = ();
38 type IdentCargo = ();
39 type ExprCargo = ();
40 type ParamCargo = ();
41 type FuncCargo = ();
42 type LetCargo = ();
43 type BinaryCargo = ();
44 type ProgramCargo = ();
45}
46
47#[derive(Debug, PartialEq, Eq, Clone)]
48pub struct TypedAST;
49
50impl ASTSpec for TypedAST {
51 type CallCargo = Type;
52 type IdentCargo = Resolution;
53 type ExprCargo = Type;
54 type ParamCargo = Type;
55 type FuncCargo = FnDef;
56 type LetCargo = LocalBinding;
57 type BinaryCargo = Type;
58 type ProgramCargo = usize;
59}
60
61#[derive(Debug, PartialEq, Eq, Clone)]
65pub struct Call<AST: ASTSpec = UntypedAST> {
66 pub target: Box<Expr<AST>>,
67 pub args: Vec<Expr<AST>>,
68 pub resolved_type: AST::CallCargo,
69}
70
71impl Call {
72 pub fn untyped(target: Expr, args: Vec<Expr>) -> Call {
73 Call { target: Box::new(target), args, resolved_type: () }
74 }
75}
76
77pub type TypedCall = Call<TypedAST>;
78
79impl Typed for TypedCall {
80 fn typ(&self) -> Type {
81 self.resolved_type.clone()
82 }
83}
84
85#[derive(Debug, PartialEq, Eq, Clone)]
89pub struct Literal<T: PartialEq + Eq + Clone> {
90 pub value: T,
91}
92
93pub type IntLiteral = Literal<i64>;
94pub type StrLiteral = Literal<String>;
95
96impl<T: fmt::Debug + PartialEq + Eq + Clone> Literal<T> {
97 pub fn new<U: Into<T>>(value: U) -> Literal<T> {
98 Literal { value: value.into() }
99 }
100}
101
102impl Typed for Literal<String> {
103 fn typ(&self) -> Type {
104 Type::Str
105 }
106}
107
108impl Typed for Literal<i64> {
109 fn typ(&self) -> Type {
110 Type::Int
111 }
112}
113
114#[derive(Debug, PartialEq, Eq, Clone)]
118pub struct Ident<AST: ASTSpec = UntypedAST> {
119 pub name: String,
120 pub resolution: AST::IdentCargo,
121}
122
123impl Ident {
124 pub fn untyped<S: ToString>(name: S) -> Ident {
125 Ident { name: name.to_string(), resolution: () }
126 }
127}
128
129pub type TypedIdent = Ident<TypedAST>;
130
131impl Typed for TypedIdent {
132 fn typ(&self) -> Type {
133 self.resolution.typ.clone()
134 }
135}
136
137#[derive(Debug, PartialEq, Eq, Clone, Copy)]
141pub enum BinaryOp {
142 Add,
143 Sub,
144 Mul,
145 Div,
146}
147
148impl From<Op> for BinaryOp {
149 fn from(value: Op) -> Self {
150 match value {
151 Op::Plus => BinaryOp::Add,
152 Op::Minus => BinaryOp::Sub,
153 Op::Star => BinaryOp::Mul,
154 Op::Slash => BinaryOp::Div,
155 }
156 }
157}
158
159#[derive(Debug, PartialEq, Eq, Clone)]
160pub struct Binary<AST: ASTSpec = UntypedAST> {
161 pub op: BinaryOp,
162 pub lhs: Box<Expr<AST>>,
163 pub rhs: Box<Expr<AST>>,
164 pub cargo: AST::BinaryCargo,
165}
166
167pub type TypedBinary = Binary<TypedAST>;
168
169impl Binary {
170 pub fn untyped(op: BinaryOp, lhs: Expr, rhs: Expr) -> Binary {
171 Binary { op, lhs: Box::new(lhs), rhs: Box::new(rhs), cargo: () }
172 }
173}
174
175impl Typed for Binary<TypedAST> {
176 fn typ(&self) -> Type {
177 self.cargo.clone()
178 }
179}
180
181#[derive(Debug, PartialEq, Eq, Clone)]
185pub enum Expr<AST: ASTSpec = UntypedAST> {
186 Ident(Ident<AST>),
187 Str(StrLiteral),
188 Int(IntLiteral),
189 Call(Call<AST>),
190 Binary(Binary<AST>),
191}
192
193impl<AST: ASTSpec> Expr<AST> {
194 pub fn as_ident(self) -> Option<Ident<AST>> {
195 if let Self::Ident(ident) = self {
196 Some(ident)
197 } else {
198 None
199 }
200 }
201}
202
203pub type TypedExpr = Expr<TypedAST>;
204
205impl Typed for TypedExpr {
206 fn typ(&self) -> Type {
207 use Expr::*;
208 match self {
209 Ident(expr) => expr.typ(),
210 Str(expr) => expr.typ(),
211 Int(expr) => expr.typ(),
212 Call(expr) => expr.typ(),
213 Binary(expr) => expr.typ(),
214 }
215 }
216}
217
218#[derive(Debug, PartialEq, Eq, Clone)]
222pub enum TypeSpec {
223 Void,
224 Simple(String),
225}
226
227impl TypeSpec {
228 pub fn simple<S: ToString>(s: S) -> TypeSpec {
229 TypeSpec::Simple(s.to_string())
230 }
231}
232
233#[derive(Debug, PartialEq, Eq, Clone)]
237pub struct Param<AST: ASTSpec = UntypedAST> {
238 pub name: String,
239 pub typ: TypeSpec,
240 pub resolved_type: AST::ParamCargo,
241}
242
243impl Param {
244 pub fn untyped<S: ToString>(name: S, typ: TypeSpec) -> Param {
245 Param { name: name.to_string(), typ, resolved_type: () }
246 }
247}
248
249pub type TypedParam = Param<TypedAST>;
250
251impl Typed for TypedParam {
252 fn typ(&self) -> Type {
253 self.resolved_type.clone()
254 }
255}
256
257#[derive(Debug, PartialEq, Eq, Clone)]
261pub struct Binding<AST: ASTSpec = UntypedAST> {
262 pub name: String,
263 pub typ: TypeSpec,
264 pub expr: Expr<AST>,
265 pub resolved_type: AST::LetCargo,
266}
267
268pub type TypedBinding = Binding<TypedAST>;
269
270impl<AST: ASTSpec> Binding<AST> {
271 pub fn new(
272 name: String,
273 typ: TypeSpec,
274 expr: Expr<AST>,
275 resolved_type: AST::LetCargo,
276 ) -> Binding<AST> {
277 Binding { name, typ, expr, resolved_type }
278 }
279}
280
281#[derive(Debug, PartialEq, Eq, Clone)]
285pub enum Stmt<AST: ASTSpec = UntypedAST> {
286 Expr(Expr<AST>),
287 Block(Block<AST>),
288 Let(Binding<AST>),
289}
290
291pub type TypedStmt = Stmt<TypedAST>;
292
293#[derive(Debug, PartialEq, Eq, Clone)]
297pub struct Block<AST: ASTSpec = UntypedAST>(pub Vec<Stmt<AST>>);
298
299pub type TypedBlock = Block<TypedAST>;
300
301#[derive(Debug, PartialEq, Eq, Clone)]
305pub struct Func<AST: ASTSpec = UntypedAST> {
306 pub name: String,
307 pub params: Vec<Param<AST>>,
308 pub body: Block<AST>,
309 pub ret: Option<TypeSpec>,
310 pub resolved_type: AST::FuncCargo,
311}
312
313impl Func {
314 pub fn untyped<S: ToString>(
315 name: S,
316 params: Vec<Param>,
317 body: Block,
318 ret: Option<TypeSpec>,
319 ) -> Func {
320 Func { name: name.to_string(), params, body, ret, resolved_type: () }
321 }
322}
323
324pub type TypedFunc = Func<TypedAST>;
325
326#[derive(Debug, PartialEq, Clone)]
330pub enum Def<AST: ASTSpec = UntypedAST> {
331 FnDef(Func<AST>),
332}
333
334pub type TypedDef = Def<TypedAST>;
335
336#[derive(Debug, PartialEq, Clone)]
340pub struct Program<AST: ASTSpec = UntypedAST> {
341 pub defs: Vec<Def<AST>>,
342 pub main_def: AST::ProgramCargo,
343}
344
345pub type TypedProgram = Program<TypedAST>;