Merge pull request 'func-section' (#1) from func-section into main
Reviewed-on: arf/arf#1
This commit is contained in:
commit
845c12c78b
@ -2,7 +2,7 @@ package arfc
|
|||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "git.tebibyte.media/sashakoshka/arf"
|
import "git.tebibyte.media/arf/arf"
|
||||||
|
|
||||||
func main () {
|
func main () {
|
||||||
if len(os.Args) != 2 {
|
if len(os.Args) != 2 {
|
||||||
|
21
face_test.go
21
face_test.go
@ -1,21 +0,0 @@
|
|||||||
package parser
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestFace (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)
|
|
||||||
}
|
|
2
go.mod
2
go.mod
@ -1,3 +1,3 @@
|
|||||||
module git.tebibyte.media/sashakoshka/arf
|
module git.tebibyte.media/arf/arf
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
@ -2,7 +2,7 @@ package infoerr
|
|||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
import "git.tebibyte.media/arf/arf/file"
|
||||||
|
|
||||||
type ErrorKind int
|
type ErrorKind int
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
import "git.tebibyte.media/arf/arf/file"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// LexingOperation holds information about an ongoing lexing operataion.
|
// LexingOperation holds information about an ongoing lexing operataion.
|
||||||
type LexingOperation struct {
|
type LexingOperation struct {
|
||||||
@ -253,14 +253,26 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
case '%':
|
case '%':
|
||||||
token := lexer.newToken()
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindPercent
|
|
||||||
lexer.addToken(token)
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
|
if err != nil { return }
|
||||||
|
token.kind = TokenKindPercent
|
||||||
|
if lexer.char == '=' {
|
||||||
|
token.kind = TokenKindPercentAssignment
|
||||||
|
err = lexer.nextRune()
|
||||||
|
token.location.SetWidth(2)
|
||||||
|
}
|
||||||
|
lexer.addToken(token)
|
||||||
case '~':
|
case '~':
|
||||||
token := lexer.newToken()
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindTilde
|
|
||||||
lexer.addToken(token)
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
|
if err != nil { return }
|
||||||
|
token.kind = TokenKindTilde
|
||||||
|
if lexer.char == '=' {
|
||||||
|
token.kind = TokenKindTildeAssignment
|
||||||
|
err = lexer.nextRune()
|
||||||
|
token.location.SetWidth(2)
|
||||||
|
}
|
||||||
|
lexer.addToken(token)
|
||||||
case '=':
|
case '=':
|
||||||
token := lexer.newToken()
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindEqualTo
|
token.kind = TokenKindEqualTo
|
||||||
@ -275,6 +287,11 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
token.kind = TokenKindLShift
|
token.kind = TokenKindLShift
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
token.location.SetWidth(2)
|
token.location.SetWidth(2)
|
||||||
|
if lexer.char == '=' {
|
||||||
|
token.kind = TokenKindLShiftAssignment
|
||||||
|
err = lexer.nextRune()
|
||||||
|
token.location.SetWidth(3)
|
||||||
|
}
|
||||||
} else if lexer.char == '=' {
|
} else if lexer.char == '=' {
|
||||||
token.kind = TokenKindLessThanEqualTo
|
token.kind = TokenKindLessThanEqualTo
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
@ -290,6 +307,11 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
token.kind = TokenKindRShift
|
token.kind = TokenKindRShift
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
token.location.SetWidth(2)
|
token.location.SetWidth(2)
|
||||||
|
if lexer.char == '=' {
|
||||||
|
token.kind = TokenKindRShiftAssignment
|
||||||
|
err = lexer.nextRune()
|
||||||
|
token.location.SetWidth(3)
|
||||||
|
}
|
||||||
} else if lexer.char == '=' {
|
} else if lexer.char == '=' {
|
||||||
token.kind = TokenKindGreaterThanEqualTo
|
token.kind = TokenKindGreaterThanEqualTo
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
@ -305,6 +327,10 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
token.kind = TokenKindLogicalOr
|
token.kind = TokenKindLogicalOr
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
token.location.SetWidth(2)
|
token.location.SetWidth(2)
|
||||||
|
} else if lexer.char == '=' {
|
||||||
|
token.kind = TokenKindBinaryOrAssignment
|
||||||
|
err = lexer.nextRune()
|
||||||
|
token.location.SetWidth(2)
|
||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
case '&':
|
case '&':
|
||||||
@ -316,6 +342,21 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
token.kind = TokenKindLogicalAnd
|
token.kind = TokenKindLogicalAnd
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
token.location.SetWidth(2)
|
token.location.SetWidth(2)
|
||||||
|
} else if lexer.char == '=' {
|
||||||
|
token.kind = TokenKindBinaryAndAssignment
|
||||||
|
err = lexer.nextRune()
|
||||||
|
token.location.SetWidth(2)
|
||||||
|
}
|
||||||
|
lexer.addToken(token)
|
||||||
|
case '^':
|
||||||
|
token := lexer.newToken()
|
||||||
|
err = lexer.nextRune()
|
||||||
|
if err != nil { return }
|
||||||
|
token.kind = TokenKindBinaryXor
|
||||||
|
if lexer.char == '=' {
|
||||||
|
token.kind = TokenKindBinaryXorAssignment
|
||||||
|
err = lexer.nextRune()
|
||||||
|
token.location.SetWidth(2)
|
||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
default:
|
default:
|
||||||
@ -331,11 +372,11 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (lexer *LexingOperation) tokenizeDashBeginning () (err error) {
|
func (lexer *LexingOperation) tokenizeDashBeginning () (err error) {
|
||||||
|
token := lexer.newToken()
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
|
||||||
if lexer.char == '-' {
|
if lexer.char == '-' {
|
||||||
token := lexer.newToken()
|
|
||||||
token.kind = TokenKindDecrement
|
token.kind = TokenKindDecrement
|
||||||
token.location.SetWidth(2)
|
token.location.SetWidth(2)
|
||||||
|
|
||||||
@ -349,18 +390,16 @@ func (lexer *LexingOperation) tokenizeDashBeginning () (err error) {
|
|||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
} else if lexer.char == '>' {
|
} else if lexer.char == '>' {
|
||||||
token := lexer.newToken()
|
|
||||||
token.kind = TokenKindReturnDirection
|
token.kind = TokenKindReturnDirection
|
||||||
token.location.SetWidth(2)
|
token.location.SetWidth(2)
|
||||||
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
} else if lexer.char >= '0' && lexer.char <= '9' {
|
} else if lexer.char >= '0' && lexer.char <= '9' {
|
||||||
lexer.tokenizeNumberBeginning(true)
|
lexer.tokenizeNumberBeginning(true)
|
||||||
} else {
|
} else {
|
||||||
token := lexer.newToken()
|
|
||||||
token.kind = TokenKindMinus
|
token.kind = TokenKindMinus
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
import "git.tebibyte.media/arf/arf/file"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
func quickToken (width int, kind TokenKind, value any) (token Token) {
|
func quickToken (width int, kind TokenKind, value any) (token Token) {
|
||||||
token.location.SetWidth(width)
|
token.location.SetWidth(width)
|
||||||
@ -152,19 +152,27 @@ func TestTokenizeAll (test *testing.T) {
|
|||||||
quickToken(1, TokenKindAt, nil),
|
quickToken(1, TokenKindAt, nil),
|
||||||
quickToken(1, TokenKindExclamation, nil),
|
quickToken(1, TokenKindExclamation, nil),
|
||||||
quickToken(1, TokenKindPercent, nil),
|
quickToken(1, TokenKindPercent, nil),
|
||||||
|
quickToken(2, TokenKindPercentAssignment, nil),
|
||||||
quickToken(1, TokenKindTilde, nil),
|
quickToken(1, TokenKindTilde, nil),
|
||||||
|
quickToken(2, TokenKindTildeAssignment, nil),
|
||||||
quickToken(1, TokenKindEqualTo, nil),
|
quickToken(1, TokenKindEqualTo, nil),
|
||||||
quickToken(2, TokenKindNotEqualTo, nil),
|
quickToken(2, TokenKindNotEqualTo, nil),
|
||||||
quickToken(1, TokenKindLessThan, nil),
|
quickToken(1, TokenKindLessThan, nil),
|
||||||
quickToken(2, TokenKindLessThanEqualTo, nil),
|
quickToken(2, TokenKindLessThanEqualTo, nil),
|
||||||
quickToken(2, TokenKindLShift, nil),
|
quickToken(2, TokenKindLShift, nil),
|
||||||
|
quickToken(3, TokenKindLShiftAssignment, nil),
|
||||||
quickToken(1, TokenKindGreaterThan, nil),
|
quickToken(1, TokenKindGreaterThan, nil),
|
||||||
quickToken(2, TokenKindGreaterThanEqualTo, nil),
|
quickToken(2, TokenKindGreaterThanEqualTo, nil),
|
||||||
quickToken(2, TokenKindRShift, nil),
|
quickToken(2, TokenKindRShift, nil),
|
||||||
|
quickToken(3, TokenKindRShiftAssignment, nil),
|
||||||
quickToken(1, TokenKindBinaryOr, nil),
|
quickToken(1, TokenKindBinaryOr, nil),
|
||||||
|
quickToken(2, TokenKindBinaryOrAssignment, nil),
|
||||||
quickToken(2, TokenKindLogicalOr, nil),
|
quickToken(2, TokenKindLogicalOr, nil),
|
||||||
quickToken(1, TokenKindBinaryAnd, nil),
|
quickToken(1, TokenKindBinaryAnd, nil),
|
||||||
|
quickToken(2, TokenKindBinaryAndAssignment, nil),
|
||||||
quickToken(2, TokenKindLogicalAnd, nil),
|
quickToken(2, TokenKindLogicalAnd, nil),
|
||||||
|
quickToken(1, TokenKindBinaryXor, nil),
|
||||||
|
quickToken(2, TokenKindBinaryXorAssignment, nil),
|
||||||
quickToken(1, TokenKindNewline, nil),
|
quickToken(1, TokenKindNewline, nil),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
import "strconv"
|
import "strconv"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// tokenizeSymbolBeginning lexes a token that starts with a number.
|
// tokenizeSymbolBeginning lexes a token that starts with a number.
|
||||||
func (lexer *LexingOperation) tokenizeNumberBeginning (negative bool) (err error) {
|
func (lexer *LexingOperation) tokenizeNumberBeginning (negative bool) (err error) {
|
||||||
@ -36,10 +36,17 @@ func (lexer *LexingOperation) tokenizeNumberBeginning (negative bool) (err error
|
|||||||
isFloat, amountRead,
|
isFloat, amountRead,
|
||||||
err = lexer.tokenizeNumber(10)
|
err = lexer.tokenizeNumber(10)
|
||||||
|
|
||||||
} else if lexer.char >= '0' && lexer.char <= '9' {
|
} else if lexer.char >= '0' && lexer.char <= '7' {
|
||||||
intNumber, floatNumber,
|
intNumber, floatNumber,
|
||||||
isFloat, amountRead,
|
isFloat, amountRead,
|
||||||
err = lexer.tokenizeNumber(8)
|
err = lexer.tokenizeNumber(8)
|
||||||
|
} else if lexer.char != ' ' { // a space should correctly
|
||||||
|
err = infoerr.NewError ( // terminate this
|
||||||
|
lexer.file.Location(1),
|
||||||
|
"unexpected rune '" + string(lexer.char) +
|
||||||
|
"' in integer literal",
|
||||||
|
infoerr.ErrorKindError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
intNumber, floatNumber,
|
intNumber, floatNumber,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
import "strconv"
|
import "strconv"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// tokenizeString tokenizes a string or rune literal.
|
// tokenizeString tokenizes a string or rune literal.
|
||||||
func (lexer *LexingOperation) tokenizeString (isRuneLiteral bool) (err error) {
|
func (lexer *LexingOperation) tokenizeString (isRuneLiteral bool) (err error) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
import "git.tebibyte.media/arf/arf/file"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// TokenKind is an enum represzenting what role a token has.
|
// TokenKind is an enum represzenting what role a token has.
|
||||||
type TokenKind int
|
type TokenKind int
|
||||||
@ -43,20 +43,28 @@ const (
|
|||||||
TokenKindAt
|
TokenKindAt
|
||||||
TokenKindExclamation
|
TokenKindExclamation
|
||||||
TokenKindPercent
|
TokenKindPercent
|
||||||
|
TokenKindPercentAssignment
|
||||||
TokenKindTilde
|
TokenKindTilde
|
||||||
|
TokenKindTildeAssignment
|
||||||
|
|
||||||
TokenKindEqualTo
|
TokenKindEqualTo
|
||||||
TokenKindNotEqualTo
|
TokenKindNotEqualTo
|
||||||
TokenKindLessThanEqualTo
|
TokenKindLessThanEqualTo
|
||||||
TokenKindLessThan
|
TokenKindLessThan
|
||||||
TokenKindLShift
|
TokenKindLShift
|
||||||
|
TokenKindLShiftAssignment
|
||||||
TokenKindGreaterThan
|
TokenKindGreaterThan
|
||||||
TokenKindGreaterThanEqualTo
|
TokenKindGreaterThanEqualTo
|
||||||
TokenKindRShift
|
TokenKindRShift
|
||||||
|
TokenKindRShiftAssignment
|
||||||
TokenKindBinaryOr
|
TokenKindBinaryOr
|
||||||
|
TokenKindBinaryOrAssignment
|
||||||
TokenKindLogicalOr
|
TokenKindLogicalOr
|
||||||
TokenKindBinaryAnd
|
TokenKindBinaryAnd
|
||||||
|
TokenKindBinaryAndAssignment
|
||||||
TokenKindLogicalAnd
|
TokenKindLogicalAnd
|
||||||
|
TokenKindBinaryXor
|
||||||
|
TokenKindBinaryXorAssignment
|
||||||
)
|
)
|
||||||
|
|
||||||
// Token represents a single token. It holds its location in the file, as well
|
// Token represents a single token. It holds its location in the file, as well
|
||||||
@ -67,6 +75,14 @@ type Token struct {
|
|||||||
value any
|
value any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewToken provides a way for a new token to be created by other modules for
|
||||||
|
// comparison purposes.
|
||||||
|
func NewToken (kind TokenKind, value any) (token Token) {
|
||||||
|
token.kind = kind
|
||||||
|
token.value = value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Kind returns the semantic role of the token.
|
// Kind returns the semantic role of the token.
|
||||||
func (token Token) Kind () (kind TokenKind) {
|
func (token Token) Kind () (kind TokenKind) {
|
||||||
return token.kind
|
return token.kind
|
||||||
@ -175,8 +191,12 @@ func (tokenKind TokenKind) Describe () (description string) {
|
|||||||
description = "Exclamation"
|
description = "Exclamation"
|
||||||
case TokenKindPercent:
|
case TokenKindPercent:
|
||||||
description = "Percent"
|
description = "Percent"
|
||||||
|
case TokenKindPercentAssignment:
|
||||||
|
description = "PercentAssignment"
|
||||||
case TokenKindTilde:
|
case TokenKindTilde:
|
||||||
description = "Tilde"
|
description = "Tilde"
|
||||||
|
case TokenKindTildeAssignment:
|
||||||
|
description = "TildeAssignment"
|
||||||
case TokenKindEqualTo:
|
case TokenKindEqualTo:
|
||||||
description = "EqualTo"
|
description = "EqualTo"
|
||||||
case TokenKindNotEqualTo:
|
case TokenKindNotEqualTo:
|
||||||
@ -187,20 +207,32 @@ func (tokenKind TokenKind) Describe () (description string) {
|
|||||||
description = "LessThanEqualTo"
|
description = "LessThanEqualTo"
|
||||||
case TokenKindLShift:
|
case TokenKindLShift:
|
||||||
description = "LShift"
|
description = "LShift"
|
||||||
|
case TokenKindLShiftAssignment:
|
||||||
|
description = "LShiftAssignment"
|
||||||
case TokenKindGreaterThan:
|
case TokenKindGreaterThan:
|
||||||
description = "GreaterThan"
|
description = "GreaterThan"
|
||||||
case TokenKindGreaterThanEqualTo:
|
case TokenKindGreaterThanEqualTo:
|
||||||
description = "GreaterThanEqualTo"
|
description = "GreaterThanEqualTo"
|
||||||
case TokenKindRShift:
|
case TokenKindRShift:
|
||||||
description = "RShift"
|
description = "RShift"
|
||||||
|
case TokenKindRShiftAssignment:
|
||||||
|
description = "RShiftAssignment"
|
||||||
case TokenKindBinaryOr:
|
case TokenKindBinaryOr:
|
||||||
description = "BinaryOr"
|
description = "BinaryOr"
|
||||||
|
case TokenKindBinaryOrAssignment:
|
||||||
|
description = "BinaryOrAssignment"
|
||||||
case TokenKindLogicalOr:
|
case TokenKindLogicalOr:
|
||||||
description = "LogicalOr"
|
description = "LogicalOr"
|
||||||
case TokenKindBinaryAnd:
|
case TokenKindBinaryAnd:
|
||||||
description = "BinaryAnd"
|
description = "BinaryAnd"
|
||||||
|
case TokenKindBinaryAndAssignment:
|
||||||
|
description = "BinaryAndAssignment"
|
||||||
case TokenKindLogicalAnd:
|
case TokenKindLogicalAnd:
|
||||||
description = "LogicalAnd"
|
description = "LogicalAnd"
|
||||||
|
case TokenKindBinaryXor:
|
||||||
|
description = "BinaryXor"
|
||||||
|
case TokenKindBinaryXorAssignment:
|
||||||
|
description = "BinaryXorAssignment"
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
9
main.go
9
main.go
@ -1,9 +0,0 @@
|
|||||||
package arf
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/parser"
|
|
||||||
|
|
||||||
func CompileModule (modulePath string, output io.Writer) (err error) {
|
|
||||||
_, err = parser.Parse(modulePath)
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
var validArgumentStartTokens = []lexer.TokenKind {
|
var validArgumentStartTokens = []lexer.TokenKind {
|
||||||
lexer.TokenKindName,
|
lexer.TokenKindName,
|
||||||
@ -12,7 +12,6 @@ var validArgumentStartTokens = []lexer.TokenKind {
|
|||||||
lexer.TokenKindString,
|
lexer.TokenKindString,
|
||||||
lexer.TokenKindRune,
|
lexer.TokenKindRune,
|
||||||
|
|
||||||
lexer.TokenKindLBrace,
|
|
||||||
lexer.TokenKindLBracket,
|
lexer.TokenKindLBracket,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +28,8 @@ func (parser *ParsingOperation) parseArgument () (argument Argument, err error)
|
|||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
|
||||||
if parser.token.Is(lexer.TokenKindColon) {
|
if parser.token.Is(lexer.TokenKindColon) {
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
var what Type
|
var what Type
|
||||||
what, err = parser.parseType()
|
what, err = parser.parseType()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
@ -77,9 +78,9 @@ func (parser *ParsingOperation) parseArgument () (argument Argument, err error)
|
|||||||
argument.value = parser.token.Value().(rune)
|
argument.value = parser.token.Value().(rune)
|
||||||
parser.nextToken()
|
parser.nextToken()
|
||||||
|
|
||||||
// case lexer.TokenKindLBrace:
|
case lexer.TokenKindLBracket:
|
||||||
|
argument.kind = ArgumentKindPhrase
|
||||||
// case lexer.TokenKindLBracket:
|
argument.value, err = parser.parseArgumentLevelPhrase()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic (
|
panic (
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// parse body parses the body of an arf file, after the metadata header.
|
// parse body parses the body of an arf file, after the metadata header.
|
||||||
func (parser *ParsingOperation) parseBody () (err error) {
|
func (parser *ParsingOperation) parseBody () (err error) {
|
||||||
@ -57,6 +57,14 @@ func (parser *ParsingOperation) parseBody () (err error) {
|
|||||||
parser.tree.enumSections[section.name] = section
|
parser.tree.enumSections[section.name] = section
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
case "func":
|
case "func":
|
||||||
|
var section *FuncSection
|
||||||
|
section, err = parser.parseFuncSection()
|
||||||
|
if parser.tree.funcSections == nil {
|
||||||
|
parser.tree.funcSections =
|
||||||
|
make(map[string] *FuncSection)
|
||||||
|
}
|
||||||
|
parser.tree.funcSections[section.name] = section
|
||||||
|
if err != nil { return }
|
||||||
default:
|
default:
|
||||||
err = parser.token.NewError (
|
err = parser.token.NewError (
|
||||||
"unknown section type \"" + sectionType + "\"",
|
"unknown section type \"" + sectionType + "\"",
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// parseData parses a data section.
|
// parseData parses a data section.
|
||||||
func (parser *ParsingOperation) parseDataSection () (
|
func (parser *ParsingOperation) parseDataSection () (
|
||||||
@ -73,7 +73,7 @@ func (parser *ParsingOperation) parseInitializationValues (
|
|||||||
var initializationValues ObjectInitializationValues
|
var initializationValues ObjectInitializationValues
|
||||||
initializationValues, err = parser.parseObjectInitializationValues()
|
initializationValues, err = parser.parseObjectInitializationValues()
|
||||||
initializationArgument.kind = ArgumentKindObjectInitializationValues
|
initializationArgument.kind = ArgumentKindObjectInitializationValues
|
||||||
initializationArgument.value = &initializationValues
|
initializationArgument.value = initializationValues
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ func (parser *ParsingOperation) parseInitializationValues (
|
|||||||
var initializationValues ArrayInitializationValues
|
var initializationValues ArrayInitializationValues
|
||||||
initializationValues, err = parser.parseArrayInitializationValues()
|
initializationValues, err = parser.parseArrayInitializationValues()
|
||||||
initializationArgument.kind = ArgumentKindArrayInitializationValues
|
initializationArgument.kind = ArgumentKindArrayInitializationValues
|
||||||
initializationArgument.value = &initializationValues
|
initializationArgument.value = initializationValues
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
func (parser *ParsingOperation) parseEnumSection () (
|
func (parser *ParsingOperation) parseEnumSection () (
|
||||||
section *EnumSection,
|
section *EnumSection,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// parseFaceSection parses an interface section.
|
// parseFaceSection parses an interface section.
|
||||||
func (parser *ParsingOperation) parseFaceSection () (
|
func (parser *ParsingOperation) parseFaceSection () (
|
||||||
@ -64,7 +64,6 @@ func (parser *ParsingOperation) parseFaceSection () (
|
|||||||
|
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFaceBehavior parses a single interface behavior. Indentation level is
|
// parseFaceBehavior parses a single interface behavior. Indentation level is
|
||||||
@ -127,6 +126,4 @@ func (parser *ParsingOperation) parseFaceBehavior () (
|
|||||||
declaration)
|
declaration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
205
parser/func.go
Normal file
205
parser/func.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
package parser
|
||||||
|
|
||||||
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
|
// parseFunc parses a function section.
|
||||||
|
func (parser *ParsingOperation) parseFuncSection () (
|
||||||
|
section *FuncSection,
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
err = parser.expect(lexer.TokenKindName)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
section = &FuncSection { location: parser.token.Location() }
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// get arguments
|
||||||
|
err = parser.nextToken(lexer.TokenKindNewline)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.parseFuncArguments(section)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
// check to see if the function is external
|
||||||
|
if !parser.token.Is(lexer.TokenKindIndent) { return }
|
||||||
|
if parser.token.Value().(int) != 1 { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
if parser.token.Is(lexer.TokenKindName) &&
|
||||||
|
parser.token.Value().(string) == "external" {
|
||||||
|
|
||||||
|
section.external = true
|
||||||
|
err = parser.nextToken(lexer.TokenKindNewline)
|
||||||
|
if err != nil { return }
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it isn't, backtrack to the start of the line
|
||||||
|
parser.previousToken()
|
||||||
|
|
||||||
|
// parse root block
|
||||||
|
section.root, err = parser.parseBlock(1)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
if len(section.root) == 0 {
|
||||||
|
infoerr.NewError (section.location,
|
||||||
|
"this function has nothing in it",
|
||||||
|
infoerr.ErrorKindWarn).Print()
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseFuncArguments parses a function's inputs, outputs, and reciever if that
|
||||||
|
// exists.
|
||||||
|
func (parser *ParsingOperation) parseFuncArguments (
|
||||||
|
into *FuncSection,
|
||||||
|
) (
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
for {
|
||||||
|
// if we've left the block, stop parsing
|
||||||
|
if !parser.token.Is(lexer.TokenKindIndent) ||
|
||||||
|
parser.token.Value().(int) != 1 {
|
||||||
|
|
||||||
|
if into.receiver != nil {
|
||||||
|
err = parser.token.NewError (
|
||||||
|
"func section terminated without a " +
|
||||||
|
"separator token",
|
||||||
|
infoerr.ErrorKindError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine whether this is an input, output, or the method
|
||||||
|
// reciever
|
||||||
|
err = parser.nextToken (
|
||||||
|
lexer.TokenKindAt,
|
||||||
|
lexer.TokenKindLessThan,
|
||||||
|
lexer.TokenKindGreaterThan,
|
||||||
|
lexer.TokenKindSeparator)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
startToken := parser.token
|
||||||
|
if parser.token.Is(lexer.TokenKindSeparator) {
|
||||||
|
// if we have encountered a separator, that means our
|
||||||
|
// work is done here.
|
||||||
|
err = parser.nextToken(lexer.TokenKindNewline)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch startToken.Kind() {
|
||||||
|
case lexer.TokenKindAt:
|
||||||
|
reciever := Declaration { }
|
||||||
|
reciever.location = parser.token.Location()
|
||||||
|
|
||||||
|
// get name
|
||||||
|
err = parser.nextToken(lexer.TokenKindName)
|
||||||
|
if err != nil { return }
|
||||||
|
reciever.name = parser.token.Value().(string)
|
||||||
|
|
||||||
|
// get type
|
||||||
|
err = parser.nextToken(lexer.TokenKindColon)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
reciever.what, err = parser.parseType()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
if into.receiver != nil {
|
||||||
|
err = startToken.NewError (
|
||||||
|
"cannot have more than one method " +
|
||||||
|
"receiver",
|
||||||
|
infoerr.ErrorKindError)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
into.receiver = &reciever
|
||||||
|
}
|
||||||
|
|
||||||
|
err = parser.expect(lexer.TokenKindNewline)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
case lexer.TokenKindGreaterThan:
|
||||||
|
input := Declaration { }
|
||||||
|
input.location = parser.token.Location()
|
||||||
|
|
||||||
|
// get name
|
||||||
|
err = parser.nextToken(lexer.TokenKindName)
|
||||||
|
if err != nil { return }
|
||||||
|
input.name = parser.token.Value().(string)
|
||||||
|
|
||||||
|
// get type
|
||||||
|
err = parser.nextToken(lexer.TokenKindColon)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
input.what, err = parser.parseType()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
into.inputs = append(into.inputs, input)
|
||||||
|
|
||||||
|
err = parser.expect(lexer.TokenKindNewline)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
case lexer.TokenKindLessThan:
|
||||||
|
output := FuncOutput { }
|
||||||
|
output.location = parser.token.Location()
|
||||||
|
|
||||||
|
// get name
|
||||||
|
err = parser.nextToken(lexer.TokenKindName)
|
||||||
|
if err != nil { return }
|
||||||
|
output.name = parser.token.Value().(string)
|
||||||
|
|
||||||
|
// get type
|
||||||
|
err = parser.nextToken(lexer.TokenKindColon)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
output.what, err = parser.parseType()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
// parse default value
|
||||||
|
if parser.token.Is(lexer.TokenKindNewline) {
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
output.defaultValue, err =
|
||||||
|
parser.parseInitializationValues(1)
|
||||||
|
into.outputs = append(into.outputs, output)
|
||||||
|
if err != nil { return }
|
||||||
|
} else {
|
||||||
|
output.defaultValue, err =
|
||||||
|
parser.parseArgument()
|
||||||
|
into.outputs = append(into.outputs, output)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
err = parser.expect(lexer.TokenKindNewline)
|
||||||
|
if err != nil { return }
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
parser/func_test.go
Normal file
119
parser/func_test.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package parser
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestFunc (test *testing.T) {
|
||||||
|
checkTree ("../tests/parser/func",
|
||||||
|
`:arf
|
||||||
|
---
|
||||||
|
func ro aBasicExternal
|
||||||
|
> someInput:Int:mut
|
||||||
|
< someOutput:Int 4
|
||||||
|
---
|
||||||
|
external
|
||||||
|
func ro bMethod
|
||||||
|
@ bird:{Bird}
|
||||||
|
> someInput:Int:mut
|
||||||
|
< someOutput:Int 4
|
||||||
|
---
|
||||||
|
external
|
||||||
|
func ro cBasicPhrases
|
||||||
|
---
|
||||||
|
[fn 329 983 7]
|
||||||
|
[fn 329 983 7]
|
||||||
|
[fn 329 983 57]
|
||||||
|
[fn [gn 329 983 57] 123]
|
||||||
|
func ro dArgumentTypes
|
||||||
|
---
|
||||||
|
[bird tree butterfly.wing "hello world" grass:{Int:mut 8}]
|
||||||
|
func ro eMath
|
||||||
|
> x:Int
|
||||||
|
> y:Int
|
||||||
|
< z:Int
|
||||||
|
---
|
||||||
|
[++ x]
|
||||||
|
[-- y]
|
||||||
|
[set z [+ [* 250 0] 98 x [/ 9832 y] 930]]
|
||||||
|
[! true]
|
||||||
|
[~ 1]
|
||||||
|
[~= x]
|
||||||
|
[% 873 32]
|
||||||
|
[= 5 5]
|
||||||
|
[!= 4 4]
|
||||||
|
[<= 4 98]
|
||||||
|
[< 4 98]
|
||||||
|
[<< 15 4]
|
||||||
|
[<<= x 4]
|
||||||
|
[>= 98 4]
|
||||||
|
[> 98 4]
|
||||||
|
[>> 240 4]
|
||||||
|
[>>= x 4]
|
||||||
|
[| 1 2]
|
||||||
|
[|= x 2]
|
||||||
|
[& 6 3]
|
||||||
|
[&= x 3]
|
||||||
|
[&& true true]
|
||||||
|
[|| true false]
|
||||||
|
func ro fReturnDirection
|
||||||
|
< err:Error
|
||||||
|
---
|
||||||
|
[someFunc 498 2980 90] -> thing:Int err
|
||||||
|
[otherFunc] -> thing err:Error
|
||||||
|
[fn 329 983 57] -> thing:Int err
|
||||||
|
func ro gControlFlow
|
||||||
|
---
|
||||||
|
[defer]
|
||||||
|
[something]
|
||||||
|
[otherThing]
|
||||||
|
[if condition]
|
||||||
|
[something]
|
||||||
|
[if condition]
|
||||||
|
[something]
|
||||||
|
[elseif]
|
||||||
|
[otherThing]
|
||||||
|
[else]
|
||||||
|
[finalThing]
|
||||||
|
[while [< x 432]]
|
||||||
|
[something]
|
||||||
|
[switch value]
|
||||||
|
[: 324]
|
||||||
|
[something]
|
||||||
|
[: 93284]
|
||||||
|
[otherThing]
|
||||||
|
[: 9128 34738 7328]
|
||||||
|
[multipleCases]
|
||||||
|
[:]
|
||||||
|
[defaultThing]
|
||||||
|
[for index:Size element:Int someArray]
|
||||||
|
[something]
|
||||||
|
[someNextThing]
|
||||||
|
[justMakingSureBlockParsingWorks]
|
||||||
|
[if condition]
|
||||||
|
[if condition]
|
||||||
|
[nestedThing]
|
||||||
|
[else]
|
||||||
|
[otherThing]
|
||||||
|
[else]
|
||||||
|
[if condition]
|
||||||
|
[nestedThing]
|
||||||
|
[else]
|
||||||
|
[otherThing]
|
||||||
|
func ro hSetPhrase
|
||||||
|
---
|
||||||
|
[set x:Int 3]
|
||||||
|
[set y:{Int} [loc x]]
|
||||||
|
[set z:{Int 8}]
|
||||||
|
398
|
||||||
|
9
|
||||||
|
2309
|
||||||
|
983
|
||||||
|
-2387
|
||||||
|
478
|
||||||
|
555
|
||||||
|
123
|
||||||
|
[set bird:Bird]
|
||||||
|
.that
|
||||||
|
.whenYou 99999
|
||||||
|
.this 324
|
||||||
|
`, test)
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// parseMeta parsese the metadata header at the top of an arf file.
|
// parseMeta parsese the metadata header at the top of an arf file.
|
||||||
func (parser *ParsingOperation) parseMeta () (err error) {
|
func (parser *ParsingOperation) parseMeta () (err error) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// parseObjtSection parses an object type definition. This allows for structured
|
// parseObjtSection parses an object type definition. This allows for structured
|
||||||
// types to be defined, and for member variables to be added and overridden.
|
// types to be defined, and for member variables to be added and overridden.
|
||||||
@ -94,8 +94,6 @@ func (parser *ParsingOperation) parseObjtMember () (
|
|||||||
member.what, err = parser.parseType()
|
member.what, err = parser.parseType()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
|
||||||
println(parser.token.Describe())
|
|
||||||
|
|
||||||
// if there is a bit width, get it
|
// if there is a bit width, get it
|
||||||
if parser.token.Is(lexer.TokenKindBinaryAnd) {
|
if parser.token.Is(lexer.TokenKindBinaryAnd) {
|
||||||
err = parser.nextToken(lexer.TokenKindUInt)
|
err = parser.nextToken(lexer.TokenKindUInt)
|
||||||
|
@ -3,9 +3,9 @@ package parser
|
|||||||
import "io"
|
import "io"
|
||||||
import "os"
|
import "os"
|
||||||
import "path/filepath"
|
import "path/filepath"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
import "git.tebibyte.media/arf/arf/file"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// ParsingOperation holds information about an ongoing parsing operation.
|
// ParsingOperation holds information about an ongoing parsing operation.
|
||||||
type ParsingOperation struct {
|
type ParsingOperation struct {
|
||||||
|
354
parser/phrase.go
Normal file
354
parser/phrase.go
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
package parser
|
||||||
|
|
||||||
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
|
|
||||||
|
// operatorTokens lists all symbolic tokens that can act as a command to a
|
||||||
|
// phrase.
|
||||||
|
var operatorTokens = []lexer.TokenKind {
|
||||||
|
lexer.TokenKindColon,
|
||||||
|
lexer.TokenKindPlus,
|
||||||
|
lexer.TokenKindMinus,
|
||||||
|
lexer.TokenKindIncrement,
|
||||||
|
lexer.TokenKindDecrement,
|
||||||
|
lexer.TokenKindAsterisk,
|
||||||
|
lexer.TokenKindSlash,
|
||||||
|
lexer.TokenKindExclamation,
|
||||||
|
lexer.TokenKindPercent,
|
||||||
|
lexer.TokenKindPercentAssignment,
|
||||||
|
lexer.TokenKindTilde,
|
||||||
|
lexer.TokenKindTildeAssignment,
|
||||||
|
lexer.TokenKindEqualTo,
|
||||||
|
lexer.TokenKindNotEqualTo,
|
||||||
|
lexer.TokenKindLessThanEqualTo,
|
||||||
|
lexer.TokenKindLessThan,
|
||||||
|
lexer.TokenKindLShift,
|
||||||
|
lexer.TokenKindLShiftAssignment,
|
||||||
|
lexer.TokenKindGreaterThan,
|
||||||
|
lexer.TokenKindGreaterThanEqualTo,
|
||||||
|
lexer.TokenKindRShift,
|
||||||
|
lexer.TokenKindRShiftAssignment,
|
||||||
|
lexer.TokenKindBinaryOr,
|
||||||
|
lexer.TokenKindBinaryOrAssignment,
|
||||||
|
lexer.TokenKindLogicalOr,
|
||||||
|
lexer.TokenKindBinaryAnd,
|
||||||
|
lexer.TokenKindBinaryAndAssignment,
|
||||||
|
lexer.TokenKindLogicalAnd,
|
||||||
|
lexer.TokenKindBinaryXor,
|
||||||
|
lexer.TokenKindBinaryXorAssignment,
|
||||||
|
}
|
||||||
|
|
||||||
|
// isTokenOperator returns whether or not the token is an operator token.
|
||||||
|
func isTokenOperator (token lexer.Token) (isOperator bool) {
|
||||||
|
for _, kind := range operatorTokens {
|
||||||
|
if token.Is(kind) {
|
||||||
|
isOperator = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// validPhraseStartTokens lists all tokens that are expected when parsing the
|
||||||
|
// first part of a phrase.
|
||||||
|
var validPhraseStartTokens = append (
|
||||||
|
operatorTokens,
|
||||||
|
lexer.TokenKindLBracket,
|
||||||
|
lexer.TokenKindName,
|
||||||
|
lexer.TokenKindString)
|
||||||
|
|
||||||
|
// validBlockLevelPhraseTokens lists all tokens that are expected when parsing
|
||||||
|
// a block level phrase.
|
||||||
|
var validBlockLevelPhraseTokens = append (
|
||||||
|
validArgumentStartTokens,
|
||||||
|
lexer.TokenKindNewline,
|
||||||
|
lexer.TokenKindReturnDirection)
|
||||||
|
|
||||||
|
// validDelimitedPhraseTokens is like validBlockLevelPhraseTokens, but it also
|
||||||
|
// includes a right brace token.
|
||||||
|
var validDelimitedPhraseTokens = append (
|
||||||
|
validArgumentStartTokens,
|
||||||
|
lexer.TokenKindNewline,
|
||||||
|
lexer.TokenKindIndent,
|
||||||
|
lexer.TokenKindRBracket,
|
||||||
|
lexer.TokenKindReturnDirection)
|
||||||
|
|
||||||
|
// controlFlowKinds contains a list of all phrase kinds that must have a block
|
||||||
|
// underneath them.
|
||||||
|
var controlFlowKinds = []PhraseKind {
|
||||||
|
PhraseKindIf,
|
||||||
|
PhraseKindElse,
|
||||||
|
PhraseKindElseIf,
|
||||||
|
PhraseKindFor,
|
||||||
|
PhraseKindWhile,
|
||||||
|
PhraseKindDefer,
|
||||||
|
PhraseKindCase,
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseBlock parses an indented block of phrases
|
||||||
|
func (parser *ParsingOperation) parseBlock (
|
||||||
|
indent int,
|
||||||
|
) (
|
||||||
|
block Block,
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
for {
|
||||||
|
// if we've left the block, stop parsing
|
||||||
|
if !parser.token.Is(lexer.TokenKindIndent) { return }
|
||||||
|
if parser.token.Value().(int) != indent { return }
|
||||||
|
|
||||||
|
var phrase Phrase
|
||||||
|
phrase, err = parser.parseBlockLevelPhrase(indent)
|
||||||
|
block = append(block, phrase)
|
||||||
|
if err != nil { return }
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseBlockLevelPhrase parses a phrase that is not being used as an argument
|
||||||
|
// to something else. This method is allowed to do things like parse return
|
||||||
|
// directions, and indented blocks beneath the phrase.
|
||||||
|
func (parser *ParsingOperation) parseBlockLevelPhrase (
|
||||||
|
indent int,
|
||||||
|
) (
|
||||||
|
phrase Phrase,
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
if !parser.token.Is(lexer.TokenKindIndent) { return }
|
||||||
|
if parser.token.Value().(int) != indent { return }
|
||||||
|
err = parser.nextToken(validPhraseStartTokens...)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
expectRightBracket := false
|
||||||
|
if parser.token.Is(lexer.TokenKindLBracket) {
|
||||||
|
expectRightBracket = true
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
}
|
||||||
|
|
||||||
|
// get command
|
||||||
|
err = parser.expect(validPhraseStartTokens...)
|
||||||
|
if err != nil { return }
|
||||||
|
phrase.command, phrase.kind, err = parser.parsePhraseCommand()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
for {
|
||||||
|
if expectRightBracket {
|
||||||
|
// delimited
|
||||||
|
// [someFunc arg1 arg2 arg3] -> someVariable
|
||||||
|
err = parser.expect(validDelimitedPhraseTokens...)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
if parser.token.Is(lexer.TokenKindRBracket) {
|
||||||
|
// this is an ending delimiter
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
break
|
||||||
|
|
||||||
|
} else if parser.token.Is(lexer.TokenKindNewline) {
|
||||||
|
// we are delimited, so we can safely skip
|
||||||
|
// newlines
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
continue
|
||||||
|
|
||||||
|
} else if parser.token.Is(lexer.TokenKindIndent) {
|
||||||
|
// we are delimited, so we can safely skip
|
||||||
|
// indents
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not delimited
|
||||||
|
// someFunc arg1 arg2 arg3 -> someVariable
|
||||||
|
err = parser.expect(validBlockLevelPhraseTokens...)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
if parser.token.Is(lexer.TokenKindReturnDirection) {
|
||||||
|
// we've reached a return direction, so that
|
||||||
|
// means this is the end of the phrase
|
||||||
|
break
|
||||||
|
} else if parser.token.Is(lexer.TokenKindNewline) {
|
||||||
|
// we've reached the end of the line, so that
|
||||||
|
// means this is the end of the phrase.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is an argument
|
||||||
|
var argument Argument
|
||||||
|
argument, err = parser.parseArgument()
|
||||||
|
phrase.arguments = append(phrase.arguments, argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect newline or return direction
|
||||||
|
err = parser.expect (
|
||||||
|
lexer.TokenKindNewline,
|
||||||
|
lexer.TokenKindReturnDirection)
|
||||||
|
if err != nil { return }
|
||||||
|
expectReturnDirection := parser.token.Is(lexer.TokenKindReturnDirection)
|
||||||
|
|
||||||
|
// if we have hit a return direction, parse it...
|
||||||
|
if expectReturnDirection {
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
for {
|
||||||
|
err = parser.expect (
|
||||||
|
lexer.TokenKindNewline,
|
||||||
|
lexer.TokenKindName)
|
||||||
|
if err != nil { return }
|
||||||
|
// ...until we hit a newline
|
||||||
|
if parser.token.Is(lexer.TokenKindNewline) { break }
|
||||||
|
|
||||||
|
var returnTo Argument
|
||||||
|
returnTo, err = parser.parseArgument()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
phrase.returnsTo = append(phrase.returnsTo, returnTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
// if this is a set phrase, parse initialization values under it
|
||||||
|
if phrase.kind == PhraseKindSet {
|
||||||
|
var values Argument
|
||||||
|
values, err = parser.parseInitializationValues(indent)
|
||||||
|
|
||||||
|
if values.kind != ArgumentKindNil {
|
||||||
|
phrase.arguments = append(phrase.arguments, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this is a control flow phrase, parse block under it
|
||||||
|
isControlFlow := false
|
||||||
|
for _, kind := range controlFlowKinds {
|
||||||
|
if phrase.kind == kind {
|
||||||
|
isControlFlow = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isControlFlow { return }
|
||||||
|
|
||||||
|
// if it is any of those, parse the block under it
|
||||||
|
phrase.block, err = parser.parseBlock(indent + 1)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseArgumentLevelPhrase parses a phrase that is being used as an argument to
|
||||||
|
// something. It is forbidden from using return direction, and it must be
|
||||||
|
// delimited by brackets.
|
||||||
|
func (parser *ParsingOperation) parseArgumentLevelPhrase () (
|
||||||
|
phrase Phrase,
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
err = parser.expect(lexer.TokenKindLBracket)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
// get command
|
||||||
|
err = parser.nextToken(validPhraseStartTokens...)
|
||||||
|
if err != nil { return }
|
||||||
|
phrase.command, phrase.kind, err = parser.parsePhraseCommand()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
for {
|
||||||
|
// delimited
|
||||||
|
// [someFunc arg1 arg2 arg3] -> someVariable
|
||||||
|
err = parser.expect(validDelimitedPhraseTokens...)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
if parser.token.Is(lexer.TokenKindRBracket) {
|
||||||
|
// this is an ending delimiter
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
return
|
||||||
|
|
||||||
|
} else if parser.token.Is(lexer.TokenKindNewline) {
|
||||||
|
// we are delimited, so we can safely skip
|
||||||
|
// newlines
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
continue
|
||||||
|
|
||||||
|
} else if parser.token.Is(lexer.TokenKindIndent) {
|
||||||
|
// we are delimited, so we can safely skip
|
||||||
|
// indents
|
||||||
|
err = parser.nextToken()
|
||||||
|
if err != nil { return }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is an argument
|
||||||
|
var argument Argument
|
||||||
|
argument, err = parser.parseArgument()
|
||||||
|
phrase.arguments = append(phrase.arguments, argument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePhraseCommand parses the command argument of a phrase.
|
||||||
|
func (parser *ParsingOperation) parsePhraseCommand () (
|
||||||
|
command Argument,
|
||||||
|
kind PhraseKind,
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
if isTokenOperator(parser.token) {
|
||||||
|
err = parser.expect(operatorTokens...)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
command.location = parser.token.Location()
|
||||||
|
command.kind = ArgumentKindOperator
|
||||||
|
command.value = parser.token.Kind()
|
||||||
|
|
||||||
|
if parser.token.Is(lexer.TokenKindColon) {
|
||||||
|
kind = PhraseKindCase
|
||||||
|
} else {
|
||||||
|
kind = PhraseKindOperator
|
||||||
|
}
|
||||||
|
|
||||||
|
err = parser.nextToken()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// phrase command is not an operator, it is just a normal argument
|
||||||
|
command, err = parser.parseArgument()
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
// determine semantic role of phrase
|
||||||
|
if command.kind == ArgumentKindString {
|
||||||
|
kind = PhraseKindCallExternal
|
||||||
|
|
||||||
|
} else if command.kind == ArgumentKindIdentifier {
|
||||||
|
identifier := command.value.(Identifier)
|
||||||
|
if len(identifier.trail) == 1 {
|
||||||
|
switch identifier.trail[0] {
|
||||||
|
case "set":
|
||||||
|
kind = PhraseKindSet
|
||||||
|
case "loc":
|
||||||
|
kind = PhraseKindReference
|
||||||
|
case "defer":
|
||||||
|
kind = PhraseKindDefer
|
||||||
|
case "if":
|
||||||
|
kind = PhraseKindIf
|
||||||
|
case "elseif":
|
||||||
|
kind = PhraseKindElseIf
|
||||||
|
case "else":
|
||||||
|
kind = PhraseKindElse
|
||||||
|
case "switch":
|
||||||
|
kind = PhraseKindSwitch
|
||||||
|
case "while":
|
||||||
|
kind = PhraseKindWhile
|
||||||
|
case "for":
|
||||||
|
kind = PhraseKindFor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -3,10 +3,20 @@ package parser
|
|||||||
import "io"
|
import "io"
|
||||||
import "strings"
|
import "strings"
|
||||||
import "testing"
|
import "testing"
|
||||||
// import "git.tebibyte.media/sashakoshka/arf/types"
|
// import "git.tebibyte.media/arf/arf/types"
|
||||||
|
|
||||||
func checkTree (modulePath string, correct string, test *testing.T) {
|
func checkTree (modulePath string, correct string, test *testing.T) {
|
||||||
tree, err := Parse(modulePath)
|
tree, err := Parse(modulePath)
|
||||||
|
if tree == nil {
|
||||||
|
test.Log("TREE IS NIL!")
|
||||||
|
if err != io.EOF && err != nil {
|
||||||
|
test.Log("returned error:")
|
||||||
|
test.Log(err)
|
||||||
|
}
|
||||||
|
test.Fail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
treeString := tree.ToString(0)
|
treeString := tree.ToString(0)
|
||||||
treeRunes := []rune(treeString)
|
treeRunes := []rune(treeString)
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package parser
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "sort"
|
import "sort"
|
||||||
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
|
|
||||||
func doIndent (indent int, input ...string) (output string) {
|
func doIndent (indent int, input ...string) (output string) {
|
||||||
for index := 0; index < indent; index ++ {
|
for index := 0; index < indent; index ++ {
|
||||||
@ -70,10 +71,15 @@ func (tree *SyntaxTree) ToString (indent int) (output string) {
|
|||||||
for _, name := range dataSectionKeys {
|
for _, name := range dataSectionKeys {
|
||||||
output += tree.dataSections[name].ToString(indent)
|
output += tree.dataSections[name].ToString(indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funcSectionKeys := sortMapKeysAlphabetically(tree.funcSections)
|
||||||
|
for _, name := range funcSectionKeys {
|
||||||
|
output += tree.funcSections[name].ToString(indent)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (identifier *Identifier) ToString () (output string) {
|
func (identifier Identifier) ToString () (output string) {
|
||||||
for index, trailItem := range identifier.trail {
|
for index, trailItem := range identifier.trail {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
output += "."
|
output += "."
|
||||||
@ -110,13 +116,13 @@ func (what *Type) ToString () (output string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (declaration *Declaration) ToString () (output string) {
|
func (declaration Declaration) ToString () (output string) {
|
||||||
output += declaration.name + ":"
|
output += declaration.name + ":"
|
||||||
output += declaration.what.ToString()
|
output += declaration.what.ToString()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (attributes *ObjectInitializationValues) ToString (
|
func (attributes ObjectInitializationValues) ToString (
|
||||||
indent int,
|
indent int,
|
||||||
) (
|
) (
|
||||||
output string,
|
output string,
|
||||||
@ -136,7 +142,7 @@ func (attributes *ObjectInitializationValues) ToString (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (values *ArrayInitializationValues) ToString (
|
func (values ArrayInitializationValues) ToString (
|
||||||
indent int,
|
indent int,
|
||||||
) (
|
) (
|
||||||
output string,
|
output string,
|
||||||
@ -148,39 +154,6 @@ func (values *ArrayInitializationValues) ToString (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (phrase *Phrase) ToString (indent int, breakLine bool) (output string) {
|
|
||||||
if breakLine {
|
|
||||||
output += doIndent (
|
|
||||||
indent,
|
|
||||||
"[", phrase.command.ToString(0, false))
|
|
||||||
output += "\n"
|
|
||||||
for _, argument := range phrase.arguments {
|
|
||||||
output += doIndent (
|
|
||||||
indent,
|
|
||||||
argument.ToString(indent + 1, true))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
output += "[" + phrase.command.ToString(0, false)
|
|
||||||
for _, argument := range phrase.arguments {
|
|
||||||
output += " " + argument.ToString(0, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output += "]"
|
|
||||||
|
|
||||||
if len(phrase.returnsTo) > 0 {
|
|
||||||
output += " ->"
|
|
||||||
for _, returnItem := range phrase.returnsTo {
|
|
||||||
output += " " + returnItem.ToString(0, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if breakLine {
|
|
||||||
output += "\n"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (argument *Argument) ToString (indent int, breakLine bool) (output string) {
|
func (argument *Argument) ToString (indent int, breakLine bool) (output string) {
|
||||||
if !breakLine { indent = 0 }
|
if !breakLine { indent = 0 }
|
||||||
if argument.kind == ArgumentKindNil {
|
if argument.kind == ArgumentKindNil {
|
||||||
@ -191,30 +164,30 @@ func (argument *Argument) ToString (indent int, breakLine bool) (output string)
|
|||||||
|
|
||||||
switch argument.kind {
|
switch argument.kind {
|
||||||
case ArgumentKindPhrase:
|
case ArgumentKindPhrase:
|
||||||
output += argument.value.(*Phrase).ToString (
|
output += argument.value.(Phrase).ToString (
|
||||||
indent,
|
indent,
|
||||||
breakLine)
|
breakLine)
|
||||||
|
|
||||||
case ArgumentKindObjectInitializationValues:
|
case ArgumentKindObjectInitializationValues:
|
||||||
// this should only appear in contexts where breakLine is true
|
// this should only appear in contexts where breakLine is true
|
||||||
output += argument.value.(*ObjectInitializationValues).
|
output += argument.value.(ObjectInitializationValues).
|
||||||
ToString(indent)
|
ToString(indent)
|
||||||
|
|
||||||
case ArgumentKindArrayInitializationValues:
|
case ArgumentKindArrayInitializationValues:
|
||||||
// this should only appear in contexts where breakLine is true
|
// this should only appear in contexts where breakLine is true
|
||||||
output += argument.value.(*ArrayInitializationValues).
|
output += argument.value.(ArrayInitializationValues).
|
||||||
ToString(indent)
|
ToString(indent)
|
||||||
|
|
||||||
case ArgumentKindIdentifier:
|
case ArgumentKindIdentifier:
|
||||||
output += doIndent (
|
output += doIndent (
|
||||||
indent,
|
indent,
|
||||||
argument.value.(*Identifier).ToString())
|
argument.value.(Identifier).ToString())
|
||||||
if breakLine { output += "\n" }
|
if breakLine { output += "\n" }
|
||||||
|
|
||||||
case ArgumentKindDeclaration:
|
case ArgumentKindDeclaration:
|
||||||
output += doIndent (
|
output += doIndent (
|
||||||
indent,
|
indent,
|
||||||
argument.value.(*Declaration).ToString())
|
argument.value.(Declaration).ToString())
|
||||||
if breakLine { output += "\n" }
|
if breakLine { output += "\n" }
|
||||||
|
|
||||||
case ArgumentKindInt, ArgumentKindUInt, ArgumentKindFloat:
|
case ArgumentKindInt, ArgumentKindUInt, ArgumentKindFloat:
|
||||||
@ -234,10 +207,71 @@ func (argument *Argument) ToString (indent int, breakLine bool) (output string)
|
|||||||
if breakLine { output += "\n" }
|
if breakLine { output += "\n" }
|
||||||
|
|
||||||
case ArgumentKindOperator:
|
case ArgumentKindOperator:
|
||||||
// TODO
|
var stringValue string
|
||||||
// also when parsing this argument kind, don't do it in the
|
switch argument.value.(lexer.TokenKind) {
|
||||||
// argument parsing function. do it specifically when parsing a
|
case lexer.TokenKindColon:
|
||||||
// phrase command.
|
stringValue = ":"
|
||||||
|
case lexer.TokenKindPlus:
|
||||||
|
stringValue = "+"
|
||||||
|
case lexer.TokenKindMinus:
|
||||||
|
stringValue = "-"
|
||||||
|
case lexer.TokenKindIncrement:
|
||||||
|
stringValue = "++"
|
||||||
|
case lexer.TokenKindDecrement:
|
||||||
|
stringValue = "--"
|
||||||
|
case lexer.TokenKindAsterisk:
|
||||||
|
stringValue = "*"
|
||||||
|
case lexer.TokenKindSlash:
|
||||||
|
stringValue = "/"
|
||||||
|
case lexer.TokenKindExclamation:
|
||||||
|
stringValue = "!"
|
||||||
|
case lexer.TokenKindPercent:
|
||||||
|
stringValue = "%"
|
||||||
|
case lexer.TokenKindPercentAssignment:
|
||||||
|
stringValue = "%="
|
||||||
|
case lexer.TokenKindTilde:
|
||||||
|
stringValue = "~"
|
||||||
|
case lexer.TokenKindTildeAssignment:
|
||||||
|
stringValue = "~="
|
||||||
|
case lexer.TokenKindEqualTo:
|
||||||
|
stringValue = "="
|
||||||
|
case lexer.TokenKindNotEqualTo:
|
||||||
|
stringValue = "!="
|
||||||
|
case lexer.TokenKindLessThanEqualTo:
|
||||||
|
stringValue = "<="
|
||||||
|
case lexer.TokenKindLessThan:
|
||||||
|
stringValue = "<"
|
||||||
|
case lexer.TokenKindLShift:
|
||||||
|
stringValue = "<<"
|
||||||
|
case lexer.TokenKindLShiftAssignment:
|
||||||
|
stringValue = "<<="
|
||||||
|
case lexer.TokenKindGreaterThan:
|
||||||
|
stringValue = ">"
|
||||||
|
case lexer.TokenKindGreaterThanEqualTo:
|
||||||
|
stringValue = ">="
|
||||||
|
case lexer.TokenKindRShift:
|
||||||
|
stringValue = ">>"
|
||||||
|
case lexer.TokenKindRShiftAssignment:
|
||||||
|
stringValue = ">>="
|
||||||
|
case lexer.TokenKindBinaryOr:
|
||||||
|
stringValue = "|"
|
||||||
|
case lexer.TokenKindBinaryOrAssignment:
|
||||||
|
stringValue = "|="
|
||||||
|
case lexer.TokenKindLogicalOr:
|
||||||
|
stringValue = "||"
|
||||||
|
case lexer.TokenKindBinaryAnd:
|
||||||
|
stringValue = "&"
|
||||||
|
case lexer.TokenKindBinaryAndAssignment:
|
||||||
|
stringValue = "&="
|
||||||
|
case lexer.TokenKindLogicalAnd:
|
||||||
|
stringValue = "&&"
|
||||||
|
case lexer.TokenKindBinaryXor:
|
||||||
|
stringValue = "^"
|
||||||
|
case lexer.TokenKindBinaryXorAssignment:
|
||||||
|
stringValue = "^="
|
||||||
|
}
|
||||||
|
output += doIndent(indent, stringValue)
|
||||||
|
if breakLine { output += "\n" }
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -389,3 +423,87 @@ func (behavior *FaceBehavior) ToString (indent int) (output string) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (phrase Phrase) ToString (indent int, ownLine bool) (output string) {
|
||||||
|
if ownLine {
|
||||||
|
output += doIndent(indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
var initializationValues Argument
|
||||||
|
|
||||||
|
output += "[" + phrase.command.ToString(0, false)
|
||||||
|
for _, argument := range phrase.arguments {
|
||||||
|
isInitializationValue :=
|
||||||
|
argument.kind == ArgumentKindObjectInitializationValues ||
|
||||||
|
argument.kind == ArgumentKindArrayInitializationValues
|
||||||
|
if isInitializationValue {
|
||||||
|
initializationValues = argument
|
||||||
|
} else {
|
||||||
|
output += " " + argument.ToString(0, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output += "]"
|
||||||
|
|
||||||
|
if len(phrase.returnsTo) > 0 {
|
||||||
|
output += " ->"
|
||||||
|
for _, returnItem := range phrase.returnsTo {
|
||||||
|
output += " " + returnItem.ToString(0, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ownLine {
|
||||||
|
output += "\n"
|
||||||
|
if initializationValues.kind != ArgumentKindNil {
|
||||||
|
output += initializationValues.ToString(indent + 1, true)
|
||||||
|
}
|
||||||
|
output += phrase.block.ToString(indent + 1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (block Block) ToString (indent int) (output string) {
|
||||||
|
for _, phrase := range block {
|
||||||
|
output += phrase.ToString(indent, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (funcOutput FuncOutput) ToString () (output string) {
|
||||||
|
output += funcOutput.Declaration.ToString()
|
||||||
|
if funcOutput.defaultValue.kind != ArgumentKindNil {
|
||||||
|
output += " " + funcOutput.defaultValue.ToString(0, false)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (section *FuncSection) ToString (indent int) (output string) {
|
||||||
|
output += doIndent (
|
||||||
|
indent,
|
||||||
|
"func ",
|
||||||
|
section.permission.ToString(), " ",
|
||||||
|
section.name, "\n")
|
||||||
|
|
||||||
|
if section.receiver != nil {
|
||||||
|
output += doIndent (
|
||||||
|
indent + 1,
|
||||||
|
"@ ", section.receiver.ToString(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, inputItem := range section.inputs {
|
||||||
|
output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, outputItem := range section.outputs {
|
||||||
|
output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
output += doIndent(indent + 1, "---\n")
|
||||||
|
|
||||||
|
if section.external {
|
||||||
|
output += doIndent(indent + 1, "external\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
output += section.root.ToString(indent + 1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
import "git.tebibyte.media/arf/arf/file"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
|
|
||||||
// SyntaxTree represents an abstract syntax tree. It covers an entire module. It
|
// SyntaxTree represents an abstract syntax tree. It covers an entire module. It
|
||||||
// can be expected to be syntactically correct, but it might not be semantically
|
// can be expected to be syntactically correct, but it might not be semantically
|
||||||
@ -16,6 +16,7 @@ type SyntaxTree struct {
|
|||||||
enumSections map[string] *EnumSection
|
enumSections map[string] *EnumSection
|
||||||
faceSections map[string] *FaceSection
|
faceSections map[string] *FaceSection
|
||||||
dataSections map[string] *DataSection
|
dataSections map[string] *DataSection
|
||||||
|
funcSections map[string] *FuncSection
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identifier represents a chain of arguments separated by a dot.
|
// Identifier represents a chain of arguments separated by a dot.
|
||||||
@ -78,15 +79,6 @@ type ArrayInitializationValues struct {
|
|||||||
values []Argument
|
values []Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phrase represents a function call or operator. In ARF they are the same
|
|
||||||
// syntactical concept.
|
|
||||||
type Phrase struct {
|
|
||||||
location file.Location
|
|
||||||
command Argument
|
|
||||||
arguments []Argument
|
|
||||||
returnsTo []Argument
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArgumentKind specifies the type of thing the value of an argument should be
|
// ArgumentKind specifies the type of thing the value of an argument should be
|
||||||
// cast to.
|
// cast to.
|
||||||
type ArgumentKind int
|
type ArgumentKind int
|
||||||
@ -97,7 +89,7 @@ const (
|
|||||||
// [name argument]
|
// [name argument]
|
||||||
// [name argument argument]
|
// [name argument argument]
|
||||||
// etc...
|
// etc...
|
||||||
ArgumentKindPhrase = iota
|
ArgumentKindPhrase
|
||||||
|
|
||||||
// {name}
|
// {name}
|
||||||
ArgumentKindDereference
|
ArgumentKindDereference
|
||||||
@ -185,7 +177,7 @@ type ObjtMember struct {
|
|||||||
defaultValue Argument
|
defaultValue Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjtSection represents an object type definition
|
// ObjtSection represents an object type definition.
|
||||||
type ObjtSection struct {
|
type ObjtSection struct {
|
||||||
location file.Location
|
location file.Location
|
||||||
name string
|
name string
|
||||||
@ -195,6 +187,7 @@ type ObjtSection struct {
|
|||||||
members []ObjtMember
|
members []ObjtMember
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnumMember represents a member of an enum section.
|
||||||
type EnumMember struct {
|
type EnumMember struct {
|
||||||
location file.Location
|
location file.Location
|
||||||
name string
|
name string
|
||||||
@ -229,3 +222,60 @@ type FaceSection struct {
|
|||||||
permission types.Permission
|
permission types.Permission
|
||||||
behaviors map[string] FaceBehavior
|
behaviors map[string] FaceBehavior
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PhraseKind determines what semantic role a phrase plays.
|
||||||
|
type PhraseKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
PhraseKindCall = iota
|
||||||
|
PhraseKindCallExternal
|
||||||
|
PhraseKindOperator
|
||||||
|
PhraseKindSet
|
||||||
|
PhraseKindReference
|
||||||
|
PhraseKindDefer
|
||||||
|
PhraseKindIf
|
||||||
|
PhraseKindElseIf
|
||||||
|
PhraseKindElse
|
||||||
|
PhraseKindSwitch
|
||||||
|
PhraseKindCase
|
||||||
|
PhraseKindWhile
|
||||||
|
PhraseKindFor
|
||||||
|
)
|
||||||
|
|
||||||
|
// Phrase represents a function call or operator. In ARF they are the same
|
||||||
|
// syntactical concept.
|
||||||
|
type Phrase struct {
|
||||||
|
location file.Location
|
||||||
|
command Argument
|
||||||
|
arguments []Argument
|
||||||
|
returnsTo []Argument
|
||||||
|
|
||||||
|
kind PhraseKind
|
||||||
|
|
||||||
|
// only applicable for control flow phrases
|
||||||
|
block Block
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block represents a scoped/indented block of code.
|
||||||
|
type Block []Phrase
|
||||||
|
|
||||||
|
// FuncOutput represents an input a function section. It is unlike an input in
|
||||||
|
// that it can have a default value.
|
||||||
|
type FuncOutput struct {
|
||||||
|
Declaration
|
||||||
|
defaultValue Argument
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncSection represents a function section.
|
||||||
|
type FuncSection struct {
|
||||||
|
location file.Location
|
||||||
|
name string
|
||||||
|
permission types.Permission
|
||||||
|
|
||||||
|
receiver *Declaration
|
||||||
|
inputs []Declaration
|
||||||
|
outputs []FuncOutput
|
||||||
|
root Block
|
||||||
|
|
||||||
|
external bool
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/arf/arf/lexer"
|
||||||
// import "git.tebibyte.media/sashakoshka/arf/infoerr"
|
// import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
// parseTypeSection parses a blind type definition, meaning it can inherit from
|
// parseTypeSection parses a blind type definition, meaning it can inherit from
|
||||||
// anything including primitives, but cannot define structure.
|
// anything including primitives, but cannot define structure.
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
:arf
|
:arf
|
||||||
--- rw -> -349820394 932748397 239485.37520 "hello world!\n" 'E' helloWorld:.,..[]{}
|
--- rw -> -349820394 932748397 239485.37520 "hello world!\n" 'E' helloWorld:.,..[]{}
|
||||||
+ - ++ -- * / @ ! % ~ = != < <= << > >= >> | || & &&
|
+ - ++ -- * / @ ! % %= ~ ~= = != < <= << <<= > >= >> >>= | |= || & &= && ^ ^=
|
||||||
|
135
tests/parser/func/main.arf
Normal file
135
tests/parser/func/main.arf
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
:arf
|
||||||
|
---
|
||||||
|
func ro aBasicExternal
|
||||||
|
> someInput:Int:mut
|
||||||
|
< someOutput:Int 4
|
||||||
|
---
|
||||||
|
external
|
||||||
|
|
||||||
|
func ro bMethod
|
||||||
|
@ bird:{Bird}
|
||||||
|
> someInput:Int:mut
|
||||||
|
< someOutput:Int 4
|
||||||
|
---
|
||||||
|
external
|
||||||
|
|
||||||
|
func ro cBasicPhrases
|
||||||
|
---
|
||||||
|
fn 329 983 07
|
||||||
|
[fn 329 983 07]
|
||||||
|
[fn
|
||||||
|
329
|
||||||
|
983
|
||||||
|
071]
|
||||||
|
fn [gn
|
||||||
|
329 983
|
||||||
|
071] 123
|
||||||
|
|
||||||
|
func ro dArgumentTypes
|
||||||
|
---
|
||||||
|
[bird tree butterfly.wing "hello world"
|
||||||
|
grass:{Int:mut 8}]
|
||||||
|
|
||||||
|
func ro eMath
|
||||||
|
> x:Int
|
||||||
|
> y:Int
|
||||||
|
< z:Int
|
||||||
|
---
|
||||||
|
++ x
|
||||||
|
-- y
|
||||||
|
set z [+ [* 0372 00] 98 x [/ 9832 y] 930]
|
||||||
|
|
||||||
|
! true
|
||||||
|
~ 0b01
|
||||||
|
~= x
|
||||||
|
% 873 32
|
||||||
|
|
||||||
|
= 5 5
|
||||||
|
!= 4 4
|
||||||
|
|
||||||
|
<= 4 98
|
||||||
|
< 4 98
|
||||||
|
<< 0x0F 4
|
||||||
|
<<= x 4
|
||||||
|
|
||||||
|
>= 98 4
|
||||||
|
> 98 4
|
||||||
|
>> 0xF0 4
|
||||||
|
>>= x 4
|
||||||
|
|
||||||
|
| 0b01 0b10
|
||||||
|
|= x 0b10
|
||||||
|
& 0b110 0b011
|
||||||
|
&= x 0b011
|
||||||
|
|
||||||
|
&& true true
|
||||||
|
|| true false
|
||||||
|
|
||||||
|
func ro fReturnDirection
|
||||||
|
< err:Error
|
||||||
|
---
|
||||||
|
someFunc 498 2980 90 -> thing:Int err
|
||||||
|
otherFunc -> thing err:Error
|
||||||
|
|
||||||
|
[fn
|
||||||
|
329
|
||||||
|
983
|
||||||
|
071] -> thing:Int err
|
||||||
|
|
||||||
|
func ro gControlFlow
|
||||||
|
---
|
||||||
|
defer
|
||||||
|
something
|
||||||
|
otherThing
|
||||||
|
|
||||||
|
if condition
|
||||||
|
something
|
||||||
|
|
||||||
|
if condition
|
||||||
|
something
|
||||||
|
elseif
|
||||||
|
[otherThing]
|
||||||
|
else
|
||||||
|
finalThing
|
||||||
|
|
||||||
|
while [< x 432]
|
||||||
|
something
|
||||||
|
|
||||||
|
switch value
|
||||||
|
: 324
|
||||||
|
something
|
||||||
|
[: 93284]
|
||||||
|
otherThing
|
||||||
|
: 9128 34738 7328
|
||||||
|
multipleCases
|
||||||
|
:
|
||||||
|
[defaultThing]
|
||||||
|
|
||||||
|
for index:Size element:Int someArray
|
||||||
|
something
|
||||||
|
someNextThing
|
||||||
|
justMakingSureBlockParsingWorks
|
||||||
|
|
||||||
|
[if condition]
|
||||||
|
if condition
|
||||||
|
nestedThing
|
||||||
|
else
|
||||||
|
otherThing
|
||||||
|
else
|
||||||
|
if condition
|
||||||
|
nestedThing
|
||||||
|
else
|
||||||
|
otherThing
|
||||||
|
|
||||||
|
func ro hSetPhrase
|
||||||
|
---
|
||||||
|
set x:Int 3
|
||||||
|
# loc is a reference, similar to * in C
|
||||||
|
set y:{Int} [loc x]
|
||||||
|
set z:{Int 8}
|
||||||
|
398 9 2309 983 -2387
|
||||||
|
478 555 123
|
||||||
|
set bird:Bird
|
||||||
|
.that
|
||||||
|
.whenYou 99999
|
||||||
|
.this 324
|
Reference in New Issue
Block a user