1use crate::{MiniError, MiniResult};
2
3pub type Ast = Vec<Stmt>;
4
5#[derive(Clone, Debug, PartialEq, Eq)]
6pub enum Stmt {
7 Binding(String, Expr),
8 Print(Expr),
9 Define(String, Vec<String>, Expr),
10}
11
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum Expr {
14 Value(i32),
15 Variable(String),
16 Operation(Operator, Box<Expr>, Box<Expr>),
17 FuncCall(String, Vec<Expr>),
18 If(Box<Expr>, Box<Expr>, Box<Expr>),
19}
20
21#[derive(Copy, Clone, Debug, PartialEq, Eq)]
23pub enum Operator {
24 Add,
26 Sub,
28 Mul,
30 Div,
32 Rem,
34 Gt,
36 Ge,
38 Lt,
40 Le,
42 Eq,
44 Neq,
46}
47
48pub fn parse<S: AsRef<str>>(input: S) -> MiniResult<Ast> {
49 parser::program(input.as_ref()).map_err(MiniError::Parse)
50}
51
52peg::parser! { grammar parser() for str {
53 rule _ = ("\t"/" "/"\\\n"/"\\\r")*
54 rule __ = (_ ("\n"/"\r"))*
55 rule space() = ("\t"/" "/"\\\n"/"\\\r")+
56
57 pub rule program() -> Ast
58 = stmt()*
59
60 rule stmt() -> Stmt
61 = print()
62 / binding()
63 / define()
64
65 rule print() -> Stmt
66 = _ "print" space() e:expr() __ { Stmt::Print(e) }
67
68 rule binding() -> Stmt
69 = _ "let" space() v:ident() _ "=" _ e:expr() __ { Stmt::Binding(v, e) }
70
71 rule define() -> Stmt
72 = _ "def" space() n:ident() _
73 "(" a:((_ a:ident() _ { a }) ** (",")) ","? _ ")" _
74 "=" _ e:expr() __ { Stmt::Define(n, a, e) }
75
76 rule expr() -> Expr = eq()
77
78 rule eq() -> Expr
79 = l:comp() rs:( _ op:$(("=="/"!=")) _ r:comp() { (op, r) })*
80 {
81 rs.into_iter().fold(l, |l, (op, r)| Expr::Operation(
82 match op {
83 "==" => Operator::Eq,
84 "!=" => Operator::Neq,
85 _ => unreachable!(),
86 },
87 Box::new(l),
88 Box::new(r),
89 ))
90 }
91
92 rule comp() -> Expr
93 = l:add() rs:( _ op:$(("=>"/"=<"/">="/"<="/">"/"<")) _ r:add() { (op, r) })*
94 {
95 rs.into_iter().fold(l, |l, (op, r)| Expr::Operation(
96 match op {
97 ">" => Operator::Gt,
98 "=>" | ">=" => Operator::Ge,
99 "<" => Operator::Lt,
100 "=<" | "<=" => Operator::Le,
101 _ => unreachable!(),
102 },
103 Box::new(l),
104 Box::new(r),
105 ))
106 }
107
108 rule add() -> Expr
109 = l:mul() rs:( _ op:$(("+"/"-")) _ r:mul() { (op, r) })*
110 {
111 rs.into_iter().fold(l, |l, (op, r)| Expr::Operation(
112 match op {
113 "+" => Operator::Add,
114 "-" => Operator::Sub,
115 _ => unreachable!(),
116 },
117 Box::new(l),
118 Box::new(r),
119 ))
120 }
121
122 rule mul() -> Expr
123 = l:atom() rs:( _ op:$(("*"/"/"/"%")) _ r:atom() { (op, r) })*
124 {
125 rs.into_iter().fold(l, |l, (op, r)| Expr::Operation(
126 match op {
127 "*" => Operator::Mul,
128 "/" => Operator::Div,
129 "%" => Operator::Rem,
130 _ => unreachable!(),
131 },
132 Box::new(l),
133 Box::new(r),
134 ))
135 }
136
137 rule atom() -> Expr
138 = n:number() { Expr::Value(n) }
139 / "(" _ e:expr() _ ")" { e }
140 / funccall()
141 / if_expr()
142 / v:ident() { Expr::Variable(v) }
143
144 rule funccall() -> Expr
145 = n:ident() _ "(" e:((_ e:expr() _ { e }) ** (",")) ","? _ ")" {
146 Expr::FuncCall(n, e)
147 }
148
149 rule if_expr() -> Expr
150 = "if" space() c:expr() space()
151 "then" space() t:expr() space()
152 "else" space() f:expr() { Expr::If(Box::new(c), Box::new(t), Box::new(f)) }
153
154 rule ident() -> String
155 = s:$(['a'..='z' | '_']*) { String::from(s) }
156
157 rule number() -> i32
158 = "-" _ n:unsigned() { -n }
159 / ("+"/"") _ n:unsigned() { n }
160
161 rule unsigned() -> i32
162 = n:$(['0'..='9']+) {? n.parse().or(Err("Integer Parsing Error"))}
163
164}}