This repository has been archived on 2024-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
arf/analyzer/enum-section.go

143 lines
3.7 KiB
Go

package analyzer
import "git.tebibyte.media/arf/arf/types"
import "git.tebibyte.media/arf/arf/parser"
import "git.tebibyte.media/arf/arf/infoerr"
// EnumSection represents an enumerated type section.
type EnumSection struct {
sectionBase
what Type
members []EnumMember
}
// EnumMember is a member of an enumerated type.
type EnumMember struct {
locatable
name string
argument Argument
}
// ToString returns all data stored within the member, in string form.
func (member EnumMember) ToString (indent int) (output string) {
output += doIndent(indent, "member ", member.name, "\n")
if member.argument != nil {
output += member.argument.ToString(indent + 1)
}
return
}
// ToString returns all data stored within the type section, in string form.
func (section EnumSection) ToString (indent int) (output string) {
output += doIndent(indent, "enumSection ")
output += section.permission.ToString() + " "
output += section.where.ToString()
output += "\n"
output += section.what.ToString(indent + 1)
for _, member := range section.members {
output += member.ToString(indent + 1)
}
return
}
// analyzeEnumSection analyzes an enumerated type section.
func (analyzer analysisOperation) analyzeEnumSection () (
section Section,
err error,
) {
outputSection := EnumSection { }
outputSection.where = analyzer.currentPosition
section = &outputSection
analyzer.addSection(section)
inputSection := analyzer.currentSection.(parser.EnumSection)
outputSection.location = analyzer.currentSection.Location()
if inputSection.Permission() == types.PermissionReadWrite {
err = inputSection.NewError (
"read-write (rw) permission not understood in this " +
"context, try read-only (ro)",
infoerr.ErrorKindError)
return
}
outputSection.permission = inputSection.Permission()
// get inherited type
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 {
err = inputSection.Type().NewError (
"enum sections can only inherit from other type " +
"sections",
infoerr.ErrorKindError)
return
}
// analyze members
for index := 0; index < inputSection.Length(); index ++ {
inputMember := inputSection.Item(index)
outputMember := EnumMember { }
outputMember.location = inputMember.Location()
outputMember.name = inputMember.Name()
if !inputMember.Argument().Nil() {
outputMember.argument,
err = analyzer.analyzeArgument(inputMember.Argument())
if err != nil { return }
// type check default value
err = analyzer.typeCheck (
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 (
outputSection.members,
outputMember)
}
// TODO: fill in members that do not have values with incrementing
// values. take care to not duplicate them.
outputSection.complete = true
return
}