Compare commits
No commits in common. "e069569c3c9c0a918a152fd852cb1c7fbca7642c" and "0a067524ce42354315205cfaa0031df9898b8164" have entirely different histories.
e069569c3c
...
0a067524ce
@ -29,8 +29,6 @@ These are some design goals that I have followed/am following:
|
|||||||
- Language syntax must have zero ambiguity
|
- Language syntax must have zero ambiguity
|
||||||
- The compiler should not generate new functions or complex logic that the user
|
- The compiler should not generate new functions or complex logic that the user
|
||||||
has not written
|
has not written
|
||||||
- One line at a time - the language's syntax should encourage writing code that
|
|
||||||
flows vertically and not horizontally, with minimal nesting
|
|
||||||
|
|
||||||
## Planned features
|
## Planned features
|
||||||
|
|
||||||
|
@ -52,30 +52,20 @@ func (err Error) Error () (formattedMessage string) {
|
|||||||
|
|
||||||
if err.width > 0 {
|
if err.width > 0 {
|
||||||
// print erroneous line
|
// print erroneous line
|
||||||
line := err.Location.file.lines[err.Location.row]
|
|
||||||
formattedMessage +=
|
formattedMessage +=
|
||||||
err.Location.file.lines[err.Location.row] + "\n"
|
err.Location.file.lines[err.Location.row] + "\n"
|
||||||
|
|
||||||
// position error marker
|
|
||||||
var index int
|
|
||||||
for index = 0; index < err.Location.column; index ++ {
|
|
||||||
if line[index] == '\t' {
|
|
||||||
formattedMessage += "\t"
|
|
||||||
} else {
|
|
||||||
formattedMessage += " "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// print an arrow with a tail spanning the width of the mistake
|
// print an arrow with a tail spanning the width of the mistake
|
||||||
for err.width > 1 {
|
columnCountdown := err.Location.column
|
||||||
if line[index] == '\t' {
|
for columnCountdown > 1 {
|
||||||
formattedMessage += "--------"
|
// TODO: for tabs, print out a teb instead.
|
||||||
} else {
|
formattedMessage += " "
|
||||||
formattedMessage += "-"
|
columnCountdown --
|
||||||
}
|
}
|
||||||
index ++
|
for err.width > 1 {
|
||||||
|
// TODO: for tabs, print out 8 of these instead.
|
||||||
|
formattedMessage += "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
formattedMessage += "^\n"
|
formattedMessage += "^\n"
|
||||||
}
|
}
|
||||||
formattedMessage += err.message + "\n"
|
formattedMessage += err.message + "\n"
|
||||||
|
@ -176,17 +176,7 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
case '.':
|
case '.':
|
||||||
token := lexer.newToken()
|
token := lexer.newToken()
|
||||||
err = lexer.nextRune()
|
|
||||||
if err != nil { return }
|
|
||||||
token.kind = TokenKindDot
|
token.kind = TokenKindDot
|
||||||
if lexer.char == '.' {
|
|
||||||
token.kind = TokenKindElipsis
|
|
||||||
err = lexer.nextRune()
|
|
||||||
}
|
|
||||||
lexer.addToken(token)
|
|
||||||
case ',':
|
|
||||||
token := lexer.newToken()
|
|
||||||
token.kind = TokenKindComma
|
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
case '[':
|
case '[':
|
||||||
@ -210,15 +200,15 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
case '+':
|
case '+':
|
||||||
token := lexer.newToken()
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindPlus
|
token.kind = TokenKindPlus
|
||||||
if lexer.char == '+' {
|
if lexer.char == '+' {
|
||||||
token.kind = TokenKindIncrement
|
token.kind = TokenKindIncrement
|
||||||
err = lexer.nextRune()
|
|
||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
|
err = lexer.nextRune()
|
||||||
case '-':
|
case '-':
|
||||||
err = lexer.tokenizeDashBeginning()
|
err = lexer.tokenizeDashBeginning()
|
||||||
case '*':
|
case '*':
|
||||||
@ -252,45 +242,45 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
|
|||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
case '<':
|
case '<':
|
||||||
token := lexer.newToken()
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindLessThan
|
token.kind = TokenKindLessThan
|
||||||
if lexer.char == '<' {
|
if lexer.char == '<' {
|
||||||
token.kind = TokenKindLShift
|
token.kind = TokenKindLShift
|
||||||
err = lexer.nextRune()
|
|
||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
|
err = lexer.nextRune()
|
||||||
case '>':
|
case '>':
|
||||||
token := lexer.newToken()
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindGreaterThan
|
token.kind = TokenKindGreaterThan
|
||||||
if lexer.char == '>' {
|
if lexer.char == '>' {
|
||||||
token.kind = TokenKindRShift
|
token.kind = TokenKindRShift
|
||||||
err = lexer.nextRune()
|
|
||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
|
err = lexer.nextRune()
|
||||||
case '|':
|
case '|':
|
||||||
token := lexer.newToken()
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindBinaryOr
|
token.kind = TokenKindBinaryOr
|
||||||
if lexer.char == '|' {
|
if lexer.char == '|' {
|
||||||
token.kind = TokenKindLogicalOr
|
token.kind = TokenKindLogicalOr
|
||||||
err = lexer.nextRune()
|
|
||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
|
err = lexer.nextRune()
|
||||||
case '&':
|
case '&':
|
||||||
token := lexer.newToken()
|
|
||||||
err = lexer.nextRune()
|
err = lexer.nextRune()
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
token := lexer.newToken()
|
||||||
token.kind = TokenKindBinaryAnd
|
token.kind = TokenKindBinaryAnd
|
||||||
if lexer.char == '&' {
|
if lexer.char == '&' {
|
||||||
token.kind = TokenKindLogicalAnd
|
token.kind = TokenKindLogicalAnd
|
||||||
err = lexer.nextRune()
|
|
||||||
}
|
}
|
||||||
lexer.addToken(token)
|
lexer.addToken(token)
|
||||||
|
err = lexer.nextRune()
|
||||||
default:
|
default:
|
||||||
err = file.NewError (
|
err = file.NewError (
|
||||||
lexer.file.Location(1),
|
lexer.file.Location(1),
|
||||||
|
@ -62,8 +62,6 @@ func TestTokenizeAll (test *testing.T) {
|
|||||||
Token { kind: TokenKindName, value: "helloWorld" },
|
Token { kind: TokenKindName, value: "helloWorld" },
|
||||||
Token { kind: TokenKindColon },
|
Token { kind: TokenKindColon },
|
||||||
Token { kind: TokenKindDot },
|
Token { kind: TokenKindDot },
|
||||||
Token { kind: TokenKindComma },
|
|
||||||
Token { kind: TokenKindElipsis },
|
|
||||||
Token { kind: TokenKindLBracket },
|
Token { kind: TokenKindLBracket },
|
||||||
Token { kind: TokenKindRBracket },
|
Token { kind: TokenKindRBracket },
|
||||||
Token { kind: TokenKindLBrace },
|
Token { kind: TokenKindLBrace },
|
||||||
@ -93,10 +91,6 @@ func TestTokenizeAll (test *testing.T) {
|
|||||||
|
|
||||||
func TestTokenizeNumbers (test *testing.T) {
|
func TestTokenizeNumbers (test *testing.T) {
|
||||||
checkTokenSlice("../tests/lexer/numbers.arf", []Token {
|
checkTokenSlice("../tests/lexer/numbers.arf", []Token {
|
||||||
Token { kind: TokenKindUInt, value: uint64(0) },
|
|
||||||
Token { kind: TokenKindNewline },
|
|
||||||
Token { kind: TokenKindUInt, value: uint64(8) },
|
|
||||||
Token { kind: TokenKindNewline },
|
|
||||||
Token { kind: TokenKindUInt, value: uint64(83628266) },
|
Token { kind: TokenKindUInt, value: uint64(83628266) },
|
||||||
Token { kind: TokenKindNewline },
|
Token { kind: TokenKindNewline },
|
||||||
Token { kind: TokenKindUInt, value: uint64(83628266) },
|
Token { kind: TokenKindUInt, value: uint64(83628266) },
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
|
import "git.tebibyte.media/sashakoshka/arf/file"
|
||||||
|
|
||||||
// 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) {
|
||||||
var number uint64
|
var number uint64
|
||||||
@ -21,6 +23,11 @@ func (lexer *LexingOperation) tokenizeNumberBeginning (negative bool) (err error
|
|||||||
number, fragment, isFloat, err = lexer.tokenizeNumber(10)
|
number, fragment, isFloat, err = lexer.tokenizeNumber(10)
|
||||||
} else if lexer.char >= '0' && lexer.char <= '9' {
|
} else if lexer.char >= '0' && lexer.char <= '9' {
|
||||||
number, fragment, isFloat, err = lexer.tokenizeNumber(8)
|
number, fragment, isFloat, err = lexer.tokenizeNumber(8)
|
||||||
|
} else {
|
||||||
|
return file.NewError (
|
||||||
|
lexer.file.Location(1),
|
||||||
|
"unexpected character in number literal",
|
||||||
|
file.ErrorKindError)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
number, fragment, isFloat, err = lexer.tokenizeNumber(10)
|
number, fragment, isFloat, err = lexer.tokenizeNumber(10)
|
||||||
|
@ -24,8 +24,6 @@ const (
|
|||||||
|
|
||||||
TokenKindColon
|
TokenKindColon
|
||||||
TokenKindDot
|
TokenKindDot
|
||||||
TokenKindElipsis
|
|
||||||
TokenKindComma
|
|
||||||
|
|
||||||
TokenKindLBracket
|
TokenKindLBracket
|
||||||
TokenKindRBracket
|
TokenKindRBracket
|
||||||
@ -135,10 +133,6 @@ func (tokenKind TokenKind) Describe () (description string) {
|
|||||||
description = "Colon"
|
description = "Colon"
|
||||||
case TokenKindDot:
|
case TokenKindDot:
|
||||||
description = "Dot"
|
description = "Dot"
|
||||||
case TokenKindElipsis:
|
|
||||||
description = "Elipsis"
|
|
||||||
case TokenKindComma:
|
|
||||||
description = "Comma"
|
|
||||||
case TokenKindLBracket:
|
case TokenKindLBracket:
|
||||||
description = "LBracket"
|
description = "LBracket"
|
||||||
case TokenKindRBracket:
|
case TokenKindRBracket:
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
package parser
|
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
|
||||||
|
|
||||||
var validArgumentStartTokens = []lexer.TokenKind {
|
|
||||||
lexer.TokenKindName,
|
|
||||||
|
|
||||||
lexer.TokenKindInt,
|
|
||||||
lexer.TokenKindUInt,
|
|
||||||
lexer.TokenKindFloat,
|
|
||||||
lexer.TokenKindString,
|
|
||||||
lexer.TokenKindRune,
|
|
||||||
|
|
||||||
lexer.TokenKindLBrace,
|
|
||||||
lexer.TokenKindLBracket,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (parser *ParsingOperation) parseArgument () (argument Argument, err error) {
|
|
||||||
argument.location = parser.token.Location()
|
|
||||||
|
|
||||||
err = parser.expect(validArgumentStartTokens...)
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
switch parser.token.Kind() {
|
|
||||||
case lexer.TokenKindName:
|
|
||||||
var identifier Identifier
|
|
||||||
identifier, err = parser.parseIdentifier()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
if parser.token.Is(lexer.TokenKindColon) {
|
|
||||||
var what Type
|
|
||||||
what, err = parser.parseType()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
if len(identifier.trail) != 1 {
|
|
||||||
err = parser.token.NewError (
|
|
||||||
"cannot use member selection in " +
|
|
||||||
"a variable definition",
|
|
||||||
file.ErrorKindError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
argument.kind = ArgumentKindDeclaration
|
|
||||||
argument.value = Declaration {
|
|
||||||
location: argument.location,
|
|
||||||
name: identifier.trail[0],
|
|
||||||
what: what,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
argument.kind = ArgumentKindIdentifier
|
|
||||||
argument.value = identifier
|
|
||||||
}
|
|
||||||
|
|
||||||
case lexer.TokenKindInt:
|
|
||||||
argument.kind = ArgumentKindInt
|
|
||||||
argument.value = parser.token.Value().(int64)
|
|
||||||
err = parser.nextToken()
|
|
||||||
|
|
||||||
case lexer.TokenKindUInt:
|
|
||||||
argument.kind = ArgumentKindUInt
|
|
||||||
argument.value = parser.token.Value().(uint64)
|
|
||||||
err = parser.nextToken()
|
|
||||||
|
|
||||||
case lexer.TokenKindFloat:
|
|
||||||
argument.kind = ArgumentKindFloat
|
|
||||||
argument.value = parser.token.Value().(float64)
|
|
||||||
err = parser.nextToken()
|
|
||||||
|
|
||||||
case lexer.TokenKindString:
|
|
||||||
argument.kind = ArgumentKindString
|
|
||||||
argument.value = parser.token.Value().(string)
|
|
||||||
parser.nextToken()
|
|
||||||
|
|
||||||
case lexer.TokenKindRune:
|
|
||||||
argument.kind = ArgumentKindRune
|
|
||||||
argument.value = parser.token.Value().(rune)
|
|
||||||
parser.nextToken()
|
|
||||||
|
|
||||||
// case lexer.TokenKindLBrace:
|
|
||||||
|
|
||||||
// case lexer.TokenKindLBracket:
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic (
|
|
||||||
"unimplemented argument kind " +
|
|
||||||
parser.token.Kind().Describe())
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,34 +1,18 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
||||||
|
|
||||||
// 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) {
|
||||||
for {
|
err = parser.nextToken(lexer.TokenKindName)
|
||||||
err = parser.expect(lexer.TokenKindName)
|
if err != nil { return }
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
sectionType := parser.token.Value().(string)
|
switch parser.token.Value().(string) {
|
||||||
switch sectionType {
|
case "data":
|
||||||
case "data":
|
case "type":
|
||||||
var section *DataSection
|
case "func":
|
||||||
section, err = parser.parseDataSection()
|
case "face":
|
||||||
if parser.tree.dataSections == nil {
|
|
||||||
parser.tree.dataSections =
|
|
||||||
make(map[string] *DataSection)
|
|
||||||
}
|
|
||||||
parser.tree.dataSections[section.name] = section
|
|
||||||
if err != nil { return }
|
|
||||||
case "type":
|
|
||||||
case "face":
|
|
||||||
case "enum":
|
|
||||||
case "func":
|
|
||||||
default:
|
|
||||||
err = parser.token.NewError (
|
|
||||||
"unknown section type \"" + sectionType + "\"",
|
|
||||||
file.ErrorKindError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
310
parser/data.go
310
parser/data.go
@ -1,312 +1,6 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
// parseData parses a data section
|
||||||
import "git.tebibyte.media/sashakoshka/arf/types"
|
func (parser *ParsingOperation) parseData () (err error) {
|
||||||
import "git.tebibyte.media/sashakoshka/arf/lexer"
|
|
||||||
|
|
||||||
// parseData parses a data section.
|
|
||||||
func (parser *ParsingOperation) parseDataSection () (
|
|
||||||
section *DataSection,
|
|
||||||
err error,
|
|
||||||
) {
|
|
||||||
err = parser.expect(lexer.TokenKindName)
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
section = &DataSection { location: parser.token.Location() }
|
|
||||||
|
|
||||||
err = parser.nextToken(lexer.TokenKindPermission)
|
|
||||||
if err != nil { return }
|
|
||||||
section.permission = parser.token.Value().(types.Permission)
|
|
||||||
|
|
||||||
err = parser.nextToken(lexer.TokenKindName)
|
|
||||||
if err != nil { return }
|
|
||||||
section.name = parser.token.Value().(string)
|
|
||||||
|
|
||||||
err = parser.nextToken(lexer.TokenKindColon)
|
|
||||||
if err != nil { return }
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
section.what, err = parser.parseType()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
if parser.token.Is(lexer.TokenKindNewline) {
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
section.value, err = parser.parseInitializationValues(0)
|
|
||||||
if err != nil { return }
|
|
||||||
} else {
|
|
||||||
section.value, err = parser.parseArgument()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
err = parser.expect(lexer.TokenKindNewline)
|
|
||||||
if err != nil { return }
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseInitializationValues starts on the line after a data section, or a set
|
|
||||||
// phrase. It checks for an indent greater than the indent of the aforementioned
|
|
||||||
// data section or set phrase (passed through baseIndent), and if there is,
|
|
||||||
// it parses initialization values.
|
|
||||||
func (parser *ParsingOperation) parseInitializationValues (
|
|
||||||
baseIndent int,
|
|
||||||
) (
|
|
||||||
initializationArgument Argument,
|
|
||||||
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 }
|
|
||||||
|
|
||||||
initializationArgument.location = parser.token.Location()
|
|
||||||
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
if parser.token.Is(lexer.TokenKindDot) {
|
|
||||||
|
|
||||||
// object initialization
|
|
||||||
parser.previousToken()
|
|
||||||
var initializationValues ObjectInitializationValues
|
|
||||||
initializationValues, err = parser.parseObjectInitializationValues()
|
|
||||||
initializationArgument.kind = ArgumentKindObjectInitializationValues
|
|
||||||
initializationArgument.value = &initializationValues
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// array initialization
|
|
||||||
parser.previousToken()
|
|
||||||
var initializationValues ArrayInitializationValues
|
|
||||||
initializationValues, err = parser.parseArrayInitializationValues()
|
|
||||||
initializationArgument.kind = ArgumentKindArrayInitializationValues
|
|
||||||
initializationArgument.value = &initializationValues
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseObjectInitializationValues parses a list of object initialization
|
|
||||||
// values until the indentation level drops.
|
|
||||||
func (parser *ParsingOperation) parseObjectInitializationValues () (
|
|
||||||
initializationValues ObjectInitializationValues,
|
|
||||||
err error,
|
|
||||||
) {
|
|
||||||
println("BEGIN")
|
|
||||||
defer println("END")
|
|
||||||
|
|
||||||
initializationValues.attributes = make(map[string] Argument)
|
|
||||||
|
|
||||||
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 {
|
|
||||||
initializationValues.location = parser.token.Location()
|
|
||||||
baseIndent = indent
|
|
||||||
begin = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// do not parse any further if the indent has changed
|
|
||||||
if indent != baseIndent { break }
|
|
||||||
|
|
||||||
println("HIT")
|
|
||||||
|
|
||||||
// move on to the beginning of the line, which must contain
|
|
||||||
// a member initialization value
|
|
||||||
err = parser.nextToken(lexer.TokenKindDot)
|
|
||||||
if err != nil { return }
|
|
||||||
err = parser.nextToken(lexer.TokenKindName)
|
|
||||||
if err != nil { return }
|
|
||||||
name := parser.token.Value().(string)
|
|
||||||
|
|
||||||
// if the member has already been listed, throw an error
|
|
||||||
_, exists := initializationValues.attributes[name]
|
|
||||||
if exists {
|
|
||||||
err = parser.token.NewError (
|
|
||||||
"duplicate member \"" + name + "\" in object " +
|
|
||||||
"member initialization",
|
|
||||||
file.ErrorKindError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the argument determining the member initialization
|
|
||||||
// value
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
var value Argument
|
|
||||||
if parser.token.Is(lexer.TokenKindNewline) {
|
|
||||||
|
|
||||||
// recurse
|
|
||||||
err = parser.nextToken(lexer.TokenKindIndent)
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
value, err = parser.parseInitializationValues(baseIndent)
|
|
||||||
initializationValues.attributes[name] = value
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// parse as normal argument
|
|
||||||
value, err = parser.parseArgument()
|
|
||||||
initializationValues.attributes[name] = value
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
err = parser.expect(lexer.TokenKindNewline)
|
|
||||||
if err != nil { return }
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseArrayInitializationValues parses a list of array initialization values
|
|
||||||
// until the indentation lexel drops.
|
|
||||||
func (parser *ParsingOperation) parseArrayInitializationValues () (
|
|
||||||
initializationValues ArrayInitializationValues,
|
|
||||||
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 {
|
|
||||||
initializationValues.location = parser.token.Location()
|
|
||||||
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
|
|
||||||
// arguments
|
|
||||||
err = parser.nextToken(validArgumentStartTokens...)
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
for {
|
|
||||||
// stop parsing this line and go on to the next if a
|
|
||||||
// newline token is encountered
|
|
||||||
if parser.token.Is(lexer.TokenKindNewline) {
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, parse the argument
|
|
||||||
var argument Argument
|
|
||||||
argument, err = parser.parseArgument()
|
|
||||||
if err != nil { return }
|
|
||||||
initializationValues.values = append (
|
|
||||||
initializationValues.values,
|
|
||||||
argument)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseType parses a type notation of the form Name, {Name}, etc.
|
|
||||||
func (parser *ParsingOperation) parseType () (what Type, err error) {
|
|
||||||
err = parser.expect(lexer.TokenKindName, lexer.TokenKindLBrace)
|
|
||||||
if err != nil { return }
|
|
||||||
what.location = parser.token.Location()
|
|
||||||
|
|
||||||
if parser.token.Is(lexer.TokenKindLBrace) {
|
|
||||||
what.kind = TypeKindPointer
|
|
||||||
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
var points Type
|
|
||||||
points, err = parser.parseType()
|
|
||||||
if err != nil { return }
|
|
||||||
what.points = &points
|
|
||||||
|
|
||||||
err = parser.expect (
|
|
||||||
lexer.TokenKindUInt,
|
|
||||||
lexer.TokenKindRBrace,
|
|
||||||
lexer.TokenKindElipsis)
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
if parser.token.Is(lexer.TokenKindUInt) {
|
|
||||||
what.kind = TypeKindArray
|
|
||||||
|
|
||||||
what.length = parser.token.Value().(uint64)
|
|
||||||
|
|
||||||
err = parser.nextToken(lexer.TokenKindRBrace)
|
|
||||||
if err != nil { return }
|
|
||||||
} else if parser.token.Is(lexer.TokenKindElipsis) {
|
|
||||||
what.kind = TypeKindArray
|
|
||||||
|
|
||||||
err = parser.nextToken(lexer.TokenKindRBrace)
|
|
||||||
if err != nil { return }
|
|
||||||
}
|
|
||||||
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
} else {
|
|
||||||
what.name, err = parser.parseIdentifier()
|
|
||||||
if err != nil { return }
|
|
||||||
}
|
|
||||||
|
|
||||||
if parser.token.Is(lexer.TokenKindColon) {
|
|
||||||
err = parser.nextToken(lexer.TokenKindName)
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
qualifier := parser.token.Value().(string)
|
|
||||||
switch qualifier {
|
|
||||||
case "mut":
|
|
||||||
what.mutable = true
|
|
||||||
default:
|
|
||||||
err = parser.token.NewError (
|
|
||||||
"unknown type qualifier \"" + qualifier + "\"",
|
|
||||||
file.ErrorKindError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseIdentifier parses an identifier made out of dot separated names.
|
|
||||||
func (parser *ParsingOperation) parseIdentifier () (
|
|
||||||
identifier Identifier,
|
|
||||||
err error,
|
|
||||||
) {
|
|
||||||
err = parser.expect(lexer.TokenKindName)
|
|
||||||
if err != nil { return }
|
|
||||||
identifier.location = parser.token.Location()
|
|
||||||
|
|
||||||
for {
|
|
||||||
// TODO: eat up newlines and tabs after the dot, but not before
|
|
||||||
// it.
|
|
||||||
if !parser.token.Is(lexer.TokenKindName) { break }
|
|
||||||
|
|
||||||
identifier.trail = append (
|
|
||||||
identifier.trail,
|
|
||||||
parser.token.Value().(string))
|
|
||||||
|
|
||||||
err = parser.nextToken()
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
if !parser.token.Is(lexer.TokenKindDot) { break }
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -111,12 +111,3 @@ func (parser *ParsingOperation) nextToken (allowed ...lexer.TokenKind) (err erro
|
|||||||
err = parser.expect(allowed...)
|
err = parser.expect(allowed...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// previousToken goes back one token. If the parser is already at the beginning,
|
|
||||||
// this does nothing.
|
|
||||||
func (parser *ParsingOperation) previousToken () {
|
|
||||||
parser.tokenIndex --
|
|
||||||
if parser.tokenIndex < 0 { parser.tokenIndex = 0 }
|
|
||||||
parser.token = parser.tokens[parser.tokenIndex]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
@ -1,75 +1,33 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "io"
|
import "reflect"
|
||||||
import "testing"
|
import "testing"
|
||||||
// import "git.tebibyte.media/sashakoshka/arf/types"
|
|
||||||
|
|
||||||
func checkTree (modulePath string, correct string, test *testing.T) {
|
func checkTree (modulePath string, correct *SyntaxTree, test *testing.T) {
|
||||||
tree, err := Parse(modulePath)
|
tree, err := Parse(modulePath)
|
||||||
treeString := tree.ToString(0)
|
|
||||||
|
|
||||||
test.Log("CORRECT TREE:")
|
if err != nil {
|
||||||
test.Log(correct)
|
|
||||||
test.Log("WHAT WAS PARSED:")
|
|
||||||
test.Log(treeString)
|
|
||||||
|
|
||||||
if err != io.EOF && err != nil {
|
|
||||||
test.Log("returned error:")
|
test.Log("returned error:")
|
||||||
test.Log(err.Error())
|
test.Log(err.Error())
|
||||||
test.Fail()
|
test.Fail()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if treeString != correct {
|
if !reflect.DeepEqual(tree, correct) {
|
||||||
test.Log("trees not equal!")
|
test.Log("trees not equal")
|
||||||
test.Fail()
|
test.Fail()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMeta (test *testing.T) {
|
func TestMeta (test *testing.T) {
|
||||||
checkTree ("../tests/parser/meta",
|
checkTree("../tests/parser/meta",&SyntaxTree {
|
||||||
`:arf
|
license: "GPLv3",
|
||||||
author "Sasha Koshka"
|
author: "Sasha Koshka",
|
||||||
license "GPLv3"
|
|
||||||
require "someModule"
|
requires: []string {
|
||||||
require "otherModule"
|
"someModule",
|
||||||
---
|
"otherModule",
|
||||||
`, test)
|
},
|
||||||
|
}, test)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestData (test *testing.T) {
|
|
||||||
checkTree ("../tests/parser/data",
|
|
||||||
`:arf
|
|
||||||
---
|
|
||||||
data wr integer:Int 3202
|
|
||||||
data wr integerArray16:{Int 16}
|
|
||||||
data wr integerArrayInitialized:{Int 16}
|
|
||||||
3948
|
|
||||||
293
|
|
||||||
293049
|
|
||||||
948
|
|
||||||
912
|
|
||||||
340
|
|
||||||
0
|
|
||||||
2304
|
|
||||||
0
|
|
||||||
4785
|
|
||||||
92
|
|
||||||
data wr integerArrayVariable:{Int ..}
|
|
||||||
data wr integerPointer:{Int}
|
|
||||||
data wr mutInteger:Int:mut 3202
|
|
||||||
data wr mutIntegerPointer:{Int}:mut
|
|
||||||
data wr nestedObject:Obj
|
|
||||||
.that
|
|
||||||
.bird2 123.8439
|
|
||||||
.bird3 9328.21348239
|
|
||||||
.this
|
|
||||||
.bird0 324
|
|
||||||
.bird1 "hello world"
|
|
||||||
data wr object:Obj
|
|
||||||
.that 2139
|
|
||||||
.this 324
|
|
||||||
`, test)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,248 +0,0 @@
|
|||||||
package parser
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
import "sort"
|
|
||||||
|
|
||||||
func doIndent (indent int, input ...string) (output string) {
|
|
||||||
for index := 0; index < indent; index ++ {
|
|
||||||
output += "\t"
|
|
||||||
}
|
|
||||||
for _, inputSection := range input {
|
|
||||||
output += inputSection
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortMapKeysAlphabetically[KEY_TYPE any] (
|
|
||||||
unsortedMap map[string] KEY_TYPE,
|
|
||||||
) (
|
|
||||||
sortedKeys []string,
|
|
||||||
) {
|
|
||||||
sortedKeys = make([]string, len(unsortedMap))
|
|
||||||
index := 0
|
|
||||||
for key, _ := range unsortedMap {
|
|
||||||
sortedKeys[index] = key
|
|
||||||
index ++
|
|
||||||
}
|
|
||||||
sort.Strings(sortedKeys)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tree *SyntaxTree) ToString (indent int) (output string) {
|
|
||||||
output += doIndent(indent, ":arf\n")
|
|
||||||
|
|
||||||
if tree.author != "" {
|
|
||||||
output += doIndent(indent, "author \"", tree.author, "\"\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if tree.license != "" {
|
|
||||||
output += doIndent(indent, "license \"", tree.license, "\"\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, require := range tree.requires {
|
|
||||||
output += doIndent(indent, "require \"", require, "\"\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
output += doIndent(indent, "---\n")
|
|
||||||
|
|
||||||
dataSectionKeys := sortMapKeysAlphabetically(tree.dataSections)
|
|
||||||
for _, name := range dataSectionKeys {
|
|
||||||
output += tree.dataSections[name].ToString(indent)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (identifier *Identifier) ToString () (output string) {
|
|
||||||
for index, trailItem := range identifier.trail {
|
|
||||||
if index > 0 {
|
|
||||||
output += "."
|
|
||||||
}
|
|
||||||
|
|
||||||
output += trailItem
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (what *Type) ToString () (output string) {
|
|
||||||
if what.kind == TypeKindBasic {
|
|
||||||
output += what.name.ToString()
|
|
||||||
} else {
|
|
||||||
output += "{"
|
|
||||||
output += what.points.ToString()
|
|
||||||
|
|
||||||
if what.kind == TypeKindArray {
|
|
||||||
output += " "
|
|
||||||
if what.length == 0 {
|
|
||||||
output += ".."
|
|
||||||
} else {
|
|
||||||
output += fmt.Sprint(what.length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output += "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if what.mutable {
|
|
||||||
output += ":mut"
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (declaration *Declaration) ToString () (output string) {
|
|
||||||
output += declaration.name + ":"
|
|
||||||
output += declaration.what.ToString()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (attributes *ObjectInitializationValues) ToString (
|
|
||||||
indent int,
|
|
||||||
) (
|
|
||||||
output string,
|
|
||||||
) {
|
|
||||||
for _, name := range sortMapKeysAlphabetically(attributes.attributes) {
|
|
||||||
value := attributes.attributes[name]
|
|
||||||
|
|
||||||
output += doIndent(indent, ".", name, " ")
|
|
||||||
if value.kind == ArgumentKindObjectInitializationValues {
|
|
||||||
output += "\n"
|
|
||||||
output += value.ToString(indent + 1, true)
|
|
||||||
} else {
|
|
||||||
output += value.ToString(0, false) + "\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (values *ArrayInitializationValues) ToString (
|
|
||||||
indent int,
|
|
||||||
) (
|
|
||||||
output string,
|
|
||||||
) {
|
|
||||||
for _, value := range values.values {
|
|
||||||
output += value.ToString(indent, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if !breakLine { indent = 0 }
|
|
||||||
if argument.kind == ArgumentKindNil {
|
|
||||||
output += "NIL-ARGUMENT"
|
|
||||||
if breakLine { output += "\n" }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch argument.kind {
|
|
||||||
case ArgumentKindPhrase:
|
|
||||||
output += argument.value.(*Phrase).ToString (
|
|
||||||
indent,
|
|
||||||
breakLine)
|
|
||||||
|
|
||||||
case ArgumentKindObjectInitializationValues:
|
|
||||||
// this should only appear in contexts where breakLine is true
|
|
||||||
output += argument.value.(*ObjectInitializationValues).
|
|
||||||
ToString(indent)
|
|
||||||
|
|
||||||
case ArgumentKindArrayInitializationValues:
|
|
||||||
// this should only appear in contexts where breakLine is true
|
|
||||||
output += argument.value.(*ArrayInitializationValues).
|
|
||||||
ToString(indent)
|
|
||||||
|
|
||||||
case ArgumentKindIdentifier:
|
|
||||||
output += doIndent (
|
|
||||||
indent,
|
|
||||||
argument.value.(*Identifier).ToString())
|
|
||||||
if breakLine { output += "\n" }
|
|
||||||
|
|
||||||
case ArgumentKindDeclaration:
|
|
||||||
output += doIndent (
|
|
||||||
indent,
|
|
||||||
argument.value.(*Declaration).ToString())
|
|
||||||
if breakLine { output += "\n" }
|
|
||||||
|
|
||||||
case ArgumentKindInt, ArgumentKindUInt, ArgumentKindFloat:
|
|
||||||
output += doIndent(indent, fmt.Sprint(argument.value))
|
|
||||||
if breakLine { output += "\n" }
|
|
||||||
|
|
||||||
case ArgumentKindString:
|
|
||||||
output += doIndent (
|
|
||||||
indent,
|
|
||||||
"\"" + argument.value.(string) + "\"")
|
|
||||||
if breakLine { output += "\n" }
|
|
||||||
|
|
||||||
case ArgumentKindRune:
|
|
||||||
output += doIndent (
|
|
||||||
indent,
|
|
||||||
"'" + string(argument.value.(rune)) + "'")
|
|
||||||
if breakLine { output += "\n" }
|
|
||||||
|
|
||||||
case ArgumentKindOperator:
|
|
||||||
// TODO
|
|
||||||
// also when parsing this argument kind, don't do it in the
|
|
||||||
// argument parsing function. do it specifically when parsing a
|
|
||||||
// phrase command.
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (section *DataSection) ToString (indent int) (output string) {
|
|
||||||
output += doIndent (
|
|
||||||
indent,
|
|
||||||
"data ",
|
|
||||||
section.permission.ToString(), " ",
|
|
||||||
section.name, ":",
|
|
||||||
section.what.ToString())
|
|
||||||
|
|
||||||
isComplexInitialization :=
|
|
||||||
section.value.kind == ArgumentKindObjectInitializationValues ||
|
|
||||||
section.value.kind == ArgumentKindArrayInitializationValues
|
|
||||||
|
|
||||||
if section.value.value == nil {
|
|
||||||
output += "\n"
|
|
||||||
} else if isComplexInitialization {
|
|
||||||
output += "\n"
|
|
||||||
output += section.value.ToString(indent + 1, true)
|
|
||||||
} else {
|
|
||||||
output += " " + section.value.ToString(0, false)
|
|
||||||
output += "\n"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
152
parser/tree.go
152
parser/tree.go
@ -1,8 +1,5 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/arf/file"
|
|
||||||
import "git.tebibyte.media/sashakoshka/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
|
||||||
// correct (because it has not been analyzed yet.)
|
// correct (because it has not been analyzed yet.)
|
||||||
@ -10,152 +7,5 @@ type SyntaxTree struct {
|
|||||||
license string
|
license string
|
||||||
author string
|
author string
|
||||||
|
|
||||||
requires []string
|
requires []string
|
||||||
dataSections map[string] *DataSection
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identifier represents a chain of arguments separated by a dot.
|
|
||||||
type Identifier struct {
|
|
||||||
location file.Location
|
|
||||||
trail []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeKind represents what kind of type a type is
|
|
||||||
type TypeKind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TypeKindBasic either means it's a primitive, or it inherits from
|
|
||||||
// something.
|
|
||||||
TypeKindBasic TypeKind = iota
|
|
||||||
|
|
||||||
// TypeKindPointer means it's a pointer
|
|
||||||
TypeKindPointer
|
|
||||||
|
|
||||||
// TypeKindArray means it's an array.
|
|
||||||
TypeKindArray
|
|
||||||
)
|
|
||||||
|
|
||||||
// Type represents a type specifier
|
|
||||||
type Type struct {
|
|
||||||
location file.Location
|
|
||||||
|
|
||||||
mutable bool
|
|
||||||
kind TypeKind
|
|
||||||
|
|
||||||
// only applicable for arrays. a value of zero means it has an
|
|
||||||
// undefined/dynamic length.
|
|
||||||
length uint64
|
|
||||||
|
|
||||||
// only applicable for basic.
|
|
||||||
name Identifier
|
|
||||||
|
|
||||||
// not applicable for basic.
|
|
||||||
points *Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declaration represents a variable declaration.
|
|
||||||
type Declaration struct {
|
|
||||||
location file.Location
|
|
||||||
name string
|
|
||||||
what Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObjectInitializationValues represents a list of object member initialization
|
|
||||||
// attributes.
|
|
||||||
type ObjectInitializationValues struct {
|
|
||||||
location file.Location
|
|
||||||
attributes map[string] Argument
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArrayInitializationValues represents a list of attributes initializing an
|
|
||||||
// array.
|
|
||||||
type ArrayInitializationValues struct {
|
|
||||||
location file.Location
|
|
||||||
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
|
|
||||||
// cast to.
|
|
||||||
type ArgumentKind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
ArgumentKindNil ArgumentKind = iota
|
|
||||||
|
|
||||||
// [name argument]
|
|
||||||
// [name argument argument]
|
|
||||||
// etc...
|
|
||||||
ArgumentKindPhrase = iota
|
|
||||||
|
|
||||||
// {name}
|
|
||||||
ArgumentKindDereference
|
|
||||||
|
|
||||||
// {name 23}
|
|
||||||
ArgumentKindSubscript
|
|
||||||
|
|
||||||
// .name value
|
|
||||||
// but like, a lot of them
|
|
||||||
ArgumentKindObjectInitializationValues
|
|
||||||
|
|
||||||
// value value...
|
|
||||||
ArgumentKindArrayInitializationValues
|
|
||||||
|
|
||||||
// name.name
|
|
||||||
// name.name.name
|
|
||||||
// etc...
|
|
||||||
ArgumentKindIdentifier
|
|
||||||
|
|
||||||
// name:Type
|
|
||||||
// name:{Type}
|
|
||||||
// name:{Type ..}
|
|
||||||
// name:{Type 23}
|
|
||||||
// etc...
|
|
||||||
ArgumentKindDeclaration
|
|
||||||
|
|
||||||
// -1337
|
|
||||||
ArgumentKindInt
|
|
||||||
|
|
||||||
// 1337
|
|
||||||
ArgumentKindUInt
|
|
||||||
|
|
||||||
// 0.44
|
|
||||||
ArgumentKindFloat
|
|
||||||
|
|
||||||
// "hello world"
|
|
||||||
ArgumentKindString
|
|
||||||
|
|
||||||
// 'S'
|
|
||||||
ArgumentKindRune
|
|
||||||
|
|
||||||
// + - * / etc...
|
|
||||||
// this is only used as a phrase command
|
|
||||||
ArgumentKindOperator
|
|
||||||
)
|
|
||||||
|
|
||||||
// Argument represents a value that can be placed anywhere a value goes. This
|
|
||||||
// allows things like phrases being arguments to other phrases.
|
|
||||||
type Argument struct {
|
|
||||||
location file.Location
|
|
||||||
kind ArgumentKind
|
|
||||||
value any
|
|
||||||
// TODO: if there is an argument expansion operator its existence should
|
|
||||||
// be stored here in a boolean.
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataSection represents a global variable.
|
|
||||||
type DataSection struct {
|
|
||||||
location file.Location
|
|
||||||
name string
|
|
||||||
|
|
||||||
what Type
|
|
||||||
value Argument
|
|
||||||
permission types.Permission
|
|
||||||
}
|
}
|
||||||
|
@ -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:.[]{}
|
||||||
+ - ++ -- * / @ ! % ~ < << > >> | || & &&
|
+ - ++ -- * / @ ! % ~ < << > >> | || & &&
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
:arf
|
:arf
|
||||||
0
|
|
||||||
8
|
|
||||||
83628266
|
83628266
|
||||||
0b100111111000001000011101010
|
0b100111111000001000011101010
|
||||||
0x4Fc10Ea
|
0x4Fc10Ea
|
||||||
|
@ -3,50 +3,25 @@
|
|||||||
|
|
||||||
data wr integer:Int 3202
|
data wr integer:Int 3202
|
||||||
|
|
||||||
data wr mutInteger:Int:mut 3202
|
|
||||||
|
|
||||||
data wr integerPointer:{Int}
|
data wr integerPointer:{Int}
|
||||||
|
# TODO: data wr integerPointer:{Int} [& integer]
|
||||||
data wr mutIntegerPointer:{Int}:mut
|
|
||||||
|
|
||||||
data wr integerArray16:{Int 16}
|
data wr integerArray16:{Int 16}
|
||||||
|
|
||||||
data wr integerArrayVariable:{Int ..}
|
data wr integerArrayVariable:{Int ...}
|
||||||
|
|
||||||
data wr integerArrayInitialized:{Int 16}
|
data wr integerArrayInitialized:{Int 16}
|
||||||
3948 293 293049 948 912
|
3948 293 293049 948 912
|
||||||
340 0 2304 0 4785 92
|
340 0 2304 0 4785 92
|
||||||
|
|
||||||
# TODO: reinstate these two after phrase parsing is implemented
|
|
||||||
# data wr integerPointerInit:{Int} [& integer]
|
|
||||||
|
|
||||||
# data wr mutIntegerPointerInit:{Int}:mut [& integer]
|
|
||||||
|
|
||||||
data wr object:Obj
|
data wr object:Obj
|
||||||
.this 324
|
: this 324
|
||||||
.that 2139
|
: that 2139
|
||||||
|
|
||||||
data wr nestedObject:Obj
|
data wr nestedObject:Obj
|
||||||
.this
|
: this
|
||||||
.bird0 324
|
: bird0 324
|
||||||
.bird1 "hello world"
|
: bird1 "hello world"
|
||||||
.that
|
: that
|
||||||
.bird2 123.8439
|
: bird2 123.8439
|
||||||
.bird3 9328.21348239
|
: bird3 9328.21348239
|
||||||
|
|
||||||
|
|
||||||
# func rr main
|
|
||||||
# ---
|
|
||||||
# # TODO: set should be a special case, checking under itself for object
|
|
||||||
# member initialization args. it should also check for args in general
|
|
||||||
# under there which should be treated as array initialization args.
|
|
||||||
# basically, under a set phrase, it should do the same checks that it
|
|
||||||
# does under a data section.
|
|
||||||
#
|
|
||||||
# [set object:Obj]
|
|
||||||
# .this 324
|
|
||||||
# .that 2139
|
|
||||||
#
|
|
||||||
# set object:Obj
|
|
||||||
# .this 324
|
|
||||||
# .that 2139
|
|
||||||
|
@ -30,19 +30,3 @@ func PermissionFrom (data string) (permission Permission) {
|
|||||||
permission.External = ModeFrom(rune(data[1]))
|
permission.External = ModeFrom(rune(data[1]))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mode Mode) ToString () (output string) {
|
|
||||||
switch mode {
|
|
||||||
case ModeNone: output = "n"
|
|
||||||
case ModeRead: output = "r"
|
|
||||||
case ModeWrite: output = "w"
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (permission Permission) ToString () (output string) {
|
|
||||||
output += permission.Internal.ToString()
|
|
||||||
output += permission.External.ToString()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user