diff --git a/src/dreamchecker/lib.rs b/src/dreamchecker/lib.rs index 80d768d9..c0a10dbe 100644 --- a/src/dreamchecker/lib.rs +++ b/src/dreamchecker/lib.rs @@ -1366,6 +1366,12 @@ impl<'o, 's> AnalyzeProc<'o, 's> { allterm.finalize(); return allterm }, + Statement::ForInfinite { block } => { + let mut scoped_locals = local_vars.clone(); + let mut state = self.visit_block(block, &mut scoped_locals); + state.end_loop(); + return state + } Statement::ForLoop { init, test, inc, block } => { let mut scoped_locals = local_vars.clone(); if let Some(init) = init { diff --git a/src/dreamchecker/tests/branch_eval_tests.rs b/src/dreamchecker/tests/branch_eval_tests.rs index e7ee1a6d..7e085331 100644 --- a/src/dreamchecker/tests/branch_eval_tests.rs +++ b/src/dreamchecker/tests/branch_eval_tests.rs @@ -74,15 +74,17 @@ fn do_while() { } pub const FOR_LOOP_CONDITION_ERRORS: &[(u32, u16, &str)] = &[ - (2, 5, "loop condition is always true"), - (2, 5, "control flow condition is a static term"), - (4, 5, "control flow condition is a constant evalutation"), + (4, 5, "loop condition is always true"), + (4, 5, "control flow condition is a static term"), + (6, 5, "control flow condition is a constant evalutation"), ]; #[test] fn for_loop_condition() { let code = r##" /proc/test() + for() + break for(var/x = 0; 1; x++) break for(var/y = 0; 5 <= 7; y++) diff --git a/src/dreammaker/ast.rs b/src/dreammaker/ast.rs index 7cf059f2..4ab84e60 100644 --- a/src/dreammaker/ast.rs +++ b/src/dreammaker/ast.rs @@ -1028,6 +1028,9 @@ pub enum Statement { arms: Vec<(Spanned, Block)>, else_arm: Option }, + ForInfinite { + block: Block, + }, ForLoop { init: Option>, test: Option>, diff --git a/src/dreammaker/parser.rs b/src/dreammaker/parser.rs index c24bd43b..b0edee5c 100644 --- a/src/dreammaker/parser.rs +++ b/src/dreammaker/parser.rs @@ -268,6 +268,7 @@ impl TTKind { #[derive(Debug)] enum LoopContext { None, + ForInfinite, ForLoop, ForList, ForRange, @@ -1241,6 +1242,7 @@ impl<'ctx, 'an, 'inp> Parser<'ctx, 'an, 'inp> { require!(self.statement_terminator()); spanned(Statement::DoWhile { block, condition }) } else if let Some(()) = self.exact_ident("for")? { + // for () // for (Var [as Type] [in List]) Statement // for (Init, Test, Inc) Statement // for (Var in Low to High) @@ -1353,7 +1355,10 @@ impl<'ctx, 'an, 'inp> Parser<'ctx, 'an, 'inp> { block: require!(self.block(&LoopContext::ForList)), }) } else { - Err(self.error("for-in-list must start with variable")) + require!(self.exact(Token::Punct(Punctuation::RParen))); + spanned(Statement::ForInfinite { + block: require!(self.block(&LoopContext::ForInfinite)), + }) } } else if let Some(()) = self.exact_ident("spawn")? { let expr; diff --git a/src/langserver/find_references.rs b/src/langserver/find_references.rs index 0964f10c..e4bc990c 100644 --- a/src/langserver/find_references.rs +++ b/src/langserver/find_references.rs @@ -237,6 +237,9 @@ impl<'o> WalkProc<'o> { self.visit_block(else_arm); } }, + Statement::ForInfinite { block } => { + self.visit_block(block); + } Statement::ForLoop { init, test, inc, block } => { if let Some(init) = init { self.visit_statement(location, init);