diff --git a/.github/workflows/dubtest.yml b/.github/workflows/dubtest.yml index ca30bad..a6e5981 100644 --- a/.github/workflows/dubtest.yml +++ b/.github/workflows/dubtest.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - dc: [ldc-1.30.0] + dc: [ldc-1.31.0] runs-on: ${{ matrix.os }} steps: diff --git a/source/dutils/math/core.d b/source/dutils/math/core.d index ef53bc2..4adbccf 100644 --- a/source/dutils/math/core.d +++ b/source/dutils/math/core.d @@ -11,7 +11,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .*/ /** Copyright: 2022-2023, Ruby The Roobster*/ -/**Author: Ruby The Roobster, */ +/**Author: Ruby The Roobster, */ /**Date: January 16, 2023*/ /** License: GPL-3.0**/ @@ -47,9 +47,233 @@ else bool registerFunction(in dstring name, in dstring func, in dstring def) @safe { - auto ret = validateFunction(func, def) && name ~ func !in funcList.funcs; + import std.uni; + bool isOp = false; + dchar[] tempstr = []; + size_t oldi; + size_t oldi2; + bool bruh = false; + for(size_t i = 0; i < def.length; ++i) + { + oldi = 0; + bruh = false; + if((def[i] != d('x') && !def[i].isNumber && def[i] != d('\\') && def[i] != d('(')) || isOp && def[i] == d(' ')) + { + isOp = false; + oldi = tempstr.length; + oldi2 = i; + if(def[i+1] == d(' ')) + { + ++i; + oldi +=2; + tempstr ~= def[i-1]; + bruh = true; + } + do + { + tempstr ~= def[i]; + if(i != def.length) + ++i; + if(i == def.length) + goto c; + } + while(def[i] != d('x') && !def[i].isNumber && def[i] != d('\\') && def[i] != d('(')); + + if(def[i] != d('(')) + goto c; + + do + { + tempstr ~= def[i]; + if(i != def.length) + ++i; + if(i == def.length) + goto c; + } + while(def[i] != d(')')); + + if(i+1 == def.length) + goto c; + + if(def[i+1] != d('(')) + goto c; + + i += 2; + tempstr ~= ")("d; + do + { + tempstr ~= def[i]; + ++i; + } + while(def[i] != d(')')); + tempstr ~= ")"d; + + // It truely is a function (EXTREME PAIN AND SUFFERING): + + // Get the paramaters and return type of the function in func ... + dstring[] params; + dstring[] returni; + size_t k = 0; + getParamsReturns(params, func, k); //Get the function return type. + dstring returns; + ++k; //Make sure to get out of the closing parenthesis. + getParamsReturns(returni, func, k); //Get the parameter types. + static foreach(type; typel) + { + mixin(type ~ "[] " ~ type ~ "ParamList;"); + mixin(type ~ "[] " ~ type ~ "OperandList;"); + } + returns = returni[0]; + + size_t j = oldi; + dchar[] tempstr2 = []; + size_t[] tempxns = []; + debug import std.stdio; + "here".writeln; + debug oldi.writeln; + debug + { + if(oldi > 0) + debug tempstr[oldi].writeln; + } + for(; j < tempstr.length; ++j) + { + tempstr.writeln; + if(tempstr[j] == d(')')) + break; + else if(tempstr[j] == d('x')) // Get the parameter types ... + { + dstring tempstr3 = ""d; + ++j; + do + { + tempstr3 ~= tempstr[j]; + ++j; + if(tempstr.length == j) + break; + } + while(tempstr[j].isNumber); + + import std.conv : to; + tempstr2 ~= params[to!size_t(tempstr3)-1]; + tempxns ~= to!size_t(tempstr3); + } + else + tempstr2 ~= tempstr[j]; + if(tempstr[j] == d(')')) + break; + } + tempstr2 ~= tempstr[j .. $].dup; // The return type is known, we just need to copy it. + // Verify that tempstr2 is a registered function. + if(tempstr2.idup !in funcList) + return false; + + tempstr2 = funcList[tempstr2.idup].dup; // Load the function body + for(j = 0; j < tempstr2.length; j++) // Substitue the xns + { + if(tempstr2[j] == d('x')) // Do the substitution + { + auto oldj = ++j; + dstring tempstr3 = ""d; + + do + { + tempstr3 ~= tempstr2[j]; + ++j; + if(j == tempstr2.length) + break; + } + while(tempstr2[j].isNumber); + + import std.conv : to; + auto tempstr4 = to!dstring(tempxns[to!size_t(tempstr3) - 1]); + if(tempstr4.length > tempstr3.length) + { + tempstr2.length += tempstr4.length - tempstr3.length; + tempstr2[j + tempstr4.length - tempstr3.length .. $] = tempstr2[j .. $ + tempstr3.length - tempstr4.length].dup; // Shift it up + tempstr2[oldj .. j+1] = tempstr4.dup; + } + else if(tempstr4.length == tempstr3.length) + { + tempstr2[oldj .. j] = tempstr4.dup; + } + else // The string has to be shrunk. + { + tempstr2[j + tempstr4.length - tempstr3.length .. $ + tempstr4.length - tempstr3.length] = tempstr2[j .. $].dup; + tempstr2[oldj .. j + 1 + tempstr4.length - tempstr3.length] = tempstr4.dup; + tempstr2.length += tempstr4.length - tempstr3.length; + } + } + } + + tempstr2 = "("d.dup ~ tempstr2 ~ ")"d; // Encapsulate it ... + // Substitute it into the body ... + if(tempstr2.length > i - oldi) + { + tempstr.length += tempstr2.length + oldi - i; + tempstr[tempstr2.length + oldi .. $] = tempstr[i .. $ + i - oldi - tempstr2.length].dup; + tempstr[oldi .. i + tempstr2.length + 1] = tempstr2.dup; + } + else if(tempstr2.length == i - oldi) + { + tempstr[oldi .. i] = tempstr2.dup; + } + else + { + debug import std.stdio; + debug "bruh".writeln; + if(bruh) + { + debug tempstr[oldi2 + oldi .. $].writeln; + debug tempstr[oldi .. oldi+tempstr[oldi2 + oldi .. $].length].writeln; + } + if(!bruh) + tempstr[tempstr2.length + oldi .. $ + tempstr2.length + oldi - i] = tempstr[i .. $].dup; + else // THIS LINE I SWEAR + tempstr[oldi .. oldi+tempstr[oldi2 + oldi .. $].length] = tempstr[oldi2 + oldi .. $].dup; + if(bruh) + debug tempstr[oldi .. oldi + oldi2 - tempstr2.length + 1].writeln; + debug tempstr2.writeln; + if(!bruh) + tempstr[oldi .. tempstr2.length + oldi] = tempstr2.dup; + else + tempstr[oldi .. oldi + oldi2 - tempstr2.length + 1] = tempstr2.dup; + if(bruh) + tempstr.length += tempstr.length - oldi - oldi2 - tempstr2.length + 1; + else + tempstr.length += tempstr2.length + oldi - i - 1; + } + + debug import std.stdio; + debug tempstr.writeln; + continue; + } + c: // If it is only an operator, and not a function. + //debug import std.stdio; + //debug "here".writeln; + //debug oldi.writeln; + //if(oldi != 0) + // i = oldi; + isOp = true; + if(i == def.length) + break; + tempstr ~= def[i]; + //debug tempstr.writeln; + } + debug import std.stdio; + debug tempstr.writeln; + + for(size_t i = 0; i < tempstr.length; ++i) // Remove any whitespace + { + if(tempstr[i] == d(' ')) + { + tempstr[i .. $-1] = tempstr[i+1 .. $].dup; + --tempstr.length; + } + } + auto ret = validateFunction(func, tempstr.idup) && name ~ func !in funcList.funcs; if(ret) - funcList.funcs[name ~ func] = def; + funcList.funcs[name ~ func] = tempstr.idup; return ret; } @@ -57,10 +281,22 @@ bool registerFunction(in dstring name, in dstring func, in dstring def) @safe @safe unittest { dstring func = "(Number)(Number)"d; - dstring def = "x1"d; + dstring def = "x1*x1"d; dstring name = "f"d; assert(registerFunction(name, func, def)); assert(!registerFunction(name, func, def)); //No registering an already-existing function. + + // Issue 12 + name = "g"d; + def = "f(x1)(Number)"d; + assert(registerFunction(name, func, def)); + + name = "h"d; + func = "(Number,Number)(Number)"d; + def = "g(x1)(Number)+ f(x2)(Number)"d; + debug import std.stdio; + "bug".writeln; + assert(registerFunction(name, func, def)); } /************************************************** @@ -449,38 +685,7 @@ bool validateFunction(in dstring func, in dstring def) @trusted ++i; } while((def[i] != d('x') && def[i] != d('\\')) && (def[i] != d('(') && def[i] != d(' '))); - - /+if(def[i] != d('(')) // Operators+/ - currOp = tempstr.idup; - /+else // Oh shit oh fuck a function (THIS CODE DOESN'T WROK AND WILL BE FIXED LATER) - { - // We need to get the types of its arguments - tempstr = tempstr[0 .. $-1].dup; - dchar[] tempargs = []; - ++i; - do - { - tempargs ~= def[i]; - ++i; - } - while(def[i] != d(')')); - - import std.algorithm; - auto indexes = tempargs.splitter(d(',')); - foreach(ref index; indexes) - index = index[1 .. $].dup; - - size_t[] indices = []; - import std.conv; - foreach(index; indexes) - indices ~= index.to!size_t; - - dstring[] temptypes; - foreach(indice; indices) - temptypes ~= paramTypeList[indice]; - - - }+/ + currOp = tempstr.idup; } } while(i < def.length); @@ -525,9 +730,9 @@ bool validateFunction(in dstring func, in dstring def) @trusted def = "x1*x2"d; func = "(Number,Number)(Number)"d; assert(registerFunction("f"d, func, def)); - //Functions within functions were too hard to implement, so we removed them. - //def = "x1* f(x1,x2)(Number)"d; - //assert(validateFunction(func, def)); + // Functions within functions. The substitution is done at registration, it should execute fine. + //def = "x1*f(x1,x2)(Number)"d; + //assert(registerFunction(func, def)); } /************************************ @@ -580,7 +785,7 @@ import std.typecons : Tuple; /*********************************************************** * Executes a function. * - * TODO: Actually write the function. + * TODO: * Params: * func = * The function to execute.