blob: 162205de4ca4947153eef43e8e048cd111342ec0 [file] [log] [blame]
Chris Luke90f52bf2016-09-12 08:55:13 -04001# Licensed under the Apache License, Version 2.0 (the "License");
2# you may not use this file except in compliance with the License.
3# You may obtain a copy of the License at:
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS,
9# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10# See the License for the specific language governing permissions and
11# limitations under the License.
12
Paul Vinciguerrab55aec12020-03-01 01:42:28 -050013import html
14import pyparsing as pp
Chris Luke90f52bf2016-09-12 08:55:13 -040015
16# Some useful primitives
17ident = pp.Word(pp.alphas + "_", pp.alphas + pp.nums + "_")
18intNum = pp.Word(pp.nums)
19hexNum = pp.Literal("0x") + pp.Word(pp.hexnums)
20octalNum = pp.Literal("0") + pp.Word("01234567")
21integer = (hexNum | octalNum | intNum) + \
22 pp.Optional(pp.Literal("ULL") | pp.Literal("LL") | pp.Literal("L"))
23floatNum = pp.Regex(r'\d+(\.\d*)?([eE]\d+)?') + pp.Optional(pp.Literal("f"))
24char = pp.Literal("'") + pp.Word(pp.printables, exact=1) + pp.Literal("'")
25arrayIndex = integer | ident
26
27lbracket = pp.Literal("(").suppress()
28rbracket = pp.Literal(")").suppress()
29lbrace = pp.Literal("{").suppress()
30rbrace = pp.Literal("}").suppress()
31comma = pp.Literal(",").suppress()
32equals = pp.Literal("=").suppress()
33dot = pp.Literal(".").suppress()
34semicolon = pp.Literal(";").suppress()
35
36# initializer := { [member = ] (variable | expression | { initializer } ) }
37typeName = ident
38varName = ident
39typeSpec = pp.Optional("unsigned") + \
40 pp.oneOf("int long short float double char u8 i8 void") + \
41 pp.Optional(pp.Word("*"), default="")
42typeCast = pp.Combine( "(" + ( typeSpec | typeName ) + ")" ).suppress()
43
44string = pp.Combine(pp.OneOrMore(pp.QuotedString(quoteChar='"',
45 escChar='\\', multiline=True)), adjacent=False)
46literal = pp.Optional(typeCast) + (integer | floatNum | char | string)
47var = pp.Combine(pp.Optional(typeCast) + varName +
48 pp.Optional("[" + arrayIndex + "]"))
49
50# This could be more complete, but suffices for our uses
51expr = (literal | var)
52
53"""Parse and render a block of text into a Python dictionary."""
54class Parser(object):
55 """Compiled PyParsing BNF"""
56 _parser = None
57
58 def __init__(self):
59 super(Parser, self).__init__()
60 self._parser = self.BNF()
61
62 def BNF(self):
63 raise NotImplementedError
64
65 def item(self, item):
66 raise NotImplementedError
67
68 def parse(self, input):
69 item = self._parser.parseString(input).asList()
70 return self.item(item)
71
72
73"""Parser for function-like macros - without the closing semi-colon."""
74class ParserFunctionMacro(Parser):
75 def BNF(self):
76 # VLIB_CONFIG_FUNCTION (unix_config, "unix")
77 macroName = ident
78 params = pp.Group(pp.ZeroOrMore(expr + comma) + expr)
79 macroParams = lbracket + params + rbracket
80
81 return macroName + macroParams
82
83 def item(self, item):
84 r = {
85 "macro": item[0],
86 "name": item[1][1],
87 "function": item[1][0],
88 }
89
90 return r
91
92
93"""Parser for function-like macros with a closing semi-colon."""
94class ParseFunctionMacroStmt(ParserFunctionMacro):
95 def BNF(self):
96 # VLIB_CONFIG_FUNCTION (unix_config, "unix");
97 function_macro = super(ParseFunctionMacroStmt, self).BNF()
98 mi = function_macro + semicolon
99 mi.ignore(pp.cppStyleComment)
100
101 return mi
102
103
104"""
105Parser for our struct initializers which are composed from a
Paul Vinciguerrab55aec12020-03-01 01:42:28 -0500106function-like macro, equals sign, and then a normal C struct initializer
Chris Luke90f52bf2016-09-12 08:55:13 -0400107block.
108"""
109class MacroInitializer(ParserFunctionMacro):
110 def BNF(self):
111 # VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
112 # .path = "show sr tunnel",
113 # .short_help = "show sr tunnel [name <sr-tunnel-name>]",
114 # .function = show_sr_tunnel_fn,
115 # };
116 cs = pp.Forward()
117
118
119 member = pp.Combine(dot + varName + pp.Optional("[" + arrayIndex + "]"),
120 adjacent=False)
121 value = (expr | cs)
122
123 entry = pp.Group(pp.Optional(member + equals, default="") + value)
124 entries = (pp.ZeroOrMore(entry + comma) + entry + pp.Optional(comma)) | \
125 (pp.ZeroOrMore(entry + comma))
126
127 cs << (lbrace + entries + rbrace)
128
129 macroName = ident
130 params = pp.Group(pp.ZeroOrMore(expr + comma) + expr)
131 macroParams = lbracket + params + rbracket
132
133 function_macro = super(MacroInitializer, self).BNF()
134 mi = function_macro + equals + pp.Group(cs) + semicolon
135 mi.ignore(pp.cppStyleComment)
136
137 return mi
138
139 def item(self, item):
140 r = {
141 "macro": item[0],
142 "name": item[1][0],
143 "params": item[2],
144 "value": {},
145 }
146
147 for param in item[2]:
Paul Vinciguerrab55aec12020-03-01 01:42:28 -0500148 r["value"][param[0]] = html.escape(param[1])
Chris Luke90f52bf2016-09-12 08:55:13 -0400149
150 return r