1use crate::ast::{BinOp, Expr, ExprKind, UnOp};
2use crate::program::Program;
3use crate::span::Span;
4use crate::symbol::Symbol;
5use rust_decimal::Decimal;
6use thiserror::Error;
7
8#[derive(Error, Debug, Clone)]
10pub enum IrError {
11 #[error("Undefined symbol {0}")]
12 UndefinedSymbol(String, Span),
13}
14
15#[derive(Debug, Clone)]
16pub enum Instr<'sym> {
17 Push(Decimal),
18 Load(&'sym Symbol),
19 Neg,
20 Add,
21 Sub,
22 Mul,
23 Div,
24 Pow,
25 Fact,
26 Call(&'sym Symbol, usize), Equal,
29 NotEqual,
30 Less,
31 LessEqual,
32 Greater,
33 GreaterEqual,
34}
35
36pub struct IrBuilder<'sym> {
38 prog: Program<'sym>,
39}
40
41impl<'src, 'sym> IrBuilder<'sym> {
42 pub fn new() -> Self {
44 Self {
45 prog: Program::new(),
46 }
47 }
48
49 pub fn build(mut self, expr: &Expr<'src, 'sym>) -> Result<Program<'sym>, IrError> {
51 self.emit(expr)?;
52 Ok(self.prog)
53 }
54
55 fn emit(&mut self, e: &Expr<'src, 'sym>) -> Result<(), IrError> {
56 match &e.kind {
57 ExprKind::Literal(v) => {
58 self.prog.code.push(Instr::Push(*v));
59 }
60 ExprKind::Ident { name, sym } => {
61 if sym.is_none() {
62 return Err(IrError::UndefinedSymbol(name.to_string(), e.span));
63 }
64 self.prog.code.push(Instr::Load(sym.unwrap()));
65 }
66 ExprKind::Unary { op, expr } => {
67 self.emit(expr)?;
68 match op {
69 UnOp::Neg => self.prog.code.push(Instr::Neg),
70 UnOp::Fact => self.prog.code.push(Instr::Fact),
71 }
72 }
73 ExprKind::Binary { op, left, right } => {
74 self.emit(left)?;
75 self.emit(right)?;
76 self.prog.code.push(match op {
77 BinOp::Add => Instr::Add,
78 BinOp::Sub => Instr::Sub,
79 BinOp::Mul => Instr::Mul,
80 BinOp::Div => Instr::Div,
81 BinOp::Pow => Instr::Pow,
82 BinOp::Equal => Instr::Equal,
83 BinOp::NotEqual => Instr::NotEqual,
84 BinOp::Less => Instr::Less,
85 BinOp::LessEqual => Instr::LessEqual,
86 BinOp::Greater => Instr::Greater,
87 BinOp::GreaterEqual => Instr::GreaterEqual,
88 });
89 }
90 ExprKind::Call { name, args, sym } => {
91 if sym.is_none() {
92 return Err(IrError::UndefinedSymbol(name.to_string(), e.span));
93 }
94 for a in args.iter() {
95 self.emit(a)?;
96 }
97 self.prog.code.push(Instr::Call(sym.unwrap(), args.len()));
98 }
99 }
100 Ok(())
101 }
102}