protected IEnumerable <TElementStaticType> GetFlattenedElements <TElementStaticType>(ParseTreeNode parseTreeNode, AstContext context) { foreach (var parseTreeChild in parseTreeNode.ChildNodes) { /* * The type of childValue is 'object' because childValue can be other than an element, which causes error, * but we want to give a proper error message (see below) instead of throwing a simple cast exception * */ object childValue = GrammarHelper.AstNodeToValue(parseTreeChild.AstNode); if (domainElementType.IsInstanceOfType(childValue)) { yield return((TElementStaticType)childValue); } else if (parseTreeChild.Term.Flags.IsSet(TermFlags.IsList)) { foreach (var descendantElement in GetFlattenedElements <TElementStaticType>(parseTreeChild, context)) { yield return(descendantElement); } } else if (parseTreeChild.Term.Flags.IsSet(TermFlags.NoAstNode)) { // simply omit children with no ast (they are probably delimiters) } else { // throw exception only if this situation cannot be the consequence of another ast error if (!GrammarHelper.HasError(context)) { string errorMessage = string.Format("Term '{0}' should be type of '{1}' but found '{2}' instead", parseTreeChild.Term, domainElementType.FullName, childValue != null ? childValue.GetType().FullName : "<<NULL>>"); throw new InvalidOperationException(errorMessage); } } } }
private static ValueIntroducer <TDOut> ConvertValueConverterToValueIntroducer <TDIn, TDOut>(ValueConverter <TDIn, TDOut> valueConverter, bool isOptionalValue, TDOut defaultValue) { return((context, parseTreeNode) => { Func <IEnumerable <ParseTreeNode>, Func <ParseTreeNode, bool>, ParseTreeNode> chooser; if (isOptionalValue) { chooser = Enumerable.SingleOrDefault <ParseTreeNode>; } else { chooser = Enumerable.Single <ParseTreeNode>; } ParseTreeNode parseTreeChild; try { parseTreeChild = chooser(parseTreeNode.ChildNodes, childNode => childNode.AstNode != null); } catch (InvalidOperationException) { if (isOptionalValue) { throw new ArgumentException("Only zero or one child with ast node is allowed for an optional BnfiTermConversion term: {0}", parseTreeNode.Term.Name); } else { throw new ArgumentException("Exactly one child with ast node is allowed for a non-optional BnfiTermConversion term: {0}", parseTreeNode.Term.Name); } } return parseTreeChild != null ? valueConverter(GrammarHelper.AstNodeToValue <TDIn>(parseTreeChild.AstNode)) : defaultValue; }); }
public static BnfiTermConversion <TDOut> Cast <TDOut>(Terminal terminal) { return(Intro <TDOut>(terminal, (context, parseNode) => GrammarHelper.AstNodeToValue <TDOut>(parseNode.Token.Value), IdentityFunctionForceCast <TDOut, object>)); }
protected BnfiTermRecord(Type domainType, string name) : base(domainType, name) { #if !WINDOWS_STORE #if PCL if (domainType.GetConstructor(new Type[0]) == null) #else if (domainType.GetConstructor(bindingAttrInstanceAll, binder: null, types: Type.EmptyTypes, modifiers: null) == null) #endif { throw new ArgumentException("Type has no default constructor (neither public nor nonpublic)", "type"); } #endif this.AstConfig.NodeCreator = (context, parseTreeNode) => { try { object astValue; try { #if PCL astValue = ActivatorEx.CreateInstance(domainType, nonPublic: true); #else astValue = Activator.CreateInstance(domainType, nonPublic: true); #endif } catch (MissingMemberException) { throw new AstException(string.Format("Type '{0}' does not have a parameterless public or internal constructor", domainType.FullName)); } var parseChildBnfTerms = parseTreeNode.ChildNodes.Select(childParseTreeNode => childParseTreeNode.Term).ToList(); var parseChildValues = parseTreeNode.ChildNodes .Select( (parseChildNode, parseChildNodeIndex) => new { ReferredBnfTerm = new ReferredBnfTermEL(parseChildBnfTerms, parseChildNode.Term, parseChildNodeIndex), Value = GrammarHelper.AstNodeToValue(parseChildNode.AstNode) } ) .Where(parseChildValue => parseChildValue.Value != null) .ToList(); // 1. memberwise copy for BnfiTermCopy items foreach (var parseChildValue in parseChildValues) { if (!IsMemberAtParse(parseChildValue.ReferredBnfTerm) && IsMemberwiseCopyable(astValue, parseChildValue.Value)) { MemberwiseCopyExceptNullAndEmptyCollectionValues(astValue, parseChildValue.Value); } } // 2. set member values for member items (it's the second step, so that we can overwrite the copied members if we want) foreach (var parseChildValue in parseChildValues) { if (IsMemberAtParse(parseChildValue.ReferredBnfTerm)) { SetValue(GetMemberAtParse(parseChildValue.ReferredBnfTerm).MemberInfo, astValue, parseChildValue.Value); } } parseTreeNode.AstNode = GrammarHelper.ValueToAstNode(astValue, context, parseTreeNode); } catch (AstException e) { context.AddMessage(AstException.ErrorLevel, parseTreeNode.Span.Location, e.Message); } catch (FatalAstException e) { context.AddMessage(FatalAstException.ErrorLevel, parseTreeNode.Span.Location, e.Message); // although it will be abandoned anyway e.Location = parseTreeNode.Span.Location; throw; } }; }