294 lines
7.2 KiB
Go
294 lines
7.2 KiB
Go
package analyzer
|
|
|
|
import "fmt"
|
|
import "git.tebibyte.media/arf/arf/types"
|
|
import "git.tebibyte.media/arf/arf/parser"
|
|
import "git.tebibyte.media/arf/arf/infoerr"
|
|
|
|
// TypeSection represents a type definition section.
|
|
type TypeSection struct {
|
|
sectionBase
|
|
what Type
|
|
argument Argument
|
|
members []ObjectMember
|
|
}
|
|
|
|
// ObjectMember is a member of an object type.
|
|
type ObjectMember struct {
|
|
locatable
|
|
name string
|
|
bitWidth uint64
|
|
permission types.Permission
|
|
|
|
what Type
|
|
argument Argument
|
|
}
|
|
|
|
// ToString returns all data stored within the member, in string form.
|
|
func (member ObjectMember) ToString (indent int) (output string) {
|
|
output += doIndent (
|
|
indent, "member ",
|
|
member.permission.ToString(), " ",
|
|
member.name)
|
|
if member.bitWidth > 0 {
|
|
output += fmt.Sprint(" width ", member.bitWidth)
|
|
}
|
|
output += "\n"
|
|
|
|
output += member.what.ToString(indent + 1)
|
|
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 TypeSection) ToString (indent int) (output string) {
|
|
output += doIndent(indent, "typeSection ")
|
|
output += section.permission.ToString() + " "
|
|
output += section.where.ToString()
|
|
output += "\n"
|
|
output += section.what.ToString(indent + 1)
|
|
if section.argument != nil {
|
|
output += section.argument.ToString(indent + 1)
|
|
}
|
|
for _, member := range section.members {
|
|
output += member.ToString(indent + 1)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Member returns the membrs ksdn ,mn ,mxc lkzxjclkjxzc l,mnzc .,zxmn.,zxmc
|
|
// IT RECURSES!
|
|
func (section TypeSection) Member (
|
|
name string,
|
|
) (
|
|
member ObjectMember,
|
|
exists bool,
|
|
) {
|
|
switch section.what.kind {
|
|
case TypeKindBasic:
|
|
for _, currentMember := range section.members {
|
|
if currentMember.name == name {
|
|
member = currentMember
|
|
exists = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !exists {
|
|
if section.what.actual == nil { return }
|
|
|
|
actual, isTypeSection := section.what.actual.(*TypeSection)
|
|
if !isTypeSection { return }
|
|
member, exists = actual.Member(name)
|
|
}
|
|
|
|
case TypeKindPointer:
|
|
points := section.what.points
|
|
if points == nil { return }
|
|
|
|
actual, isTypeSection := points.actual.(*TypeSection)
|
|
if !isTypeSection { return }
|
|
member, exists = actual.Member(name)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// analyzeTypeSection analyzes a type section.
|
|
func (analyzer analysisOperation) analyzeTypeSection () (
|
|
section Section,
|
|
err error,
|
|
) {
|
|
outputSection := TypeSection { }
|
|
outputSection.where = analyzer.currentPosition
|
|
|
|
section = &outputSection
|
|
analyzer.addSection(section)
|
|
|
|
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()
|
|
|
|
// get inherited type
|
|
outputSection.what, err = analyzer.analyzeType(inputSection.Type())
|
|
if err != nil { return }
|
|
|
|
if !inputSection.Argument().Nil() {
|
|
outputSection.argument,
|
|
err = analyzer.analyzeArgument(inputSection.Argument())
|
|
if err != nil { return }
|
|
|
|
// type check default value
|
|
err = analyzer.typeCheck (
|
|
outputSection.argument,
|
|
outputSection.what)
|
|
if err != nil { return }
|
|
}
|
|
|
|
// analyze members
|
|
isObj := outputSection.what.underlyingPrimitive() == &PrimitiveObj
|
|
if isObj {
|
|
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
|
|
// Obj as a primitive, throw an error.
|
|
err = inputSection.Member(0).NewError (
|
|
"members can only be defined on types descending " +
|
|
"from Obj",
|
|
infoerr.ErrorKindError)
|
|
if err != nil { return }
|
|
}
|
|
|
|
outputSection.complete = true
|
|
return
|
|
}
|
|
|
|
// analyzeObjectMembers analyzes object members from a parser type section into
|
|
// a semantic type section.
|
|
func (analyzer *analysisOperation) analyzeObjectMembers (
|
|
into *TypeSection,
|
|
from parser.TypeSection,
|
|
) (
|
|
err error,
|
|
) {
|
|
inheritedSection := into.what.actual.(*TypeSection)
|
|
inheritsFromSameModule := analyzer.inCurrentModule(inheritedSection)
|
|
|
|
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()
|
|
outputMember.bitWidth = inputMember.BitWidth()
|
|
|
|
inheritedMember, exists :=
|
|
inheritedSection.Member(inputMember.Name())
|
|
|
|
if exists {
|
|
// modifying default value/permissions of an
|
|
// inherited member
|
|
|
|
canAccessMember :=
|
|
inheritsFromSameModule ||
|
|
inheritedMember.permission !=
|
|
types.PermissionPrivate
|
|
|
|
if !canAccessMember {
|
|
err = inputMember.NewError (
|
|
"inherited member is private (pv) in " +
|
|
"parent type, and cannot be modified " +
|
|
"here",
|
|
infoerr.ErrorKindError)
|
|
return
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
canOverwriteMember :=
|
|
inheritsFromSameModule ||
|
|
inheritedMember.permission ==
|
|
types.PermissionReadWrite
|
|
|
|
// apply default value
|
|
if inputMember.Argument().Nil() {
|
|
// if it is unspecified, inherit it
|
|
outputMember.argument = inheritedMember.argument
|
|
} else {
|
|
if !canOverwriteMember {
|
|
err = inputMember.Argument().NewError (
|
|
"member is read-only (ro) in " +
|
|
"parent type, its default " +
|
|
"value cannot be overridden",
|
|
infoerr.ErrorKindError)
|
|
return
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
outputMember.what, err = analyzer.analyzeType (
|
|
inputMember.Type())
|
|
if err != nil { 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 }
|
|
}
|
|
}
|
|
|
|
// ensure all member names are unique
|
|
for _, compareMember := range into.members {
|
|
if compareMember.name == outputMember.name {
|
|
err = inputMember.NewError (
|
|
"object member names must be unique",
|
|
infoerr.ErrorKindError)
|
|
return
|
|
}
|
|
}
|
|
|
|
into.members = append (
|
|
into.members,
|
|
outputMember)
|
|
}
|
|
return
|
|
}
|