363b4078be
Change-Id: I003851390566dfe2b98cecc88afc8153f061ad68 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159522 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
4476 lines
165 KiB
Text
4476 lines
165 KiB
Text
/* -*- 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"_ostr); }
|
|
| TOK_PUBLISHED { $$ = new OString("published"_ostr); }
|
|
| TOK_SET { $$ = new OString("set"_ostr); }
|
|
;
|
|
|
|
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: */
|