std::wstring VdfParser::ResolveFqId(const wchar_t * const id, bool is_type_id, Tokens& tokens) const { vector<wstring> matching_fq_ids; assert(_variables); wstring search_namespace = _current_namespace; for (;;) { wstring fq_id = search_namespace.empty() ? id : (search_namespace + L"::" + id); if (IdExists(fq_id.c_str(), is_type_id)) { matching_fq_ids.push_back(fq_id); break; } else if (search_namespace.empty()) { break; } else { search_namespace = OuterNamespace(search_namespace); } } for (auto name_space : _namespace_in_use) { assert(!name_space.empty()); wstring fq_id = name_space + L"::" + id; if (IdExists(fq_id.c_str(), is_type_id)) { matching_fq_ids.push_back(fq_id); } } if (matching_fq_ids.empty()) { throw CompileError(tokens.GetCurrentToken(), CompileErrorTypeNotFound, wstring(L"Type not found: ") + id); } else if (matching_fq_ids.size() > 1) { wstring error_message = L"Ambiguous ID: "; error_message += id; error_message += L". Could be: \n"; for (auto fq_id : matching_fq_ids) { error_message += (fq_id + L"\n"); } throw CompileError(tokens.GetCurrentToken(), CompileErrorAmbiguousId, error_message); } return matching_fq_ids[0]; }
bool VdfParser::ProcessStatement(Tokens& tokens) { while (!tokens.AtEnd()) { switch (tokens.GetCurrentToken().type) { case TokenKeywordBool: case TokenKeywordInt: case TokenKeywordFloat: case TokenKeywordString: ProcessSimpleDeclaration(tokens); break; case TokenId: ProcessSimpleDeclaration(tokens); break; case TokenKeywordArray: ProcessArrayDeclaration(tokens, *_variables); break; case TokenKeywordStruct: ProcessStructDeclaration(tokens); break; case TokenKeywordEnum: ProcessEnumDeclaration(tokens); break; case TokenKeywordNamespace: ProcessNamespace(tokens); break; case TokenKeywordUsing: ProcessUsing(tokens); break; case TokenSemiColon: tokens.FinishProcessingStatement(); break; case TokenRightBrace: // This function maybe called when the processing iterator is pointing to // the beginning of a tokens, which maybe hosted in a namespace. // If current tokens is enclosed in a namespace, then the right brace // means the end of namespace. if (_current_namespace.empty()) { throw CompileError(tokens.GetCurrentToken(), CompileErrorTypeExpected, L"Unexpected \'}\'"); } else return true; default: throw(CompileError(tokens.GetCurrentToken(), CompileErrorTypeExpected, L"Expected one of float, int, string, bool, array, struct.")); } } return true; }
bool VdfParser::ProcessArrayDeclaration(Tokens& tokens, VariableSpace& variables) { static map<TokenType, int> token_to_array_property{ {TokenKeywordFloat, VariableFloatArray}, {TokenKeywordInt, VariableIntArray}, {TokenKeywordString, VariableStringArray}, {TokenKeywordBool, VariableBoolArray}, {TokenId, VariableStructArray}, }; tokens.AssertToken(TokenKeywordArray, true); tokens.AssertToken(TokenLessThan, true); auto type = tokens.GetCurrentToken().type; auto element_type_id = tokens.GetCurrentToken().text; auto fq_type_id = ResolveFqId(element_type_id.c_str(), true, tokens); assert(type == TokenKeywordFloat || type == TokenKeywordInt || type == TokenKeywordBool || type == TokenKeywordString || type == TokenId); tokens.Next(); tokens.AssertToken(TokenGreaterThan, true); auto id = (&variables == _variables.get()) ? GetFqId(tokens.GetId().c_str()) : tokens.GetId(); if (!tokens.IsTokenOfType(TokenSharp, true)) { variables.AddArray(fq_type_id.c_str(), id.c_str(), L""); } else { tokens.AssertToken(TokenLessThan, true); auto start_index = _wtoi(tokens.GetLiteralValue().c_str()); tokens.AssertToken(TokenComma, true); auto end_index = _wtoi(tokens.GetLiteralValue().c_str()); tokens.AssertToken(TokenGreaterThan, true); for (int i = start_index; i <= end_index; ++i) { wostringstream output; output << id << i; auto variable_id = (&variables == _variables.get()) ? GetFqId(output.str().c_str()) : output.str(); variables.AddArray(fq_type_id.c_str(), variable_id.c_str(), L""); } } tokens.AssertToken(TokenSemiColon, true); return true; }
bool VdfParser::ProcessSimpleDeclaration(Tokens& tokens) { assert(_variables); auto type = tokens.GetCurrentToken().type; auto type_id = tokens.GetCurrentToken().text; assert(type == TokenKeywordFloat || type == TokenKeywordInt || type == TokenKeywordBool || type == TokenKeywordString || type == TokenId); tokens.Next(); auto id = tokens.GetId(); auto fq_type_id = ResolveFqId(type_id.c_str(), true, tokens); if (!tokens.IsTokenOfType(TokenSharp, true)) { _variables->Add(fq_type_id.c_str(), GetFqId(id.c_str()).c_str(), L""); } else { tokens.AssertToken(TokenLessThan, true); auto start_index = boost::lexical_cast<int>(tokens.GetLiteralValue()); tokens.AssertToken(TokenComma, true); auto end_index = boost::lexical_cast<int>(tokens.GetLiteralValue()); tokens.AssertToken(TokenGreaterThan, true); for (int i = start_index; i <= end_index; ++i) { wostringstream output; output << id << i; wstring variable_id = GetFqId(output.str().c_str()); _variables->Add(fq_type_id.c_str(), variable_id.c_str(), L""); } } tokens.AssertToken(TokenSemiColon, true); return true; }
bool VdfParser::ProcessStructDeclaration(Tokens& tokens) { tokens.AssertToken(TokenKeywordStruct, true); auto struct_id = GetFqId(tokens.GetId().c_str()); tokens.AssertToken(TokenLeftBrace, true); VariableSpace struct_variables; static std::set<TokenType> s_allowed_types = { TokenKeywordBool, TokenKeywordFloat, TokenKeywordInt, TokenKeywordString, TokenKeywordArray, TokenId }; do { auto& type_token = tokens.GetCurrentToken(); if (s_allowed_types.find(type_token.type) == s_allowed_types.end()) { throw(CompileError(type_token, CompileErrorTypeExpected, L"Expected either one of float, int, string, bool, array, or a struct name.")); } if (type_token.type == TokenKeywordArray) { ProcessArrayDeclaration(tokens, struct_variables); } else { auto type_id = ResolveFqId(type_token.text.c_str(), true, tokens); if (type_token.type == TokenId) { if (!_variables->TypeExists(type_id.c_str())) throw CompileError(type_token, CompileErrorTypeNotFound, L"Type not found."); if (type_token.text == struct_id) throw CompileError(type_token, CompileErrorNestStruct, L"Nested struct definition not allowed."); } tokens.Next(); auto& member_token = tokens.GetCurrentToken(); if (struct_variables.VariableExists(member_token.text.c_str())) throw CompileError(type_token, CompileErrorMemeberExists, L"Duplicated struct member ids."); auto prototype = _variables->GetType(type_id.c_str()); if (prototype == nullptr) throw CompileError(type_token, CompileErrorTypeNotFound, L"Type not found."); auto member = dynamic_cast<IVariable*>(prototype->Clone()); assert(member != nullptr); member->SetId(member_token.text.c_str()); struct_variables.Add(member); tokens.Next(); tokens.AssertToken(TokenSemiColon, true); } } while (!tokens.IsTokenOfType(TokenRightBrace, false)); tokens.Next(); tokens.AssertToken(TokenSemiColon, true); _variables->AddType(struct_id.c_str(), struct_variables.Variables()); return true; }