From 0fcd2d8e0e8f3f9912f17cb9fb12d911014e2a2f Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Tue, 26 Oct 2021 16:44:41 -0400 Subject: [PATCH] Add lexer/detector for zed Reference: https://docs.authzed.com/reference/schema-lang Used by project SpiceDB (https://github.com/authzed/spicedb), a database system for managing security-critical permissions checking, inspired by Google's Zanzibar paper --- lexers/testdata/zed.actual | 29 ++++++ lexers/testdata/zed.expected | 175 +++++++++++++++++++++++++++++++++++ lexers/z/zed.go | 53 +++++++++++ 3 files changed, 257 insertions(+) create mode 100644 lexers/testdata/zed.actual create mode 100644 lexers/testdata/zed.expected create mode 100644 lexers/z/zed.go diff --git a/lexers/testdata/zed.actual b/lexers/testdata/zed.actual new file mode 100644 index 0000000..e51ab5d --- /dev/null +++ b/lexers/testdata/zed.actual @@ -0,0 +1,29 @@ +/** + * Project is a project. + */ +definition test/project { + relation issue_creator: role#member + relation issue_assigner: role#member + relation any_issue_resolver: role#member + relation assigned_issue_resolver: role#member + relation comment_creator: role#member + relation comment_deleter: role#member + relation role_manager: role#member + + permission create_issue = issue_creator + permission create_role = role_manager +} + +definition role { + /** project is the project */ + relation project: project + relation member: user + relation built_in_role: project + + permission delete = project->role_manager - built_in_role->role_manager + permission add_user = project->role_manager + permission add_permission = project->role_manager & built_in_role->role_manager + + // with arrows! + permission remove_permission = project->role_manager + built_in_role->role_manager +} \ No newline at end of file diff --git a/lexers/testdata/zed.expected b/lexers/testdata/zed.expected new file mode 100644 index 0000000..3336a31 --- /dev/null +++ b/lexers/testdata/zed.expected @@ -0,0 +1,175 @@ +[ + {"type":"CommentMultiline","value":"/**\n * Project is a project.\n */"}, + {"type":"TextWhitespace","value":"\n"}, + {"type":"KeywordType","value":"definition"}, + {"type":"TextWhitespace","value":" "}, + {"type":"NameNamespace","value":"test/"}, + {"type":"Name","value":"project"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Punctuation","value":"{"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"issue_creator"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"NameVariable","value":"#member"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"issue_assigner"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"NameVariable","value":"#member"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"any_issue_resolver"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"NameVariable","value":"#member"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"assigned_issue_resolver"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"NameVariable","value":"#member"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"comment_creator"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"NameVariable","value":"#member"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"comment_deleter"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"NameVariable","value":"#member"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role_manager"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"NameVariable","value":"#member"}, + {"type":"TextWhitespace","value":"\n\t\n\t"}, + {"type":"KeywordDeclaration","value":"permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"create_issue"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"="}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"issue_creator"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordDeclaration","value":"permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"create_role"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"="}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":"\n"}, + {"type":"Punctuation","value":"}"}, + {"type":"TextWhitespace","value":"\n\n"}, + {"type":"KeywordType","value":"definition"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"role"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Punctuation","value":"{"}, + {"type":"TextWhitespace","value":"\n "}, + {"type":"CommentMultiline","value":"/** project is the project */"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"project"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"project"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"member"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"user"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordNamespace","value":"relation"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"built_in_role"}, + {"type":"Operator","value":":"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"project"}, + {"type":"TextWhitespace","value":"\n\t\n\t"}, + {"type":"KeywordDeclaration","value":"permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"delete"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"="}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"project"}, + {"type":"Operator","value":"-\u003e"}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"-"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"built_in_role"}, + {"type":"Operator","value":"-\u003e"}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordDeclaration","value":"permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"add_user"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"="}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"project"}, + {"type":"Operator","value":"-\u003e"}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":"\n\t"}, + {"type":"KeywordDeclaration","value":"permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"add_permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"="}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"project"}, + {"type":"Operator","value":"-\u003e"}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"\u0026"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"built_in_role"}, + {"type":"Operator","value":"-\u003e"}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":"\n\n "}, + {"type":"CommentSingle","value":"// with arrows!\n"}, + {"type":"TextWhitespace","value":"\t"}, + {"type":"KeywordDeclaration","value":"permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"remove_permission"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"="}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"project"}, + {"type":"Operator","value":"-\u003e"}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Operator","value":"+"}, + {"type":"TextWhitespace","value":" "}, + {"type":"Name","value":"built_in_role"}, + {"type":"Operator","value":"-\u003e"}, + {"type":"Name","value":"role_manager"}, + {"type":"TextWhitespace","value":"\n"}, + {"type":"Punctuation","value":"}"} +] diff --git a/lexers/z/zed.go b/lexers/z/zed.go new file mode 100644 index 0000000..5479a2c --- /dev/null +++ b/lexers/z/zed.go @@ -0,0 +1,53 @@ +package z + +import ( + "strings" + + . "github.com/alecthomas/chroma" // nolint + "github.com/alecthomas/chroma/lexers/internal" +) + +// Zed lexer. +var Zed = internal.Register(MustNewLazyLexer( + &Config{ + Name: "Zed", + Aliases: []string{"zed"}, + Filenames: []string{"*.zed"}, + MimeTypes: []string{"text/zed"}, + }, + zedRules, +).SetAnalyser(func(text string) float32 { + if strings.Contains(text, "definition ") && strings.Contains(text, "relation ") && strings.Contains(text, "permission ") { + return 0.9 + } + if strings.Contains(text, "definition ") { + return 0.5 + } + if strings.Contains(text, "relation ") { + return 0.5 + } + if strings.Contains(text, "permission ") { + return 0.25 + } + return 0.0 +})) + +func zedRules() Rules { + return Rules{ + "root": { + {`\n`, TextWhitespace, nil}, + {`\s+`, TextWhitespace, nil}, + {`//.*?\n`, CommentSingle, nil}, + {`/(\\\n)?[*][\w\W]*?[*](\\\n)?/`, CommentMultiline, nil}, + {`/(\\\n)?[*][\w\W]*`, CommentMultiline, nil}, + {Words(``, `\b`, `definition`), KeywordType, nil}, + {Words(``, `\b`, `relation`), KeywordNamespace, nil}, + {Words(``, `\b`, `permission`), KeywordDeclaration, nil}, + {`[a-zA-Z_]\w*/`, NameNamespace, nil}, + {`[a-zA-Z_]\w*`, Name, nil}, + {`#[a-zA-Z_]\w*`, NameVariable, nil}, + {`[+%=><|^!?/\-*&~:]`, Operator, nil}, + {`[{}()\[\],.;]`, Punctuation, nil}, + }, + } +}