Beispiel #1
0
// ENUM_BODY     -> [ ENUN_VALUE {, ENUM_VALUE} [,] ]
// ENUM_VALUE    -> [ATTRIBUTES] name [equals ENUM_VAL_INITIALIZER]
func (p *Parser) parseEnumBody(mojomEnum *mojom.MojomEnum) bool {
	if !p.OK() {
		return p.OK()
	}
	p.pushChildNode("enumBody")
	defer p.popNode()

	// The enum body forms a new scope in which it's enun values are defined.
	p.pushScope(mojomEnum.InitAsScope(p.currentScope))
	defer p.popScope()

	rbraceFound := false
	trailingCommaFound := false
	firstValue := true
	for attributes := p.parseAttributes(); !rbraceFound; attributes = p.parseAttributes() {
		if !p.OK() {
			return false
		}
		nextToken := p.peekNextToken("I was parsing an enum body.")
		var duplicateNameError error = nil
		switch nextToken.Kind {
		case lexer.Name:
			if !firstValue && !trailingCommaFound {
				message := fmt.Sprintf("Expecting a comma after %s before "+
					"the next value %s at %s. ", p.lastConsumed, nextToken,
					nextToken.LongLocationString())
				p.err = &ParseError{ParserErrorCodeUnexpectedToken, message}
				return false
			}
			firstValue = false
			name := p.readName()
			p.attachToken()
			nameToken := p.lastConsumed
			var valueRef mojom.ValueRef
			if p.tryMatch(lexer.Equals) {
				valueRef = p.parseEnumValueInitializer(mojomEnum)
			}
			declData := p.DeclData(name, nameToken, attributes)
			duplicateNameError = mojomEnum.AddEnumValue(declData, valueRef)
			trailingCommaFound = p.tryMatch(lexer.Comma)
		case lexer.RBrace:
			rbraceFound = true
			if attributes != nil {
				message := "Enum body ends with extraneouss attributes."
				p.err = &ParseError{ParserErrorCodeBadAttributeLocation, message}
			}
			break
		case lexer.Comma:
			break
		default:
			p.unexpectedTokenError(nextToken, "either another enum value or }")
			return false
		}
		if p.OK() && duplicateNameError != nil {
			p.err = &ParseError{ParserErrorCodeDuplicateDeclaration, duplicateNameError.Error()}
			return false
		}
	}
	return p.OK()
}
Beispiel #2
0
// ENUM_VAL_INITIALIZER -> INTEGER_LITERAL | ENUM_VALUE_REF
// ENUM_VALUE_REF       -> IDENTIFIER {{that resolves to a declared enum value}}
func (p *Parser) parseEnumValueInitializer(mojoEnum *mojom.MojomEnum) mojom.ValueRef {
	if !p.OK() {
		return nil
	}
	p.pushChildNode("enumValueInitializer")
	defer p.popNode()

	// We need to manufacture an instance of Type to act as the "assigneeType"
	// for the new ValueSpec we are creating. This is because unlike
	// other types of value assignment, an enum value initializer is not
	// preceded by a type reference for the assignee. Rather the type of
	// the assignee is implicit in the scope.
	enumType := mojom.NewResolvedUserTypeRef(mojoEnum.FullyQualifiedName(), mojoEnum)

	valueToken := p.peekNextToken("Parsing an enum value initializer type.")
	valueRef := p.parseValue(enumType)
	if valueRef == nil {
		return nil
	}
	if !valueRef.MarkUsedAsEnumValueInitializer() {
		message := fmt.Sprintf("Illegal value: %s at %s. An enum value may "+
			"only be initialized by an integer or another enum value.", valueToken,
			valueToken.LongLocationString())
		p.err = &ParseError{ParserErrorCodeUnexpectedToken, message}
		return nil
	}

	return valueRef
}
Beispiel #3
0
// ENUM_BODY     -> [ ENUN_VALUE {, ENUM_VALUE} [,] ]
// ENUM_VALUE    -> [ATTRIBUTES] name [equals ENUM_VAL_INITIALIZER]
func (p *Parser) parseEnumBody(mojomEnum *mojom.MojomEnum) bool {
	if !p.OK() {
		return p.OK()
	}
	p.pushChildNode("enumBody")
	defer p.popNode()

	// The enum body forms a new scope in which it's enun values are defined.
	p.pushScope(mojomEnum.InitAsScope(p.currentScope))
	defer p.popScope()

	rbraceFound := false
	trailingCommaFound := false
	firstValue := true
	for attributes := p.parseAttributes(); !rbraceFound; attributes = p.parseAttributes() {
		if !p.OK() {
			return false
		}
		nextToken := p.peekNextToken("I was parsing an enum body.")
		dupeMessage := ""
		switch nextToken.Kind {
		case lexer.NAME:
			if !firstValue && !trailingCommaFound {
				message := fmt.Sprintf("Expecting a comma after %s before "+
					"the next value %s at %s. ", p.lastConsumed, nextToken,
					nextToken.LongLocationString())
				p.err = &ParseError{E_UNEXPECTED_TOKEN, message}
				return false
			}
			firstValue = false
			name := p.readName()
			p.attachToken()
			nameToken := p.lastConsumed
			var valueRef mojom.ValueRef
			if p.tryMatch(lexer.EQUALS) {
				valueRef = p.parseEnumValueInitializer(mojomEnum)
			}
			dupeMessage = p.duplicateNameMessage(
				mojomEnum.AddEnumValue(name, valueRef, attributes), nameToken)
			trailingCommaFound = p.tryMatch(lexer.COMMA)
		case lexer.RBRACE:
			rbraceFound = true
			if attributes != nil {
				message := "Enum body ends with extranesous attributes."
				p.err = &ParseError{E_BAD_ATTRIBUTE_LOCATION, message}
			}
			break
		case lexer.COMMA:
			break
		default:
			p.unexpectedTokenError(nextToken, "either another enum value or }")
			return false
		}
		if p.OK() && len(dupeMessage) > 0 {
			p.err = &ParseError{E_DUPLICATE_DECLARATION, dupeMessage}
			return false
		}
	}
	if p.OK() {
		mojomEnum.ComputeEnumValues()
	}
	return p.OK()
}