NewObjectNode TransformExpression(Expression e, Property contextProp, FileSourceInfo src, Node owner, Reflection.IdentifierScope identifierScope, bool rootLevel = false) { if (e is Binding) { var binding = e as Binding; return(TransformExpression(binding.Key, contextProp, src, owner, Reflection.IdentifierScope.Data, rootLevel)); } if (e is ModeExpression) { var mod = (ModeExpression)e; if (!rootLevel) { if (mod.Mode.HasFlag(Modifier.Write)) { ReportError(owner.Source, "Write-modifiers only allowed on root-level expressions"); } if (mod.Mode.HasFlag(Modifier.Clear)) { ReportError(owner.Source, "Clear-modifiers only allowed on root-level expressions"); } } return(TransformExpression(mod.Expression, contextProp, src, owner, Reflection.IdentifierScope.Data)); } if (e is RawExpression) { var re = e as RawExpression; return(TransformExpression(re.Expression, contextProp, src, owner, Reflection.IdentifierScope.Globals)); } if (e is ThisExpression) { e = new Identifier("this"); identifierScope = Reflection.IdentifierScope.Globals; } if (e is Identifier) { var id = e as Identifier; if (identifierScope == Reflection.IdentifierScope.Data || identifierScope == Reflection.IdentifierScope.Names) { var idd = new NewObjectNode(src, null, FindType("Fuse.Reactive.Data"), InstanceType.Local); idd.CreateMembers(); owner.AddChild(idd); _nodes.Add(new object(), idd); idd.AtomicProperties.First(x => x.Facet.Name == "Key").Value = new String(id.Name, owner.Source); return(idd); } if (identifierScope == Reflection.IdentifierScope.Globals) { var literal = new NewObjectNode(src, null, FindType("Fuse.Reactive.Constant"), InstanceType.Local); owner.AddChild(literal); literal.CreateMembers(); _nodes.Add(new object(), literal); var valueProp = literal.BindableProperties.OfType <ReferenceProperty>().First(x => x.Facet.Name == "Value"); ParseTrivialExpression(id.Name, literal, valueProp, contextProp, owner.Source); return(literal); } } if (e is Literal) { var li = e as Literal; var literal = new NewObjectNode(src, null, FindType("Fuse.Reactive.Constant"), InstanceType.Local); literal.CreateMembers(); _nodes.Add(new object(), literal); var v = li is StringLiteral ? new String(li.Value, owner.Source) : ParseArbitraryValue(li.Value, contextProp.Facet.DataType, owner.Source); var bv = new BoxedValueNode(src, null, FindType("object"), v, InstanceType.Local); bv.CreateMembers(); owner.AddChild(bv); literal.BindableProperties.First(x => x.Facet.Name == "Value").Bind(bv); owner.AddChild(literal); return(literal); } if (e is MemberExpression) { var me = e as MemberExpression; var obj = TransformExpression(me.Object, contextProp, src, owner, identifierScope); var op = new NewObjectNode(src, null, FindType("Fuse.Reactive.Member"), InstanceType.Local); op.CreateMembers(); owner.AddChild(op); _nodes.Add(new object(), op); op.BindableProperties.First(x => x.Facet.Name == "Object").Bind(obj); op.AtomicProperties.First(x => x.Facet.Name == "Name").Value = new String(me.Member, owner.Source); return(op); } if (e is NameValuePairExpression) { var me = e as NameValuePairExpression; var nameExp = me.Name; if (nameExp is Expressions.Identifier) { nameExp = new Expressions.StringLiteral(((Expressions.Identifier)nameExp).Name); // Interpret {foo: bar} as {'foo':bar} } var name = TransformExpression(nameExp, contextProp, src, owner, Reflection.IdentifierScope.Globals); // Left hand of : is in global context, to allow {foo: bar} var obj = TransformExpression(me.Value, contextProp, src, owner, identifierScope); var op = new NewObjectNode(src, null, FindType("Fuse.Reactive.NameValuePair"), InstanceType.Local); op.CreateMembers(); owner.AddChild(op); _nodes.Add(new object(), op); op.BindableProperties.First(x => x.Facet.Name == "Value").Bind(obj); op.BindableProperties.First(x => x.Facet.Name == "Name").Bind(name); return(op); } if (e is LookUpExpression) { var me = e as LookUpExpression; var collection = TransformExpression(me.Collection, contextProp, src, owner, identifierScope); var index = TransformExpression(me.Index, contextProp, src, owner, identifierScope); var op = new NewObjectNode(src, null, FindType("Fuse.Reactive.LookUp"), InstanceType.Local); op.CreateMembers(); owner.AddChild(op); _nodes.Add(new object(), op); op.BindableProperties.First(x => x.Facet.Name == "Collection").Bind(collection); op.BindableProperties.First(x => x.Facet.Name == "Index").Bind(index); return(op); } if (e is BinaryExpression) { var be = e as BinaryExpression; var op = new NewObjectNode(src, null, FindType("Fuse.Reactive." + be.Name), InstanceType.Local); op.CreateMembers(); owner.AddChild(op); _nodes.Add(new object(), op); ParseAttribute(op, op.BindableProperties.First(x => x.Facet.Name == "Left"), contextProp, be.Left, src, identifierScope); ParseAttribute(op, op.BindableProperties.First(x => x.Facet.Name == "Right"), contextProp, be.Right, src, identifierScope); return(op); } if (e is ConditionalExpression) { var be = e as ConditionalExpression; var op = new NewObjectNode(src, null, FindType("Fuse.Reactive.Conditional"), InstanceType.Local); op.CreateMembers(); owner.AddChild(op); _nodes.Add(new object(), op); ParseAttribute(op, op.BindableProperties.First(x => x.Facet.Name == "Condition"), contextProp, be.Condition, src, identifierScope); ParseAttribute(op, op.BindableProperties.First(x => x.Facet.Name == "TrueValue"), contextProp, be.TrueCase, src, identifierScope); ParseAttribute(op, op.BindableProperties.First(x => x.Facet.Name == "FalseValue"), contextProp, be.FalseCase, src, identifierScope); return(op); } if (e is UnaryExpression) { var ue = e as UnaryExpression; var op = new NewObjectNode(src, null, FindType("Fuse.Reactive." + ue.Name), InstanceType.Local); op.CreateMembers(); owner.AddChild(op); _nodes.Add(new object(), op); ParseAttribute(op, op.BindableProperties.First(x => x.Facet.Name == "Operand"), contextProp, ue.Operand, src, identifierScope); return(op); } if (e is UserDefinedUnaryOperator) { var ud = e as UserDefinedUnaryOperator; var operatorType = Types.FirstOrDefault(x => x.UXUnaryOperatorName == ud.UxUnaryOperatorName); if (operatorType == null) { ReportError(owner.Source, "Could not resolve UX unary operator type: " + ud.UxUnaryOperatorName); return(null); } var op = new NewObjectNode(src, null, operatorType, InstanceType.Local); op.CreateMembers(); owner.AddChild(op); _nodes.Add(new object(), op); // TODO: Remove fuselibs-specific type reference https://github.com/fusetools/uno/issues/1424 if (operatorType.FullName == "Fuse.Reactive.Property") { var objProp = op.BindableProperties.First(x => x.Facet.Name == "Object"); var accessorProp = op.BindableProperties.First(x => x.Facet.Name == "Accessor"); var mem = ud.Argument as MemberExpression; if (mem != null) { ParsePropertyAccessor(owner, op, objProp, accessorProp, mem.Object, mem.Member); } else { var id = ud.Argument as Identifier; if (id != null) { ParsePropertyAccessor(owner, op, objProp, accessorProp, new ThisExpression(), id.Name); } else { ReportError(owner.Source, "Argument to property-binding must be on the form 'named_object.Property' or 'Property' (to refer to properties on 'this' implicitly)"); return(null); } } } else { ParseAttribute(op, op.Properties.First(x => x.Facet.IsConstructorArgument), contextProp, ud.Argument, src, identifierScope); } return(op); } if (e is FunctionCallExpression) { var fce = (FunctionCallExpression)e; Reflection.IDataType func; if (identifierScope == Reflection.IdentifierScope.Names) { func = FindType("Fuse.Reactive.NamedFunctionCall"); } else { if (!_uxFunctions.TryGetValue(fce.FuncName, out func)) { ReportError(owner.Source, "UX function not found: '" + fce.FuncName + "'"); } } var fo = new NewObjectNode(src, null, func, InstanceType.Local); fo.CreateMembers(); owner.AddChild(fo); _nodes.Add(new object(), fo); if (identifierScope == Reflection.IdentifierScope.Names) { fo.AtomicProperties.First(x => x.Facet.Name == "Name").Value = new String(fce.FuncName, fo.Source); identifierScope = Reflection.IdentifierScope.Globals; } if (func.Implements(VarArgFunction)) { var args = fo.BindableProperties.First(x => x.Facet.Name == "Arguments"); for (int i = 0; i < fce.Args.Length; i++) { var arg = TransformExpression(fce.Args[i], contextProp, src, owner, identifierScope); args.Bind(arg); } } else { var index = 0; foreach (var dep in fo.Properties.Where(x => x.Facet.IsConstructorArgument)) { ParseAttribute(fo, dep, contextProp, fce.Args[index++], src, identifierScope); } } return(fo); } if (e is VectorExpression) { var ve = (VectorExpression)e; var vectorFunc = FindType("Fuse.Reactive.Vector"); if (ve.Comps.All(x => x is Expressions.NameValuePairExpression)) { vectorFunc = FindType("Fuse.Reactive.Object"); } var vo = new NewObjectNode(src, null, vectorFunc, InstanceType.Local); vo.CreateMembers(); owner.AddChild(vo); _nodes.Add(new object(), vo); var args = vo.BindableProperties.First(x => x.Facet.Name == "Arguments"); for (int i = 0; i < ve.Comps.Length; i++) { var arg = TransformExpression(ve.Comps[i], contextProp, src, owner, identifierScope); args.Bind(arg); } return(vo); } throw new Exception("Unsupported expression type: " + e.GetType()); }
void ParseAttribute(Node owner, Property targetProp, Property contextProp, Expression e, FileSourceInfo src, Reflection.IdentifierScope identifierScope) { if (ExpressionType != null && targetProp.Facet.DataType.Implements(ExpressionType)) { // This supports e.g. <DataBinding Target="foo.Prop" Key="foo" /> ((BindableProperty)targetProp).Bind(TransformExpression(e, contextProp, src, owner, identifierScope, true)); } else if (e.IsTrivial && !(targetProp is ReferenceProperty && (e is StringLiteral) && !(targetProp.Facet.DataType.Implements(FileSourceType)))) { ParseTrivialExpression(e.ToString().Trim('\"'), owner, targetProp, contextProp, src); } else { var binding = new NewObjectNode(owner.Source, null, DataBindingType, InstanceType.Local); _nodes.Add(e, binding); binding.BindableProperties.First(x => x.Facet.Name == "Target").Bind(owner, targetProp); _uxProperties.Add(new UXPropertyClass(targetProp, owner)); var argumentProp = binding.BindableProperties.First(x => x.Facet.Name == "Key"); var mode = "Default"; if (e is Binding) { var b = (Binding)e; if (b.Key is ModeExpression) { var mod = b.Key as ModeExpression; e = new Binding(mod.Expression); mode = mod.Mode.ToString(); } } binding.AtomicProperties.First(x => x.Facet.Name == "Mode") .Value = new EnumValue((Reflection.IEnum)FindType("Fuse.Reactive.BindingMode"), mode, owner.Source); var exp = TransformExpression(e, contextProp, src, owner, identifierScope, true); argumentProp.Bind(exp); TryFindSuitableParent(owner, binding); } }