Example #1
0
        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());
        }
Example #2
0
        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);
            }
        }