Merge pull request 'objt-section' (#5) from objt-section into main

Reviewed-on: #5
This commit is contained in:
Sasha Koshka 2022-08-20 19:47:44 +00:00
commit 61819311e9
8 changed files with 274 additions and 191 deletions

View File

@ -27,7 +27,16 @@ func (parser *ParsingOperation) parseBody () (err error) {
parser.tree.typeSections =
make(map[string] *TypeSection)
}
parser.tree.typeSections[section.root.name] = section
parser.tree.typeSections[section.name] = section
if err != nil { return }
case "objt":
var section *ObjtSection
section, err = parser.parseObjtSection()
if parser.tree.objtSections == nil {
parser.tree.objtSections =
make(map[string] *ObjtSection)
}
parser.tree.objtSections[section.name] = section
if err != nil { return }
case "face":
case "enum":

119
parser/objt.go Normal file
View File

@ -0,0 +1,119 @@
package parser
import "git.tebibyte.media/sashakoshka/arf/types"
import "git.tebibyte.media/sashakoshka/arf/lexer"
import "git.tebibyte.media/sashakoshka/arf/infoerr"
// parseObjtSection parses an object type definition. This allows for structured
// types to be defined, and for member variables to be added and overridden.
func (parser *ParsingOperation) parseObjtSection () (
section *ObjtSection,
err error,
) {
err = parser.expect(lexer.TokenKindName)
if err != nil { return }
section = &ObjtSection {
location: parser.token.Location(),
members: make(map[string] ObjtMember),
}
// get permission
err = parser.nextToken(lexer.TokenKindPermission)
if err != nil { return }
section.permission = parser.token.Value().(types.Permission)
// get name
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
section.name = parser.token.Value().(string)
// parse inherited type
err = parser.nextToken(lexer.TokenKindColon)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
section.inherits, err = parser.parseType()
if err != nil { return }
err = parser.expect(lexer.TokenKindNewline)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
// parse members
err = parser.parseObjtMembers(section)
if err != nil { return }
if len(section.members) == 0 {
infoerr.NewError (
section.location,
"defining an object with no members",
infoerr.ErrorKindWarn).Print()
}
return
}
// parseObjtMembers parses a list of members for an object section. Indentation
// level is assumed.
func (parser *ParsingOperation) parseObjtMembers (
into *ObjtSection,
) (
err error,
) {
for {
// if we've left the block, stop parsing
if !parser.token.Is(lexer.TokenKindIndent) { return }
if parser.token.Value().(int) != 1 { return }
// add member to object section
var member ObjtMember
member, err = parser.parseObjtMember()
into.members[member.name] = member
if err != nil { return }
}
}
// parseObjtMember parses a single member of an object section. Indentation
// level is assumed.
func (parser *ParsingOperation) parseObjtMember () (
member ObjtMember,
err error,
) {
// get permission
err = parser.nextToken(lexer.TokenKindPermission)
if err != nil { return }
member.permission = parser.token.Value().(types.Permission)
// get name
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
member.name = parser.token.Value().(string)
// get type
err = parser.nextToken(lexer.TokenKindColon)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
member.what, err = parser.parseType()
if err != nil { return }
// parse default value
if parser.token.Is(lexer.TokenKindNewline) {
err = parser.nextToken()
if err != nil { return }
member.defaultValue,
err = parser.parseInitializationValues(1)
if err != nil { return }
} else {
member.defaultValue, err = parser.parseArgument()
if err != nil { return }
err = parser.expect(lexer.TokenKindNewline)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
}
return
}

View File

@ -1,6 +1,7 @@
package parser
import "io"
import "strings"
import "testing"
// import "git.tebibyte.media/sashakoshka/arf/types"
@ -10,9 +11,9 @@ func checkTree (modulePath string, correct string, test *testing.T) {
treeRunes := []rune(treeString)
test.Log("CORRECT TREE:")
test.Log(correct)
logWithLineNumbers(correct, test)
test.Log("WHAT WAS PARSED:")
test.Log(treeString)
logWithLineNumbers(treeString, test)
if err != io.EOF && err != nil {
test.Log("returned error:")
@ -63,6 +64,15 @@ func checkTree (modulePath string, correct string, test *testing.T) {
}
}
func logWithLineNumbers (bigString string, test *testing.T) {
lines := strings.Split (
strings.Replace(bigString, "\t", " ", -1), "\n")
for index, line := range lines {
test.Logf("%3d | %s", index + 1, line)
}
}
func TestMeta (test *testing.T) {
checkTree ("../tests/parser/meta",
`:arf
@ -115,20 +125,6 @@ func TestType (test *testing.T) {
---
type ro Basic:Int
type ro BasicInit:Int 6
type ro Complex:Obj
ro that:Basic
ro this:Basic
type ro ComplexInit:Obj
ro that:BasicInit
ro this:Basic 23
type ro ComplexWithComplexInit:Obj
ro basic:Basic 87
ro complex0:Complex
.that 98
.this 2
ro complex1:Complex
.that 98902
.this 235
type ro IntArray:{Int ..}
type ro IntArrayInit:{Int 3}
3298
@ -137,3 +133,28 @@ type ro IntArrayInit:{Int 3}
`, test)
}
func TestObjt (test *testing.T) {
checkTree ("../tests/parser/objt",
`:arf
---
objt ro Basic:Obj
ro that:Basic
ro this:Basic
objt ro ComplexInit:Obj
ro basic:Int 87
ro complex0:Bird
.that 98
.this 2
ro complex1:Bird
.that 98902
.this 235
ro whatever:{Int 3}
230984
849
394580
objt ro Init:Obj
ro that:String "hello world"
ro this:Int 23
`, test)
}

View File

@ -51,6 +51,11 @@ func (tree *SyntaxTree) ToString (indent int) (output string) {
output += tree.typeSections[name].ToString(indent)
}
objtSectionKeys := sortMapKeysAlphabetically(tree.objtSections)
for _, name := range objtSectionKeys {
output += tree.objtSections[name].ToString(indent)
}
dataSectionKeys := sortMapKeysAlphabetically(tree.dataSections)
for _, name := range dataSectionKeys {
output += tree.dataSections[name].ToString(indent)
@ -253,39 +258,64 @@ func (section *DataSection) ToString (indent int) (output string) {
}
func (section *TypeSection) ToString (indent int) (output string) {
output += section.root.ToString(indent, true)
return
}
output += doIndent (
indent,
"type ",
section.permission.ToString(), " ",
section.name, ":",
section.inherits.ToString())
func (node TypeNode) ToString (indent int, isRoot bool) (output string) {
output += doIndent(indent)
if isRoot {
output += "type "
}
output += node.permission.ToString() + " "
output += node.name + ":"
output += node.what.ToString()
isComplexInitialization :=
node.defaultValue.kind == ArgumentKindObjectInitializationValues ||
node.defaultValue.kind == ArgumentKindArrayInitializationValues
if node.defaultValue.value == nil {
section.defaultValue.kind == ArgumentKindObjectInitializationValues ||
section.defaultValue.kind == ArgumentKindArrayInitializationValues
if section.defaultValue.value == nil {
output += "\n"
if len(node.children) > 0 {
for _, name := range sortMapKeysAlphabetically(node.children) {
child := node.children[name]
output += child.ToString(indent + 1, false)
}
}
} else if isComplexInitialization {
output += "\n"
output += node.defaultValue.ToString(indent + 1, true)
output += section.defaultValue.ToString(indent + 1, true)
} else {
output += " " + node.defaultValue.ToString(0, false)
output += "\n"
output += " " + section.defaultValue.ToString(0, false)
output += "\n"
}
return
}
func (member ObjtMember) ToString (indent int) (output string) {
output += doIndent(indent)
output += member.permission.ToString() + " "
output += member.name + ":"
output += member.what.ToString()
isComplexInitialization :=
member.defaultValue.kind == ArgumentKindObjectInitializationValues ||
member.defaultValue.kind == ArgumentKindArrayInitializationValues
if member.defaultValue.value == nil {
output += "\n"
} else if isComplexInitialization {
output += "\n"
output += member.defaultValue.ToString(indent + 1, true)
} else {
output += " " + member.defaultValue.ToString(0, false)
output += "\n"
}
return
}
func (section *ObjtSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"objt ",
section.permission.ToString(), " ",
section.name, ":",
section.inherits.ToString(), "\n")
for _, name := range sortMapKeysAlphabetically(section.members) {
output += section.members[name].ToString(indent + 1)
}
return
}

View File

@ -12,6 +12,7 @@ type SyntaxTree struct {
requires []string
typeSections map[string] *TypeSection
objtSections map[string] *ObjtSection
dataSections map[string] *DataSection
}
@ -161,19 +162,32 @@ type DataSection struct {
value Argument
}
// TypeNode represents a part of a type.
type TypeNode struct {
// TypeSection represents a blind type definition.
type TypeSection struct {
location file.Location
name string
inherits Type
permission types.Permission
defaultValue Argument
}
// ObjtMember represents a part of an object type definition.
type ObjtMember struct {
location file.Location
name string
what Type
permission types.Permission
defaultValue Argument
children map[string] TypeNode
}
// TypeSection represents a type definition.
type TypeSection struct {
// ObjtSection represents an object type definition
type ObjtSection struct {
location file.Location
root TypeNode
name string
inherits Type
permission types.Permission
members map[string] ObjtMember
}

View File

@ -2,9 +2,10 @@ package parser
import "git.tebibyte.media/sashakoshka/arf/types"
import "git.tebibyte.media/sashakoshka/arf/lexer"
import "git.tebibyte.media/sashakoshka/arf/infoerr"
// import "git.tebibyte.media/sashakoshka/arf/infoerr"
// parseTypeSection parses a type definition.
// parseTypeSection parses a blind type definition, meaning it can inherit from
// anything including primitives, but cannot define structure.
func (parser *ParsingOperation) parseTypeSection () (
section *TypeSection,
err error,
@ -14,50 +15,33 @@ func (parser *ParsingOperation) parseTypeSection () (
section = &TypeSection { location: parser.token.Location() }
// parse root node
err = parser.nextToken()
if err != nil { return }
section.root, err = parser.parseTypeNode(0)
return
}
// parseTypeNode parses a single type definition node recursively.
func (parser *ParsingOperation) parseTypeNode (
baseIndent int,
) (
node TypeNode,
err error,
) {
node.children = make(map[string] TypeNode)
// get permission
err = parser.expect(lexer.TokenKindPermission)
err = parser.nextToken(lexer.TokenKindPermission)
if err != nil { return }
node.permission = parser.token.Value().(types.Permission)
section.permission = parser.token.Value().(types.Permission)
// get name
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
node.name = parser.token.Value().(string)
section.name = parser.token.Value().(string)
// get inherited type
// parse inherited type
err = parser.nextToken(lexer.TokenKindColon)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
node.what, err = parser.parseType()
section.inherits, err = parser.parseType()
if err != nil { return }
// get value, or child nodes
// parse default values
if parser.token.Is(lexer.TokenKindNewline) {
err = parser.nextToken()
if err != nil { return }
err = parser.parseTypeNodeBlock(baseIndent, &node)
section.defaultValue, err = parser.parseInitializationValues(0)
if err != nil { return }
} else {
node.defaultValue, err = parser.parseArgument()
section.defaultValue, err = parser.parseArgument()
if err != nil { return }
err = parser.expect(lexer.TokenKindNewline)
@ -67,101 +51,3 @@ func (parser *ParsingOperation) parseTypeNode (
}
return
}
// parseTypeNodeBlock starts on the line after a type node, and parses what
// could be either an array initialization, an object initialization, or more
// child nodes. It is similar to parseInitializationValues. If none of these
// things were found the parser stays at the beginning of the line and the
// method returns.
func (parser *ParsingOperation) parseTypeNodeBlock (
baseIndent int,
parent *TypeNode,
) (
err error,
) {
// check if line is indented one more than baseIndent
if !parser.token.Is(lexer.TokenKindIndent) { return }
if parser.token.Value().(int) != baseIndent + 1 { return }
thingLocation := parser.token.Location()
err = parser.nextToken()
if err != nil { return }
if parser.token.Is(lexer.TokenKindDot) {
// object initialization
parser.previousToken()
initializationArgument := Argument { location: thingLocation }
var initializationValues ObjectInitializationValues
initializationValues, err = parser.parseObjectInitializationValues()
initializationArgument.kind = ArgumentKindObjectInitializationValues
initializationArgument.value = &initializationValues
parent.defaultValue = initializationArgument
} else if parser.token.Is(lexer.TokenKindPermission) {
// child members
parser.previousToken()
err = parser.parseTypeNodeChildren(parent)
} else {
// array initialization
parser.previousToken()
initializationArgument := Argument { location: thingLocation }
var initializationValues ArrayInitializationValues
initializationValues, err = parser.parseArrayInitializationValues()
initializationArgument.kind = ArgumentKindArrayInitializationValues
initializationArgument.value = &initializationValues
parent.defaultValue = initializationArgument
}
return
}
// parseTypeNodeChildren parses child type nodes into a parent type node.
func (parser *ParsingOperation) parseTypeNodeChildren (
parent *TypeNode,
) (
err error,
) {
baseIndent := 0
begin := true
for {
// if there is no indent we can just stop parsing
if !parser.token.Is(lexer.TokenKindIndent) { break }
indent := parser.token.Value().(int)
if begin == true {
baseIndent = indent
begin = false
}
// do not parse any further if the indent has changed
if indent != baseIndent { break }
// move on to the beginning of the line, which must contain
// a type node
err = parser.nextToken()
if err != nil { return }
var child TypeNode
child, err = parser.parseTypeNode(baseIndent)
// if the member has already been listed, throw an error
_, exists := parent.children[child.name]
if exists {
err = parser.token.NewError (
"duplicate member \"" + child.name +
"\" in object member initialization",
infoerr.ErrorKindError)
return
}
// store in parent
parent.children[child.name] = child
}
return
}

View File

@ -0,0 +1,21 @@
:arf
---
objt ro Basic:Obj
ro that:Basic
ro this:Basic
objt ro Init:Obj
ro that:String "hello world"
ro this:Int 23
objt ro ComplexInit:Obj
ro whatever:{Int 3}
230984
849 394580
ro complex0:Bird
.that 98
.this 2
ro complex1:Bird
.that 98902
.this 235
ro basic:Int 87

View File

@ -8,20 +8,3 @@ type ro IntArray:{Int ..}
type ro IntArrayInit:{Int 3}
3298 923 92
type ro Complex:Obj
ro that:Basic
ro this:Basic
type ro ComplexInit:Obj
ro that:BasicInit
ro this:Basic 23
type ro ComplexWithComplexInit:Obj
ro complex0:Complex
.that 98
.this 2
ro complex1:Complex
.that 98902
.this 235
ro basic:Basic 87