From 2669a0485791f9cf0ce26031a2c4095a925b8dd9 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Fri, 14 Oct 2022 04:00:05 -0400 Subject: [PATCH] Enum member names and values must be unique --- analyzer/argument.go | 2 ++ analyzer/enum-section.go | 31 +++++++++++++++++++ analyzer/literals.go | 48 +++++++++++++++++++++++++++++ file/location.go | 4 +++ tests/analyzer/enumSection/main.arf | 11 +++---- 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/analyzer/argument.go b/analyzer/argument.go index 21387e4..bd292a6 100644 --- a/analyzer/argument.go +++ b/analyzer/argument.go @@ -20,6 +20,8 @@ type Argument interface { Location () (location file.Location) NewError (message string, kind infoerr.ErrorKind) (err error) ToString (indent int) (output string) + Equals (value any) (equal bool) + Value () (value any) canBePassedAs (what Type) (allowed bool) } diff --git a/analyzer/enum-section.go b/analyzer/enum-section.go index 3100f42..b018a55 100644 --- a/analyzer/enum-section.go +++ b/analyzer/enum-section.go @@ -69,6 +69,10 @@ func (analyzer analysisOperation) analyzeEnumSection () ( outputSection.what, err = analyzer.analyzeType(inputSection.Type()) if err != nil { return } + isNumeric := + outputSection.what.isNumeric() && + outputSection.what.isSingular() + // enum sections are only allowed to inherit from type sections _, inheritsFromTypeSection := outputSection.what.actual.(*TypeSection) if !inheritsFromTypeSection { @@ -96,6 +100,33 @@ func (analyzer analysisOperation) analyzeEnumSection () ( outputMember.argument, outputSection.what) if err != nil { return } + } else if !isNumeric { + // non-numeric enums must have filled in values + err = inputMember.NewError ( + "member value must be specified manually for " + + "non-numeric enums", + infoerr.ErrorKindError) + return + } + + for _, compareMember := range outputSection.members { + if compareMember.name == outputMember.name { + err = inputMember.NewError ( + "enum member names must be unique", + infoerr.ErrorKindError) + return + } + + if outputMember.argument == nil { continue } + + if compareMember.argument.Equals ( + outputMember.argument.Value(), + ) { + err = inputMember.NewError ( + "enum member values must be unique", + infoerr.ErrorKindError) + return + } } outputSection.members = append ( diff --git a/analyzer/literals.go b/analyzer/literals.go index ce6fe6d..8236b90 100644 --- a/analyzer/literals.go +++ b/analyzer/literals.go @@ -39,6 +39,18 @@ func (literal IntLiteral) What () (what Type) { return } +// Equals returns whether the literal is equal to the specified value. +func (literal IntLiteral) Equals (value any) (equal bool) { + equal = literal.value == value + return +} + +// Value returns the literal's value +func (literal IntLiteral) Value () (value any) { + value = literal.value + return +} + // canBePassedAs returns true if this literal can be implicitly cast to the // specified type, and false if it can't. func (literal IntLiteral) canBePassedAs (what Type) (allowed bool) { @@ -63,6 +75,18 @@ func (literal UIntLiteral) What () (what Type) { return } +// Equals returns whether the literal is equal to the specified value. +func (literal UIntLiteral) Equals (value any) (equal bool) { + equal = literal.value == value + return +} + +// Value returns the literal's value +func (literal UIntLiteral) Value () (value any) { + value = literal.value + return +} + // canBePassedAs returns true if this literal can be implicitly cast to the // specified type, and false if it can't. func (literal UIntLiteral) canBePassedAs (what Type) (allowed bool) { @@ -86,6 +110,18 @@ func (literal FloatLiteral) ToString (indent int) (output string) { return } +// Equals returns whether the literal is equal to the specified value. +func (literal FloatLiteral) Equals (value any) (equal bool) { + equal = literal.value == value + return +} + +// Value returns the literal's value +func (literal FloatLiteral) Value () (value any) { + value = literal.value + return +} + // canBePassedAs returns true if this literal can be implicitly cast to the // specified type, and false if it can't. func (literal FloatLiteral) canBePassedAs (what Type) (allowed bool) { @@ -117,6 +153,18 @@ func (literal StringLiteral) ToString (indent int) (output string) { return } +// Equals returns whether the literal is equal to the specified value. +func (literal StringLiteral) Equals (value any) (equal bool) { + equal = literal.value == value + return +} + +// Value returns the literal's value +func (literal StringLiteral) Value () (value any) { + value = literal.value + return +} + // canBePassedAs returns true if this literal can be implicitly cast to the // specified type, and false if it can't. func (literal StringLiteral) canBePassedAs (what Type) (allowed bool) { diff --git a/file/location.go b/file/location.go index fb92989..7be2cde 100644 --- a/file/location.go +++ b/file/location.go @@ -47,3 +47,7 @@ func (location Location) Describe () (description string) { " column ", location.column + 1, " width ", location.width) } + +// TODO: add extend method that extends that takes in another location, and +// returns a new location that spans the two. then, use it in the parser to +// properly locate an entire tree node. diff --git a/tests/analyzer/enumSection/main.arf b/tests/analyzer/enumSection/main.arf index b5bd3a5..0093333 100644 --- a/tests/analyzer/enumSection/main.arf +++ b/tests/analyzer/enumSection/main.arf @@ -1,4 +1,5 @@ :arf +require '../typeSection' --- enum ro aWeekday:Int @@ -12,9 +13,7 @@ enum ro aWeekday:Int type ro bColor:U32 -enum ro cNamedColor:bColor - - red 0xFF0000 - - green 0x00FF00 - - blue 0x0000FF - -type ro X:cNamedColor +# enum ro cNamedColor:bColor + # - red 0xFF0000 + # - green 0x00FF00 + # - blue 0x0000FF