From 2ceb3f817433c62ef625915095905d7c2da33a5a Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Thu, 29 Sep 2022 15:45:25 -0400 Subject: [PATCH] Interfaces get parsed properly (i think) --- parser/face.go | 88 ++++++++++++++++++++++++++++---------- parser/face_test.go | 14 +++--- parser/tree.go | 14 +++++- tests/parser/face/main.arf | 2 +- 4 files changed, 87 insertions(+), 31 deletions(-) diff --git a/parser/face.go b/parser/face.go index 62f2605..776f198 100644 --- a/parser/face.go +++ b/parser/face.go @@ -12,8 +12,7 @@ func (parser *ParsingOperation) parseFaceSection () ( err = parser.expect(lexer.TokenKindName) if err != nil { return } - section.behaviors = make(map[string] FaceBehavior) - section.location = parser.token.Location() + section.location = parser.token.Location() // get permission err = parser.nextToken(lexer.TokenKindPermission) @@ -32,24 +31,59 @@ func (parser *ParsingOperation) parseFaceSection () ( if err != nil { return } section.inherits, err = parser.parseIdentifier() if err != nil { return } - err = parser.nextToken(lexer.TokenKindNewline) + err = parser.expect(lexer.TokenKindNewline) if err != nil { return } err = parser.nextToken() if err != nil { return } + + if !parser.token.Is(lexer.TokenKindIndent) { return } + if parser.token.Value().(int) != 1 { return } + err = parser.nextToken ( + lexer.TokenKindName, + lexer.TokenKindGreaterThan, + lexer.TokenKindLessThan) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindName) { + // parse type interface + parser.previousToken() + section.behaviors, err = parser.parseFaceBehaviors() + if err != nil { return } + } else { + // parse function interface + parser.previousToken() + section.inputs, + section.outputs, err = parser.parseFaceBehaviorArguments(1) + if err != nil { return } + } + + return +} + +// parseFaceBehaviors parses a list of interface behaviors for an object +// interface. +func (parser *ParsingOperation) parseFaceBehaviors () ( + behaviors map[string] FaceBehavior, + err error, +) { // parse members + behaviors = make(map[string] FaceBehavior) for { // if we've left the block, stop parsing if !parser.token.Is(lexer.TokenKindIndent) { return } if parser.token.Value().(int) != 1 { return } + + err = parser.nextToken(lexer.TokenKindName) + behaviorBeginning := parser.token.Location() + if err != nil { return } // parse behavior - behaviorBeginning := parser.token.Location() var behavior FaceBehavior - behavior, err = parser.parseFaceBehavior() + behavior, err = parser.parseFaceBehavior(1) // add to section - _, exists := section.behaviors[behavior.name] + _, exists := behaviors[behavior.name] if exists { err = infoerr.NewError ( behaviorBeginning, @@ -58,23 +92,21 @@ func (parser *ParsingOperation) parseFaceSection () ( infoerr.ErrorKindError) return } - section.behaviors[behavior.name] = behavior + behaviors[behavior.name] = behavior if err != nil { return } } } -// parseFaceBehavior parses a single interface behavior. Indentation level is -// assumed. -func (parser *ParsingOperation) parseFaceBehavior () ( +// parseFaceBehavior parses a single interface behavior. +func (parser *ParsingOperation) parseFaceBehavior ( + indent int, +) ( behavior FaceBehavior, err error, ) { - err = parser.expect(lexer.TokenKindIndent) - if err != nil { return } - // get name - err = parser.nextToken(lexer.TokenKindName) + err = parser.expect(lexer.TokenKindName) if err != nil { return } behavior.name = parser.token.Value().(string) @@ -82,11 +114,27 @@ func (parser *ParsingOperation) parseFaceBehavior () ( if err != nil { return } err = parser.nextToken() if err != nil { return } + + behavior.inputs, + behavior.outputs, + err = parser.parseFaceBehaviorArguments(indent + 1) + if err != nil { return } + + return +} + +func (parser *ParsingOperation) parseFaceBehaviorArguments ( + indent int, +) ( + inputs []Declaration, + outputs []Declaration, + err error, +) { for { - // if we've left the block, stop parsing + // if we've left the behavior, stop parsing if !parser.token.Is(lexer.TokenKindIndent) { return } - if parser.token.Value().(int) != 2 { return } + if parser.token.Value().(int) != indent { return } // get preceding symbol err = parser.nextToken ( @@ -115,13 +163,9 @@ func (parser *ParsingOperation) parseFaceBehavior () ( if err != nil { return } if kind == lexer.TokenKindGreaterThan { - behavior.inputs = append ( - behavior.inputs, - declaration) + inputs = append(inputs, declaration) } else { - behavior.outputs = append ( - behavior.outputs, - declaration) + outputs = append(outputs, declaration) } } } diff --git a/parser/face_test.go b/parser/face_test.go index a7b8b4b..ff38360 100644 --- a/parser/face_test.go +++ b/parser/face_test.go @@ -6,18 +6,18 @@ func TestFace (test *testing.T) { checkTree ("../tests/parser/face", false, `:arf --- -face ro ReadWriter:Face - write - > data:{Byte ..} - < wrote:Int - < err:Error +face ro aReadWriter:Face read > into:{Byte ..} < read:Int < err:Error -face ro Destroyer:Face + write + > data:{Byte ..} + < wrote:Int + < err:Error +face ro bDestroyer:Face destroy -face ro cFuncInterface +face ro cFuncInterface:Func > something:Int < someOutput:Int < otherOutput:String diff --git a/parser/tree.go b/parser/tree.go index c89b899..35eb8fd 100644 --- a/parser/tree.go +++ b/parser/tree.go @@ -191,6 +191,15 @@ type EnumSection struct { members []EnumMember } +// FaceKind determines if an interface is a type interface or an function +// interface. +type FaceKind int + +const ( + FaceKindType FaceKind = iota + FaceKindFunc +) + // FaceBehavior represents a behavior of an interface section. type FaceBehavior struct { locatable @@ -206,8 +215,11 @@ type FaceSection struct { nameable permissionable inherits Identifier - + + kind FaceKind + behaviors map[string] FaceBehavior + FaceBehavior } // PhraseKind determines what semantic role a phrase plays. diff --git a/tests/parser/face/main.arf b/tests/parser/face/main.arf index ab00e62..0a39686 100644 --- a/tests/parser/face/main.arf +++ b/tests/parser/face/main.arf @@ -14,7 +14,7 @@ face ro aReadWriter:Face face ro bDestroyer:Face destroy -face ro cFuncInterface +face ro cFuncInterface:Func > something:Int < someOutput:Int < otherOutput:String