summaryrefslogtreecommitdiffstats
path: root/unoidl/source/sourceprovider-parser.y
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--unoidl/source/sourceprovider-parser.y4476
1 files changed, 4476 insertions, 0 deletions
diff --git a/unoidl/source/sourceprovider-parser.y b/unoidl/source/sourceprovider-parser.y
new file mode 100644
index 000000000..abe17e355
--- /dev/null
+++ b/unoidl/source/sourceprovider-parser.y
@@ -0,0 +1,4476 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*TODO: check Exception, RuntimeException, XInterface defns */
+
+%locations
+%pure-parser
+
+%{
+
+#include <sal/config.h>
+
+#include <o3tl/unreachable.hxx>
+#include <o3tl/string_view.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <unoidl/unoidl.hxx>
+
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstddef>
+#include <cstdlib>
+#include <limits>
+#include <new>
+#include <utility>
+#include <vector>
+
+#include "sourceprovider-parser-requires.hxx"
+
+%}
+
+%union {
+ sal_uInt64 ival;
+ double fval;
+ OString * sval;
+
+ bool bval;
+ std::vector<OUString> * excns;
+ unoidl::detail::SourceProviderAccessDecls decls;
+ unoidl::InterfaceTypeEntity::Method::Parameter::Direction dir;
+ unoidl::detail::SourceProviderFlags flags;
+ unoidl::detail::SourceProviderExpr expr;
+ unoidl::detail::SourceProviderType * type;
+ std::vector<unoidl::detail::SourceProviderType> * types;
+}
+
+/* TODO: %destructor { delete $$; } <sval> <excns> <type> <types> */
+
+%lex-param {yyscan_t yyscanner}
+%parse-param {yyscan_t yyscanner}
+
+%{
+
+#include <osl/file.h>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+
+#include "sourceprovider-scanner.hxx"
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { (Current) = YYRHSLOC((Rhs), (N) ? 1 : 0); } while (0)
+
+static void yyerror(YYLTYPE * locp, yyscan_t yyscanner, char const * msg) {
+ assert(locp != nullptr);
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->errorLine = *locp;
+ data->parserError = OString(msg);
+}
+
+namespace {
+
+void error(YYLTYPE location, yyscan_t yyscanner, OUString const & message) {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->errorLine = location;
+ data->errorMessage = message;
+}
+
+OUString flagName(unoidl::detail::SourceProviderFlags flag) {
+ switch (flag) {
+ case unoidl::detail::FLAG_ATTRIBUTE:
+ return "attribute";
+ case unoidl::detail::FLAG_BOUND:
+ return "bound";
+ case unoidl::detail::FLAG_CONSTRAINED:
+ return "constrained";
+ case unoidl::detail::FLAG_MAYBEAMBIGUOUS:
+ return "maybeambiguous";
+ case unoidl::detail::FLAG_MAYBEDEFAULT:
+ return "maybedefault";
+ case unoidl::detail::FLAG_MAYBEVOID:
+ return "maybevoid";
+ case unoidl::detail::FLAG_OPTIONAL:
+ return "optional";
+ case unoidl::detail::FLAG_PROPERTY:
+ return "property";
+ case unoidl::detail::FLAG_READONLY:
+ return "readonly";
+ case unoidl::detail::FLAG_REMOVABLE:
+ return "removable";
+ case unoidl::detail::FLAG_TRANSIENT:
+ return "transient";
+ default:
+ assert(false && "this cannot happen"); for (;;) { std::abort(); }
+ }
+}
+
+OUString convertName(OString const * name) {
+ assert(name != nullptr);
+ OUString s(OStringToOUString(*name, RTL_TEXTENCODING_ASCII_US));
+ delete name;
+ return s;
+}
+
+OUString convertToFullName(
+ unoidl::detail::SourceProviderScannerData const * data,
+ OString const * identifier)
+{
+ assert(data != nullptr);
+ OUString pref;
+ if (!data->modules.empty()) {
+ pref = data->modules.back() + ".";
+ }
+ return pref + convertName(identifier);
+}
+
+void convertToCurrentName(
+ unoidl::detail::SourceProviderScannerData * data,
+ OString const * identifier)
+{
+ assert(data != nullptr);
+ assert(data->currentName.isEmpty());
+ data->currentName = convertToFullName(data, identifier);
+ assert(!data->currentName.isEmpty());
+}
+
+void clearCurrentState(unoidl::detail::SourceProviderScannerData * data) {
+ assert(data != nullptr);
+ data->currentName.clear();
+ data->publishedContext = false;
+}
+
+unoidl::detail::SourceProviderEntity * getCurrentEntity(
+ unoidl::detail::SourceProviderScannerData * data)
+{
+ assert(data != nullptr);
+ assert(!data->currentName.isEmpty());
+ std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator i(
+ data->entities.find(data->currentName));
+ assert(i != data->entities.end());
+ assert(i->second.kind == unoidl::detail::SourceProviderEntity::KIND_LOCAL);
+ assert(i->second.pad.is());
+ return &i->second;
+}
+
+template<typename T> rtl::Reference<T> getCurrentPad(
+ unoidl::detail::SourceProviderScannerData * data)
+{
+ rtl::Reference<T> pad(dynamic_cast<T *>(getCurrentEntity(data)->pad.get()));
+ assert(pad.is());
+ return pad;
+}
+
+bool nameHasSameIdentifierAs(std::u16string_view name, std::u16string_view identifier)
+{
+ size_t i = name.rfind('.') + 1;
+ return identifier.size() == name.size() - i
+ && o3tl::starts_with(name.substr(i), identifier);
+}
+
+bool coerce(
+ YYLTYPE location, yyscan_t yyscanner,
+ unoidl::detail::SourceProviderExpr * lhs,
+ unoidl::detail::SourceProviderExpr * rhs)
+{
+ assert(lhs != nullptr);
+ assert(rhs != nullptr);
+ bool ok = bool(); // avoid warnings
+ switch (lhs->type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ ok = rhs->type != unoidl::detail::SourceProviderExpr::TYPE_BOOL;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ switch (rhs->type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ ok = false;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ ok = true;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if (lhs->ival >= 0) {
+ lhs->type = unoidl::detail::SourceProviderExpr::TYPE_UINT;
+ ok = true;
+ } else if (rhs->uval <= SAL_MAX_INT64) {
+ rhs->type = unoidl::detail::SourceProviderExpr::TYPE_INT;
+ ok = true;
+ } else {
+ ok = false;
+ }
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ {
+ auto tmp = lhs->ival;
+ lhs->fval = tmp;
+ ok = true;
+ }
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ switch (rhs->type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ ok = false;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if (rhs->ival >= 0) {
+ rhs->type = unoidl::detail::SourceProviderExpr::TYPE_UINT;
+ ok = true;
+ } else if (lhs->uval <= SAL_MAX_INT64) {
+ lhs->type = unoidl::detail::SourceProviderExpr::TYPE_INT;
+ ok = true;
+ } else {
+ ok = false;
+ }
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ ok = true;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ {
+ auto nTmp = lhs->uval;
+ lhs->fval = nTmp;
+ ok = true;
+ }
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ switch (rhs->type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ ok = false;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ {
+ auto tmp = rhs->ival;
+ rhs->fval = tmp;
+ ok = true;
+ }
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ {
+ auto tmp = rhs->uval;
+ rhs->fval = tmp;
+ ok = true;
+ }
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ ok = true;
+ break;
+ }
+ break;
+ }
+ if (!ok) {
+ error(location, yyscanner, "cannot coerce binary expression arguments");
+ }
+ return ok;
+}
+
+unoidl::detail::SourceProviderEntity * findEntity_(
+ unoidl::detail::SourceProviderScannerData * data, OUString * name)
+{
+ assert(data != nullptr);
+ assert(name != nullptr);
+ OUString n;
+ if (!name->startsWith(".", &n)) {
+ for (auto i(data->modules.rbegin()); i != data->modules.rend(); ++i) {
+ n = *i + "." + *name;
+ std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator j(
+ data->entities.find(n));
+ if (j != data->entities.end()) {
+ *name = n;
+ return &j->second;
+ }
+ rtl::Reference<unoidl::Entity> ent(data->manager->findEntity(n));
+ if (ent.is()) {
+ std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator
+ k(data->entities.emplace(
+ n,
+ unoidl::detail::SourceProviderEntity(
+ unoidl::detail::SourceProviderEntity::KIND_EXTERNAL,
+ ent)).
+ first);
+ *name = n;
+ return &k->second;
+ }
+ }
+ n = *name;
+ }
+ std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator i(
+ data->entities.find(n));
+ if (i != data->entities.end()) {
+ *name = n;
+ return &i->second;
+ }
+ rtl::Reference<unoidl::Entity> ent(data->manager->findEntity(n));
+ if (ent.is()) {
+ std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator
+ j(data->entities.emplace(
+ n,
+ unoidl::detail::SourceProviderEntity(
+ unoidl::detail::SourceProviderEntity::KIND_EXTERNAL,
+ ent)).
+ first);
+ *name = n;
+ return &j->second;
+ }
+ return nullptr;
+}
+
+enum Found { FOUND_ERROR, FOUND_TYPE, FOUND_ENTITY };
+
+Found findEntity(
+ YYLTYPE location, yyscan_t yyscanner,
+ unoidl::detail::SourceProviderScannerData * data,
+ bool resolveInterfaceDefinitions, OUString * name,
+ unoidl::detail::SourceProviderEntity const ** entity, bool * typedefed,
+ unoidl::detail::SourceProviderType * typedefedType)
+{
+ //TODO: avoid recursion
+ assert(data != nullptr);
+ assert(name != nullptr);
+ assert(entity != nullptr);
+ unoidl::detail::SourceProviderEntity * e = findEntity_(data, name);
+ OUString n(*name);
+ OUString typeNucleus;
+ std::size_t rank = 0;
+ std::vector<unoidl::detail::SourceProviderType> args;
+ for (;;) {
+ if (e != nullptr) {
+ switch (e->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
+ if (e->pad.is()) {
+ break;
+ }
+ assert(e->entity.is());
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
+ if (e->entity->getSort() == unoidl::Entity::SORT_TYPEDEF) {
+ if (typedefed != nullptr) {
+ *typedefed = true;
+ }
+ if (data->publishedContext
+ && !static_cast<unoidl::TypedefEntity *>(
+ e->entity.get())->isPublished())
+ {
+ error(
+ location, yyscanner,
+ ("type " + *name + " based on unpublished typedef "
+ + n + " used in published context"));
+ return FOUND_ERROR;
+ }
+ OUString t(
+ static_cast<unoidl::TypedefEntity *>(e->entity.get())
+ ->getType());
+ typeNucleus = t;
+ while (typeNucleus.startsWith("[]", &typeNucleus)) {
+ if (!args.empty()) {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: bad type " + *name
+ + (" based on instantiated polymorphic struct"
+ " type based on sequence type named ")
+ + t));
+ return FOUND_ERROR;
+ }
+ if (rank == std::numeric_limits<std::size_t>::max()) {
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + " based on sequence type of too high rank"));
+ return FOUND_ERROR;
+ }
+ ++rank;
+ }
+ sal_Int32 i = typeNucleus.indexOf('<');
+ if (i != -1) {
+ if (!args.empty()) {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: bad type " + *name
+ + (" based on instantiated polymorphic struct"
+ " type based on instantiated polymorphic"
+ " struct type named ")
+ + t));
+ return FOUND_ERROR;
+ }
+ std::u16string_view tmpl(typeNucleus.subView(0, i));
+ do {
+ ++i; // skip '<' or ','
+ sal_Int32 j = i;
+ for (sal_Int32 level = 0;
+ j != typeNucleus.getLength(); ++j)
+ {
+ sal_Unicode c = typeNucleus[j];
+ if (c == ',') {
+ if (level == 0) {
+ break;
+ }
+ } else if (c == '<') {
+ ++level;
+ } else if (c == '>') {
+ if (level == 0) {
+ break;
+ }
+ --level;
+ }
+ }
+ if (j != typeNucleus.getLength()) {
+ OUString argName(typeNucleus.copy(i, j - i));
+ unoidl::detail::SourceProviderEntity const *
+ argEnt;
+ unoidl::detail::SourceProviderType argType;
+ switch (
+ findEntity(
+ location, yyscanner, data, false,
+ &argName, &argEnt, nullptr, &argType))
+ {
+ case FOUND_ERROR:
+ return FOUND_ERROR;
+ case FOUND_TYPE:
+ break;
+ case FOUND_ENTITY:
+ if (argEnt == nullptr) {
+ error(
+ location, yyscanner,
+ (("inconsistent type manager: bad"
+ " instantiated polymorphic struct"
+ " type template type argument ")
+ + argName));
+ return FOUND_ERROR;
+ } else {
+ unoidl::detail::SourceProviderType::Type
+ argT
+ = unoidl::detail::SourceProviderType::Type();
+ // avoid warnings
+ switch (argEnt->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
+ if (e->pad.is()) {
+ error(
+ location, yyscanner,
+ (("inconsistent type"
+ " manager: bad"
+ " instantiated"
+ " polymorphic struct type"
+ " template type"
+ " argument ")
+ + argName));
+ return FOUND_ERROR;
+ }
+ assert(e->entity.is());
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
+ switch (e->entity->getSort()) {
+ case unoidl::Entity::SORT_ENUM_TYPE:
+ argT = unoidl::detail::SourceProviderType::TYPE_ENUM;
+ break;
+ case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
+ argT = unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT;
+ break;
+ case unoidl::Entity::SORT_INTERFACE_TYPE:
+ argT = unoidl::detail::SourceProviderType::TYPE_INTERFACE;
+ break;
+ default:
+ error(
+ location, yyscanner,
+ (("inconsistent type"
+ "manager: bad"
+ " instantiated"
+ " polymorphic struct type"
+ " template type"
+ " argument ")
+ + argName));
+ return FOUND_ERROR;
+ }
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ argT = unoidl::detail::SourceProviderType::TYPE_INTERFACE;
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_MODULE:
+ assert(false && "this cannot happen");
+ }
+ argType
+ = unoidl::detail::SourceProviderType(
+ argT, argName, argEnt);
+ }
+ break;
+ }
+ args.push_back(argType);
+ }
+ i = j;
+ } while (i != typeNucleus.getLength()
+ && typeNucleus[i] != '>');
+ if (i != typeNucleus.getLength() - 1
+ || typeNucleus[i] != '>')
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: bad type name \""
+ + t + "\""));
+ return FOUND_ERROR;
+ }
+ assert(!args.empty());
+ typeNucleus = tmpl;
+ }
+ if (typeNucleus.isEmpty()) {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: bad type name \"" + t
+ + "\""));
+ return FOUND_ERROR;
+ }
+ if (typeNucleus == "void") {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: bad type " + *name
+ + " based on void"));
+ return FOUND_ERROR;
+ }
+ if (typeNucleus == "boolean" || typeNucleus == "byte"
+ || typeNucleus == "short"
+ || typeNucleus == "unsigned short"
+ || typeNucleus == "long"
+ || typeNucleus == "unsigned long"
+ || typeNucleus == "hyper"
+ || typeNucleus == "unsigned hyper"
+ || typeNucleus == "float" || typeNucleus == "double"
+ || typeNucleus == "char" || typeNucleus == "string"
+ || typeNucleus == "type" || typeNucleus == "any")
+ {
+ if (!args.empty()) {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: bad type " + *name
+ + (" based on instantiated polymorphic struct"
+ " type based on ")
+ + typeNucleus));
+ return FOUND_ERROR;
+ }
+ break;
+ }
+ n = "." + typeNucleus;
+ typeNucleus.clear();
+ e = findEntity_(data, &n);
+ continue;
+ }
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ if (resolveInterfaceDefinitions) {
+ rtl::Reference<unoidl::Entity> ent(
+ data->manager->findEntity(n));
+ // Do not allow ent to be of SORT_TYPEDEF:
+ if (!ent.is()
+ || (ent->getSort()
+ != unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ error(
+ location, yyscanner,
+ (*name + " is based on interface declaration " + n
+ + " that is not an interface type entity"));
+ return FOUND_ERROR;
+ }
+ e->kind
+ = unoidl::detail::SourceProviderEntity::KIND_EXTERNAL;
+ e->entity = ent;
+ }
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_MODULE:
+ error(
+ location, yyscanner,
+ *name + " is based on module entity " + n);
+ return FOUND_ERROR;
+ }
+ }
+ if (!typeNucleus.isEmpty() || rank != 0 || !args.empty()) {
+ if (typeNucleus.isEmpty() && e == nullptr) {
+ // Found a type name based on an unknown entity:
+ *entity = nullptr;
+ return FOUND_ENTITY;
+ }
+ unoidl::detail::SourceProviderType t;
+ if (args.empty()) {
+ if (typeNucleus == "boolean") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_BOOLEAN);
+ } else if (typeNucleus == "byte") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_BYTE);
+ } else if (typeNucleus == "short") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_SHORT);
+ } else if (typeNucleus == "unsigned short") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_UNSIGNED_SHORT);
+ } else if (typeNucleus == "long") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_LONG);
+ } else if (typeNucleus == "unsigned long") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_UNSIGNED_LONG);
+ } else if (typeNucleus == "hyper") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_HYPER);
+ } else if (typeNucleus == "unsigned hyper") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_UNSIGNED_HYPER);
+ } else if (typeNucleus == "float") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_FLOAT);
+ } else if (typeNucleus == "double") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_DOUBLE);
+ } else if (typeNucleus == "char") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_CHAR);
+ } else if (typeNucleus == "string") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_STRING);
+ } else if (typeNucleus == "type") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_TYPE);
+ } else if (typeNucleus == "any") {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_ANY);
+ } else {
+ assert(typeNucleus.isEmpty());
+ assert(e != nullptr);
+ switch (e->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
+ if (e->pad.is()) {
+ if (dynamic_cast<unoidl::detail::SourceProviderEnumTypeEntityPad *>(
+ e->pad.get())
+ != nullptr)
+ {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_ENUM,
+ n, e);
+ } else if (dynamic_cast<unoidl::detail::SourceProviderPlainStructTypeEntityPad *>(
+ e->pad.get())
+ != nullptr)
+ {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT,
+ n, e);
+ } else if (dynamic_cast<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
+ e->pad.get())
+ != nullptr)
+ {
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + (" based on recursive reference to"
+ " polymorphic struct type template ")
+ + n));
+ return FOUND_ERROR;
+ } else if (dynamic_cast<unoidl::detail::SourceProviderExceptionTypeEntityPad *>(
+ e->pad.get())
+ != nullptr)
+ {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_EXCEPTION,
+ n, e);
+ } else if (dynamic_cast<unoidl::detail::SourceProviderInterfaceTypeEntityPad *>(
+ e->pad.get())
+ != nullptr)
+ {
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_INTERFACE,
+ n, e);
+ } else {
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + " based on non-type entity " + n));
+ return FOUND_ERROR;
+ }
+ break;
+ }
+ assert(e->entity.is());
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
+ switch (e->entity->getSort()) {
+ case unoidl::Entity::SORT_ENUM_TYPE:
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_ENUM,
+ n, e);
+ break;
+ case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT,
+ n, e);
+ break;
+ case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + " based on polymorphic struct type template "
+ + n + " without type arguments"));
+ return FOUND_ERROR;
+ case unoidl::Entity::SORT_EXCEPTION_TYPE:
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_EXCEPTION,
+ n, e);
+ break;
+ case unoidl::Entity::SORT_INTERFACE_TYPE:
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_INTERFACE,
+ n, e);
+ break;
+ default:
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + " based on non-type entity " + n));
+ return FOUND_ERROR;
+ }
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ t = unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_INTERFACE,
+ n, e);
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_MODULE:
+ assert(false && "this cannot happen");
+ }
+ }
+ } else {
+ assert(typeNucleus.isEmpty());
+ assert(e != nullptr);
+ switch (e->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
+ if (e->pad.is()) {
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + (" based on instantiated polymorphic struct type"
+ " based on ")
+ + n
+ + (" that is either not a polymorphic struct type"
+ " template or a recursive reference to a"
+ " polymorphic struct type template")));
+ return FOUND_ERROR;
+ }
+ assert(e->entity.is());
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
+ if (e->entity->getSort()
+ == unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE)
+ {
+ if (args.size()
+ != (static_cast<
+ unoidl::PolymorphicStructTypeTemplateEntity *>(
+ e->entity.get())
+ ->getTypeParameters().size()))
+ {
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + (" based on instantiated polymorphic struct"
+ " type with ")
+ + OUString::number(args.size())
+ + (" type arguments based on polymorphic"
+ " struct type template ")
+ + n + " with "
+ + OUString::number(
+ static_cast<
+ unoidl::PolymorphicStructTypeTemplateEntity *>(
+ e->entity.get())
+ ->getTypeParameters().size())
+ + " type parameters"));
+ return FOUND_ERROR;
+ }
+ t = unoidl::detail::SourceProviderType(n, e, std::move(args));
+ break;
+ }
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ error(
+ location, yyscanner,
+ ("bad type " + *name
+ + (" based on instantiated polymorphic struct type"
+ " based on ")
+ + n
+ + " that is not a polymorphic struct type template"));
+ return FOUND_ERROR;
+ case unoidl::detail::SourceProviderEntity::KIND_MODULE:
+ assert(false && "this cannot happen");
+ }
+ }
+ if (typedefedType != nullptr) {
+ for (std::size_t i = 0; i != rank; ++i) {
+ t = unoidl::detail::SourceProviderType(&t);
+ }
+ *typedefedType = t;
+ typedefedType->typedefName = *name;
+ }
+ *entity = nullptr;
+ return FOUND_TYPE;
+ }
+ *entity = e;
+ return FOUND_ENTITY;
+ }
+}
+
+
+bool checkTypeArgument(
+ YYLTYPE location, yyscan_t yyscanner,
+ unoidl::detail::SourceProviderType const & type)
+{
+ switch (type.type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_SHORT:
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_LONG:
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_HYPER:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ case unoidl::detail::SourceProviderType::TYPE_PARAMETER: //TODO?
+ error(
+ location, yyscanner,
+ "bad instantiated polymorphic struct type argument");
+ return false;
+ case unoidl::detail::SourceProviderType::TYPE_SEQUENCE:
+ return checkTypeArgument(location, yyscanner, type.subtypes.front());
+ default:
+ return true;
+ }
+}
+
+bool checkInstantiatedPolymorphicStructTypeArgument(
+ unoidl::detail::SourceProviderType const & type, OUString const & name)
+{
+ if (type.type
+ == unoidl::detail::SourceProviderType::TYPE_INSTANTIATED_POLYMORPHIC_STRUCT)
+ {
+ for (auto & i: type.subtypes) {
+ if (checkInstantiatedPolymorphicStructTypeArgument(i, name)
+ || i.getName() == name) // no need to worry about typedef
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+std::vector<OUString> annotations(bool deprecated) {
+ std::vector<OUString> ann;
+ if (deprecated) {
+ ann.push_back("deprecated");
+ }
+ return ann;
+}
+
+}
+
+%}
+
+%token TOK_ELLIPSIS
+%token TOK_COLONS
+%token TOK_LEFTSHIFT
+%token TOK_RIGHTSHIFT
+
+%token TOK_FALSE
+%token TOK_TRUE
+%token TOK_ANY
+%token TOK_ATTRIBUTE
+%token TOK_BOOLEAN
+%token TOK_BOUND
+%token TOK_BYTE
+%token TOK_CHAR
+%token TOK_CONST
+%token TOK_CONSTANTS
+%token TOK_CONSTRAINED
+%token TOK_DOUBLE
+%token TOK_ENUM
+%token TOK_EXCEPTION
+%token TOK_FLOAT
+%token TOK_GET
+%token TOK_HYPER
+%token TOK_IN
+%token TOK_INOUT
+%token TOK_INTERFACE
+%token TOK_LONG
+%token TOK_MAYBEAMBIGUOUS
+%token TOK_MAYBEDEFAULT
+%token TOK_MAYBEVOID
+%token TOK_MODULE
+%token TOK_OPTIONAL
+%token TOK_OUT
+%token TOK_PROPERTY
+%token TOK_PUBLISHED
+%token TOK_RAISES
+%token TOK_READONLY
+%token TOK_REMOVABLE
+%token TOK_SEQUENCE
+%token TOK_SERVICE
+%token TOK_SET
+%token TOK_SHORT
+%token TOK_SINGLETON
+%token TOK_STRING
+%token TOK_STRUCT
+%token TOK_TRANSIENT
+%token TOK_TYPE
+%token TOK_TYPEDEF
+%token TOK_UNSIGNED
+%token TOK_VOID
+
+%token<sval> TOK_IDENTIFIER
+%token<ival> TOK_INTEGER
+%token<fval> TOK_FLOATING
+
+%token TOK_DEPRECATED
+
+%token TOK_ERROR
+
+%type<sval> identifier name singleInheritance singleInheritance_opt
+%type<bval> ctors_opt deprecated_opt ellipsis_opt published_opt
+%type<decls> attributeAccessDecl attributeAccessDecls
+%type<dir> direction
+%type<excns> exceptionSpec exceptionSpec_opt exceptions
+%type<flags> flag flagSection flagSection_opt flags
+%type<expr> addExpr andExpr expr multExpr orExpr primaryExpr shiftExpr unaryExpr
+ xorExpr
+%type<type> type
+%type<types> typeArguments
+
+%initial-action { yylloc = 1; }
+
+%%
+
+definitions:
+ definitions definition
+| /* empty */
+;
+
+definition:
+ moduleDecl
+| enumDefn
+| plainStructDefn
+| polymorphicStructTemplateDefn
+| exceptionDefn
+| interfaceDefn
+| typedefDefn
+| constantGroupDefn
+| singleInterfaceBasedServiceDefn
+| accumulationBasedServiceDefn
+| interfaceBasedSingletonDefn
+| serviceBasedSingletonDefn
+| interfaceDecl
+;
+
+moduleDecl:
+ TOK_MODULE identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertToFullName(data, $2));
+ data->modules.push_back(name);
+ std::pair<std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator, bool> p(
+ data->entities.emplace(
+ name,
+ unoidl::detail::SourceProviderEntity(
+ unoidl::detail::SourceProviderEntity::KIND_MODULE)));
+ if (!p.second
+ && (p.first->second.kind
+ != unoidl::detail::SourceProviderEntity::KIND_MODULE))
+ {
+ error(@2, yyscanner, "multiple entities named " + name);
+ YYERROR;
+ }
+ }
+ '{' definitions '}' ';' { yyget_extra(yyscanner)->modules.pop_back(); }
+;
+
+enumDefn:
+ deprecated_opt published_opt TOK_ENUM identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ if (!data->entities.emplace(
+ data->currentName,
+ unoidl::detail::SourceProviderEntity(
+ new unoidl::detail::SourceProviderEnumTypeEntityPad(
+ $2))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ }
+ '{' enumMembers '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderEnumTypeEntityPad * pad =
+ dynamic_cast<unoidl::detail::SourceProviderEnumTypeEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ ent->entity = new unoidl::EnumTypeEntity(
+ pad->isPublished(), std::move(pad->members), annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+enumMembers:
+| enumMembers ',' enumMember
+| enumMember
+;
+
+enumMember:
+ deprecated_opt identifier
+ {
+ OUString id(convertName($2));
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderEnumTypeEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderEnumTypeEntityPad>(data));
+ sal_Int32 v;
+ if (pad->members.empty()) {
+ v = 0;
+ } else {
+ v = pad->members.back().value;
+ if (v == SAL_MAX_INT32) {
+ error(
+ @2, yyscanner,
+ ("enum " + data->currentName + " member " + id
+ + " would have out-of-range value 2^31"));
+ YYERROR;
+ }
+ ++v;
+ }
+ pad->members.emplace_back(id, v, annotations($1));
+ }
+| deprecated_opt identifier '=' expr
+ {
+ OUString id(convertName($2));
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderEnumTypeEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderEnumTypeEntityPad>(data));
+ sal_Int32 v;
+ switch ($4.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($4.ival < SAL_MIN_INT32 || $4.ival > SAL_MAX_INT32) {
+ error(
+ @4, yyscanner,
+ ("out-of-range enum " + data->currentName + " member " + id
+ + " value " + OUString::number($4.ival)));
+ YYERROR;
+ }
+ v = static_cast<sal_Int32>($4.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($4.uval > SAL_MAX_INT32) {
+ error(
+ @4, yyscanner,
+ ("out-of-range enum " + data->currentName + " member " + id
+ + " value " + OUString::number($4.uval)));
+ YYERROR;
+ }
+ v = static_cast<sal_Int32>($4.uval);
+ break;
+ default:
+ error(
+ @4, yyscanner,
+ ("non-integer enum " + data->currentName + " member " + id
+ + " value"));
+ YYERROR;
+ break;
+ }
+ pad->members.emplace_back(id, v, annotations($1));
+ }
+;
+
+plainStructDefn:
+ deprecated_opt published_opt TOK_STRUCT identifier singleInheritance_opt
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ OUString baseName;
+ rtl::Reference<unoidl::PlainStructTypeEntity> baseEnt;
+ if ($5 != nullptr) {
+ baseName = convertName($5);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ @5, yyscanner, data, false, &baseName, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || p->entity->getSort() != unoidl::Entity::SORT_PLAIN_STRUCT_TYPE)
+ {
+ error(
+ @5, yyscanner,
+ ("plain struct type " + data->currentName + " base "
+ + baseName
+ + " does not resolve to an existing plain struct type"));
+ YYERROR;
+ }
+ baseEnt = static_cast<unoidl::PlainStructTypeEntity *>(
+ p->entity.get());
+ if ($2 && !baseEnt->isPublished()) {
+ error(
+ @5, yyscanner,
+ ("published plain struct type " + data->currentName + " base "
+ + baseName + " is unpublished"));
+ YYERROR;
+ }
+ }
+ if (!data->entities.emplace(
+ data->currentName,
+ unoidl::detail::SourceProviderEntity(
+ new unoidl::detail::SourceProviderPlainStructTypeEntityPad(
+ $2, baseName, baseEnt))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ }
+ '{' structMembers '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderPlainStructTypeEntityPad * pad =
+ dynamic_cast<
+ unoidl::detail::SourceProviderPlainStructTypeEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ ent->entity = new unoidl::PlainStructTypeEntity(
+ pad->isPublished(), pad->baseName, std::move(pad->members), annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+polymorphicStructTemplateDefn:
+ deprecated_opt published_opt TOK_STRUCT identifier '<'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ if (!data->entities.emplace(
+ data->currentName,
+ unoidl::detail::SourceProviderEntity(
+ new unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad(
+ $2))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ }
+ typeParameters '>' '{' structMembers '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *
+ pad = dynamic_cast<
+ unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ ent->entity = new unoidl::PolymorphicStructTypeTemplateEntity(
+ pad->isPublished(), std::move(pad->typeParameters), std::move(pad->members),
+ annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+typeParameters:
+ typeParameters ',' identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>(
+ data));
+ OUString id(convertName($3));
+ if (std::find(pad->typeParameters.begin(), pad->typeParameters.end(), id)
+ != pad->typeParameters.end())
+ {
+ error(
+ @3, yyscanner,
+ ("polymorphic struct type template " + data->currentName
+ + " type parameter " + id
+ + " has same identifier as another type parameter"));
+ YYERROR;
+ }
+ pad->typeParameters.push_back(id);
+ }
+| identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>(
+ data));
+ OUString id(convertName($1));
+ assert(pad->typeParameters.empty());
+ pad->typeParameters.push_back(id);
+ }
+;
+
+exceptionDefn:
+ deprecated_opt published_opt TOK_EXCEPTION identifier singleInheritance_opt
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ OUString baseName;
+ rtl::Reference<unoidl::ExceptionTypeEntity> baseEnt;
+ if ($5 != nullptr) {
+ baseName = convertName($5);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ @5, yyscanner, data, false, &baseName, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || p->entity->getSort() != unoidl::Entity::SORT_EXCEPTION_TYPE)
+ {
+ error(
+ @5, yyscanner,
+ ("exception type " + data->currentName + " base " + baseName
+ + " does not resolve to an existing exception type"));
+ YYERROR;
+ }
+ baseEnt = static_cast<unoidl::ExceptionTypeEntity *>(
+ p->entity.get());
+ if ($2 && !baseEnt->isPublished()) {
+ error(
+ @5, yyscanner,
+ ("published exception type " + data->currentName + " base "
+ + baseName + " is unpublished"));
+ YYERROR;
+ }
+ }
+ if (!data->entities.emplace(
+ data->currentName,
+ unoidl::detail::SourceProviderEntity(
+ new unoidl::detail::SourceProviderExceptionTypeEntityPad(
+ $2, baseName, baseEnt))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ }
+ '{' structMembers '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderExceptionTypeEntityPad * pad =
+ dynamic_cast<unoidl::detail::SourceProviderExceptionTypeEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ ent->entity = new unoidl::ExceptionTypeEntity(
+ pad->isPublished(), pad->baseName, std::move(pad->members), annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+structMembers:
+ structMembers structMember
+| /* empty */
+;
+
+structMember:
+ deprecated_opt type identifier ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderType t(*$2);
+ delete $2;
+ OUString id(convertName($3));
+ switch (t.type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ error(
+ @2, yyscanner,
+ ("illegal struct/exception type " + data->currentName
+ + " direct member " + id + " type"));
+ YYERROR;
+ break;
+ default:
+ break;
+ }
+ if (t.type != unoidl::detail::SourceProviderType::TYPE_PARAMETER
+ && t.getName() == data->currentName) // no need to worry about typedef
+ {
+ error(
+ @2, yyscanner,
+ ("struct/exception type " + data->currentName + " direct member "
+ + id + " has same type as the type itself"));
+ YYERROR;
+ }
+ if (checkInstantiatedPolymorphicStructTypeArgument(t, data->currentName))
+ {
+ error(
+ @2, yyscanner,
+ ("struct/exception type " + data->currentName + " direct member "
+ + id
+ + (" has instantiated polymorphic struct type that uses the type"
+ " itself as an argument")));
+ YYERROR;
+ }
+ if (nameHasSameIdentifierAs(data->currentName, id)) {
+ error(
+ @3, yyscanner,
+ ("struct/exception type " + data->currentName + " direct member "
+ + id + " has same unqualified identifier as the type itself"));
+ YYERROR;
+ }
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderPlainStructTypeEntityPad * p1 =
+ dynamic_cast<unoidl::detail::SourceProviderPlainStructTypeEntityPad *>(
+ ent->pad.get());
+ if (p1 != nullptr) {
+ for (const auto & i: p1->members) {
+ if (id == i.name) {
+ error(
+ @3, yyscanner,
+ ("plain struct type " + data->currentName
+ + " direct member " + id
+ + " has same identifier as another direct member"));
+ YYERROR;
+ }
+ }
+ if (p1->baseEntity.is()) {
+ OUString baseName(p1->baseName);
+ for (auto baseEnt(p1->baseEntity);;) {
+ if (nameHasSameIdentifierAs(baseName, id)) {
+ error(
+ @3, yyscanner,
+ ("plain struct type " + data->currentName
+ + " direct member " + id
+ + " has same unqalified identifier as base "
+ + baseName));
+ YYERROR;
+ }
+ for (auto & i: baseEnt->getDirectMembers()) {
+ if (id == i.name) {
+ error(
+ @3, yyscanner,
+ ("plain struct type " + data->currentName
+ + " direct member " + id
+ + " has same identifier as a member of base "
+ + baseName));
+ YYERROR;
+ }
+ }
+ baseName = baseEnt->getDirectBase();
+ if (baseName.isEmpty()) {
+ break;
+ }
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ @2, yyscanner, data, false, &baseName, &p, nullptr,
+ nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_PLAIN_STRUCT_TYPE))
+ {
+ error(
+ @2, yyscanner,
+ ("inconsistent type manager: plain struct type "
+ + data->currentName + " base " + baseName
+ + (" does not resolve to an existing plain struct"
+ " type")));
+ YYERROR;
+ }
+ baseEnt = static_cast<unoidl::PlainStructTypeEntity *>(
+ p->entity.get());
+ }
+ }
+ p1->members.emplace_back(id, t.getName(), annotations($1));
+ } else {
+ unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *
+ p2 = dynamic_cast<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
+ ent->pad.get());
+ if (p2 != nullptr) {
+ for (const auto & i: p2->members) {
+ if (id == i.name) {
+ error(
+ @3, yyscanner,
+ ("polymorphic struct type template "
+ + data->currentName + " direct member " + id
+ + " has same identifier as another direct member"));
+ YYERROR;
+ }
+ }
+ p2->members.emplace_back(
+ id, t.getName(),
+ t.type == unoidl::detail::SourceProviderType::TYPE_PARAMETER,
+ annotations($1));
+ } else {
+ unoidl::detail::SourceProviderExceptionTypeEntityPad * p3
+ = dynamic_cast<unoidl::detail::SourceProviderExceptionTypeEntityPad *>(
+ ent->pad.get());
+ assert(p3 != nullptr);
+ for (const auto & i: p3->members) {
+ if (id == i.name) {
+ error(
+ @3, yyscanner,
+ ("exception type " + data->currentName
+ + " direct member " + id
+ + " has same identifier as another direct member"));
+ YYERROR;
+ }
+ }
+ if (p3->baseEntity.is()) {
+ OUString baseName(p3->baseName);
+ for (auto baseEnt(p3->baseEntity);;) {
+ if (nameHasSameIdentifierAs(baseName, id)) {
+ error(
+ @3, yyscanner,
+ ("exception type " + data->currentName
+ + " direct member " + id
+ + " has same unqalified identifier as base "
+ + baseName));
+ YYERROR;
+ }
+ for (auto & i: baseEnt->getDirectMembers()) {
+ if (id == i.name) {
+ error(
+ @3, yyscanner,
+ ("exception type " + data->currentName
+ + " direct member " + id
+ + " has same identifier as a member of base "
+ + baseName));
+ YYERROR;
+ }
+ }
+ baseName = baseEnt->getDirectBase();
+ if (baseName.isEmpty()) {
+ break;
+ }
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ @2, yyscanner, data, false, &baseName, &p,
+ nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_EXCEPTION_TYPE))
+ {
+ error(
+ @2, yyscanner,
+ ("inconsistent type manager: exception type "
+ + data->currentName + " base " + baseName
+ + (" does not resolve to an existing exception"
+ " type")));
+ YYERROR;
+ }
+ baseEnt = static_cast<unoidl::ExceptionTypeEntity *>(
+ p->entity.get());
+ }
+ }
+ p3->members.emplace_back(id, t.getName(), annotations($1));
+ }
+ }
+ }
+;
+
+interfaceDefn:
+ deprecated_opt published_opt TOK_INTERFACE identifier singleInheritance_opt
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ OUString baseName;
+ rtl::Reference<unoidl::InterfaceTypeEntity> baseEnt;
+ if ($5 != nullptr) {
+ baseName = convertName($5);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ @5, yyscanner, data, true, &baseName, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || p->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ @5, yyscanner,
+ ("interface type " + data->currentName + " direct base "
+ + baseName
+ + " does not resolve to an existing interface type"));
+ YYERROR;
+ }
+ baseEnt = static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get());
+ if ($2 && !baseEnt->isPublished()) {
+ error(
+ @5, yyscanner,
+ ("published interface type " + data->currentName
+ + " direct base " + baseName + " is unpublished"));
+ YYERROR;
+ }
+ }
+ std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator i(
+ data->entities.find(data->currentName));
+ if (i != data->entities.end()) {
+ switch (i->second.kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ if (!$2) {
+ error(
+ @4, yyscanner,
+ ("unpublished interface type " + data->currentName
+ + " has been declared published"));
+ YYERROR;
+ }
+ break;
+ default:
+ error(
+ @4, yyscanner,
+ "multiple entities named " + data->currentName);
+ YYERROR;
+ break;
+ }
+ }
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
+ new unoidl::detail::SourceProviderInterfaceTypeEntityPad(
+ $2, baseEnt.is()));
+ if (baseEnt.is()
+ && !pad->addDirectBase(
+ @4, yyscanner, data,
+ unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
+ baseName, baseEnt, std::vector<OUString>()),
+ false))
+ {
+ YYERROR;
+ }
+ data->entities[data->currentName] = unoidl::detail::SourceProviderEntity(
+ pad);
+ }
+ '{' interfaceMembers '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderInterfaceTypeEntityPad * pad =
+ dynamic_cast<unoidl::detail::SourceProviderInterfaceTypeEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ if (pad->directMandatoryBases.empty()
+ && data->currentName != "com.sun.star.uno.XInterface")
+ {
+ OUString base(".com.sun.star.uno.XInterface");
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@4, yyscanner, data, true, &base, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || p->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ @3, yyscanner,
+ ("interface type " + data->currentName
+ + " implicit direct base " + base
+ + " does not resolve to an existing interface type"));
+ YYERROR;
+ }
+ if (!pad->addDirectBase(
+ @3, yyscanner, data,
+ unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
+ base,
+ static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get()),
+ std::vector<OUString>()),
+ false))
+ {
+ YYERROR;
+ }
+ }
+ std::vector<unoidl::AnnotatedReference> mbases;
+ for (auto & i: pad->directMandatoryBases) {
+ mbases.emplace_back(i.name, std::move(i.annotations));
+ }
+ std::vector<unoidl::AnnotatedReference> obases;
+ for (auto & i: pad->directOptionalBases) {
+ obases.emplace_back(i.name, std::move(i.annotations));
+ }
+ ent->entity = new unoidl::InterfaceTypeEntity(
+ pad->isPublished(), std::move(mbases), std::move(obases), std::move(pad->directAttributes),
+ std::move(pad->directMethods), annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+interfaceMembers:
+ interfaceMembers interfaceMember
+| /* empty */
+;
+
+interfaceMember:
+ interfaceBase
+| interfaceAttribute
+| interfaceMethod
+;
+
+interfaceBase:
+ deprecated_opt flagSection_opt TOK_INTERFACE name ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertName($4));
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
+ data));
+ if (pad->singleBase) {
+ error(
+ @3, yyscanner,
+ "single-inheritance interface cannot have additional bases");
+ YYERROR;
+ }
+ if (($2 & ~unoidl::detail::FLAG_OPTIONAL) != 0) {
+ error(
+ @2, yyscanner,
+ "interface base can only be flagged as [optional]");
+ YYERROR;
+ }
+ bool opt = ($2 & unoidl::detail::FLAG_OPTIONAL) != 0;
+ OUString orgName(name);
+ unoidl::detail::SourceProviderEntity const * p;
+ bool typedefed = false;
+ if (findEntity(@4, yyscanner, data, true, &name, &p, &typedefed, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || p->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ @4, yyscanner,
+ ("interface type " + data->currentName + " direct base " + name
+ + " does not resolve to an existing interface type"));
+ YYERROR;
+ }
+ if (typedefed) {
+ error(
+ @4, yyscanner,
+ ("interface type " + data->currentName + " direct base " + orgName
+ + " is a typedef"));
+ YYERROR;
+ }
+ rtl::Reference<unoidl::InterfaceTypeEntity> ent(
+ static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get()));
+ if (data->publishedContext && !ent->isPublished()) {
+ error(
+ @4, yyscanner,
+ ("published interface type " + data->currentName + " direct base "
+ + name + " is unpublished"));
+ YYERROR;
+ }
+ if (!pad->addDirectBase(
+ @4, yyscanner, data,
+ unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
+ name, ent, annotations($1)),
+ opt))
+ {
+ YYERROR;
+ }
+ }
+;
+
+interfaceAttribute:
+ deprecated_opt flagSection type identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderType t(*$3);
+ delete $3;
+ OUString id(convertName($4));
+ if (($2 & unoidl::detail::FLAG_ATTRIBUTE) == 0) {
+ error(
+ @2, yyscanner,
+ "interface attribute must be flagged as [attribute]");
+ YYERROR;
+ }
+ if (($2
+ & ~(unoidl::detail::FLAG_ATTRIBUTE | unoidl::detail::FLAG_BOUND
+ | unoidl::detail::FLAG_READONLY))
+ != 0)
+ {
+ error(
+ @2, yyscanner,
+ ("interface attribute can only be flagged as [attribute,"
+ " bound, readonly]"));
+ YYERROR;
+ }
+ switch (t.type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ error(
+ @3, yyscanner,
+ ("illegal interface type " + data->currentName
+ + " direct attribute " + id + " type"));
+ YYERROR;
+ break;
+ default:
+ break;
+ }
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
+ data));
+ if (!pad->addDirectMember(@4, yyscanner, data, id)) {
+ YYERROR;
+ }
+ pad->directAttributes.emplace_back(
+ id, t.getName(), ($2 & unoidl::detail::FLAG_BOUND) != 0,
+ ($2 & unoidl::detail::FLAG_READONLY) != 0,
+ std::vector<OUString>(), std::vector<OUString>(), annotations($1));
+ }
+ attributeAccessDecls_opt ';'
+;
+
+attributeAccessDecls_opt:
+ '{' attributeAccessDecls '}'
+| /* empty */
+;
+
+attributeAccessDecls:
+ attributeAccessDecls attributeAccessDecl
+ {
+ if (($1 & $2) != 0) {
+ error(
+ @2, yyscanner, "duplicate get/set attribute access declaration");
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderAccessDecls($1 | $2);
+ }
+| /* empty */ { $$ = unoidl::detail::SourceProviderAccessDecls(0); }
+;
+
+attributeAccessDecl:
+ TOK_GET exceptionSpec ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
+ data));
+ assert(!pad->directAttributes.empty());
+ pad->directAttributes.back().getExceptions = *$2;
+ delete $2;
+ $$ = unoidl::detail::ACCESS_DECL_GET;
+ }
+| TOK_SET exceptionSpec ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
+ data));
+ assert(!pad->directAttributes.empty());
+ pad->directAttributes.back().setExceptions = *$2;
+ delete $2;
+ if (pad->directAttributes.back().readOnly) {
+ error(
+ @1, yyscanner,
+ ("interface type " + data->currentName
+ + " direct read-only attribute "
+ + pad->directAttributes.back().name
+ + " cannot have set access declaration"));
+ YYERROR;
+ }
+ $$ = unoidl::detail::ACCESS_DECL_SET;
+ }
+;
+
+interfaceMethod:
+ deprecated_opt type identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderType t(*$2);
+ delete $2;
+ OUString id(convertName($3));
+ if (t.type == unoidl::detail::SourceProviderType::TYPE_EXCEPTION) {
+ error(
+ @3, yyscanner,
+ ("illegal interface type " + data->currentName
+ + " direct method " + id + " return type"));
+ YYERROR;
+ }
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
+ data));
+ if (!pad->addDirectMember(@3, yyscanner, data, id)) {
+ YYERROR;
+ }
+ pad->directMethods.emplace_back(
+ id, t.getName(),
+ std::vector<unoidl::InterfaceTypeEntity::Method::Parameter>(),
+ std::vector<OUString>(), annotations($1));
+ }
+ '(' methodParams_opt ')' exceptionSpec_opt ';'
+ {
+ if ($8 != nullptr) {
+ unoidl::detail::SourceProviderScannerData * data
+ = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
+ data));
+ assert(!pad->directMethods.empty());
+ pad->directMethods.back().exceptions = *$8;
+ delete $8;
+ }
+ }
+;
+
+methodParams_opt:
+ methodParams
+| /* empty */
+;
+
+methodParams:
+ methodParams ',' methodParam
+| methodParam
+;
+
+methodParam:
+ '[' direction ']' type identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderType t(*$4);
+ delete $4;
+ OUString id(convertName($5));
+ rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderInterfaceTypeEntityPad>(
+ data));
+ assert(!pad->directMethods.empty());
+ switch (t.type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ error(
+ @4, yyscanner,
+ ("illegal interface type " + data->currentName
+ + " direct method " + pad->directMethods.back().name
+ + " parameter " + id + " type"));
+ YYERROR;
+ break;
+ default:
+ break;
+ }
+ for (const auto & i: pad->directMethods.back().parameters) {
+ if (id == i.name) {
+ error(
+ @5, yyscanner,
+ ("interface type " + data->currentName + " direct method "
+ + pad->directMethods.back().name + " parameter " + id
+ + " has same identifier as another parameter"));
+ YYERROR;
+ }
+ }
+ pad->directMethods.back().parameters.emplace_back(id, t.getName(), $2);
+ }
+;
+
+direction:
+ TOK_IN { $$ = unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN; }
+| TOK_OUT
+ { $$ = unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT; }
+| TOK_INOUT
+ { $$ = unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN_OUT; }
+;
+
+typedefDefn:
+ deprecated_opt published_opt TOK_TYPEDEF type identifier ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ unoidl::detail::SourceProviderType t(*$4);
+ delete $4;
+ OUString name(convertToFullName(data, $5));
+ // There is no good reason to forbid typedefs to VOID, to instantiated
+ // polymorphic struct types, and to exception types, but some old client
+ // code of registry data expects this typedef restriction (like the
+ // assert(false) default in handleTypedef in
+ // codemaker/source/javamaker/javatype.cxx), so forbid them for now:
+ switch (t.type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ case unoidl::detail::SourceProviderType::TYPE_INSTANTIATED_POLYMORPHIC_STRUCT:
+ error(@4, yyscanner, "bad typedef type");
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_ENUM:
+ case unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT:
+ case unoidl::detail::SourceProviderType::TYPE_INTERFACE:
+ if ($2) {
+ bool unpub = false;
+ switch (t.entity->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ unpub = true;
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_MODULE:
+ O3TL_UNREACHABLE;
+ default:
+ assert(t.entity->entity.is() || t.entity->pad.is());
+ unpub
+ = !(t.entity->entity.is()
+ ? static_cast<unoidl::PublishableEntity *>(
+ t.entity->entity.get())->isPublished()
+ : t.entity->pad->isPublished());
+ break;
+ }
+ if (unpub) {
+ error(
+ @4, yyscanner,
+ "published typedef " + name + " type is unpublished");
+ YYERROR;
+ }
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_PARAMETER:
+ O3TL_UNREACHABLE;
+ default:
+ break;
+ }
+ if (!data->entities.emplace(
+ name,
+ unoidl::detail::SourceProviderEntity(
+ unoidl::detail::SourceProviderEntity::KIND_LOCAL,
+ new unoidl::TypedefEntity(
+ $2, t.getName(), annotations($1)))).
+ second)
+ {
+ error(@5, yyscanner, "multiple entities named " + name);
+ YYERROR;
+ }
+ clearCurrentState(data);
+ }
+;
+
+constantGroupDefn:
+ deprecated_opt published_opt TOK_CONSTANTS identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ if (!data->entities.emplace(
+ data->currentName,
+ unoidl::detail::SourceProviderEntity(
+ new unoidl::detail::SourceProviderConstantGroupEntityPad(
+ $2))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ }
+ '{' constants '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderConstantGroupEntityPad * pad =
+ dynamic_cast<unoidl::detail::SourceProviderConstantGroupEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ ent->entity = new unoidl::ConstantGroupEntity(
+ pad->isPublished(), std::move(pad->members), annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+constants:
+ constants constant
+| /* empty */
+;
+
+constant:
+ deprecated_opt TOK_CONST type identifier '=' expr ';'
+ {
+ OUString id(convertName($4));
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderConstantGroupEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderConstantGroupEntityPad>(
+ data));
+ unoidl::detail::SourceProviderType t(*$3);
+ delete $3;
+ unoidl::ConstantValue v(false); // dummy value
+ switch (t.type) {
+ case unoidl::detail::SourceProviderType::TYPE_BOOLEAN:
+ if ($6.type != unoidl::detail::SourceProviderExpr::TYPE_BOOL) {
+ error(
+ @6, yyscanner,
+ ("bad value of boolean-typed constant " + data->currentName
+ + "." + id));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue($6.bval);
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_BYTE:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($6.ival < SAL_MIN_INT8 || $6.ival > SAL_MAX_INT8) {
+ error(
+ @6, yyscanner,
+ ("out-of-range byte-typed constant " + data->currentName
+ + "." + id + " value " + OUString::number($6.ival)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_Int8>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($6.uval > SAL_MAX_INT8) {
+ error(
+ @6, yyscanner,
+ ("out-of-range byte-typed constant " + data->currentName
+ + "." + id + " value " + OUString::number($6.uval)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_Int8>($6.uval));
+ break;
+ default:
+ error(
+ @6, yyscanner,
+ ("bad value of byte-typed constant " + data->currentName + "."
+ + id));
+ YYERROR;
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_SHORT:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($6.ival < SAL_MIN_INT16 || $6.ival > SAL_MAX_INT16) {
+ error(
+ @6, yyscanner,
+ ("out-of-range short-typed constant " + data->currentName
+ + "." + id + " value " + OUString::number($6.ival)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_Int16>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($6.uval > SAL_MAX_INT16) {
+ error(
+ @6, yyscanner,
+ ("out-of-range short-typed constant " + data->currentName
+ + "." + id + " value " + OUString::number($6.uval)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_Int16>($6.uval));
+ break;
+ default:
+ error(
+ @6, yyscanner,
+ ("bad value of short-typed constant " + data->currentName
+ + "." + id));
+ YYERROR;
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_SHORT:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($6.ival < 0 || $6.ival > SAL_MAX_UINT16) {
+ error(
+ @6, yyscanner,
+ ("out-of-range unsigned-short-typed constant "
+ + data->currentName + "." + id + " value "
+ + OUString::number($6.ival)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_uInt16>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($6.uval > SAL_MAX_UINT16) {
+ error(
+ @6, yyscanner,
+ ("out-of-range unsigned-short-typed constant "
+ + data->currentName + "." + id + " value "
+ + OUString::number($6.uval)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_uInt16>($6.uval));
+ break;
+ default:
+ error(
+ @6, yyscanner,
+ ("bad value of unsigned-short-typed constant "
+ + data->currentName + "." + id));
+ YYERROR;
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_LONG:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($6.ival < SAL_MIN_INT32 || $6.ival > SAL_MAX_INT32) {
+ error(
+ @6, yyscanner,
+ ("out-of-range long-typed constant " + data->currentName
+ + "." + id + " value " + OUString::number($6.ival)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_Int32>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($6.uval > SAL_MAX_INT32) {
+ error(
+ @6, yyscanner,
+ ("out-of-range long-typed constant " + data->currentName
+ + "." + id + " value " + OUString::number($6.uval)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_Int32>($6.uval));
+ break;
+ default:
+ error(
+ @6, yyscanner,
+ ("bad value of long-typed constant " + data->currentName
+ + "." + id));
+ YYERROR;
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_LONG:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($6.ival < 0 || $6.ival > SAL_MAX_UINT32) {
+ error(
+ @6, yyscanner,
+ ("out-of-range unsigned-long-typed constant "
+ + data->currentName + "." + id + " value "
+ + OUString::number($6.ival)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_uInt32>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($6.uval > SAL_MAX_UINT32) {
+ error(
+ @6, yyscanner,
+ ("out-of-range unsigned-long-typed constant "
+ + data->currentName + "." + id + " value "
+ + OUString::number($6.uval)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_uInt32>($6.uval));
+ break;
+ default:
+ error(
+ @6, yyscanner,
+ ("bad value of unsigned-long-typed constant "
+ + data->currentName + "." + id));
+ YYERROR;
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_HYPER:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ v = unoidl::ConstantValue($6.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($6.uval > SAL_MAX_INT64) {
+ error(
+ @6, yyscanner,
+ ("out-of-range hyper-typed constant " + data->currentName
+ + "." + id + " value " + OUString::number($6.uval)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_Int64>($6.uval));
+ break;
+ default:
+ error(
+ @6, yyscanner,
+ ("bad value of hyper-typed constant " + data->currentName
+ + "." + id));
+ YYERROR;
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_HYPER:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($6.ival < 0) {
+ error(
+ @6, yyscanner,
+ ("out-of-range unsigned-hyper-typed constant "
+ + data->currentName + "." + id + " value "
+ + OUString::number($6.ival)));
+ YYERROR;
+ }
+ v = unoidl::ConstantValue(static_cast<sal_uInt64>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ v = unoidl::ConstantValue($6.uval);
+ break;
+ default:
+ error(
+ @6, yyscanner,
+ ("bad value of unsigned-hyper-typed constant "
+ + data->currentName + "." + id));
+ YYERROR;
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_FLOAT:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ error(
+ @6, yyscanner,
+ ("bad boolean value of float-typed constant "
+ + data->currentName + "." + id));
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ v = unoidl::ConstantValue(static_cast<float>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ v = unoidl::ConstantValue(static_cast<float>($6.uval));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ v = unoidl::ConstantValue(static_cast<float>($6.fval));
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderType::TYPE_DOUBLE:
+ switch ($6.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ error(
+ @6, yyscanner,
+ ("bad boolean value of double-typed constant "
+ + data->currentName + "." + id));
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ v = unoidl::ConstantValue(static_cast<double>($6.ival));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ v = unoidl::ConstantValue(static_cast<double>($6.uval));
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ v = unoidl::ConstantValue($6.fval);
+ break;
+ }
+ break;
+ default:
+ error(
+ @3, yyscanner,
+ "bad type for constant " + data->currentName + "." + id);
+ YYERROR;
+ break;
+ }
+ pad->members.emplace_back(id, v, annotations($1));
+ }
+;
+
+singleInterfaceBasedServiceDefn:
+ deprecated_opt published_opt TOK_SERVICE identifier singleInheritance
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ OUString base(convertName($5));
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@5, yyscanner, data, false, &base, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ bool ifcBase = false;
+ bool pubBase = false;
+ if (p != nullptr) {
+ switch (p->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ ifcBase = true;
+ pubBase = false;
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ ifcBase = true;
+ pubBase = true;
+ break;
+ default:
+ if (p->entity.is()
+ && (p->entity->getSort()
+ == unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ ifcBase = true;
+ pubBase = static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get())->isPublished();
+ }
+ break;
+ }
+ }
+ if (!ifcBase) {
+ error(
+ @5, yyscanner,
+ ("single-interface--based service " + data->currentName + " base "
+ + base + " does not resolve to an interface type"));
+ YYERROR;
+ }
+ if ($2 && !pubBase) {
+ error(
+ @5, yyscanner,
+ ("published single-interface--based service " + data->currentName
+ + " base " + base + " is unpublished"));
+ YYERROR;
+ }
+ if (!data->entities.emplace(
+ data->currentName,
+ unoidl::detail::SourceProviderEntity(
+ new unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad(
+ $2, base))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ }
+ ctors_opt ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad * pad =
+ dynamic_cast<unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ std::vector<unoidl::SingleInterfaceBasedServiceEntity::Constructor> ctors;
+ if ($7) {
+ for (const auto & i: pad->constructors) {
+ std::vector<unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter> parms;
+ for (auto & j: i.parameters) {
+ parms.emplace_back(j.name, j.type.getName(), j.rest);
+ }
+ ctors.push_back(
+ unoidl::SingleInterfaceBasedServiceEntity::Constructor(
+ i.name, std::vector(parms), std::vector(i.exceptions), std::vector(i.annotations)));
+ }
+ } else {
+ assert(pad->constructors.empty());
+ ctors.push_back(
+ unoidl::SingleInterfaceBasedServiceEntity::Constructor());
+ }
+ ent->entity = new unoidl::SingleInterfaceBasedServiceEntity(
+ pad->isPublished(), pad->base, std::move(ctors), annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+ctors_opt:
+ '{' ctors '}' { $$ = true; }
+| /* empty */ { $$ = false; }
+;
+
+ctors:
+ ctors ctor
+| /* empty */
+;
+
+ctor:
+ deprecated_opt identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString id(convertName($2));
+ rtl::Reference<unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad>(
+ data));
+ for (const auto & i: pad->constructors) {
+ if (id == i.name) {
+ error(
+ @2, yyscanner,
+ ("single-interface--based service " + data->currentName
+ + " constructor " + id
+ + " has same identifier as another constructor"));
+ YYERROR;
+ }
+ }
+ pad->constructors.push_back(
+ unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad::Constructor(
+ id, annotations($1)));
+ }
+ '(' ctorParams_opt ')' exceptionSpec_opt ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ rtl::Reference<unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad>(
+ data));
+ assert(!pad->constructors.empty());
+ if ($7 != nullptr) {
+ pad->constructors.back().exceptions = *$7;
+ delete $7;
+ }
+ for (auto i(pad->constructors.begin()); i != pad->constructors.end() - 1;
+ ++i)
+ {
+ if (i->parameters.size()
+ == pad->constructors.back().parameters.size())
+ {
+ bool same = true;
+ for (auto
+ j(i->parameters.begin()),
+ k(pad->constructors.back().parameters.begin());
+ j != i->parameters.end(); ++j, ++k)
+ {
+ if (!j->type.equals(k->type) || j->rest != k->rest) {
+ same = false;
+ break;
+ }
+ }
+ if (same) {
+ error(
+ @2, yyscanner,
+ ("single-interface--based service " + data->currentName
+ + " constructor " + pad->constructors.back().name
+ + " has similar paramete list to constructor "
+ + i->name));
+ YYERROR;
+ }
+ }
+ }
+ }
+;
+
+ctorParams_opt:
+ ctorParams
+| /* empty */
+;
+
+ctorParams:
+ ctorParams ',' ctorParam
+| ctorParam
+;
+
+ctorParam:
+ '[' direction ']' type ellipsis_opt identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderType t(*$4);
+ delete $4;
+ OUString id(convertName($6));
+ rtl::Reference<unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad>(
+ data));
+ assert(!pad->constructors.empty());
+ if ($2 != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) {
+ error(
+ @4, yyscanner,
+ ("single-interface--based service " + data->currentName
+ + " constructor " + pad->constructors.back().name + " parameter "
+ + id + " direction must be [in]"));
+ YYERROR;
+ }
+ switch (t.type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ error(
+ @4, yyscanner,
+ ("illegal single-interface--based service " + data->currentName
+ + " constructor " + pad->constructors.back().name + " parameter "
+ + id + " type"));
+ YYERROR;
+ break;
+ default:
+ break;
+ }
+ if ($5) {
+ if (t.type != unoidl::detail::SourceProviderType::TYPE_ANY) {
+ error(
+ @4, yyscanner,
+ ("illegal single-interface--based service "
+ + data->currentName + " constructor "
+ + pad->constructors.back().name + " rest parameter " + id
+ + " non-any type"));
+ YYERROR;
+ }
+ if (!pad->constructors.back().parameters.empty()) {
+ error(
+ @5, yyscanner,
+ ("single-interface--based service " + data->currentName
+ + " constructor " + pad->constructors.back().name
+ + " rest parameter " + id + " must be first parameter"));
+ YYERROR;
+ }
+ } else if (!pad->constructors.back().parameters.empty()
+ && pad->constructors.back().parameters.back().rest)
+ {
+ error(
+ @1, yyscanner,
+ ("single-interface--based service " + data->currentName
+ + " constructor " + pad->constructors.back().name
+ + " rest parameter must be last parameter"));
+ YYERROR;
+ }
+ for (const auto & i: pad->constructors.back().parameters) {
+ if (id == i.name) {
+ error(
+ @6, yyscanner,
+ ("single-interface--based service " + data->currentName
+ + " constructor " + pad->constructors.back().name
+ + " parameter " + id
+ + " has same identifier as another parameter"));
+ YYERROR;
+ }
+ }
+ pad->constructors.back().parameters.push_back(
+ unoidl::detail::SourceProviderSingleInterfaceBasedServiceEntityPad::Constructor::Parameter(
+ id, std::move(t), $5));
+ }
+;
+
+ellipsis_opt:
+ TOK_ELLIPSIS { $$ = true; }
+| /* empty */ { $$ = false; }
+
+accumulationBasedServiceDefn:
+ deprecated_opt published_opt TOK_SERVICE identifier
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ convertToCurrentName(data, $4);
+ if (!data->entities.emplace(
+ data->currentName,
+ unoidl::detail::SourceProviderEntity(
+ new unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad(
+ $2))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ }
+ '{' serviceMembers '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad * pad =
+ dynamic_cast<unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad *>(
+ ent->pad.get());
+ assert(pad != nullptr);
+ ent->entity = new unoidl::AccumulationBasedServiceEntity(
+ pad->isPublished(), std::move(pad->directMandatoryBaseServices),
+ std::move(pad->directOptionalBaseServices), std::move(pad->directMandatoryBaseInterfaces),
+ std::move(pad->directOptionalBaseInterfaces), std::move(pad->directProperties),
+ annotations($1));
+ ent->pad.clear();
+ clearCurrentState(data);
+ }
+;
+
+serviceMembers:
+ serviceMembers serviceMember
+| /* empty */
+;
+
+serviceMember:
+ serviceBase
+| serviceInterfaceBase
+| serviceProperty
+;
+
+serviceBase:
+ deprecated_opt flagSection_opt TOK_SERVICE name ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertName($4));
+ rtl::Reference<unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad>(
+ data));
+ if (($2 & ~unoidl::detail::FLAG_OPTIONAL) != 0) {
+ error(
+ @2, yyscanner,
+ "service base can only be flagged as [optional]");
+ YYERROR;
+ }
+ bool opt = ($2 & unoidl::detail::FLAG_OPTIONAL) != 0;
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@4, yyscanner, data, false, &name, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE))
+ {
+ error(
+ @4, yyscanner,
+ ("accumulation-based service " + data->currentName
+ + " direct base service " + name
+ + " does not resolve to an accumulation-based service"));
+ YYERROR;
+ }
+ if (data->publishedContext
+ && !static_cast<unoidl::AccumulationBasedServiceEntity *>(
+ p->entity.get())->isPublished())
+ {
+ error(
+ @4, yyscanner,
+ ("published accumulation-based service " + data->currentName
+ + " direct base service " + name + " is unpublished"));
+ YYERROR;
+ }
+ std::vector<unoidl::AnnotatedReference> & v(
+ opt
+ ? pad->directOptionalBaseServices : pad->directMandatoryBaseServices);
+ for (const auto & i: v) {
+ if (name == i.name) {
+ error(
+ @4, yyscanner,
+ ("accumulation-based service " + data->currentName
+ + " duplicate direct base service " + name));
+ YYERROR;
+ }
+ }
+ v.emplace_back(name, annotations($1));
+ }
+;
+
+serviceInterfaceBase:
+ deprecated_opt flagSection_opt TOK_INTERFACE name ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertName($4));
+ rtl::Reference<unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad> pad(
+ getCurrentPad<unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad>(
+ data));
+ if (($2 & ~unoidl::detail::FLAG_OPTIONAL) != 0) {
+ error(
+ @2, yyscanner,
+ "interface base can only be flagged as [optional]");
+ YYERROR;
+ }
+ bool opt = ($2 & unoidl::detail::FLAG_OPTIONAL) != 0;
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@4, yyscanner, data, false, &name, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ bool ifcBase = false;
+ bool pubBase = false;
+ if (p != nullptr) {
+ switch (p->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ ifcBase = true;
+ pubBase = false;
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ ifcBase = true;
+ pubBase = true;
+ break;
+ default:
+ if (p->entity.is()
+ && (p->entity->getSort()
+ == unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ ifcBase = true;
+ pubBase = static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get())->isPublished();
+ }
+ break;
+ }
+ }
+ if (!ifcBase) {
+ error(
+ @4, yyscanner,
+ ("accumulation-based service " + data->currentName
+ + " direct base interface " + name
+ + " does not resolve to an interface type"));
+ YYERROR;
+ }
+ if (data->publishedContext && !opt && !pubBase) {
+ error(
+ @4, yyscanner,
+ ("published accumulation-based service " + data->currentName
+ + " direct base interface " + name + " is unpublished"));
+ YYERROR;
+ }
+ std::vector<unoidl::AnnotatedReference> & v(
+ opt
+ ? pad->directOptionalBaseInterfaces
+ : pad->directMandatoryBaseInterfaces);
+ for (const auto & i: v) {
+ if (name == i.name) {
+ error(
+ @4, yyscanner,
+ ("accumulation-based service " + data->currentName
+ + " duplicate direct base interface " + name));
+ YYERROR;
+ }
+ }
+ v.emplace_back(name, annotations($1));
+ }
+;
+
+serviceProperty:
+ deprecated_opt flagSection type identifier ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::detail::SourceProviderType t(*$3);
+ delete $3;
+ OUString id(convertName($4));
+ if (($2 & unoidl::detail::FLAG_PROPERTY) == 0) {
+ error(
+ @2, yyscanner,
+ ("accumulation-based service property must be flagged as"
+ " [property]"));
+ YYERROR;
+ }
+ if (($2
+ & ~(unoidl::detail::FLAG_BOUND | unoidl::detail::FLAG_CONSTRAINED
+ | unoidl::detail::FLAG_MAYBEAMBIGUOUS
+ | unoidl::detail::FLAG_MAYBEDEFAULT
+ | unoidl::detail::FLAG_MAYBEVOID | unoidl::detail::FLAG_OPTIONAL
+ | unoidl::detail::FLAG_PROPERTY | unoidl::detail::FLAG_READONLY
+ | unoidl::detail::FLAG_REMOVABLE
+ | unoidl::detail::FLAG_TRANSIENT))
+ != 0)
+ {
+ error(
+ @2, yyscanner,
+ ("accumulation-based service property can only be flagged as"
+ " [property, bound, constrained, maybeambiguous, maybedefault,"
+ " maybevoid, optional, readonly, removable, transient]"));
+ YYERROR;
+ }
+ int att = 0;
+ if (($2 & unoidl::detail::FLAG_BOUND) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_BOUND;
+ }
+ if (($2 & unoidl::detail::FLAG_CONSTRAINED) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_CONSTRAINED;
+ }
+ if (($2 & unoidl::detail::FLAG_MAYBEAMBIGUOUS) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_MAYBE_AMBIGUOUS;
+ }
+ if (($2 & unoidl::detail::FLAG_MAYBEDEFAULT) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_MAYBE_DEFAULT;
+ }
+ if (($2 & unoidl::detail::FLAG_MAYBEVOID) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_MAYBE_VOID;
+ }
+ if (($2 & unoidl::detail::FLAG_OPTIONAL) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_OPTIONAL;
+ }
+ if (($2 & unoidl::detail::FLAG_READONLY) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_READ_ONLY;
+ }
+ if (($2 & unoidl::detail::FLAG_REMOVABLE) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_REMOVABLE;
+ }
+ if (($2 & unoidl::detail::FLAG_TRANSIENT) != 0) {
+ att |= unoidl::AccumulationBasedServiceEntity::Property::ATTRIBUTE_TRANSIENT;
+ }
+ switch (t.type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ error(
+ @3, yyscanner,
+ ("illegal accumulation-based service " + data->currentName
+ + " direct property " + id + " type"));
+ YYERROR;
+ break;
+ default:
+ break;
+ }
+ rtl::Reference<unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad>
+ pad(getCurrentPad<unoidl::detail::SourceProviderAccumulationBasedServiceEntityPad>(
+ data));
+ for (const auto & i: pad->directProperties) {
+ if (id == i.name) {
+ error(
+ @4, yyscanner,
+ ("accumulation-based service " + data->currentName
+ + " duplicate direct property " + id));
+ YYERROR;
+ }
+ }
+ pad->directProperties.emplace_back(
+ id, t.getName(),
+ unoidl::AccumulationBasedServiceEntity::Property::Attributes(att),
+ annotations($1));
+ }
+;
+
+interfaceBasedSingletonDefn:
+ deprecated_opt published_opt TOK_SINGLETON identifier singleInheritance ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ OUString name(convertToFullName(data, $4));
+ OUString base(convertName($5));
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@5, yyscanner, data, false, &base, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ bool ifcBase = false;
+ bool pubBase = false;
+ if (p != nullptr) {
+ switch (p->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ ifcBase = true;
+ pubBase = false;
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ ifcBase = true;
+ pubBase = true;
+ break;
+ default:
+ if (p->entity.is()
+ && (p->entity->getSort()
+ == unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ ifcBase = true;
+ pubBase = static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get())->isPublished();
+ }
+ break;
+ }
+ }
+ if (!ifcBase) {
+ error(
+ @5, yyscanner,
+ ("interface-based singleton " + name + " base " + base
+ + " does not resolve to an interface type"));
+ YYERROR;
+ }
+ if ($2 && !pubBase) {
+ error(
+ @5, yyscanner,
+ ("published interface-based singleton " + name + " base " + base
+ + " is unpublished"));
+ YYERROR;
+ }
+ if (!data->entities.emplace(
+ name,
+ unoidl::detail::SourceProviderEntity(
+ unoidl::detail::SourceProviderEntity::KIND_LOCAL,
+ new unoidl::InterfaceBasedSingletonEntity(
+ $2, base, annotations($1)))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + name);
+ YYERROR;
+ }
+ clearCurrentState(data);
+ }
+;
+
+serviceBasedSingletonDefn:
+ deprecated_opt published_opt TOK_SINGLETON identifier '{' TOK_SERVICE name ';'
+ '}' ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ OUString name(convertToFullName(data, $4));
+ OUString base(convertName($7));
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@7, yyscanner, data, false, &base, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr
+ || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE))
+ {
+ error(
+ @7, yyscanner,
+ ("service-based singleton " + name + " base " + base
+ + " does not resolve to an accumulation-based service"));
+ YYERROR;
+ }
+ if ($2
+ && !static_cast<unoidl::AccumulationBasedServiceEntity *>(
+ p->entity.get())->isPublished())
+ {
+ error(
+ @7, yyscanner,
+ ("published service-based singleton " + name + " base " + base
+ + " is unpublished"));
+ YYERROR;
+ }
+ if (!data->entities.emplace(
+ name,
+ unoidl::detail::SourceProviderEntity(
+ unoidl::detail::SourceProviderEntity::KIND_LOCAL,
+ new unoidl::ServiceBasedSingletonEntity(
+ $2, base, annotations($1)))).
+ second)
+ {
+ error(@4, yyscanner, "multiple entities named " + name);
+ YYERROR;
+ }
+ clearCurrentState(data);
+ }
+;
+
+singleInheritance_opt:
+ singleInheritance
+| /* empty */ { $$ = nullptr; }
+;
+
+singleInheritance: ':' name { $$ = $2; }
+;
+
+exceptionSpec_opt:
+ exceptionSpec
+| /* empty */ { $$ = nullptr; }
+;
+
+exceptionSpec: TOK_RAISES '(' exceptions ')' { $$ = $3; }
+;
+
+exceptions:
+ exceptions ',' name
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertName($3));
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@3, yyscanner, data, false, &name, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ delete $1; /* see commented-out %destructor above */
+ YYERROR;
+ }
+ if (p == nullptr
+ || !p->entity.is()
+ || (p->entity->getSort() != unoidl::Entity::SORT_EXCEPTION_TYPE))
+ {
+ delete $1; /* see commented-out %destructor above */
+ error(
+ @3, yyscanner,
+ ("exception " + name + " does not resolve to an exception type"));
+ YYERROR;
+ }
+ if (data->publishedContext
+ && !(static_cast<unoidl::ExceptionTypeEntity *>(p->entity.get())
+ ->isPublished()))
+ {
+ delete $1; /* see commented-out %destructor above */
+ error(
+ @3, yyscanner,
+ ("unpublished exception " + name + " used in published context"));
+ YYERROR;
+ }
+ if (std::find($1->begin(), $1->end(), name) != $1->end()) {
+ delete $1; /* see commented-out %destructor above */
+ error(
+ @3, yyscanner, ("exception " + name + " listed more than once"));
+ YYERROR;
+ }
+ $1->push_back(name);
+ $$ = $1;
+ }
+| name
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertName($1));
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(@1, yyscanner, data, false, &name, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (p == nullptr
+ || !p->entity.is()
+ || (p->entity->getSort() != unoidl::Entity::SORT_EXCEPTION_TYPE))
+ {
+ error(
+ @1, yyscanner,
+ ("exception " + name + " does not resolve to an exception type"));
+ YYERROR;
+ }
+ if (data->publishedContext
+ && !(static_cast<unoidl::ExceptionTypeEntity *>(p->entity.get())
+ ->isPublished()))
+ {
+ error(
+ @1, yyscanner,
+ ("unpublished exception " + name + " used in published context"));
+ YYERROR;
+ }
+ $$ = new std::vector<OUString>; $$->push_back(name);
+ }
+;
+
+interfaceDecl:
+ deprecated_opt/*ignored*/ published_opt TOK_INTERFACE identifier ';'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ data->publishedContext = $2;
+ OUString name(convertToFullName(data, $4));
+ std::pair<std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator, bool> p(
+ data->entities.emplace(
+ name,
+ unoidl::detail::SourceProviderEntity(
+ $2
+ ? unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL
+ : unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL)));
+ if (!p.second) {
+ switch (p.first->second.kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ if ($2) {
+ p.first->second.kind
+ = unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL;
+ }
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ break;
+ default:
+ assert(p.first->second.entity.is());
+ if (p.first->second.entity->getSort()
+ != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ @4, yyscanner,
+ "multiple entities named " + data->currentName);
+ YYERROR;
+ }
+ if ($2
+ && !static_cast<unoidl::InterfaceTypeEntity *>(
+ p.first->second.entity.get())->isPublished())
+ {
+ error(
+ @4, yyscanner,
+ ("published interface type declaration "
+ + data->currentName + " has been defined unpublished"));
+ YYERROR;
+ }
+ }
+ }
+ clearCurrentState(data);
+ }
+;
+
+published_opt:
+ TOK_PUBLISHED { $$ = true; }
+| /* empty */ { $$ = false; }
+;
+
+flagSection_opt:
+ flagSection
+| /* empty */ { $$ = unoidl::detail::SourceProviderFlags(0); }
+;
+
+flagSection: '[' flags ']' { $$ = $2; }
+;
+
+flags:
+ flags ',' flag
+ {
+ if (($1 & $3) != 0) {
+ error(@3, yyscanner, "duplicate flag " + flagName($3));
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderFlags($1 | $3);
+ }
+| flag
+;
+
+flag:
+ TOK_ATTRIBUTE { $$ = unoidl::detail::FLAG_ATTRIBUTE; }
+| TOK_BOUND { $$ = unoidl::detail::FLAG_BOUND; }
+| TOK_CONSTRAINED { $$ = unoidl::detail::FLAG_CONSTRAINED; }
+| TOK_MAYBEAMBIGUOUS { $$ = unoidl::detail::FLAG_MAYBEAMBIGUOUS; }
+| TOK_MAYBEDEFAULT { $$ = unoidl::detail::FLAG_MAYBEDEFAULT; }
+| TOK_MAYBEVOID { $$ = unoidl::detail::FLAG_MAYBEVOID; }
+| TOK_OPTIONAL { $$ = unoidl::detail::FLAG_OPTIONAL; }
+| TOK_PROPERTY { $$ = unoidl::detail::FLAG_PROPERTY; }
+| TOK_READONLY { $$ = unoidl::detail::FLAG_READONLY; }
+| TOK_REMOVABLE { $$ = unoidl::detail::FLAG_REMOVABLE; }
+| TOK_TRANSIENT { $$ = unoidl::detail::FLAG_TRANSIENT; }
+;
+
+expr: orExpr
+;
+
+orExpr:
+ orExpr '|' xorExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival | $3.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval | $3.uval);
+ break;
+ default:
+ error(@1, yyscanner, "arguments of non-integer type to \"|\"");
+ YYERROR;
+ break;
+ }
+ }
+| xorExpr
+;
+
+xorExpr:
+ xorExpr '^' andExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival ^ $3.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval ^ $3.uval);
+ break;
+ default:
+ error(@1, yyscanner, "arguments of non-integer type to \"^\"");
+ YYERROR;
+ break;
+ }
+ }
+| andExpr
+;
+
+andExpr:
+ andExpr '&' shiftExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival & $3.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval & $3.uval);
+ break;
+ default:
+ error(@1, yyscanner, "arguments of non-integer type to \"&\"");
+ YYERROR;
+ break;
+ }
+ }
+| shiftExpr
+;
+
+shiftExpr:
+ shiftExpr TOK_LEFTSHIFT addExpr
+ {
+ int n;
+ switch ($3.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($3.ival < 0 || $3.ival > 63) {
+ error(
+ @3, yyscanner,
+ ("out-of-range shift argument " + OUString::number($3.ival)
+ + " to \"<<\" "));
+ YYERROR;
+ }
+ n = static_cast<int>($3.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($3.uval > 63) {
+ error(
+ @3, yyscanner,
+ ("out-of-range shift argument " + OUString::number($3.uval)
+ + " to \"<<\" "));
+ YYERROR;
+ }
+ n = static_cast<int>($3.uval);
+ break;
+ default:
+ error(@3, yyscanner, "right argument of non-integer type to \"<<\"");
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($1.ival < 0) {
+ error(
+ @1, yyscanner,
+ ("cannot left-shift negative argument "
+ + OUString::number($1.ival)));
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival << n);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval << n);
+ break;
+ default:
+ error(@1, yyscanner, "left argument of non-integer type to \"<<\"");
+ YYERROR;
+ break;
+ }
+ }
+| shiftExpr TOK_RIGHTSHIFT addExpr
+ {
+ int n;
+ switch ($3.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($3.ival < 0 || $3.ival > 63) {
+ error(
+ @3, yyscanner,
+ ("out-of-range shift argument " + OUString::number($3.ival)
+ + " to \">>\" "));
+ YYERROR;
+ }
+ n = static_cast<int>($3.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($3.uval > 63) {
+ error(
+ @3, yyscanner,
+ ("out-of-range shift argument " + OUString::number($3.uval)
+ + " to \">>\" "));
+ YYERROR;
+ }
+ n = static_cast<int>($3.uval);
+ break;
+ default:
+ error(@3, yyscanner, "right argument of non-integer type to \">>\"");
+ YYERROR;
+ break;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival >> n);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval >> n);
+ break;
+ default:
+ error(@1, yyscanner, "left argument of non-integer type to \">>\"");
+ YYERROR;
+ break;
+ }
+ }
+| addExpr
+;
+
+addExpr:
+ addExpr '+' multExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ error(@1, yyscanner, "arguments of boolean type to binary \"+\"");
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival + $3.ival); //TODO: overflow
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval + $3.uval); //TODO: overflow
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ $$ = unoidl::detail::SourceProviderExpr::Float($1.fval + $3.fval);
+ break;
+ }
+ }
+| addExpr '-' multExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ error(@1, yyscanner, "arguments of boolean type to binary \"-\"");
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival - $3.ival); //TODO: overflow
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval - $3.uval); //TODO: overflow
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ $$ = unoidl::detail::SourceProviderExpr::Float($1.fval - $3.fval);
+ break;
+ }
+ }
+| multExpr
+;
+
+multExpr:
+ multExpr '*' unaryExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ error(@1, yyscanner, "arguments of boolean type to \"*\"");
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival * $3.ival); //TODO: overflow
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval * $3.uval); //TODO: overflow
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ $$ = unoidl::detail::SourceProviderExpr::Float($1.fval * $3.fval);
+ break;
+ }
+ }
+| multExpr '/' unaryExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ error(@1, yyscanner, "arguments of boolean type to \"/\"");
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($3.ival == 0) {
+ error(@3, yyscanner, "cannot divide by zero");
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival / $3.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($3.uval == 0) {
+ error(@3, yyscanner, "cannot divide by zero");
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval / $3.uval);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ if ($3.fval == 0) {
+ error(@3, yyscanner, "cannot divide by zero");
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Float($1.fval - $3.fval);
+ break;
+ }
+ }
+| multExpr '%' unaryExpr
+ {
+ if (!coerce(@1, yyscanner, &$1, &$3)) {
+ YYERROR;
+ }
+ switch ($1.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($3.ival == 0) {
+ error(@3, yyscanner, "cannot divide by zero");
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Int($1.ival % $3.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($3.uval == 0) {
+ error(@3, yyscanner, "cannot divide by zero");
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Uint($1.uval % $3.uval);
+ break;
+ default:
+ error(@1, yyscanner, "arguments of non-integer type to \"%\"");
+ YYERROR;
+ break;
+ }
+ }
+| unaryExpr
+;
+
+unaryExpr:
+ '+' primaryExpr
+ {
+ if ($2.type == unoidl::detail::SourceProviderExpr::TYPE_BOOL) {
+ error(@2, yyscanner, "argument of boolean type to unary \"+\"");
+ YYERROR;
+ }
+ $$ = $2;
+ }
+| '-' primaryExpr
+ {
+ switch ($2.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
+ error(@2, yyscanner, "argument of boolean type to unary \"-\"");
+ YYERROR;
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ if ($2.ival == SAL_MIN_INT64) {
+ error(@2, yyscanner, "cannot negate -2^63");
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Int(-$2.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ if ($2.uval == SAL_CONST_UINT64(0x8000000000000000)) {
+ $$ = unoidl::detail::SourceProviderExpr::Int(SAL_MIN_INT64);
+ } else {
+ if ($2.uval > SAL_MAX_INT64) {
+ error(
+ @2, yyscanner,
+ ("cannot negate out-of-range value "
+ + OUString::number($2.uval)));
+ YYERROR;
+ }
+ $$ = unoidl::detail::SourceProviderExpr::Int(
+ -static_cast<sal_Int64>($2.uval));
+ }
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
+ $$ = unoidl::detail::SourceProviderExpr::Float(-$2.fval);
+ break;
+ }
+ }
+| '~' primaryExpr
+ {
+ switch ($2.type) {
+ case unoidl::detail::SourceProviderExpr::TYPE_INT:
+ $$ = unoidl::detail::SourceProviderExpr::Int(~$2.ival);
+ break;
+ case unoidl::detail::SourceProviderExpr::TYPE_UINT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint(~$2.uval);
+ break;
+ default:
+ error(@2, yyscanner, "argument of non-integer type to \"~\"");
+ YYERROR;
+ break;
+ }
+ }
+| primaryExpr
+;
+
+primaryExpr:
+ '(' expr ')' { $$ = $2; }
+| TOK_FALSE { $$ = unoidl::detail::SourceProviderExpr::Bool(false); }
+| TOK_TRUE { $$ = unoidl::detail::SourceProviderExpr::Bool(true); }
+| TOK_INTEGER { $$ = unoidl::detail::SourceProviderExpr::Uint($1); }
+| TOK_FLOATING { $$ = unoidl::detail::SourceProviderExpr::Float($1); }
+| name
+ {
+ OUString name(convertName($1));
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ unoidl::ConstantValue v(false); // dummy value
+ bool found = false;
+ bool unpub = false;
+ sal_Int32 i = name.lastIndexOf('.');
+ if (i == -1) {
+ rtl::Reference<unoidl::detail::SourceProviderEntityPad> pad(
+ getCurrentEntity(data)->pad);
+ unoidl::detail::SourceProviderEnumTypeEntityPad * p1 = dynamic_cast<
+ unoidl::detail::SourceProviderEnumTypeEntityPad *>(pad.get());
+ if (p1 != nullptr) {
+ for (const auto & j: p1->members) {
+ if (j.name == name) {
+ v = unoidl::ConstantValue(j.value);
+ found = true;
+ break;
+ }
+ }
+ } else {
+ unoidl::detail::SourceProviderConstantGroupEntityPad * p2
+ = dynamic_cast<
+ unoidl::detail::SourceProviderConstantGroupEntityPad *>(
+ pad.get());
+ if (p2 != nullptr) {
+ for (const auto & j: p2->members) {
+ if (j.name == name) {
+ v = j.value;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ OUString scope(name.copy(0, i));
+ unoidl::detail::SourceProviderEntity const * ent;
+ if (findEntity(
+ @1, yyscanner, data, false, &scope, &ent, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (ent != nullptr) {
+ std::u16string_view id(name.subView(i + 1));
+ // No need to check for enum members here, as they cannot be
+ // referenced in expressions by qualified name (TODO: is that true?):
+ if (ent->entity.is()) {
+ if (ent->entity->getSort()
+ == unoidl::Entity::SORT_CONSTANT_GROUP)
+ {
+ std::vector<unoidl::ConstantGroupEntity::Member> const &
+ mems(
+ static_cast<unoidl::ConstantGroupEntity *>(
+ ent->entity.get())->
+ getMembers());
+ for (auto & j: mems) {
+ if (j.name == id) {
+ v = j.value;
+ found = true;
+ unpub
+ = !static_cast<unoidl::ConstantGroupEntity *>(
+ ent->entity.get())->isPublished();
+ break;
+ }
+ }
+ }
+ } else if (ent->pad.is()) {
+ unoidl::detail::SourceProviderConstantGroupEntityPad * pad
+ = dynamic_cast<
+ unoidl::detail::SourceProviderConstantGroupEntityPad *>(
+ ent->pad.get());
+ if (pad != nullptr) {
+ for (const auto & j: pad->members) {
+ if (j.name == id) {
+ v = j.value;
+ found = true;
+ unpub = !ent->pad->isPublished();
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!found) {
+ error(
+ @1, yyscanner,
+ (name
+ + (" does not resolve to neither a constant nor an unqualified"
+ " enum member")));
+ YYERROR;
+ }
+ if (data->publishedContext && unpub) {
+ error(
+ @1, yyscanner,
+ "unpublished value " + name + " used in published context");
+ YYERROR;
+ }
+ switch (v.type) {
+ case unoidl::ConstantValue::TYPE_BOOLEAN:
+ $$ = unoidl::detail::SourceProviderExpr::Bool(v.booleanValue);
+ break;
+ case unoidl::ConstantValue::TYPE_BYTE:
+ $$ = unoidl::detail::SourceProviderExpr::Int(v.byteValue);
+ break;
+ case unoidl::ConstantValue::TYPE_SHORT:
+ $$ = unoidl::detail::SourceProviderExpr::Int(v.shortValue);
+ break;
+ case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
+ $$ = unoidl::detail::SourceProviderExpr::Uint(v.unsignedShortValue);
+ break;
+ case unoidl::ConstantValue::TYPE_LONG:
+ $$ = unoidl::detail::SourceProviderExpr::Int(v.longValue);
+ break;
+ case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
+ $$ = unoidl::detail::SourceProviderExpr::Uint(v.unsignedLongValue);
+ break;
+ case unoidl::ConstantValue::TYPE_HYPER:
+ $$ = unoidl::detail::SourceProviderExpr::Int(v.hyperValue);
+ break;
+ case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
+ $$ = unoidl::detail::SourceProviderExpr::Uint(v.unsignedHyperValue);
+ break;
+ case unoidl::ConstantValue::TYPE_FLOAT:
+ $$ = unoidl::detail::SourceProviderExpr::Float(v.floatValue);
+ break;
+ case unoidl::ConstantValue::TYPE_DOUBLE:
+ $$ = unoidl::detail::SourceProviderExpr::Float(v.doubleValue);
+ break;
+ }
+ }
+;
+
+typeArguments:
+ typeArguments ',' type
+ {
+ unoidl::detail::SourceProviderType t(*$3);
+ delete $3;
+ if (!checkTypeArgument(@3, yyscanner, t)) {
+ delete $1; /* see commented-out %destructor above */
+ YYERROR;
+ }
+ $1->push_back(t);
+ $$ = $1;
+ }
+| type
+ {
+ unoidl::detail::SourceProviderType t(*$1);
+ delete $1;
+ if (!checkTypeArgument(@1, yyscanner, t)) {
+ YYERROR;
+ }
+ $$ = new std::vector<unoidl::detail::SourceProviderType>;
+ $$->push_back(t);
+ }
+;
+
+type:
+ TOK_VOID
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_VOID);
+ }
+| TOK_BOOLEAN
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_BOOLEAN);
+ }
+| TOK_BYTE
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_BYTE);
+ }
+| TOK_SHORT
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_SHORT);
+ }
+| TOK_UNSIGNED TOK_SHORT
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_UNSIGNED_SHORT);
+ }
+| TOK_LONG
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_LONG);
+ }
+| TOK_UNSIGNED TOK_LONG
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_UNSIGNED_LONG);
+ }
+| TOK_HYPER
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_HYPER);
+ }
+| TOK_UNSIGNED TOK_HYPER
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_UNSIGNED_HYPER);
+ }
+| TOK_FLOAT
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_FLOAT);
+ }
+| TOK_DOUBLE
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_DOUBLE);
+ }
+| TOK_CHAR
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_CHAR);
+ }
+| TOK_STRING
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_STRING);
+ }
+| TOK_TYPE
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_TYPE);
+ }
+| TOK_ANY
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_ANY);
+ }
+| TOK_SEQUENCE '<' type '>'
+ {
+ switch ($3->type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ case unoidl::detail::SourceProviderType::TYPE_PARAMETER: //TODO?
+ error(@3, yyscanner, "illegal sequence type component type");
+ YYERROR;
+ break;
+ default:
+ break;
+ }
+ $$ = new unoidl::detail::SourceProviderType($3);
+ delete $3;
+ }
+| name
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertName($1));
+ bool done = false;
+ if (name.indexOf('.') == -1 && !data->currentName.isEmpty()) {
+ unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
+ unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *
+ pad = dynamic_cast<
+ unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
+ ent->pad.get());
+ if (pad != nullptr
+ && (std::find(
+ pad->typeParameters.begin(), pad->typeParameters.end(),
+ name)
+ != pad->typeParameters.end()))
+ {
+ $$ = new unoidl::detail::SourceProviderType(name);
+ done = true;
+ }
+ }
+ if (!done) {
+ unoidl::detail::SourceProviderEntity const * ent;
+ unoidl::detail::SourceProviderType t;
+ switch (findEntity(
+ @1, yyscanner, data, false, &name, &ent, nullptr, &t))
+ {
+ case FOUND_ERROR:
+ YYERROR;
+ break;
+ case FOUND_TYPE:
+ $$ = new unoidl::detail::SourceProviderType(t);
+ break;
+ case FOUND_ENTITY:
+ if (ent == nullptr) {
+ error(@1, yyscanner, "unknown entity " + name);
+ YYERROR;
+ }
+ bool ok = false;
+ switch (ent->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
+ if (ent->pad.is()) {
+ if (data->publishedContext && !ent->pad->isPublished()) {
+ error(
+ @1, yyscanner,
+ ("unpublished entity " + name
+ + " used in published context"));
+ YYERROR;
+ }
+ if (dynamic_cast<unoidl::detail::SourceProviderEnumTypeEntityPad *>(
+ ent->pad.get())
+ != nullptr)
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_ENUM,
+ name, ent);
+ ok = true;
+ } else if (dynamic_cast<unoidl::detail::SourceProviderPlainStructTypeEntityPad *>(
+ ent->pad.get())
+ != nullptr)
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT,
+ name, ent);
+ ok = true;
+ } else if (dynamic_cast<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
+ ent->pad.get())
+ != nullptr)
+ {
+ error(
+ @1, yyscanner,
+ (("recursive reference to polymorphic struct type"
+ " template ")
+ + name));
+ YYERROR;
+ } else if (dynamic_cast<unoidl::detail::SourceProviderExceptionTypeEntityPad *>(
+ ent->pad.get())
+ != nullptr)
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_EXCEPTION,
+ name, ent);
+ ok = true;
+ } else if (dynamic_cast<unoidl::detail::SourceProviderInterfaceTypeEntityPad *>(
+ ent->pad.get())
+ != nullptr)
+ {
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_INTERFACE,
+ name, ent);
+ ok = true;
+ }
+ break;
+ }
+ assert(ent->entity.is());
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
+ if (data->publishedContext
+ && ent->entity->getSort() != unoidl::Entity::SORT_MODULE
+ && !static_cast<unoidl::PublishableEntity *>(
+ ent->entity.get())->isPublished())
+ {
+ error(
+ @1, yyscanner,
+ ("unpublished entity " + name
+ + " used in published context"));
+ YYERROR;
+ }
+ switch (ent->entity->getSort()) {
+ case unoidl::Entity::SORT_ENUM_TYPE:
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_ENUM, name,
+ ent);
+ ok = true;
+ break;
+ case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT,
+ name, ent);
+ ok = true;
+ break;
+ case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
+ error(
+ @1, yyscanner,
+ ("polymorphic struct type template " + name
+ + " without type arguments"));
+ YYERROR;
+ break;
+ case unoidl::Entity::SORT_EXCEPTION_TYPE:
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_EXCEPTION,
+ name, ent);
+ ok = true;
+ break;
+ case unoidl::Entity::SORT_INTERFACE_TYPE:
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_INTERFACE,
+ name, ent);
+ ok = true;
+ break;
+ case unoidl::Entity::SORT_TYPEDEF:
+ O3TL_UNREACHABLE;
+ default:
+ break;
+ }
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ if (data->publishedContext) {
+ error(
+ @1, yyscanner,
+ ("unpublished entity " + name
+ + " used in published context"));
+ YYERROR;
+ }
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ $$ = new unoidl::detail::SourceProviderType(
+ unoidl::detail::SourceProviderType::TYPE_INTERFACE, name,
+ ent);
+ ok = true;
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_MODULE:
+ assert(false && "this cannot happen");
+ }
+ if (!ok) {
+ error(@1, yyscanner, "non-type entity " + name);
+ YYERROR;
+ }
+ break;
+ }
+ }
+ }
+| name '<' typeArguments '>'
+ {
+ unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
+ OUString name(convertName($1));
+ std::vector<unoidl::detail::SourceProviderType> args(*$3);
+ delete $3;
+ unoidl::detail::SourceProviderEntity const * ent;
+ if (findEntity(@1, yyscanner, data, false, &name, &ent, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ YYERROR;
+ }
+ if (ent == nullptr) {
+ error(@1, yyscanner, "unknown entity " + name);
+ YYERROR;
+ }
+ bool ok = false;
+ switch (ent->kind) {
+ case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
+ if (ent->pad.is()) {
+ if (dynamic_cast<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
+ ent->pad.get())
+ != nullptr)
+ {
+ error(
+ @1, yyscanner,
+ (("recursive reference to polymorphic struct type"
+ " template ")
+ + name));
+ YYERROR;
+ }
+ break;
+ }
+ assert(ent->entity.is());
+ [[fallthrough]];
+ case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
+ if (ent->entity->getSort()
+ == unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE)
+ {
+ rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity> e(
+ static_cast<unoidl::PolymorphicStructTypeTemplateEntity *>(
+ ent->entity.get()));
+ if (args.size() != e->getTypeParameters().size()) {
+ error(
+ @1, yyscanner,
+ ("bad number of polymorphic struct type template " + name
+ + " type arguments"));
+ YYERROR;
+ }
+ if (data->publishedContext && !e->isPublished()) {
+ error(
+ @1, yyscanner,
+ ("unpublished polymorphic struct type template " + name
+ + " used in published context"));
+ YYERROR;
+ }
+ $$ = new unoidl::detail::SourceProviderType(name, ent, std::move(args));
+ ok = true;
+ }
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
+ case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
+ break;
+ case unoidl::detail::SourceProviderEntity::KIND_MODULE:
+ assert(false && "this cannot happen");
+ }
+ if (!ok) {
+ error(@1, yyscanner, "non-type entity " + name);
+ YYERROR;
+ }
+ }
+;
+
+name:
+ name TOK_COLONS identifier { *$1 += "." + *$3; delete $3; $$ = $1; }
+| TOK_COLONS identifier { *$2 = "." + *$2; $$ = $2; }
+| identifier
+;
+
+identifier:
+ TOK_IDENTIFIER
+| TOK_GET { $$ = new OString("get"); }
+| TOK_PUBLISHED { $$ = new OString("published"); }
+| TOK_SET { $$ = new OString("set"); }
+;
+
+deprecated_opt:
+ TOK_DEPRECATED { $$ = true; }
+| /* empty */ { $$ = false; }
+;
+
+%%
+
+namespace unoidl::detail {
+
+OUString SourceProviderType::getName() const {
+ if (!typedefName.isEmpty()) {
+ return typedefName;
+ }
+ switch (type) {
+ case unoidl::detail::SourceProviderType::TYPE_VOID:
+ return "void";
+ case unoidl::detail::SourceProviderType::TYPE_BOOLEAN:
+ return "boolean";
+ case unoidl::detail::SourceProviderType::TYPE_BYTE:
+ return "byte";
+ case unoidl::detail::SourceProviderType::TYPE_SHORT:
+ return "short";
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_SHORT:
+ return "unsigned short";
+ case unoidl::detail::SourceProviderType::TYPE_LONG:
+ return "long";
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_LONG:
+ return "unsigned long";
+ case unoidl::detail::SourceProviderType::TYPE_HYPER:
+ return "hyper";
+ case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_HYPER:
+ return "unsigned hyper";
+ case unoidl::detail::SourceProviderType::TYPE_FLOAT:
+ return "float";
+ case unoidl::detail::SourceProviderType::TYPE_DOUBLE:
+ return "double";
+ case unoidl::detail::SourceProviderType::TYPE_CHAR:
+ return "char";
+ case unoidl::detail::SourceProviderType::TYPE_STRING:
+ return "string";
+ case unoidl::detail::SourceProviderType::TYPE_TYPE:
+ return "type";
+ case unoidl::detail::SourceProviderType::TYPE_ANY:
+ return "any";
+ case unoidl::detail::SourceProviderType::TYPE_SEQUENCE:
+ assert(subtypes.size() == 1);
+ return "[]" + subtypes.front().getName();
+ case unoidl::detail::SourceProviderType::TYPE_ENUM:
+ case unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT:
+ case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
+ case unoidl::detail::SourceProviderType::TYPE_INTERFACE:
+ case unoidl::detail::SourceProviderType::TYPE_PARAMETER:
+ return name;
+ case unoidl::detail::SourceProviderType::TYPE_INSTANTIATED_POLYMORPHIC_STRUCT:
+ {
+ OUStringBuffer n(512);
+ n.append(name + "<");
+ for (auto i(subtypes.begin()); i != subtypes.end(); ++i) {
+ if (i != subtypes.begin()) {
+ n.append(",");
+ }
+ n.append(i->getName());
+ }
+ return n.append(">").makeStringAndClear();
+ }
+ default:
+ assert(false && "this cannot happen"); for (;;) { std::abort(); }
+ }
+}
+
+bool SourceProviderType::equals(SourceProviderType const & other) const {
+ if (type != other.type || name != other.name
+ || subtypes.size() != other.subtypes.size())
+ {
+ return false;
+ }
+ for (auto i(subtypes.begin()), j(other.subtypes.begin());
+ i != subtypes.end(); ++i, ++j)
+ {
+ if (!i->equals(*j)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::addDirectBase(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ DirectBase const & base, bool optional)
+{
+ std::set<OUString> seen;
+ if (!(checkBaseClashes(
+ location, yyscanner, data, base.name, base.entity, true, optional,
+ optional, &seen)
+ && addBase(
+ location, yyscanner, data, base.name, base.name, base.entity,
+ true, optional)))
+ {
+ return false;
+ }
+ if (optional) {
+ addOptionalBaseMembers(
+ location, yyscanner, data, base.name, base.entity);
+ }
+ (optional ? directOptionalBases : directMandatoryBases).push_back(base);
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::addDirectMember(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name)
+{
+ assert(data != nullptr);
+ if (!checkMemberClashes(location, yyscanner, data, u"", name, true)) {
+ return false;
+ }
+ allMembers.emplace(name, Member(data->currentName));
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::checkBaseClashes(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity, bool direct,
+ bool optional, bool outerOptional, std::set<OUString> * seen) const
+{
+ assert(data != nullptr);
+ assert(entity.is());
+ assert(seen != nullptr);
+ if (direct || optional || seen->insert(name).second) {
+ std::map<OUString, BaseKind>::const_iterator i(allBases.find(name));
+ if (i != allBases.end()) {
+ switch (i->second) {
+ case BASE_INDIRECT_OPTIONAL:
+ if (direct && optional) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ break;
+ case BASE_DIRECT_OPTIONAL:
+ if (direct || !outerOptional) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ return true;
+ case BASE_INDIRECT_MANDATORY:
+ if (direct) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ return true;
+ case BASE_DIRECT_MANDATORY:
+ if (direct || (!optional && !outerOptional)) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate base " + name));
+ return false;
+ }
+ return true;
+ }
+ }
+ if (direct || !optional) {
+ for (auto & j: entity->getDirectMandatoryBases()) {
+ OUString n("." + j.name);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ location, yyscanner, data, true, &n, &p, nullptr,
+ nullptr)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (p == nullptr || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!checkBaseClashes(
+ location, yyscanner, data, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get()),
+ false, false, outerOptional, seen))
+ {
+ return false;
+ }
+ }
+ for (auto & j: entity->getDirectOptionalBases()) {
+ OUString n("." + j.name);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ location, yyscanner, data, true, &n, &p, nullptr,
+ nullptr)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (p == nullptr || !p->entity.is()
+ || (p->entity->getSort()
+ != unoidl::Entity::SORT_INTERFACE_TYPE))
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!checkBaseClashes(
+ location, yyscanner, data, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(
+ p->entity.get()),
+ false, true, outerOptional, seen))
+ {
+ return false;
+ }
+ }
+ for (auto & j: entity->getDirectAttributes()) {
+ if (!checkMemberClashes(
+ location, yyscanner, data, name, j.name,
+ !outerOptional))
+ {
+ return false;
+ }
+ }
+ for (auto & j: entity->getDirectMethods()) {
+ if (!checkMemberClashes(
+ location, yyscanner, data, name, j.name,
+ !outerOptional))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::checkMemberClashes(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ std::u16string_view interfaceName, OUString const & memberName,
+ bool checkOptional) const
+{
+ std::map<OUString, Member>::const_iterator i(allMembers.find(memberName));
+ if (i != allMembers.end()) {
+ if (!i->second.mandatory.isEmpty()) {
+ // For a direct member, interfaceName will be empty, so this will
+ // catch two direct members with the same name:
+ if (i->second.mandatory != interfaceName) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate member " + memberName));
+ return false;
+ }
+ } else if (checkOptional) {
+ for (auto & j: i->second.optional) {
+ if (j != interfaceName) {
+ error(
+ location, yyscanner,
+ ("interface type " + data->currentName
+ + " duplicate member " + memberName));
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::addBase(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & directBaseName, OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity, bool direct,
+ bool optional)
+{
+ assert(data != nullptr);
+ assert(entity.is());
+ BaseKind kind = optional
+ ? direct ? BASE_DIRECT_OPTIONAL : BASE_INDIRECT_OPTIONAL
+ : direct ? BASE_DIRECT_MANDATORY : BASE_INDIRECT_MANDATORY;
+ std::pair<std::map<OUString, BaseKind>::iterator, bool> p(
+ allBases.emplace(name, kind));
+ bool seen = !p.second && p.first->second >= BASE_INDIRECT_MANDATORY;
+ if (!p.second && kind > p.first->second) {
+ p.first->second = kind;
+ }
+ if (!optional && !seen) {
+ for (auto & i: entity->getDirectMandatoryBases()) {
+ OUString n("." + i.name);
+ unoidl::detail::SourceProviderEntity const * q;
+ if (findEntity(
+ location, yyscanner, data, true, &n, &q, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (q == nullptr || !q->entity.is()
+ || q->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!addBase(
+ location, yyscanner, data, directBaseName, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(q->entity.get()),
+ false, false))
+ {
+ return false;
+ }
+ }
+ for (auto & i: entity->getDirectOptionalBases())
+ {
+ OUString n("." + i.name);
+ unoidl::detail::SourceProviderEntity const * q;
+ if (findEntity(
+ location, yyscanner, data, true, &n, &q, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (q == nullptr || !q->entity.is()
+ || q->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!addBase(
+ location, yyscanner, data, directBaseName, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(q->entity.get()),
+ false, true))
+ {
+ return false;
+ }
+ }
+ for (auto & i: entity->getDirectAttributes()) {
+ allMembers.emplace(i.name, Member(name));
+ }
+ for (auto & i: entity->getDirectMethods()) {
+ allMembers.emplace(i.name, Member(name));
+ }
+ }
+ return true;
+}
+
+bool SourceProviderInterfaceTypeEntityPad::addOptionalBaseMembers(
+ YYLTYPE location, yyscan_t yyscanner, SourceProviderScannerData * data,
+ OUString const & name,
+ rtl::Reference<unoidl::InterfaceTypeEntity> const & entity)
+{
+ assert(entity.is());
+ for (auto & i: entity->getDirectMandatoryBases()) {
+ OUString n("." + i.name);
+ unoidl::detail::SourceProviderEntity const * p;
+ if (findEntity(
+ location, yyscanner, data, true, &n, &p, nullptr, nullptr)
+ == FOUND_ERROR)
+ {
+ return false;
+ }
+ if (p == nullptr || !p->entity.is()
+ || p->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
+ {
+ error(
+ location, yyscanner,
+ ("inconsistent type manager: interface type "
+ + data->currentName + " base " + n
+ + " does not resolve to an existing interface type"));
+ return false;
+ }
+ if (!addOptionalBaseMembers(
+ location, yyscanner, data, n,
+ static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get())))
+ {
+ return false;
+ }
+ }
+ for (auto & i: entity->getDirectAttributes()) {
+ Member & m(
+ allMembers.emplace(i.name, Member(""))
+ .first->second);
+ if (m.mandatory.isEmpty()) {
+ m.optional.insert(name);
+ }
+ }
+ for (auto & i: entity->getDirectMethods()) {
+ Member & m(
+ allMembers.emplace(i.name, Member(""))
+ .first->second);
+ if (m.mandatory.isEmpty()) {
+ m.optional.insert(name);
+ }
+ }
+ return true;
+}
+
+bool parse(OUString const & uri, SourceProviderScannerData * data) {
+ assert(data != nullptr);
+ oslFileHandle handle;
+ oslFileError e = osl_openFile(uri.pData, &handle, osl_File_OpenFlag_Read);
+ switch (e) {
+ case osl_File_E_None:
+ break;
+ case osl_File_E_NOENT:
+ return false;
+ default:
+ throw FileFormatException(uri, "cannot open: " + OUString::number(e));
+ }
+ sal_uInt64 size;
+ e = osl_getFileSize(handle, &size);
+ if (e != osl_File_E_None) {
+ oslFileError e2 = osl_closeFile(handle);
+ SAL_WARN_IF(
+ e2 != osl_File_E_None, "unoidl",
+ "cannot close " << uri << ": " << +e2);
+ throw FileFormatException(
+ uri, "cannot get size: " + OUString::number(e));
+ }
+ void * address;
+ e = osl_mapFile(handle, &address, size, 0, osl_File_MapFlag_RandomAccess);
+ if (e != osl_File_E_None) {
+ oslFileError e2 = osl_closeFile(handle);
+ SAL_WARN_IF(
+ e2 != osl_File_E_None, "unoidl",
+ "cannot close " << uri << ": " << +e2);
+ throw FileFormatException(uri, "cannot mmap: " + OUString::number(e));
+ }
+ try {
+ data->setSource(address, size);
+ yyscan_t yyscanner;
+ if (yylex_init_extra(data, &yyscanner) != 0) {
+ // Checking errno for the specific EINVAL, ENOMEM documented for
+ // yylex_init_extra would not work as those values are not defined
+ // by the C++ Standard:
+ int e2 = errno;
+ throw FileFormatException(
+ uri,
+ "yylex_init_extra failed with errno " + OUString::number(e2));
+ }
+ int e2 = yyparse(yyscanner);
+ yylex_destroy(yyscanner);
+ switch (e2) {
+ case 0:
+ break;
+ default:
+ O3TL_UNREACHABLE;
+ case 1:
+ throw FileFormatException(
+ uri,
+ ("cannot parse"
+ + (data->errorLine == 0
+ ? OUString() : " line " + OUString::number(data->errorLine))
+ + (data->parserError.isEmpty()
+ ? OUString()
+ : (", "
+ + OStringToOUString(
+ data->parserError, osl_getThreadTextEncoding())))
+ + (data->errorMessage.isEmpty()
+ ? OUString() : ": \"" + data->errorMessage + "\"")));
+ case 2:
+ throw std::bad_alloc();
+ }
+ } catch (...) {
+ e = osl_unmapMappedFile(handle, address, size);
+ SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot unmap: " << +e);
+ e = osl_closeFile(handle);
+ SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot close: " << +e);
+ throw;
+ }
+ e = osl_unmapMappedFile(handle, address, size);
+ SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot unmap: " << +e);
+ e = osl_closeFile(handle);
+ SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot close: " << +e);
+ return true;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */