1use pest::Parser;
2use pest_derive::Parser;
3use crate::eval::exec_stmt;
4use crate::ast::{Stmt, Expr, Op, Context};
5
6#[derive(Parser)]
7#[grammar = "dash.pest"]
8pub struct DashParser;
9
10pub fn run(source: &str) {
18 match DashParser::parse(Rule::program, source) {
19 Ok(mut pairs) => {
20 let pair = pairs.next().unwrap();
21 let ast = build_ast(pair.into_inner());
22 let mut ctx = Context::default();
23 for stmt in ast {
24 exec_stmt(&stmt, &mut ctx);
25 }
26 }
27 Err(e) => {
28 println!("Parse error: {}", e);
29 }
30 }
31}
32
33fn build_ast(pairs: pest::iterators::Pairs<Rule>) -> Vec<Stmt> {
43 pairs
44 .filter_map(|pair| match pair.as_rule() {
45 Rule::statement => Some(build_stmt(pair.into_inner())),
46 _ => None,
47 })
48 .collect()
49}
50
51fn build_stmt(mut pairs: pest::iterators::Pairs<Rule>) -> Stmt {
61 let pair = pairs.next().unwrap();
62 match pair.as_rule() {
63 Rule::print_stmt => {
64 let mut inner = pair.into_inner();
65 let expr_pair = inner.find(|p| p.as_rule() == Rule::expr).unwrap();
66 let expr = build_expr(expr_pair);
67 Stmt::Print(expr)
68 }
69 Rule::let_stmt => {
70 let mut inner = pair.into_inner();
71 let name = inner.next().unwrap().as_str().to_string();
72 let expr = build_expr(inner.next().unwrap());
73 Stmt::Let(name, expr)
74 }
75 Rule::if_stmt => {
76 let mut inner = pair.into_inner();
77 let condition = build_expr(inner.next().unwrap());
78 let then_block = build_block(inner.next().unwrap());
79 let else_block = inner.next().map(build_block);
80 Stmt::If {
81 condition,
82 then_branch: then_block,
83 else_branch: else_block,
84 }
85 }
86 Rule::while_stmt => {
87 let mut inner = pair.into_inner();
88 let condition = build_expr(inner.next().unwrap());
89 let body = build_block(inner.next().unwrap());
90 Stmt::While { condition, body }
91 }
92 Rule::break_stmt => Stmt::Break,
93 Rule::continue_stmt => Stmt::Continue,
94 Rule::fn_stmt => {
95 let mut inner = pair.into_inner();
96 let name = inner.next().unwrap().as_str().to_string();
97 let param_list = inner.next().unwrap();
98 let params = param_list
99 .into_inner()
100 .map(|p| p.as_str().to_string())
101 .collect();
102 let body = build_block(inner.next().unwrap());
103 Stmt::Fn { name, params, body }
104 }
105 Rule::call_stmt => {
106 let expr = build_expr(pair.into_inner().next().unwrap());
107 if let Expr::Call(name, args) = expr {
108 Stmt::Call(name, args)
109 } else {
110 panic!("Expected call expression in call_stmt");
111 }
112 }
113 Rule::return_stmt => {
114 let expr = build_expr(pair.into_inner().next().unwrap());
115 Stmt::Return(expr)
116 }
117 _ => unreachable!(),
118 }
119}
120
121fn build_expr(pair: pest::iterators::Pair<Rule>) -> Expr {
131 match pair.as_rule() {
132 Rule::expr => {
133 let mut inner = pair.into_inner();
134 let mut left = build_expr(inner.next().unwrap());
135 while let Some(op_pair) = inner.next() {
136 let right = build_expr(inner.next().unwrap());
137 let op = match op_pair.as_str() {
138 "+" => Op::Add,
139 "-" => Op::Sub,
140 _ => unreachable!(),
141 };
142 left = Expr::Binary(Box::new(left), op, Box::new(right));
143 }
144 left
145 }
146 Rule::term => {
147 let mut inner = pair.into_inner();
148 let mut left = build_expr(inner.next().unwrap());
149 while let Some(op_pair) = inner.next() {
150 let op = match op_pair.as_str() {
151 "*" => Op::Mul,
152 "/" => Op::Div,
153 _ => panic!("Unexpected operator in term: {:?}", op_pair.as_str()),
154 };
155 let right = build_expr(inner.next().unwrap());
156 left = Expr::Binary(Box::new(left), op, Box::new(right));
157 }
158 left
159 }
160 Rule::factor => build_expr(pair.into_inner().next().unwrap()),
161 Rule::number => Expr::Int(pair.as_str().parse().unwrap()),
162 Rule::string => {
163 let s = pair.as_str();
164 Expr::Str(s[1..s.len() - 1].to_string()) }
166 Rule::ident => Expr::Var(pair.as_str().to_string()),
167 Rule::comparison => {
168 let mut inner = pair.into_inner();
169 let left = build_expr(inner.next().unwrap());
170 if let Some(op_pair) = inner.next() {
171 let right = build_expr(inner.next().unwrap());
172 let op = match op_pair.as_str() {
173 ">" => Op::Greater,
174 "<" => Op::Less,
175 ">=" => Op::GreaterEq,
176 "<=" => Op::LessEq,
177 "==" => Op::Equal,
178 "!=" => Op::NotEqual,
179 _ => unreachable!(),
180 };
181 Expr::Binary(Box::new(left), op, Box::new(right))
182 } else {
183 left
184 }
185 }
186 Rule::call_expr => {
187 let mut inner = pair.into_inner();
188 let name = inner.next().unwrap().as_str().to_string();
189 let args = if let Some(arg_list) = inner.next() {
190 arg_list.into_inner().map(build_expr).collect()
191 } else {
192 Vec::new()
193 };
194 Expr::Call(name, args)
195 }
196 Rule::primary => build_expr(pair.into_inner().next().unwrap()),
197 _ => unreachable!(),
198 }
199}
200
201fn build_block(pair: pest::iterators::Pair<Rule>) -> Vec<Stmt> {
211 build_ast(pair.into_inner())
212}