mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 20:51:30 +00:00
Whitespace is not significant, so this should not be a problem. https://secwiki.org/w/Nmap/Code_Standards
323 lines
14 KiB
Lua
Executable File
323 lines
14 KiB
Lua
Executable File
-- Copyright (c) 2011 Patrick Joseph Donnelly
|
|
--
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
-- of this software and associated documentation files (the "Software"), to deal
|
|
-- in the Software without restriction, including without limitation the rights
|
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
-- copies of the Software, and to permit persons to whom the Software is
|
|
-- furnished to do so, subject to the following conditions:
|
|
--
|
|
-- The above copyright notice and this permission notice shall be included in
|
|
-- all copies or substantial portions of the Software.
|
|
--
|
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
-- SOFTWARE.
|
|
|
|
local DEBUG = false;
|
|
|
|
local assert = assert;
|
|
local pairs = pairs;
|
|
local require = require;
|
|
local tostring = tostring;
|
|
|
|
local io = require "io";
|
|
local read = io.read;
|
|
local write = io.write;
|
|
local stderr = io.stderr;
|
|
|
|
local table = require "table";
|
|
local concat = table.concat;
|
|
|
|
local lpeg = require "lpeg";
|
|
|
|
lpeg.setmaxstack(8000);
|
|
|
|
local P = lpeg.P;
|
|
local S = lpeg.S;
|
|
local V = lpeg.V;
|
|
|
|
local C = lpeg.C;
|
|
local Cb = lpeg.Cb;
|
|
local Cc = lpeg.Cc;
|
|
local Cf = lpeg.Cf;
|
|
local Cg = lpeg.Cg;
|
|
local Cp = lpeg.Cp;
|
|
local Cs = lpeg.Cs;
|
|
local Cmt = lpeg.Cmt;
|
|
local Ct = lpeg.Ct;
|
|
|
|
local NEWLINE = Cb "newline" * ((V "space" - P "\n")^0 * P "\n")^-1;
|
|
local SPACE = Cb "space";
|
|
local INDENT_SPACE = Cb "indent_space";
|
|
local function INDENT_INCREASE (p, nonewline)
|
|
if nonewline then
|
|
return Cg(Cg(Cb "indent" * INDENT_SPACE, "indent") * p);
|
|
else
|
|
return Cg(Cg(Cb "indent" * INDENT_SPACE, "indent") * NEWLINE * p);
|
|
end
|
|
end
|
|
local INDENT = Cb "indent";
|
|
|
|
local shebang = P "#" * (P(1) - P "\n")^0 * P "\n";
|
|
|
|
local function K (k) -- keyword
|
|
return C(k) * -(V "alnum" + P "_");
|
|
end
|
|
|
|
-- The formatter uses captures to indent code. We necessarily use thousands and
|
|
-- thousands of them. At various strategic points, we concatenate these captures
|
|
-- so we don't overflow the Lua stack.
|
|
local function FLATTEN (pattern)
|
|
return Ct(pattern) / concat;
|
|
end
|
|
|
|
local lua = lpeg.locale {
|
|
V "_init" * FLATTEN(V "_script");
|
|
|
|
_init = Cg(Cc "\n", "newline") * Cg(Cc "", "indent") * Cg(Cc " ", "indent_space") * Cg(Cc " ", "space");
|
|
|
|
_script = C(shebang)^-1 * V "filler" * V "chunk" * V "filler" * -P(1);
|
|
|
|
-- keywords
|
|
|
|
keywords = K "and" + K "break" + K "do" + K "else" + K "elseif" +
|
|
K "end" + K "false" + K "for" + K "function" + K "if" +
|
|
K "in" + K "local" + K "nil" + K "not" + K "or" + K "repeat" +
|
|
K "return" + K "then" + K "true" + K "until" + K "while";
|
|
|
|
-- longstrings
|
|
|
|
longstring = P { -- from Roberto Ierusalimschy's lpeg examples
|
|
(V "open" * (P(1) - V "closeeq")^0 * V "close") / "%0";
|
|
|
|
open = "[" * Cg((P "=")^0, "init") * P "[" * (P "\n")^-1;
|
|
close = "]" * C((P "=")^0) * "]";
|
|
closeeq = Cmt(V "close" * Cb "init", function (s, i, a, b) return a == b end)
|
|
};
|
|
|
|
-- comments & whitespace
|
|
|
|
-- read a comment but do not capture any whitespace at the end
|
|
chomp_comment = C((P(1) - (V "space" - P "\n")^0 * (P "\n" + -P(1)))^0) * (V "space" - P "\n")^0 * (P "\n" + -P(1)) * Cc "\n";
|
|
one_line_comment = -V "multi_line_comment" * C "--" * V "chomp_comment";
|
|
multi_line_comment = C "--" * V "longstring";
|
|
comment = V "multi_line_comment" + V "one_line_comment" * INDENT;
|
|
|
|
whitespace = (V "space" + (SPACE * V "comment" * SPACE))^0;
|
|
space_after_stat = ((V "space" - P "\n")^0 * (P ";")^-1 * (V "space" - P "\n")^0 * SPACE * V "one_line_comment") +
|
|
(V "whitespace" * P ";")^-1 * NEWLINE;
|
|
|
|
-- match "filler" comments
|
|
line_of_space = (V "space" - P "\n")^0 * P "\n";
|
|
collapse_whitespace = V "line_of_space"^2 * Cc "\n\n" + V "line_of_space"^1 * Cc "\n";
|
|
filler_comment = (V "space" - P "\n")^0 * INDENT * V "one_line_comment"; -- * C "\n"^-1;
|
|
--filler_comment = (V "space" - P "\n")^0 * INDENT * (V "one_line_comment" - V "multi_line_comment"); -- * C "\n"^-1; -- FIXME highlighted after INDENT
|
|
filler = (V "collapse_whitespace" + V "filler_comment")^0 * V "whitespace" + V "whitespace";
|
|
|
|
-- Types and Comments
|
|
|
|
Name = C((V "alpha" + P "_") * (V "alnum" + P "_")^0) - V "keywords";
|
|
BinaryExponent = S "pP" * (P "-")^-1 * V "digit"^1;
|
|
DecimalExponent = S "eE" * (P "-")^-1 * V "digit"^1;
|
|
Number = C((P "-")^-1 * V "whitespace" * P "0" * S "xX" * V "xdigit"^1 * (P "." * V "xdigit"^0)^-1 * V "BinaryExponent"^-1 * -(V "alnum" + P "_")) +
|
|
C((P "-")^-1 * V "whitespace" * V "digit"^1 * (P "." * V "digit"^0)^-1 * V "DecimalExponent"^-1 * -(V "alnum" + P "_")) +
|
|
C((P "-")^-1 * V "whitespace" * P "." * V "digit"^1 * V "DecimalExponent"^-1 * -(V "alnum" + P "_"));
|
|
String = C(P "\"" * (P "\\" * P(1) + (1 - P "\""))^0 * P "\"") +
|
|
C(P "'" * (P "\\" * P(1) + (1 - P "'"))^0 * P "'") +
|
|
V "longstring";
|
|
|
|
-- Lua Complete Syntax
|
|
|
|
chunk = FLATTEN((V "filler" * INDENT * FLATTEN(V "stat") * V "space_after_stat")^0 * (V "filler" * INDENT * V "retstat" * V "space_after_stat")^-1);
|
|
|
|
block = V "chunk";
|
|
|
|
stat = P ";" +
|
|
V "label" +
|
|
K "break" +
|
|
K "goto" * SPACE * V "whitespace" * V "Name" +
|
|
K "do" * INDENT_INCREASE(V "filler" * V "block" * V "filler") * INDENT * K "end" +
|
|
K "while" * SPACE * V "whitespace" * V "_oneline_exp" * V "whitespace" * SPACE * K "do" * INDENT_INCREASE(V "filler" * V "block" * V "filler") * INDENT * K "end" +
|
|
K "repeat" * INDENT_INCREASE(V "filler" * V "block" * V "filler") * INDENT * K "until" * SPACE * V "whitespace" * V "_oneline_exp" +
|
|
K "if" * SPACE * V "whitespace" * V "_oneline_exp" * V "whitespace" * SPACE * K "then" * INDENT_INCREASE(V "filler" * V "block" * V "filler") * (INDENT * K "elseif" * SPACE * V "whitespace" * V "_oneline_exp" * V "whitespace" * SPACE * K "then" * INDENT_INCREASE(V "filler" * V "block" * V "filler"))^0 * (INDENT * K "else" * INDENT_INCREASE(V "filler" * V "block" * V "filler"))^-1 * INDENT * K "end" +
|
|
K "for" * SPACE * V "whitespace" * V "Name" * V "whitespace" * SPACE * C "=" * SPACE * V "whitespace" * V "_oneline_exp" * V "whitespace" * C "," * SPACE * V "whitespace" * V "_oneline_exp" * (V "whitespace" * C "," * SPACE * V "whitespace" * V "_oneline_exp")^-1 * V "whitespace" * SPACE * K "do" * INDENT_INCREASE(V "filler" * V "block" * V "filler") * INDENT * K "end" +
|
|
K "for" * SPACE * V "whitespace" * V "namelist" * V "whitespace" * SPACE * K "in" * SPACE * V "whitespace" * V "explist" * V "whitespace" * SPACE * K "do" * INDENT_INCREASE(V "filler" * V "block" * V "filler") * INDENT * K "end" +
|
|
K "function" * SPACE * V "whitespace" * V "funcname" * SPACE * V "whitespace" * V "funcbody" +
|
|
K "local" * SPACE * V "whitespace" * K "function" * SPACE * V "whitespace" * V "Name" * V "whitespace" * SPACE * V "funcbody" +
|
|
K "local" * SPACE * V "whitespace" * V "namelist" * (SPACE * V "whitespace" * C "=" * SPACE * V "whitespace" * V "explist")^-1 * V "_check_ambiguous" +
|
|
V "_function_declaration" +
|
|
V "varlist" * V "whitespace" * SPACE * C "=" * SPACE * V "whitespace" * V "explist" * V "_check_ambiguous" +
|
|
V "functioncall" * V "_check_ambiguous";
|
|
|
|
-- If the script uses a semicolon to avoid an ambiguous syntax situation, we keep it.
|
|
-- Example:
|
|
-- a = f()
|
|
-- ("foo"):method()
|
|
--
|
|
-- Can be parsed as:
|
|
-- a = f()("foo"):method();
|
|
-- or
|
|
-- a = f();
|
|
-- ("foo"):method();
|
|
_check_ambiguous = #(V "whitespace" * P ";" * V "whitespace" * P "(") * Cc ";" + P(true);
|
|
|
|
_function_declaration = Cmt(V "Name" * V "space"^0 * P "=" * V "space"^0 * FLATTEN(V "function") * -(V "whitespace" * (V "binop" + P ",")), function (s, p, name, f) local new = f:gsub("^function", "function "..name) return true, new end);
|
|
|
|
label = C "::" * V "whitespace" * V "Name" * V "whitespace" * C "::";
|
|
|
|
retstat = K "return" * (SPACE * V "whitespace" * V "explist")^-1;
|
|
|
|
funcname = V "Name" * (V "whitespace" * C "." * V "whitespace" * V "Name")^0 * (V "whitespace" * C ":" * V "whitespace" * V "Name")^-1;
|
|
|
|
namelist = V "Name" * (V "whitespace" * C "," * SPACE * V "whitespace" * V "Name")^0;
|
|
|
|
varlist = V "var" * (V "whitespace" * C "," * SPACE * V "whitespace" * V "var")^0;
|
|
|
|
-- Let's come up with a syntax that does not use left recursion (only listing changes to Lua 5.1 extended BNF syntax)
|
|
-- value ::= nil | false | true | Number | String | '...' | function | tableconstructor | functioncall | var | '(' exp ')'
|
|
-- exp ::= unop exp | value [binop exp]
|
|
-- prefix ::= '(' exp ')' | Name
|
|
-- index ::= '[' exp ']' | '.' Name
|
|
-- call ::= args | ':' Name args
|
|
-- suffix ::= call | index
|
|
-- var ::= prefix {suffix} index | Name
|
|
-- functioncall ::= prefix {suffix} call
|
|
|
|
_deparenthesis_value = P "(" * V "whitespace" * (V "_deparenthesis_value" + V "_value_simple") * V "whitespace" * P ")";
|
|
|
|
_value_simple = K "nil" +
|
|
K "false" +
|
|
K "true" +
|
|
V "Number" +
|
|
V "String" +
|
|
V "function" +
|
|
V "tableconstructor" +
|
|
V "var";
|
|
|
|
-- Something that represents a value (or many values)
|
|
value = K "nil" +
|
|
K "false" +
|
|
K "true" +
|
|
V "Number" +
|
|
V "String" +
|
|
K "..." +
|
|
V "function" +
|
|
V "tableconstructor" +
|
|
V "functioncall" +
|
|
V "var" +
|
|
V "_deparenthesis_value" + -- remove redundant parenthesis
|
|
C "(" * V "whitespace" * V "exp" * V "whitespace" * C ")";
|
|
|
|
-- An expression operates on values to produce a new value or is a value
|
|
exp = V "unop" * V "whitespace" * V "exp" +
|
|
V "value" * (V "whitespace" * V "binop" * V "whitespace" * V "exp")^-1;
|
|
|
|
-- This is an expression which is always truncated to 1 result, and so we can remove
|
|
-- redundant parenthesis.
|
|
_single_exp = P "(" * V "whitespace" * V "_single_exp" * V "whitespace" * P ")" * -(V "whitespace" * (V "suffix" + V "binop")) +
|
|
V "exp";
|
|
|
|
_oneline_exp = Cg(Cg(Cc " ", "newline") * Cg(Cc "", "indent") * Cg(Cc "", "indent_space") * V "_single_exp");
|
|
|
|
-- Index and Call
|
|
index = C "[" * V "whitespace" * V "_single_exp" * V "whitespace" * C "]" +
|
|
C "." * V "whitespace" * V "Name";
|
|
call = V "args" +
|
|
C ":" * V "whitespace" * V "Name" * V "whitespace" * V "args";
|
|
|
|
-- A Prefix is a the leftmost side of a var(iable) or functioncall
|
|
prefix = C "(" * V "whitespace" * V "exp" * V "whitespace" * C ")" +
|
|
V "Name";
|
|
-- A Suffix is a Call or Index
|
|
suffix = V "call" +
|
|
V "index";
|
|
|
|
var = V "prefix" * (V "whitespace" * V "suffix" * #(V "whitespace" * V "suffix"))^0 * V "whitespace" * V "index" +
|
|
V "Name";
|
|
functioncall = V "prefix" * (V "whitespace" * V "suffix" * #(V "whitespace" * V "suffix"))^0 * V "whitespace" * V "call";
|
|
|
|
explist = V "exp" * (V "whitespace" * C "," * SPACE * V "whitespace" * V "exp")^0;
|
|
|
|
-- Change func({}) to func {}
|
|
-- Change func("...") to func "..."
|
|
args = P "(" * SPACE * V "whitespace" * V "tableconstructor" * V "whitespace" * P ")" +
|
|
P "(" * SPACE * V "whitespace" * V "String" * V "whitespace" * P ")" +
|
|
C "(" * INDENT_INCREASE(V "whitespace" * (V "explist" * V "whitespace")^-1, true) * C ")" +
|
|
SPACE * V "tableconstructor" +
|
|
SPACE * V "String";
|
|
|
|
["function"] = FLATTEN(K "function" * SPACE * V "whitespace" * V "funcbody");
|
|
|
|
funcbody = C "(" * V "whitespace" * (V "parlist" * V "whitespace")^-1 * C ")" * INDENT_INCREASE(V "block" * V "whitespace") * INDENT * K "end";
|
|
|
|
parlist = V "namelist" * (V "whitespace" * C "," * SPACE * V "whitespace" * K "...")^-1 +
|
|
K "...";
|
|
|
|
tableconstructor = FLATTEN(C "{" * (INDENT_INCREASE(V "filler" * V "fieldlist" * V "filler") * INDENT + V "filler") * C "}");
|
|
|
|
field_space_after = (V "space" - P "\n")^0 * SPACE * V "one_line_comment";
|
|
fieldlist = INDENT * FLATTEN(V "field") * (V "whitespace" * V "fieldsep" * (V "field_space_after" + NEWLINE) * V "filler" * INDENT * FLATTEN(V "field"))^0 * (V "whitespace" * V "fieldsep" + Cc ",")^-1 * (V "field_space_after" + NEWLINE);
|
|
|
|
field = C "[" * V "whitespace" * V "_oneline_exp" * V "whitespace" * C "]" * SPACE * V "whitespace" * C "=" * SPACE * V "whitespace" * V "_single_exp" +
|
|
V "Name" * SPACE * V "whitespace" * C "=" * SPACE * V "whitespace" * V "_single_exp" +
|
|
V "exp";
|
|
|
|
fieldsep = C "," +
|
|
P ";" * Cc ","; -- use only commas
|
|
|
|
binop = SPACE * K "and" * SPACE + -- match longest token sequences first
|
|
SPACE * K "or" * SPACE +
|
|
SPACE * C ".." * SPACE +
|
|
SPACE * C "<=" * SPACE +
|
|
SPACE * C ">=" * SPACE +
|
|
SPACE * C "==" * SPACE +
|
|
SPACE * C "~=" * SPACE +
|
|
SPACE * C "+" * SPACE +
|
|
SPACE * (C "-" - P "--") * SPACE +
|
|
SPACE * C "*" * SPACE +
|
|
SPACE * C "/" * SPACE +
|
|
C "^" + -- no space for power
|
|
SPACE * C "%" * SPACE +
|
|
SPACE * C "<" * SPACE +
|
|
SPACE * C ">" * SPACE;
|
|
|
|
unop = (C "-" - P "--") +
|
|
C "#" +
|
|
K "not" * SPACE;
|
|
};
|
|
|
|
if DEBUG then
|
|
local level = 0;
|
|
for k, p in pairs(lua) do
|
|
local enter = lpeg.Cmt(lpeg.P(true), function (s, p)
|
|
stderr:write((" "):rep(level*2), "ENTER ", k, ": ", s:sub(p, p), "\n");
|
|
level = level+1;
|
|
return true;
|
|
end);
|
|
local match = lpeg.Cmt(lpeg.P(true), function (s, p)
|
|
level = level-1;
|
|
if k == "space" or k == "comment" then
|
|
return true;
|
|
else
|
|
stderr:write((" "):rep(level*2), "MATCH ", k, "\n", s:sub(p - 200 < 0 and 1 or p-200, p-1), "\n");
|
|
return true;
|
|
end
|
|
end);
|
|
local leave = lpeg.Cmt(lpeg.P(true), function (s, p)
|
|
level = level-1;
|
|
stderr:write((" "):rep(level*2), "LEAVE ", k, "\n");
|
|
return false;
|
|
end);
|
|
lua[k] = enter * p * match + leave;
|
|
end
|
|
end
|
|
|
|
lua = P(lua);
|
|
|
|
write(assert(lua:match(assert(read "*a"))));
|