Skip to content

Commit

Permalink
Add tests for incomplete script definitions, incomplete arrays, incom…
Browse files Browse the repository at this point in the history
…plete structs, incomplete backticked identifiers
  • Loading branch information
byxor committed Apr 9, 2022
1 parent 29d0941 commit 5b84340
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 20 deletions.
16 changes: 11 additions & 5 deletions compiler/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,15 +246,15 @@ func LexSourceCode(lexer *Lexer) Error { // do lexical analysis (build an array
}
}

CanFindIdentifier := func() (string, bool) {
CanFindIdentifier := func() (string, bool, error) {
start := lexer.Index
end := start

if lexer.SourceCode[start] == '`' {
end++
for {
if end >= len(lexer.SourceCode) {
break
return "", true, errors.New("EOF while scanning identifier (`)")
}
if lexer.SourceCode[end] == '`' {
end++
Expand All @@ -263,7 +263,7 @@ func LexSourceCode(lexer *Lexer) Error { // do lexical analysis (build an array
end++
}

return lexer.SourceCode[start:end], end != start + 1
return lexer.SourceCode[start:end], end != start + 1, nil
} else {
for {
if end >= len(lexer.SourceCode) {
Expand All @@ -277,7 +277,7 @@ func LexSourceCode(lexer *Lexer) Error { // do lexical analysis (build an array
end++
}

return lexer.SourceCode[start:end], start != end
return lexer.SourceCode[start:end], start != end, nil
}
}

Expand Down Expand Up @@ -414,7 +414,13 @@ func LexSourceCode(lexer *Lexer) Error { // do lexical analysis (build an array
} else if CanFindKeyword("return", true) {
SaveToken(lexer, TokenKind_Return, "return")
lexer.Index += 6
} else if identifier, found := CanFindIdentifier(); found {
} else if identifier, found, err := CanFindIdentifier(); found {
if err != nil {
return CompilationError{
message: err.Error(),
lineNumber: lexer.LineNumber,
}
}
if identifier[0] == '`' && identifier[len(identifier)-1] == '`' {
identifier = identifier[1:len(identifier)-1]
lexer.Index += 2
Expand Down
47 changes: 32 additions & 15 deletions compiler/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func BuildAbstractSyntaxTree(parser *Parser) {

return ParseResult{
GotResult: false,
Reason: TokensNotRecognisedError(parser.Tokens[index:], "a root body node"),
//Reason: TokensNotRecognisedError(parser.Tokens[index:], "a root body node"),
}
}

Expand Down Expand Up @@ -257,7 +257,7 @@ func BuildAbstractSyntaxTree(parser *Parser) {
}
return ParseResult{
GotResult: false,
Reason: TokensNotRecognisedError(parser.Tokens[index:], "an expression"),
//Reason: TokensNotRecognisedError(parser.Tokens[index:], "an expression"),
LineNumber: GetToken(index - 1).LineNumber,
}
}
Expand Down Expand Up @@ -689,6 +689,7 @@ func BuildAbstractSyntaxTree(parser *Parser) {
}

ParseArray = func(index int) ParseResult {
startIndex := index
index++

// gather array elements
Expand All @@ -697,25 +698,26 @@ func BuildAbstractSyntaxTree(parser *Parser) {
if GetKind(index) == TokenKind_BackwardSlash && GetKind(index+1) == TokenKind_NewLine {
index += 2
elementNodes.TokensConsumed += 2
}
if GetKind(index) == TokenKind_RightSquareBracket {
} else if GetKind(index) == TokenKind_RightSquareBracket {
break
}
if GetKind(index) == TokenKind_SingleLineComment || GetKind(index) == TokenKind_MultiLineComment {
} else if GetKind(index) == TokenKind_SingleLineComment || GetKind(index) == TokenKind_MultiLineComment {
index++
elementNodes.TokensConsumed++
}
if newLineParseResult := ParseNewLine(index); newLineParseResult.GotResult {
} else if newLineParseResult := ParseNewLine(index); newLineParseResult.GotResult {
elementNodes.MaybeSave(newLineParseResult)
index += newLineParseResult.TokensConsumed
}
if commaParseResult := ParseComma(index); commaParseResult.GotResult {
} else if commaParseResult := ParseComma(index); commaParseResult.GotResult {
elementNodes.MaybeSave(commaParseResult)
index += commaParseResult.TokensConsumed
}
if expressionParseResult := ParseExpression(index, true); expressionParseResult.GotResult {
} else if expressionParseResult := ParseExpression(index, true); expressionParseResult.GotResult {
elementNodes.MaybeSave(expressionParseResult)
index += expressionParseResult.TokensConsumed
} else {
return ParseResult{
GotResult: true,
Error: errors.New("Incomplete array"),
LineNumber: GetToken(startIndex).LineNumber,
}
}
}

Expand All @@ -741,6 +743,8 @@ func BuildAbstractSyntaxTree(parser *Parser) {
}
}

startIndex := index

index++
indexAfterLastIteration := index
for { // gather struct elements
Expand Down Expand Up @@ -779,7 +783,9 @@ func BuildAbstractSyntaxTree(parser *Parser) {
index += parseResult.TokensConsumed
} else if index == indexAfterLastIteration {
return ParseResult{
GotResult: false,
GotResult: true,
Error: errors.New("Incomplete struct"),
LineNumber: GetToken(startIndex).LineNumber,
Reason: TokensNotRecognisedError(parser.Tokens[index:], "a struct element"),
}
}
Expand Down Expand Up @@ -954,7 +960,9 @@ func BuildAbstractSyntaxTree(parser *Parser) {

if GetKind(index) != TokenKind_Identifier && GetKind(index) != TokenKind_RawChecksum {
return ParseResult{
GotResult: false,
GotResult: true,
Error: errors.New("Incomplete script definition"),
LineNumber: GetToken(index-1).LineNumber,
Reason: "Second token in script wasn't an identifier or a checksum",
}
}
Expand All @@ -976,7 +984,9 @@ func BuildAbstractSyntaxTree(parser *Parser) {
bodyParseResult, bodyNodes := ParseBodyOfCode(index)
if !bodyParseResult.GotResult {
return ParseResult{
GotResult: false,
GotResult: true,
Error: errors.New("Incomplete script definition"),
LineNumber: GetToken(index - 1).LineNumber,
Reason: WrapStr("Couldn't parse script body", bodyParseResult.Reason),
}
} else if bodyParseResult.Error != nil {
Expand Down Expand Up @@ -1170,6 +1180,8 @@ func BuildAbstractSyntaxTree(parser *Parser) {
if GetKind(index) != TokenKind_LeftCurlyBrace {
return ParseResult{
GotResult: false,
Error: errors.New("Incomplete script definition"),
LineNumber: GetToken(startIndex).LineNumber,
Reason: "First token in body of code wasn't '{'",
}, []AstNode{}
}
Expand All @@ -1178,6 +1190,11 @@ func BuildAbstractSyntaxTree(parser *Parser) {
var bodyNodes AstNodeBuffer
for {
if GetKind(index) == TokenKind_OutOfRange {
return ParseResult{
GotResult: true,
Error: errors.New("Incomplete script definition"),
LineNumber: GetToken(startIndex).LineNumber,
}, []AstNode{}
break
} else if GetKind(index) == TokenKind_RightCurlyBrace {
index++
Expand Down
131 changes: 131 additions & 0 deletions compiler/tests/verify_error_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ func main() {
}
}

// check(UnknownEscapeSequenceInString)
check(IncompleteBacktickedIdentifier)
check(IncompleteStruct)
check(IncompleteArray)
check(IncompleteScript)
check(ExtraParenthesis)
check(IncompleteVector)
check(IncompletePair)
Expand All @@ -45,6 +50,132 @@ func main() {
check(EOFWhileScanningStringLiteral)
}

func IncompleteBacktickedIdentifier() error {
expectedMessage = "EOF while scanning identifier (`)"

code = "`x"
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `script Foo {
cas_item = `+"`"+`kneepad shorts
}`
expectedLineNumber = 2
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

return nil
}

func IncompleteStruct() error {
expectedMessage = "Incomplete struct"

code = `x = {`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `x = {
y = {
z = {
}
}`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `x = 1
y = { "struct", "requires", "closing", "}"
`
expectedLineNumber = 2
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

return nil
}

func IncompleteArray() error {
expectedMessage = "Incomplete array"

code = `x = [`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `x = [1, 2, 3, 4`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `x = 5
y = [
1`
expectedLineNumber = 2
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `x = [1, 2, 3, 4]
y = [
1 2 3,4 \`
expectedLineNumber = 2
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

return nil
}

func IncompleteScript() error {
expectedMessage = "Incomplete script definition"

code = `script`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `script Foo {}
script Bar {}
script Baz { x = 10 }
script`
expectedLineNumber = 4
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `script Foo`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `script Foo text=""`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `script Foo text="" {`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `script Foo {
Bar
`
expectedLineNumber = 1
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

code = `script Foo {}
script Bar x=1 y=(2.0, 3.0) z="wow" {
Stuff \
goes=here \
so={it does}
`
expectedLineNumber = 2
err = compileAndCheckError(checkMessageAndLineNumber)
if err != nil { return err }

return nil
}

func ExtraParenthesis() error {
expectedMessage = "Unnecessary parenthesis )"

Expand Down

0 comments on commit 5b84340

Please sign in to comment.