private JSExpression Hoist(JSExpression expression, TypeReference type, List <JSExpression> commaElements)
        {
            if (expression is JSVariable)
            {
                return(null);
            }
            else if (expression is JSLiteral)
            {
                return(null);
            }

            var thisBoe = expression as JSBinaryOperatorExpression;

            if ((thisBoe != null) &&
                (thisBoe.Operator == JSOperator.Assignment) &&
                (thisBoe.Left is JSVariable)
                )
            {
                // If the value is (x = y), insert 'x = y' and then set the value to 'x'
                commaElements.Add(thisBoe);
                return(thisBoe.Left);
            }
            else
            {
                var tempVar = TemporaryVariable.ForFunction(Function, type, FunctionSource);

                commaElements.Add(new JSBinaryOperatorExpression(
                                      JSOperator.Assignment, tempVar, expression, type
                                      ));

                return(tempVar);
            }
        }
Example #2
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            JSPropertyAccess     pa;
            JSAssignmentOperator assignmentOperator;
            JSBinaryOperator     newOperator;

            if (
                IsPropertyAccess(boe, out pa) &&
                ((assignmentOperator = boe.Operator as JSAssignmentOperator) != null) &&
                IntroduceEnumCasts.ReverseCompoundAssignments.TryGetValue(assignmentOperator, out newOperator)
                )
            {
                // FIXME: Terrible hack
                var type         = pa.GetActualType(TypeSystem);
                var tempVariable = TemporaryVariable.ForFunction(
                    Stack.Last() as JSFunctionExpression, type
                    );
                var replacement = new JSCommaExpression(
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment, tempVariable,
                        new JSBinaryOperatorExpression(
                            newOperator,
                            new JSPropertyAccess(
                                pa.ThisReference, pa.Property, false,
                                pa.TypeQualified,
                                pa.OriginalType, pa.OriginalMethod,
                                pa.IsVirtualCall
                                ),
                            boe.Right, boe.GetActualType(TypeSystem)
                            ), type
                        ),
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment,
                        new JSPropertyAccess(
                            pa.ThisReference, pa.Property, true,
                            pa.TypeQualified,
                            pa.OriginalType, pa.OriginalMethod,
                            pa.IsVirtualCall
                            ), tempVariable, type
                        ),
                    tempVariable
                    );

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            }
            else
            {
                VisitChildren(boe);
            }
        }
        public void VisitNode(JSUnaryOperatorExpression uoe)
        {
            JSUnaryMutationOperator op;
            JSExpression            target;
            TypeReference           type;

            if (UnpackUnaryMutation(uoe, out op, out target, out type))
            {
                var tempVar = TemporaryVariable.ForFunction(
                    Stack.Last() as JSFunctionExpression, type
                    );
                var store = new JSBinaryOperatorExpression(
                    JSOperator.Assignment, tempVar, target, type
                    );

                var delta = (
                    (op == JSOperator.PostIncrement) ||
                    (op == JSOperator.PreIncrement)
                    )
                    ? 1
                    : -1;

                JSExpression replacement;
                if (
                    (op == JSOperator.PostIncrement) ||
                    (op == JSOperator.PostDecrement)
                    )
                {
                    var mutated = new JSPointerAddExpression(target, JSLiteral.New(delta), false);
                    replacement = new JSCommaExpression(store, mutated, tempVar);
                }
                else
                {
                    replacement = new JSPointerAddExpression(target, JSLiteral.New(delta), true);
                }

                ParentNode.ReplaceChild(uoe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(uoe);
        }
        public void VisitNode(JSUnaryOperatorExpression uoe)
        {
            JSExpression expr;

            if (!JSReferenceExpression.TryDereference(JSIL, uoe.Expression, out expr))
            {
                expr = uoe.Expression;
            }

            var eVar        = expr as JSVariable;
            var eChangeType = expr as JSChangeTypeExpression;

            if (eChangeType != null)
            {
                eVar = eChangeType.Expression as JSVariable;
            }

            var type = uoe.Expression.GetActualType(TypeSystem);

            if (
                (eVar != null) &&
                (eVar.Identifier == Variable.Identifier) &&
                (uoe.Operator is JSUnaryMutationOperator)
                )
            {
                var newValue = DecomposeMutationOperators.DecomposeUnaryMutation(
                    uoe, () => TemporaryVariable.ForFunction(
                        Stack.Last() as JSFunctionExpression, type
                        ), type, TypeSystem
                    );
                var replacement = new JSWriteThroughReferenceExpression(
                    Variable, newValue
                    );
                ParentNode.ReplaceChild(uoe, replacement);
                VisitReplacement(replacement);
            }
            else
            {
                VisitChildren(uoe);
            }
        }
Example #5
0
        public void VisitNode(JSUnaryOperatorExpression uoe)
        {
            var type       = uoe.Expression.GetActualType(TypeSystem);
            var isIntegral = TypeUtil.Is32BitIntegral(type);

            if (isIntegral && (uoe.Operator is JSUnaryMutationOperator))
            {
                var replacement = DecomposeUnaryMutation(
                    uoe,
                    () => TemporaryVariable.ForFunction(
                        Stack.Last() as JSFunctionExpression, type
                        ),
                    type, TypeSystem
                    );

                ParentNode.ReplaceChild(uoe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(uoe);
        }
        /// <summary>
        ///     This function handles unsupported features by <see cref="Regen.Flee"/> evaluator by creating temporary
        ///     variables or even changing the type of expression.
        /// </summary>
        /// <remarks>
        /// Because flee does not support arrays, we temporarly store any parsed array
        /// into a variable and then just pass the variable name, letting Regen just fetch it
        /// and pass it around.
        ///</remarks>
        public Expression HandleUnsupported(Expression expr, List <TemporaryVariable> temps, Type caller = null)
        {
            //todo after we support dictionaries, add support here
            switch (expr)
            {
            case NullIdentity _:
            case CharLiteral _:
            case NumberLiteral _:
            case StringLiteral _:
            case BooleanLiteral _:
            case StringIdentity _:
            case ReferenceIdentity _:
            case EmptyExpression _:
                return(expr);

            case ArgumentsExpression argumentsExpression: {
                for (var i = 0; i < argumentsExpression.Arguments.Length; i++)
                {
                    argumentsExpression.Arguments[i] = HandleUnsupported(argumentsExpression.Arguments[i], temps, typeof(ArgumentsExpression));
                }

                return(argumentsExpression);
            }

            case ArrayExpression arrayExpression: {
                for (var i = 0; i < arrayExpression.Values.Length; i++)
                {
                    arrayExpression.Values[i] = HandleUnsupported(arrayExpression.Values[i], temps, typeof(ArrayExpression));
                }

                var parsedArray = Compute(arrayExpression, temps, typeof(ArrayExpression));
                var temp        = new TemporaryVariable(Context, parsedArray);
                //todo this might lead to memory leaks!
                //temps.Add(temp);
                //if (caller == typeof(RegenCompiler)) { //if this is the first expression that is being parsed
                //    temp.MarkPermanent();
                //}
                return(IdentityExpression.WrapVariable(temp.Name));
            }

            case IndexerCallExpression indexerCallExpression: {
                indexerCallExpression.Left      = HandleUnsupported(indexerCallExpression.Left, temps, typeof(IndexerCallExpression));
                indexerCallExpression.Arguments = (ArgumentsExpression)HandleUnsupported(indexerCallExpression.Arguments, temps, typeof(IndexerCallExpression));
                return(indexerCallExpression);
            }

            case CallExpression callExpression: {
                callExpression.FunctionName = HandleUnsupported(callExpression.FunctionName, temps, typeof(CallExpression));
                callExpression.Arguments    = (ArgumentsExpression)HandleUnsupported(callExpression.Arguments, temps, typeof(CallExpression));
                return(callExpression);
            }

            case IdentityExpression identityExpression: {
                //here we turn any string literal into a reference to a variable.
                //if theres no such variable, we assume it is for a functionname of property.
                if (identityExpression.Identity is StringIdentity sr)
                {
                    if (Context.Variables.ContainsKey(sr.Name))
                    {
                        return(new IdentityExpression(ReferenceIdentity.Wrap(sr)));
                    }
                }

                identityExpression.Identity = HandleUnsupported(identityExpression.Identity, temps, caller ?? typeof(IdentityExpression));
                return(identityExpression);
            }

            case HashtagReferenceExpression hashtagReference: {
                var key = $"__{hashtagReference.Number}__";
                return(new IdentityExpression(new ReferenceIdentity(key, new RegexResult()
                    {
                        Value = key, Index = hashtagReference.Matches().First().Index, Length = 1 + hashtagReference.Number.Length
                    })));
            }

            case GroupExpression groupExpression:
                groupExpression.InnerExpression = HandleUnsupported(groupExpression.InnerExpression, temps, caller ?? typeof(GroupExpression));
                return(groupExpression);

            case PropertyIdentity propertyIdentity:
                //todo maybe here we parse Left, store and push? but first invalidate that it is not just a name.
                propertyIdentity.Left  = HandleUnsupported(propertyIdentity.Left, temps, caller ?? typeof(PropertyIdentity));
                propertyIdentity.Right = HandleUnsupported(propertyIdentity.Right, temps, caller ?? typeof(PropertyIdentity));
                return(propertyIdentity);

            case KeyValueExpression keyValueExpression:
                keyValueExpression.Key   = HandleUnsupported(keyValueExpression.Key, temps, typeof(KeyValueExpression));
                keyValueExpression.Value = HandleUnsupported(keyValueExpression.Value, temps, typeof(KeyValueExpression));
                return(keyValueExpression);

            case NewExpression newExpression:
                newExpression.Constructor = HandleUnsupported(newExpression.Constructor, temps, typeof(NewExpression));
                return(newExpression);

            case LeftOperatorExpression leftOperatorExpression:
                leftOperatorExpression.Right = HandleUnsupported(leftOperatorExpression.Right, temps, typeof(LeftOperatorExpression));
                return(leftOperatorExpression);

            case OperatorExpression operatorExpression:
                operatorExpression.Left  = HandleUnsupported(operatorExpression.Left, temps, typeof(OperatorExpression));
                operatorExpression.Right = HandleUnsupported(operatorExpression.Right, temps, typeof(OperatorExpression));
                return(operatorExpression);

            case RightOperatorExpression rightOperatorExpression:
                rightOperatorExpression.Left = HandleUnsupported(rightOperatorExpression.Left, temps, typeof(RightOperatorExpression));
                return(rightOperatorExpression);

            case ThrowExpression throwExpression:
                throwExpression.Right = HandleUnsupported(throwExpression.Right, temps, typeof(ThrowExpression));
                return(throwExpression);

            case ForeachExpression foreachExpression:
            case ImportExpression importExpression:
            case InteractableExpression interactableExpression:
            case VariableDeclarationExpression variableExpression:
                throw new NotSupportedException(); //todo support? this should be found in an expression. it is a higher level expression

            case Identity identity:                //this is an abstract class.
                throw new NotSupportedException();

            default:
                throw new NotImplementedException();
            }
        }
        /// <summary>
        ///     Perform the evaluation or translate <see cref="Expression"/> into a variable for later use in computation.
        /// </summary>
        /// <returns></returns>
        private Data Compute(Expression expression, List <TemporaryVariable> temps, Type _caller = null)
        {
            return(_eval(expression, _caller));

            Data _eval(Expression express, Type caller = null)
            {
                switch (express)
                {
                case null:
                    throw new NullReferenceException();

                case ArgumentsExpression argumentsExpression: {
                    var arr = new Array();
                    foreach (var expr in argumentsExpression.Arguments)
                    {
                        arr.Add(_eval(expr));
                    }

                    return(arr);
                }

                case ArrayExpression arrayExpression: {
                    var arr = new Array();
                    foreach (var expr in arrayExpression.Values)
                    {
                        arr.Add(_eval(expr));
                    }

                    return(arr);
                }

                case NumberLiteral numberLiteral: {
                    return(new NumberScalar(_evaluate(numberLiteral.Value)));
                }

                case BooleanLiteral booleanLiteral: {
                    return(new BoolScalar(booleanLiteral.Value));
                }

                case CharLiteral charLiteral: {
                    return(new StringScalar(charLiteral.Value.ToString()));
                }

                case NullIdentity nullIdentity: {
                    return(Data.Null);
                }

                case StringLiteral stringLiteral: {
                    return(new StringScalar(stringLiteral.Value));
                }

                case KeyValueExpression keyValueExpression: {
                    //todo create a KeyValue regen data type.
                    return(new NetObject(new KeyValuePair <object, object>(_eval(keyValueExpression.Key), _eval(keyValueExpression.Value))));
                }

                case EmptyExpression emptyExpression: {
                    return(Data.Null);
                }

                case ForeachExpression foreachExpression: {
                    break;
                }

                case GroupExpression groupExpression: {
                    return(_eval(groupExpression.InnerExpression));
                }

                case ReferenceIdentity referenceIdentity: {
                    if (!Context.Variables.ContainsKey(referenceIdentity.Name))
                    {
                        return(new ReferenceData(referenceIdentity.Name));
                    }

                    if (!Context.Variables.TryGetValue(referenceIdentity.Name, out var value, true))
                    {
                        throw new Exception("This should never occur.");
                    }

                    //if it is not a reference, make one.
                    if (!(value is ReferenceData))
                    {
                        return(new ReferenceData(referenceIdentity.Name));
                    }

                    return((ReferenceData)value);
                }

                case PropertyIdentity propertyIdentity: {
                    TemporaryVariable tmp = null;
                    var left = _eval(propertyIdentity.Left);

                    if (left is ReferenceData rf)
                    {
                        var right = new PropertyIdentity(IdentityExpression.WrapVariable(rf.EmitExpressive()), propertyIdentity.Right).AsString();

                        return(Data.Create(_evaluate(right)));
                    }


                    //not reference
                    using (tmp = new TemporaryVariable(Context, left is NetObject no ? no.Value : left)) {
                        return(Data.Create(_evaluate($"{tmp.Name}.{propertyIdentity.Right.AsString()}")));
                    }

                    using (var var = new TemporaryVariable(Context, left is NetObject no ? no.Value : left)) {
                        var right = new PropertyIdentity(IdentityExpression.WrapVariable(var.Name), propertyIdentity.Right).AsString();

                        return(Data.Create(_evaluate(right)));
                    }
                }

                case StringIdentity stringIdentity: {
                    return(new ReferenceData(stringIdentity.Name));
                }

                case IdentityExpression identityExpression: {
                    return(_eval(identityExpression.Identity, caller));    //todo test
                }

                case Identity identity: {
                    throw new NotSupportedException();
                }

                case CallExpression callExpression: {
                    var left = _eval(callExpression.FunctionName, typeof(CallExpression));
                    var args = (Array)_eval(callExpression.Arguments);


                    if (left is NetObject || left is Array || left is Dictionary)
                    {
                        goto _storing;
                    }
                    //try regular parsing:

                    try {
                        var parsed = $"{left.Emit()}({args.Select(arg => arg.EmitExpressive()).StringJoin(", ")})";
                        return(Data.Create(_evaluate(parsed)));
                    } catch (ExpressionCompileException e) when(e.InnerException?.Message.Contains("FunctionCallElement: Could find not function") ?? false)
                    {
                        throw;
                    } catch (ExpressionCompileException) { }

_storing:           //try storing left as variable
                    using (var var = new TemporaryVariable(Context, left is NetObject no ? no.Value : left)) {
                        var parsed = $"{var.Name}({args.Select(arg => arg.EmitExpressive()).StringJoin(", ")})";
                        return(Data.Create(_evaluate(parsed)));
                    }
                }

                case IndexerCallExpression indexerCallExpression: {
                    var left = Data.Create(_eval(indexerCallExpression.Left, typeof(IndexerCallExpression)));
                    var args = (Array)_eval(indexerCallExpression.Arguments);

                    if (left is NetObject || left is Array || left is Dictionary)
                    {
                        goto _storing;
                    }
                    //try regular parsing:
                    try {
                        var parsed = $"{left.Emit()}[{args.Select(arg => arg.EmitExpressive()).StringJoin(", ")}]";
                        return(Data.Create(_evaluate(parsed)));
                    } catch (ExpressionCompileException) { }

_storing:           //try storing left as variable
                    using (var var = new TemporaryVariable(Context, left is NetObject no ? no.Value : left)) {
                        var parsed = $"{var.Name}[{args.Select(arg => arg.EmitExpressive()).StringJoin(", ")}]";
                        return(Data.Create(_evaluate(parsed)));
                    }
                }

                case NewExpression newExpression: {
                    //todo new
                    break;
                }

                case LeftOperatorExpression leftOperatorExpression: {
                    foreach (var e in leftOperatorExpression.Iterate())
                    {
                        if (e is ArrayExpression)
                        {
                            throw new NotSupportedException("Unable to compile a nested array, please define it in a variable first.");
                        }
                    }

                    //todo BuiltinTests.len fails here because we do not expand left or right. we should.
                    return(Data.Create(_evaluate(leftOperatorExpression.AsString())));
                }

                case OperatorExpression operatorExpression: {
                    foreach (var e in operatorExpression.Iterate())
                    {
                        if (e is ArrayExpression)
                        {
                            throw new NotSupportedException("Unable to compile a nested array, please define it in a variable first.");
                        }
                    }

                    //todo BuiltinTests.len fails here because we do not expand left or right. we should.

                    return(Data.Create(_evaluate(operatorExpression.AsString())));
                }

                case RightOperatorExpression rightOperatorExpression: {
                    foreach (var e in rightOperatorExpression.Iterate())
                    {
                        if (e is ArrayExpression)
                        {
                            throw new NotSupportedException("Unable to compile a nested array, please define it in a variable first.");
                        }
                    }

                    //todo BuiltinTests.len fails here because we do not expand left or right. we should.
                    return(Data.Create(_evaluate(rightOperatorExpression.AsString())));
                }

                case ThrowExpression throwExpression: {
                    break;
                }

                case VariableDeclarationExpression variableExpression: {
                    var name = Data.Create(_eval(variableExpression.Name));
                    if (name.GetType() != typeof(StringScalar))
                    {
                        throw new NotSupportedException("Variable names can contain only _azAZ0-9");
                    }
                    var value = Data.Create(_eval(variableExpression.Right));
                    Context.Variables[name.ToString()] = value;
                    return(value);
                }
                }

                return(Data.Null);
            }
        }
Example #8
0
        public void VisitNode(JSUnaryOperatorExpression uoe)
        {
            var type       = uoe.Expression.GetActualType(TypeSystem);
            var isIntegral = TypeUtil.Is32BitIntegral(type);

            if (isIntegral && (uoe.Operator is JSUnaryMutationOperator))
            {
                if (
                    (uoe.Operator == JSOperator.PreIncrement) ||
                    (uoe.Operator == JSOperator.PreDecrement)
                    )
                {
                    var assignment = MakeUnaryMutation(
                        uoe.Expression,
                        (uoe.Operator == JSOperator.PreDecrement)
                            ? JSOperator.Subtract
                            : JSOperator.Add,
                        type
                        );

                    ParentNode.ReplaceChild(uoe, assignment);
                    VisitReplacement(assignment);
                    return;
                }
                else if (
                    (uoe.Operator == JSOperator.PostIncrement) ||
                    (uoe.Operator == JSOperator.PostDecrement)
                    )
                {
                    // FIXME: Terrible hack
                    var tempVariable = TemporaryVariable.ForFunction(
                        Stack.Last() as JSFunctionExpression, type
                        );
                    var makeTempCopy = new JSBinaryOperatorExpression(
                        JSOperator.Assignment, tempVariable, uoe.Expression, type
                        );
                    var assignment = MakeUnaryMutation(
                        uoe.Expression,
                        (uoe.Operator == JSOperator.PostDecrement)
                            ? JSOperator.Subtract
                            : JSOperator.Add,
                        type
                        );

                    var comma = new JSCommaExpression(
                        makeTempCopy,
                        assignment,
                        tempVariable
                        );

                    ParentNode.ReplaceChild(uoe, comma);
                    VisitReplacement(comma);
                    return;
                }
                else
                {
                    throw new NotImplementedException("Unary mutation not supported: " + uoe);
                }
            }

            VisitChildren(uoe);
        }
Example #9
0
        public void VisitNode(JSUnaryOperatorExpression uoe)
        {
            var type   = uoe.Expression.GetActualType(TypeSystem);
            var isEnum = IsEnumOrNullableEnum(type);

            if (isEnum)
            {
                var castToInt = JSInvocationExpression.InvokeMethod(
                    JS.valueOf(TypeSystem.Int32), uoe.Expression, null, true
                    );

                if (LogicalOperators.Contains(uoe.Operator))
                {
                    uoe.ReplaceChild(uoe.Expression, castToInt);
                }
                else if (uoe.Operator == JSOperator.Negation)
                {
                    uoe.ReplaceChild(uoe.Expression, castToInt);
                }
                else if (uoe.Operator is JSUnaryMutationOperator)
                {
                    if (
                        (uoe.Operator == JSOperator.PreIncrement) ||
                        (uoe.Operator == JSOperator.PreDecrement)
                        )
                    {
                        var assignment = MakeUnaryMutation(
                            uoe.Expression,
                            (uoe.Operator == JSOperator.PreDecrement)
                                ? JSOperator.Subtract
                                : JSOperator.Add,
                            type
                            );

                        ParentNode.ReplaceChild(uoe, assignment);
                        VisitReplacement(assignment);
                        return;
                    }
                    else if (
                        (uoe.Operator == JSOperator.PostIncrement) ||
                        (uoe.Operator == JSOperator.PostDecrement)
                        )
                    {
                        // FIXME: Terrible hack
                        var tempVariable = TemporaryVariable.ForFunction(
                            Stack.Last() as JSFunctionExpression, type
                            );
                        var makeTempCopy = new JSBinaryOperatorExpression(
                            JSOperator.Assignment, tempVariable, uoe.Expression, type
                            );
                        var assignment = MakeUnaryMutation(
                            uoe.Expression,
                            (uoe.Operator == JSOperator.PostDecrement)
                                ? JSOperator.Subtract
                                : JSOperator.Add,
                            type
                            );

                        var comma = new JSCommaExpression(
                            makeTempCopy,
                            assignment,
                            tempVariable
                            );

                        ParentNode.ReplaceChild(uoe, comma);
                        VisitReplacement(comma);
                        return;
                    }
                    else
                    {
                        throw new NotImplementedException("Unary mutation of enum not supported: " + uoe.ToString());
                    }
                }
            }

            VisitChildren(uoe);
        }