@@ -17,13 +17,14 @@ argparse = require "argparse"
1717parser = argparse " moon-tags" , " Generate ctags style tags file for MoonScript files"
1818parser\ argument( " files" , " MoonScript files to generate tags for" ) \ args " +"
1919parser\ flag " --include-line" , " Include line number field for each tag"
20+ parser\ flag " --lapis" , " Support extracting lapis routes"
2021
2122args = parser\ parse [ v for _, v in ipairs _G . arg]
2223
2324TAGS = {} -- the final output of tags
2425
2526literals = require " moonscript.parse.literals"
26- import Indent from require " moonscript.parse.util"
27+ import Indent , simple_string from require " moonscript.parse.util"
2728
2829import P , S , C , Cc , Cg , Cb , Ct , Cs , V from require " lpeg"
2930
@@ -32,18 +33,20 @@ until_end = (1 - literals.Stop)^0
3233whitespace = S " \t " -- not including newline
3334ignore_line = Ct until_end -- tag it for empty line
3435
36+ -- NOTE: we disable interpolation parsing since we don't have full grammar
37+ SingleString = simple_string " '" , false
38+ DoubleString = simple_string ' "' , false
39+ String = SingleString + DoubleString
40+
3541-- we have to do this double Ct to capture both the full line and the grouped captures
3642Type = ( name) -> Cg Cc ( name) , " type"
3743Line = ( type_name, p) -> Ct C Ct Cg ( Indent , " indent" ) * p * Type type_name
3844
39- class_line = Line " class" , P " class" * whitespace^ 1 * Cg ( literals. Name , " tag" ) * until_end
40-
41- -- TODO: support lapis style routes
42- -- class_property = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * until_end * Type "property"
43-
4445method = P { P " =>" + P ( 1 - literals. Stop ) * V ( 1 ) }
4546func = P { P " ->" + P " =>" + P ( 1 - literals. Stop ) * V ( 1 ) }
4647
48+ self_prefix = Cg ( P ( " @" ) * Cc ( true ) , " self" )
49+
4750-- this matches end-of-file return table convention for module files to figure
4851-- out what names are exported
4952export_list = Ct P " {" * P {
@@ -52,17 +55,37 @@ export_list = Ct P"{" * P {
5255
5356eof_exports = P { export_list * S ( " \t\r\n " ) ^ 0 * P ( - 1 ) + P ( 1 ) * V ( 1 ) }
5457
58+ class_line = Line " class" , P " class" * whitespace^ 1 * Cg ( literals. Name , " tag" ) * until_end
59+ class_property = Line " property" , self_prefix^- 1 * Cg ( literals. Name , " tag" ) * P " :" * whitespace^ 0 * Cg ( String , " value" ) ^ 0 * until_end
5560class_method = Line ( " method" , P ( " @" ) ^- 1 * Cg ( literals. Name , " tag" ) * P " :" * method) * until_end
5661function_def = Line ( " function" , Cg ( literals. Name , " tag" ) * whitespace^ 0 * P " =" * func) * until_end
62+ lapis_route = Line " lapis-route" , P " [" * Cg ( literals. Name , " tag" ) * P " :" * whitespace^ 0 * Cg ( String , " route" ) * whitespace^ 0 * P ( " ]:" ) * until_end
63+
64+ line_types = class_line + class_method + class_property + function_def
65+
66+ if args. lapis
67+ line_types += lapis_route
5768
5869parse_lines = Ct P {
59- ( class_line + class_method + function_def + ignore_line) * ( P ( - 1 ) + literals. Break * V ( 1 ))
70+ ( line_types + ignore_line) * ( P ( - 1 ) + literals. Break * V ( 1 ))
6071}
6172
6273escape_tagaddress = ( line_text) ->
6374 replacements = S ( [[ \/.$^]] ) / [[ \%0]] + P ( " \t " ) / [[ \t]] + P ( " \r " ) / [[ \r]] + P ( " \n " ) / [[ \n]]
6475 Cs (( replacements + 1 ) ^ 0 ) \ match line_text
6576
77+ import types from require " tableshape"
78+
79+ class_field = types. partial {
80+ " self" : true
81+ tag : types. string\ tag " name"
82+ value : types. partial {
83+ " string"
84+ types. string
85+ types. string\ tag " value" -- TODO: will need to un-escape this
86+ }
87+ }
88+
6689for fname in * args. files
6790 file = assert io.open fname
6891 contents = assert file\ read " *a"
@@ -109,6 +132,30 @@ for fname in *args.files
109132 table.insert fields, 1 , " line:#{line_no}"
110133
111134 switch properties. type
135+ when " lapis-route"
136+ if cls = find_class properties
137+ prefix = if cls. fields
138+ cls. fields. name
139+
140+ table.insert TAGS , {
141+ " #{prefix or " " }#{properties.tag}"
142+ fname
143+ " /^#{escape_tagaddress line_text}/;\" "
144+ " f"
145+ table.concat fields, " "
146+ }
147+
148+ when " property"
149+ -- this is necessary to register the correct indent level for the class
150+ cls = find_class properties
151+
152+ -- record the fields into the class object so they can be referenced by
153+ -- other tags. Note this is code-order dependent
154+ if cls and args. lapis
155+ if field = class_field properties
156+ cls. fields or= {}
157+ cls. fields[ field. name] = field. value
158+
112159 when " function"
113160 if exports[ properties. tag] and properties. indent == 0
114161 table.insert TAGS , {
0 commit comments