| 2201 | } |
| 2202 | |
| 2203 | GDScriptParser::ForNode *GDScriptParser::parse_for() { |
| 2204 | ForNode *n_for = alloc_node<ForNode>(); |
| 2205 | |
| 2206 | if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected loop variable name after "for".)")) { |
| 2207 | n_for->variable = parse_identifier(); |
| 2208 | } |
| 2209 | |
| 2210 | if (match(GDScriptTokenizer::Token::COLON)) { |
| 2211 | n_for->datatype_specifier = parse_type(); |
| 2212 | if (n_for->datatype_specifier == nullptr) { |
| 2213 | push_error(R"(Expected type specifier after ":".)"); |
| 2214 | } |
| 2215 | } |
| 2216 | |
| 2217 | if (n_for->datatype_specifier == nullptr) { |
| 2218 | consume(GDScriptTokenizer::Token::TK_IN, R"(Expected "in" or ":" after "for" variable name.)"); |
| 2219 | } else { |
| 2220 | consume(GDScriptTokenizer::Token::TK_IN, R"(Expected "in" after "for" variable type specifier.)"); |
| 2221 | } |
| 2222 | |
| 2223 | n_for->list = parse_expression(false); |
| 2224 | |
| 2225 | if (!n_for->list) { |
| 2226 | push_error(R"(Expected iterable after "in".)"); |
| 2227 | } |
| 2228 | |
| 2229 | consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "for" condition.)"); |
| 2230 | |
| 2231 | // Save break/continue state. |
| 2232 | bool could_break = can_break; |
| 2233 | bool could_continue = can_continue; |
| 2234 | |
| 2235 | // Allow break/continue. |
| 2236 | can_break = true; |
| 2237 | can_continue = true; |
| 2238 | |
| 2239 | SuiteNode *suite = alloc_node<SuiteNode>(); |
| 2240 | if (n_for->variable) { |
| 2241 | const SuiteNode::Local &local = current_suite->get_local(n_for->variable->name); |
| 2242 | if (local.type != SuiteNode::Local::UNDEFINED) { |
| 2243 | push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", local.get_name(), n_for->variable->name), n_for->variable); |
| 2244 | } |
| 2245 | suite->add_local(SuiteNode::Local(n_for->variable, current_function)); |
| 2246 | } |
| 2247 | suite->is_in_loop = true; |
| 2248 | n_for->loop = parse_suite(R"("for" block)", suite); |
| 2249 | complete_extents(n_for); |
| 2250 | |
| 2251 | // Reset break/continue state. |
| 2252 | can_break = could_break; |
| 2253 | can_continue = could_continue; |
| 2254 | |
| 2255 | return n_for; |
| 2256 | } |
| 2257 | |
| 2258 | GDScriptParser::IfNode *GDScriptParser::parse_if(const String &p_token) { |
| 2259 | IfNode *n_if = alloc_node<IfNode>(); |