Beispiel #1
0
        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);
        }
Beispiel #2
0
        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");
        }