summaryrefslogtreecommitdiff
path: root/cpp/src/slice2php/Main.cpp
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2009-06-23 17:47:58 -0700
committerMark Spruiell <mes@zeroc.com>2009-06-23 17:47:58 -0700
commita2e794a1366fcd71f04496c206869ffa158547ac (patch)
tree4c9d6554f3dc658aeaa76892aeecfc3d7eb56b61 /cpp/src/slice2php/Main.cpp
parentAdd x64 configurations to C++ projects (diff)
downloadice-a2e794a1366fcd71f04496c206869ffa158547ac.tar.bz2
ice-a2e794a1366fcd71f04496c206869ffa158547ac.tar.xz
ice-a2e794a1366fcd71f04496c206869ffa158547ac.zip
PHP changes:
- static translation - more traditional language mapping (multiple communicators, etc.) - support for registered (persistent) communicators - support for PHP namespaces (PHP 5.3 or later)
Diffstat (limited to 'cpp/src/slice2php/Main.cpp')
-rw-r--r--cpp/src/slice2php/Main.cpp1677
1 files changed, 1677 insertions, 0 deletions
diff --git a/cpp/src/slice2php/Main.cpp b/cpp/src/slice2php/Main.cpp
new file mode 100644
index 00000000000..9ad5e42935e
--- /dev/null
+++ b/cpp/src/slice2php/Main.cpp
@@ -0,0 +1,1677 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/DisableWarnings.h>
+#include <IceUtil/CtrlCHandler.h>
+#include <IceUtil/IceUtil.h>
+#include <IceUtil/InputUtil.h>
+#include <IceUtil/Options.h>
+#include <IceUtil/OutputUtil.h>
+#include <IceUtil/StringUtil.h>
+#include <IceUtil/StaticMutex.h>
+#include <Slice/Checksum.h>
+#include <Slice/Preprocessor.h>
+#include <Slice/FileTracker.h>
+#include <Slice/PHPUtil.h>
+#include <Slice/Util.h>
+#include <cstring>
+#include <climits>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+using namespace std;
+using namespace Slice;
+using namespace Slice::PHP;
+using namespace IceUtil;
+using namespace IceUtilInternal;
+
+//
+// CodeVisitor generates the PHP mapping for a translation unit.
+//
+class CodeVisitor : public ParserVisitor
+{
+public:
+
+ CodeVisitor(IceUtilInternal::Output&, bool);
+
+ virtual void visitClassDecl(const ClassDeclPtr&);
+ virtual bool visitClassDefStart(const ClassDefPtr&);
+ virtual bool visitExceptionStart(const ExceptionPtr&);
+ virtual bool visitStructStart(const StructPtr&);
+ virtual void visitSequence(const SequencePtr&);
+ virtual void visitDictionary(const DictionaryPtr&);
+ virtual void visitEnum(const EnumPtr&);
+ virtual void visitConst(const ConstPtr&);
+
+private:
+
+ void startNamespace(const ContainedPtr&);
+ void endNamespace();
+
+ //
+ // Return the PHP name for the given Slice type. When using namespaces,
+ // this name is a relative (unqualified) name, otherwise this name is the
+ // flattened absolute name.
+ //
+ string getName(const ContainedPtr&, const string& = string());
+
+ //
+ // Return the PHP variable for the given object's type.
+ //
+ string getTypeVar(const ContainedPtr&, const string& = string());
+
+ //
+ // Emit the array for a Slice type.
+ //
+ void writeType(const TypePtr&);
+
+ //
+ // Write a default value for a given type.
+ //
+ void writeDefaultValue(const TypePtr&);
+
+ struct MemberInfo
+ {
+ string fixedName;
+ TypePtr type;
+ bool inherited;
+ StringList metaData;
+ };
+ typedef list<MemberInfo> MemberInfoList;
+
+ //
+ // Write a member assignment statement for a constructor.
+ //
+ void writeAssign(const MemberInfo&);
+
+ //
+ // Convert an operation mode into a string.
+ //
+ string getOperationMode(Slice::Operation::Mode, bool);
+
+ void collectClassMembers(const ClassDefPtr&, MemberInfoList&, bool);
+ void collectExceptionMembers(const ExceptionPtr&, MemberInfoList&, bool);
+
+ Output& _out;
+ bool _ns; // Using namespaces?
+ list<string> _moduleStack; // TODO: Necessary?
+ set<string> _classHistory; // TODO: Necessary?
+};
+
+//
+// CodeVisitor implementation.
+//
+CodeVisitor::CodeVisitor(Output& out, bool ns) :
+ _out(out), _ns(ns)
+{
+}
+
+void
+CodeVisitor::visitClassDecl(const ClassDeclPtr& p)
+{
+ //
+ // Handle forward declarations.
+ //
+ string scoped = p->scoped();
+ string abs = getAbsolute(p, _ns);
+ if(_classHistory.count(scoped) == 0)
+ {
+ startNamespace(p);
+
+ string type = getTypeVar(p);
+ _out << sp << nl << "if(!isset(" << type << "))";
+ _out << sb;
+ _out << nl << type << " = IcePHP_declareClass('" << scoped << "');";
+ if(!p->isLocal())
+ {
+ _out << nl << type << "Prx = IcePHP_defineProxy(" << type << ");";
+ }
+ _out << eb;
+
+ endNamespace();
+
+ _classHistory.insert(scoped); // Avoid redundant declarations.
+ }
+}
+
+bool
+CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ string scoped = p->scoped();
+ string name = getName(p);
+ string type = getTypeVar(p);
+ string abs = getAbsolute(p, _ns);
+ string prxName = getName(p, "Prx");
+ string prxType = getTypeVar(p, "Prx");
+ string prxAbs = getAbsolute(p, _ns, "", "Prx");
+ ClassList bases = p->bases();
+ ClassDefPtr base;
+ OperationList ops = p->operations();
+ OperationList::iterator oli;
+ DataMemberList members = p->dataMembers();
+ bool isInterface = p->isInterface();
+ bool isAbstract = isInterface || p->allOperations().size() > 0; // Don't use isAbstract() - see bug 3739
+
+ startNamespace(p);
+
+ //
+ // Define the class.
+ //
+ if(isInterface)
+ {
+ _out << sp << nl << "if(!interface_exists('" << escapeName(abs) << "'))";
+ _out << sb;
+ _out << nl << "interface " << name;
+ if(!bases.empty())
+ {
+ _out << " extends ";
+ for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
+ {
+ if(q != bases.begin())
+ {
+ _out << ", ";
+ }
+ _out << getAbsolute(*q, _ns);
+ }
+ }
+ _out << sb;
+ for(oli = ops.begin(); oli != ops.end(); ++oli)
+ {
+ _out << nl << "public function " << fixIdent((*oli)->name()) << '(';
+ ParamDeclList params = (*oli)->parameters();
+ for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q)
+ {
+ if(q != params.begin())
+ {
+ _out << ", ";
+ }
+ _out << '$' << fixIdent((*q)->name());
+ }
+ _out << ");";
+ }
+ _out << eb;
+ }
+ else
+ {
+ _out << sp << nl << "if(!class_exists('" << escapeName(abs) << "'))";
+ _out << sb;
+ _out << nl;
+ if(isAbstract)
+ {
+ _out << "abstract ";
+ }
+ _out << "class " << name;
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ base = bases.front();
+ bases.pop_front();
+ }
+ if(base)
+ {
+ _out << " extends " << getAbsolute(base, _ns);
+ }
+ else
+ {
+ if(!p->isLocal())
+ {
+ _out << " extends " << scopedToName("::Ice::ObjectImpl", _ns);
+ }
+ }
+ if(!bases.empty())
+ {
+ _out << " implements ";
+ for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
+ {
+ if(q != bases.begin())
+ {
+ _out << ", ";
+ }
+ _out << getAbsolute(*q, _ns);
+ }
+ }
+
+ _out << sb;
+
+ //
+ // __construct
+ //
+ _out << nl << "public function __construct(";
+ MemberInfoList allMembers;
+ collectClassMembers(p, allMembers, false);
+ if(!allMembers.empty())
+ {
+ for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(q != allMembers.begin())
+ {
+ _out << ", ";
+ }
+ _out << '$' << q->fixedName << '=';
+ writeDefaultValue(q->type);
+ }
+ }
+ _out << ")";
+ _out << sb;
+ if(base)
+ {
+ _out << nl << "parent::__construct(";
+ int count = 0;
+ for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(q->inherited)
+ {
+ if(count)
+ {
+ _out << ", ";
+ }
+ _out << '$' << q->fixedName;
+ ++count;
+ }
+ }
+ _out << ");";
+ }
+ {
+ for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(!q->inherited)
+ {
+ writeAssign(*q);
+ }
+ }
+ }
+ _out << eb;
+
+ if(!ops.empty())
+ {
+ _out << sp;
+ for(oli = ops.begin(); oli != ops.end(); ++oli)
+ {
+ _out << nl << "abstract public function " << fixIdent((*oli)->name()) << '(';
+ ParamDeclList params = (*oli)->parameters();
+ for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q)
+ {
+ if(q != params.begin())
+ {
+ _out << ", ";
+ }
+ _out << '$' << fixIdent((*q)->name());
+ }
+ _out << ");";
+ }
+ }
+
+ if(!p->isLocal())
+ {
+ //
+ // ice_staticId
+ //
+ _out << sp << nl << "public static function ice_staticId()";
+ _out << sb;
+ _out << nl << "return '" << scoped << "';";
+ _out << eb;
+ }
+
+ //
+ // __toString
+ //
+ _out << sp << nl << "public function __toString()";
+ _out << sb;
+ _out << nl << "global " << type << ';';
+ _out << nl << "return IcePHP_stringify($this, " << type << ");";
+ _out << eb;
+
+ if(!members.empty())
+ {
+ _out << sp;
+ bool isProtected = p->hasMetaData("protected");
+ for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ _out << nl;
+ if(isProtected || (*q)->hasMetaData("protected"))
+ {
+ _out << "protected ";
+ }
+ else
+ {
+ _out << "public ";
+ }
+ _out << "$" << fixIdent((*q)->name()) << ";";
+ }
+ }
+
+ _out << eb; // End of class.
+ }
+
+ //
+ // Define the proxy class.
+ //
+ if(!p->isLocal())
+ {
+ _out << sp << nl << "class " << prxName << "Helper";
+ _out << sb;
+
+ _out << sp << nl << "public static function checkedCast($proxy, $facetOrCtx=null, $ctx=null)";
+ _out << sb;
+ _out << nl << "return $proxy->ice_checkedCast('" << scoped << "', $facetOrCtx, $ctx);";
+ _out << eb;
+
+ _out << sp << nl << "public static function uncheckedCast($proxy, $facet=null)";
+ _out << sb;
+ _out << nl << "return $proxy->ice_uncheckedCast('" << scoped << "', $facet);";
+ _out << eb;
+
+ _out << eb;
+ }
+
+ if(_classHistory.count(scoped) == 0 && p->canBeCyclic())
+ {
+ //
+ // Emit a forward declaration for the class in case a data member refers to this type.
+ //
+ _out << sp << nl << type << " = IcePHP_declareClass('" << scoped << "');";
+ }
+
+ //
+ // Emit the type information.
+ //
+ _out << sp << nl << type << " = IcePHP_defineClass('" << scoped << "', '" << escapeName(abs) << "', "
+ << (isAbstract ? "true" : "false") << ", ";
+ if(!base)
+ {
+ _out << "$Ice__t_Object";
+ }
+ else
+ {
+ _out << getTypeVar(base);
+ }
+ _out << ", ";
+ //
+ // Interfaces
+ //
+ if(!bases.empty())
+ {
+ _out << "array(";
+ for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
+ {
+ if(q != bases.begin())
+ {
+ _out << ", ";
+ }
+ _out << getTypeVar(*q);
+ }
+ _out << ')';
+ }
+ else
+ {
+ _out << "null";
+ }
+ _out << ", ";
+ //
+ // Members
+ //
+ // Data members are represented as an array:
+ //
+ // ('MemberName', MemberType)
+ //
+ // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type.
+ //
+ if(!members.empty())
+ {
+ _out << "array(";
+ for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ if(q != members.begin())
+ {
+ _out << ',' << nl;
+ }
+ _out.inc();
+ _out << nl << "array('" << fixIdent((*q)->name()) << "', ";
+ writeType((*q)->type());
+ _out << ')';
+ _out.dec();
+ }
+ _out << ')';
+ }
+ else
+ {
+ _out << "null";
+ }
+ _out << ");";
+
+ if(!p->isLocal())
+ {
+ _out << sp << nl << prxType << " = IcePHP_defineProxy(" << type << ");";
+
+ //
+ // Define each operation. The arguments to IcePHP_defineOperation are:
+ //
+ // $ClassType, 'opName', Mode, SendMode, (InParams), (OutParams), ReturnType, (Exceptions)
+ //
+ // where InParams and OutParams are arrays of type descriptions, and Exceptions
+ // is an array of exception type ids.
+ //
+ if(!ops.empty())
+ {
+ _out << sp;
+ for(oli = ops.begin(); oli != ops.end(); ++oli)
+ {
+ ParamDeclList params = (*oli)->parameters();
+ ParamDeclList::iterator t;
+ int count;
+
+ _out << nl << "IcePHP_defineOperation(" << type << ", '" << (*oli)->name() << "', "
+ << getOperationMode((*oli)->mode(), _ns) << ", " << getOperationMode((*oli)->sendMode(), _ns)
+ << ", ";
+ for(t = params.begin(), count = 0; t != params.end(); ++t)
+ {
+ if(!(*t)->isOutParam())
+ {
+ if(count == 0)
+ {
+ _out << "array(";
+ }
+ else if(count > 0)
+ {
+ _out << ", ";
+ }
+ writeType((*t)->type());
+ ++count;
+ }
+ }
+ if(count > 0)
+ {
+ _out << ')';
+ }
+ else
+ {
+ _out << "null";
+ }
+ _out << ", ";
+ for(t = params.begin(), count = 0; t != params.end(); ++t)
+ {
+ if((*t)->isOutParam())
+ {
+ if(count == 0)
+ {
+ _out << "array(";
+ }
+ else if(count > 0)
+ {
+ _out << ", ";
+ }
+ writeType((*t)->type());
+ ++count;
+ }
+ }
+ if(count > 0)
+ {
+ _out << ')';
+ }
+ else
+ {
+ _out << "null";
+ }
+ _out << ", ";
+ TypePtr returnType = (*oli)->returnType();
+ if(returnType)
+ {
+ writeType(returnType);
+ }
+ else
+ {
+ _out << "null";
+ }
+ _out << ", ";
+ ExceptionList exceptions = (*oli)->throws();
+ if(!exceptions.empty())
+ {
+ _out << "array(";
+ for(ExceptionList::iterator u = exceptions.begin(); u != exceptions.end(); ++u)
+ {
+ if(u != exceptions.begin())
+ {
+ _out << ", ";
+ }
+ _out << getTypeVar(*u);
+ }
+ _out << ')';
+ }
+ else
+ {
+ _out << "null";
+ }
+ _out << ");";
+ }
+ }
+ }
+
+ _out << eb;
+
+ endNamespace();
+
+ if(_classHistory.count(scoped) == 0)
+ {
+ _classHistory.insert(scoped); // Avoid redundant declarations.
+ }
+
+ return false;
+}
+
+bool
+CodeVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ string scoped = p->scoped();
+ string name = getName(p);
+ string type = getTypeVar(p);
+ string abs = getAbsolute(p, _ns);
+
+ startNamespace(p);
+
+ _out << sp << nl << "if(!class_exists('" << escapeName(abs) << "'))";
+ _out << sb;
+ _out << nl << "class " << name << " extends ";
+ ExceptionPtr base = p->base();
+ string baseName;
+ if(base)
+ {
+ baseName = getAbsolute(base, _ns);
+ _out << baseName;
+ }
+ else if(p->isLocal())
+ {
+ _out << scopedToName("::Ice::LocalException", _ns);
+ }
+ else
+ {
+ _out << scopedToName("::Ice::UserException", _ns);
+ }
+ _out << sb;
+
+ DataMemberList members = p->dataMembers();
+ DataMemberList::iterator dmli;
+
+ //
+ // __construct
+ //
+ _out << nl << "public function __construct(";
+ MemberInfoList allMembers;
+ collectExceptionMembers(p, allMembers, false);
+ if(!allMembers.empty())
+ {
+ for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(q != allMembers.begin())
+ {
+ _out << ", ";
+ }
+ _out << '$' << q->fixedName << '=';
+ writeDefaultValue(q->type);
+ }
+ }
+ _out << ")";
+ _out << sb;
+ if(base)
+ {
+ _out << nl << "parent::__construct(";
+ int count = 0;
+ for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(q->inherited)
+ {
+ if(count)
+ {
+ _out << ", ";
+ }
+ _out << '$' << q->fixedName;
+ ++count;
+ }
+ }
+ _out << ");";
+ }
+ for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(!q->inherited)
+ {
+ writeAssign(*q);
+ }
+ }
+ _out << eb;
+
+ //
+ // ice_name
+ //
+ _out << sp << nl << "public function ice_name()";
+ _out << sb;
+ _out << nl << "return '" << scoped.substr(2) << "';";
+ _out << eb;
+
+ //
+ // __toString
+ //
+ _out << sp << nl << "public function __toString()";
+ _out << sb;
+ _out << nl << "global " << type << ';';
+ _out << nl << "return IcePHP_stringifyException($this, " << type << ");";
+ _out << eb;
+
+ if(!members.empty())
+ {
+ _out << sp;
+ for(dmli = members.begin(); dmli != members.end(); ++dmli)
+ {
+ _out << nl << "public $" << fixIdent((*dmli)->name()) << ";";
+ }
+ }
+
+ _out << eb;
+
+ //
+ // Emit the type information.
+ //
+ _out << sp << nl << type << " = IcePHP_defineException('" << scoped << "', '" << escapeName(abs) << "', ";
+ if(!base)
+ {
+ _out << "null";
+ }
+ else
+ {
+ _out << getTypeVar(base);
+ }
+ _out << ", ";
+ //
+ // Data members are represented as an array:
+ //
+ // ('MemberName', MemberType)
+ //
+ // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type.
+ //
+ if(!members.empty())
+ {
+ _out << "array(";
+ for(dmli = members.begin(); dmli != members.end(); ++dmli)
+ {
+ if(dmli != members.begin())
+ {
+ _out << ',' << nl;
+ }
+ _out.inc();
+ _out << nl << "array('" << fixIdent((*dmli)->name()) << "', ";
+ writeType((*dmli)->type());
+ _out << ')';
+ _out.dec();
+ }
+ _out << ')';
+ }
+ else
+ {
+ _out << "null";
+ }
+ _out << ");";
+
+ _out << eb;
+
+ endNamespace();
+
+ return false;
+}
+
+bool
+CodeVisitor::visitStructStart(const StructPtr& p)
+{
+ string scoped = p->scoped();
+ string name = getName(p);
+ string type = getTypeVar(p);
+ string abs = getAbsolute(p, _ns);
+ MemberInfoList memberList;
+ MemberInfoList::iterator r;
+
+ {
+ DataMemberList members = p->dataMembers();
+ for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ memberList.push_back(MemberInfo());
+ memberList.back().fixedName = fixIdent((*q)->name());
+ memberList.back().type = (*q)->type();
+ memberList.back().metaData = (*q)->getMetaData();
+ }
+ }
+
+ startNamespace(p);
+
+ _out << sp << nl << "if(!class_exists('" << escapeName(abs) << "'))";
+ _out << sb;
+
+ _out << nl << "class " << name;
+ _out << sb;
+ _out << nl << "public function __construct(";
+ for(r = memberList.begin(); r != memberList.end(); ++r)
+ {
+ if(r != memberList.begin())
+ {
+ _out << ", ";
+ }
+ _out << '$' << r->fixedName << '=';
+ writeDefaultValue(r->type);
+ }
+ _out << ")";
+ _out << sb;
+ for(r = memberList.begin(); r != memberList.end(); ++r)
+ {
+ writeAssign(*r);
+ }
+ _out << eb;
+
+ //
+ // __toString
+ //
+ _out << sp << nl << "public function __toString()";
+ _out << sb;
+ _out << nl << "global " << type << ';';
+ _out << nl << "return IcePHP_stringify($this, " << type << ");";
+ _out << eb;
+
+ if(!memberList.empty())
+ {
+ _out << sp;
+ for(r = memberList.begin(); r != memberList.end(); ++r)
+ {
+ _out << nl << "public $" << r->fixedName << ';';
+ }
+ }
+
+ _out << eb;
+
+ //
+ // Emit the type information.
+ //
+ _out << sp << nl << type << " = IcePHP_defineStruct('" << scoped << "', '" << escapeName(abs) << "', array(";
+ //
+ // Data members are represented as an array:
+ //
+ // ('MemberName', MemberType)
+ //
+ // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type.
+ //
+ for(r = memberList.begin(); r != memberList.end(); ++r)
+ {
+ if(r != memberList.begin())
+ {
+ _out << ", ";
+ }
+ _out.inc();
+ _out << nl << "array('" << r->fixedName << "', ";
+ writeType(r->type);
+ _out << ')';
+ _out.dec();
+ }
+ _out << "));";
+
+ _out << eb;
+
+ endNamespace();
+
+ return false;
+}
+
+void
+CodeVisitor::visitSequence(const SequencePtr& p)
+{
+ string type = getTypeVar(p);
+ TypePtr content = p->type();
+
+ startNamespace(p);
+
+ //
+ // Emit the type information.
+ //
+ string scoped = p->scoped();
+ _out << sp << nl << "if(!isset(" << type << "))";
+ _out << sb;
+ _out << nl << type << " = IcePHP_defineSequence('" << scoped << "', ";
+ writeType(content);
+ _out << ", ";
+ if(content->isVariableLength())
+ {
+ _out << "true";
+ }
+ else
+ {
+ _out << "false";
+ }
+ _out << ", " << content->minWireSize() << ");";
+ _out << eb;
+
+ endNamespace();
+}
+
+void
+CodeVisitor::visitDictionary(const DictionaryPtr& p)
+{
+ string type = getTypeVar(p);
+
+ startNamespace(p);
+
+ //
+ // Emit the type information.
+ //
+ string scoped = p->scoped();
+ _out << sp << nl << "if(!isset(" << type << "))";
+ _out << sb;
+ _out << nl << type << " = IcePHP_defineDictionary('" << scoped << "', ";
+ writeType(p->keyType());
+ _out << ", ";
+ writeType(p->valueType());
+ _out << ");";
+ _out << eb;
+
+ endNamespace();
+}
+
+void
+CodeVisitor::visitEnum(const EnumPtr& p)
+{
+ string scoped = p->scoped();
+ string name = getName(p);
+ string type = getTypeVar(p);
+ string abs = getAbsolute(p, _ns);
+ EnumeratorList enums = p->getEnumerators();
+ EnumeratorList::iterator q;
+ long i;
+
+ startNamespace(p);
+
+ _out << sp << nl << "if(!class_exists('" << escapeName(abs) << "'))";
+ _out << sb;
+ _out << nl << "class " << name;
+ _out << sb;
+
+ for(q = enums.begin(), i = 0; q != enums.end(); ++q, ++i)
+ {
+ string fixedEnum = fixIdent((*q)->name());
+ ostringstream idx;
+ idx << i;
+ _out << nl << "const " << fixedEnum << " = " << idx.str() << ';';
+ }
+
+ _out << eb;
+
+ //
+ // Emit the type information.
+ //
+ _out << sp << nl << type << " = IcePHP_defineEnum('" << scoped << "', array(";
+ for(q = enums.begin(); q != enums.end(); ++q)
+ {
+ if(q != enums.begin())
+ {
+ _out << ", ";
+ }
+ _out << "'" << (*q)->name() << "'";
+ }
+ _out << "));";
+
+ _out << eb;
+
+ endNamespace();
+}
+
+void
+CodeVisitor::visitConst(const ConstPtr& p)
+{
+ string name = getName(p);
+ string type = getTypeVar(p);
+ string abs = getAbsolute(p, _ns);
+ string value = p->value();
+ Slice::TypePtr valueType = p->type();
+
+ startNamespace(p);
+
+ _out << sp << nl << "if(!defined('" << escapeName(abs) << "'))";
+ _out << sb;
+ _out << sp << nl << "define('" << name << "', ";
+
+ Slice::BuiltinPtr b = Slice::BuiltinPtr::dynamicCast(valueType);
+ Slice::EnumPtr en = Slice::EnumPtr::dynamicCast(valueType);
+ if(b)
+ {
+ switch(b->kind())
+ {
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ {
+ _out << value;
+ break;
+ }
+ case Slice::Builtin::KindLong:
+ {
+ IceUtil::Int64 l;
+ IceUtilInternal::stringToInt64(value, l);
+ //
+ // The platform's 'long' type may not be 64 bits, so we store 64-bit
+ // values as a string.
+ //
+ if(sizeof(IceUtil::Int64) > sizeof(long) && (l < LONG_MIN || l > LONG_MAX))
+ {
+ _out << "'" << value << "'";
+ }
+ else
+ {
+ _out << value;
+ }
+ break;
+ }
+
+ case Slice::Builtin::KindString:
+ {
+ //
+ // Expand strings into the basic source character set. We can't use isalpha() and the like
+ // here because they are sensitive to the current locale.
+ //
+ static const string basicSourceChars = "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "_{}[]#()<>%:;.?*+-/^&|~!=, '";
+ static const set<char> charSet(basicSourceChars.begin(), basicSourceChars.end());
+
+ _out << "\""; // Opening "
+
+ for(string::const_iterator c = value.begin(); c != value.end(); ++c)
+ {
+ switch(*c)
+ {
+ case '$':
+ {
+ _out << "\\$";
+ break;
+ }
+ case '"':
+ {
+ _out << "\\\"";
+ break;
+ }
+ case '\\':
+ {
+ _out << "\\\\";
+ break;
+ }
+ case '\r':
+ {
+ _out << "\\r";
+ break;
+ }
+ case '\n':
+ {
+ _out << "\\n";
+ break;
+ }
+ case '\t':
+ {
+ _out << "\\t";
+ break;
+ }
+ case '\b':
+ {
+ _out << "\\b";
+ break;
+ }
+ case '\f':
+ {
+ _out << "\\f";
+ break;
+ }
+ default:
+ {
+ if(charSet.find(*c) == charSet.end())
+ {
+ unsigned char uc = *c; // Char may be signed, so make it positive.
+ stringstream s;
+ s << "\\"; // Print as octal if not in basic source character set.
+ s.flags(ios_base::oct);
+ s.width(3);
+ s.fill('0');
+ s << static_cast<unsigned>(uc);
+ _out << s.str();
+ }
+ else
+ {
+ _out << *c; // Print normally if in basic source character set.
+ }
+ break;
+ }
+ }
+ }
+
+ _out << "\""; // Closing "
+ break;
+ }
+
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+ }
+ else if(en)
+ {
+ string::size_type colon = value.rfind(':');
+ if(colon != string::npos)
+ {
+ value = value.substr(colon + 1);
+ }
+ Slice::EnumeratorList l = en->getEnumerators();
+ Slice::EnumeratorList::iterator q;
+ for(q = l.begin(); q != l.end(); ++q)
+ {
+ if((*q)->name() == value)
+ {
+ _out << getAbsolute(en, _ns) << "::" << fixIdent(value);
+ break;
+ }
+ }
+ }
+ else
+ {
+ assert(false); // Unknown const type.
+ }
+
+ _out << ");";
+ _out << eb;
+
+ endNamespace();
+}
+
+void
+CodeVisitor::startNamespace(const ContainedPtr& cont)
+{
+ if(_ns)
+ {
+ string scope = cont->scope();
+ scope = scope.substr(2); // Removing leading '::'
+ scope = scope.substr(0, scope.length() - 2); // Removing trailing '::'
+ _out << sp << nl << "namespace " << scopedToName(scope, true);
+ _out << sb;
+ }
+}
+
+void
+CodeVisitor::endNamespace()
+{
+ if(_ns)
+ {
+ _out << eb;
+ }
+}
+
+string
+CodeVisitor::getTypeVar(const ContainedPtr& p, const string& suffix)
+{
+ return "$" + getAbsolute(p, false, "_t_", suffix);
+}
+
+string
+CodeVisitor::getName(const ContainedPtr& p, const string& suffix)
+{
+ if(_ns)
+ {
+ return fixIdent(p->name() + suffix);
+ }
+ else
+ {
+ return getAbsolute(p, false, "", suffix);
+ }
+}
+
+void
+CodeVisitor::writeType(const TypePtr& p)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindBool:
+ {
+ _out << "$IcePHP__t_bool";
+ break;
+ }
+ case Builtin::KindByte:
+ {
+ _out << "$IcePHP__t_byte";
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ _out << "$IcePHP__t_short";
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ _out << "$IcePHP__t_int";
+ break;
+ }
+ case Builtin::KindLong:
+ {
+ _out << "$IcePHP__t_long";
+ break;
+ }
+ case Builtin::KindFloat:
+ {
+ _out << "$IcePHP__t_float";
+ break;
+ }
+ case Builtin::KindDouble:
+ {
+ _out << "$IcePHP__t_double";
+ break;
+ }
+ case Builtin::KindString:
+ {
+ _out << "$IcePHP__t_string";
+ break;
+ }
+ case Builtin::KindObject:
+ {
+ _out << "$Ice__t_Object";
+ break;
+ }
+ case Builtin::KindObjectProxy:
+ {
+ _out << "$Ice__t_ObjectPrx";
+ break;
+ }
+ case Builtin::KindLocalObject:
+ {
+ _out << "$Ice__t_LocalObject";
+ break;
+ }
+ }
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(p);
+ if(prx)
+ {
+ _out << getTypeVar(prx->_class(), "Prx");
+ return;
+ }
+
+ ContainedPtr cont = ContainedPtr::dynamicCast(p);
+ assert(cont);
+ _out << getTypeVar(cont);
+}
+
+void
+CodeVisitor::writeDefaultValue(const TypePtr& p)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindBool:
+ {
+ _out << "false";
+ break;
+ }
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ {
+ _out << "0";
+ break;
+ }
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ {
+ _out << "0.0";
+ break;
+ }
+ case Builtin::KindString:
+ {
+ _out << "''";
+ break;
+ }
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ _out << "null";
+ break;
+ }
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(p);
+ if(en)
+ {
+ EnumeratorList enums = en->getEnumerators();
+ _out << getAbsolute(en, _ns) << "::" << fixIdent(enums.front()->name());
+ return;
+ }
+
+ //
+ // PHP does not allow the following construct:
+ //
+ // function foo($theStruct=new MyStructType)
+ //
+ // Instead we use null as the default value and allocate an instance in
+ // the constructor.
+ //
+ StructPtr st = StructPtr::dynamicCast(p);
+ if(st)
+ {
+ _out << "null";
+ return;
+ }
+
+ _out << "null";
+}
+
+void
+CodeVisitor::writeAssign(const MemberInfo& info)
+{
+ StructPtr st = StructPtr::dynamicCast(info.type);
+ if(st)
+ {
+ _out << nl << "$this->" << info.fixedName << " = is_null($" << info.fixedName << ") ? new "
+ << getAbsolute(st, _ns) << " : $" << info.fixedName << ';';
+ }
+ else
+ {
+ _out << nl << "$this->" << info.fixedName << " = $" << info.fixedName << ';';
+ }
+}
+
+string
+CodeVisitor::getOperationMode(Slice::Operation::Mode mode, bool ns)
+{
+ ostringstream ostr;
+ ostr << static_cast<int>(mode);
+ return ostr.str();
+}
+
+void
+CodeVisitor::collectClassMembers(const ClassDefPtr& p, MemberInfoList& allMembers, bool inherited)
+{
+ ClassList bases = p->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ collectClassMembers(bases.front(), allMembers, true);
+ }
+
+ DataMemberList members = p->dataMembers();
+
+ for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ MemberInfo m;
+ m.fixedName = fixIdent((*q)->name());
+ m.type = (*q)->type();
+ m.inherited = inherited;
+ m.metaData = (*q)->getMetaData();
+ allMembers.push_back(m);
+ }
+}
+
+void
+CodeVisitor::collectExceptionMembers(const ExceptionPtr& p, MemberInfoList& allMembers, bool inherited)
+{
+ ExceptionPtr base = p->base();
+ if(base)
+ {
+ collectExceptionMembers(base, allMembers, true);
+ }
+
+ DataMemberList members = p->dataMembers();
+
+ for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ MemberInfo m;
+ m.fixedName = fixIdent((*q)->name());
+ m.type = (*q)->type();
+ m.inherited = inherited;
+ m.metaData = (*q)->getMetaData();
+ allMembers.push_back(m);
+ }
+}
+
+static void
+generate(const UnitPtr& un, bool all, bool checksum, bool ns, const vector<string>& includePaths, Output& out)
+{
+ if(!all)
+ {
+ vector<string> paths = includePaths;
+ for(vector<string>::iterator p = paths.begin(); p != paths.end(); ++p)
+ {
+ *p = fullPath(*p);
+ }
+
+ StringList includes = un->includeFiles();
+ if(!includes.empty())
+ {
+ if(ns)
+ {
+ out << sp;
+ out << nl << "namespace";
+ out << sb;
+ }
+ for(StringList::const_iterator q = includes.begin(); q != includes.end(); ++q)
+ {
+ string file = changeInclude(*q, paths);
+ out << nl << "require '" << file << ".php';";
+ }
+ if(ns)
+ {
+ out << eb;
+ }
+ }
+ }
+
+ CodeVisitor codeVisitor(out, ns);
+ un->visit(&codeVisitor, false);
+
+ if(checksum)
+ {
+ ChecksumMap checksums = createChecksums(un);
+ if(!checksums.empty())
+ {
+ out << sp;
+ if(ns)
+ {
+ out << "namespace"; // Global namespace.
+ out << sb;
+ }
+ for(ChecksumMap::const_iterator p = checksums.begin(); p != checksums.end(); ++p)
+ {
+ out << nl << "$Ice_sliceChecksums[\"" << p->first << "\"] = \"";
+ ostringstream str;
+ str.flags(ios_base::hex);
+ str.fill('0');
+ for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q)
+ {
+ str << (int)(*q);
+ }
+ out << str.str() << "\";";
+ }
+ if(ns)
+ {
+ out << eb;
+ }
+ }
+ }
+
+ out << nl; // Trailing newline.
+}
+
+static void
+printHeader(IceUtilInternal::Output& out)
+{
+ static const char* header =
+"// **********************************************************************\n"
+"//\n"
+"// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.\n"
+"//\n"
+"// This copy of Ice is licensed to you under the terms described in the\n"
+"// ICE_LICENSE file included in this distribution.\n"
+"//\n"
+"// **********************************************************************\n"
+ ;
+
+ out << header;
+ out << "\n// Ice version " << ICE_STRING_VERSION;
+}
+
+static IceUtil::StaticMutex _mutex = ICE_STATIC_MUTEX_INITIALIZER;
+static bool _interrupted = false;
+
+void
+interruptedCallback(int signal)
+{
+ IceUtil::StaticMutex::Lock lock(_mutex);
+
+ _interrupted = true;
+}
+
+void
+usage(const char* n)
+{
+ cerr << "Usage: " << n << " [options] slice-files...\n";
+ cerr <<
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-DNAME Define NAME as 1.\n"
+ "-DNAME=DEF Define NAME as DEF.\n"
+ "-UNAME Remove any definition for NAME.\n"
+ "-IDIR Put DIR in the include file search path.\n"
+ "-E Print preprocessor output on stdout.\n"
+ "--output-dir DIR Create files in the directory DIR.\n"
+ "-d, --debug Print debug messages.\n"
+ "--ice Permit `Ice' prefix (for building Ice source code only)\n"
+ "--all Generate code for Slice definitions in included files.\n"
+ "--checksum Generate checksums for Slice definitions.\n"
+ "-n, --namespace Use PHP namespaces (requires PHP 5.3.0 or later).\n"
+ ;
+}
+
+int
+main(int argc, char* argv[])
+{
+ IceUtilInternal::Options opts;
+ opts.addOpt("h", "help");
+ opts.addOpt("v", "version");
+ opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("E");
+ opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg);
+ opts.addOpt("d", "debug");
+ opts.addOpt("", "ice");
+ opts.addOpt("", "all");
+ opts.addOpt("", "checksum");
+ opts.addOpt("n", "namespace");
+
+ vector<string> args;
+ try
+ {
+#if defined(__BCPLUSPLUS__) && (__BCPLUSPLUS__ >= 0x0600)
+ IceUtil::DummyBCC dummy;
+#endif
+ args = opts.parse(argc, (const char**)argv);
+ }
+ catch(const IceUtilInternal::BadOptException& e)
+ {
+ cerr << argv[0] << ": error: " << e.reason << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if(opts.isSet("help"))
+ {
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if(opts.isSet("version"))
+ {
+ cerr << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+
+ vector<string> cppArgs;
+ vector<string> optargs = opts.argVec("D");
+ vector<string>::const_iterator i;
+ for(i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs.push_back("-D" + *i);
+ }
+
+ optargs = opts.argVec("U");
+ for(i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs.push_back("-U" + *i);
+ }
+
+ vector<string> includePaths = opts.argVec("I");
+ for(i = includePaths.begin(); i != includePaths.end(); ++i)
+ {
+ cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
+ }
+
+ bool preprocess = opts.isSet("E");
+
+ string output = opts.optArg("output-dir");
+
+ bool debug = opts.isSet("debug");
+
+ bool ice = opts.isSet("ice");
+
+ bool all = opts.isSet("all");
+
+ bool checksum = opts.isSet("checksum");
+
+ bool ns = opts.isSet("namespace");
+
+ if(args.empty())
+ {
+ getErrorStream() << argv[0] << ": error: no input file" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ int status = EXIT_SUCCESS;
+
+ IceUtil::CtrlCHandler ctrlCHandler;
+ ctrlCHandler.setCallback(interruptedCallback);
+
+ for(i = args.begin(); i != args.end(); ++i)
+ {
+ Preprocessor icecpp(argv[0], *i, cppArgs);
+ FILE* cppHandle = icecpp.preprocess(false);
+
+ if(cppHandle == 0)
+ {
+ return EXIT_FAILURE;
+ }
+
+ if(preprocess)
+ {
+ char buf[4096];
+ while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != NULL)
+ {
+ if(fputs(buf, stdout) == EOF)
+ {
+ return EXIT_FAILURE;
+ }
+ }
+ if(!icecpp.close())
+ {
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ UnitPtr u = Unit::createUnit(false, all, ice);
+ int parseStatus = u->parse(*i, cppHandle, debug);
+
+ if(!icecpp.close())
+ {
+ u->destroy();
+ return EXIT_FAILURE;
+ }
+
+ if(parseStatus == EXIT_FAILURE)
+ {
+ status = EXIT_FAILURE;
+ }
+ else
+ {
+ string base = icecpp.getBaseName();
+ string::size_type pos = base.find_last_of("/\\");
+ if(pos != string::npos)
+ {
+ base.erase(0, pos + 1);
+ }
+
+ string file = base + ".php";
+ if(!output.empty())
+ {
+ file = output + '/' + file;
+ }
+
+ try
+ {
+ IceUtilInternal::Output out;
+ out.open(file.c_str());
+ if(!out)
+ {
+ ostringstream os;
+ os << "cannot open`" << file << "': " << strerror(errno);
+ throw FileException(__FILE__, __LINE__, os.str());
+ }
+ FileTracker::instance()->addFile(file);
+
+ out << "<?php\n";
+ printHeader(out);
+ out << "\n// Generated from file `" << base << ".ice'\n";
+
+ //
+ // Generate the PHP mapping.
+ //
+ generate(u, all, checksum, ns, includePaths, out);
+
+ out << "?>\n";
+ out.close();
+ }
+ catch(const Slice::FileException& ex)
+ {
+ // If a file could not be created, then cleanup any
+ // created files.
+ FileTracker::instance()->cleanup();
+ u->destroy();
+ getErrorStream() << argv[0] << ": error: " << ex.reason() << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const string& err)
+ {
+ FileTracker::instance()->cleanup();
+ getErrorStream() << argv[0] << ": error: " << err << endl;
+ status = EXIT_FAILURE;
+ }
+ }
+
+ u->destroy();
+ }
+
+ {
+ IceUtil::StaticMutex::Lock lock(_mutex);
+
+ if(_interrupted)
+ {
+ FileTracker::instance()->cleanup();
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ return status;
+}