Skip to content

Commit fc2aca4

Browse files
committed
[feature] Introduce syntax and parser rules for simple 'for' statements.
1 parent 8148814 commit fc2aca4

File tree

2 files changed

+67
-32
lines changed

2 files changed

+67
-32
lines changed

src/ir/ast.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ impl<A> TestEnvironment<A> {
144144
};
145145
}
146146
}
147+
147148
#[derive(Clone, Debug, PartialEq)]
148149
pub enum Type {
149150
TInteger,
@@ -219,9 +220,10 @@ pub enum Expression {
219220
pub enum Statement {
220221
VarDeclaration(Name),
221222
ValDeclaration(Name),
222-
Assignment(Name, Box<Expression>, Option<Type>),
223+
Assignment(Name, Box<Expression>),
223224
IfThenElse(Box<Expression>, Box<Statement>, Option<Box<Statement>>),
224225
While(Box<Expression>, Box<Statement>),
226+
For(Name, Box<Expression>, Box<Statement>),
225227
Block(Vec<Statement>),
226228
Sequence(Box<Statement>, Box<Statement>),
227229
AssertTrue(Box<Expression>, String),

src/parser/parser.rs

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ type ParseResult<'a, T> = IResult<&'a str, T, Error<&'a str>>;
1313

1414
const KEYWORDS: &[&str] = &[
1515
"if",
16+
"in",
1617
"else",
1718
"def",
1819
"while",
20+
"for",
1921
"val",
2022
"var",
2123
"return",
@@ -101,6 +103,7 @@ fn statement(input: &str) -> IResult<&str, Statement> {
101103
alt((
102104
function_def,
103105
if_statement,
106+
for_statement,
104107
return_statement,
105108
assignment,
106109
declaration,
@@ -421,6 +424,29 @@ fn if_statement(input: &str) -> IResult<&str, Statement> {
421424
))
422425
}
423426

427+
// A 'for' statement parser.
428+
// A basic 'for' statement in Python has the following
429+
// syntax:
430+
//
431+
// > for <var> in <exp>:
432+
// > <stmt>
433+
fn for_statement(input: &str) -> IResult<&str, Statement> {
434+
let (input, _) = tag("for")(input)?;
435+
let (input, _) = space1(input)?;
436+
let (input, var) = identifier(input)?;
437+
let (input, _) = space1(input)?;
438+
let (input, _) = tag("in")(input)?;
439+
let (input, _) = space1(input)?;
440+
let (input, exp) = expression(input)?;
441+
let (input, _) = space0(input)?;
442+
let (input, _) = char(':')(input)?;
443+
let (input, block) = indented_block(input)?;
444+
Ok((
445+
input,
446+
Statement::For(var, Box::new(exp), Box::new(Statement::Block(block))),
447+
))
448+
}
449+
424450
fn declaration(input: &str) -> IResult<&str, Statement> {
425451
let (input, keyword) = alt((tag("var"), tag("val")))(input)?;
426452
let (input, _) = space1(input)?;
@@ -442,19 +468,7 @@ fn assignment(input: &str) -> IResult<&str, Statement> {
442468
let (input, _) = delimited(space0, char('='), space0)(input)?;
443469
let (input, expr) = expression(input)?;
444470

445-
// Infer type from expression
446-
let inferred_type = match &expr {
447-
Expression::CInt(_) => Some(Type::TInteger),
448-
Expression::CReal(_) => Some(Type::TReal),
449-
Expression::CString(_) => Some(Type::TString),
450-
Expression::CTrue | Expression::CFalse => Some(Type::TBool),
451-
_ => None,
452-
};
453-
454-
Ok((
455-
input,
456-
Statement::Assignment(name, Box::new(expr), inferred_type),
457-
))
471+
Ok((input, Statement::Assignment(name, Box::new(expr))))
458472
}
459473

460474
fn parse_type(type_name: &str) -> Type {
@@ -647,7 +661,7 @@ mod tests {
647661
let (rest, stmt) = assignment(input).unwrap();
648662
assert_eq!(rest, "");
649663
match stmt {
650-
Statement::Assignment(name, expr, _type) => {
664+
Statement::Assignment(name, expr) => {
651665
// Added _type
652666
assert_eq!(name, "x");
653667
match *expr {
@@ -674,7 +688,7 @@ mod tests {
674688
assert_eq!(rest, "");
675689

676690
match &stmts[0] {
677-
Statement::Assignment(name, expr, _type) => {
691+
Statement::Assignment(name, expr) => {
678692
// Added _type
679693
assert_eq!(name, "x");
680694
match **expr {
@@ -695,7 +709,7 @@ mod tests {
695709

696710
// Verify first statement is assignment
697711
match &stmts[0] {
698-
Statement::Assignment(name, expr, _type) => {
712+
Statement::Assignment(name, expr) => {
699713
// Added _type
700714
assert_eq!(name, "x");
701715
assert!(matches!(**expr, Expression::CInt(10)));
@@ -714,7 +728,7 @@ mod tests {
714728
Statement::Block(ref stmts) => {
715729
assert_eq!(stmts.len(), 1);
716730
match &stmts[0] {
717-
Statement::Assignment(name, expr, _type) => {
731+
Statement::Assignment(name, expr) => {
718732
assert_eq!(name, "y");
719733
assert!(matches!(**expr, Expression::CInt(1)));
720734
}
@@ -730,7 +744,7 @@ mod tests {
730744
Statement::Block(ref stmts) => {
731745
assert_eq!(stmts.len(), 1);
732746
match &stmts[0] {
733-
Statement::Assignment(name, expr, _type) => {
747+
Statement::Assignment(name, expr) => {
734748
assert_eq!(name, "y");
735749
assert!(matches!(**expr, Expression::CInt(2)));
736750
}
@@ -762,7 +776,7 @@ mod tests {
762776
Statement::Block(ref stmts) => {
763777
assert_eq!(stmts.len(), 1);
764778
match &stmts[0] {
765-
Statement::Assignment(name, expr, _type) => {
779+
Statement::Assignment(name, expr) => {
766780
assert_eq!(name, "y");
767781
assert!(matches!(**expr, Expression::CInt(1)));
768782
}
@@ -778,7 +792,7 @@ mod tests {
778792
Statement::Block(ref stmts) => {
779793
assert_eq!(stmts.len(), 1);
780794
match &stmts[0] {
781-
Statement::Assignment(name, expr, _type) => {
795+
Statement::Assignment(name, expr) => {
782796
assert_eq!(name, "y");
783797
assert!(matches!(**expr, Expression::CInt(2)));
784798
}
@@ -813,7 +827,7 @@ mod tests {
813827
Statement::Block(ref stmts) => {
814828
assert_eq!(stmts.len(), 1);
815829
match &stmts[0] {
816-
Statement::Assignment(name, expr, _type) => {
830+
Statement::Assignment(name, expr) => {
817831
assert_eq!(name, "y");
818832
assert!(matches!(**expr, Expression::CInt(1)));
819833
}
@@ -829,7 +843,7 @@ mod tests {
829843
Statement::Block(ref stmts) => {
830844
assert_eq!(stmts.len(), 1);
831845
match &stmts[0] {
832-
Statement::Assignment(name, expr, _type) => {
846+
Statement::Assignment(name, expr) => {
833847
assert_eq!(name, "y");
834848
assert!(matches!(**expr, Expression::CInt(2)));
835849
}
@@ -845,6 +859,28 @@ mod tests {
845859
}
846860
}
847861

862+
#[test]
863+
fn test_for_statement() {
864+
let input = "for x in range:\n x = x+1";
865+
let (rest, stmt) = statement(input).unwrap();
866+
let expected = Statement::For(
867+
"x".to_string(),
868+
Box::new(Expression::Var("range".to_string())),
869+
Box::new(Statement::Block(
870+
[Statement::Assignment(
871+
"x".to_string(),
872+
Box::new(Expression::Add(
873+
Box::new(Expression::Var("x".to_string())),
874+
Box::new(Expression::CInt(1)),
875+
)),
876+
)]
877+
.to_vec(),
878+
)),
879+
);
880+
assert_eq!(rest, "");
881+
assert_eq!(stmt, expected)
882+
}
883+
848884
#[test]
849885
fn test_multiline_parse() {
850886
let input = "x = 42\ny = 10";
@@ -853,7 +889,7 @@ mod tests {
853889
assert_eq!(stmts.len(), 2);
854890

855891
match &stmts[0] {
856-
Statement::Assignment(name, expr, _type) => {
892+
Statement::Assignment(name, expr) => {
857893
assert_eq!(&**name, "x");
858894
match **expr {
859895
Expression::CInt(42) => (),
@@ -864,7 +900,7 @@ mod tests {
864900
}
865901

866902
match &stmts[1] {
867-
Statement::Assignment(name, expr, _type) => {
903+
Statement::Assignment(name, expr) => {
868904
assert_eq!(&**name, "y");
869905
match **expr {
870906
Expression::CInt(10) => (),
@@ -921,7 +957,7 @@ mod tests {
921957
let (rest, stmt) = assignment(input).unwrap();
922958
assert_eq!(rest, "");
923959
match stmt {
924-
Statement::Assignment(name, expr, _type) => {
960+
Statement::Assignment(name, expr) => {
925961
assert_eq!(name, "result");
926962
match *expr {
927963
Expression::FuncCall(func_name, args) => {
@@ -1326,17 +1362,15 @@ mod tests {
13261362
[
13271363
Statement::Assignment(
13281364
String::from("x"),
1329-
Box::new(Expression::COk(Box::new(Expression::CTrue))),
1330-
None
1365+
Box::new(Expression::COk(Box::new(Expression::CTrue)))
13311366
),
13321367
Statement::IfThenElse(
13331368
Box::new(Expression::Unwrap(Box::new(Expression::Var(String::from(
13341369
"x"
13351370
))))),
13361371
Box::new(Statement::Block(vec![Statement::Assignment(
13371372
String::from("y"),
1338-
Box::new(Expression::CInt(1)),
1339-
Some(Type::TInteger)
1373+
Box::new(Expression::CInt(1))
13401374
)])),
13411375
None
13421376
),
@@ -1346,8 +1380,7 @@ mod tests {
13461380
)))),
13471381
Box::new(Statement::Block(vec![Statement::Assignment(
13481382
String::from("y"),
1349-
Box::new(Expression::CInt(1)),
1350-
Some(Type::TInteger)
1383+
Box::new(Expression::CInt(1))
13511384
)])),
13521385
None
13531386
)

0 commit comments

Comments
 (0)