vassilych / cscs

CSCS: Customized Scripting in C#
MIT License
166 stars 47 forks source link

Get Function Args #24

Open bakman23 opened 4 years ago

bakman23 commented 4 years ago

Hello, is it possible to get a function arg by index ?

I would like create an IF function like excel.

IFELSE( [condition] , [if true action] , [if false action] )

the problem is, if I use GetFunctionArgs all args will be interpreted and this exemple "IFELSE( 1 != 1 , 1 / 0 , "ok")" the divided by zero will be catch.

the must will be to test fisrt param, if it return 0 the second param will not be interpreted only the third Exemple `

        //get condition
        var arg = script.GetFunctionArgByIndex(indexParam: 0);
        var condition = Utils.GetSafeString(arg, 0);
        if (condition == "1")
        {
            arg = script.GetFunctionArgsIndex(indexParam: 1);
            string actionIfTrue = Utils.GetSafeString(arg, 0);
            return new Variable(actionIfTrue);
        }
        else
        {
            arg = script.GetFunctionArgsIndex(indexParam: 2);
            string actionIfFalse = Utils.GetSafeString(arg, 0);
            return new Variable(actionIfFalse);
        }

` I tried to create the GetFunctionArgsIndex and it work with this IFELSE( 1 != 1 , 1 / 0 , "ok") but not with that IFELESE ( functA(x) functB(y) != 0 , 3 - 10 Round( 1 / 0 ) , Ceil(0.4))

`

public static List GetFunctionArgsIndex(ParsingScript script, char start, char end, Action outList, int indexParam ) { List args = new List(); bool isList = script.StillValid() && script.Current == Constants.START_GROUP;

        if (!script.StillValid() || script.Current == Constants.END_STATEMENT)
        {
            return args;
        }

        ParsingScript tempScript = script.GetTempScript(script.String, script.Pointer);

        if (script.Current != start && script.TryPrev() != start &&
           (script.Current == ' ' || script.TryPrev() == ' '))
        { // Allow functions with space separated arguments
            start = ' ';
            end = Constants.END_STATEMENT;
        }

        // ScriptingEngine - body is unsed (used in Debugging) but GetBodyBetween has sideeffects           

pragma warning disable 219

        string body = Utils.GetBodyBetween(tempScript, start, end);

pragma warning restore 219

        // After the statement above tempScript.Parent will point to the last
        // character belonging to the body between start and end characters. 

        int index = 0;

        while (script.Pointer < tempScript.Pointer)
        {

            if (index == indexParam)
            {

                Variable item = Utils.GetItem(script, false);
                args.Add(item);
                break;
            }
            else
            {
                Parser.Split(script, Constants.NEXT_OR_END_ARRAY);
            }

            if (script.Pointer < tempScript.Pointer)
            {
                script.MoveForwardIf(Constants.END_GROUP);
                script.MoveForwardIf(Constants.NEXT_ARG);
            }
            else if (script.Pointer > tempScript.Pointer)
            {
                script.MoveForwardIf(Constants.NEXT_ARG);
            }
            if (script.Pointer == tempScript.Pointer - 1)
            {
                script.MoveForwardIf(Constants.END_ARG, Constants.END_GROUP);
            }
            index++;
        }

        if (script.Pointer <= tempScript.Pointer)
        {
            // Eat closing parenthesis, if there is one, but only if it closes
            // the current argument list, not one after it. 
            script.MoveForwardIf(Constants.END_ARG, end);
        }

        script.MoveForwardIf(Constants.SPACE);
        //script.MoveForwardIf(Constants.SPACE, Constants.END_STATEMENT);
        outList(isList);
        return args;
    }

`

Can you help me, please ?

vassilych commented 4 years ago

Hi,

What you can do is to use Utils.GetToken() function instead of GetFunctionArgs(). Here is an example:

string funcName = Utils.GetToken(script, Constants.NEXT_OR_END_ARRAY);

This function doesn't execute the parameters, i.e. it treats them as strings. So you will get next string in the list. Unfortunately you have to call this function multiple times if you want to extract multiple parameters. I am going to create a convenience method to get a list of all args.

Let me know if calling GetToken() multiple times can solve the issue for you. Note that as a separation token you can also use a space if needed.

Best, Vassili