# This file is part of NIT ( http://www.nitlanguage.org ). # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Parsing of commands understood by documentation tools. # # This can be through: # * `nitx` commands like `code: MEntity::name` # * `nitdoc` wikilinks like `[[doc: MEntity::name]]` module doc_commands # class DocCommandParser # List of allowed command names for this parser var allowed_commands: Array[String] = [ "doc", "list", "param", "return", "new", "call", "code", "graph"] is writable # Parse `string` as a DocCommand # # Returns `null` if the string cannot be parsed. # # ~~~ # var parser = new DocCommandParser # # var command = parser.parse("doc: core::Array") # assert command isa CommentCommand # assert command.arg == "core::Array" # # command = parser.parse(":") # syntax error # assert command == null # assert parser.errors.not_empty # ~~~ fun parse(string: String): nullable DocCommand do var pos = 0 var tmp = new FlatBuffer errors.clear # Parse command name pos = string.read_until(tmp, pos, ':') var name = tmp.write_to_string.trim # Check allowed commands if name.is_empty then error("empty command name", 0) return null end if not allowed_commands.has(name) then error("unknown command name", 0) return null end # Build the command var command = new_command(name, string) if command == null then error("unknown command name", 0) return null end # Parse the argument tmp.clear pos = string.read_until(tmp, pos + 1, '|') var arg = tmp.write_to_string.trim if arg.is_empty then error("empty command arg", pos) return null end command.arg = arg # Parse command options while pos < string.length do # Parse option name tmp.clear pos = string.read_until(tmp, pos + 1, ':', ',') var oname = tmp.write_to_string.trim var oval = "" if oname.is_empty then break # Parse option value if pos < string.length and string[pos] == ':' then tmp.clear pos = string.read_until(tmp, pos + 1, ',') oval = tmp.write_to_string.trim end command.opts[oname] = oval # TODO Check options end return command end # Init a new DocCommand from its `name` # # You must redefine this method to add new custom commands. fun new_command(name, string: String): nullable DocCommand do if name == "doc" then return new CommentCommand(string) if name == "list" then return new ListCommand(string) if name == "param" then return new ParamCommand(string) if name == "return" then return new ReturnCommand(string) if name == "new" then return new NewCommand(string) if name == "call" then return new CallCommand(string) if name == "code" then return new CodeCommand(string) if name == "graph" then return new GraphCommand(string) return null end # Errors and warnings from last call to `parse` var errors = new Array[DocMessage] # Generate an error fun error(message: String, col: nullable Int) do errors.add new DocMessage(1, message, col) end # Generate a warning fun warning(message: String, col: nullable Int) do errors.add new DocMessage(2, message, col) end end # A message generated by the DocCommandParser class DocMessage # Message severity # # 1- Error # 2- Warning var level: Int # Message explanatory string var message: String # Related column in original string if any var col: nullable Int redef fun to_s do var str = new FlatBuffer if level == 1 then str.append "Error: " else str.append "Warning: " end str.append message var col = self.col if col != null then str.append " (col: {col})" end return str.write_to_string end end redef class Text # Read `self` as raw text until `nend` and append it to the `out` buffer. private fun read_until(out: FlatBuffer, start: Int, nend: Char...): Int do var pos = start while pos < length do var c = self[pos] var end_reached = false for n in nend do if c == n then end_reached = true break end end if end_reached then break out.add c pos += 1 end return pos end end # A command aimed at a documentation tool like `nitdoc` or `nitx`. # # `DocCommand` are generally of the form `command: arg | opt1: val1, opt2: val2`. abstract class DocCommand # Original command string. var string: String # Command name. var name: String is noinit # Command arguments. var arg: String is noinit, writable # Command options. var opts = new HashMap[String, String] is writable redef fun to_s do if opts.is_empty then return "{name}: {arg}" end return "{name}: {arg} | {opts.join(", ", ": ")}" end end # A `DocCommand` that includes the documentation article of a `MEntity`. # # Syntax: `doc: MEntity::name`. class CommentCommand super DocCommand redef var name = "doc" end # A `DocCommand` that includes a list of something. # # Syntax: `list:kind: `. class ListCommand super DocCommand redef var name = "list" end # A `DocCommand` that includes the list of methods tanking a `MType` as parameter. # # Syntax: `param: MType`. class ParamCommand super DocCommand redef var name = "param" end # A `DocCommand` that includes the list of methods returning a `MType` as parameter. # # Syntax: `return: MType`. class ReturnCommand super DocCommand redef var name = "return" end # A `DocCommand` that includes the list of methods creating new instances of a specific `MType` # # Syntax: `new: MType`. class NewCommand super DocCommand redef var name = "new" end # A `DocCommand` that includes the list of methods calling a specific `MProperty`. # # Syntax: `call: MEntity::name`. class CallCommand super DocCommand redef var name = "call" end # A `DocCommand` that includes the source code of a `MEntity`. # # Syntax: # * `code: MEntity::name` # * `./src/file.nit` to include source code from a file. # * `./src/file.nit:1,2--3,4` to select code between positions. class CodeCommand super DocCommand redef var name = "code" end # A `DocCommand` that display an graph for a `MEntity`. # # Syntax: # * `graph: MEntity::name` class GraphCommand super DocCommand redef var name = "graph" end