void WriteSequenceOp(SequenceOp s, ExpressionUsage u, bool parentIsSequenceOp) { Begin(!parentIsSequenceOp); if (s.Left is SequenceOp) { WriteSequenceOp(s.Left as SequenceOp, ExpressionUsage.Statement, true); } else { WriteExpression(s.Left, ExpressionUsage.Statement); } Write(Comma); if (s.Right is SequenceOp) { WriteSequenceOp(s.Right as SequenceOp, u, true); } else { WriteExpression(s.Right, u); } End(!parentIsSequenceOp); }
public static bool TryCreateReadonlyValueFieldIndirection(Namescope scope, ref Expression e) { var address = e as AddressOf; var lf = address?.Operand as LoadField; if (lf == null) { return(false); } var f = lf.Field; var dt = f.ReturnType; if (f.FieldModifiers.HasFlag(FieldModifiers.ReadOnly) && dt.IsValueType) { Expression ind; if (TryCreateIndirection(scope, ref e, out ind)) { e = new SequenceOp(ind, e); return(true); } } return(false); }
// TODO: Get rid of parent parameter public static bool TryTransformSetPropertyChainToSequence(this SetProperty s, Namescope scope, Statement parent, ref Expression result) { if (parent == null || parent is SequenceOp && (parent as SequenceOp).Left == s) { return(false); } var ind = TryCreateIndirection(scope, ref s.Value); result = new SequenceOp(s, s.Value); if (ind != null) { result = new SequenceOp(ind, result); } return(true); }
void OnObject(ref Expression e) { if (e == null) { return; } switch (e.ExpressionType) { case ExpressionType.LoadField: OnObject(ref (e as LoadField).Object); return; case ExpressionType.AddressOf: OnObject(ref (e as AddressOf).Operand); return; case ExpressionType.LoadElement: case ExpressionType.LoadArgument: case ExpressionType.LoadLocal: case ExpressionType.This: return; } if (MustCopyType(e.ReturnType) && MustCopyValue(e)) { if (e.ExpressionType == ExpressionType.SequenceOp && (e as SequenceOp).Right.ExpressionType == ExpressionType.AddressOf) { var s = e as SequenceOp; s.Right = (s.Right as AddressOf).Operand; } var v = new Variable(e.Source, Function, Type.GetUniqueIdentifier("struct"), e.ReturnType, VariableType.Default, new Default(e.Source, e.ReturnType)); e = new SequenceOp( new StoreLocal(e.Source, v, e), new LoadLocal(e.Source, v)); } }
public Expression CompileExpression(AstExpression e) { switch (e.ExpressionType) { case AstExpressionType.Initializer: { var s = (AstInitializer)e; var root = CompileExpression(s.Expressions[0]); for (var i = 1; i < s.Expressions.Count; i++) { root = new SequenceOp(root, CompileExpression(s.Expressions[i])); } return(root); } case AstExpressionType.Identifier: return(CompilePartial(ResolveIdentifier(e as AstIdentifier, null))); case AstExpressionType.Macro: return(new ExternString(e.Source, Essentials.String, ((AstMacro)e).Value, GetUsings(e.Source))); case AstExpressionType.Void: case AstExpressionType.Global: case AstExpressionType.Generic: case AstExpressionType.BuiltinType: case AstExpressionType.Array: case AstExpressionType.FixedArray: case AstExpressionType.Parameterizer: return(CompilePartial(NameResolver.ResolveExpression(Namescope, e, null))); case AstExpressionType.Add: case AstExpressionType.Sub: case AstExpressionType.Mul: case AstExpressionType.Div: case AstExpressionType.Mod: case AstExpressionType.NullOp: case AstExpressionType.LogAnd: case AstExpressionType.LogOr: case AstExpressionType.Equal: case AstExpressionType.NotEqual: case AstExpressionType.LessThan: case AstExpressionType.LessThanOrEqual: case AstExpressionType.GreaterThan: case AstExpressionType.GreaterThanOrEqual: case AstExpressionType.BitwiseAnd: case AstExpressionType.BitwiseOr: case AstExpressionType.BitwiseXor: case AstExpressionType.ShiftLeft: case AstExpressionType.ShiftRight: case AstExpressionType.Assign: case AstExpressionType.AddAssign: case AstExpressionType.SubAssign: case AstExpressionType.MulAssign: case AstExpressionType.DivAssign: case AstExpressionType.ModAssign: case AstExpressionType.BitwiseAndAssign: case AstExpressionType.BitwiseOrAssign: case AstExpressionType.BitwiseXorAssign: case AstExpressionType.ShiftLeftAssign: case AstExpressionType.ShiftRightAssign: case AstExpressionType.LogAndAssign: case AstExpressionType.LogOrAssign: case AstExpressionType.Sequence: return(CompileBinOp(e as AstBinary)); case AstExpressionType.DecreasePrefix: case AstExpressionType.DecreasePostfix: case AstExpressionType.IncreasePrefix: case AstExpressionType.IncreasePostfix: case AstExpressionType.Negate: case AstExpressionType.LogNot: case AstExpressionType.BitwiseNot: return(CompileUnOp(e as AstUnary)); case AstExpressionType.Cast: return(CompileCast(e as AstCast)); case AstExpressionType.Call: return(CompileCall(e as AstCall)); case AstExpressionType.LookUp: return(CompilePartial(ResolveLookUp(e as AstCall))); case AstExpressionType.Member: return(CompilePartial(ResolveMember(e as AstMember, null))); case AstExpressionType.New: return(CompileNewExpression(e as AstNew)); case AstExpressionType.This: return(CompileThis(e.Source)); case AstExpressionType.Base: return(CompileBase(e.Source)); case AstExpressionType.Import: return(CompileImport(e as AstImport)); case AstExpressionType.VertexAttribImplicit: return(CompileVertexAttribImplicit(e as AstVertexAttribImplicit)); case AstExpressionType.VertexAttribExplicit: return(CompileVertexAttribExplicit(e as AstVertexAttribExplicit)); case AstExpressionType.Null: return(new Constant(e.Source, DataType.Null, null)); case AstExpressionType.Defined: return(new Constant(e.Source, Essentials.Bool, Environment.Test(e.Source, (e as AstDefined).Condition))); case AstExpressionType.Default: return(new Default(e.Source, NameResolver.GetType(Namescope, ((AstUnary)e).Operand))); case AstExpressionType.True: return(new Constant(e.Source, Essentials.Bool, true)); case AstExpressionType.False: return(new Constant(e.Source, Essentials.Bool, false)); case AstExpressionType.Zero: return(new Constant(e.Source, Essentials.Int, 0)); case AstExpressionType.Int: return(new Constant(e.Source, Essentials.Int, ((AstInt)e).Value)); case AstExpressionType.UInt: return(new Constant(e.Source, Essentials.UInt, ((AstUInt)e).Value)); case AstExpressionType.Long: return(new Constant(e.Source, Essentials.Long, ((AstLong)e).Value)); case AstExpressionType.ULong: return(new Constant(e.Source, Essentials.ULong, ((AstULong)e).Value)); case AstExpressionType.Float: return(new Constant(e.Source, Essentials.Float, ((AstFloat)e).Value)); case AstExpressionType.Double: return(new Constant(e.Source, Essentials.Double, ((AstDouble)e).Value)); case AstExpressionType.Char: return(new Constant(e.Source, Essentials.Char, ((AstChar)e).Value)); case AstExpressionType.String: return(new Constant(e.Source, Essentials.String, ((AstString)e).Value)); case AstExpressionType.Unchecked: { CheckCastStack.Add(false); var result = CompileExpression(((AstUnary)e).Operand); CheckCastStack.RemoveLast(); return(result); } case AstExpressionType.ReadOnly: { var s = e as AstUnary; return(new StageOp(s.Source, MetaStage.ReadOnly, CompileExpression(s.Operand))); } case AstExpressionType.Volatile: { var s = e as AstUnary; return(new StageOp(s.Source, MetaStage.Volatile, CompileExpression(s.Operand))); } case AstExpressionType.Vertex: { var s = e as AstUnary; return(new StageOp(s.Source, MetaStage.Vertex, CompileExpression(s.Operand))); } case AstExpressionType.Pixel: { var s = e as AstUnary; return(new StageOp(s.Source, MetaStage.Pixel, CompileExpression(s.Operand))); } case AstExpressionType.Extern: { var s = (AstExtern)e; return(new ExternOp(s.Value.Source, Compiler.CompileAttributes(Namescope, s.Attributes), s.OptionalType != null ? NameResolver.GetType(Namescope, s.OptionalType) : DataType.Void, s.Value.String, ExtensionTransform.CreateObject(s.Source, Function, TypeBuilder.Parameterize(Function.DeclaringType)), s.OptionalArguments != null ? CompileArgumentList(s.OptionalArguments) : ExtensionTransform.CreateArgumentList(s.Source, Function), GetUsings(s.Source))); } case AstExpressionType.Ternary: { var s = e as AstTernary; if (s.Condition is AstDefined) { var def = s.Condition as AstDefined; var result = Environment.Test(def.Source, def.Condition) ? CompileExpression(s.True) : CompileExpression(s.False); return(result.ReturnType.IsNull ? Error(s.Source, ErrorCode.E0000, "Cannot resolve type of <null> in constant folded conditional expression") : result); } var cond = CompileImplicitCast(s.Condition.Source, Essentials.Bool, CompileExpression(s.Condition)); var left = CompileExpression(s.True); var right = CompileExpression(s.False); if (!left.ReturnType.IsNull) { right = CompileImplicitCast(s.False.Source, left.ReturnType, right); } else if (!right.ReturnType.IsNull) { left = CompileImplicitCast(s.True.Source, right.ReturnType, left); } else { return(Error(s.Source, ErrorCode.E2086, "The type of the conditional expression could not be resolved because there is no implicit conversion between <null> and <null>")); } return(new ConditionalOp(s.Source, cond, left, right)); } case AstExpressionType.Local: { var s = e as AstLocal; var p = TryResolveLocalIdentifier(s.Name); if (p == null && Namescope is BlockBase) { p = TryResolveCapturedLocalIdentifier(Namescope as BlockBase, s.Name); } return(p != null ? CompilePartial(p) : Error(e.Source, ErrorCode.E0000, s.Name.Quote() + " is not a local variable or method parameter")); } case AstExpressionType.Prev: { var s = e as AstPrev; if (s.OptionalName != null) { var b = CompileExpression(s.OptionalName); if (b.IsInvalid) { return(b); } var mp = b as GetMetaProperty; return(mp == null ? Error(s.OptionalName.Source, ErrorCode.E2035, b.Quote() + " is not a meta property") : new GetMetaProperty(s.Source, mp.ReturnType, mp.Name, mp.Offset + s.Offset)); } return(MetaProperty != null ? new GetMetaProperty(s.Source, MetaProperty.ReturnType, MetaProperty.Name, 1) : Error(s.Source, ErrorCode.E2036, "Current scope is not a meta property scope")); } case AstExpressionType.PixelSampler: { var s = e as AstPixelSampler; var texture = CompileExpression(s.Texture); Expression samplerState = null; if (s.OptionalState != null) { var samplerStateType = ILFactory.GetType(s.OptionalState.Source, "Uno.Graphics.SamplerState"); samplerState = CompileImplicitCast(s.OptionalState.Source, samplerStateType, CompileExpression(s.OptionalState)); } switch (texture.ReturnType.BuiltinType) { case BuiltinType.Texture2D: return(new NewPixelSampler(s.Source, Essentials.Sampler2D, texture, samplerState)); case BuiltinType.TextureCube: return(new NewPixelSampler(s.Source, Essentials.SamplerCube, texture, samplerState)); case BuiltinType.VideoTexture: return(new NewPixelSampler(s.Source, Essentials.VideoSampler, texture, samplerState)); } return(!texture.IsInvalid ? Error(s.Texture.Source, ErrorCode.E0000, "First argument to 'pixel_sampler' must be an object of type 'texture2D' or 'textureCube'") : Expression.Invalid); } case AstExpressionType.Is: { var s = (AstBinary)e; var obj = CompileExpression(s.Left); var type = NameResolver.GetType(Namescope, s.Right); return(new IsOp(e.Source, obj, type, Essentials.Bool)); } case AstExpressionType.As: { var s = (AstBinary)e; var obj = CompileExpression(s.Left); var type = NameResolver.GetType(Namescope, s.Right); return(new AsOp(e.Source, obj, type)); } case AstExpressionType.SizeOf: { var s = (AstUnary)e; var dt = NameResolver.GetType(Namescope, s.Operand); return(new Constant(s.Source, Essentials.Int, NameResolver.GetSizeOf(s.Source, dt))); } case AstExpressionType.TypeOf: { var s = (AstUnary)e; return(new TypeOf(s.Source, Essentials.Type, NameResolver.GetType(Namescope, s.Operand))); } case AstExpressionType.NameOf: { // TODO: Missing verification var s = (AstUnary)e; return(new Constant(s.Source, Essentials.String, ResolveExpression(s.Operand, null).ToString())); } case AstExpressionType.Lambda: return(CompileLambda((AstLambda)e)); case AstExpressionType.ArrayInitializer: return(Error(e.Source, ErrorCode.E2075, "Array initializers are not supported in this context")); } return(e is AstIL ? (e as AstIL).Expression : Error(e.Source, ErrorCode.I2042, "Unhandled expression type in CompileExpression: " + e.ExpressionType)); }
public Expression CompileNewExpression(AstNew e) { // Implicitly typed arrays if (e.OptionalType == null) { if (e.OptionalArguments != null) { return(Error(e.Source, ErrorCode.E2001, "Array constructors cannot have argument list")); } if (e.OptionalArraySize != null) { return(Error(e.Source, ErrorCode.E2002, "Cannot specify size on implicitly typed arrays")); } if (e.OptionalCollectionInitializer == null || e.OptionalCollectionInitializer.Count == 0) { return(Error(e.Source, ErrorCode.E2003, "Must provide non-empty initializer list for implicitly typed arrays")); } var values = new Expression[e.OptionalCollectionInitializer.Count]; for (int i = 0; i < values.Length; i++) { values[i] = CompileExpression(e.OptionalCollectionInitializer[i]); } var et = TryGetImplicitElementType(values); if (et == null) { return(Error(e.Source, ErrorCode.E2004, "No best type found for implicitly typed array")); } for (int i = 0; i < values.Length; i++) { values[i] = CompileImplicitCast(e.Source, et, values[i]); } return(et.IsValueType || et.IsReferenceType ? new NewArray(e.Source, TypeBuilder.GetArray(et), values) : et != DataType.Invalid ? Error(e.Source, ErrorCode.E2080, "Cannot create an implicitly typed array of type " + et.Quote()) : Expression.Invalid); } var dt = NameResolver.GetType(Namescope, e.OptionalType); switch (dt.TypeType) { case TypeType.RefArray: { if (e.OptionalArguments != null) { return(Error(e.Source, ErrorCode.E2005, "Array constructors cannot have argument list")); } var at = dt as RefArrayType; Expression size = null; if (e.OptionalArraySize != null) { size = CompileImplicitCast(e.Source, Essentials.Int, CompileExpression(e.OptionalArraySize)); if (size.IsInvalid) { return(Expression.Invalid); } } if (e.OptionalCollectionInitializer != null) { var values = new Expression[e.OptionalCollectionInitializer.Count]; for (int i = 0; i < values.Length; i++) { values[i] = CompileExpression(e.OptionalCollectionInitializer[i]); } if (size != null) { var c = Compiler.ConstantFolder.TryMakeConstant(size); if (c == null || !c.Value.Equals(values.Length)) { return(Error(size.Source, ErrorCode.E2006, "Inconsistent array size and initializer list length")); } } switch (at.ElementType.BuiltinType) { case BuiltinType.Bool: case BuiltinType.Byte: case BuiltinType.Char: case BuiltinType.Double: case BuiltinType.Int: case BuiltinType.Float: case BuiltinType.Long: case BuiltinType.SByte: case BuiltinType.Short: case BuiltinType.UInt: case BuiltinType.ULong: case BuiltinType.UShort: // Disable warning on primitive types break; default: if (TryGetImplicitElementType(values) == at.ElementType) { Log.Warning3(e.Source, ErrorCode.W2007, "Array can be instantiated as implicitly typed array (new[] { ... })"); } break; } for (int i = 0; i < values.Length; i++) { values[i] = CompileImplicitCast(values[i].Source, at.ElementType, values[i]); } return(new NewArray(e.Source, at, values)); } return(new NewArray(e.Source, at, size)); } case TypeType.Class: case TypeType.Struct: case TypeType.GenericParameter: { if (dt.IsStatic) { return(Error(e.Source, ErrorCode.E2090, "Cannot instantiate static class")); } if (e.OptionalArguments != null || e.OptionalCollectionInitializer != null) { if (e.OptionalArraySize != null) { return(Error(e.Source, ErrorCode.E2008, "Object constructors cannot have array size")); } Expression newObject; if (dt.IsStruct && (e.OptionalArguments == null || e.OptionalArguments.Count == 0)) { newObject = new Default(e.Source, dt); } else { dt.PopulateMembers(); Constructor ctor; Expression[] args; if (!TryResolveConstructorOverload(e.Source, dt.Constructors, e.OptionalArguments ?? AstArgument.Empty, out ctor, out args)) { return(e.OptionalArguments != null && e.OptionalArguments.Count > 0 ? (dt.Constructors.Count == 1 ? Error(e.Source, ErrorCode.E2009, "Call to " + (dt + PrintableParameterList(dt.Constructors[0].Parameters)).Quote() + " has some invalid arguments " + PrintableArgumentList(e.OptionalArguments)) : Error(e.Source, ErrorCode.E2009, dt.Quote() + " has no constructors matching the argument list " + PrintableArgumentList(e.OptionalArguments) + NameResolver.SuggestCandidates(dt.Constructors))) : Error(e.Source, ErrorCode.E0000, dt.Quote() + " has no default constructor")); } newObject = new NewObject(e.Source, ctor, args); } if (e.OptionalCollectionInitializer != null && e.OptionalCollectionInitializer.Count > 0) { var var = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("collection"), newObject.ReturnType); CurrentVariableScope.Variables.Add(var.Name, var); Expression root = new StoreLocal(e.Source, var, newObject); // See if it is a member initializer or collection initializer var containsAssignOp = false; foreach (var i in e.OptionalCollectionInitializer) { if (i is AstBinary && (i as AstBinary).IsAssign) { containsAssignOp = true; break; } } if (containsAssignOp) { var initedMembers = new List <string>(); // Assign members foreach (var i in e.OptionalCollectionInitializer) { var binOp = i as AstBinary; if (binOp == null || binOp.Type != AstBinaryType.Assign || !(binOp.Left is AstIdentifier)) { Log.Error(i.Source, ErrorCode.E2077, "Invalid initalizer member declarator"); continue; } var id = (AstIdentifier)binOp.Left; var member = new AstMember(new AstIdentifier(i.Source, var.Name), id); if (binOp.Right is AstArrayInitializer) { var ai = binOp.Right as AstArrayInitializer; var collection = CompileExpression(member); var cvar = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("array"), collection.ReturnType); CurrentVariableScope.Variables.Add(cvar.Name, cvar); root = new SequenceOp(root, new StoreLocal(collection.Source, cvar, collection)); if (collection.IsInvalid) { continue; } foreach (var ci in ai.Values) { root = new SequenceOp(root, CompileAddToCollection(cvar.Name, ci)); } } else { var assign = CompileAssign(new AstBinary(AstBinaryType.Assign, member, i.Source, binOp.Right)); root = new SequenceOp(root, assign); if (assign.IsInvalid) { continue; } } foreach (var m in initedMembers) { if (m == id.Symbol) { Log.Error(i.Source, ErrorCode.E2078, "Duplicate initialization of member " + id.Symbol.Quote()); break; } } initedMembers.Add(id.Symbol); } } else { // Add to collection foreach (var i in e.OptionalCollectionInitializer) { root = new SequenceOp(root, CompileAddToCollection(var.Name, i)); } } return(new SequenceOp(root, new LoadLocal(e.Source, var))); } if (e.OptionalType is AstBuiltinType && dt.IsStruct) { Log.Warning(e.Source, ErrorCode.W0000, "Redundant 'new' operator on builtin struct initialization"); } return(newObject); } return(Error(e.Source, ErrorCode.E2011, "Must provide argument list for object constructor")); } case TypeType.Delegate: { if (e.OptionalArguments == null) { return(Error(e.Source, ErrorCode.E0000, "Must provide argument list for delegate constructor")); } var args = CompileArgumentList(e.OptionalArguments); if (e.OptionalCollectionInitializer != null) { return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have collection initializer")); } if (e.OptionalArraySize != null) { return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have array size")); } if (args.Length != 1 || args[0].ExpressionType != ExpressionType.MethodGroup) { return(Error(e.Source, ErrorCode.E0000, "Delegate construction requires one method argument")); } return(CompileImplicitCast(e.Source, dt, args[0])); } case TypeType.Invalid: return(Expression.Invalid); default: return(Error(e.Source, ErrorCode.E2012, "Instances of type " + dt.Quote() + " cannot be created using 'new' because it is not a class, struct or array type")); } }
public override void Begin(ref Expression e, ExpressionUsage u) { switch (e.ExpressionType) { case ExpressionType.FixOp: { var s = (FixOp)e; GetIndirection(ref s.Operand); break; } case ExpressionType.AddressOf: { var s = (AddressOf)e; switch (s.AddressType) { case AddressType.Out: case AddressType.Ref: GetIndirection(ref s.Operand); break; } break; } case ExpressionType.StoreField: { var s = e as StoreField; OnObject(ref s.Object); break; } case ExpressionType.StoreElement: { var s = e as StoreElement; OnObject(ref s.Array); break; } case ExpressionType.StoreArgument: { Variable var; var s = e as StoreArgument; if (GetIndirection(s.Index, s.Parameter, out var)) { e = new StoreLocal(s.Source, var, s.Value); Begin(ref e, u); } else { VerifyPointer(s.Parameter, s.Value); } break; } case ExpressionType.LoadArgument: { Variable var; var s = e as LoadArgument; if (GetIndirection(s.Index, s.Parameter, out var)) { e = new LoadLocal(s.Source, var); Begin(ref e, u); } break; } case ExpressionType.StoreLocal: { var s = e as StoreLocal; VerifyPointer(s.Variable, s.Value); break; } case ExpressionType.LoadField: { var s = e as LoadField; OnObject(ref s.Object); break; } case ExpressionType.LoadElement: { var s = e as LoadElement; OnObject(ref s.Array); break; } case ExpressionType.AddListener: case ExpressionType.RemoveListener: case ExpressionType.GetProperty: case ExpressionType.SetProperty: case ExpressionType.CallMethod: case ExpressionType.CallDelegate: { var s = (CallExpression)e; OnObject(ref s.Object); if (!s.Function.ReturnType.IsVoid && ( Backend.IsConstrained(s.Function) || s.Object is Base && s.Function.IsVirtual) ) { s.Storage = new Variable(s.Source, Function, Type.GetUniqueIdentifier("ret"), s.Function.ReturnType, VariableType.Indirection); Variables.Add(s.Storage); } break; } case ExpressionType.NewDelegate: { var s = (NewDelegate)e; OnObject(ref s.Object); break; } case ExpressionType.NewArray: { var s = e as NewArray; // Structs with non-trivial copy-ctor cannot be passed through '...' (uInitArray<T>) if (s.Initializers != null && IsNonTrivialStruct(s.ArrayType.ElementType)) { var v = new Variable(s.Source, null, Type.GetUniqueIdentifier("array"), s.ReturnType); e = new StoreLocal(s.Source, v, new NewArray(s.Source, s.ArrayType, new Constant(s.Source, Essentials.Int, s.Initializers.Length))); for (int i = 0; i < s.Initializers.Length; i++) { e = new SequenceOp(e, new StoreElement(s.Source, new LoadLocal(s.Source, v), new Constant(s.Source, Essentials.Int, i), s.Initializers[i])); } e = new SequenceOp(e, new LoadLocal(s.Source, v)); } break; } } }
public Statement CompileStatement(AstStatement e) { switch (e.StatementType) { default: if (e is AstExpression) { return(CompileExpression(e as AstExpression)); } break; case AstStatementType.VariableDeclaration: return(CompileVariableDeclaration(e as AstVariableDeclaration)); case AstStatementType.FixedArrayDeclaration: return(CompileFixedArrayDeclaration(e as AstFixedArrayDeclaration)); case AstStatementType.Scope: return(CompileScope(e as AstScope)); case AstStatementType.Draw: return(Compiler.BlockBuilder.CompileDraw(Function, VariableScopeStack, e as AstDraw)); case AstStatementType.DrawDispose: return(new DrawDispose(e.Source)); case AstStatementType.Break: return(new Break(e.Source)); case AstStatementType.Continue: return(new Continue(e.Source)); case AstStatementType.Unchecked: { CheckCastStack.Add(false); try { return(CompileStatement(((AstModifiedStatement)e).Statement)); } finally { CheckCastStack.RemoveLast(); } } case AstStatementType.IfElse: { var s = e as AstIfElse; if (s.Condition is AstDefined) { var def = s.Condition as AstDefined; return(Environment.Test(def.Source, def.Condition) ? s.OptionalIfBody != null ? CompileStatement(s.OptionalIfBody) : new NoOp(s.Source) : s.OptionalElseBody != null ? CompileStatement(s.OptionalElseBody) : new NoOp(s.Source)); } var r = new IfElse(s.Source, CompileCondition(s.Condition)); if (s.OptionalIfBody != null) { r.OptionalIfBody = CompileStatement(s.OptionalIfBody); } if (s.OptionalElseBody != null) { r.OptionalElseBody = CompileStatement(s.OptionalElseBody); } return(r); } case AstStatementType.ExternScope: { var s = (AstExternScope)e; return(new ExternScope(s.Source, Compiler.CompileAttributes(Namescope, s.Attributes), s.Body.String, ExtensionTransform.CreateObject(s.Source, Function, TypeBuilder.Parameterize(Function.DeclaringType)), s.OptionalArguments != null ? CompileArgumentList(s.OptionalArguments) : ExtensionTransform.CreateArgumentList(s.Source, Function), GetUsings(s.Source))); } case AstStatementType.While: { var s = e as AstLoop; var r = new While(s.Source, false, CompileCondition(s.Condition)); var vscope = new VariableScope(); VariableScopeStack.Add(vscope); if (s.OptionalBody != null) { r.OptionalBody = CompileStatement(s.OptionalBody); } if (s.OptionalBody == null || (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) || !(s.OptionalBody is AstScope)))) { VariableScopeStack.Remove(vscope); CurrentVariableScope.Scopes.Add(vscope); } return(r); } case AstStatementType.DoWhile: { var s = e as AstLoop; var r = new While(s.Source, true, CompileCondition(s.Condition)); var vscope = new VariableScope(); VariableScopeStack.Add(vscope); if (s.OptionalBody != null) { r.OptionalBody = CompileStatement(s.OptionalBody); } if (s.OptionalBody == null || (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) || !(s.OptionalBody is AstScope)))) { VariableScopeStack.Remove(vscope); CurrentVariableScope.Scopes.Add(vscope); } return(r); } case AstStatementType.For: { var s = e as AstFor; var r = new For(s.Source); var vscope = new VariableScope(); VariableScopeStack.Add(vscope); if (s.OptionalInitializer != null) { r.OptionalInitializer = CompileStatement(s.OptionalInitializer); } if (s.OptionalCondition != null) { r.OptionalCondition = CompileCondition(s.OptionalCondition); } if (s.OptionalBody != null) { r.OptionalBody = CompileStatement(s.OptionalBody); } if (s.OptionalIncrement != null) { r.OptionalIncrement = CompileExpression(s.OptionalIncrement); } if (s.OptionalBody == null || (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) || !(s.OptionalBody is AstScope)))) { VariableScopeStack.Remove(vscope); CurrentVariableScope.Scopes.Add(vscope); } return(r); } case AstStatementType.Foreach: { var s = e as AstForeach; var scope = new Scope(s.Source); var collection = CompileExpression(s.Collection); Statement result; var vscope = new VariableScope(); VariableScopeStack.Add(vscope); VerifyVariableName(s.ElementName.Source, s.ElementName.Symbol); if (collection.ReturnType.IsArray || collection.ReturnType == Essentials.String) { var loop = new For(s.Source) { OptionalBody = scope }; var collectionVar = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("array"), collection.ReturnType); if (collection is LoadLocal) { collectionVar = (collection as LoadLocal).Variable; } else { vscope.Variables.Add(collectionVar.Name, collectionVar); } var indexInitializer = new Constant(s.Collection.Source, Essentials.Int, 0); var lengthInitializer = CompileImplicitCast(s.Collection.Source, Essentials.Int, CompileExpression( new AstMember( new AstIdentifier(s.Collection.Source, collectionVar.Name), new AstIdentifier(s.Collection.Source, "Length")))); var indexVar = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("index"), Essentials.Int); var lengthVar = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("length"), Essentials.Int); if (collection is LoadLocal) { indexVar.OptionalValue = indexInitializer; lengthVar.OptionalValue = lengthInitializer; loop.OptionalInitializer = new VariableDeclaration(indexVar, lengthVar); } else { loop.OptionalInitializer = new SequenceOp( new StoreLocal(s.Collection.Source, collectionVar, collection), new StoreLocal(s.Collection.Source, indexVar, indexInitializer), new StoreLocal(s.Collection.Source, lengthVar, lengthInitializer)); } vscope.Variables.Add(indexVar.Name, indexVar); vscope.Variables.Add(lengthVar.Name, lengthVar); loop.OptionalCondition = CompileCondition( new AstBinary(AstBinaryType.LessThan, new AstIdentifier(s.Collection.Source, indexVar.Name), s.Collection.Source, new AstIdentifier(s.Collection.Source, lengthVar.Name))); loop.OptionalIncrement = new FixOp(s.Collection.Source, FixOpType.IncreaseBefore, new LoadLocal(s.Collection.Source, indexVar)); var elementType = s.ElementType.ExpressionType == AstExpressionType.Var ? collection.ReturnType.IsArray ? collection.ReturnType.ElementType : Essentials.Char : NameResolver.GetType(Namescope, s.ElementType); var elementVar = new Variable(s.ElementName.Source, Function, s.ElementName.Symbol, elementType, VariableType.Iterator, CompileImplicitCast(s.ElementName.Source, elementType, CompileExpression( new AstCall(AstCallType.LookUp, new AstIdentifier(s.ElementName.Source, collectionVar.Name), new AstIdentifier(s.ElementName.Source, indexVar.Name))))); scope.Statements.Add(new VariableDeclaration(elementVar)); vscope.Variables.Add(elementVar.Name, elementVar); result = loop; } else { // TODO: Verify that collection implements IEnumerable<T> var loop = new While(s.Source) { OptionalBody = scope }; var enumeratorInitializer = ILFactory.CallMethod(s.Collection.Source, collection.Address, "GetEnumerator"); var enumeratorVar = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("enum"), enumeratorInitializer.ReturnType, VariableType.Default, enumeratorInitializer); vscope.Variables.Add(enumeratorVar.Name, enumeratorVar); loop.Condition = CompileImplicitCast(s.Collection.Source, Essentials.Bool, ILFactory.CallMethod(s.Collection.Source, new LoadLocal(s.Collection.Source, enumeratorVar).Address, "MoveNext")); var elementInitializer = CompileExpression(new AstMember( new AstIdentifier(s.ElementName.Source, enumeratorVar.Name), new AstIdentifier(s.ElementName.Source, "Current"))); var elementType = s.ElementType.ExpressionType == AstExpressionType.Var ? elementInitializer.ReturnType : NameResolver.GetType(Namescope, s.ElementType); var elementVar = new Variable(s.Source, Function, s.ElementName.Symbol, elementType, VariableType.Iterator, CompileImplicitCast(s.ElementName.Source, elementType, elementInitializer)); var hasDispose = false; foreach (var m in enumeratorVar.ValueType.Methods) { if (m.Name == "Dispose" && m.Parameters.Length == 0) { hasDispose = true; break; } } // Optimization: avoid casting to IDisposable when Dispose() method is found var dispose = hasDispose ? ILFactory.CallMethod(s.Collection.Source, new LoadLocal(s.Collection.Source, enumeratorVar).Address, "Dispose") : ILFactory.CallMethod(s.Collection.Source, new CastOp(s.Collection.Source, Essentials.IDisposable, new LoadLocal(s.Collection.Source, enumeratorVar)).Address, "Dispose"); scope.Statements.Add(new VariableDeclaration(elementVar)); vscope.Variables.Add(elementVar.Name, elementVar); result = new Scope(s.Source, new VariableDeclaration(enumeratorVar), new TryCatchFinally(s.Source, new Scope(s.Source, loop), new Scope(s.Source, dispose))); } if (s.OptionalBody != null) { var body = CompileStatement(s.OptionalBody); if (body is Scope) { scope.Statements.AddRange((body as Scope).Statements); } else { scope.Statements.Add(body); } } if (s.OptionalBody == null || !s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) || !(s.OptionalBody is AstScope))) { VariableScopeStack.Remove(vscope); CurrentVariableScope.Scopes.Add(vscope); } return(result); } case AstStatementType.Return: return(new Return(e.Source)); case AstStatementType.ReturnValue: { var s = e as AstValueStatement; var returnValue = CompileExpression(s.Value); var returnType = Lambdas.Count == 0 ? Function.ReturnType : Lambdas.Peek().DelegateType.ReturnType; return(new Return(s.Source, CompileImplicitCast(s.Source, returnType, returnValue))); } case AstStatementType.TryCatchFinally: { var s = e as AstTryCatchFinally; var tryScope = CompileScope(s.TryScope); var catchBlocks = new List <CatchBlock>(); Scope finallyScope = null; foreach (var c in s.CatchBlocks) { var exceptionType = c.OptionalType != null? NameResolver.GetType(Namescope, c.OptionalType) : Essentials.Exception; var vscope = new VariableScope(); VariableScopeStack.Add(vscope); VerifyVariableName(c.Name.Source, c.Name.Symbol); var exceptionVar = new Variable(c.Name.Source, Function, c.Name.Symbol, exceptionType, VariableType.Exception); vscope.Variables.Add(exceptionVar.Name, exceptionVar); var catchBody = CompileScope(c.Body); if (c.Body == null || !c.Body.IsInvalid && c.Body.IsClosed) { VariableScopeStack.Remove(vscope); CurrentVariableScope.Scopes.Add(vscope); } catchBlocks.Add(new CatchBlock(c.Name.Source, exceptionVar, catchBody)); } if (s.OptionalFinallyScope != null) { finallyScope = CompileScope(s.OptionalFinallyScope); } return(new TryCatchFinally(s.Source, tryScope, finallyScope, catchBlocks.ToArray())); } case AstStatementType.Lock: { var s = e as AstLock; var scope = new Scope(s.Source); var tryScope = new Scope(s.Source); var finallyScope = new Scope(s.Source); var obj = CompileExpression(s.Object); switch (obj.ExpressionType) { case ExpressionType.LoadLocal: case ExpressionType.LoadArgument: case ExpressionType.LoadField: case ExpressionType.This: case ExpressionType.Base: if (!obj.ReturnType.IsReferenceType) { Log.Error(obj.Source, ErrorCode.E0000, "Only reference types can be used in 'lock'"); } break; default: Log.Error(obj.Source, ErrorCode.E0000, "Only variables can occur inside 'lock' initializer"); break; } if (s.OptionalBody != null) { tryScope.Statements.Add(CompileStatement(s.OptionalBody)); } scope.Statements.Add(ILFactory.CallMethod(obj.Source, Essentials.Monitor, "Enter", obj)); finallyScope.Statements.Add(ILFactory.CallMethod(obj.Source, Essentials.Monitor, "Exit", obj)); scope.Statements.Add(new TryCatchFinally(s.Source, tryScope, finallyScope)); return(scope); } case AstStatementType.Using: { var s = e as AstUsing; var scope = new Scope(s.Source); var objects = new List <Expression>(); var vscope = new VariableScope(); VariableScopeStack.Add(vscope); var init = CompileStatement(s.Initializer); for (int i = 0; i < 1; i++) { switch (init.StatementType) { case StatementType.VariableDeclaration: { scope.Statements.Add(init); for (var var = ((VariableDeclaration)init).Variable; var != null; var = var.Next) { objects.Add(new LoadLocal(var.Source, var)); } continue; } case StatementType.Expression: { if (AddObjects(objects, (Expression)init)) { continue; } break; } } // TODO: Actually some expressions are valid as well in C#. Read spec and implement later Log.Error(init.Source, ErrorCode.E0000, "Only variable declarations, fields and/or local variables can occur inside 'using' initializer"); } var tryScope = new Scope(s.Source); var finallyScope = new Scope(s.Source); if (s.OptionalBody != null) { tryScope.Statements.Add(CompileStatement(s.OptionalBody)); } foreach (var dispose in Enumerable.Reverse(objects)) { var idisposable = CompileImplicitCast(dispose.Source, Essentials.IDisposable, dispose); finallyScope.Statements.Add(ILFactory.CallMethod(dispose.Source, idisposable, "Dispose")); } scope.Statements.Add(new TryCatchFinally(s.Source, tryScope, finallyScope)); if (s.OptionalBody == null || (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) || !(s.OptionalBody is AstScope)))) { VariableScopeStack.Remove(vscope); CurrentVariableScope.Scopes.Add(vscope); } return(scope); } case AstStatementType.ThrowValue: { var s = e as AstValueStatement; return(new Throw(s.Source, CompileExpression(s.Value))); } case AstStatementType.Throw: { for (int i = VariableScopeStack.Count - 1; i >= 0; i--) { foreach (var v in VariableScopeStack[i].Variables.Values) { if (v.IsException) { return(new Throw(e.Source, new LoadLocal(e.Source, v), true)); } } } return(Error(e.Source, ErrorCode.E0000, "Cannot rethrow outside of catch block")); } case AstStatementType.Switch: { var s = e as AstSwitch; var c = CompileExpression(s.Condition); if (!c.ReturnType.IsIntegralType) { c = TryCompileImplicitCast(s.Source, Essentials.Int, c) ?? Error(s.Condition.Source, ErrorCode.E3415, "A switch expression must be of enum or integral type"); } var cases = new List <SwitchCase>(); foreach (var a in s.Cases) { var handler = CompileScope(a.Scope); var values = new List <Constant>(); var includesDefault = false; foreach (var v in a.Values) { if (v == null) { includesDefault = true; continue; } var sym = CompileImplicitCast(v.Source, c.ReturnType, CompileExpression(v)); var constSym = Compiler.ConstantFolder.TryMakeConstant(sym); if (constSym != null) { values.Add(constSym); } else if (sym.IsInvalid) { values.Add(new Constant(sym.Source, DataType.Invalid, -1)); } else { Log.Error(v.Source, ErrorCode.E3410, "Case-expression must be constant"); } } cases.Add(new SwitchCase(values.ToArray(), includesDefault, handler)); } return(new Switch(s.Source, c, cases.ToArray())); } case AstStatementType.Assert: { if (!Environment.Debug) { return(new NoOp(e.Source, "Stripped assert")); } var s = e as AstValueStatement; var value = CompileExpression(s.Value); var args = new List <Expression> { value, new Constant(s.Source, Essentials.String, value.ToString()), new Constant(s.Source, Essentials.String, s.Source.File.ToString().Replace('\\', '/')), new Constant(s.Source, Essentials.Int, s.Source.Line), }; var locals = new List <StoreLocal>(); switch (value.ExpressionType) { case ExpressionType.CallUnOp: { var o = value as CallUnOp; args.Add(CreateAssertIndirection(ref o.Operand, locals, Namescope)); break; } case ExpressionType.CallBinOp: { var o = value as CallBinOp; args.Add(CreateAssertIndirection(ref o.Left, locals, Namescope)); args.Add(CreateAssertIndirection(ref o.Right, locals, Namescope)); break; } case ExpressionType.BranchOp: { var o = value as BranchOp; args.Add(CreateAssertIndirection(ref o.Left, locals, Namescope)); args.Add(CreateAssertIndirection(ref o.Right, locals, Namescope)); break; } case ExpressionType.CallMethod: { var o = value as CallMethod; for (int i = 0; i < o.Arguments.Length; i++) { args.Add(CreateAssertIndirection(ref o.Arguments[i], locals, Namescope)); } break; } } var result = ILFactory.CallMethod(s.Source, "Uno.Diagnostics.Debug", "Assert", args.ToArray()); while (locals.Count > 0) { result = new SequenceOp(locals.RemoveLast(), result); } return(result); } case AstStatementType.DebugLog: { if (!Environment.Debug) { return(new NoOp(e.Source, "Stripped debug_log")); } var s = (AstValueStatement)e; var message = CompileExpression(s.Value); return(ILFactory.CallMethod(s.Source, "Uno.Diagnostics.Log", "Debug", message)); } case AstStatementType.BuildError: return(CreateBuildError(e.Source, true)); case AstStatementType.BuildWarning: return(CreateBuildError(e.Source, false)); case AstStatementType.BuildErrorMessage: { var s = (AstValueStatement)e; return(CreateBuildError(e.Source, true, s.Value)); } case AstStatementType.BuildWarningMessage: { var s = (AstValueStatement)e; return(CreateBuildError(e.Source, false, s.Value)); } } Log.Error(e.Source, ErrorCode.I3411, "Unknown statement type <" + e.StatementType + ">"); return(Expression.Invalid); }
public virtual void WriteSequenceOp(SequenceOp s, ExpressionUsage u) { WriteSequenceOp(s, u, u < ExpressionUsage.Argument); }