1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
module Rouge
module Lexers
class Bicep < Rouge::RegexLexer
tag 'bicep'
filenames '*.bicep'
title "Bicep"
desc 'Bicep is a domain-specific language (DSL) that uses declarative syntax to deploy Azure resources.'
def self.keywords
@keywords ||= Set.new %w(
as assert existing extends extension false for from func if import in metadata module
none null output param provider resource targetScope test true type using var void with
)
end
def self.datatypes
@datatypes ||= Set.new %w(array bool int object string)
end
def self.functions
@functions ||= Set.new %w(
array base64 base64ToJson base64ToString bool cidrHost cidrSubnet concat contains dataUri
dataUriToString dateTimeAdd dateTimeFromEpoch dateTimeToEpoch deployer deployment empty endsWith
environment extensionResourceId fail filter first flatten format getSecret groupBy guid indexOf int
intersection items join json last lastIndexOf length list* listAccountSas listKeys listSecrets loadFileAsBase64
loadJsonContent loadTextContent loadYamlContent managementGroup managementGroupResourceId map mapValue max min
newGuid objectKeys padLeft parseCidr pickZones range readEnvironmentVariable reduce reference replace resourceGroup
resourceId shallowMerge skip sort split startsWith string subscription subscriptionResourceId substring take tenant
tenantResourceId toLogicalZone toLower toObject toPhysicalZone toUpper trim union uniqueString uri uriComponent
uriComponentToString utcNow
)
end
operators = %w(+ - * / % < <= > >= == != =~ !~ && || ! ?? ... .?)
punctuations = %w(( ) { } [ ] , : ; = .)
state :root do
mixin :comments
# Match strings
rule %r/'/, Str::Single, :string
# Match numbers
rule %r/\b\d+\b/, Num
# Rules for sets of reserved keywords
rule %r/\b\w+\b/ do |m|
if self.class.keywords.include? m[0]
token Keyword
elsif self.class.datatypes.include? m[0]
token Keyword::Type
elsif self.class.functions.include? m[0]
token Name::Function
else
token Name
end
end
# Match operators
rule %r/#{operators.map { |o| Regexp.escape(o) }.join('|')}/, Operator
# Enter a state when encountering an opening curly bracket
rule %r/{/, Punctuation::Indicator, :block
# Match punctuation
rule %r/#{punctuations.map { |p| Regexp.escape(p) }.join('|')}/, Punctuation
# Match identifiers
rule %r/[a-zA-Z_]\w*/, Name
# Match decorators
rule %r/@[a-zA-Z_]\w*/, Name::Decorator
# Ignore whitespace
rule %r/\s+/, Text
end
state :comments do
rule %r(//[^\n\r]+), Comment::Single
rule %r(/\*.*?\*/)m, Comment::Multiline
end
state :string do
rule %r/[^'$}]+/, Str::Single
rule %r/\$(?!\{)/, Str::Single
rule %r/\$[\{]/, Str::Interpol, :interp
rule %r/\'/, Str::Single, :pop!
rule %r/\$+/, Str::Single
end
state :interp do
rule %r/\}/, Str::Interpol, :pop!
mixin :root
end
# State for matching code blocks between curly brackets
state :block do
# Match property names
rule %r/\b([a-zA-Z_]\w*)\b(?=\s*:)/, Name::Property
# Match closing curly brackets
rule %r/}/, Punctuation::Indicator, :pop!
# Include the root state for nested tokens
mixin :root
end
end
end
end
|