diff --git a/pkg/dsl/parser/parser.go b/pkg/dsl/parser/parser.go index 4e94a0e4..31e8f494 100644 --- a/pkg/dsl/parser/parser.go +++ b/pkg/dsl/parser/parser.go @@ -33,6 +33,8 @@ type Parser struct { l *lexer.Lexer // the current token being processed currentToken token.Token + // the token before currentToken + previousToken token.Token // the next token after currentToken peekToken token.Token // a slice of error messages that are generated during parsing @@ -82,6 +84,8 @@ func (p *Parser) next() { peek := p.l.NextToken() // if the token is not an ignored token (e.g. whitespace or comments), update the currentToken and peekToken fields and exit the loop if !token.IsIgnores(peek.Type) { + // set the previousToken before changing currentToken + p.previousToken = p.currentToken // set the currentToken field to the previous peekToken value p.currentToken = p.peekToken // set the peekToken field to the new peek value @@ -118,6 +122,18 @@ func (p *Parser) currentTokenIs(tokens ...token.Type) bool { return false } +// previousTokenIs checks if the Parser's previousToken type is any of the given types +func (p *Parser) previousTokenIs(tokens ...token.Type) bool { + for _, t := range tokens { + if p.previousToken.Type == t { + // if a match is found, return true + return true + } + } + // if no match is found, return false + return false +} + // peekTokenIs checks if the Parser's peekToken is any of the given token types func (p *Parser) peekTokenIs(tokens ...token.Type) bool { // iterate through the given token types and check if any of them match the peekToken's type @@ -588,7 +604,7 @@ func (p *Parser) parseExpression(precedence int) (ast.Expression, error) { var exp ast.Expression var err error - if p.currentTokenIs(token.NEWLINE) { + if p.currentTokenIs(token.NEWLINE) && p.previousTokenIs(token.LP, token.AND, token.OR, token.IN, token.NOT, token.ASSIGN) { // advance to the next token p.next() } diff --git a/pkg/dsl/parser/parser_test.go b/pkg/dsl/parser/parser_test.go index b47b7be2..7a0de6ee 100644 --- a/pkg/dsl/parser/parser_test.go +++ b/pkg/dsl/parser/parser_test.go @@ -896,5 +896,24 @@ var _ = Describe("parser", func() { Expect(rs1.Name.Literal).Should(Equal("check_balance")) Expect(rs1.Expression).Should(Equal("\nbalance >= amount && amount <= 5000\n\t\t")) }) + + It("Case 25 - Multi-line Permission Expression w/ Rule - should fail", func() { + pr := NewParser(` + entity account { + relation owner @user + attribute balance float + + permission withdraw = check_balance(request.amount, balance) + owner + } + + rule check_balance(amount float, balance float) { + balance >= amount && amount <= 5000 + } + `) + + _, err := pr.Parse() + Expect(err).Should(HaveOccurred()) + }) }) })