Пример #1
0
        private void MapProperty(PropertyInfo property, object astNode, ICstNode newCstNode)
        {
            /*
             *                      else if (consumeAttribute.Converter != null)
             *                      {
             *                          CoalesceAndConvert(astNode, property, newCstNode, consumeAttribute.Converter, consumeAttribute.ConverterArgs);
             *                      }
             */
            // If the property type is simple, we will just convert the text of the CST node into that type.
            if (IsSimpleType(property.PropertyType))
            {
                Coalesce(astNode, property, newCstNode, property.PropertyType);
            }
            // Lists are a special case to help unravel recursion.
            else if (property.PropertyType.IsGenericList())
            {
                BuildList(property, astNode, (CstNonterminalNode)newCstNode);
            }
            // Each enum value may contain a ConsumeAttribute indicating how to map it. Otherwise we do
            // a simple parse.
            else if (property.PropertyType.IsEnum)
            {
                var    enums        = property.PropertyType.GetEnums();
                string expectedName = newCstNode.Coalesce();
                foreach (var @enum in enums)
                {
                    string             name = @enum.Name;
                    ConsumeAttribute[] enumConsumeAttributes = @enum.Field.GetAttributes <ConsumeAttribute>();
                    if (enumConsumeAttributes.Length > 0)
                    {
                        foreach (ConsumeAttribute enumConsume in enumConsumeAttributes)
                        {
                            if (enumConsume.Expression == expectedName)
                            {
                                name = enumConsume.Expression;
                                break;
                            }
                        }
                    }
                    if (name == expectedName)
                    {
                        property.SetValue(astNode, @enum.Value, null);
                        goto foundEnum;
                    }
                }
                throw new InvalidOperationException("No enum found for " + expectedName + " in " + property.PropertyType);
foundEnum:
                ;
            }
            // Otherwise we create a new AST node and recurse into this method.
            else //if (nonterminalTypes.Values.Contains(property.PropertyType))
            {
                object newAstNode = Build(property.PropertyType, newCstNode);

                // Set the property to the new AST node
                property.SetValue(astNode, newAstNode, null);
            }
        }
Пример #2
0
        private void Coalesce(object astNode, PropertyInfo property, ICstNode cstNode, Type targetType)
        {
            string value = cstNode.Coalesce();
            object o;

            try
            {
                o = Convert.ChangeType(value, targetType);
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Error converting '" + value + "' to a " + targetType.FullName + " for property " + property.GetPath(), e);
            }
            property.SetValue(astNode, o, null);
        }
Пример #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="astNodeType">The type of node we are creating.  A subclass might possibly be selected.</param>
        /// <param name="cstNode">The CST node that represents the structured input for the specified AST node</param>
        /// <returns>The new astNode of the specified astNodeType that consumes the cstNode</returns>
        private object Build(Type astNodeType, ICstNode cstNode)
        {
            int consumeIndex = 0;

            if (astNodeType.IsAbstract || astNodeType.IsInterface)
            {
                string             ruleName           = ((CstNonterminalNode)cstNode).Nonterminal.Name;
                CstNonterminalNode cstNonterminalNode = (CstNonterminalNode)cstNode;
                astNodeType = GetSubclass(ref cstNonterminalNode, ruleName);
                cstNode     = cstNonterminalNode;
            }
            object astNode;

            try
            {
                if (astNodeType == typeof(string))
                {
                    return(cstNode.Coalesce());
                }
                else if (astNodeType == typeof(int))
                {
                    return(int.Parse(cstNode.Coalesce()));
                }
                else if (astNodeType == typeof(byte))
                {
                    return(byte.Parse(cstNode.Coalesce()));
                }
                else if (astNodeType == typeof(short))
                {
                    return(short.Parse(cstNode.Coalesce()));
                }
                else if (astNodeType == typeof(long))
                {
                    return(long.Parse(cstNode.Coalesce()));
                }
                else if (astNodeType == typeof(float))
                {
                    return(float.Parse(cstNode.Coalesce()));
                }
                else if (astNodeType == typeof(double))
                {
                    return(double.Parse(cstNode.Coalesce()));
                }
                else if (astNodeType == typeof(decimal))
                {
                    return(decimal.Parse(cstNode.Coalesce()));
                }
                else if (astNodeType == typeof(bool))
                {
                    return(bool.Parse(cstNode.Coalesce()));
                }
                else
                {
                    astNode = CreateAstNode(astNodeType);
                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Error instantiating " + astNodeType.FullName, e);
            }
            foreach (PropertyInfo property in astNode.GetType().GetAllPropertiesInAncestry())
            {
                ConsumeAttribute[] consumeAttributes = property.GetAttributes <ConsumeAttribute>();
                foreach (ConsumeAttribute consumeAttribute in consumeAttributes)
                {
                    if (consumeIndex > 0 && consumeIndex != consumeAttribute.Production)
                    {
                        continue;
                    }

                    CstNonterminalNode productionNode = cstNode as CstNonterminalNode;

                    // 1) Handle the simple case where the NonTerminal exactly matches the NonTerminal property of our consume attribute
                    // 2) Handle the empty [Consume] case, which means it goes into this block no matter what.
                    // Get the expression (parsed from the NonTerminal property)
                    ConsumeExpression expression = consumeAttribute.GetExpression();

                    // The goal of the expression is to bring us to a new CST node (a descendent of the current one)
                    ICstNode newCstNode;
                    try
                    {
                        newCstNode = expression != null?expression.Resolve(productionNode).FirstOrDefault() : productionNode;
                    }
                    catch (Exception e)
                    {
                        throw new InvalidOperationException("Error resolving expression '" + consumeAttribute.Expression + "' for " + property.GetPath(), e);
                    }

                    // There are a number of reasons why the new cst node might be null.  It is perfectly
                    // legal to specify nonterminal expressions that only resolve under certain productions.
                    // In other scenarios, it will remain null.
                    if (newCstNode != null)
                    {
                        // If the Value property is set, then we simply assign the property to that value (since newCstNode is not null)
                        if (consumeAttribute.Value != null)
                        {
                            property.SetValue(astNode, consumeAttribute.Value, null);
                        }
                        else if (consumeAttribute.Type != null)
                        {
                            Coalesce(astNode, property, newCstNode, consumeAttribute.Type);
                        }
                        else
                        {
                            MapProperty(property, astNode, newCstNode);
                        }
                        goto nextProperty;
                    }
                }

                var impliedCstNode = ((CstNonterminalNode)cstNode).Children.OfType <ICstNonterminalNode>().SingleOrDefault(o => o.Nonterminal.Name == property.Name);
                if (impliedCstNode != null)
                {
                    MapProperty(property, astNode, impliedCstNode);
                }

                nextProperty :;
            }
            return(astNode);
        }