From f817894b4900c71cef422db4d56001809fd0891c Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Wed, 12 Oct 2022 23:25:21 -0400 Subject: [PATCH] Added untested object member analysis --- analyzer/type-section.go | 102 +++++++++++++++++++++++++++++++--- analyzer/type-section_test.go | 6 +- parser/accessors.go | 6 ++ 3 files changed, 106 insertions(+), 8 deletions(-) diff --git a/analyzer/type-section.go b/analyzer/type-section.go index 9e0c5d1..ec7e0d1 100644 --- a/analyzer/type-section.go +++ b/analyzer/type-section.go @@ -19,6 +19,7 @@ type TypeSection struct { // ObjectMember is a member of an object type. type ObjectMember struct { + locatable name string // even if there is a private permission in another module, we still @@ -27,6 +28,7 @@ type ObjectMember struct { permission types.Permission what Type + argument Argument } func (member ObjectMember) ToString (indent int) (output string) { @@ -98,12 +100,13 @@ func (analyzer analysisOperation) analyzeTypeSection () ( inputSection := analyzer.currentSection.(parser.TypeSection) 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() @@ -126,12 +129,10 @@ func (analyzer analysisOperation) analyzeTypeSection () ( // analyze members isObj := outputSection.what.underlyingPrimitive() == &PrimitiveObj if isObj { - // use the Member method on the inherited type to type check and - // permission check default value overrides. - for index := 0; index < inputSection.MembersLength(); index ++ { - // inputMember := inputSection.Member(index) - // TODO - } + err = analyzer.analyzeObjectMembers ( + &outputSection, + inputSection) + if err != nil { return } } else if inputSection.MembersLength() > 0 { // if there are members, and the inherited type does not have @@ -140,8 +141,95 @@ func (analyzer analysisOperation) analyzeTypeSection () ( "members can only be defined on types descending " + "from Obj", infoerr.ErrorKindError) + if err != nil { return } } outputSection.complete = true return } + +func (analyzer *analysisOperation) analyzeObjectMembers ( + into *TypeSection, + from parser.TypeSection, +) ( + err error, +) { + inheritedSection := into.what.actual + for index := 0; index < from.MembersLength(); index ++ { + inputMember := from.Member(index) + + outputMember := ObjectMember { } + outputMember.location = inputMember.Location() + outputMember.name = inputMember.Name() + outputMember.permission = inputMember.Permission() + + inheritedMember, exists := + inheritedSection.Member(inputMember.Name()) + + if exists { + // modifying default value/permissions of an + // inherited member + + outputMember.what = inheritedMember.what + if !inputMember.Type().Nil() { + err = inputMember.NewError ( + "cannot override type of " + + "inherited member", + infoerr.ErrorKindError) + return + } + + if outputMember.permission > inheritedMember.permission { + err = inputMember.NewError ( + "cannot relax permission of " + + "inherited member", + infoerr.ErrorKindError) + return + } + + // apply default value + if inputMember.Argument().Nil() { + // if it is unspecified, inherit it + outputMember.argument = inheritedMember.argument + } else { + outputMember.argument, + err = analyzer.analyzeArgument(inputMember.Argument()) + if err != nil { return } + + // type check default value + err = analyzer.typeCheck ( + outputMember.argument, + outputMember.what) + if err != nil { return } + } + + } else { + // defining a new member + if inputMember.Type().Nil() { + err = inputMember.NewError ( + "new members must be given a " + + "type", + infoerr.ErrorKindError) + return + } + + // apply default value + if !inputMember.Argument().Nil() { + outputMember.argument, + err = analyzer.analyzeArgument(inputMember.Argument()) + if err != nil { return } + + // type check default value + err = analyzer.typeCheck ( + outputMember.argument, + outputMember.what) + if err != nil { return } + } + } + + into.members = append ( + into.members, + outputMember) + } + return +} diff --git a/analyzer/type-section_test.go b/analyzer/type-section_test.go index 832370a..794058b 100644 --- a/analyzer/type-section_test.go +++ b/analyzer/type-section_test.go @@ -4,7 +4,9 @@ import "testing" func TestTypeSection (test *testing.T) { checkTree ("../tests/analyzer/typeSection", false, -`typeSection ro ../tests/analyzer/typeSection.aBasicInt +`typeSection ro ../tests/analyzer/typeSection/something.Thing + type 1 basic Int +typeSection ro ../tests/analyzer/typeSection.aBasicInt type 1 basic Int arg uint 5 typeSection ro ../tests/analyzer/typeSection.bOnBasicInt @@ -15,5 +17,7 @@ typeSection ro ../tests/analyzer/typeSection.cBasicObject type 1 basic Int member ro this type 1 basic Int +typeSection ro ../tests/analyzer/typeSection.dInheritedFromOther + type 1 basic Thing `, test) } diff --git a/parser/accessors.go b/parser/accessors.go index acfef7d..37bba2b 100644 --- a/parser/accessors.go +++ b/parser/accessors.go @@ -55,6 +55,12 @@ func (what Type) Kind () (kind TypeKind) { return } +// Nil returns true if the type is nil, and false if it isn't. +func (what Type) Nil () (isNil bool) { + isNil = what.kind == TypeKindNil + return +} + // Mutable returns whether or not the type's data is mutable. func (what Type) Mutable () (mutable bool) { mutable = what.mutable