public PatternBufferSchema Parse(string source) { NonterminalToken token = parser.Parse(source); PatternBufferSchema schema = null; if (this.error == null && token != null) { schema = (PatternBufferSchema)CreateObject(token); } if (this.error != null) { throw new PatternBufferSchemaException(this.error); } return(schema); }
public Object CreateObjectFromNonterminal(NonterminalToken token) { // Delve the tree foreach (Token t in token.Tokens) { t.UserObject = CreateObject(t); } switch (token.Rule.Id) { case (int)RuleConstants.RULE_SCHEMA: //<Schema> ::= <SchemaNameElement> <SchemaElements> // This is actually the home stretch, even though it comes first. // It pulls together everything gathered thus far and creates the actual schema object // we want in the end. //DumpTree(token); // Schema name string schemaName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_SCHEMANAMEELEMENT); // Schema hints Dictionary <string, string> hints = token.GetUserObjectForSubToken <Dictionary <string, string> >((int)SymbolConstants.SYMBOL_HINT); // Schema elements List <PatternBufferType> types = new List <PatternBufferType>(); Dictionary <string, PatternBufferType> nameTypeMap = new Dictionary <string, PatternBufferType>(); List <PatternBufferEnum> enums = new List <PatternBufferEnum>(); Dictionary <string, PatternBufferEnum> nameEnumMap = new Dictionary <string, PatternBufferEnum>(); List <IPatternBufferReferrable> schemaElements = token.GetUserObjectForSubToken <List <IPatternBufferReferrable> >((int)SymbolConstants.SYMBOL_SCHEMAELEMENT); List <string> names = new List <string>(); List <ushort> typeIds = new List <ushort>(); List <PatternBufferField> referenceFields = new List <PatternBufferField>(); // Index all the schema elements foreach (IPatternBufferReferrable schemaElement in schemaElements) { if (names.Contains(schemaElement.Name)) { throw new PatternBufferSchemaException("The name \"" + schemaElement.Name + "\" is duplicated. Type and enum names must be unique."); } names.Add(schemaElement.Name); if (schemaElement is PatternBufferEnum) { PatternBufferEnum e = (PatternBufferEnum)schemaElement; enums.Add(e); nameEnumMap[e.Name] = e; } else if (schemaElement is PatternBufferType) { PatternBufferType type = (PatternBufferType)schemaElement; if (type.TypeId > 0) { if (typeIds.Contains(type.TypeId)) { throw new PatternBufferSchemaException("Multiple types map to type ID " + type.TypeId + ". Type IDs must be unique."); } typeIds.Add(type.TypeId); } types.Add(type); nameTypeMap[type.Name] = type; foreach (PatternBufferField f in type.Fields) { if (f.FieldType is ReferenceFieldType) { referenceFields.Add((PatternBufferField)f); } } } } // Autonumber types, if necessary if (this.autonumberedTypes.Count > 0) { ushort autonumberedTypeId = 1; foreach (PatternBufferType autonumberedType in this.autonumberedTypes) { while (typeIds.Contains(autonumberedTypeId)) { autonumberedTypeId++; } autonumberedType.TypeId = autonumberedTypeId; typeIds.Add(autonumberedTypeId); Console.WriteLine("Autonumbering type \"" + autonumberedType.Name + "\" as type ID " + autonumberedType.TypeId + "."); } } // Bundle up all referrables Dictionary <string, IPatternBufferReferrable> nameReferrableMap = new Dictionary <string, IPatternBufferReferrable>(); foreach (PatternBufferEnum allEnum in enums) { nameReferrableMap[allEnum.name] = allEnum; } foreach (PatternBufferType allType in types) { nameReferrableMap[allType.name] = allType; } // Validate name if (schemaName == null) { throw new PatternBufferSchemaException("No schema name is specified. A schema name is required."); } // Validate type hierarchy (no circuits, classes exist) Dictionary <string, List <string> > typeNameFieldNamesMap = new Dictionary <string, List <string> >(); foreach (PatternBufferType type in types) { // Validate the type this.ValidateType(type, nameReferrableMap, nameTypeMap, nameEnumMap); // Set the base type if (type.baseTypeName != null) { type.baseType = nameTypeMap[type.baseTypeName]; } } // Set final attribute on all types with no derivatives. foreach (PatternBufferType type in types) { type.isFinal = true; foreach (PatternBufferType otherType in types) { // If any type claims the current type as a base type, it's not final. // This will inform our list/set/map serialization code to minimize type ID duplication. if (type != otherType && otherType.baseType == type) { type.isFinal = false; break; } } } // Create and return PatternBufferSchema schema = new PatternBufferSchema( schemaName, types, enums, hints ); return(schema); case (int)RuleConstants.RULE_SCHEMANAMEELEMENT_NAME_SEMI: //<SchemaNameElement> ::= Name <SchemaName> ';' return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_SCHEMANAME)); case (int)RuleConstants.RULE_SCHEMANAME_NAME: //<SchemaName> ::= Name return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME)); case (int)RuleConstants.RULE_SCHEMAELEMENT: //<SchemaElement> ::= <Type> <SchemaElement> List <IPatternBufferReferrable> schemaElements2 = token.GetUserObjectForSubToken <List <IPatternBufferReferrable> >((int)SymbolConstants.SYMBOL_SCHEMAELEMENT); PatternBufferType t = token.GetUserObjectForSubToken <PatternBufferType>((int)SymbolConstants.SYMBOL_TYPE2); schemaElements2.Insert(0, t); return(schemaElements2); case (int)RuleConstants.RULE_SCHEMAELEMENT2: //<SchemaElement> ::= <Enum> <SchemaElement> schemaElements = token.GetUserObjectForSubToken <List <IPatternBufferReferrable> >((int)SymbolConstants.SYMBOL_SCHEMAELEMENT); schemaElements.Insert(0, token.GetUserObjectForSubToken <PatternBufferEnum>((int)SymbolConstants.SYMBOL_ENUM2)); return(schemaElements); case (int)RuleConstants.RULE_SCHEMAELEMENT3: //<SchemaElement> ::= return(new List <IPatternBufferReferrable>()); case (int)RuleConstants.RULE_BASETYPE_COLON: //<BaseType> ::= ':' <BaseTypeName> return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_BASETYPENAME)); case (int)RuleConstants.RULE_BASETYPE: //<BaseType> ::= return(null); case (int)RuleConstants.RULE_BASETYPENAME_NAME: //<BaseTypeName> ::= Name return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME)); case (int)RuleConstants.RULE_TYPE_TYPE_LPAREN_RPAREN_LBRACE_RBRACE: //<Type> ::= type '(' <TypeId> ')' <TypeName> <BaseType> '{' <Hint> <TypeField> '}' int typeIdInt = token.GetUserObjectForSubToken <int>((int)SymbolConstants.SYMBOL_TYPEID2); ushort typeId = (ushort)0; if (typeIdInt >= 0) { typeId = (ushort)typeIdInt; } string typeName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_TYPENAME); string baseTypeName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_BASETYPE); Dictionary <string, string> typeHints = token.GetUserObjectForSubToken <Dictionary <string, string> >((int)SymbolConstants.SYMBOL_HINT);; IList <PatternBufferField> typeFields = token.GetUserObjectForSubToken <IList <PatternBufferField> >((int)SymbolConstants.SYMBOL_TYPEFIELD); PatternBufferType newType = new PatternBufferType( typeName, typeId, typeFields, typeHints, baseTypeName ); if (typeIdInt < 0) { this.autonumberedTypes.Add(newType); } return(newType); case (int)RuleConstants.RULE_TYPENAME_NAME: //<TypeName> ::= Name return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME)); case (int)RuleConstants.RULE_TYPEID_TYPEID: //<TypeId> ::= TypeId return(token.GetUserObjectForSubToken <int>((int)SymbolConstants.SYMBOL_TYPEID)); case (int)RuleConstants.RULE_TYPEID: //<TypeId> ::= return(0); case (int)RuleConstants.RULE_TYPEFIELD: //<TypeField> ::= <PrimitiveField> <TypeField> IList <PatternBufferField> fields1 = token.GetUserObjectForSubToken <IList <PatternBufferField> >((int)SymbolConstants.SYMBOL_TYPEFIELD); PatternBufferField primitiveField = token.GetUserObjectForSubToken <PatternBufferField>((int)SymbolConstants.SYMBOL_PRIMITIVEFIELD); fields1.Insert(0, primitiveField); return(fields1); case (int)RuleConstants.RULE_TYPEFIELD2: //<TypeField> ::= <ReferenceField> <TypeField> IList <PatternBufferField> fields2 = token.GetUserObjectForSubToken <IList <PatternBufferField> >((int)SymbolConstants.SYMBOL_TYPEFIELD); PatternBufferField referenceField = token.GetUserObjectForSubToken <PatternBufferField>((int)SymbolConstants.SYMBOL_REFERENCEFIELD); fields2.Insert(0, referenceField); return(fields2); case (int)RuleConstants.RULE_TYPEFIELD3: //<TypeField> ::= <ListField> <TypeField> IList <PatternBufferField> fields3 = token.GetUserObjectForSubToken <IList <PatternBufferField> >((int)SymbolConstants.SYMBOL_TYPEFIELD); PatternBufferField listField = token.GetUserObjectForSubToken <PatternBufferField>((int)SymbolConstants.SYMBOL_LISTFIELD); fields3.Insert(0, listField); return(fields3); case (int)RuleConstants.RULE_TYPEFIELD4: //<TypeField> ::= <SetField> <TypeField> IList <PatternBufferField> fields4 = token.GetUserObjectForSubToken <IList <PatternBufferField> >((int)SymbolConstants.SYMBOL_TYPEFIELD); PatternBufferField setField = token.GetUserObjectForSubToken <PatternBufferField>((int)SymbolConstants.SYMBOL_SETFIELD); fields4.Insert(0, setField); return(fields4); case (int)RuleConstants.RULE_TYPEFIELD5: //<TypeField> ::= <MapField> <TypeField> IList <PatternBufferField> fields5 = token.GetUserObjectForSubToken <IList <PatternBufferField> >((int)SymbolConstants.SYMBOL_TYPEFIELD); PatternBufferField mapField = token.GetUserObjectForSubToken <PatternBufferField>((int)SymbolConstants.SYMBOL_MAPFIELD); fields5.Insert(0, mapField); return(fields5); case (int)RuleConstants.RULE_TYPEFIELD6: //<TypeField> ::= return(new List <PatternBufferField>()); case (int)RuleConstants.RULE_PRIMITIVEFIELD_SEMI: //<PrimitiveField> ::= <PrimitiveFieldType> <FieldName> ';' string primitiveFieldType = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_PRIMITIVEFIELDTYPE); string primitiveFieldName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_FIELDNAME); return(new PatternBufferField( primitiveFieldName, new PrimitiveFieldType((PrimitiveType)Enum.Parse(typeof(PrimitiveType), primitiveFieldType, true)) )); case (int)RuleConstants.RULE_PRIMITIVEFIELDTYPE_PRIMITIVE: //<PrimitiveFieldType> ::= Primitive return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_PRIMITIVE)); case (int)RuleConstants.RULE_REFERENCEFIELD_SEMI: //<ReferenceField> ::= <ReferenceFieldType> <FieldName> ';' string referenceFieldType = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_REFERENCEFIELDTYPE); string referenceFieldName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_FIELDNAME); return(new PatternBufferField( referenceFieldName, new ReferenceFieldType(referenceFieldType) )); case (int)RuleConstants.RULE_REFERENCEFIELDTYPE_NAME: //<ReferenceFieldType> ::= Name return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME)); case (int)RuleConstants.RULE_FIELDNAME_NAME: //<FieldName> ::= Name return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME)); case (int)RuleConstants.RULE_LISTFIELD_LIST_LT_GT_SEMI: //<ListField> ::= list '<' <AggregateArg> '>' <FieldName> ';' string listAggregateArgName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_AGGREGATEARG); string listFieldName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_FIELDNAME); return(new PatternBufferField( listFieldName, new ListFieldType(this.CreateAggregateableFieldType(listAggregateArgName)) )); case (int)RuleConstants.RULE_SETFIELD_SET_LT_GT_SEMI: //<SetField> ::= set '<' <AggregateArg> '>' <FieldName> ';' string setAggregateArgName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_AGGREGATEARG); string setFieldName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_FIELDNAME); return(new PatternBufferField( setFieldName, new SetFieldType(this.CreateAggregateableFieldType(setAggregateArgName)) )); case (int)RuleConstants.RULE_MAPFIELD_MAP_LT_COMMA_GT_SEMI: //<MapField> ::= map '<' <AggregateArg> ',' <AggregateArg> '>' <FieldName> ';' string mapKeyAggregateArgName = null; string mapValueAggregateArgName = null; foreach (Token mapToken in token.Tokens) { if (mapToken is NonterminalToken) { NonterminalToken mapNonterminal = (NonterminalToken)mapToken; if (mapNonterminal.Symbol.Id == (int)SymbolConstants.SYMBOL_AGGREGATEARG) { if (mapKeyAggregateArgName == null) { mapKeyAggregateArgName = (string)mapNonterminal.UserObject; } else { mapValueAggregateArgName = (string)mapNonterminal.UserObject; break; } } } } string mapFieldName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_FIELDNAME); return(new PatternBufferField( mapFieldName, new MapFieldType( this.CreateAggregateableFieldType(mapKeyAggregateArgName), this.CreateAggregateableFieldType(mapValueAggregateArgName) ) )); case (int)RuleConstants.RULE_AGGREGATEARG: //<AggregateArg> ::= <PrimitiveFieldType> return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_PRIMITIVEFIELDTYPE)); case (int)RuleConstants.RULE_AGGREGATEARG2: //<AggregateArg> ::= <ReferenceFieldType> return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_REFERENCEFIELDTYPE)); case (int)RuleConstants.RULE_ENUM_ENUM_LBRACE_RBRACE: //<Enum> ::= enum <EnumName> '{' <Hint> <EnumValue> '}' string enumName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_ENUMNAME); List <string> enumValues = token.GetUserObjectForSubToken <List <string> >((int)SymbolConstants.SYMBOL_ENUMVALUE); HashSet <string> uniques = new HashSet <string>(enumValues); if (uniques.Count < enumValues.Count) { throw new PatternBufferSchemaException("Enum \"" + enumName + "\" has " + (enumValues.Count - uniques.Count) + " duplicate enum values."); } if (uniques.Count == 0) { throw new PatternBufferSchemaException("Enum \"" + enumName + "\" has no values. Enums must have at least one value."); } Dictionary <string, string> enumHints = token.GetUserObjectForSubToken <Dictionary <string, string> >((int)SymbolConstants.SYMBOL_HINT); return(new PatternBufferEnum( enumName, enumValues, enumHints )); case (int)RuleConstants.RULE_ENUMNAME_NAME: //<EnumName> ::= Name return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME)); case (int)RuleConstants.RULE_ENUMVALUE_NAME: //<EnumValue> ::= Name return(new List <string>() { token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME) }); case (int)RuleConstants.RULE_ENUMVALUE_NAME_COMMA: //<EnumValue> ::= Name ',' <EnumValue> List <string> enumValues2 = token.GetUserObjectForSubToken <List <string> >((int)SymbolConstants.SYMBOL_ENUMVALUE); enumValues2.Insert(0, token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_NAME)); return(enumValues2); case (int)RuleConstants.RULE_HINT_LBRACKET_EQ_RBRACKET: //<Hint> ::= '[' <HintName> '=' <HintValue> ']' <Hint> Dictionary <string, string> collectedHints = token.GetUserObjectForSubToken <Dictionary <string, string> >((int)SymbolConstants.SYMBOL_HINT); string hintName = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_HINTNAME2); string hintValue = token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_HINTVALUE); collectedHints[hintName] = hintValue; return(collectedHints); case (int)RuleConstants.RULE_HINT: //<Hint> ::= return(new Dictionary <string, string>()); case (int)RuleConstants.RULE_HINTNAME_HINTNAME: //<HintName> ::= HintName return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_HINTNAME)); case (int)RuleConstants.RULE_HINTVALUE_STRING: //<HintValue> ::= String return(token.GetUserObjectForSubToken <string>((int)SymbolConstants.SYMBOL_STRING)); } throw new RuleException("Unknown rule"); }