From a1faf68cce94e1f233ea2ffb54731f1fd016bcbe Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Thu, 13 Oct 2022 18:02:35 -0400 Subject: [PATCH] Untested enum analysis --- analyzer/analyzer.go | 4 +- analyzer/enum-section.go | 104 ++++++++++++++++++++++++++++ analyzer/enum-section_test.go | 9 +++ analyzer/type-section.go | 8 +-- parser/enum.go | 3 +- tests/analyzer/enumSection/main.arf | 11 +++ 6 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 analyzer/enum-section.go create mode 100644 analyzer/enum-section_test.go create mode 100644 tests/analyzer/enumSection/main.arf diff --git a/analyzer/analyzer.go b/analyzer/analyzer.go index cc8c789..a2bb773 100644 --- a/analyzer/analyzer.go +++ b/analyzer/analyzer.go @@ -111,7 +111,7 @@ func (analyzer *analysisOperation) fetchSection ( analyzer.currentTree = previousTree } () - // TODO: analyze section. have analysis methods work on currentPosition + // analyze section. have analysis methods work on currentPosition // and currentSection. // // while building an analyzed section, add it to the section @@ -123,6 +123,8 @@ func (analyzer *analysisOperation) fetchSection ( section, err = analyzer.analyzeTypeSection() if err != nil { return} case parser.EnumSection: + section, err = analyzer.analyzeEnumSection() + if err != nil { return} case parser.FaceSection: case parser.DataSection: case parser.FuncSection: diff --git a/analyzer/enum-section.go b/analyzer/enum-section.go new file mode 100644 index 0000000..35d558d --- /dev/null +++ b/analyzer/enum-section.go @@ -0,0 +1,104 @@ +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 } + + // 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 } + } + } + + outputSection.complete = true + return +} diff --git a/analyzer/enum-section_test.go b/analyzer/enum-section_test.go new file mode 100644 index 0000000..1650a70 --- /dev/null +++ b/analyzer/enum-section_test.go @@ -0,0 +1,9 @@ +package analyzer + +import "testing" + +func TestEnumSection (test *testing.T) { + checkTree ("../tests/analyzer/enumSection", false, +` +`, test) +} diff --git a/analyzer/type-section.go b/analyzer/type-section.go index f18354c..c24b61f 100644 --- a/analyzer/type-section.go +++ b/analyzer/type-section.go @@ -9,7 +9,6 @@ import "git.tebibyte.media/arf/arf/infoerr" type TypeSection struct { sectionBase what Type - complete bool argument Argument members []ObjectMember } @@ -19,10 +18,6 @@ type ObjectMember struct { locatable name string bitWidth uint64 - - // even if there is a private permission in another module, we still - // need to include it in the semantic analysis because we need to know - // what members objects have. permission types.Permission what Type @@ -126,6 +121,7 @@ func (analyzer analysisOperation) analyzeTypeSection () ( outputSection.permission = inputSection.Permission() + // get inherited type outputSection.what, err = analyzer.analyzeType(inputSection.Type()) if err != nil { return } @@ -173,6 +169,8 @@ func (analyzer analysisOperation) analyzeTypeSection () ( return } +// analyzeObjectMembers analyzes object members from a parser type section into +// a semantic type section. func (analyzer *analysisOperation) analyzeObjectMembers ( into *TypeSection, from parser.TypeSection, diff --git a/parser/enum.go b/parser/enum.go index 93a37f4..76d0e99 100644 --- a/parser/enum.go +++ b/parser/enum.go @@ -87,7 +87,8 @@ func (parser *parsingOperation) parseEnumMember () ( err = parser.nextToken() if err != nil { return } if parser.token.Is(lexer.TokenKindNewline) { - parser.nextToken() + err = parser.nextToken() + if err != nil { return } // if we have exited the member, return if !parser.token.Is(lexer.TokenKindIndent) { return } if parser.token.Value().(int) != 2 { return } diff --git a/tests/analyzer/enumSection/main.arf b/tests/analyzer/enumSection/main.arf new file mode 100644 index 0000000..6c2a43a --- /dev/null +++ b/tests/analyzer/enumSection/main.arf @@ -0,0 +1,11 @@ +:arf +--- + +enum ro Weekday:Int + - sunday + - monday + - tuesday + - wednesday + - thursday + - friday + - saturday