face-section #7
@ -9,7 +9,7 @@ data pv helloText:String "Hello, world!"
|
||||
|
||||
# this is a struct definition
|
||||
objt ro Greeter:Obj
|
||||
wr text:String "Hi."
|
||||
rw text:String "Hi."
|
||||
|
||||
# this is a function
|
||||
func ro main
|
||||
|
@ -39,6 +39,14 @@ func (parser *ParsingOperation) parseBody () (err error) {
|
||||
parser.tree.objtSections[section.name] = section
|
||||
if err != nil { return }
|
||||
case "face":
|
||||
var section *FaceSection
|
||||
section, err = parser.parseFaceSection()
|
||||
if parser.tree.faceSections == nil {
|
||||
parser.tree.faceSections =
|
||||
make(map[string] *FaceSection)
|
||||
}
|
||||
parser.tree.faceSections[section.name] = section
|
||||
if err != nil { return }
|
||||
case "enum":
|
||||
var section *EnumSection
|
||||
section, err = parser.parseEnumSection()
|
||||
|
132
parser/face.go
Normal file
132
parser/face.go
Normal file
@ -0,0 +1,132 @@
|
||||
package parser
|
||||
|
||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
||||
|
||||
// parseFaceSection parses an interface section.
|
||||
func (parser *ParsingOperation) parseFaceSection () (
|
||||
section *FaceSection,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
section = &FaceSection {
|
||||
location: parser.token.Location(),
|
||||
behaviors: make(map[string] FaceBehavior),
|
||||
}
|
||||
|
||||
// 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 interface
|
||||
err = parser.nextToken(lexer.TokenKindColon)
|
||||
if err != nil { return }
|
||||
err = parser.nextToken(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
section.inherits = parser.token.Value().(string)
|
||||
if err != nil { return }
|
||||
err = parser.nextToken(lexer.TokenKindNewline)
|
||||
if err != nil { return }
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
|
||||
// parse members
|
||||
for {
|
||||
// if we've left the block, stop parsing
|
||||
if !parser.token.Is(lexer.TokenKindIndent) { return }
|
||||
if parser.token.Value().(int) != 1 { return }
|
||||
|
||||
// parse behavior
|
||||
behaviorBeginning := parser.token.Location()
|
||||
var behavior FaceBehavior
|
||||
behavior, err = parser.parseFaceBehavior()
|
||||
|
||||
// add to section
|
||||
_, exists := section.behaviors[behavior.name]
|
||||
if exists {
|
||||
err = infoerr.NewError (
|
||||
behaviorBeginning,
|
||||
"multiple behaviors named " + behavior.name +
|
||||
" in this interface",
|
||||
infoerr.ErrorKindError)
|
||||
return
|
||||
}
|
||||
section.behaviors[behavior.name] = behavior
|
||||
|
||||
if err != nil { return }
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// parseFaceBehavior parses a single interface behavior. Indentation level is
|
||||
// assumed.
|
||||
func (parser *ParsingOperation) parseFaceBehavior () (
|
||||
behavior FaceBehavior,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindIndent)
|
||||
if err != nil { return }
|
||||
|
||||
// get name
|
||||
err = parser.nextToken(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
behavior.name = parser.token.Value().(string)
|
||||
|
||||
err = parser.nextToken(lexer.TokenKindNewline)
|
||||
if err != nil { return }
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
|
||||
for {
|
||||
// if we've left the block, stop parsing
|
||||
if !parser.token.Is(lexer.TokenKindIndent) { return }
|
||||
if parser.token.Value().(int) != 2 { return }
|
||||
|
||||
// get preceding symbol
|
||||
err = parser.nextToken (
|
||||
lexer.TokenKindGreaterThan,
|
||||
lexer.TokenKindLessThan)
|
||||
if err != nil { return }
|
||||
kind := parser.token.Kind()
|
||||
|
||||
var declaration Declaration
|
||||
|
||||
// get name
|
||||
err = parser.nextToken(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
declaration.name = parser.token.Value().(string)
|
||||
|
||||
// parse inherited type
|
||||
err = parser.nextToken(lexer.TokenKindColon)
|
||||
if err != nil { return }
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
declaration.what, err = parser.parseType()
|
||||
if err != nil { return }
|
||||
err = parser.expect(lexer.TokenKindNewline)
|
||||
if err != nil { return }
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
|
||||
if kind == lexer.TokenKindGreaterThan {
|
||||
behavior.inputs = append (
|
||||
behavior.inputs,
|
||||
declaration)
|
||||
} else {
|
||||
behavior.outputs = append (
|
||||
behavior.outputs,
|
||||
declaration)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -192,3 +192,21 @@ enum ro Weekday:Int
|
||||
wednesday
|
||||
`, test)
|
||||
}
|
||||
|
||||
func Test (test *testing.T) {
|
||||
checkTree ("../tests/parser/face",
|
||||
`:arf
|
||||
---
|
||||
face ro Destroyer:Face
|
||||
destroy
|
||||
face ro ReadWriter:Face
|
||||
read
|
||||
> into:{Byte ..}
|
||||
< read:Int
|
||||
< err:Error
|
||||
write
|
||||
> data:{Byte ..}
|
||||
< wrote:Int
|
||||
< err:Error
|
||||
`, test)
|
||||
}
|
||||
|
@ -61,6 +61,11 @@ func (tree *SyntaxTree) ToString (indent int) (output string) {
|
||||
output += tree.enumSections[name].ToString(indent)
|
||||
}
|
||||
|
||||
faceSectionKeys := sortMapKeysAlphabetically(tree.faceSections)
|
||||
for _, name := range faceSectionKeys {
|
||||
output += tree.faceSections[name].ToString(indent)
|
||||
}
|
||||
|
||||
dataSectionKeys := sortMapKeysAlphabetically(tree.dataSections)
|
||||
for _, name := range dataSectionKeys {
|
||||
output += tree.dataSections[name].ToString(indent)
|
||||
@ -353,3 +358,32 @@ func (section *EnumSection) ToString (indent int) (output string) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (section *FaceSection) ToString (indent int) (output string) {
|
||||
output += doIndent (
|
||||
indent,
|
||||
"face ",
|
||||
section.permission.ToString(), " ",
|
||||
section.name, ":",
|
||||
section.inherits, "\n")
|
||||
|
||||
for _, name := range sortMapKeysAlphabetically(section.behaviors) {
|
||||
behavior := section.behaviors[name]
|
||||
output += behavior.ToString(indent + 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (behavior *FaceBehavior) ToString (indent int) (output string) {
|
||||
output += doIndent(indent, behavior.name, "\n")
|
||||
|
||||
for _, inputItem := range behavior.inputs {
|
||||
output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n")
|
||||
}
|
||||
|
||||
for _, outputItem := range behavior.outputs {
|
||||
output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ type SyntaxTree struct {
|
||||
typeSections map[string] *TypeSection
|
||||
objtSections map[string] *ObjtSection
|
||||
enumSections map[string] *EnumSection
|
||||
faceSections map[string] *FaceSection
|
||||
dataSections map[string] *DataSection
|
||||
}
|
||||
|
||||
@ -203,3 +204,22 @@ type EnumSection struct {
|
||||
// TODO: order matters here we need to store these in an array
|
||||
members map[string] Argument
|
||||
}
|
||||
|
||||
// FaceBehavior represents a behavior of an interface section.
|
||||
type FaceBehavior struct {
|
||||
location file.Location
|
||||
name string
|
||||
|
||||
inputs []Declaration
|
||||
outputs []Declaration
|
||||
}
|
||||
|
||||
// FaceSection represents an interface type section.
|
||||
type FaceSection struct {
|
||||
location file.Location
|
||||
name string
|
||||
inherits string
|
||||
|
||||
permission types.Permission
|
||||
behaviors map[string] FaceBehavior
|
||||
}
|
||||
|
15
tests/parser/face/main.arf
Normal file
15
tests/parser/face/main.arf
Normal file
@ -0,0 +1,15 @@
|
||||
:arf
|
||||
---
|
||||
|
||||
face ro ReadWriter:Face
|
||||
write
|
||||
> data:{Byte ..}
|
||||
< wrote:Int
|
||||
< err:Error
|
||||
read
|
||||
> into:{Byte ..}
|
||||
< read:Int
|
||||
< err:Error
|
||||
|
||||
face ro Destroyer:Face
|
||||
destroy
|
Reference in New Issue
Block a user