Browse Source

Basic Wiring for CSharp

Josh Engebretson 10 years ago
parent
commit
0aae7e8283

+ 1 - 2
Source/ToolCore/Command/BindCmd.cpp

@@ -70,9 +70,7 @@ void BindCmd::Run()
 {
 {
     ToolEnvironment* env = GetSubsystem<ToolEnvironment>();
     ToolEnvironment* env = GetSubsystem<ToolEnvironment>();
 
 
-    //bindPlatform_ = "MACOSX";
     sourceRootFolder_ = env->GetRootSourceDir();
     sourceRootFolder_ = env->GetRootSourceDir();
-    //packageFolder_ = "Source/AtomicJS/Packages/Atomic/";
 
 
     SharedPtr<JSBind> jsbind(new JSBind(context_));
     SharedPtr<JSBind> jsbind(new JSBind(context_));
 
 
@@ -81,6 +79,7 @@ void BindCmd::Run()
     LOGINFOF("Generating JS Bindings");
     LOGINFOF("Generating JS Bindings");
 
 
     jsbind->GenerateBindings(sourceRootFolder_, packageFolder_, bindPlatform_);
     jsbind->GenerateBindings(sourceRootFolder_, packageFolder_, bindPlatform_);
+    jsbind->GenerateCSharpBindings(sourceRootFolder_, packageFolder_, bindPlatform_);
 
 
     Finished();
     Finished();
 
 

+ 95 - 0
Source/ToolCore/JSBind/CSharp/CSBClassWriter.cpp

@@ -0,0 +1,95 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#include <Atomic/IO/FileSystem.h>
+
+#include "../JSBind.h"
+#include "../JSBModule.h"
+#include "../JSBPackage.h"
+#include "../JSBEnum.h"
+#include "../JSBClass.h"
+#include "../JSBFunction.h"
+
+#include "CSBClassWriter.h"
+#include "CSBFunctionWriter.h"
+
+namespace ToolCore
+{
+
+CSBClassWriter::CSBClassWriter(JSBClass *klass) : klass_(klass)
+{
+
+}
+
+
+void CSBClassWriter::WriteFunctions(String& source)
+{
+    for (unsigned i = 0; i < klass_->functions_.Size(); i++)
+    {
+        JSBFunction* function = klass_->functions_.At(i);
+
+        if (function->Skip())
+            continue;
+
+        if (function->IsDestructor())
+            continue;
+
+        CSBFunctionWriter writer(function);
+        writer.GenerateSource(source);
+    }
+
+}
+
+void CSBClassWriter::GenerateSource(String& sourceOut)
+{
+    String source = "";
+
+    if (klass_->IsNumberArray())
+        return;
+
+    WriteFunctions(source);
+
+    String packageName = klass_->GetModule()->GetPackage()->GetName();
+
+    source.AppendWithFormat("static void jsb_class_define_%s(JSVM* vm)\n{\n", klass_->GetName().CString());
+    source.Append("duk_context* ctx = vm->GetJSContext();\n");
+    source.AppendWithFormat("js_class_get_prototype(ctx, \"%s\", \"%s\");\n", packageName.CString(), klass_->GetName().CString());
+
+    for (unsigned i = 0; i < klass_->functions_.Size(); i++)
+    {
+        JSBFunction* function = klass_->functions_.At(i);
+
+        if (function->Skip())
+            continue;
+
+        if (function->IsConstructor() || function->IsDestructor())
+            continue;
+
+        if (function->FirstDefaultParameter() != -1)
+        {
+            source.AppendWithFormat("duk_push_c_function(ctx, jsb_class_%s_%s, DUK_VARARGS);\n", klass_->GetName().CString(), function->GetName().CString());
+        }
+        else
+        {
+            source.AppendWithFormat("duk_push_c_function(ctx, jsb_class_%s_%s, %i);\n", klass_->GetName().CString(), function->GetName().CString(), (int) function->GetParameters().Size());
+        }
+
+        String scriptName =  function->GetName();
+        scriptName[0] = tolower(scriptName[0]);
+        source.AppendWithFormat("duk_put_prop_string(ctx, -2, \"%s\");\n", scriptName.CString());
+
+    }
+
+    source.Append("duk_pop(ctx);\n");
+    source.Append("}\n");
+
+
+    sourceOut += source;
+
+}
+
+}

+ 37 - 0
Source/ToolCore/JSBind/CSharp/CSBClassWriter.h

@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#pragma once
+
+#include <Atomic/Container/Str.h>
+
+using namespace Atomic;
+
+namespace ToolCore
+{
+
+class JSBPackage;
+class JSBClass;
+
+class CSBClassWriter
+{
+
+public:
+
+    CSBClassWriter(JSBClass* klass);
+
+    void GenerateSource(String& sourceOut);
+
+private:
+
+    void WriteFunctions(String& source);
+
+    JSBClass* klass_;
+
+};
+
+}

+ 60 - 0
Source/ToolCore/JSBind/CSharp/CSBFunctionWriter.cpp

@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#include <Atomic/IO/FileSystem.h>
+
+#include "../JSBind.h"
+#include "../JSBModule.h"
+#include "../JSBPackage.h"
+#include "../JSBEnum.h"
+#include "../JSBClass.h"
+#include "../JSBFunction.h"
+
+#include "CSBFunctionWriter.h"
+
+namespace ToolCore
+{
+
+CSBFunctionWriter::CSBFunctionWriter(JSBFunction *function) : function_(function)
+{
+
+}
+
+void CSBFunctionWriter::WriteParameterMarshal(String& source)
+{
+
+}
+
+
+void CSBFunctionWriter::WriteConstructor(String& source)
+{
+
+}
+
+void CSBFunctionWriter::WriteFunction(String& source)
+{
+
+}
+
+void CSBFunctionWriter::GenerateSource(String& sourceOut)
+{
+    String source = "";
+
+    if (function_->IsConstructor())
+    {
+        WriteConstructor(source);
+    }
+    else
+    {
+        WriteFunction(source);
+    }
+
+    sourceOut += source;
+
+}
+
+}

+ 39 - 0
Source/ToolCore/JSBind/CSharp/CSBFunctionWriter.h

@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#pragma once
+
+#include <Atomic/Container/Str.h>
+
+using namespace Atomic;
+
+namespace ToolCore
+{
+
+class JSBPackage;
+class JSBFunction;
+
+class CSBFunctionWriter
+{
+
+public:
+
+    CSBFunctionWriter(JSBFunction* function);
+
+    void GenerateSource(String& sourceOut);
+
+private:
+
+    void WriteFunction(String& source);
+    void WriteConstructor(String& source);
+    void WriteParameterMarshal(String& source);
+
+    JSBFunction* function_;
+
+};
+
+}

+ 138 - 0
Source/ToolCore/JSBind/CSharp/CSBModuleWriter.cpp

@@ -0,0 +1,138 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#include <Atomic/IO/FileSystem.h>
+
+#include "../JSBind.h"
+#include "../JSBPackage.h"
+#include "../JSBModule.h"
+#include "../JSBEnum.h"
+#include "../JSBClass.h"
+#include "../JSBFunction.h"
+
+#include "CSBClassWriter.h"
+#include "CSBModuleWriter.h"
+
+namespace ToolCore
+{
+
+CSBModuleWriter::CSBModuleWriter(JSBModule *module) : module_(module)
+{
+
+}
+
+void CSBModuleWriter::WriteIncludes(String& source)
+{
+
+    Vector<String>& includes = module_->includes_;
+    for (unsigned i = 0; i < includes.Size(); i++)
+    {
+      if (includes[i].StartsWith("<"))
+          source.AppendWithFormat("#include %s\n", includes[i].CString());
+      else
+          source.AppendWithFormat("#include \"%s\"\n", includes[i].CString());
+    }
+
+    Vector<JSBHeader*> allheaders;
+
+    HashMap<StringHash, SharedPtr<JSBEnum> >::Iterator eitr = module_->enums_.Begin();
+    while (eitr != module_->enums_.End())
+    {
+        allheaders.Push(eitr->second_->GetHeader());
+        eitr++;
+    }
+
+    HashMap<StringHash, SharedPtr<JSBClass> >::Iterator citr = module_->classes_.Begin();
+    while (citr != module_->classes_.End())
+    {
+        allheaders.Push(citr->second_->GetHeader());
+        citr++;
+    }
+
+    Vector<JSBHeader*> included;
+
+    for (unsigned i = 0; i < allheaders.Size(); i++)
+    {
+        JSBHeader* header = allheaders.At(i);
+
+        if (included.Contains(header))
+            continue;
+
+        String headerPath = GetPath(header->GetFilePath());
+
+        String headerfile = GetFileNameAndExtension(header->GetFilePath());
+
+        JSBind* jsbind = header->GetSubsystem<JSBind>();
+
+        headerPath.Replace(jsbind->GetSourceRootFolder() + "Source/", "");
+
+        source.AppendWithFormat("#include <%s%s>\n", headerPath.CString(), headerfile.CString());
+
+        included.Push(header);
+    }
+
+}
+
+
+void CSBModuleWriter::GenerateSource(String& sourceOut)
+{
+    source_ = "// This file was autogenerated by JSBind, changes will be lost\n";
+
+    source_ += "#ifdef ATOMIC_PLATFORM_WINDOWS\n";
+
+    source_ += "#pragma warning(disable: 4244) // possible loss of data\n";
+
+    source_ += "#endif\n";
+
+    if (module_->Requires("3D"))
+    {
+        source_ += "#ifdef ATOMIC_3D\n";
+    }
+
+    source_ += "#include <Duktape/duktape.h>\n";
+    source_ += "#include <AtomicJS/Javascript/JSVM.h>\n";
+    source_ += "#include <AtomicJS/Javascript/JSAPI.h>\n";
+
+    WriteIncludes(source_);
+
+    String ns = module_->GetPackage()->GetNamespace();
+
+    if (ns != "Atomic")
+    {
+        source_ += "\n\nusing namespace " + ns + ";\n\n";
+    }
+
+    source_ += "\n\nnamespace Atomic\n{\n \n";
+
+    source_ += "// Begin Class Declarations\n";
+
+    source_ += "// End Class Declarations\n\n";
+
+    source_ += "// Begin Classes\n";
+
+    Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
+
+    for (unsigned i = 0; i < classes.Size(); i++)
+    {
+        CSBClassWriter clsWriter(classes[i]);
+        clsWriter.GenerateSource(source_);
+    }
+
+    source_ += "// End Classes\n\n";
+
+    // end Atomic namespace
+    source_ += "\n}\n";
+
+    if (module_->Requires("3D"))
+    {
+        source_ += "#endif //ATOMIC_3D\n";
+    }
+
+    sourceOut = source_;
+}
+
+}

+ 37 - 0
Source/ToolCore/JSBind/CSharp/CSBModuleWriter.h

@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#pragma once
+
+#include <Atomic/Container/Str.h>
+
+using namespace Atomic;
+
+namespace ToolCore
+{
+
+class JSBModule;
+
+class CSBModuleWriter
+{
+
+public:
+
+    CSBModuleWriter(JSBModule* module);
+
+    void GenerateSource(String& sourceOut);
+
+private:
+
+    void WriteIncludes(String& source);
+
+    JSBModule* module_;
+    String source_;
+
+};
+
+}

+ 34 - 0
Source/ToolCore/JSBind/CSharp/CSBPackageWriter.cpp

@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#include <Atomic/IO/FileSystem.h>
+
+#include "../JSBind.h"
+#include "../JSBModule.h"
+#include "../JSBPackage.h"
+#include "../JSBEnum.h"
+#include "../JSBClass.h"
+
+#include "CSBPackageWriter.h"
+
+namespace ToolCore
+{
+
+CSBPackageWriter::CSBPackageWriter(JSBPackage *package) : package_(package)
+{
+
+}
+
+void CSBPackageWriter::GenerateSource(String& sourceOut)
+{
+    String source = "// This file was autogenerated by JSBind, changes will be lost\n\n";
+
+    sourceOut = source;
+
+}
+
+}

+ 35 - 0
Source/ToolCore/JSBind/CSharp/CSBPackageWriter.h

@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// LICENSE: Atomic Game Engine Editor and Tools EULA
+// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
+// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+
+#pragma once
+
+#include <Atomic/Container/Str.h>
+
+using namespace Atomic;
+
+namespace ToolCore
+{
+
+class JSBPackage;
+class JSBClass;
+
+class CSBPackageWriter
+{
+
+public:
+
+    CSBPackageWriter(JSBPackage* package);
+
+    void GenerateSource(String& sourceOut);
+
+private:
+
+    JSBPackage* package_;
+
+};
+
+}

+ 1 - 0
Source/ToolCore/JSBind/JSBClass.h

@@ -89,6 +89,7 @@ public:
 class JSBClass : public Object
 class JSBClass : public Object
 {
 {
     friend class JSBClassWriter;
     friend class JSBClassWriter;
+    friend class CSBClassWriter;
 
 
     OBJECT(JSBClass)
     OBJECT(JSBClass)
 
 

+ 1 - 0
Source/ToolCore/JSBind/JSBFunction.h

@@ -81,6 +81,7 @@ public:
 class JSBFunction : public JSBSymbol
 class JSBFunction : public JSBSymbol
 {
 {
     friend class JSBFunctionWriter;
     friend class JSBFunctionWriter;
+    friend class CSBFunctionWriter;
 
 
 public:
 public:
 
 

+ 16 - 0
Source/ToolCore/JSBind/JSBModule.cpp

@@ -21,6 +21,8 @@
 #include "JSBModuleWriter.h"
 #include "JSBModuleWriter.h"
 #include "JSBType.h"
 #include "JSBType.h"
 
 
+#include "CSharp/CSBModuleWriter.h"
+
 namespace ToolCore
 namespace ToolCore
 {
 {
 
 
@@ -496,4 +498,18 @@ void JSBModule::GenerateSource(const String& outPath)
     file.Close();
     file.Close();
 }
 }
 
 
+void JSBModule::GenerateCSharpSource(const String& outPath)
+{
+    CSBModuleWriter writer(this);
+    writer.GenerateSource(source_);
+
+    String filepath = outPath + "/CSModule" + name_ + ".cpp";
+    File file(context_);
+    file.Open(filepath, FILE_WRITE);
+    file.Write(source_.CString(), source_.Length());
+    file.Close();
+
+}
+
+
 }
 }

+ 3 - 0
Source/ToolCore/JSBind/JSBModule.h

@@ -28,6 +28,7 @@ class JSBPrimitiveType;
 class JSBModule : public Object
 class JSBModule : public Object
 {
 {
     friend class JSBModuleWriter;
     friend class JSBModuleWriter;
+    friend class CSBModuleWriter;
 
 
     OBJECT(JSBModule)
     OBJECT(JSBModule)
 
 
@@ -63,6 +64,8 @@ public:
     void PostProcessClasses();
     void PostProcessClasses();
 
 
     void GenerateSource(const String& outPath);
     void GenerateSource(const String& outPath);
+    void GenerateCSharpSource(const String& outPath);
+
     const String& GetSource();
     const String& GetSource();
 
 
 private:
 private:

+ 23 - 3
Source/ToolCore/JSBind/JSBPackage.cpp

@@ -14,10 +14,12 @@
 #include "JSBModule.h"
 #include "JSBModule.h"
 #include "JSBPackage.h"
 #include "JSBPackage.h"
 
 
-#include "JSBPackageWriter.h"
 #include "JSBDoc.h"
 #include "JSBDoc.h"
-#include "JSBTypeScript.h"
-#include "JSBHaxe.h"
+
+#include "JSBPackageWriter.h" // Atomic JavaScript
+#include "JSBTypeScript.h" // Atomic TypeScript
+#include "JSBHaxe.h" // Atomic Haxe
+#include "CSharp/CSBPackageWriter.h" // Atomic C#
 
 
 namespace ToolCore
 namespace ToolCore
 {
 {
@@ -66,6 +68,24 @@ void JSBPackage::ProcessModules()
 
 
 }
 }
 
 
+void JSBPackage::GenerateCSharpSource(const String &outPath)
+{
+    CSBPackageWriter writer(this);
+    writer.GenerateSource(source_);
+
+    String filepath = outPath + "/CSPackage" + name_ + ".cpp";
+
+    File file(context_);
+    file.Open(filepath, FILE_WRITE);
+    file.Write(source_.CString(), source_.Length());
+    file.Close();
+
+    for (unsigned i = 0; i < modules_.Size(); i++)
+    {
+        modules_[i]->GenerateCSharpSource(outPath);
+    }
+}
+
 void JSBPackage::GenerateSource(const String &outPath)
 void JSBPackage::GenerateSource(const String &outPath)
 {
 {
     JSBPackageWriter writer(this);
     JSBPackageWriter writer(this);

+ 1 - 0
Source/ToolCore/JSBind/JSBPackage.h

@@ -60,6 +60,7 @@ public:
     static bool ContainsConstantAllPackages(const String& constantName);
     static bool ContainsConstantAllPackages(const String& constantName);
 
 
     void GenerateSource(const String& outPath);
     void GenerateSource(const String& outPath);
+    void GenerateCSharpSource(const String &outPath);
 
 
 private:
 private:
 
 

+ 1 - 1
Source/ToolCore/JSBind/JSBPackageWriter.cpp

@@ -32,7 +32,7 @@ void JSBPackageWriter::WriteProtoTypeRecursive(String &source, JSBClass* klass,
 
 
     Vector<JSBClass*>::Iterator itr = baseClasses.End() - 1 ;
     Vector<JSBClass*>::Iterator itr = baseClasses.End() - 1 ;
 
 
-    while (itr !=baseClasses.Begin() - 1)
+    while (itr != baseClasses.Begin() - 1)
     {
     {
         WriteProtoTypeRecursive(source, (*itr), written);
         WriteProtoTypeRecursive(source, (*itr), written);
         itr--;
         itr--;

+ 30 - 6
Source/ToolCore/JSBind/JSBind.cpp

@@ -14,7 +14,8 @@
 namespace ToolCore
 namespace ToolCore
 {
 {
 
 
-JSBind::JSBind(Context* context) : Object(context)
+JSBind::JSBind(Context* context) : Object(context),
+    package_(new JSBPackage(context))
 {
 {
 
 
 }
 }
@@ -24,18 +25,41 @@ JSBind::~JSBind()
 
 
 }
 }
 
 
-bool JSBind::GenerateBindings(const String& sourceRootFolder, const String& packageFolder, const String& platform)
+bool JSBind::GenerateCSharpBindings(const String& sourceRootFolder, const String& packageFolder, const String& platform)
 {
 {
     sourceRootFolder_ = sourceRootFolder;
     sourceRootFolder_ = sourceRootFolder;
     packageFolder_ = packageFolder;
     packageFolder_ = packageFolder;
     platform_ = platform;
     platform_ = platform;
 
 
-    SharedPtr<JSBPackage> package (new JSBPackage(context_));
+    package_->Load(sourceRootFolder_ + packageFolder_);
+
+    String modulesFolder = "Build/Source/Generated/" + platform + "/CSharp/Packages/";
+    modulesFolder += package_->GetName() + "/";
+
+    String outputFolder = sourceRootFolder + "/" + modulesFolder;
+
+    FileSystem* fs = GetSubsystem<FileSystem>();
+
+    if (!fs->CreateDirs(sourceRootFolder, modulesFolder) || !fs->DirExists(outputFolder))
+    {
+        String error = "Unable to create bindings output folder: " + outputFolder;
+        ErrorExit(error.CString());
+    }
+
+    package_->GenerateCSharpSource(outputFolder);
+
+    return true;
+}
+
 
 
-    package->Load(sourceRootFolder_ + packageFolder_);
+bool JSBind::GenerateBindings(const String& sourceRootFolder, const String& packageFolder, const String& platform)
+{
+    sourceRootFolder_ = sourceRootFolder;
+    packageFolder_ = packageFolder;
+    platform_ = platform;
 
 
     String modulesFolder = "Build/Source/Generated/" + platform + "/Javascript/Packages/";
     String modulesFolder = "Build/Source/Generated/" + platform + "/Javascript/Packages/";
-    modulesFolder += package->GetName() + "/";
+    modulesFolder += package_->GetName() + "/";
 
 
     String outputFolder = sourceRootFolder + "/" + modulesFolder;
     String outputFolder = sourceRootFolder + "/" + modulesFolder;
 
 
@@ -47,7 +71,7 @@ bool JSBind::GenerateBindings(const String& sourceRootFolder, const String& pack
         ErrorExit(error.CString());
         ErrorExit(error.CString());
     }
     }
 
 
-    package->GenerateSource(outputFolder);
+    package_->GenerateSource(outputFolder);
 
 
     return true;
     return true;
 }
 }

+ 5 - 0
Source/ToolCore/JSBind/JSBind.h

@@ -14,6 +14,8 @@ using namespace Atomic;
 namespace ToolCore
 namespace ToolCore
 {
 {
 
 
+class JSBPackage;
+
 class JSBind : public Object
 class JSBind : public Object
 {
 {
 
 
@@ -25,6 +27,7 @@ public:
     virtual ~JSBind();
     virtual ~JSBind();
 
 
     bool GenerateBindings(const String& sourceRootFolder, const String& packageFolder, const String& platform);
     bool GenerateBindings(const String& sourceRootFolder, const String& packageFolder, const String& platform);
+    bool GenerateCSharpBindings(const String& sourceRootFolder, const String& packageFolder, const String& platform);
 
 
     const String& GetSourceRootFolder() { return sourceRootFolder_; }
     const String& GetSourceRootFolder() { return sourceRootFolder_; }
     const String& GetPackageFolder() { return packageFolder_; }
     const String& GetPackageFolder() { return packageFolder_; }
@@ -32,6 +35,8 @@ public:
 
 
 private:
 private:
 
 
+    SharedPtr<JSBPackage> package_;
+
     String sourceRootFolder_;
     String sourceRootFolder_;
     String packageFolder_;
     String packageFolder_;
     String platform_;
     String platform_;