Home | History | Annotate | Line # | Download | only in indent
t_options.lua revision 1.1
      1  1.1  rillig -- $NetBSD: t_options.lua,v 1.1 2023/05/20 21:32:05 rillig Exp $
      2  1.1  rillig --
      3  1.1  rillig -- Copyright (c) 2023 The NetBSD Foundation, Inc.
      4  1.1  rillig -- All rights reserved.
      5  1.1  rillig --
      6  1.1  rillig -- Redistribution and use in source and binary forms, with or without
      7  1.1  rillig -- modification, are permitted provided that the following conditions
      8  1.1  rillig -- are met:
      9  1.1  rillig -- 1. Redistributions of source code must retain the above copyright
     10  1.1  rillig --    notice, this list of conditions and the following disclaimer.
     11  1.1  rillig -- 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  rillig --    notice, this list of conditions and the following disclaimer in the
     13  1.1  rillig --    documentation and/or other materials provided with the distribution.
     14  1.1  rillig --
     15  1.1  rillig -- THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     16  1.1  rillig -- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     17  1.1  rillig -- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  1.1  rillig -- PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     19  1.1  rillig -- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  1.1  rillig -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  1.1  rillig -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  1.1  rillig -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  1.1  rillig -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  1.1  rillig -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  1.1  rillig -- POSSIBILITY OF SUCH DAMAGE.
     26  1.1  rillig 
     27  1.1  rillig -- Test driver for indent that runs indent on several inputs, checks the
     28  1.1  rillig -- output and can run indent with different command line options on the same
     29  1.1  rillig -- input.
     30  1.1  rillig --
     31  1.1  rillig -- The test files contain the input to be formatted, the formatting options
     32  1.1  rillig -- and the output, all as close together as possible. The test files use the
     33  1.1  rillig -- following directives:
     34  1.1  rillig --
     35  1.1  rillig --	//indent input [description]
     36  1.1  rillig --		Specifies the input to be formatted.
     37  1.1  rillig --	//indent run [options]
     38  1.1  rillig --		Runs indent on the input, using the given options.
     39  1.1  rillig --	//indent end [description]
     40  1.1  rillig --		Finishes an '//indent input' or '//indent run' section.
     41  1.1  rillig --	//indent run-equals-input [options]
     42  1.1  rillig --		Runs indent on the input, expecting unmodified output.
     43  1.1  rillig --	//indent run-equals-prev-output [options]
     44  1.1  rillig --		Runs indent on the input, expecting the same output as from
     45  1.1  rillig --		the previous run.
     46  1.1  rillig --
     47  1.1  rillig -- All text outside input..end or run..end directives is not passed to indent.
     48  1.1  rillig --
     49  1.1  rillig -- Inside the input..end or run..end sections, comments that start with '$'
     50  1.1  rillig -- are filtered out, they can be used for remarks near the affected code.
     51  1.1  rillig --
     52  1.1  rillig -- The actual output from running indent is written to stdout, the expected
     53  1.1  rillig -- test output is written to 'expected.out'.
     54  1.1  rillig 
     55  1.1  rillig local warned = false
     56  1.1  rillig 
     57  1.1  rillig local filename = ""
     58  1.1  rillig local lineno = 0
     59  1.1  rillig 
     60  1.1  rillig local prev_empty_lines = 0	-- the finished "block" of empty lines
     61  1.1  rillig local curr_empty_lines = 0	-- the ongoing "block" of empty lines
     62  1.1  rillig local max_empty_lines = 0	-- between sections
     63  1.1  rillig local seen_input_section = false-- the first input section is not checked
     64  1.1  rillig 
     65  1.1  rillig local section = ""		-- "", "input" or "run"
     66  1.1  rillig local section_excl_comm = ""	-- without dollar comments
     67  1.1  rillig local section_incl_comm = ""	-- with dollar comments
     68  1.1  rillig 
     69  1.1  rillig local input_excl_comm = ""	-- the input text for indent
     70  1.1  rillig local input_incl_comm = ""	-- used for duplicate checks
     71  1.1  rillig local unused_input_lineno = 0
     72  1.1  rillig 
     73  1.1  rillig local output_excl_comm = ""	-- expected output
     74  1.1  rillig local output_incl_comm = ""	-- used for duplicate checks
     75  1.1  rillig local output_lineno = 0
     76  1.1  rillig 
     77  1.1  rillig local expected_out = assert(io.open("expected.out", "w"))
     78  1.1  rillig 
     79  1.1  rillig local function die(ln, msg)
     80  1.1  rillig 	io.stderr:write(("%s:%d: error: %s\n"):format(filename, ln, msg))
     81  1.1  rillig 	os.exit(false)
     82  1.1  rillig end
     83  1.1  rillig 
     84  1.1  rillig local function warn(ln, msg)
     85  1.1  rillig 	io.stderr:write(("%s:%d: warning: %s\n"):format(filename, ln, msg))
     86  1.1  rillig 	warned = true
     87  1.1  rillig end
     88  1.1  rillig 
     89  1.1  rillig local function init_file(fname)
     90  1.1  rillig 	filename = fname
     91  1.1  rillig 	lineno = 0
     92  1.1  rillig 
     93  1.1  rillig 	prev_empty_lines = 0
     94  1.1  rillig 	curr_empty_lines = 0
     95  1.1  rillig 	max_empty_lines = 0
     96  1.1  rillig 	seen_input_section = false
     97  1.1  rillig 
     98  1.1  rillig 	section = ""
     99  1.1  rillig 	section_excl_comm = ""
    100  1.1  rillig 	section_incl_comm = ""
    101  1.1  rillig 
    102  1.1  rillig 	input_excl_comm = ""
    103  1.1  rillig 	input_incl_comm = ""
    104  1.1  rillig 	unused_input_lineno = 0
    105  1.1  rillig 
    106  1.1  rillig 	output_excl_comm = ""
    107  1.1  rillig 	output_incl_comm = ""
    108  1.1  rillig 	output_lineno = 0
    109  1.1  rillig end
    110  1.1  rillig 
    111  1.1  rillig local function check_empty_lines_block(n)
    112  1.1  rillig 	if max_empty_lines ~= n and seen_input_section then
    113  1.1  rillig 		local lines = n ~= 1 and "lines" or "line"
    114  1.1  rillig 		warn(lineno, ("expecting %d empty %s, got %d")
    115  1.1  rillig 		    :format(n, lines, max_empty_lines))
    116  1.1  rillig 	end
    117  1.1  rillig end
    118  1.1  rillig 
    119  1.1  rillig local function check_unused_input()
    120  1.1  rillig 	if unused_input_lineno ~= 0 then
    121  1.1  rillig 		warn(unused_input_lineno, "input is not used")
    122  1.1  rillig 	end
    123  1.1  rillig end
    124  1.1  rillig 
    125  1.1  rillig local function run_indent(inp, args)
    126  1.1  rillig 	local indent = os.getenv("INDENT") or "indent"
    127  1.1  rillig 	local cmd = indent .. " " .. args .. " indent.in -st"
    128  1.1  rillig 
    129  1.1  rillig 	local indent_in = assert(io.open("indent.in", "w"))
    130  1.1  rillig 	indent_in:write(inp)
    131  1.1  rillig 	indent_in:close()
    132  1.1  rillig 	ok, kind, info = os.execute(cmd)
    133  1.1  rillig 	if not ok then
    134  1.1  rillig 		print(kind .. " " .. info)
    135  1.1  rillig 	end
    136  1.1  rillig 	os.remove("indent.in")
    137  1.1  rillig end
    138  1.1  rillig 
    139  1.1  rillig local function handle_empty_section(line)
    140  1.1  rillig 	if line == "" then
    141  1.1  rillig 		curr_empty_lines = curr_empty_lines + 1
    142  1.1  rillig 	else
    143  1.1  rillig 		if curr_empty_lines > max_empty_lines then
    144  1.1  rillig 			max_empty_lines = curr_empty_lines
    145  1.1  rillig 		end
    146  1.1  rillig 		if curr_empty_lines > 0 then
    147  1.1  rillig 			if prev_empty_lines > 1 then
    148  1.1  rillig 				warn(lineno - curr_empty_lines - 1,
    149  1.1  rillig 				    prev_empty_lines .. " empty lines a few "
    150  1.1  rillig 				    .. "lines above, should be only 1")
    151  1.1  rillig 			end
    152  1.1  rillig 			prev_empty_lines = curr_empty_lines
    153  1.1  rillig 		end
    154  1.1  rillig 		curr_empty_lines = 0
    155  1.1  rillig 	end
    156  1.1  rillig end
    157  1.1  rillig 
    158  1.1  rillig local function handle_indent_directive(line, command, args)
    159  1.1  rillig 	print(line)
    160  1.1  rillig 	expected_out:write(line .. "\n")
    161  1.1  rillig 
    162  1.1  rillig 	if command == "input" then
    163  1.1  rillig 		if prev_empty_lines ~= 2 and seen_input_section then
    164  1.1  rillig 			warn(lineno, "input section needs 2 empty lines "
    165  1.1  rillig 			    .. "above, not " .. prev_empty_lines)
    166  1.1  rillig 		end
    167  1.1  rillig 		check_empty_lines_block(2)
    168  1.1  rillig 		check_unused_input()
    169  1.1  rillig 		section = "input"
    170  1.1  rillig 		section_excl_comm = ""
    171  1.1  rillig 		section_incl_comm = ""
    172  1.1  rillig 		unused_input_lineno = lineno
    173  1.1  rillig 		seen_input_section = true
    174  1.1  rillig 		output_excl_comm = ""
    175  1.1  rillig 		output_incl_comm = ""
    176  1.1  rillig 		output_lineno = 0
    177  1.1  rillig 
    178  1.1  rillig 	elseif command == "run" then
    179  1.1  rillig 		if section ~= "" then
    180  1.1  rillig 			warn(lineno, "unfinished section '" .. section .. "'")
    181  1.1  rillig 		end
    182  1.1  rillig 		check_empty_lines_block(1)
    183  1.1  rillig 		if prev_empty_lines ~= 1 then
    184  1.1  rillig 			warn(lineno, "run section needs 1 empty line above, "
    185  1.1  rillig 			    .. "not " .. prev_empty_lines)
    186  1.1  rillig 		end
    187  1.1  rillig 		section = "run"
    188  1.1  rillig 		output_lineno = lineno
    189  1.1  rillig 		section_excl_comm = ""
    190  1.1  rillig 		section_incl_comm = ""
    191  1.1  rillig 
    192  1.1  rillig 		run_indent(input_excl_comm, args)
    193  1.1  rillig 		unused_input_lineno = 0
    194  1.1  rillig 
    195  1.1  rillig 	elseif command == "run-equals-input" then
    196  1.1  rillig 		check_empty_lines_block(1)
    197  1.1  rillig 		run_indent(input_excl_comm, args)
    198  1.1  rillig 		expected_out:write(input_excl_comm)
    199  1.1  rillig 		unused_input_lineno = 0
    200  1.1  rillig 		max_empty_lines = 0
    201  1.1  rillig 
    202  1.1  rillig 	elseif command == "run-equals-prev-output" then
    203  1.1  rillig 		check_empty_lines_block(1)
    204  1.1  rillig 		run_indent(input_excl_comm, args)
    205  1.1  rillig 		expected_out:write(output_excl_comm)
    206  1.1  rillig 		max_empty_lines = 0
    207  1.1  rillig 
    208  1.1  rillig 	elseif command == "end" and section == "input" then
    209  1.1  rillig 		if section_incl_comm == input_incl_comm then
    210  1.1  rillig 			warn(lineno, "duplicate input; remove this section")
    211  1.1  rillig 		end
    212  1.1  rillig 
    213  1.1  rillig 		input_excl_comm = section_excl_comm
    214  1.1  rillig 		input_incl_comm = section_incl_comm
    215  1.1  rillig 		section = ""
    216  1.1  rillig 		max_empty_lines = 0
    217  1.1  rillig 
    218  1.1  rillig 	elseif command == "end" and section == "run" then
    219  1.1  rillig 		if section_incl_comm == input_incl_comm then
    220  1.1  rillig 			warn(output_lineno,
    221  1.1  rillig 			    "output == input; use run-equals-input")
    222  1.1  rillig 		end
    223  1.1  rillig 		if section_incl_comm == output_incl_comm then
    224  1.1  rillig 			warn(output_lineno,
    225  1.1  rillig 			    "duplicate output; use run-equals-prev-output")
    226  1.1  rillig 		end
    227  1.1  rillig 
    228  1.1  rillig 		output_excl_comm = section_excl_comm
    229  1.1  rillig 		output_incl_comm = section_incl_comm
    230  1.1  rillig 		section = ""
    231  1.1  rillig 		max_empty_lines = 0
    232  1.1  rillig 
    233  1.1  rillig 	elseif command == "end" then
    234  1.1  rillig 		warn(lineno, "misplaced '//indent end'")
    235  1.1  rillig 
    236  1.1  rillig 	else
    237  1.1  rillig 		die(lineno, "invalid line '" .. line .. "'")
    238  1.1  rillig 	end
    239  1.1  rillig 
    240  1.1  rillig 	prev_empty_lines = 0
    241  1.1  rillig 	curr_empty_lines = 0
    242  1.1  rillig end
    243  1.1  rillig 
    244  1.1  rillig local function handle_line(line)
    245  1.1  rillig 	if section == "" then
    246  1.1  rillig 		handle_empty_section(line)
    247  1.1  rillig 	end
    248  1.1  rillig 
    249  1.1  rillig 	-- Hide comments starting with dollar from indent; they are used for
    250  1.1  rillig 	-- marking bugs and adding other remarks directly in the input or
    251  1.1  rillig 	-- output sections.
    252  1.1  rillig 	if line:match("^%s*/[*]%s*[$].*[*]/$")
    253  1.1  rillig 	    or line:match("^%s*//%s*[$]") then
    254  1.1  rillig 		if section ~= "" then
    255  1.1  rillig 			section_incl_comm = section_incl_comm .. line .. "\n"
    256  1.1  rillig 		end
    257  1.1  rillig 		return
    258  1.1  rillig 	end
    259  1.1  rillig 
    260  1.1  rillig 	local cmd, args = line:match("^//indent%s+([^%s]+)%s*(.*)$")
    261  1.1  rillig 	if cmd then
    262  1.1  rillig 		handle_indent_directive(line, cmd, args)
    263  1.1  rillig 		return
    264  1.1  rillig 	end
    265  1.1  rillig 
    266  1.1  rillig 	if section == "input" or section == "run" then
    267  1.1  rillig 		section_excl_comm = section_excl_comm .. line .. "\n"
    268  1.1  rillig 		section_incl_comm = section_incl_comm .. line .. "\n"
    269  1.1  rillig 	end
    270  1.1  rillig 
    271  1.1  rillig 	if section == "run" then
    272  1.1  rillig 		expected_out:write(line .. "\n")
    273  1.1  rillig 	end
    274  1.1  rillig 
    275  1.1  rillig 	if section == ""
    276  1.1  rillig 	    and line ~= ""
    277  1.1  rillig 	    and line:sub(1, 1) ~= "#"
    278  1.1  rillig 	    and line:sub(1, 1) ~= "/"
    279  1.1  rillig 	    and line:sub(1, 2) ~= " *" then
    280  1.1  rillig 		warn(lineno, "non-comment line outside 'input' or 'run' "
    281  1.1  rillig 		    .. "section")
    282  1.1  rillig 	end
    283  1.1  rillig end
    284  1.1  rillig 
    285  1.1  rillig local function handle_file(fname)
    286  1.1  rillig 	init_file(fname)
    287  1.1  rillig 	local f = assert(io.open(fname))
    288  1.1  rillig 	for line in f:lines() do
    289  1.1  rillig 		lineno = lineno + 1
    290  1.1  rillig 		handle_line(line)
    291  1.1  rillig 	end
    292  1.1  rillig 	f:close()
    293  1.1  rillig end
    294  1.1  rillig 
    295  1.1  rillig local function main()
    296  1.1  rillig 	for _, arg in ipairs(arg) do
    297  1.1  rillig 		handle_file(arg)
    298  1.1  rillig 	end
    299  1.1  rillig 	if section ~= "" then
    300  1.1  rillig 		die(lineno, "still in section '" .. section .. "'")
    301  1.1  rillig 	end
    302  1.1  rillig 	check_unused_input()
    303  1.1  rillig 	expected_out:close()
    304  1.1  rillig 	os.exit(not warned)
    305  1.1  rillig end
    306  1.1  rillig 
    307  1.1  rillig main()
    308