// C++ CodeWorker interface for building dynamic library bindings #include // strtod #include "CW4dl.h" #include "ExternalValueNode.h" #include "FinanceChart.h" class CWPluginDoubleArray : public DoubleArray { public: inline CWPluginDoubleArray() {} inline CWPluginDoubleArray(const DoubleArray& copy) : DoubleArray(copy.data, copy.len) {} ~CWPluginDoubleArray() { delete [] data; } }; class CWPluginIntArray : public IntArray { public: inline CWPluginIntArray() {} inline CWPluginIntArray(const IntArray& copy) : IntArray(copy.data, copy.len) {} ~CWPluginIntArray() { delete [] data; } }; class CWPluginStringArray : public StringArray { public: inline CWPluginStringArray() {} inline CWPluginStringArray(const StringArray& copy) : StringArray(copy.data, copy.len) {} ~CWPluginStringArray() { delete [] data; } }; class CWPluginMemBlock : public MemBlock { public: inline CWPluginMemBlock() {} inline CWPluginMemBlock(const MemBlock& copy) : MemBlock(copy.data, copy.len) {} ~CWPluginMemBlock() { delete [] data; } }; void toDoubleArray(CW4dl::Interpreter* interpreter, CW4dl::Tree* p_a, DoubleArray& a); void populateDoubleArray(CW4dl::Interpreter* interpreter, CW4dl::Tree* pInstance, const DoubleArray& a) { for (int i = 0; i < a.len; ++i) { interpreter->setDoubleValue(interpreter->pushItem(pInstance), a.data[i]); } } int string2enum(const char* tcValue) { if ((strncmp(tcValue, "Chart::", 7) == 0) || (strncmp(tcValue, "CHART::", 7) == 0)) { return string2enum(tcValue + 7); } @ foreach i in this.namespaces["Chart"].unnamed_enums { foreach j in i.values { @ if (strcmp(tcValue, "@key(j)@") == 0) return Chart::@key(j)@; @ } } foreach i in this.namespaces["Chart"].enums { foreach j in i.values { @ if (strcmp(tcValue, "@key(j)@") == 0) return Chart::@key(j)@; @ } } @ return 0; } int string2int(const char* tcValue) { int iResult = 0; char* tcNext = strchr(tcValue, '+'); if (tcNext != NULL) { std::string sExpr = tcValue; sExpr = sExpr.substr(0, sExpr.find('+')); return string2int(sExpr.c_str()) + string2int(tcNext + 1); } if ((tcValue[0] == '0') && (tcValue[1] == 'x')) { char* u = (char*) (tcValue + 2); do { iResult *= 16; if ((*u >= '0') && (*u <= '9')) iResult += *u - '0'; else if ((*u >= 'a') && (*u <= 'f')) iResult += 10 + *u - 'a'; else if ((*u >= 'A') && (*u <= 'F')) iResult += 10 + *u - 'A'; else return 0; ++u; } while (*u != '\0'); } else if (tcValue[0] == 'C') { iResult = string2enum(tcValue); } else { iResult = atoi(tcValue); } return iResult; } void toIntArray(CW4dl::Interpreter* interpreter, CW4dl::Tree* p_a, IntArray& a) { a.len = interpreter->size(p_a); if (a.len == 0) { if (interpreter->getValue(p_a) != NULL) { a.len = 1; int* tiValues = new int[a.len]; a.data = tiValues; tiValues[0] = string2int(interpreter->getValue(p_a)); } else { a.len = 0; a.data = NULL; } } else { int* tiValues = new int[a.len]; a.data = tiValues; const char** tcKeys = new const char*[a.len]; interpreter->allValues(p_a, tcKeys); for (int i = 0; i < a.len; ++i) { tiValues[i] = string2int(tcKeys[i]); } delete [] tcKeys; } } void populateIntArray(CW4dl::Interpreter* interpreter, CW4dl::Tree* pInstance, const IntArray& a) { for (int i = 0; i < a.len; ++i) { interpreter->setIntValue(interpreter->pushItem(pInstance), a.data[i]); } } void toStringArray(CW4dl::Interpreter* interpreter, CW4dl::Tree* p_a, StringArray& a) { a.len = interpreter->size(p_a); if ((a.len == 0) && (interpreter->getValue(p_a) != NULL)) { a.len = 1; char** tsValues = new char*[a.len]; a.data = tsValues; tsValues[0] = (char*) interpreter->getValue(p_a); } else { char** tsValues = new char*[a.len]; a.data = tsValues; const char** tcKeys = new const char*[a.len]; interpreter->allValues(p_a, tcKeys); for (int i = 0; i < a.len; ++i) { tsValues[i] = (char*) tcKeys[i]; } delete [] tcKeys; } } void populateStringArray(CW4dl::Interpreter* interpreter, CW4dl::Tree* pInstance, const StringArray& a) { for (int i = 0; i < a.len; ++i) { interpreter->pushItem(pInstance, a.data[i]); } } static char tcHexa[] = "0123456789ABCDEF"; void populateMemBlock(CW4dl::Interpreter* interpreter, CW4dl::Tree* pInstance, const MemBlock& a) { char* tcText = new char[2*a.len + 1]; char* u = tcText; for (int i = 0; i < a.len; ++i) { int iDigit = (unsigned char) a.data[i]; *u++ = tcHexa[iDigit >> 4]; *u++ = tcHexa[iDigit & 0x0F]; } *u = '\0'; interpreter->setValue(pInstance, tcText); delete [] tcText; } //------------------------------------------------------------------------- // Exported function 'CHART_Init'. // // Initialization of the module in CodeWorker. // Registers all commands in CodeWorker, for recognizing them in the // scripting language. //------------------------------------------------------------------------- CW4DL_EXPORT_SYMBOL void CHART_Init(CW4dl::Interpreter* interpreter) { @ function param2Cpp(sParam : value, theType : node) { switch(theType) { case "base": if theType.pointers { if theType.name == "char" && $theType.pointers.length() == 1$ return sParam + " = (char*) p_" + sParam; traceObject(theType); error("not handled yet!"); } switch(theType.name) { case "int": return sParam + " = string2int((const char*) p_" + sParam + ")"; case "double": return sParam +" = atof((const char*) p_" + sParam + ")"; case "bool": return sParam + " = (((const char*) p_" + sParam + ")[0] != '\\0')"; case "char": return sParam + " = ((const char*) p_" + sParam + ")[0]"; } break; case "array": return "to" + theType.name + "(interpreter, (CW4dl::Tree*) p_" + sParam + ", " + sParam + ")"; case "class": return sParam + " = (External" + theType.name + "ValueNode*) interpreter->getExternalValue((CW4dl::Tree*) p_" + sParam + ")"; case "enum": if theType.name return sParam + " = string2" + theType.name + "(interpreter, (const char*) p_" + sParam + ")"; return sParam + " = string2UnnamedEnum(interpreter, (const char*) p_" + sParam + ")"; } } foreach i in this.namespaces["Chart"].functions { foreach j in i { if $j.parameters.size() <= 4$ { @ interpreter->createCommand("@j.name@"@ foreach k in j.parameters { if k.type.isNodeType() { @, CW4dl::NODE_PARAMETER@ } else { @, CW4dl::VALUE_PARAMETER@ } } @); @ } else { @ CW4dl::PARAMETER_TYPE @j.name@Params[] = {@ foreach k in j.parameters { if !k.first() { @, @ } if k.type.isNodeType() { @CW4dl::NODE_PARAMETER@ } else { @CW4dl::VALUE_PARAMETER@ } } @}; interpreter->createCommand("@j.name@", @j.parameters.size()@, @j.name@Params); @ } break; } } foreach i in this.classes { foreach i0 in i.functions { foreach j in i0 { if i0.key() == i.name { if $j.parameters.size() <= 3$ { @ interpreter->createCommand("create@i.name@", CW4dl::NODE_PARAMETER@ foreach k in j.parameters { if k.type.isNodeType() { @, CW4dl::NODE_PARAMETER@ } else { @, CW4dl::VALUE_PARAMETER@ } } @); @ } else { @ CW4dl::PARAMETER_TYPE create@i.name@Params[] = {CW4dl::NODE_PARAMETER@ foreach k in j.parameters { if k.type.isNodeType() { @, CW4dl::NODE_PARAMETER@ } else { @, CW4dl::VALUE_PARAMETER@ } } @}; interpreter->createCommand("create@i.name@", @$j.parameters.size() + 1$@, create@i.name@Params); @ } break; } else { insert project.allFunctions[i0.key()].bySize[j.parameters.size()].classes[i.key()]; } } } } foreach i in sorted project.allFunctions { foreach j in i.bySize { foreach k in j.classes { local sSignature; foreach m in this.classes[k.key()].functions[i.key()] { if m.parameters.size() != j.key() continue; sSignature = getCppType(m.return_type) + ' ' + i.key(); local iMinSize = 0; foreach p in m.parameters { if !p.default increment(iMinSize); sSignature += '.' + getCppType(p.type); } if i.key() == "setLogScale" { if m.parameters#front.type.name == "bool" continue; } else if i.key() == "yZoneColor" { if sSignature.endString("ValueNode*") { if k.key() != "XYChart" continue; // change the last parameter type of XYChart::yZoneColor(...) setall m.parameters#back.original_type = m.parameters#back.type; insert m.parameters#back.original_default = m.parameters#back.default; m.parameters#back.type.clearVariable(); m.parameters#back.default = true; m.parameters#back.type = "base"; insert m.parameters#back.type.name = "bool"; } } if $sSignature.findString("const int*") >= 0$ || $sSignature.findString("const double*") >= 0$ || $sSignature.findString("const void*") >= 0$ || $sSignature.findString("const char**") >= 0$ || $sSignature.findString("const char*const*") >= 0$ { sSignature = ""; } else { if !j.min_size || $j.min_size > iMinSize$ insert j.min_size = iMinSize; if j.signature { local oldSegments; cutString(j.signature, "Array", oldSegments); local newSegments; cutString(sSignature, "Array", newSegments); if $oldSegments.size() != newSegments.size()$ { local oldFunction, newFunction; if $oldSegments.size() < newSegments.size()$ { j.signature = ""; ref oldFunction = j.firstFunction; ref newFunction = m; } else { sSignature = ""; ref oldFunction = m; ref newFunction = j.firstFunction; } local iIndex = 0; local degeneratedParams; insert j.degenerate = true; foreach p in newFunction.parameters { if p.type == "array" && oldFunction.parameters#[iIndex].type == "base" { local sTypeName = getBaseTypeOfArray(p.type.name); if oldFunction.parameters#[iIndex].type.name != sTypeName { j.degenerate = false; break; } else { pushItem degeneratedParams = iIndex; } } else if p.type.name != oldFunction.parameters#[iIndex].type.name { j.degenerate = false; break; } increment(iIndex); } if j.degenerate { foreach p in degeneratedParams { insert newFunction.parameters#[p].degenerate = true; } } } } if sSignature { if !j.signature insert j.signature = sSignature; if sSignature == j.signature { ref k.function = m; ref j.firstFunction = m; } else { local alternatives; local iParamIndex = 0; while $iParamIndex < j.key()$ { if getCppType(m.parameters#[iParamIndex].type) != getCppType(j.firstFunction.parameters#[iParamIndex].type) { if m.parameters#[iParamIndex].type.name in {"int", "bool", "char"} && j.firstFunction.parameters#[iParamIndex].type.name in {"int", "bool", "char"} { insert alternatives[iParamIndex] = iParamIndex; traceLine(i.key() + " " + j.key() + " " + k.key()); traceLine("!! incompatible signatures: " + sSignature + " and " + j.signature); } else { if m.parameters#[iParamIndex].type.name == "char" && j.firstFunction.parameters#[iParamIndex].type == "class" { ref k.function = m; ref j.firstFunction = m; j.signature = sSignature; traceLine(i.key() + " " + j.key() + " " + k.key()); traceLine("!! selected " + sSignature + ", eliminating " + j.signature); } else if m.parameters#[iParamIndex].type == "class" && j.firstFunction.parameters#[iParamIndex].type.name == "char" { traceLine(i.key() + " " + j.key() + " " + k.key()); traceLine("!! selected " + j.signature + ", eliminating " + sSignature); } else { break; } } } increment(iParamIndex); } if $iParamIndex < j.key()$ { traceLine(i.key() + " " + j.key() + " " + k.key()); traceLine("!! incompatible signatures: " + sSignature + " and " + j.signature); insert j.ambiguity = true; if i.key() != "makeChart" && i.key() != "addExtraField" { local iIndex = 0; foreach p in m.parameters { if p.type.isNodeType() != j.firstFunction.parameters#[iIndex] { break; } increment(iIndex); } insert j.conflict = $iIndex < m.parameters.size()$; if !j.conflict ref k.function = m; } } else { ref k.function = m; foreach p in alternatives { setall j.firstFunction.parameters#[p].alternative_type = m.parameters#[p].type; } } } } } } if !j.signature { traceLine(i.key() + " " + j.key() + " " + k.key()); traceLine("!! no correct signature found!"); continue; } } } } foreach i in project.allFunctions if i.key() != '=' { foreach j in i.bySize if !j.conflict && j.signature { localref myFunction = j.firstFunction; local paramTypes; pushItem paramTypes = "CW4dl::NODE_PARAMETER"; foreach k in myFunction.parameters { if k.type.isNodeType() { pushItem paramTypes = "CW4dl::NODE_PARAMETER"; } else { pushItem paramTypes = "CW4dl::VALUE_PARAMETER"; } } if myFunction.return_type == "class" || myFunction.return_type == "array" || myFunction.return_type == "special" { pushItem paramTypes = "CW4dl::NODE_PARAMETER"; } if $paramTypes.size() > 4$ { @ CW4dl::PARAMETER_TYPE @i.key()@@j.key()@Params[] = {@ foreach k in paramTypes { if !k.first() { @, @ } @@k@@ } @}; interpreter->createCommand("@i.key()@@j.key()@", @paramTypes.size()@, @i.key()@@j.key()@Params@ } else { @ interpreter->createCommand("@i.key()@@j.key()@"@ foreach k in paramTypes { @, @k@@ } } @); @ } } foreach i in this.namespaces["Chart"].arrays { @ CW4dl::Tree* p_@i.key()@ = interpreter->createVariable("@i.key()@"); @ foreach j in i { @ interpreter->setIntValue(interpreter->pushItem(p_@i.key()@), @j@); @ } } foreach i in this.namespaces["Chart"].constants { @ CW4dl::Tree* p_@i.key()@ = interpreter->createVariable("@i.key()@"); @ foreach j in i { @ interpreter->setDoubleValue(p_@i.key()@, @j@); @ } } @} @ local enumValues; foreach i in this.namespaces["Chart"].unnamed_enums { foreach j in i.values { insert enumValues[j.key()]; } } @int string2UnnamedEnum(CW4dl::Interpreter* interpreter, const std::string& sEnum) { std::string::size_type iIndex = sEnum.find('+'); if (iIndex != std::string::npos) { return string2UnnamedEnum(interpreter, sEnum.substr(0, iIndex)) + string2UnnamedEnum(interpreter, sEnum.substr(iIndex + 1)); } std::string sStart = sEnum.substr(0, 7); if ((sStart == "Chart::") || (sStart == "CHART::")) { return string2UnnamedEnum(interpreter, sEnum.substr(7)); } else if ((sStart[0] == '0' && sStart[1] == 'x') || sStart[0] == '-' || (sStart[0] >= '0' && sStart[0] <= '9')) { return string2int(sEnum.c_str()); } @ foreach i in enumValues { @ if (sEnum == "@i.key()@") return Chart::@i.key()@; @ } @ interpreter->error("invalid enum value passed as an argument"); return -1; // never reached } @ foreach i in this.namespaces["Chart"].enums { @Chart::@i.key()@ string2@i.key()@(CW4dl::Interpreter* interpreter, const std::string& sEnum) { std::string::size_type iIndex = sEnum.find('+'); if (iIndex != std::string::npos) { return (Chart::@i.key()@) (string2@i.key()@(interpreter, sEnum.substr(0, iIndex)) + string2@i.key()@(interpreter, sEnum.substr(iIndex + 1))); } std::string sStart = sEnum.substr(0, 7); if ((sStart == "Chart::") || (sStart == "CHART::")) { return string2@i.key()@(interpreter, sEnum.substr(7)); } else if ((sStart[0] == '0' && sStart[1] == 'x') || sStart[0] == '-' || (sStart[0] >= '0' && sStart[0] <= '9')) { return (Chart::@i.key()@) string2int(sEnum.c_str()); } @ foreach j in i.values { @ if (sEnum == "@j.key()@") return Chart::@j.key()@; @ } @ interpreter->error("invalid enum value passed as an argument for @i.key()@"); return (Chart::@i.key()@) -1; // never reached } @ } @ class ExternalChartDirectorValueNode : public CodeWorker::ExternalValueNode { public: enum CLASS_TYPE {@ foreach i in this.classes { if !i.first() { @, @ } @@i.name.toUpperString()@_CLASS@ } @}; virtual CLASS_TYPE getType() const = 0; virtual bool instanceOf(CLASS_TYPE theType) const = 0; virtual const char* getValue() const { return NULL; } virtual void setValue(const char* /*tcValue*/) {} }; @ foreach i in this.classes { @class External@i.name@ValueNode : public @ if i.inheritance { @External@i.inheritance@ValueNode {@ } else if i.typedef { @External@i.typedef@ValueNode {@ } else { @ExternalChartDirectorValueNode { public: @i.name@* internal_; bool bOwn_; @ } if i.functions[i.name].empty() || !i.functions[i.name]#front.parameters.empty() { @ protected: inline External@i.name@ValueNode() @ if !i.inheritance && !i.typedef { @: bOwn_(true) @ } @{} @ } @ public: inline External@i.name@ValueNode(@i.name@* pInternal) : @ if i.inheritance { @External@i.inheritance@ValueNode(pInternal)@ } else if i.typedef { @External@i.typedef@ValueNode(pInternal)@ } else { @internal_(pInternal), bOwn_(false)@ } @ {} @ foreach j in i.functions[i.name] { @ inline External@i.name@ValueNode(@ foreach k in j.parameters { if !k.first() { @, @ } @@getCppType(k.type)@ @k.key()@@ } @) @ if !i.inheritance && !i.typedef { @: bOwn_(true) @ } @{@ if !i.functions[i.name].empty() && !i.functions[i.name]#front.parameters.empty() { @ internal_ = new @i.name@@ foreach j in i.functions[i.name] { if !j.parameters.empty() { @(@ foreach k in j.parameters { if !k.first() { @, @ } @@k.key()@@ } @)@ } break; } @; @ } @} @ break; } @ virtual ~External@i.name@ValueNode() { @ if !i.inheritance && !i.typedef { @ if (bOwn_) delete internal_; @ } @ } virtual CLASS_TYPE getType() const { return @i.name.toUpperString()@_CLASS; } virtual bool instanceOf(CLASS_TYPE theType) const { if (External@i.name@ValueNode::getType() == theType) return true; return @ if i.inheritance { @External@i.inheritance@ValueNode::instanceOf(theType)@ } else if i.typedef { @External@i.typedef@ValueNode::instanceOf(theType)@ } else { @false@ } @; } static void delete@i.name@(ExternalValueNode* ptr) { delete ptr; } virtual CodeWorker::EXTERNAL_VALUE_NODE_DESTRUCTOR getDestructor() const { return delete@i.name@; } @ foreach i0 in i.functions if i0.key() != i.name && i0.key() != '=' { foreach j in i0 { local sType = getCppReturnType(j.return_type); @ virtual @sType@ @i0.key()@(@ foreach k in j.parameters { if !k.first() { @, @ } @@getCppType(k.type)@ @k.key()@@ } @) { @ if sType != "void" { @ return @ } else { @ @ } if j.return_type == "class" { @new External@j.return_type.name@ValueNode(@ } if j.return_type.is_reference { @&@ } @((@i.name@*) internal_)->@i0.key()@(@ foreach k in j.parameters { if !k.first() { @, @ } if k.original_type { @@k.original_default@@ } else if k.type == "class" { @((@k.key()@ == NULL) ? NULL : (@k.type.name@*) @k.key()@->internal_)@ } else { @@k.key()@@ } } if j.return_type == "class" { @)@ } @); } @ } } @}; @ } //-------------------------------------------------------------------------------------- // Generate the stubs for functions //-------------------------------------------------------------------------------------- foreach i in this.namespaces["Chart"].functions { foreach j in i { insert j.is_packaged = true; @CW4DL_EXPORT_SYMBOL const char* @j.name@(CW4dl::Interpreter* interpreter@ if $j.parameters.size() <= 4$ { foreach k in j.parameters { @, CW4dl::Parameter p_@k.key()@@ } @) { @ } else { @, CW4dl::Parameter* tParams) { @ local iIndex = 0; foreach k in j.parameters { @ CW4dl::Parameter p_@k.key()@ = tParams[@iIndex@]; @ increment(iIndex); } } foreach k in j.parameters { @ @getCppValueType(k.type)@ @k.key()@; if (p_@k.key()@ == NULL@ if !isNodeType(k.type) { @ || ((const char*) p_@k.key()@)[0] == '\0'@ } @) @ if k.default { @@k.key()@ = @k.default@; else @ } else { @interpreter->error("No default value available for parameter '@k.key()@'; you must populate it!"); @ } @@param2Cpp(k.key(), k.type)@; @ } if j.return_type.name != "void" { @ return interpreter->copyLocal@ switch(j.return_type.name) { case "int": {@Int@} break; case "double": {@Double@} break; case "bool": {@Boolean@} break; case "char": {@String@} break; } @(@ } else { @ @ } @Chart::@j.name@(@ foreach p in j.parameters { if !p.first() { @, @ } @@p.key()@@ } if j.return_type.name != "void" { @)); @ } else { @); return interpreter->trueConstant(); @ } @} @ break; } } //-------------------------------------------------------------------------------------- // Generate the stubs for constructors //-------------------------------------------------------------------------------------- foreach i in this.classes { foreach j in i.functions[i.name] { insert j.is_packaged = true; @CW4DL_EXPORT_SYMBOL const char* create@i.name@(CW4dl::Interpreter* interpreter, @ local bMulti = $j.parameters.size() >= 4$; if !bMulti { @CW4dl::Parameter pThis@ foreach k in j.parameters { @, CW4dl::Parameter p_@k.key()@@ } @) { @ } else { @CW4dl::Parameter* tParams) { CW4dl::Parameter pThis = tParams[0]; @ local iIndex = 1; foreach k in j.parameters { @ CW4dl::Parameter p_@k.key()@ = tParams[@iIndex@]; @ increment(iIndex); } } @ if (pThis == NULL) return NULL; @ foreach k in j.parameters { @ @getCppValueType(k.type)@ @k.key()@; if (p_@k.key()@ == NULL@ if !isNodeType(k.type) { @ || ((const char*) p_@k.key()@)[0] == '\0'@ } @) @ if k.default { @@k.key()@ = @k.default@; else @ } else { @interpreter->error("No default value available for parameter '@k.key()@'; you must populate it!"); @ } @@param2Cpp(k.key(), k.type)@; @ } @ interpreter->setExternalValue((CW4dl::Tree*) pThis, new External@i.name@ValueNode@ if !j.parameters.empty() { @(@ foreach k in j.parameters { if !k.first() { @, @ } @@k.key()@@ } @)@ } @); return interpreter->trueConstant(); } @ break; } } //-------------------------------------------------------------------------------------- // Generate the stubs for methods //-------------------------------------------------------------------------------------- function generateWrapperFunctionCall(myFunction : node, sClass : value, sAlternativeState : value) { if myFunction.return_type.name != "void" { @ return interpreter->copyLocal@ switch(myFunction.return_type.name) { case "int": {@Int@} break; case "double": {@Double@} break; case "bool": {@Boolean@} break; case "char": {@String@} break; } @(@ } else { @ @ } @((External@sClass@ValueNode*) pThisInstance)->@myFunction.name@(@ foreach p in myFunction.parameters { if !p.first() { @, @ } @@p.key()@@ if sAlternativeState && p.alternative_type { @_alt@ } } if myFunction.return_type.name != "void" { @)); @ } else { @); @ } } foreach i in project.allFunctions if i.key() != '=' { foreach j in i.bySize if !j.conflict && j.signature { @CW4DL_EXPORT_SYMBOL const char* @i.key()@@j.key()@(CW4dl::Interpreter* interpreter@ localref myFunction = j.firstFunction; local iNbParams = $myFunction.parameters.size() + 1$; if myFunction.return_type == "class" || myFunction.return_type == "array" || myFunction.return_type == "special" { insert myFunction.output_param = true; increment(iNbParams); } if $iNbParams <= 4$ { @, CW4dl::Parameter pThis@ foreach p in myFunction.parameters { @, CW4dl::Parameter p_@p.key()@@ } if myFunction.output_param { @, CW4dl::Parameter p_returnedInstance@ } @) { @ } else { @, CW4dl::Parameter* tParams) { CW4dl::Parameter pThis = tParams[0]; @ local iIndex = 1; foreach p in myFunction.parameters { @ CW4dl::Parameter p_@p.key()@ = tParams[@iIndex@]; @ increment(iIndex); } if myFunction.output_param { @ CW4dl::Parameter p_returnedInstance = tParams[@iIndex@]; @ } } @ if (pThis == NULL) return false; ExternalChartDirectorValueNode* pThisInstance = (ExternalChartDirectorValueNode*) interpreter->getExternalValue((CW4dl::Tree*) pThis); @ local sKey = i.key() + j.key() + "::alternatives"; if j.ambiguity { if getProtectedArea(sKey) setProtectedArea(sKey); else populateProtectedArea(sKey, " interpreter->error(\"CHART::" + i.key() + "(): signature ambiguity not implemented yet!\");" + endl()); } else { setProtectedArea(sKey); } local sAlternativeState; foreach k in myFunction.parameters { @ @getCppValueType(k.type)@ @k.key()@; @ if k.alternative_type { sAlternativeState = k.key() + "_alt"; @ @getCppValueType(k.alternative_type)@ @k.key()@_alt; bool @k.key()@_alt_used = false; CW4dl::Parameter p_@k.key()@_alt = p_@k.key()@; @ } @ if (p_@k.key()@ == NULL@ if !isNodeType(k.type) { @ || ((const char*) p_@k.key()@)[0] == '\0'@ } @) @ if k.default { if k.type.name == "bool" && k.default == "true" { @@k.key()@ = (p_@k.key()@ == NULL); else @ } else { @@k.key()@ = @k.default@; else @ } } else if k.type.name == "bool" { @@k.key()@ = false; else @ } else if k.alternative_type.name == "bool" { @{ @k.key()@_alt = false; @k.key()@_alt_used = true; } else @ } else { @interpreter->error("No default value available for parameter '@k.key()@'; you must populate it!"); @ } if k.type.name == "bool" { if k.alternative_type.name == "int" { @if (((const char*) p_@k.key()@)[0] != 't') { @param2Cpp(k.key() + "_alt", k.type)@; @k.key()@_alt_used = true; } else @k.key()@ = true; @ } else { @@param2Cpp(k.key(), k.type)@; @ } } else if k.alternative_type.name == "bool" { @if (((const char*) p_@k.key()@)[0] == 't') { @k.key()@_alt = true; @k.key()@_alt_used = true; } else @param2Cpp(k.key(), k.type)@; @ } else { @@param2Cpp(k.key(), k.type)@; @ } } if j.degenerate { @ if (@ local bFirstParam = true; foreach p in myFunction.parameters if p.degenerate { if bFirstParam { bFirstParam = false; } else { @ || @ } @((p_@p.key()@ != NULL) && (interpreter->getValue((CW4dl::Tree*) p_@p.key()@) != NULL))@ } @) { @ local sKey = i.key() + j.key() + "::degeneration"; if getProtectedArea(sKey) setProtectedArea(sKey); else populateProtectedArea(sKey, " interpreter->error(\"CHART::" + i.key() + "(): degeneration of array types to base types not implemented yet!\");" + endl()); @ } @ } if myFunction.output_param { if myFunction.return_type == "class" { @ ExternalChartDirectorValueNode* returnedInstance; @ } else { @ @getCppReturnType(myFunction.return_type)@ returnedInstance; @ } } local bFirstClass = true; foreach k in j.classes if k.function.existVariable() { insert k.function.is_packaged = true; if myFunction.output_param insert k.function.output_param = true; if bFirstClass { bFirstClass = false; @ @ } else { @ else @ } @if (pThisInstance->instanceOf(ExternalChartDirectorValueNode::@toUpperString(k.key())@_CLASS)) { @ // change default values, if needed, depending on the instance class local iParam = 0; local bAlternativeState = false; foreach p in k.function.parameters { if p.default && myFunction.parameters#[iParam].default != p.default { local sParamName = myFunction.parameters#[iParam].name; local bAlternate = myFunction.parameters#[iParam].alternative_type && (myFunction.parameters#[iParam].alternative_type.name == p.type.name); if bAlternate { bAlternate = "_alt"; bAlternativeState = true; sAlternativeState = myFunction.parameters#[iParam].name + "_alt"; } @ if (p_@sParamName@ == NULL@ if !isNodeType(p.type) { @ || ((const char*) p_@sParamName@)[0] == '\0'@ } @) { @ if p.type.name == "bool" && p.default == "true" { @@sParamName + bAlternate@ = (p_@sParamName@ == NULL);@ } else { @@sParamName + bAlternate@ = @p.default@;@ } if bAlternate { @@sParamName@_alt_used = true;@ } @ }@endl()@@ } increment(iParam); } // call the wrapper method local bAlternativeFormOnly = bAlternativeState && $this.classes[k.key()].functions[i.key()].size() == 1$; if bAlternativeFormOnly { local iParam = 0; foreach p in k.function.parameters { local sParamName = myFunction.parameters#[iParam].name; local bAlternate = myFunction.parameters#[iParam].alternative_type && (myFunction.parameters#[iParam].alternative_type.name == p.type.name); if bAlternate { @ if (!@sParamName@_alt_used) @param2Cpp(sParamName + "_alt", p.type)@; @ } increment(iParam); } } if myFunction.output_param { if bAlternativeState { if !bAlternativeFormOnly { // not necessary the alternative only @ if (@sAlternativeState@_used) { @ } @ returnedInstance = ((External@k.key()@ValueNode*) pThisInstance)->@myFunction.name@(@ foreach p in myFunction.parameters { if !p.first() { @, @ } @@p.key()@@ if p.alternative_type { @_alt@ } } @); @ if !bAlternativeFormOnly { // not necessary the alternative only @ } else { @ } } if !bAlternativeState || !bAlternativeFormOnly { @ returnedInstance = ((External@k.key()@ValueNode*) pThisInstance)->@myFunction.name@(@ foreach p in myFunction.parameters { if !p.first() { @, @ } @@p.key()@@ } @); @ if sAlternativeState { @ } @ } } } else { if bAlternativeState { if !bAlternativeFormOnly { @ if (@sAlternativeState@_used) { @ } generateWrapperFunctionCall(myFunction, k.key(), sAlternativeState); if !bAlternativeFormOnly { @ } else { @ generateWrapperFunctionCall(myFunction, k.key(), ""); @ } @ } } else { generateWrapperFunctionCall(myFunction, k.key(), ""); } } @ }@ } @ else { interpreter->error("function @i.key()@() doesn't exist for the 'this' instance passed as first argument"); } @ if myFunction.return_type == "class" { @ interpreter->setExternalValue((CW4dl::Tree*) p_returnedInstance, returnedInstance); @ } else if myFunction.return_type == "array" || myFunction.return_type == "special" { @ populate@myFunction.return_type.name@(interpreter, (CW4dl::Tree*) p_returnedInstance, returnedInstance); @ } @ return interpreter->trueConstant(); } @ } } @ void toDoubleArray(CW4dl::Interpreter* interpreter, CW4dl::Tree* p_a, DoubleArray& a) { ExternalArrayMathValueNode* pArrayMath = (ExternalArrayMathValueNode*) interpreter->getExternalValue(p_a); if (pArrayMath == NULL) { a.len = interpreter->size(p_a); if (a.len == 0) { if (interpreter->getValue(p_a) != NULL) { a.len = 1; double* tdValues = new double[a.len]; a.data = tdValues; tdValues[0] = interpreter->getDoubleValue(p_a); } else { a.len = 0; a.data = NULL; } } else { a.len = interpreter->size(p_a); double* tdValues = new double[a.len]; a.data = tdValues; const char** tcKeys = new const char*[a.len]; interpreter->allValues(p_a, tcKeys); char* tcEndStr; for (int i = 0; i < a.len; ++i) { tdValues[i] = strtod(tcKeys[i], &tcEndStr); } delete [] tcKeys; } } else { DoubleArray b = *(pArrayMath->internal_); a.len = b.len; double* tdValues = new double[a.len]; a.data = tdValues; memcpy(tdValues, b.data, sizeof(double)*a.len); } }