SAWYER_EXPORT std::string Grammar::evalFunction(TokenStream &tokens, ErrorLocation &eloc) const { ASSERT_require(tokens.isa(TOK_FUNCTION)); std::string funcName = tokens.lexeme(); ASSERT_require(funcName.size() >= 2 && '@' == funcName[0]); funcName = funcName.substr(1); tokens.consume(); // Get the function declaration const Function::Ptr func = functions_.getOrDefault(funcName); if (!func) throw SyntaxError("function \"" + funcName + "\" is not declared"); // Parse the actual arguments std::vector<std::string> actuals; while (tokens.isa(TOK_LEFT)) { tokens.consume(); if (func->isMacro()) { actuals.push_back(readArgument(tokens, eloc, CONSUME)); } else { actuals.push_back(evalArgument(tokens, eloc, CONSUME)); } } func->validateArgs(actuals, tokens); ErrorLocation::Trap t(eloc, tokens, "in function \"" + funcName + "\""); std::string retval = func->eval(*this, actuals); t.passed(); return retval; }
SAWYER_EXPORT std::string Grammar::evalArgument(TokenStream &tokens, ErrorLocation &eloc, bool requireRight) const { std::string retval, data; size_t depth = 0; while (!tokens.atEof()) { if (tokens.isa(TOK_LEFT)) { ++depth; retval += tokens.lexeme(); tokens.consume(); } else if (tokens.isa(TOK_RIGHT)) { if (0 == depth) break; --depth; retval += tokens.lexeme(); tokens.consume(); } else if (tokens.isa(TOK_FUNCTION)) { retval += evalFunction(tokens, eloc); } else { retval += tokens.lexeme(); tokens.consume(); } } if (requireRight) { if (!tokens.isa(TOK_RIGHT)) throw SyntaxError("end-of-argument expected"); tokens.consume(); } if (depth > 0) throw SyntaxError("expected end-of-argument marker"); return retval; }
SAWYER_EXPORT std::string Grammar::eval(TokenStream &tokens, ErrorLocation &eloc) const { std::string retval; while (!tokens.atEof()) { retval += evalArgument(tokens, eloc, LEAVE); if (tokens.isa(TOK_RIGHT)) throw SyntaxError("unexpected end-of-argument"); } return retval; }
SAWYER_EXPORT std::string Grammar::readArgument(TokenStream &tokens, ErrorLocation &eloc, bool requireRight) const { std::string retval; size_t depth = 0; for (/*void*/; !tokens.atEof(); tokens.consume()) { if (tokens.isa(TOK_LEFT)) { ++depth; } else if (tokens.isa(TOK_RIGHT)) { if (0 == depth) break; --depth; } retval += tokens.lexeme(); } if (requireRight) { if (!tokens.isa(TOK_RIGHT)) throw SyntaxError("end-of-argument expected"); tokens.consume(); } if (depth > 0) throw SyntaxError("expected end-of-argument marker"); return retval; }