diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/output.js | 149 | 
1 files changed, 139 insertions, 10 deletions
diff --git a/lib/output.js b/lib/output.js index c35c8ffc..48dcfff7 100644 --- a/lib/output.js +++ b/lib/output.js @@ -41,6 +41,14 @@   ***********************************************************************/ +/*********************************************************************** + +Modified by Wojtek Kosior <koszko@koszko.org> to allow printing/replacing +certain expressions with user-specified templates.  These modifications are +thereby released under Creative Commons Zero v1.0. + +***********************************************************************/ +  "use strict";  function is_some_comments(comment) { @@ -49,7 +57,17 @@ function is_some_comments(comment) {  }  function OutputStream(options) { -    options = defaults(options, { +    const template_option_names = [ +        "CALL", "PROPERTY_CALL", +        "BINARY", "LAZY_BINARY", "ASSIGNMENT_BINARY", +    ]; + +    const template_options = template_option_names.reduce( +        (acc, name) => Object.assign(acc, {[`template_for_${name}`]: null}), +        {} +    ); + +    options = defaults(options, Object.assign(template_options, {          annotations      : false,          ascii_only       : false,          beautify         : false, @@ -73,7 +91,7 @@ function OutputStream(options) {          webkit           : false,          width            : 80,          wrap_iife        : false, -    }, true); +    }, true));      // Convert comment option to RegExp if neccessary and set up comments filter      var comment_filter = return_false; // Default case, throw all comments away @@ -365,6 +383,73 @@ function OutputStream(options) {          last = str;      }; +    var re_verbose = function(flags="") { +        return (...args) => new RegExp( +            String.raw(...args) +                .split("\n") +                .map(line => +                    /^\s*(?<regex_part>([^#]|\S#+)*([^#\s]|\S#+))?(\s+(#.*)?)?/ +                        .exec(line).groups.regex_part) +                .join(""), +            flags +        ); +    }; + +    var template_substitution_regex = re_verbose("g")` +        (?<empty_substitution>\/\*\*\/) +        # name to substitute +        |\/\*(?<name1>[^*]+)\*\/ +        # name to substitute while also removing the non-whitespace that +        # appears after it +        |\/\*(?<name2>[^*]+)\*\*\/[^\s\/]* +        # opening paren or square paren +        |(?<opening>[\[\(]) +        # closing one +        |(?<closing>[\]\)]) +        # whitespace +        |(?<whitespace>\s+) +    `; + +    var print_template = function(template, src_start_token, print_callbacks) { +        template = template.trim(); + +        print_callbacks = ["line", "col"].reduce( +            (acc, prop) => Object.assign( +                acc, +                {[prop]: () => print(src_start_token[prop] + "")} +            ), +            Object.create(print_callbacks) +        ); + +        let start_pos = 0; + +        for (const match of template.matchAll(template_substitution_regex)) { +            print(template.substring(start_pos, match.index)); + +            start_pos = match.index + match[0].length; + +            const name = match.groups.name1 || match.groups.name2; + +            if (match.groups.empty_substitution) { +                /* print nothing */ +            } else if (name) { +                print_callbacks[name](this); +            } else if (match.groups.opening) { +                print(match.groups.opening); +                may_add_newline(); +            } else if (match.groups.closing) { +                may_add_newline(); +                print(match.groups.closing); +            } else if (match.groups.whitespace) { +                space(); +            } else { +                throw new Error("programming error"); +            } +        } + +        print(template.substring(start_pos)); +    }; +      var space = options.beautify ? function() {          print(" ");      } : function() { @@ -579,6 +664,7 @@ function OutputStream(options) {          has_parens      : function() { return last.slice(-1) == "(" },          newline         : newline,          print           : print, +        print_template  : print_template,          space           : space,          comma           : comma,          colon           : colon, @@ -1480,9 +1566,38 @@ function OutputStream(options) {      DEFPRINT(AST_Call, function(output) {          var self = this;          print_annotation(self, output); -        self.expression.print(output); -        if (self.optional) output.print("?."); -        print_call_args(self, output); + +        if (self.expression instanceof AST_PropAccess) { +            const template = output.option("template_for_PROPERTY_CALL") || +                  "/*function_expression*//*optional*//*parented_args*/"; + +            function print_property_expression(out) { +                if (typeof self.expression.property === "string") +                    out.print_string(self.expression.property, '"'); +                else +                    self.expression.property.print(out); +            } + +            output.print_template(template, self.start, { +                this_expression     : out => (self.expression.expression +                                              .print(out)), +                property_expression : print_property_expression, +                property_optional   : out => (self.expression.optional && +                                              out.print("?.")), +                function_expression : out => self.expression.print(out), +                optional            : out => self.optional && out.print("?."), +                parented_args       : out => print_call_args(self, out) +            }); +        } else { +            const template = output.option("template_for_CALL") || +                  "/*expression*//*optional*//*parented_args*/"; + +            output.print_template(template, self.start, { +                expression    : out => self.expression.print(out), +                optional      : out => self.optional && out.print("?."), +                parented_args : out => print_call_args(self, out) +            }); +        }      });      DEFPRINT(AST_New, function(output) {          var self = this; @@ -1551,11 +1666,25 @@ function OutputStream(options) {      });      DEFPRINT(AST_Binary, function(output) {          var self = this; -        self.left.print(output); -        output.space(); -        output.print(self.operator); -        output.space(); -        self.right.print(output); + +        for (const [regex, option] of [ +            [/^(&&|\|\|)$/, "LAZY_BINARY"], +            [/^([^=]+|[!=<>]==?)$/, "BINARY"], +            [/()/, "ASSIGNMENT_BINARY"], +        ]) { +            if (regex.test(self.operator)) { +                const template = output.option(`template_for_${option}`) || +                      "/*left*/ /*operator*/ /*right*/"; + +                output.print_template(template, self.start, { +                    left     : out => self.left.print(out), +                    right    : out => self.right.print(out), +                    operator : out => out.print(self.operator) +                }); + +                return; +            } +        }      });      DEFPRINT(AST_Conditional, function(output) {          var self = this;  | 
