Example #1
0
 public override void Disassemble(StringBuilder sb, ExpressionUsage u)
 {
     sb.AppendWhen(u.IsObject(), "(");
     sb.Append("(" + TargetType + ")");
     Operand.Disassemble(sb, ExpressionUsage.Operand);
     sb.AppendWhen(u.IsObject(), ")");
 }
Example #2
0
 public override void Disassemble(StringBuilder sb, ExpressionUsage u)
 {
     sb.AppendWhen(u.IsObject(), "(");
     sb.Append(Operator.Symbol);
     Operand.Disassemble(sb, ExpressionUsage.Operand);
     sb.AppendWhen(u.IsObject(), ")");
 }
Example #3
0
 public virtual void WriteCallUnOp(CallUnOp s, ExpressionUsage u)
 {
     Begin(u.IsObject());
     Write(s.Operator.Symbol);
     WriteExpression(s.Operand, ExpressionUsage.Object);
     End(u.IsObject());
 }
Example #4
0
 public virtual void WriteAsOp(AsOp s, ExpressionUsage u)
 {
     Begin(u.IsObject());
     WriteExpression(s.Operand, ExpressionUsage.Operand);
     Write(" as ");
     WriteType(s.Source, s.ReturnType);
     End(u.IsObject());
 }
Example #5
0
 public virtual void WriteIsOp(IsOp s, ExpressionUsage u)
 {
     Begin(u.IsObject());
     WriteExpression(s.Operand, ExpressionUsage.Operand);
     Write(" is ");
     WriteType(s.Source, s.TestType);
     End(u.IsObject());
 }
Example #6
0
 public virtual void WriteNullOp(NullOp s, ExpressionUsage u)
 {
     Begin(u.IsObject());
     WriteExpression(s.Left, ExpressionUsage.Operand);
     Write(NullOp);
     WriteExpression(s.Right, ExpressionUsage.Operand);
     End(u.IsObject());
 }
Example #7
0
 public virtual void WriteCast(Source src, DataType dt, Expression s, ExpressionUsage u = ExpressionUsage.Argument)
 {
     Begin(u.IsObject());
     Write("(");
     WriteType(src, dt);
     Write(")");
     WriteExpression(s, ExpressionUsage.Operand);
     End(u.IsObject());
 }
Example #8
0
        public override void Disassemble(StringBuilder sb, ExpressionUsage u)
        {
            sb.AppendWhen(u.IsObject(), "(");

            if (AddressType != 0)
            {
                sb.Append(AddressType.ToString().ToLower() + " ");
            }

            sb.Append("&");
            Operand.Disassemble(sb, ExpressionUsage.Operand);

            sb.AppendWhen(u.IsObject(), ")");
        }
Example #9
0
        public override void Begin(ref Expression e, ExpressionUsage u)
        {
            if (e is This && u.IsObject() || e is StoreThis)
            {
                WritesToThis = true;
            }

            // TODO: Check method calls recursively
        }
Example #10
0
 public override void Begin(ref Expression e, ExpressionUsage u)
 {
     if (e is LoadArgument && u.IsObject())
     {
         UnsafeParameters.Add((e as LoadArgument).Index);
     }
     else if (e is StoreArgument)
     {
         UnsafeParameters.Add((e as StoreArgument).Index);
     }
 }
Example #11
0
File: FixOp.cs Project: mortend/uno
        public override void Disassemble(StringBuilder sb, ExpressionUsage u)
        {
            sb.AppendWhen(u.IsObject(), "(");

            switch (Operator)
            {
            case FixOpType.IncreaseBefore: sb.Append("++"); break;

            case FixOpType.DecreaseBefore: sb.Append("--"); break;
            }

            Operand.Disassemble(sb, ExpressionUsage.Operand);

            switch (Operator)
            {
            case FixOpType.IncreaseAfter: sb.Append("++"); break;

            case FixOpType.DecreaseAfter: sb.Append("--"); break;
            }

            sb.AppendWhen(u.IsObject(), ")");
        }
Example #12
0
        public override void Begin(ref Expression e, ExpressionUsage u)
        {
            // TODO: Could need more testing of this code
            // TODO: Could need more verification here

            ProcessType(e.Source, e.ReturnType);

            switch (e.ExpressionType)
            {
            case ExpressionType.Invalid:
            case ExpressionType.Constant:
            case ExpressionType.LoadLocal:
            case ExpressionType.LoadElement:
            case ExpressionType.LoadVarying:
            case ExpressionType.LoadVertexAttrib:
            case ExpressionType.LoadPixelSampler:
            case ExpressionType.StoreLocal:
            case ExpressionType.StoreElement:
            case ExpressionType.ExternOp:
            case ExpressionType.ConditionalOp:
            case ExpressionType.BranchOp:
            case ExpressionType.ReferenceOp:
            case ExpressionType.SequenceOp:
            case ExpressionType.FixOp:
            case ExpressionType.NoOp:
                break;

            case ExpressionType.CallShader:
            {
                var s = e as CallShader;

                for (int i = 0; i < s.Arguments.Length; i++)
                {
                    var pfat = s.Function.Parameters[i].Type as FixedArrayType;

                    // Workaround to avoid fixed array parameters without length which is illegal in GLSL (FIXME: This may not be 100% robust)
                    if (pfat != null && pfat.OptionalSize == null)
                    {
                        var afat = s.Arguments[i].ReturnType as FixedArrayType;

                        if (afat != null)
                        {
                            s.Function.Parameters[i].Type = afat;
                        }
                    }
                }
            }
            break;

            case ExpressionType.AddressOf:
            {
                var a = e as AddressOf;
                var b = a.Operand as AddressOf;

                // This happens when a fixed array is bound to uniform (FIXME: Could be cleaned up for consisency)
                if (b != null)
                {
                    e = b;
                    Begin(ref e, u);
                }
            }
            break;

            case ExpressionType.LoadUniform:
                Shader.ReferencedUniforms.Add((e as LoadUniform).Index);
                break;

            case ExpressionType.RuntimeConst:
                Shader.ReferencedConstants.Add((e as RuntimeConst).Index);
                break;

            case ExpressionType.NullOp:
                e = (e as NullOp).TransformNullOpToConditionalOp(Essentials, Generator.Path.DrawBlock.Method.DeclaringType);
                Begin(ref e, u);
                break;

            case ExpressionType.Swizzle:
                if (Backend.ShaderBackend.IsIntrinsic((e as Swizzle).Fields[0].DeclaringType))
                {
                    break;
                }

                e = (e as Swizzle).TransformSwizzleToNewObject(Generator.Path.DrawBlock.Method.DeclaringType);
                Begin(ref e, u);
                break;

            case ExpressionType.Default:
                // TODO: Remove default init from shader code
                break;

            case ExpressionType.LoadArgument:
            {
                var s = e as LoadArgument;

                if (s.ReturnType.IsFixedArray && !(Parent is AddressOf))
                {
                    if (!u.IsObject())
                    {
                        Log.Error(e.Source, ErrorCode.E0000, "Fixed array argument " + Function.Parameters[s.Index].Quote() + " cannot be used as value in shader (in " + Generator.Path.Quote() + ")");
                    }

                    switch (Function.Parameters[s.Index].Modifier)
                    {
                    case ParameterModifier.Const:
                        if (Parent is StoreElement)
                        {
                            Log.Error(e.Source, ErrorCode.E0000, "Cannot store to fixed array argument " + Function.Parameters[s.Index].Quote() + " in shader (in " + Generator.Path.Quote() + ")");
                        }

                        e = new AddressOf(s, AddressType.Const);
                        Begin(ref e, u);
                        break;

                    default:
                        e = new AddressOf(s);
                        Begin(ref e, u);
                        break;
                    }
                }
            }
            break;

            case ExpressionType.StoreArgument:
            {
                var s = e as StoreArgument;

                if (s.ReturnType.IsFixedArray)
                {
                    Log.Error(e.Source, ErrorCode.E0000, "Cannot store to fixed array argument " + Function.Parameters[s.Index].Quote() + " in shader (in " + Generator.Path.Quote() + ")");
                }
            }
            break;

            case ExpressionType.LoadField:
            {
                var s = e as LoadField;

                if (s.Object == null)
                {
                    Log.Error(e.Source, ErrorCode.E5012, "Cannot read from static field " + s.Field.Quote() + " in shader (in " + Generator.Path.Quote() + ")");
                }

                ProcessType(e.Source, (e as LoadField).Field.DeclaringType);
            }
            break;

            case ExpressionType.StoreField:
            {
                var s = e as StoreField;

                if (s.Object == null)
                {
                    Log.Error(e.Source, ErrorCode.E5013, "Cannot write to static field " + s.Field.Quote() + " in shader (in " + Generator.Path.Quote() + ")");
                }

                ProcessType(e.Source, (e as StoreField).Field.DeclaringType);
            }
            break;

            case ExpressionType.CallBinOp:
            {
                var s = e as CallBinOp;

                if (s.TryTransformEnumBinOpToIntBinOp(Log, ref e) ||
                    TryProcessFunctionCall(ref e, s.Operator, new[] { s.Left, s.Right }))
                {
                    Begin(ref e, u);
                }
            }
            break;

            case ExpressionType.CallUnOp:
            {
                var s = e as CallUnOp;

                if (s.TryTransformEnumUnOpToIntUnOp(Log, ref e) ||
                    TryProcessFunctionCall(ref e, s.Operator, new[] { s.Operand }))
                {
                    Begin(ref e, u);
                }
            }
            break;

            case ExpressionType.CallCast:
            {
                var s = e as CallCast;

                if (TryProcessFunctionCall(ref e, s.Cast, new[] { s.Operand }))
                {
                    Begin(ref e, u);
                }
            }
            break;

            case ExpressionType.NewObject:
            {
                var s = e as NewObject;

                if (TryProcessFunctionCall(ref e, s.Constructor, s.Arguments))
                {
                    Begin(ref e, u);
                }
            }
            break;

            case ExpressionType.GetProperty:
            {
                var s = e as GetProperty;

                if (s.TryTransformGetFixedArrayLength(Log, ref e) ||
                    TryProcessFunctionCall(ref e, s.Property.GetMethod, s.Arguments, s.Object))
                {
                    Begin(ref e, u);
                }
            }
            break;

            case ExpressionType.SetProperty:
            {
                var s = e as SetProperty;

                if (s.TryTransformSetPropertyChainToSequence(Generator.Path.DrawBlock.Method.DeclaringType, Parent, ref e) ||
                    TryProcessFunctionCall(ref e, s.Property.SetMethod, s.Arguments, s.Value, s.Object))
                {
                    Begin(ref e, u);
                }
            }
            break;

            case ExpressionType.CallMethod:
            {
                var s = e as CallMethod;

                if (s.TryTransformEnumHasFlagToIntOps(Log, ref e) ||
                    TryProcessFunctionCall(ref e, s.Method, s.Arguments, s.Object))
                {
                    Begin(ref e, u);
                }
            }
            break;

            default:
                Log.Error(e.Source, ErrorCode.E5014, "<" + e.ExpressionType + "> is not supported in shader (in " + Generator.Path.Quote() + ")");
                break;
            }

            Parent = e;
        }
Example #13
0
        public override void Begin(ref Expression e, ExpressionUsage u)
        {
            _parent  = _current;
            _current = e;

            switch (e.ReturnType.TypeType)
            {
            case TypeType.Void:
            case TypeType.Enum:
            case TypeType.GenericParameter:
            case TypeType.RefArray:
                break;

            case TypeType.FixedArray:
                switch (e.ExpressionType)
                {
                case ExpressionType.AddressOf:
                case ExpressionType.GetMetaProperty:
                    break;

                default:
                    if (!(_parent is AddressOf))
                    {
                        Log.Error(e.Source, ErrorCode.I0000, "'fixed' arrays can only be loaded by address");
                    }
                    break;
                }

                break;

            case TypeType.Class:
            case TypeType.Struct:
            case TypeType.Delegate:
            case TypeType.Interface:
                if (Environment.IsGeneratingCode)
                {
                    break;
                }
                if (e.ReturnType.IsGenericDefinition || e.ReturnType.IsFlattenedDefinition)
                {
                    Log.Error(e.Source, ErrorCode.I4124, "Invalid expression returning unparameterized type " + e.ReturnType.Quote());
                }
                break;

            default:
                Log.Error(e.Source, ErrorCode.I4125, "Invalid expression returning " + e.ReturnType.Quote());
                break;
            }

            switch (e.ExpressionType)
            {
            case ExpressionType.Constant:
            {
                var s = e as Constant;
                if (s.Value == null)
                {
                    break;
                }

                var dt = s.ReturnType;
                if (dt.IsEnum)
                {
                    dt = dt.Base;
                }

                switch (dt.BuiltinType)
                {
                case BuiltinType.Bool:
                    if (s.Value is bool)
                    {
                        return;
                    }
                    break;

                case BuiltinType.Byte:
                    if (s.Value is byte)
                    {
                        return;
                    }
                    break;

                case BuiltinType.Char:
                    if (s.Value is char)
                    {
                        return;
                    }
                    break;

                case BuiltinType.Double:
                    if (s.Value is double)
                    {
                        return;
                    }
                    break;

                case BuiltinType.Int:
                    if (s.Value is int)
                    {
                        return;
                    }
                    break;

                case BuiltinType.Float:
                    if (s.Value is float)
                    {
                        return;
                    }
                    break;

                case BuiltinType.Long:
                    if (s.Value is long)
                    {
                        return;
                    }
                    break;

                case BuiltinType.SByte:
                    if (s.Value is sbyte)
                    {
                        return;
                    }
                    break;

                case BuiltinType.Short:
                    if (s.Value is short)
                    {
                        return;
                    }
                    break;

                case BuiltinType.String:
                    if (s.Value is string)
                    {
                        return;
                    }
                    break;

                case BuiltinType.UInt:
                    if (s.Value is uint)
                    {
                        return;
                    }
                    break;

                case BuiltinType.ULong:
                    if (s.Value is ulong)
                    {
                        return;
                    }
                    break;

                case BuiltinType.UShort:
                    if (s.Value is ushort)
                    {
                        return;
                    }
                    break;
                }

                Log.Error(s.Source, ErrorCode.I4113, "Constant was not of expected type " + dt.Quote() + ", but .NET:" + s.Value.GetType().Quote());
                break;
            }

            case ExpressionType.StoreLocal:
            {
                var s = e as StoreLocal;

                if (s.Variable.IsConstant)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Cannot write to constant " + s.Variable.Name.Quote());
                }
                else if (s.Variable.IsIterator)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Cannot write to foreach iterator variable " + s.Variable.Name.Quote());
                }
                else if (s.Variable.ValueType is FixedArrayType)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Cannot write to 'fixed' array variable " + s.Variable.Name.Quote());
                }
                break;
            }

            case ExpressionType.LoadField:
            {
                var s = e as LoadField;
                VerifyMemberAccess(s.Source, s.Object, s.Field);

                break;
            }

            case ExpressionType.StoreField:
            {
                var s = e as StoreField;
                VerifyWrite(s.Source, s.Field);
                VerifyLValue(s.Source, s.Object);
                VerifyMemberAccess(s.Source, s.Object, s.Field);

                if (s.Field.ReturnType is FixedArrayType)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Cannot write to 'fixed' array field " + s.Field.Quote());
                }
                break;
            }

            case ExpressionType.StoreElement:
            {
                var s = e as StoreElement;
                VerifyLValue(s.Source, s.Array);

                var a = s.Array as AddressOf;

                if (a != null && a.AddressType == AddressType.Const)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Cannot write to array because reference is 'const'");
                }
                break;
            }

            case ExpressionType.StoreThis:
            {
                var s = e as StoreThis;

                if (s.ReturnType.TypeType != TypeType.Struct)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Invalid write to 'this' because current type is not a struct");
                }
                break;
            }

            case ExpressionType.CallConstructor:
            {
                var s = e as CallConstructor;
                VerifyMemberAccess(s.Source, s.Constructor);
                VerifyArguments(s.Source, s.Constructor, s.Arguments);

                // Verify that base constructor is callable from current context
                if (Function.MemberType != MemberType.Constructor || Function.IsStatic)
                {
                    Log.Error(s.Source, ErrorCode.E4026, "Base contructor can only be called from instance constructor");
                }
                else if (s.Constructor.DeclaringType.MasterDefinition != Type.MasterDefinition &&
                         s.Constructor.DeclaringType != Type.Base)
                {
                    Log.Error(s.Source, ErrorCode.I0000, s.Constructor.Quote() + " cannot be called by " + Function.Quote());
                }
                else if (Type.IsValueType && s.Constructor.DeclaringType.IsReferenceType)
                {
                    Log.Error(s.Source, ErrorCode.I0000, s.Constructor.Quote() + " cannot be called by " + Function.Quote() + " because " + Type.Quote() + " is a struct");
                }
                else if (s.Constructor.MasterDefinition == Function.MasterDefinition)
                {
                    Log.Error(s.Source, ErrorCode.E0000, s.Constructor.Quote() + " cannot call itself (circular reference)");
                }

                // Verify that 'this' or 'base' is not used as an argument
                var p = new ThisVerifier(this);

                for (int i = 0; i < s.Arguments.Length; i++)
                {
                    p.Begin(ref s.Arguments[i], ExpressionUsage.Argument);
                    s.Arguments[i].Visit(p);
                    p.End(ref s.Arguments[i]);
                }

                break;
            }

            case ExpressionType.CallMethod:
            {
                var s = e as CallMethod;
                VerifyMemberAccess(s.Source, s.Object, s.Method);
                VerifyArguments(s.Source, s.Method, s.Arguments);
                break;
            }

            case ExpressionType.CallBinOp:
            {
                var s = e as CallBinOp;
                VerifyMemberAccess(s.Source, s.Operator);
                VerifyArguments(s.Source, s.Operator, s.Left, s.Right);
                break;
            }

            case ExpressionType.CallUnOp:
            {
                var s = e as CallUnOp;
                VerifyMemberAccess(s.Source, s.Operator);
                VerifyArguments(s.Source, s.Operator, s.Operand);
                break;
            }

            case ExpressionType.CallCast:
            {
                var s = e as CallCast;
                VerifyMemberAccess(s.Source, s.Cast);
                VerifyArguments(s.Source, s.Cast, s.Operand);
                break;
            }

            case ExpressionType.SetProperty:
            {
                var s = e as SetProperty;

                if (s.Property.SetMethod == null)
                {
                    Log.Error(s.Source, ErrorCode.I0000, s.Property.Quote() + " does not define a set accessor");
                }
                else
                {
                    VerifyMemberAccess(s.Source, s.Object, s.Property.SetMethod);
                    VerifyArguments(s.Source, s.Property.SetMethod, s.Arguments.Concat(s.Value));
                }
                break;
            }

            case ExpressionType.GetProperty:
            {
                var s = e as GetProperty;

                if (s.Property.GetMethod == null)
                {
                    Log.Error(s.Source, ErrorCode.I0000, s.Property.Quote() + " does not define a get accessor");
                }
                else
                {
                    VerifyMemberAccess(s.Source, s.Object, s.Property.GetMethod);
                    VerifyArguments(s.Source, s.Property.GetMethod, s.Arguments);
                }
                break;
            }

            case ExpressionType.AddListener:
            {
                var s = e as AddListener;

                if (s.Event.AddMethod == null)
                {
                    Log.Error(s.Source, ErrorCode.I0000, s.Event.Quote() + " does not define a set accessor");
                }
                else
                {
                    VerifyMemberAccess(s.Source, s.Object, s.Event.AddMethod);
                    VerifyArguments(s.Source, s.Event.AddMethod, s.Listener);
                }
                break;
            }

            case ExpressionType.RemoveListener:
            {
                var s = e as RemoveListener;

                if (s.Event.RemoveMethod == null)
                {
                    Log.Error(s.Source, ErrorCode.I0000, s.Event.Quote() + " does not define a get accessor");
                }
                else
                {
                    VerifyMemberAccess(s.Source, s.Object, s.Event.RemoveMethod);
                    VerifyArguments(s.Source, s.Event.RemoveMethod, s.Listener);
                }
                break;
            }

            case ExpressionType.NewObject:
            {
                var s = e as NewObject;
                VerifyMemberAccess(s.Source, s.Constructor);
                VerifyArguments(s.Source, s.Constructor, s.Arguments);
                VerifyObsolete(s.Source, s.Constructor.DeclaringType);

                if (s.ReturnType.IsAbstract)
                {
                    Log.Error(s.Source, ErrorCode.E4075, "Cannot instantiate abstract class " + s.ReturnType.Quote());
                }
                else if (s.ReturnType.IsStatic)
                {
                    Log.Error(s.Source, ErrorCode.E4076, "Cannot instantiate static class " + s.ReturnType.Quote());
                }
                break;
            }

            case ExpressionType.NewArray:
            {
                var s = e as NewArray;
                VerifyDataTypeAccess(s.Source, s.ReturnType.ElementType);

                if (s.Size == null && s.Initializers == null)
                {
                    Log.Error(s.Source, ErrorCode.I0000, "Expected array size or initializer for " + s.ArrayType.Quote());
                }
                break;
            }

            case ExpressionType.NewDelegate:
            {
                var s = e as NewDelegate;
                VerifyDataTypeAccess(s.Source, s.ReturnType);
                VerifyMemberAccess(s.Source, s.Method);

                if (!s.Method.IsStatic && s.Object == null)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Object is required for non-static method " + s.Method.Quote());
                }
                else if (s.Method.IsStatic && s.Object != null)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Invalid object specified for static method " + s.Method.Quote());
                }

                if (!(
                        s.Method.ReturnType.Equals(s.DelegateType.ReturnType) ||
                        s.Method.ReturnType.IsReferenceType && s.Method.ReturnType.IsSubclassOfOrEqual(s.DelegateType.ReturnType)) ||
                    !s.DelegateType.CompareParametersEqualOrSubclassOf(s.Method)
                    )
                {
                    Log.Error(s.Source, ErrorCode.I0000, "Invalid return type or parameter list on method " + s.Method.Quote() + " bound to delegate " + s.DelegateType.Quote());
                }

                if (s.Object != null && !s.Object.ReturnType.IsReferenceType)
                {
                    Log.Error(s.Source, ErrorCode.I0000, "Delegate instance field must be a reference type (was " + s.Object.ReturnType.Quote() + ")");
                }
                break;
            }

            case ExpressionType.This:
            {
                var s = e as This;

                if (Function == null)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "'this' not allowed in current context");
                }
                else if (Function.IsStatic)
                {
                    Log.Error(s.Source, ErrorCode.E4081, "'this' not allowed in static context");
                }
                else if (s.ReturnType.MasterDefinition != Function.DeclaringType.MasterDefinition)
                {
                    Log.Error(s.Source, ErrorCode.I4082, "'this' has an invalid data type");
                }
                break;
            }

            case ExpressionType.Base:
            {
                var s = e as Base;

                if (Function == null)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "'base' not allowed in current context");
                }
                else if (Function.IsStatic)
                {
                    Log.Error(s.Source, ErrorCode.E4083, "'base' not allowed in static context");
                }
                else if (s.ReturnType != Function.DeclaringType.Base)
                {
                    Log.Error(s.Source, ErrorCode.I4084, "'base' has an invalid data type");
                }
                else
                {
                    // Verify that 'base' is not used illegally
                    if (_parent != null)
                    {
                        switch (_parent.ExpressionType)
                        {
                        case ExpressionType.LoadField:
                        case ExpressionType.StoreField:
                        case ExpressionType.GetProperty:
                        case ExpressionType.SetProperty:
                        case ExpressionType.CallMethod:
                        case ExpressionType.AddListener:
                        case ExpressionType.RemoveListener:
                            return;
                        }
                    }

                    Log.Error(s.Source, ErrorCode.E4085, "'base' not allowed in current context");
                }
                break;
            }

            case ExpressionType.FixOp:
            {
                var s = e as FixOp;

                switch (s.Operand.ExpressionType)
                {
                case ExpressionType.LoadArgument:
                case ExpressionType.LoadLocal:
                case ExpressionType.LoadElement:
                case ExpressionType.LoadField:
                    VerifyLValue(s.Source, s.Operand);
                    break;

                default:
                    Log.Error(s.Source, ErrorCode.E4114, "'++'/'--' is not valid because " + s.Operand.Quote() + " is not a variable");
                    break;
                }

                break;
            }

            case ExpressionType.TypeOf:
            {
                var s = e as TypeOf;

                if (s.Type.HasAttribute(Essentials.TargetSpecificTypeAttribute))
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Invalid 'typeof' on target specific type");
                }

                break;
            }

            // TODO: Check flattened generic type definitions, figure out how to handle generic parameter types.

            case ExpressionType.IsOp:
            {
                var s = e as IsOp;
                VerifyDataTypeAccess(s.Source, s.TestType);

                if (s.Operand.ReturnType.HasAttribute(Essentials.TargetSpecificTypeAttribute) || s.ReturnType.HasAttribute(Essentials.TargetSpecificTypeAttribute))
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Invalid 'is' on target specific type");
                }
                break;
            }

            case ExpressionType.AsOp:
            {
                var s = e as AsOp;
                VerifyDataTypeAccess(s.Source, s.TestType);

                if (!s.Operand.ReturnType.IsReferenceType)
                {
                    Log.Error(s.Source, ErrorCode.E4116, "'as' is not valid because " + s.Operand.ReturnType.Quote() + " is not a reference type");
                }
                else if (!s.ReturnType.IsReferenceType)
                {
                    Log.Error(s.Source, ErrorCode.E4117, "'as' is not valid because " + s.ReturnType.Quote() + " is not a reference type");
                }
                else if (!s.ReturnType.IsRelatedTo(s.Operand.ReturnType) &&
                         !s.ReturnType.IsInterface && !s.Operand.ReturnType.IsInterface &&
                         !s.ReturnType.IsGenericType)
                {
                    Log.Error(s.Source, ErrorCode.E4118, s.Operand.ReturnType.Quote() + " cannot be converted to " + s.ReturnType.Quote() + " because the types are not related");
                }
                else if (s.Operand.ReturnType.HasAttribute(Essentials.TargetSpecificTypeAttribute) || s.ReturnType.HasAttribute(Essentials.TargetSpecificTypeAttribute))
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Invalid 'as' on target specific type");
                }
                break;
            }

            case ExpressionType.ReferenceOp:
            {
                var s = e as ReferenceOp;

                if (!s.Left.ReturnType.IsReferenceType ||
                    !s.Right.ReturnType.IsReferenceType ||
                    !s.Left.ReturnType.IsRelatedTo(s.Right.ReturnType) && !s.Left.ReturnType.IsInterface && !s.Right.ReturnType.IsInterface)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Operator '==' cannot be applied to operands of type " + s.Left.ReturnType.Quote() + " and " + s.Right.ReturnType.Quote());
                }
                break;
            }

            case ExpressionType.CastOp:
            {
                var s = e as CastOp;
                VerifyDataTypeAccess(s.Source, s.ReturnType);

                if (!s.ReturnType.IsInterface &&
                    !s.Operand.ReturnType.IsInterface &&
                    !s.ReturnType.IsSubclassOf(s.Operand.ReturnType) &&
                    !s.ReturnType.IsImplementingInterface(s.Operand.ReturnType) &&
                    !(s.ReturnType.IsGenericParameter && s.Operand.ReturnType.IsReferenceType) &&
                    !s.Operand.ReturnType.IsSubclassOf(s.ReturnType) &&
                    !s.Operand.ReturnType.IsImplementingInterface(s.ReturnType))
                {
                    Log.Error(s.Source, ErrorCode.I4119, "Invalid cast from " + s.Operand.ReturnType.Quote() + " to " + s.ReturnType.Quote());
                }

                if (s.ReturnType.IsClass && s.ReturnType.HasAttribute(Essentials.TargetSpecificTypeAttribute) ||
                    s.Operand.ReturnType.IsClass && s.Operand.ReturnType.HasAttribute(Essentials.TargetSpecificTypeAttribute))
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Cannot cast [TargetSpecificType] class");
                }
                break;
            }

            case ExpressionType.AddressOf:
            {
                var s = e as AddressOf;

                switch (s.AddressType)
                {
                case AddressType.Ref:
                case AddressType.Out:
                    switch (s.Operand.ExpressionType)
                    {
                    case ExpressionType.LoadLocal:
                    case ExpressionType.LoadArgument:
                    case ExpressionType.LoadField:
                    case ExpressionType.LoadElement:
                        return;
                    }

                    Log.Error(s.Source, ErrorCode.E4126, "Only local variables, function parameters, fields and array elements may be passed as ref/out-arguments.");
                    break;

                default:
                    switch (s.Operand.ExpressionType)
                    {
                    case ExpressionType.AddressOf:
                        break;

                    default:
                        switch (s.ReturnType.TypeType)
                        {
                        case TypeType.FixedArray:
                            return;

                        case TypeType.Enum:
                        case TypeType.Struct:
                        case TypeType.GenericParameter:
                            if (!u.IsObject())
                            {
                                Log.Error(s.Source, ErrorCode.I0000, "Address cannot be used as value " + s.Quote());
                            }
                            return;
                        }
                        break;
                    }

                    Log.Error(s.Source, ErrorCode.I0000, "Invalid address " + s.Quote());
                    break;
                }
                break;
            }

            case ExpressionType.StageOp:
            {
                var s = e as StageOp;

                if (MetaProperty != null)
                {
                    var stage = _stageStack.Last();

                    if (stage != MetaStage.Undefined && stage < s.Stage)
                    {
                        Log.Error(s.Source, ErrorCode.E0000, "Invalid " + s.Stage.ToLiteral().Quote() + " operator inside a " + stage.ToLiteral().Quote() + " operator");
                    }

                    _stageStack.Add(s.Stage);
                }
                else
                {
                    Log.Error(s.Source, ErrorCode.E0000, s.Stage.ToLiteral().Quote() + " operator is not allowed in current context");
                }
                break;
            }

            case ExpressionType.GetMetaProperty:
            {
                var s = e as GetMetaProperty;

                if (MetaProperty != null && s.Offset == 0 && MetaProperty.Name == s.Name)
                {
                    Log.Error(s.Source, ErrorCode.E0000, "Not allowed for meta property to refer to itself");
                }
                break;
            }

            case ExpressionType.NewVertexAttrib:
            {
                if (MetaProperty == null)
                {
                    Log.Error(e.Source, ErrorCode.E0000, "'vertex_attrib' is not allowed in current context");
                }
                break;
            }

            case ExpressionType.NewPixelSampler:
            {
                if (MetaProperty == null)
                {
                    Log.Error(e.Source, ErrorCode.E0000, "'pixel_sampler' is not allowed in current context");
                }
                break;
            }

            case ExpressionType.LoadVertexAttrib:
            {
                var sf = Function as ShaderFunction;

                if (sf == null || sf.Shader.Type != ShaderType.Vertex)
                {
                    Log.Error(e.Source, ErrorCode.I0000, "Invalid vertex attribute load outside of vertex shader");
                }
                break;
            }

            case ExpressionType.LoadVarying:
            {
                var sf = Function as ShaderFunction;

                if (sf == null || sf.Shader.Type != ShaderType.Pixel)
                {
                    Log.Error(e.Source, ErrorCode.I0000, "Invalid varying load outside of pixel shader");
                }
                break;
            }

            case ExpressionType.RuntimeConst:
            {
                var s  = e as RuntimeConst;
                var sf = Function as ShaderFunction;

                if (sf == null || !sf.Shader.ReferencedConstants.Contains(s.Index))
                {
                    Log.Error(e.Source, ErrorCode.I0000, "Invalid shader constant reference outside of shader declaring the constant");
                }
                break;
            }

            case ExpressionType.LoadUniform:
            {
                var s  = e as LoadUniform;
                var sf = Function as ShaderFunction;

                if (sf == null || !sf.Shader.ReferencedUniforms.Contains(s.Index))
                {
                    Log.Error(e.Source, ErrorCode.I0000, "Invalid uniform reference outside of shader declaring the uniform");
                }
                break;
            }

            case ExpressionType.LoadPixelSampler:
            {
                var sf = Function as ShaderFunction;

                if (sf == null || sf.Shader.Type != ShaderType.Pixel)
                {
                    Log.Error(e.Source, ErrorCode.I0000, "Invalid pixel sampler reference outside of pixel shader declaring the sampler");
                }
                break;
            }

            case ExpressionType.CallShader:
            {
                var s  = e as CallShader;
                var sf = Function as ShaderFunction;

                if (sf == null || !sf.Shader.Functions.Contains(s.Function))
                {
                    Log.Error(e.Source, ErrorCode.I0000, "Invalid function call outside of shader declaring the function");
                }
                break;
            }

            case ExpressionType.CapturedLocal:
            case ExpressionType.CapturedArgument:
            {
                if (MetaProperty == null)     // TODO: Verify that meta property has draw block as parent (somewhere)
                {
                    Log.Error(e.Source, ErrorCode.I0000, "Invalid variable capture outside of draw block");
                }
                break;
            }

            case ExpressionType.Lambda:
            {
                _lambdas.Push((Lambda)e);
                break;
            }

            case ExpressionType.ExternOp:
            {
                VerifyExtern(e);
                break;
            }
            }
        }
Example #14
0
 public override void WriteCast(Source src, DataType dt, Expression s, ExpressionUsage u = ExpressionUsage.Argument)
 {
     Begin(u.IsObject());
     WriteExpression(s, ExpressionUsage.Operand);
     End(u.IsObject());
 }