1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # A parser that create DocCommand from a string
17 # Used by both Nitx and the Markdown doc commands.
18 module commands_parser
20 import commands
::commands_model
21 import commands
::commands_graph
22 import commands
::commands_usage
23 import commands
::commands_catalog
25 # Parse string commands to create DocQueries
28 # ModelView used to retrieve mentities
31 # ModelBuilder used to retrieve AST nodes
32 var modelbuilder
: ModelBuilder
34 # Catalog used for catalog commands
35 var catalog
: nullable Catalog
37 # List of allowed command names for this parser
38 var allowed_commands
: Array[String] = [
39 "doc", "code", "lin", "uml", "graph", "search",
40 "parents", "ancestors", "children", "descendants",
41 "param", "return", "new", "call", "defs", "list", "random",
42 "catalog", "stats", "tags", "tag", "person", "contrib", "maintain"] is writable
44 # Parse `string` as a DocCommand
46 # Returns `null` if the string cannot be parsed.
47 # See `error` for the error messages produced by both the parser and the commands.
48 fun parse
(string
: String): nullable DocCommand do
50 var tmp
= new FlatBuffer
54 pos
= string
.read_until
(tmp
, pos
, ':')
55 var name
= tmp
.write_to_string
.trim
57 # Check allowed commands
59 error
= new CmdParserError("empty command name", 0)
62 if not allowed_commands
.has
(name
) then
63 error
= new CmdParserError("unknown command name", 0)
69 pos
= string
.read_until
(tmp
, pos
+ 1, '|')
70 var arg
= tmp
.write_to_string
.trim
72 # Parse command options
73 var opts
= new HashMap[String, String]
74 while pos
< string
.length
do
77 pos
= string
.read_until
(tmp
, pos
+ 1, ':', ',')
78 var oname
= tmp
.write_to_string
.trim
80 if oname
.is_empty
then break
82 if pos
< string
.length
and string
[pos
] == ':' then
84 pos
= string
.read_until
(tmp
, pos
+ 1, ',')
85 oval
= tmp
.write_to_string
.trim
91 var command
= new_command
(name
)
92 if command
== null then
93 error
= new CmdParserError("Unknown command name")
97 # Initialize command from string options
98 var status
= command
.parser_init
(arg
, opts
)
99 if not status
isa CmdSuccess then error
= status
104 # Init a new DocCommand from its `name`
106 # You must redefine this method to add new custom commands.
107 fun new_command
(name
: String): nullable DocCommand do
109 if name
== "doc" then return new CmdComment(view
)
110 if name
== "code" then return new CmdCode(view
, modelbuilder
)
111 if name
== "lin" then return new CmdLinearization(view
)
112 if name
== "defs" then return new CmdFeatures(view
)
113 if name
== "parents" then return new CmdParents(view
)
114 if name
== "ancestors" then return new CmdAncestors(view
)
115 if name
== "children" then return new CmdChildren(view
)
116 if name
== "descendants" then return new CmdDescendants(view
)
117 if name
== "param" then return new CmdParam(view
)
118 if name
== "return" then return new CmdReturn(view
)
119 if name
== "new" then return new CmdNew(view
, modelbuilder
)
120 if name
== "call" then return new CmdCall(view
, modelbuilder
)
122 if name
== "uml" then return new CmdUML(view
)
123 if name
== "graph" then return new CmdInheritanceGraph(view
)
125 if name
== "list" then return new CmdModelEntities(view
)
126 if name
== "random" then return new CmdRandomEntities(view
)
128 var catalog
= self.catalog
129 if catalog
!= null then
130 if name
== "catalog" then return new CmdCatalogPackages(view
, catalog
)
131 if name
== "stats" then return new CmdCatalogStats(view
, catalog
)
132 if name
== "tags" then return new CmdCatalogTags(view
, catalog
)
133 if name
== "tag" then return new CmdCatalogTag(view
, catalog
)
134 if name
== "person" then return new CmdCatalogPerson(view
, catalog
)
135 if name
== "contrib" then return new CmdCatalogContributing(view
, catalog
)
136 if name
== "maintain" then return new CmdCatalogMaintaining(view
, catalog
)
137 if name
== "search" then return new CmdCatalogSearch(view
, catalog
)
139 if name
== "search" then return new CmdSearch(view
)
144 # Error or warning from last call to `parse`
145 var error
: nullable CmdMessage = null
148 # An error produced by the CmdParser
155 # Column related to the error
156 var column
: nullable Int
158 redef fun to_s
do return message
161 redef class DocCommand
163 # Initialize the command from the CommandParser data
164 fun parser_init
(arg
: String, options
: Map[String, String]): CmdMessage do
169 redef class CmdEntity
170 redef fun parser_init
(mentity_name
, options
) do
171 self.mentity_name
= mentity_name
177 redef fun parser_init
(mentity_name
, options
) do
178 if options
.has_key
("limit") and options
["limit"].is_int
then limit
= options
["limit"].to_i
185 redef class CmdComment
186 redef fun parser_init
(mentity_name
, options
) do
187 full_doc
= not options
.has_key
("only-synopsis")
188 fallback
= not options
.has_key
("no-fallback")
189 if options
.has_key
("format") then format
= options
["format"]
195 redef fun parser_init
(mentity_name
, options
) do
196 if options
.has_key
("format") then format
= options
["format"]
201 redef class CmdSearch
202 redef fun parser_init
(mentity_name
, options
) do
204 if options
.has_key
("page") and options
["page"].is_int
then page
= options
["page"].to_i
209 redef class CmdAncestors
210 redef fun parser_init
(mentity_name
, options
) do
211 if options
.has_key
("parents") and options
["parents"] == "false" then parents
= false
216 redef class CmdDescendants
217 redef fun parser_init
(mentity_name
, options
) do
218 if options
.has_key
("children") and options
["children"] == "false" then children
= false
223 redef class CmdModelEntities
224 redef fun parser_init
(kind
, options
) do
231 redef fun parser_init
(mentity_name
, options
) do
232 if options
.has_key
("format") then format
= options
["format"]
237 redef class CmdInheritanceGraph
238 redef fun parser_init
(mentity_name
, options
) do
239 if options
.has_key
("pdepth") and options
["pdepth"].is_int
then
240 pdepth
= options
["pdepth"].to_i
242 if options
.has_key
("cdepth") and options
["cdepth"].is_int
then
243 cdepth
= options
["cdepth"].to_i
251 redef class CmdCatalogTag
252 redef fun parser_init
(mentity_name
, options
) do
258 redef class CmdCatalogPerson
259 redef fun parser_init
(mentity_name
, options
) do
260 person_name
= mentity_name
268 # Read `self` as raw text until `nend` and append it to the `out` buffer.
269 private fun read_until
(out
: FlatBuffer, start
: Int, nend
: Char...): Int do
271 while pos
< length
do
273 var end_reached
= false
280 if end_reached
then break