예제 #1
0
        // When a function takes in a lambda expression
        // This creates it
        Lambda CreateLambda(Expression lambda, int lambdaParams)
        {
            //Set up the list of parameters that this lambda will use
            List <string> parameterNames = new List <string>(lambdaParams);

            for (int i = 0; i < lambdaParams; i++)
            {
                parameterNames.Add(ParamVars.Peek());
                //Rotate the parameter variable list
                ParamVars.Enqueue(ParamVars.Dequeue());
            }
            //This is the function that will be returned
            //Everytime the lambda is used, this is what is being executed
            VObject func(VObject[] args)
            {
                var paramArgPairs = parameterNames.Zip(args).ToList();
                var oldValues     = new VObject[lambdaParams];
                int i             = 0;

                //Set the values of the parameter variables to whatever arguments were passed
                paramArgPairs.ForEach((paramArgPair) => {
                    var(paramName, argVal)            = paramArgPair;
                    oldValues[i++]                    = programState.Variables[paramName];
                    programState.Variables[paramName] = argVal;
                });

                //Set the autofill variable names to the names of the parameter variables
                //And store the old values into temp variables
                string oldAutofill1Name = programState.Autofill1Name;
                string oldAutofill2Name = programState.Autofill2Name;

                programState.Autofill1Name = parameterNames[0];
                if (lambdaParams > 1)
                {
                    programState.Autofill2Name = parameterNames[1];
                }

                //Now evaluate the lambda with the parameter variables and autofills properly set
                var result = Evaluate(lambda);

                //Reset the autofill variable names to what they were before
                programState.Autofill1Name = oldAutofill1Name;
                programState.Autofill2Name = oldAutofill2Name;

                //Reset the parameter variables to their old values
                i = 0;
                paramArgPairs.ForEach((paramArgPair) => {
                    var(paramName, _) = paramArgPair;
                    programState.Variables[paramName] = oldValues[i];
                });

                return(result);
            }

            return(func);
        }
예제 #2
0
        //How the value of an AutoExpression is decided
        //If the AutoExpression is the parameter to a higher order function
        // - Return the input
        //If we are inside a higher-order function
        // - The 'parameter variables' are 斯,成,它,感,干,法
        // - They are placed upon a stack
        // - Based on how many is needed, that number is popped from the stack
        // - E.g some higher-order functions require 3 parameters, some only need 2 or 1
        // - If there are at least two parameter variables, the first one will be designated as the first autofill
        // - and the second will be designated as the second autofill
        //Else if we are not inside a higher-order function
        // - The first autofill will be the first input passed to the program
        // - The second autofill will be the second input passed to the program
        //Now we have our first and second autofill
        // - If there are zero autofill, just use 0
        // - If there is only one autofill, use that one autofill
        // - If there are at least two autofills defined:
        //   - If the expression is an argument to a function, use the first autofill
        //   - Use the second autofill
        //   - Else just use the first

        VObject Evaluate(Expression ast)
        {
            switch (ast)
            {
            //Self-explanatory
            case NumericLiteralExpression number:
                return(new VObject(number.Value));

            case StringLiteralExpression str:
                return(new VObject(str.Value));

            case VariableReferenceExpression variable:
                return(programState.Variables[variable.Name]);

            case ConditionalExpression conditional:
                if (Evaluate(conditional.Condition).IsTruthy())
                {
                    return(Evaluate(conditional.TrueExpression));
                }
                else
                {
                    return(Evaluate(conditional.FalseExpression));
                }

            //Use the first input as autofill by default
            case AutoExpression _:
                return(programState.Autofill_1);

            case FunctionInvocationExpression funcExpr:
                VObject caller;
                if (funcExpr.Caller is AutoExpression)
                {
                    caller = programState.Autofill_1;
                }
                else
                {
                    caller = Evaluate(funcExpr.Caller);
                }

                if (Function.IsHigherOrder(funcExpr.Function, caller.ObjectType))
                {
                    HigherOrderFunction func = (HigherOrderFunction)Function.Get(funcExpr.Function, caller.ObjectType);
                    Lambda lambda;
                    bool   createdLambda = false;
                    // If an autoexpression is submitted as a lambda, then either use the default lambda or if not available, a lambda that returns the first input
                    if (funcExpr.Argument is AutoExpression)
                    {
                        lambda = func.DefaultLambda ?? (x => x[0]);
                    }
                    else
                    {
                        lambda        = CreateLambda(funcExpr.Argument, func.LambdaParameters);
                        createdLambda = true;
                    }


                    //We pass the lambda that we created into the function
                    var res = func.Invoke(caller, lambda);

                    //Re-rotate the parameter variables back
                    //We rotated them in the CreateLambda method
                    //Note this only triggers if CreateLambda was called
                    if (createdLambda)
                    {
                        for (int i = 0; i < PARAMETER_VARIABLES.Length - func.LambdaParameters; i++)
                        {
                            ParamVars.Enqueue(ParamVars.Dequeue());
                        }
                    }

                    return(res);
                }

                if (Function.IsUnary(funcExpr.Function))
                {
                    UnaryFunction func = (UnaryFunction)Function.Get(funcExpr.Function, caller.ObjectType);
                    if (func is UnaryFunctionWithProgramState funcWithProgState)
                    {
                        return(funcWithProgState.Invoke(caller, programState));
                    }
                    else
                    {
                        return(func.Invoke(caller));
                    }
                }
                else
                {
                    VObject        arg  = funcExpr.Argument is AutoExpression ? programState.Autofill_2 : Evaluate(funcExpr.Argument);
                    BinaryFunction func = (BinaryFunction)Function.Get(funcExpr.Function, caller.ObjectType, arg.ObjectType);
                    return(func.Invoke(caller, arg));
                }
                throw new Exception();

            case InterpolatedStringExpression intpStr:
                return(string.Concat(intpStr.Expressions.Select(x => Evaluate(x).ToString())));

            default:
                ErrorHandler.InternalError("This shouldn't happen.");
                throw new Exception();
            }
        }