8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:03:02 +01:00

Added method's attribute "stub": makes it possible to have default trivial implementation for new methods in new versions of interfaces

This commit is contained in:
AlexPeshkoff 2024-01-11 13:21:19 +03:00
parent 314cb34358
commit 8b7ef73688
7 changed files with 134 additions and 74 deletions

View File

@ -94,39 +94,84 @@ void DefAction::generate(const ActionParametersBlock& apb, unsigned ident)
switch(apb.language)
{
case LANGUAGE_C:
if (!apb.statusName.empty())
if (!apb.method->statusName.empty())
{
identify(apb, ident);
fprintf(apb.out, "CLOOP_setVersionError(%s, \"%s%s\", cloopVTable->version, %d);\n",
apb.statusName.c_str(), apb.prefix.c_str(),
apb.method->statusName.c_str(), apb.prefix.c_str(),
apb.interface->name.c_str(), apb.method->version);
}
break;
case LANGUAGE_CPP:
if (!apb.statusName.empty())
if (!apb.method->statusName.empty())
{
identify(apb, ident);
fprintf(apb.out, "%s::setVersionError(%s, \"%s%s\", cloopVTable->version, %d);\n",
apb.exceptionClass.c_str(), apb.statusName.c_str(), apb.prefix.c_str(),
apb.exceptionClass.c_str(), apb.method->statusName.c_str(), apb.prefix.c_str(),
apb.interface->name.c_str(), apb.method->version);
identify(apb, ident);
fprintf(apb.out, "%s::checkException(%s);\n",
apb.exceptionClass.c_str(), apb.statusName.c_str());
apb.exceptionClass.c_str(), apb.method->statusName.c_str());
}
break;
case LANGUAGE_PASCAL:
if (!apb.statusName.empty() && !apb.exceptionClass.empty())
if (!apb.method->statusName.empty() && !apb.exceptionClass.empty())
{
identify(apb, ident);
fprintf(apb.out, "%s.setVersionError(%s, \'%s%s\', vTable.version, %d);\n",
apb.exceptionClass.c_str(), apb.statusName.c_str(), apb.prefix.c_str(),
apb.exceptionClass.c_str(), apb.method->statusName.c_str(), apb.prefix.c_str(),
apb.interface->name.c_str(), apb.method->version);
}
break;
}
break;
case DEF_IGNORE:
if (apb.method->returnTypeRef.token.type != Token::TYPE_VOID ||
apb.method->returnTypeRef.isPointer)
{
identify(apb, ident);
switch(apb.language)
{
case LANGUAGE_C:
case LANGUAGE_CPP:
fprintf(apb.out, "return 0;\n");
break;
case LANGUAGE_PASCAL:
{
const char* sResult = "nil";
if (!apb.method->returnTypeRef.isPointer)
{
switch (apb.method->returnTypeRef.token.type)
{
case Token::TYPE_STRING:
break;
case Token::TYPE_BOOLEAN:
sResult = "false";
break;
case Token::TYPE_IDENTIFIER:
if (apb.method->returnTypeRef.type == BaseType::TYPE_INTERFACE)
break;
// fallthru
default:
sResult = "0";
break;
}
}
fprintf(apb.out, "Result := %s;\n", sResult);
}
break;
}
}
break;
}
}

View File

@ -37,7 +37,6 @@ struct ActionParametersBlock
Language language;
const std::string& prefix;
const std::string& exceptionClass;
const std::string& statusName;
Interface* interface;
Method* method;
};
@ -91,7 +90,7 @@ public:
class DefAction : public Action
{
public:
enum DefType { DEF_NOT_IMPLEMENTED };
enum DefType { DEF_NOT_IMPLEMENTED, DEF_IGNORE };
DefAction(DefType dt)
: defType(dt)

View File

@ -357,15 +357,8 @@ void CppGenerator::generate()
fprintf(out, "\n\t\t");
string statusName;
if (!method->parameters.empty() &&
parser->exceptionInterface &&
method->parameters.front()->typeRef.token.text == parser->exceptionInterface->name)
{
statusName = method->parameters.front()->name;
if (!method->statusName.empty())
fprintf(out, "template <typename StatusType> ");
}
fprintf(out, "%s %s(",
convertType(method->returnTypeRef).c_str(), method->name.c_str());
@ -379,7 +372,7 @@ void CppGenerator::generate()
if (k != method->parameters.begin())
fprintf(out, ", ");
if (k == method->parameters.begin() && !statusName.empty())
if (k == method->parameters.begin() && !method->statusName.empty())
fprintf(out, "StatusType* %s", parameter->name.c_str());
else
{
@ -397,7 +390,7 @@ void CppGenerator::generate()
fprintf(out, "\t\t\t{\n");
const string exceptionClass("StatusType");
ActionParametersBlock apb = {out, LANGUAGE_CPP, prefix, exceptionClass, statusName, interface, method};
ActionParametersBlock apb = {out, LANGUAGE_CPP, prefix, exceptionClass, interface, method};
if (method->notImplementedAction)
method->notImplementedAction->generate(apb, 4);
@ -419,11 +412,11 @@ void CppGenerator::generate()
fprintf(out, "\t\t\t}\n");
}
if (!statusName.empty())
if (!method->statusName.empty())
{
fprintf(out, "\t\t\t");
fprintf(out, "StatusType::clearException(%s)", statusName.c_str());
fprintf(out, "StatusType::clearException(%s)", method->statusName.c_str());
fprintf(out, ";\n");
}
@ -694,7 +687,19 @@ void CppGenerator::generate()
}
}
fprintf(out, ")%s = 0;\n", (method->isConst ? " const" : ""));
fprintf(out, ")%s", (method->isConst ? " const" : ""));
if (method->stubAction)
{
const string exceptionClass("StatusType");
ActionParametersBlock apb = {out, LANGUAGE_CPP, prefix, exceptionClass, interface, method};
fprintf(out, "\n\t\t{\n");
method->stubAction->generate(apb, 3);
fprintf(out, "\t\t}\n");
}
else
fprintf(out, " = 0;\n");
}
fprintf(out, "\t};\n");
@ -1184,7 +1189,10 @@ void PascalGenerator::generate()
if (!isProcedure)
fprintf(out, ": %s", convertType(method->returnTypeRef).c_str());
fprintf(out, "; virtual; abstract;\n");
fprintf(out, "; virtual;");
if (!method->stubAction)
fprintf(out, " abstract;");
fprintf(out, "\n");
}
fprintf(out, "\tend;\n\n");
@ -1209,15 +1217,6 @@ void PascalGenerator::generate()
bool isProcedure = method->returnTypeRef.token.type == Token::TYPE_VOID &&
!method->returnTypeRef.isPointer;
string statusName;
if (!method->parameters.empty() &&
parser->exceptionInterface &&
method->parameters.front()->typeRef.token.text == parser->exceptionInterface->name)
{
statusName = method->parameters.front()->name;
}
fprintf(out, "%s %s.%s(",
(isProcedure ? "procedure" : "function"),
escapeName(interface->name, true).c_str(),
@ -1248,8 +1247,7 @@ void PascalGenerator::generate()
{
fprintf(out, "\tif (vTable.version < %d) then begin\n", method->version);
ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass,
statusName, interface, method};
ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass, interface, method};
if (method->notImplementedAction)
method->notImplementedAction->generate(apb, 2);
@ -1290,8 +1288,8 @@ void PascalGenerator::generate()
if (ident > 1)
fprintf(out, "\tend;\n");
if (!statusName.empty() && !exceptionClass.empty())
fprintf(out, "\t%s.checkException(%s);\n", exceptionClass.c_str(), escapeName(statusName).c_str());
if (!method->statusName.empty() && !exceptionClass.empty())
fprintf(out, "\t%s.checkException(%s);\n", exceptionClass.c_str(), escapeName(method->statusName).c_str());
fprintf(out, "end;\n\n");
}
@ -1315,6 +1313,8 @@ void PascalGenerator::generate()
bool isProcedure = method->returnTypeRef.token.type == Token::TYPE_VOID &&
!method->returnTypeRef.isPointer;
ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass, interface, method};
fprintf(out, "%s %sImpl_%sDispatcher(this: %s",
(isProcedure ? "procedure" : "function"),
escapeName(interface->name, true).c_str(),
@ -1337,39 +1337,7 @@ void PascalGenerator::generate()
fprintf(out, "; cdecl;\n");
fprintf(out, "begin\n");
if (!isProcedure)
{
if (method->returnTypeRef.isPointer) {
fprintf(out, "\tResult := nil;\n");
}
else
{
const char* sResult;
switch (method->returnTypeRef.token.type)
{
case Token::TYPE_STRING:
sResult = "nil";
break;
case Token::TYPE_BOOLEAN:
sResult = "false";
break;
case Token::TYPE_IDENTIFIER:
if (method->returnTypeRef.type == BaseType::TYPE_INTERFACE)
{
sResult = "nil";
break;
}
// fallthru
default:
sResult = "0";
break;
}
fprintf(out, "\tResult := %s;\n", sResult);
}
}
DefAction(DefAction::DEF_IGNORE).generate(apb, 1);
if (!exceptionClass.empty())
fprintf(out, "\ttry\n\t");
@ -1411,8 +1379,35 @@ void PascalGenerator::generate()
fprintf(out, "\tend\n");
}
fprintf(out, "end;\n\n");
if (method->stubAction)
{
fprintf(out, "%s %sImpl.%s(",
(isProcedure ? "procedure" : "function"),
escapeName(interface->name, true).c_str(),
escapeName(method->name).c_str());
for (vector<Parameter*>::iterator k = method->parameters.begin();
k != method->parameters.end();
++k)
{
Parameter* parameter = *k;
fprintf(out, "%s%s",
k == method->parameters.begin() ? "" : "; ",
convertParameter(*parameter).c_str());
}
fprintf(out, ")");
if (!isProcedure)
fprintf(out, ": %s", convertType(method->returnTypeRef).c_str());
fprintf(out, ";\n");
fprintf(out, "begin\n");
method->stubAction->generate(apb, 1);
fprintf(out, "end;\n\n");
}
}
fprintf(out, "var\n");

View File

@ -112,6 +112,8 @@ Token& Lexer::getToken(Token& token)
token.type = Token::TYPE_CALL;
else if (token.text == "defaultAction")
token.type = Token::TYPE_DEFAULT_ACTION;
else if (token.text == "stub")
token.type = Token::TYPE_STUB;
// types
else if (token.text == "void")
token.type = Token::TYPE_VOID;

View File

@ -47,6 +47,7 @@ struct Token
TYPE_INTERFACE,
TYPE_NOT_IMPLEMENTED,
TYPE_NOT_IMPLEMENTED_ACTION,
TYPE_STUB,
TYPE_STRUCT,
TYPE_TYPEDEF,
TYPE_VERSION,

View File

@ -94,7 +94,7 @@ void Parser::parse()
}
}
// Check types.
// Check types, assign statusName to methods.
for (vector<Interface*>::iterator i = interfaces.begin(); i != interfaces.end(); ++i)
{
@ -115,6 +115,13 @@ void Parser::parse()
Parameter* parameter = *k;
checkType(parameter->typeRef);
}
if (!method->parameters.empty() &&
exceptionInterface &&
method->parameters.front()->typeRef.token.text == exceptionInterface->name)
{
method->statusName = method->parameters.front()->name;
}
}
}
}
@ -194,6 +201,7 @@ void Parser::parseItem()
{
Expr* notImplementedExpr = nullptr;
Action* notImplementedAction = nullptr;
Action* stubAction = nullptr;
std::string onError;
while (lexer->getToken(token).type == TOKEN('['))
@ -224,6 +232,12 @@ void Parser::parseItem()
notImplementedAction = parseAction(DefAction::DEF_NOT_IMPLEMENTED);
break;
case Token::TYPE_STUB:
if (stubAction)
syntaxError(token);
stubAction = parseAction(DefAction::DEF_IGNORE);
break;
default:
syntaxError(token);
break;
@ -248,7 +262,7 @@ void Parser::parseItem()
}
getToken(token, TOKEN('('));
parseMethod(typeRef, name, notImplementedExpr, onError, notImplementedAction);
parseMethod(typeRef, name, notImplementedExpr, onError, notImplementedAction, stubAction);
}
void Parser::parseConstant(const TypeRef& typeRef, const string& name)
@ -326,7 +340,7 @@ Action* Parser::parseDefAction(DefAction::DefType dt)
}
void Parser::parseMethod(const TypeRef& returnTypeRef, const string& name, Expr* notImplementedExpr,
const string& onError, Action* notImplementedAction)
const string& onError, Action* notImplementedAction, Action* stubAction)
{
Method* method = new Method();
interface->methods.push_back(method);
@ -336,6 +350,7 @@ void Parser::parseMethod(const TypeRef& returnTypeRef, const string& name, Expr*
method->version = interface->version;
method->notImplementedExpr = notImplementedExpr;
method->notImplementedAction = notImplementedAction;
method->stubAction = stubAction;
method->onErrorFunction = onError;
if (lexer->getToken(token).type != TOKEN(')'))

View File

@ -101,6 +101,7 @@ public:
Method()
: notImplementedExpr(NULL),
notImplementedAction(NULL),
stubAction(NULL),
version(0),
isConst(false)
{
@ -111,9 +112,11 @@ public:
std::vector<Parameter*> parameters;
Expr* notImplementedExpr;
Action* notImplementedAction;
Action* stubAction;
unsigned version;
bool isConst;
std::string onErrorFunction;
std::string statusName;
};
@ -178,7 +181,7 @@ public:
void parseItem();
void parseConstant(const TypeRef& typeRef, const std::string& name);
void parseMethod(const TypeRef& returnTypeRef, const std::string& name, Expr* notImplementedExpr,
const std::string& onErrorFunction, Action* notImplementedAction);
const std::string& onErrorFunction, Action* notImplementedAction, Action* stubAction);
Expr* parseExpr();
Expr* parseLogicalExpr();