public override void EmitSetValue(BoundExpression expression)
 {
     // Push the closure onto the stack.
     Scope.EmitLoadClosure(_field.Closure);
     // Push the value onto the stack.
     Generator.EmitCast(Generator.EmitExpression(expression), Type.Type);
     // Set the closure field.
     IL.Emit(OpCodes.Stfld, _field.Builder.Field);
 }
示例#2
0
            private bool? ToBoolean(BoundExpression node)
            {
                // This method tests whether the expression evaluates to a constant
                // expression. This depends on a constant folding phase for
                // correct results (which we don't have, so currently it just
                // checks for a true/false constant).

                var constant = node as BoundConstant;
                if (constant != null && constant.Value is bool)
                    return (bool)constant.Value;

                return null;
            }
示例#3
0
 public ReadState(BoundExpression expression, int writeCount)
 {
     Expression = expression;
     WriteCount = writeCount;
 }
示例#4
0
 private void EmitSetMember(BoundExpression expression, BoundExpression index, BoundExpression value)
 {
     EmitPop(EmitOperationCall(Operation.SetMember, expression, index, value));
 }
                public void Join(IList<Branch> branches)
                {
                    // If there aren't any branches, there is no work.

                    if (branches.Count == 0)
                        return;

                    // If we just have a single branch, we can just copy all
                    // assignments.

                    if (branches.Count == 1)
                    {
                        var branch = branches[0];
                        if (branch._assigned != null)
                            MergeAssigned(branch._assigned);

                        // And move the expressions.
                        Expressions = branch.Expressions;

                        return;
                    }

                    // If we don't have a single branch, we have to merge
                    // the expressions from all branches.

                    BoundExpression[] expressions = null;
                    foreach (var branch in branches)
                    {
                        if (expressions == null)
                        {
                            // If we don't have expressions yet, just move them
                            // from the branch.

                            expressions = branch.Expressions;
                        }
                        else if (branch.Expressions != null)
                        {
                            // Otherwise, concatenate the two arrays.

                            var a = expressions;
                            var b = branch.Expressions;

                            var result = new BoundExpression[a.Length + b.Length];
                            Array.Copy(a, result, a.Length);
                            Array.Copy(b, 0, result, a.Length, b.Length);
                            expressions = result;
                        }
                    }

                    Expressions = expressions;

                    // If we have an empty branch, we don't have to do
                    // any work, because nothing will be definitely assigned.

                    if (branches.Any(p => p._assigned == null))
                        return;

                    // Otherwise, we need to get the intersection of all
                    // branches.

                    var assigned = new List<BoundVariable>(branches[0]._assigned);

                    for (int i = 1; i < branches.Count; i++)
                    {
                        var branchAssigned = branches[i]._assigned;

                        for (int j = assigned.Count - 1; j >= 0; j--)
                        {
                            // If the branch does not contain an assignment
                            // for the variable in our current collection,
                            // remove it from our current collection.

                            if (!branchAssigned.Contains(assigned[j]))
                                assigned.RemoveAt(j);
                        }

                        // Stop processing when we don't have any variables
                        // left.

                        if (assigned.Count == 0)
                            break;
                    }

                    // Add the assigned variables to our list.

                    if (assigned.Count > 0)
                        MergeAssigned(assigned);
                }
示例#6
0
        private BoundValueType EmitOperationCall(Operation operation, BoundExpression left, BoundExpression right)
        {
            var leftType = left.ValueType;
            var rightType = right.ValueType;

            var method = FindOperationMethod(operation, leftType, rightType);
            var builder = FindOperationBuilder(operation, leftType, rightType);

            bool boxLeft = false;
            bool boxRight = false;

            if (method == null && builder == null)
            {
                method = FindOperationMethod(operation, leftType, BoundValueType.Unknown);
                builder = FindOperationBuilder(operation, leftType, BoundValueType.Unknown);

                if (method != null || builder != null)
                    boxRight = true;
            }

            if (method == null && builder == null)
            {
                method = FindOperationMethod(operation, BoundValueType.Unknown, rightType);
                builder = FindOperationBuilder(operation, BoundValueType.Unknown, rightType);

                if (method != null || builder != null)
                    boxLeft = true;
            }

            if (method == null && builder == null)
            {
                method = FindOperationMethod(operation, BoundValueType.Unknown, BoundValueType.Unknown);
                builder = FindOperationBuilder(operation, BoundValueType.Unknown, BoundValueType.Unknown);
                boxLeft = true;
                boxRight = true;
            }

            if (builder != null)
                return builder(this, new[] { left, right });

            if (!method.IsStatic)
                _scope.EmitLoad(SpecialLocal.Runtime);

            EmitExpression(left);
            if (boxLeft)
                EmitBox(leftType);
            EmitExpression(right);
            if (boxRight)
                EmitBox(rightType);

            return IL.EmitCall(method);
        }
            protected bool TryGetCacheSlot(BoundExpression expression, BoundConstant constant, out int index, out FieldInfo cacheSlot)
            {
                cacheSlot = null;
                index = 0;

                string name = constant.Value as string;

                if (name != null)
                    index = Generator._identifierManager.ResolveIdentifier(name);

                if (name == null && constant.ValueType == BoundValueType.Number)
                {
                    double number = (double)constant.Value;
                    index = (int)number;
                    if (index != number || index < 0)
                        return false;

                    name = index.ToString();
                }

                cacheSlot = Generator.ResolveCacheSlot(expression, name);

                return cacheSlot != null;
            }
 public override void EmitSetValue(BoundExpression expression)
 {
     // Push the value onto the stack.
     Generator.EmitCast(Generator.EmitExpression(expression), Type.Type);
     // Store into the local.
     IL.Emit(OpCodes.Stloc, Local);
 }
示例#9
0
        private BoundValueType EmitGetMember(BoundExpression expression, int index)
        {
            if (expression.ValueType != BoundValueType.Object)
                _scope.EmitLoad(SpecialLocal.Runtime);

            EmitBox(EmitExpression(expression));
            IL.EmitConstant(index);

            if (expression.ValueType == BoundValueType.Object)
            {
                var cacheSlot = ResolveCacheSlot(expression, _identifierManager.GetIdentifier(index));
                if (cacheSlot != null)
                {
                    IL.Emit(OpCodes.Ldsflda, cacheSlot);
                    return IL.EmitCall(_objectGetPropertyCached);
                }

                return IL.EmitCall(_objectGetProperty);
            }

            return IL.EmitCall(_runtimeGetMemberByIndex);
        }
示例#10
0
 private BoundValueType EmitExpression(BoundExpression node)
 {
     switch (node.Kind)
     {
         case BoundKind.Binary: return EmitBinary((BoundBinary)node);
         case BoundKind.Call: return EmitCall((BoundCall)node);
         case BoundKind.Constant: return EmitConstant((BoundConstant)node);
         case BoundKind.CreateFunction: return EmitCreateFunction((BoundCreateFunction)node);
         case BoundKind.DeleteMember: return EmitDeleteMember((BoundDeleteMember)node);
         case BoundKind.ExpressionBlock: return EmitExpressionBlock((BoundExpressionBlock)node);
         case BoundKind.GetMember: return EmitGetMember((BoundGetMember)node);
         case BoundKind.GetVariable: return EmitGetVariable((BoundGetVariable)node);
         case BoundKind.HasMember: return EmitHasMember((BoundHasMember)node);
         case BoundKind.New: return EmitNew((BoundNew)node);
         case BoundKind.NewBuiltIn: return EmitNewBuiltIn((BoundNewBuiltIn)node);
         case BoundKind.RegEx: return EmitRegEx((BoundRegEx)node);
         case BoundKind.Unary: return EmitUnary((BoundUnary)node);
         case BoundKind.Emit: return EmitEmit((BoundEmitExpression)node);
         default: throw new InvalidOperationException();
     }
 }
示例#11
0
        private FieldInfo ResolveCacheSlot(BoundExpression expression, string member)
        {
            var getVariable = expression as BoundGetVariable;
            if (getVariable != null)
            {
                var variable = getVariable.Variable;
                if (variable.Kind == BoundVariableKind.Argument)
                    variable = GetMappedArgument((BoundArgument)variable);

                if (variable.Kind == BoundVariableKind.Temporary)
                    return ResolveCacheSlot("<>Temporary" + ((BoundTemporary)variable).Index, member);
                if (variable.Kind == BoundVariableKind.Local)
                    return ResolveCacheSlot(((BoundLocal)variable).Name, member);
                if (variable.Kind == BoundVariableKind.ClosureField)
                    return ResolveCacheSlot(((BoundClosureField)variable).Name, member);
                if (variable.Kind == BoundVariableKind.Magic)
                    return ResolveCacheSlot(((BoundMagicVariable)variable).VariableType.ToString(), member);
            }

            return null;
        }
示例#12
0
        private ValueEmitter GetEmitter(BoundExpression expression)
        {
            var getVariable = expression as BoundGetVariable;
            if (getVariable == null)
                return null;

            var emitter = _scope.GetEmitter(getVariable.Variable);
            if (emitter != null)
                return emitter;

            if (getVariable.Variable.Kind == BoundVariableKind.Argument)
            {
                var mappedArgument = GetMappedArgument((BoundArgument)getVariable.Variable);
                if (mappedArgument != null)
                    return _scope.GetEmitter(mappedArgument);
            }

            return null;
        }
示例#13
0
        private void EmitTest(BoundExpression test, Label target, bool inverse)
        {
            // TODO: This should be optimized. E.g. the compare expressions
            // could be changed to e.g. a Bgt.

            var type = EmitExpression(test);

            EmitCast(type, BoundValueType.Boolean);

            IL.Emit(inverse ? OpCodes.Brfalse : OpCodes.Brtrue, target);
        }
示例#14
0
 private void EmitTest(BoundExpression test, Label target)
 {
     EmitTest(test, target, false);
 }
示例#15
0
        private void EmitSetVariable(IBoundWritable variable, BoundExpression value)
        {
            switch (variable.Kind)
            {
                case BoundVariableKind.Global:
                    _scope.GlobalScopeEmitter.EmitSetMember(new BoundSetMember(
                        new BoundGetVariable(BoundMagicVariable.Global),
                        BoundConstant.Create(((BoundGlobal)variable).Name),
                        value,
                        SourceLocation.Missing
                    ));
                    break;

                case BoundVariableKind.Local:
                case BoundVariableKind.Temporary:
                case BoundVariableKind.ClosureField:
                    _scope.GetEmitter(variable).EmitSetValue(value);
                    break;

                case BoundVariableKind.Argument:
                    var argument = (BoundArgument)variable;

                    // Check whether the argument is mapped to a local or closure
                    // field.

                    var scope = argument.Closure == null ? _scope : _scope.FindScope(argument.Closure);
                    var mappedArgument = scope.GetMappedArgument(argument);
                    if (mappedArgument != null)
                    {
                        EmitSetVariable(mappedArgument, value);
                        return;
                    }

                    BoundGetVariable getVariable;
                    if (scope.ArgumentsClosureField != null)
                        getVariable = new BoundGetVariable(scope.ArgumentsClosureField);
                    else
                        getVariable = new BoundGetVariable(BoundMagicVariable.Arguments);

                    EmitSetMember(new BoundSetMember(
                        getVariable,
                        BoundConstant.Create((double)argument.Index),
                        value,
                        SourceLocation.Missing
                    ));
                    return;

                default:
                    throw new InvalidOperationException();
            }
        }
示例#16
0
 private BoundValueType EmitGetMember(BoundExpression expression, BoundExpression index)
 {
     return EmitOperationCall(Operation.Member, expression, index);
 }
 public override void EmitSetValue(BoundExpression expression)
 {
     // Load the reference to the local.
     IL.Emit(OpCodes.Ldloca, Local);
     // Push the value onto the stack.
     Generator.EmitCast(Generator.EmitExpression(expression), Type.Type);
     // Call set_Value.
     IL.EmitCall(_setValue);
 }
示例#18
0
 private BoundExpression BuildGetMember(BoundExpression expression, BoundExpression index)
 {
     return new BoundGetMember(
         expression,
         index
     );
 }
 public abstract void EmitSetValue(BoundExpression expression);
示例#20
0
        private BoundStatement BuildSet(SyntaxNode syntax, BoundExpression value)
        {
            switch (syntax.Type)
            {
                case SyntaxType.Identifier:
                    var identifier = ((IdentifierSyntax)syntax).Identifier;

                    if (identifier.Type == IdentifierType.Global)
                        _scope.IsGlobalScopeReferenced = true;

                    return BuildSet(identifier, value);

                case SyntaxType.Property:
                    var property = (PropertySyntax)syntax;

                    return BuildSetMember(
                        BuildExpression(property.Expression),
                        BoundConstant.Create(property.Name),
                        value
                    );

                case SyntaxType.Indexer:
                    var indexer = (IndexerSyntax)syntax;

                    return BuildSetMember(
                        BuildGet(indexer.Expression),
                        BuildExpression(indexer.Index),
                        value
                    );

                default:
                    throw new InvalidOperationException();
            }
        }
示例#21
0
        private BoundValueType EmitOperationCall(Operation operation, BoundExpression obj, BoundExpression index, BoundExpression value)
        {
            var indexType = index.ValueType;

            bool boxIndex = false;

            var method = FindOperationMethod(operation, BoundValueType.Unknown, indexType, BoundValueType.Unknown);
            var builder = FindOperationBuilder(operation, BoundValueType.Unknown, indexType, BoundValueType.Unknown);

            if (method == null && builder == null)
            {
                method = FindOperationMethod(operation, BoundValueType.Unknown, BoundValueType.Unknown, BoundValueType.Unknown);
                builder = FindOperationBuilder(operation, BoundValueType.Unknown, BoundValueType.Unknown, BoundValueType.Unknown);

                boxIndex = true;
            }

            if (builder != null)
                return builder(this, new[] { obj, index, value });

            if (!method.IsStatic)
                _scope.EmitLoad(SpecialLocal.Runtime);

            EmitBox(EmitExpression(obj));

            EmitExpression(index);
            if (boxIndex)
                EmitBox(indexType);

            EmitBox(EmitExpression(value));

            return IL.EmitCall(method);
        }
示例#22
0
        private BoundStatement BuildSet(IIdentifier identifier, BoundExpression value)
        {
            switch (identifier.Type)
            {
                case IdentifierType.Parameter:
                    return new BoundSetVariable(
                        _scope.GetArgument(identifier),
                        value,
                        SourceLocation.Missing
                    );

                case IdentifierType.Scoped:
                    var builder = new BlockBuilder(this);

                    var valueTemporary = builder.CreateTemporary();

                    builder.Add(new BoundSetVariable(
                        valueTemporary,
                        value,
                        SourceLocation.Missing
                    ));

                    builder.Add(BuildSetWithScope(builder, identifier.WithScope, identifier.Fallback, valueTemporary));

                    return builder.BuildBlock(SourceLocation.Missing);

                case IdentifierType.Local:
                case IdentifierType.Global:
                    if (identifier.Type == IdentifierType.Global)
                        _scope.IsGlobalScopeReferenced = true;

                    if (identifier.Closure == null)
                        return new BoundSetVariable(_scope.GetLocal(identifier), value, SourceLocation.Missing);

                    return new BoundSetVariable(
                        _scope.GetClosureField(identifier),
                        value,
                        SourceLocation.Missing
                    );

                    /*
                    // These are handled upstream.
                case IdentifierType.This:
                case IdentifierType.Null:
                case IdentifierType.Undefined:
                case IdentifierType.Arguments:
                     */

                default:
                    throw new InvalidOperationException("Cannot find variable of argument");
            }
        }
示例#23
0
        private BoundValueType EmitOperationCall(Operation operation, BoundExpression operand)
        {
            var operandType = operand.ValueType;

            var method = FindOperationMethod(operation, operandType);
            var builder = FindOperationBuilder(operation, operandType);

            bool boxOperand = false;

            if (method == null && builder == null)
            {
                method = FindOperationMethod(operation, BoundValueType.Unknown);
                builder = FindOperationBuilder(operation, BoundValueType.Unknown);
                boxOperand = true;
            }

            if (builder != null)
                return builder(this, new[] { operand });

            if (!method.IsStatic)
                _scope.EmitLoad(SpecialLocal.Runtime);

            EmitExpression(operand);
            if (boxOperand)
                EmitBox(operandType);

            return IL.EmitCall(method);
        }
示例#24
0
 private BoundSetMember BuildSetMember(BoundExpression expression, BoundExpression index, BoundExpression value)
 {
     return new BoundSetMember(
         expression,
         index,
         value,
         SourceLocation.Missing
     );
 }
 public void MarkExpression(BoundExpression expression)
 {
     Expressions = new[] { expression };
 }
示例#26
0
        private void EmitSetMember(BoundExpression expression, int index, BoundExpression value)
        {
            EmitBox(EmitExpression(expression));
            IL.EmitConstant(index);
            EmitBox(EmitExpression(value));

            if (expression.ValueType == BoundValueType.Object)
            {
                var cacheSlot = ResolveCacheSlot(expression, _identifierManager.GetIdentifier(index));
                if (cacheSlot != null)
                {
                    IL.Emit(OpCodes.Ldsflda, cacheSlot);
                    IL.EmitCall(_objectSetPropertyCached, BoundValueType.Unset);
                }
                else
                {
                    IL.EmitCall(_objectSetProperty, BoundValueType.Unset);
                }
            }
            else
            {
                IL.EmitCall(_runtimeSetMemberByIndex, BoundValueType.Unset);
            }
        }