// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*-
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
//
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
// ACDK
//
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
//
#include "ModuleInfo.h"
#include "ArgumentInfo.h"
#include "MetaCompiler.h"
#include "CMCException.h"
#include "DmiProxyAttribute.h"
#include "DmiProxyGenerator.h"
#include <acdk/io/File.h>
#include <acdk/locale/Encoding.h>
#include <acdk/io/ByteToCharReader.h>
#include <acdk/util/StringTokenizer.h>
namespace acdk {
namespace tools {
namespace mc {
//virtual
RString
ModuleInfo::getMetaInfoCIdentifier()
{
return "";
}
RString
ModuleInfo::baseFilename()
{
acdk::io::File tf(_fname);
return tf.getName();
}
RString
ModuleInfo::getParent()
{
acdk::io::File tf(_fname);
return tf.getParent();
}
bool
ModuleInfo::checkContext()
{
bool berg = true;
RIterator it = _classes->iterator();
while (it->hasNext() == true)
berg = RClassInfo(it->next())->checkContext(const_cast<ModuleInfo*>(this)) && berg;
return berg;
}
//static
void
ModuleInfo::writeOpenNamespace(IN(RPrintWriter) out, IN(RArrayList) nslist, IN(RArrayList) usings)
{
out->print("\n");
RIterator it = nslist->iterator();
while (it->hasNext() == true)
{
RString ns = RString(it->next());
out->print("namespace ");
out->print(ns);
out->print(" { \n");
}
out->print("\n");
if (usings != Nil)
{
RIterator it = usings->iterator();
while (it->hasNext() == true) {
RString ns = RString(it->next());
out->print("using namespace ");
out->print(ns);
out->print(";\n");
}
}
}
//static
void
ModuleInfo::writeCloseNamespace(IN(RPrintWriter) out, IN(RArrayList) nslist)
{
RIterator it = nslist->iterator();
out->print("\n");
while (it->hasNext() == true)
{
RString ns = RString(it->next());
out->print("} // namespace ");
out->print(ns);
out->print("\n");
}
out->print("\n");
}
void
ModuleInfo::writeClsInfoCPP(IN(RPrintWriter) out, IN(RPrintWriter) stubout, bool withFieldInfo)
{
RPrintWriter o = stubout;
if (stubout == Nil)
o = out;
if (MetaCompiler::generateProxies == false)
{
for (int i = 0; i < _enums->length(); ++i)
{
_enums[i]->writeEnumInfo(o);
}
}
RIterator it = _classes->iterator();
while (it->hasNext() == true)
{
RClassInfo(it->next())->writeClassInfo(out, stubout, withFieldInfo);
}
}
bool
ModuleInfo::hasMetaInfo()
{
if (_enums->length() > 0)
return true;
RIterator it = _classes->iterator();
while (it->hasNext() == true) {
if (RClassInfo(it->next())->_hasMetaInfo == true)
return true;
}
return false;
}
void
ModuleInfo::dump(IN(RPrintWriter) out, IN(RString) ind)
{
out->println(ind + "Modul: [" + _fname + "]");
RIterator it = _classes->iterator();
while (it->hasNext() == true) {
RClassInfo ci = RClassInfo(it->next());
out->println(ind + "class->");
ci->dump(out, ind + " ");
}
}
void
ModuleInfo::writeModuleHeaderInclude(IN(RPrintWriter) out, IN(::acdk::io::RPrintWriter) stubout)
{
out->print("#include \"");
if (stubout != Nil || MetaCompiler::generateProxies)
{
out->print("../");
if (stubout != Nil && MetaCompiler::getMetaCompiler()->baseMetaInfoHeaderWritten == false)
{
stubout->print("#include \"");
stubout->println(baseFilename() + "\"");
}
}
out->println(baseFilename() + "\"");
writeCodes(out, ModuleInclude);
}
bool
ModuleInfo::parse()
{
ACDK_LOG(Info, "Analyse file: " + _fname);
RStreamTokenizer in = new StreamTokenizer(
new acdk::io::ByteToCharReader(
new ::acdk::io::FileReader(_fname),
acdk::locale::Encoding::getAsciiEncoding()->getDecoder()));
return parse(in);
}
//
RArrayList asContainer(IN(RStringArray) arr) // #### remove this later
{
RArrayList la = new ArrayList();
for (int i = 0; i < arr->length(); ++i)
la->add(&arr[i]);
return la;
}
bool
ModuleInfo::parse(IN(RStreamTokenizer) in)
{
int tk;
bool attn_class = true; // ## for debugging, otherwise it should be false
bool isclass = true;
acdk::tools::mc::CodeAttributeArray clsAttributes(0);
acdk::tools::mc::CodeAttributeArray unitAttributes(0);
int currentFlags = 0;
while ((tk = in->nextToken()) != StreamTokenizer::TT_EOF) {
//RString msg = RString("Readed: [") + ": " + in->getDeviceName() + in->lineno() + "] " +
// "Token: " + in->toString();
if (tk == '#') // c-preprocessor
{
MetaCompiler::skipPreprocessorStatement(in);
if (in->ttype == StreamTokenizer::TT_EOF)
break;
}
else if (tk == StreamTokenizer::TT_WORD || tk == ':')
{
if (in->sval->equals("ACDK_NO_METAINFO_HEADER") == true)
return false;
if (in->sval->equals("namespace") == true)
{
tk = in->nextToken();
RString ns = in->sval;
if (tk == StreamTokenizer::TT_WORD)
;//cerr << "namespace: " << in->sval->c_str() << endl;
else
THROW_CMC(CMCException, in, "Expect identifier after \'namespace\'");
tk = in->nextToken();
if (tk != '{')
THROW_CMC(CMCException, in, "Expect identifier after \'namespace\'");
_curNameSpace->add((acdk::lang::Object)ns);
} else if (in->sval->equals("using") == true) {
tk = in->nextToken();
if (tk != StreamTokenizer::TT_WORD)
THROW_CMC(CMCException, in, "Expect identifier after \'using\'");
if (in->sval->equals("namespace") == true) {
RString nm = MetaCompiler::readComponentIndentifier(in);
if (in->ttype == StreamTokenizer::TT_EOF)
break;
tk = in->nextToken();
if (tk != ';')
THROW_CMC(CMCException, in, "Expect \';\' after \'using namespace blabla\'");
_usings->add((acdk::lang::Object)nm);
} else {
MetaCompiler::skipStatement(in);
if (in->ttype == StreamTokenizer::TT_EOF)
break;
}
} else if (in->sval->equals("ACDK_DECL_UNIT") == true) {
RString unit = MetaCompiler::readCodeAttributeCode(in);
RUnitInfo ui = MetaCompiler::getMetaCompiler()->addUnit(unit);
ui->addCodeAttributes(&unitAttributes);
} else if (in->sval->equals("ACDK_DECL_THROWABLE") == true || in->sval->equals("ACDK_DECL_THROWABLE_FQ") == true) {
RString unit = MetaCompiler::readCodeAttributeCode(in);
_knownExceptions->append(unit->substr(0, unit->indexOf(","))->trim());
tk = in->nextToken(); // consume ';'
}
else if (in->sval->equals("ACDK_DECL_ENUM_FQ") == true ||
in->sval->equals("ACDK_DECL_ENUM") == true)
{
bool isfq = false;
if (in->sval->equals("ACDK_DECL_ENUM_FQ") == true)
isfq = true;
acdk::util::RList ns;
RString enname;
RString nsname;
tk = in->nextToken(); // (
tk = in->nextToken();
if (isfq == true)
{
nsname = in->sval;
ns = (acdk::util::RList)asContainer(acdk::util::StringTokenizer(in->sval, "::").allToken());
//ns = acdk::util::StringTokenizer(in->sval, "::").allToken()->asContainer();
in->nextToken(); // ,
in->nextToken();
enname = in->sval;
}
else
{
enname = in->sval;
}
addType(TsEnum, enname);
if (nsname != Nil)
{
if (nsname->endsWith("::") == true)
addType(TsEnum, nsname + enname);
else
addType(TsEnum, nsname + "::" + enname);
}
/*
REnumInfo ei;
if (ns == Nil)
ei = new EnumInfo(this, _curNameSpace, _usings);
else
ei = new EnumInfo(this, ns, _usings);
ei->name = enname;
MetaCompiler::getMetaCompiler()->_enums->append(ei);
*/
tk = in->nextToken(); // )
tk = in->nextToken(); // ;
continue;
}
else if (in->sval->equals("ACDK_DEF_ENUM") == true || in->sval->equals("ACDK_DEF_LIB_ENUM") == true)
{
bool withExport = false;
if (in->sval->equals("ACDK_DEF_LIB_ENUM") == true)
withExport = true;
tk = in->nextToken();
tk = in->nextToken();
RString xexport = "";
if (withExport == true)
{
xexport = in->sval;
tk = in->nextToken();
tk = in->nextToken();
}
RString enumName = in->sval;
REnumInfo ei = getEnumInfo(enumName);
if (ei == Nil)
{
ACDK_LOG(Error, "Failed to parse enum definition: " + enumName);
MetaCompiler::skipStatement(in);
continue;
}
ei->hasMetinfDef = true;
MetaCompiler::skipStatement(in);
continue;
}
else if (in->sval->equals("ACDK_CLASSATTRIBUTE") == true ||
in->sval->equals("ACDK_UNITATTRIBUTE") == true )
{
bool unitinfo = in->sval->equals("ACDK_UNITATTRIBUTE");
RString code = MetaCompiler::readCodeAttributeCode(in);
acdk::tools::mc::RCodeAttribute ca = MetaCompiler::getMetaCompiler()->readParseCodeAttribute(code);
if (ca != Nil)
{
if (unitinfo == true)
unitAttributes.append(ca);
else
clsAttributes.append(ca);
}
else
{
// ingnore it! THROW_CMC(CMCException, in, "Parsed Attribute failed: " + code);
}
} else if (in->sval->equals("ACDK_CLASS") == true) {
attn_class = true;
} else if (in->sval->equals("ACDK_INTERFACE") == true) {
attn_class = true;
isclass = false;
currentFlags |= acdk::lang::dmi::MiCiInterface;
}
else if (in->sval->equals("final") == true)
{
currentFlags |= acdk::lang::dmi::MiNoDmiProxy;
}
else if (in->sval->equals("class") == true)
{
if (attn_class == true)
{
RClassInfo ci = new ClassInfo(this, _curNameSpace, _usings, isclass, currentFlags);
currentFlags = 0;
if (ci->parse(in) == true)
{
ci->addCodeAttributes(&clsAttributes);
// ### experimental
DmiProxyGenerator::addToClass(ci);
_classes->add((acdk::lang::Object)ci);
clsAttributes.resize(0);
ci->_isThrowable = isKnownThrowable(ci->name);
}
if (in->ttype == StreamTokenizer::TT_EOF)
break;
}
isclass = true; //## debugging
} else if (in->sval->equals("const") == true ||
in->sval->equals("extern") == true) {
// 'const int val = 42;'
MetaCompiler::skipStatement(in);
if (in->ttype == StreamTokenizer::TT_EOF)
break;
}
else if (in->sval->equals("enum") == true)
{
REnumInfo ei = new EnumInfo(this, _curNameSpace, _usings);
if (ei->parse(in) == true)
{
MetaCompiler::getMetaCompiler()->_enums->append(ei);
addType(TsEnum, ei->name);
_enums->append(ei);
}
else
{
//tk = in->nextToken();
//### addType(Enum, in->sval);
ACDK_LOG(Warn, "Failed to parse enum: " + ei->name);
MetaCompiler::skipTypeDeclarator(in);
}
if (in->ttype == StreamTokenizer::TT_EOF)
break;
continue;
} else if (in->sval->equals("typedef") == true ||
in->sval->equals("friend") == true ||
in->sval->equals("template") == true ||
in->sval->equals("union") == true ||
in->sval->equals("struct") == true) {
MetaCompiler::skipTypeDeclarator(in);
if (in->ttype == StreamTokenizer::TT_EOF)
break;
} else {
// hoply only function definitions.
MetaCompiler::skipStatement(in);
if (in->ttype == StreamTokenizer::TT_EOF)
break;
}
} else if (tk == '}') { // This is namespace closure
_usings = new ArrayList();
if (_curNameSpace->size() == 0)
THROW_CMC(CMCException, in, "Unexpecting closing namespace");
_curNameSpace->removeRange(_curNameSpace->size() - 1, _curNameSpace->size());
} else {
THROW_CMC(CMCException, in, "Unexpected Token in ModuleInfo::parse()");
}
}
if (name == Nil)
return false;
return true;
}
bool
ModuleInfo::invokeCodeAttributes()
{
RIterator it = _classes->iterator();
while (it->hasNext() == true)
if (RClassInfo(it->next())->invokeCodeAttributes(this) == false)
return false;
CodeInfo::invokeCodeAttributes();
return true;
}
void
ModuleInfo::writeCodes(IN(RPrintWriter) out, CodeWhere where)
{
RIterator it = _classes->iterator();
while (it->hasNext() == true)
RClassInfo(it->next())->writeCodes(out, where);
writeCode(out, where);
}
//static
RString
ModuleInfo::getNameSpace(IN(RArrayList) ns, IN(RString) separator)
{
RIterator it = ns->iterator();
StringBuffer ret(20);
while (it->hasNext() == true)
{
RString ns = RString(it->next());
if (ret.length() > 0)
ret.append(separator);
ret.append(ns);
}
return ret.toString();
}
REnumInfo
ModuleInfo::getEnumInfo(IN(RString) name)
{
for (int i = 0; i < _enums->length(); ++i)
if (_enums[i]->getBaseName()->equals(name) == true)
return _enums[i];
return Nil;
}
bool
ModuleInfo::isKnownThrowable(IN(RString) name)
{
for (int i = 0; i < _knownExceptions->length(); ++i)
{
if (_knownExceptions[i]->equals(name) == true)
return true;
}
return false;
}
} // namespace mc
} // namespace tools
} // namespace acdk
|