8000 [refactoring] Split the parsers for 'stmt' and 'expr' · UnBCIC-TP2/r-python@7fd6efe · GitHub
[go: up one dir, main page]

Skip to content

Commit 7fd6efe

Browse files
committed
[refactoring] Split the parsers for 'stmt' and 'expr'
1 parent d46af57 commit 7fd6efe

File tree

2 files changed

+406
-110
lines changed

2 files changed

+406
-110
lines changed

src/parser/parser_expr.rs

Lines changed: 102 additions & 110 deletions
< 10000 td data-grid-cell-id="diff-975b3fbdc29dba034845cfe0ac50c8aff6e3238015a5faab6d347ac0e3c687dd-210-216-1" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-deletionNum-bgColor, var(--diffBlob-deletion-bgColor-num));text-align:center" tabindex="-1" valign="top" class="focusable-grid-cell diff-line-number position-relative left-side">
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
use nom::{
2-
IResult,
32
branch::alt,
43
bytes::complete::{tag, take_while},
5-
character::complete::{digit1, multispace0, alpha1, char},
6-
combinator::{map_res, recognize, value, map, opt, not, peek, verify},
7-
sequence::{pair, delimited, terminated, preceded},
8-
multi::{many0, fold_many0, separated_list0}
4+
character::complete::{char, digit1, multispace0},
5+
combinator::{map, map_res, opt, value, verify},
6+
multi::{fold_many0, separated_list0},
7+
sequence::{delimited, pair, preceded, tuple},
8+
IResult,
9+
error::Error,
910
};
11+
1012
use std::str::FromStr;
1113

14+
use crate::ir::ast::Expression;
15+
use crate::parser::parser_common::{identifier, keyword, is_string_char};
16+
1217
use crate::ir::ast::Function;
1318
use crate::ir::ast::Type;
14-
use crate::ir::ast::{Expression, Name, Statement, ValueConstructor};
19+
use crate::ir::ast::{Name, Statement, ValueConstructor};
1520

1621
use crate::parser::keywords::KEYWORDS;
1722

@@ -39,7 +44,9 @@ fn parse_and(input: &str) -> IResult<&str, Expression> {
3944

4045
fn parse_not(input: &str) -> IResult<&str, Expression> {
4146
alt((
42-
map(preceded(keyword("not"), parse_not), |e| Expression::Not(Box::new(e))),
47+
map(preceded(keyword("not"), parse_not), |e| {
48+
Expression::Not(Box::new(e))
49+
}),
4350
parse_relational,
4451
))(input)
4552
}
@@ -48,7 +55,14 @@ fn parse_relational(input: &str) -> IResult<&str, Expression> {
4855
let (input, init) = parse_add_sub(input)?;
4956
fold_many0(
5057
pair(
51-
alt((operator("<="), operator("<"), operator(">="), operator(">"), operator("=="), operator("!="))),
58+
alt((
59+
operator("<="),
60+
operator("<"),
61+
operator(">="),
62+
operator(">"),
63+
operator("=="),
64+
operator("!="),
65+
)),
5266
parse_add_sub,
5367
),
5468
move || init.clone(),< A3E2 /span>
@@ -69,7 +83,7 @@ fn parse_add_sub(input: &str) -> IResult<&str, Expression> {
6983
fold_many0(
7084
pair(
7185
alt((operator("+"), operator("-"))),
72-
parse_term,
86+
parse_term
7387
),
7488
move || init.clone(),
7589
|acc, (op, val)| match op {
@@ -85,7 +99,7 @@ fn parse_term(input: &str) -> IResult<&str, Expression> {
8599
fold_many0(
86100
pair(
87101
alt((operator("*"), operator("/"))),
88-
parse_factor,
102+
parse_factor
89103
),
90104
move || init.clone(),
91105
|acc, (op, val)| match op {
@@ -100,27 +114,53 @@ fn parse_factor(input: &str) -> IResult<&str, Expression> {
100114
alt((
101115
parse_bool,
102116
parse_number,
103-
parse_string,
104-
parse_var,
105-
parse_function_call,
106-
delimited(tag("("), parse_expression, tag(")")),
117+
parse_string,
118+
parse_function_call,
119+
parse_var,
120+
delimited(char::<&str, Error<&str>>('('), parse_expression, char::<&str, Error<&str>>(')')),
107121
))(input)
108122
}
109123

110124
fn parse_bool(input: &str) -> IResult<&str, Expression> {
111-
alt((value(Expression::CTrue, keyword("True")), value(Expression::CFalse, keyword("False"))))(input)
125+
alt((
126+
value(Expression::CTrue, keyword("True")),
127+
value(Expression::CFalse, keyword("False")),
128+
))(input)
112129
}
113-
130+
114131
fn parse_number(input: &str) -> IResult<&str, Expression> {
115132
let float_parser = map_res(
116-
recognize(pair(
117-
digit1,
118-
opt(pair(tag("."), digit1))
119-
)),
120-
|s: &str| f64::from_str(s)
133+
verify(
134+
tuple((
135+
opt(char::<&str, Error<&str>>('-')),
136+
digit1,
137+
char::<&str, Error<&str>>('.'),
138+
digit1
139+
)),
140+
|(_, _, _, _)| true,
141+
),
142+
|(sign, d1, _, d2)| {
143+
let s = match sign {
144+
Some(_) => format!("-{}.{}", d1, d2),
145+
None => format!("{}.{}", d1, d2),
146+
};
147+
f64::from_str(&s)
148+
},
121149
);
122150

123-
let int_parser = map_res(digit1, |s: &str| i32::from_str(s));
151+
let int_parser = map_res(
152+
tuple((
153+
opt(char::<&str, Error<&str>>('-')),
154+
digit1
155+
)),
156+
|(sign, digits)| {
157+
let s = match sign {
158+
Some(_) => format!("-{}", digits),
159+
None => digits.to_string(),
160+
};
161+
i32::from_str(&s)
162+
}
163+
);
124164

125165
alt((
126166
map(float_parser, Expression::CReal),
@@ -129,91 +169,51 @@ fn parse_number(input: &str) -> IResult<&str, Expression> {
129169
}
130170

131171
fn parse_string(input: &str) -> IResult<&str, Expression> {
132-
map(delimited(
133-
multispace0,
172+
map(
134173
delimited(
135-
tag("\""),
136-
map(take_while(is_string_char), |s: &str| s.to_string()),
137-
tag("\""),
174+
multispace0,
175+
delimited(
176+
char::<&str, Error<&str>>('"'),
177+
map(take_while(is_string_char), |s: &str| s.to_string()),
178+
char::<&str, Error<&str>>('"'),
179+
),
180+
multispace0,
138181
),
139-
multispace0,
140-
), |s| Expression::CString(s))(input)
182+
|s| Expression::CString(s),
183+
)(input)
141184
}
142185

143186
fn parse_var(input: &str) -> IResult<&str, Expression> {
144-
map(parse_identifier, |v| Expression::Var(v.into()))(input)
187+
map(identifier, |v| Expression::Var(v.into()))(input)
145188
}
146-
fn parse_function_call(input: &str) -> IResult<&str, Expression> {
147-
let (input, name) = parse_identifier(input)?;
148-
let (input, _) = multispace0(input)?;
149-
let (input, _) = char('(')(input)?;
150-
let (input, args) = separated_list0(separator(","), parse_expression)(input)?;
151-
let (input, _) = multispace0(input)?;
152-
let (input, _) = char('(')(input)?;
153189

190+
fn parse_function_call(input: &str) -> IResult<&str, Expression> {
191+
let (input, name) = identifier(input)?;
192+
let (input, args) = parse_actual_arguments(input)?;
154193
Ok((input, Expression::FuncCall(name.to_string(), args)))
155194
}
156195

157-
158-
fn separator<'a>(sep: &'static str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> {
159-
delimited(multispace0, tag(sep), multispace0)
160-
}
161-
162-
163-
164-
/// Parses a reserved keyword (e.g., "if") surrounded by optional spaces
165-
/// Fails if followed by an identifier character
166-
fn keyword<'a>(kw: &'static str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> {
167-
terminated(
168-
delimited(multispace0, tag(kw), multispace0),
169-
not(peek(identifier_start_or_continue)),
170-
)
171-
}
172-
173-
/// Parsers for identifiers.
174-
fn parse_identifier(input: &str) -> IResult<&str, &str> {
175-
let (input, _) = multispace0(input)?;
176-
177-
let (input, first_char) = identifier_start(input)?;
178-
let (input, rest) = identifier_continue(input)?;
179-
180-
let ident = format!("{}{}", first_char, rest);
181-
182-
if KEYWORDS.contains(&ident.as_str()) {
183-
Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag)))
184-
} else {
185-
Ok((input, Box::leak(ident.into_boxed_str())))
186-
}
187-
}
188-
189-
/// First character of an identifier: [a-zA-Z_]
190-
fn identifier_start(input: &str) -> IResult<&str, &str> {
191-
alt((alpha1, tag("_")))(input)
192-
}
193-
194-
/// Remaining characters: [a-zA-Z0-9_]*
195-
fn identifier_continue(input: &str) -> IResult<&str, &str> {
196-
recognize(many0(identifier_start_or_continue))(input)
197-
}
198-
199-
/// A single identifier character: alphanumeric or underscore
200-
fn identifier_start_or_continue(input: &str) -> IResult<&str, &str> {
201-
recognize(alt((alpha1, tag("_"), nom::character::complete::digit1)))(input)
196+
pub fn parse_actual_arguments(input: &str) -> IResult<&str, Vec<Expression>> {
197+
map(
198+
tuple((
199+
multispace0,
200+
char::<&str, Error<&str>>('('),
201+
separated_list0(
202+
tuple((multispace0, char::<&str, Error<&str>>(','), multispace0)),
203+
parse_expression
204+
),
205+
multispace0,
206+
char::<&str, Error<&str>>(')')
207+
)),
208+
|(_, _, args, _, _)| args
209+
)(input)
202210
}
203211

204-
205212
/// Parses an operator.
206213
fn operator<'a>(op: &'static str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> {
207214
delimited(multispace0, tag(op), multispace0)
208215
}
209216

210-
211-
/// Accepts any character except '"' and control characters (like \n, \t)
212-
fn is_string_char(c: char) -> bool {
213-
c != '"' && !c.is_control()
214-
}
215-
216-
217217
#[cfg(test)]
218218
mod tests {
219219
use super::*;
@@ -243,11 +243,6 @@ mod tests {
243243
parse_expression("-0.001rest"),
244244
Ok(("rest", Expression::CReal(-0.001)))
245245
);
246-
247-
assert_eq!(
248-
parse_expression("2e3more"),
249-
Ok(("more", Expression::CReal(2000.0)))
250-
);
251246
}
252247

253248
#[test]
@@ -264,23 +259,21 @@ mod tests {
264259
fn test_keywords() {
265260
let cases = [
266261
("if", "if"),
267-
(" else ", "else"),
268-
("while rest", "while"),
269-
(" and ", "and"),
270-
("or)", "or"),
271-
("not x", "not"),
272-
(" for (", "for"),
273-
("def ", "def"),
262+
("else", "else"),
263+
("while", "while"),
264+
("and", "and"),
265+
("or", "or"),
266+
("not", "not"),
267+
("for", "for"),
268+
("def", "def"),
274269
];
275270

276271
for (input, expected) in cases {
277-
let mut parser = keyword(expected);
278-
let result = parser(input);
279-
assert_eq!(
280-
result,
281-
Ok((input[expected.len()..].trim_start(), expected)),
282-
"Failed to parse keyword '{}'", expected
283-
);
272+
let result = keyword(expected)(input);
273+
assert!(result.is_ok(), "Failed to parse keyword '{}'", expected);
274+
let (rest, parsed) = result.unwrap();
275+
assert_eq!(parsed, expected);
276+
assert!(rest.is_empty() || rest.starts_with(' '));
284277
}
285278
}
286279

@@ -296,4 +289,3 @@ mod tests {
296289
assert!(parser("origin").is_err());
297290
}
298291
}
299-

0 commit comments

Comments
 (0)
0