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) switch(apb.language)
{ {
case LANGUAGE_C: case LANGUAGE_C:
if (!apb.statusName.empty()) if (!apb.method->statusName.empty())
{ {
identify(apb, ident); identify(apb, ident);
fprintf(apb.out, "CLOOP_setVersionError(%s, \"%s%s\", cloopVTable->version, %d);\n", 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); apb.interface->name.c_str(), apb.method->version);
} }
break; break;
case LANGUAGE_CPP: case LANGUAGE_CPP:
if (!apb.statusName.empty()) if (!apb.method->statusName.empty())
{ {
identify(apb, ident); identify(apb, ident);
fprintf(apb.out, "%s::setVersionError(%s, \"%s%s\", cloopVTable->version, %d);\n", 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); apb.interface->name.c_str(), apb.method->version);
identify(apb, ident); identify(apb, ident);
fprintf(apb.out, "%s::checkException(%s);\n", 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; break;
case LANGUAGE_PASCAL: case LANGUAGE_PASCAL:
if (!apb.statusName.empty() && !apb.exceptionClass.empty()) if (!apb.method->statusName.empty() && !apb.exceptionClass.empty())
{ {
identify(apb, ident); identify(apb, ident);
fprintf(apb.out, "%s.setVersionError(%s, \'%s%s\', vTable.version, %d);\n", 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); apb.interface->name.c_str(), apb.method->version);
} }
break; break;
} }
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; Language language;
const std::string& prefix; const std::string& prefix;
const std::string& exceptionClass; const std::string& exceptionClass;
const std::string& statusName;
Interface* interface; Interface* interface;
Method* method; Method* method;
}; };
@ -91,7 +90,7 @@ public:
class DefAction : public Action class DefAction : public Action
{ {
public: public:
enum DefType { DEF_NOT_IMPLEMENTED }; enum DefType { DEF_NOT_IMPLEMENTED, DEF_IGNORE };
DefAction(DefType dt) DefAction(DefType dt)
: defType(dt) : defType(dt)

View File

@ -357,15 +357,8 @@ void CppGenerator::generate()
fprintf(out, "\n\t\t"); fprintf(out, "\n\t\t");
string statusName; if (!method->statusName.empty())
if (!method->parameters.empty() &&
parser->exceptionInterface &&
method->parameters.front()->typeRef.token.text == parser->exceptionInterface->name)
{
statusName = method->parameters.front()->name;
fprintf(out, "template <typename StatusType> "); fprintf(out, "template <typename StatusType> ");
}
fprintf(out, "%s %s(", fprintf(out, "%s %s(",
convertType(method->returnTypeRef).c_str(), method->name.c_str()); convertType(method->returnTypeRef).c_str(), method->name.c_str());
@ -379,7 +372,7 @@ void CppGenerator::generate()
if (k != method->parameters.begin()) if (k != method->parameters.begin())
fprintf(out, ", "); 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()); fprintf(out, "StatusType* %s", parameter->name.c_str());
else else
{ {
@ -397,7 +390,7 @@ void CppGenerator::generate()
fprintf(out, "\t\t\t{\n"); fprintf(out, "\t\t\t{\n");
const string exceptionClass("StatusType"); 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) if (method->notImplementedAction)
method->notImplementedAction->generate(apb, 4); method->notImplementedAction->generate(apb, 4);
@ -419,11 +412,11 @@ void CppGenerator::generate()
fprintf(out, "\t\t\t}\n"); fprintf(out, "\t\t\t}\n");
} }
if (!statusName.empty()) if (!method->statusName.empty())
{ {
fprintf(out, "\t\t\t"); 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"); 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"); fprintf(out, "\t};\n");
@ -1184,7 +1189,10 @@ void PascalGenerator::generate()
if (!isProcedure) if (!isProcedure)
fprintf(out, ": %s", convertType(method->returnTypeRef).c_str()); 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"); fprintf(out, "\tend;\n\n");
@ -1209,15 +1217,6 @@ void PascalGenerator::generate()
bool isProcedure = method->returnTypeRef.token.type == Token::TYPE_VOID && bool isProcedure = method->returnTypeRef.token.type == Token::TYPE_VOID &&
!method->returnTypeRef.isPointer; !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(", fprintf(out, "%s %s.%s(",
(isProcedure ? "procedure" : "function"), (isProcedure ? "procedure" : "function"),
escapeName(interface->name, true).c_str(), escapeName(interface->name, true).c_str(),
@ -1248,8 +1247,7 @@ void PascalGenerator::generate()
{ {
fprintf(out, "\tif (vTable.version < %d) then begin\n", method->version); fprintf(out, "\tif (vTable.version < %d) then begin\n", method->version);
ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass, ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass, interface, method};
statusName, interface, method};
if (method->notImplementedAction) if (method->notImplementedAction)
method->notImplementedAction->generate(apb, 2); method->notImplementedAction->generate(apb, 2);
@ -1290,8 +1288,8 @@ void PascalGenerator::generate()
if (ident > 1) if (ident > 1)
fprintf(out, "\tend;\n"); fprintf(out, "\tend;\n");
if (!statusName.empty() && !exceptionClass.empty()) if (!method->statusName.empty() && !exceptionClass.empty())
fprintf(out, "\t%s.checkException(%s);\n", exceptionClass.c_str(), escapeName(statusName).c_str()); fprintf(out, "\t%s.checkException(%s);\n", exceptionClass.c_str(), escapeName(method->statusName).c_str());
fprintf(out, "end;\n\n"); fprintf(out, "end;\n\n");
} }
@ -1315,6 +1313,8 @@ void PascalGenerator::generate()
bool isProcedure = method->returnTypeRef.token.type == Token::TYPE_VOID && bool isProcedure = method->returnTypeRef.token.type == Token::TYPE_VOID &&
!method->returnTypeRef.isPointer; !method->returnTypeRef.isPointer;
ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass, interface, method};
fprintf(out, "%s %sImpl_%sDispatcher(this: %s", fprintf(out, "%s %sImpl_%sDispatcher(this: %s",
(isProcedure ? "procedure" : "function"), (isProcedure ? "procedure" : "function"),
escapeName(interface->name, true).c_str(), escapeName(interface->name, true).c_str(),
@ -1337,39 +1337,7 @@ void PascalGenerator::generate()
fprintf(out, "; cdecl;\n"); fprintf(out, "; cdecl;\n");
fprintf(out, "begin\n"); fprintf(out, "begin\n");
DefAction(DefAction::DEF_IGNORE).generate(apb, 1);
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);
}
}
if (!exceptionClass.empty()) if (!exceptionClass.empty())
fprintf(out, "\ttry\n\t"); fprintf(out, "\ttry\n\t");
@ -1411,8 +1379,35 @@ void PascalGenerator::generate()
fprintf(out, "\tend\n"); fprintf(out, "\tend\n");
} }
fprintf(out, "end;\n\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"); fprintf(out, "var\n");

View File

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

View File

@ -47,6 +47,7 @@ struct Token
TYPE_INTERFACE, TYPE_INTERFACE,
TYPE_NOT_IMPLEMENTED, TYPE_NOT_IMPLEMENTED,
TYPE_NOT_IMPLEMENTED_ACTION, TYPE_NOT_IMPLEMENTED_ACTION,
TYPE_STUB,
TYPE_STRUCT, TYPE_STRUCT,
TYPE_TYPEDEF, TYPE_TYPEDEF,
TYPE_VERSION, 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) for (vector<Interface*>::iterator i = interfaces.begin(); i != interfaces.end(); ++i)
{ {
@ -115,6 +115,13 @@ void Parser::parse()
Parameter* parameter = *k; Parameter* parameter = *k;
checkType(parameter->typeRef); 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; Expr* notImplementedExpr = nullptr;
Action* notImplementedAction = nullptr; Action* notImplementedAction = nullptr;
Action* stubAction = nullptr;
std::string onError; std::string onError;
while (lexer->getToken(token).type == TOKEN('[')) while (lexer->getToken(token).type == TOKEN('['))
@ -224,6 +232,12 @@ void Parser::parseItem()
notImplementedAction = parseAction(DefAction::DEF_NOT_IMPLEMENTED); notImplementedAction = parseAction(DefAction::DEF_NOT_IMPLEMENTED);
break; break;
case Token::TYPE_STUB:
if (stubAction)
syntaxError(token);
stubAction = parseAction(DefAction::DEF_IGNORE);
break;
default: default:
syntaxError(token); syntaxError(token);
break; break;
@ -248,7 +262,7 @@ void Parser::parseItem()
} }
getToken(token, TOKEN('(')); 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) 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, 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(); Method* method = new Method();
interface->methods.push_back(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->version = interface->version;
method->notImplementedExpr = notImplementedExpr; method->notImplementedExpr = notImplementedExpr;
method->notImplementedAction = notImplementedAction; method->notImplementedAction = notImplementedAction;
method->stubAction = stubAction;
method->onErrorFunction = onError; method->onErrorFunction = onError;
if (lexer->getToken(token).type != TOKEN(')')) if (lexer->getToken(token).type != TOKEN(')'))

View File

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