Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat: add nil token to allow nil permission expressions #1633

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pkg/dsl/lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,13 @@ func (l *Lexer) NextToken() (tok token.Token) {
if isLetter(l.ch) {
tok.PositionInfo = positionInfo(l.linePosition, l.columnPosition)
tok.Literal = l.lexIdent()
if tok.Literal == "true" || tok.Literal == "false" {
switch tok.Literal {
case "true", "false":
tok.Type = token.BOOLEAN
return
case "nil":
tok.Type = token.NIL
return
}
tok.Type = token.LookupKeywords(tok.Literal)
return
Expand Down
92 changes: 92 additions & 0 deletions pkg/dsl/lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -980,5 +980,97 @@ rule check_ip_address(ip_addresses string[]) {
Expect(index + lexeme.Literal).Should(Equal(index + tt.expectedLiteral))
}
})

It("Case 10", func() {
str := `
entity user {}

entity organization {
relation admin @user
relation member @user

action create_repository = nil
action delete = nil
}

`

tests := []struct {
expectedType token.Type
expectedLiteral string
}{
{token.NEWLINE, "\n"},
{token.ENTITY, "entity"},
{token.SPACE, " "},
{token.IDENT, "user"},
{token.SPACE, " "},
{token.LCB, "{"},
{token.RCB, "}"},
{token.NEWLINE, "\n"},
{token.NEWLINE, "\n"},
// --
{token.ENTITY, "entity"},
{token.SPACE, " "},
{token.IDENT, "organization"},
{token.SPACE, " "},
{token.LCB, "{"},
{token.NEWLINE, "\n"},
// --
{token.TAB, "\t"},
{token.RELATION, "relation"},
{token.SPACE, " "},
{token.IDENT, "admin"},
{token.SPACE, " "},
{token.SIGN, "@"},
{token.IDENT, "user"},
{token.NEWLINE, "\n"},
// --
{token.SPACE, " "},
{token.SPACE, " "},
{token.SPACE, " "},
{token.SPACE, " "},
{token.RELATION, "relation"},
{token.SPACE, " "},
{token.IDENT, "member"},
{token.SPACE, " "},
{token.SIGN, "@"},
{token.IDENT, "user"},
{token.NEWLINE, "\n"},
{token.NEWLINE, "\n"},
// --
{token.TAB, "\t"},
{token.PERMISSION, "action"},
{token.SPACE, " "},
{token.IDENT, "create_repository"},
{token.SPACE, " "},
{token.ASSIGN, "="},
{token.SPACE, " "},
{token.NIL, "nil"},
{token.NEWLINE, "\n"},
// --
{token.TAB, "\t"},
{token.PERMISSION, "action"},
{token.SPACE, " "},
{token.IDENT, "delete"},
{token.SPACE, " "},
{token.ASSIGN, "="},
{token.SPACE, " "},
{token.NIL, "nil"},
{token.NEWLINE, "\n"},
{token.RCB, "}"},
{token.NEWLINE, "\n"},
{token.NEWLINE, "\n"},
// --
}

l := NewLexer(str)

for i, tt := range tests {
lexeme := l.NextToken()
index := strconv.Itoa(i) + ": "
Expect(index + lexeme.Type.String()).Should(Equal(index + tt.expectedType.String()))
Expect(index + lexeme.Literal).Should(Equal(index + tt.expectedLiteral))
}
})
})
})
3 changes: 2 additions & 1 deletion pkg/dsl/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ func NewParser(str string) (p *Parser) {
references: ast.NewReferences(), // initialize an empty map for relational references
}

// register prefix parsing functions for token types IDENT and NOT
// register prefix parsing functions for token types IDENT and NIL
p.prefixParseFns = make(map[token.Type]prefixParseFn) // initialize an empty map for prefix parsing functions
p.registerPrefix(token.IDENT, p.parseIdentifierOrCall) // associate the parseIdentifier function with the IDENT token type
p.registerPrefix(token.NIL, p.parseIdentifierOrCall)

// register infix parsing functions for token types AND, OR, NOT
p.infixParseFunc = make(map[token.Type]infixParseFn) // initialize an empty map for infix parsing functions
Expand Down
17 changes: 17 additions & 0 deletions pkg/dsl/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1041,5 +1041,22 @@ rule confidentiality_level_low(confidentiality_level double) {
// Ensure the error message contains the expected string
Expect(err.Error()).Should(ContainSubstring("7:15:expected token to be RELATION, PERMISSION, ATTRIBUTE, got OR instead"))
})

It("Case 30 - Nil Permission", func() {
pr := NewParser(`
entity account {
relation owner @user
relation admin @user

action check_balance = nil

permission withdraw = nil
}
`)

_, err := pr.Parse()
// Ensure an error is not returned
Expect(err).ShouldNot(HaveOccurred())
})
})
})
1 change: 1 addition & 0 deletions pkg/dsl/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const (
INTEGER = "INTEGER"
DOUBLE = "DOUBLE"
BOOLEAN = "BOOLEAN"
NIL = "NIL"

/*
Symbols
Expand Down
Loading