Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) { String name; Error err = _parse_type_full_name(name); if (err) return err; Token tk = get_token(); if (tk == TK_COMMA) { err = _parse_class_base(r_base); if (err) return err; } else if (tk == TK_IDENTIFIER && String(value) == "where") { err = _parse_type_constraints(); if (err) { return err; } // An open curly bracket was parsed by _parse_type_constraints, so we can exit } else if (tk == TK_CURLY_BRACKET_OPEN) { // we are finished when we hit the open curly bracket } else { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } r_base.push_back(name); return OK; }
Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) { String name; Error err = _parse_type_full_name(name); if (err) return err; Token tk = get_token(); bool generic = false; if (tk == TK_OP_LESS) { Error err = _skip_generic_type_params(); if (err) return err; // We don't add it to the base list if it's generic generic = true; tk = get_token(); } if (tk == TK_COMMA) { Error err = _parse_class_base(r_base); if (err) return err; } else if (tk == TK_IDENTIFIER && String(value) == "where") { Error err = _parse_type_constraints(); if (err) { return err; } // An open curly bracket was parsed by _parse_type_constraints, so we can exit } else if (tk == TK_CURLY_BRACKET_OPEN) { // we are finished when we hit the open curly bracket } else { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } if (!generic) { r_base.push_back(name); } return OK; }
Error ScriptClassParser::parse(const String &p_code) { code = p_code; idx = 0; line = 0; error_str = String(); error = false; value = Variant(); classes.clear(); Token tk = get_token(); Map<int, NameDecl> name_stack; int curly_stack = 0; int type_curly_stack = 0; while (!error && tk != TK_EOF) { if (tk == TK_IDENTIFIER && String(value) == "class") { tk = get_token(); if (tk == TK_IDENTIFIER) { String name = value; int at_level = type_curly_stack; ClassDecl class_decl; for (Map<int, NameDecl>::Element *E = name_stack.front(); E; E = E->next()) { const NameDecl &name_decl = E->value(); if (name_decl.type == NameDecl::NAMESPACE_DECL) { if (E != name_stack.front()) class_decl.namespace_ += "."; class_decl.namespace_ += name_decl.name; } else { class_decl.name += name_decl.name + "."; } } class_decl.name += name; class_decl.nested = type_curly_stack > 0; bool generic = false; while (true) { tk = get_token(); if (tk == TK_COLON) { Error err = _parse_class_base(class_decl.base); if (err) return err; curly_stack++; type_curly_stack++; break; } else if (tk == TK_CURLY_BRACKET_OPEN) { curly_stack++; type_curly_stack++; break; } else if (tk == TK_OP_LESS && !generic) { generic = true; Error err = _skip_generic_type_params(); if (err) return err; } else if (tk == TK_IDENTIFIER && String(value) == "where") { Error err = _parse_type_constraints(); if (err) { return err; } // An open curly bracket was parsed by _parse_type_constraints, so we can exit curly_stack++; type_curly_stack++; break; } else { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } NameDecl name_decl; name_decl.name = name; name_decl.type = NameDecl::CLASS_DECL; name_stack[at_level] = name_decl; if (!generic) { // no generics, thanks classes.push_back(class_decl); } else if (OS::get_singleton()->is_stdout_verbose()) { String full_name = class_decl.namespace_; if (full_name.length()) full_name += "."; full_name += class_decl.name; OS::get_singleton()->print("%s", String("Ignoring generic class declaration: " + class_decl.name).utf8().get_data()); } } } else if (tk == TK_IDENTIFIER && String(value) == "struct") { String name; int at_level = type_curly_stack; while (true) { tk = get_token(); if (tk == TK_IDENTIFIER && name.empty()) { name = String(value); } else if (tk == TK_CURLY_BRACKET_OPEN) { if (name.empty()) { error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword `struct`, found " + get_token_name(TK_CURLY_BRACKET_OPEN); error = true; return ERR_PARSE_ERROR; } curly_stack++; type_curly_stack++; break; } else if (tk == TK_EOF) { error_str = "Expected " + get_token_name(TK_CURLY_BRACKET_OPEN) + " after struct decl, found " + get_token_name(TK_EOF); error = true; return ERR_PARSE_ERROR; } } NameDecl name_decl; name_decl.name = name; name_decl.type = NameDecl::STRUCT_DECL; name_stack[at_level] = name_decl; } else if (tk == TK_IDENTIFIER && String(value) == "namespace") { if (type_curly_stack > 0) { error_str = "Found namespace nested inside type."; error = true; return ERR_PARSE_ERROR; } String name; int at_level = curly_stack; Error err = _parse_namespace_name(name, curly_stack); if (err) return err; NameDecl name_decl; name_decl.name = name; name_decl.type = NameDecl::NAMESPACE_DECL; name_stack[at_level] = name_decl; } else if (tk == TK_CURLY_BRACKET_OPEN) { curly_stack++; } else if (tk == TK_CURLY_BRACKET_CLOSE) { curly_stack--; if (name_stack.has(curly_stack)) { if (name_stack[curly_stack].type != NameDecl::NAMESPACE_DECL) type_curly_stack--; name_stack.erase(curly_stack); } } tk = get_token(); } if (!error && tk == TK_EOF && curly_stack > 0) { error_str = "Reached EOF with missing close curly brackets."; error = true; } if (error) return ERR_PARSE_ERROR; return OK; }
Error ScriptClassParser::_parse_type_constraints() { Token tk = get_token(); if (tk != TK_IDENTIFIER) { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } tk = get_token(); if (tk != TK_COLON) { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } while (true) { tk = get_token(); if (tk == TK_IDENTIFIER) { if (String(value) == "where") { return _parse_type_constraints(); } tk = get_token(); if (tk == TK_PERIOD) { while (true) { tk = get_token(); if (tk != TK_IDENTIFIER) { error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } tk = get_token(); if (tk != TK_PERIOD) break; } } } if (tk == TK_COMMA) { continue; } else if (tk == TK_IDENTIFIER && String(value) == "where") { return _parse_type_constraints(); } else if (tk == TK_SYMBOL && String(value) == "(") { tk = get_token(); if (tk != TK_SYMBOL || String(value) != ")") { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } else if (tk == TK_OP_LESS) { Error err = _skip_generic_type_params(); if (err) return err; } else if (tk == TK_CURLY_BRACKET_OPEN) { return OK; } else { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } }