add support for detecting lapis routes

This commit is contained in:
leaf corcoran 2023-06-23 09:33:37 -07:00
parent 524d64ffd3
commit fbd8ad4873

View File

@ -17,13 +17,14 @@ argparse = require "argparse"
parser = argparse "moon-tags", "Generate ctags style tags file for MoonScript files" parser = argparse "moon-tags", "Generate ctags style tags file for MoonScript files"
parser\argument("files", "MoonScript files to generate tags for")\args "+" parser\argument("files", "MoonScript files to generate tags for")\args "+"
parser\flag "--include-line", "Include line number field for each tag" parser\flag "--include-line", "Include line number field for each tag"
parser\flag "--lapis", "Support extracting lapis routes"
args = parser\parse [v for _, v in ipairs _G.arg] args = parser\parse [v for _, v in ipairs _G.arg]
TAGS = {} -- the final output of tags TAGS = {} -- the final output of tags
literals = require "moonscript.parse.literals" literals = require "moonscript.parse.literals"
import Indent from require "moonscript.parse.util" import Indent, simple_string from require "moonscript.parse.util"
import P, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg" import P, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg"
@ -32,18 +33,20 @@ until_end = (1 - literals.Stop)^0
whitespace = S"\t " -- not including newline whitespace = S"\t " -- not including newline
ignore_line = Ct until_end -- tag it for empty line ignore_line = Ct until_end -- tag it for empty line
-- NOTE: we disable interpolation parsing since we don't have full grammar
SingleString = simple_string "'", false
DoubleString = simple_string '"', false
String = SingleString + DoubleString
-- we have to do this double Ct to capture both the full line and the grouped captures -- we have to do this double Ct to capture both the full line and the grouped captures
Type = (name) -> Cg Cc(name), "type" Type = (name) -> Cg Cc(name), "type"
Line = (type_name, p) -> Ct C Ct Cg(Indent, "indent") * p * Type type_name Line = (type_name, p) -> Ct C Ct Cg(Indent, "indent") * p * Type type_name
class_line = Line "class", P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end
-- TODO: support lapis style routes
-- class_property = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * until_end * Type "property"
method = P { P"=>" + P(1 - literals.Stop) * V(1) } method = P { P"=>" + P(1 - literals.Stop) * V(1) }
func = P { P"->" + P"=>" + P(1 - literals.Stop) * V(1) } func = P { P"->" + P"=>" + P(1 - literals.Stop) * V(1) }
self_prefix = Cg(P("@") * Cc(true), "self")
-- this matches end-of-file return table convention for module files to figure -- this matches end-of-file return table convention for module files to figure
-- out what names are exported -- out what names are exported
export_list = Ct P"{" * P { export_list = Ct P"{" * P {
@ -52,17 +55,37 @@ export_list = Ct P"{" * P {
eof_exports = P { export_list * S(" \t\r\n")^0 * P(-1) + P(1) * V(1) } eof_exports = P { export_list * S(" \t\r\n")^0 * P(-1) + P(1) * V(1) }
class_line = Line "class", P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end
class_property = Line "property", self_prefix^-1 * Cg(literals.Name, "tag") * P":" * whitespace^0 * Cg(String, "value")^0 * until_end
class_method = Line("method", P("@")^-1 * Cg(literals.Name, "tag") * P":" * method) * until_end class_method = Line("method", P("@")^-1 * Cg(literals.Name, "tag") * P":" * method) * until_end
function_def = Line("function", Cg(literals.Name, "tag") * whitespace^0 * P"=" * func) * until_end function_def = Line("function", Cg(literals.Name, "tag") * whitespace^0 * P"=" * func) * until_end
lapis_route = Line "lapis-route", P"[" * Cg(literals.Name, "tag") * P":" * whitespace^0 * Cg(String, "route") * whitespace^0 * P("]:") * until_end
line_types = class_line + class_method + class_property + function_def
if args.lapis
line_types += lapis_route
parse_lines = Ct P { parse_lines = Ct P {
(class_line + class_method + function_def + ignore_line) * (P(-1) + literals.Break * V(1)) (line_types + ignore_line) * (P(-1) + literals.Break * V(1))
} }
escape_tagaddress = (line_text) -> escape_tagaddress = (line_text) ->
replacements = S([[\/.$^]]) / [[\%0]]+ P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]] replacements = S([[\/.$^]]) / [[\%0]]+ P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]]
Cs((replacements + 1)^0)\match line_text Cs((replacements + 1)^0)\match line_text
import types from require "tableshape"
class_field = types.partial {
"self": true
tag: types.string\tag "name"
value: types.partial {
"string"
types.string
types.string\tag "value" -- TODO: will need to un-escape this
}
}
for fname in *args.files for fname in *args.files
file = assert io.open fname file = assert io.open fname
contents = assert file\read "*a" contents = assert file\read "*a"
@ -109,6 +132,30 @@ for fname in *args.files
table.insert fields, 1, "line:#{line_no}" table.insert fields, 1, "line:#{line_no}"
switch properties.type switch properties.type
when "lapis-route"
if cls = find_class properties
prefix = if cls.fields
cls.fields.name
table.insert TAGS, {
"#{prefix or ""}#{properties.tag}"
fname
"/^#{escape_tagaddress line_text}/;\""
"f"
table.concat fields, " "
}
when "property"
-- this is necessary to register the correct indent level for the class
cls = find_class properties
-- record the fields into the class object so they can be referenced by
-- other tags. Note this is code-order dependent
if cls and args.lapis
if field = class_field properties
cls.fields or= {}
cls.fields[field.name] = field.value
when "function" when "function"
if exports[properties.tag] and properties.indent == 0 if exports[properties.tag] and properties.indent == 0
table.insert TAGS, { table.insert TAGS, {