npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nv-js-parse

v1.4.25

Published

nv-js-parse ============ - nv-js-parse - wrap of @babel/parser - add some display/show/path/traverse methods , make it easy for manual-edit ast - nv-js-parse is slow, coz it insert some functions to original-babel-parser - and rebuild the path/traverse o

Downloads

227

Readme

nv-js-parse

  • nv-js-parse
  • wrap of @babel/parser
  • add some display/show/path/traverse methods , make it easy for manual-edit ast
  • nv-js-parse is slow, coz it insert some functions to original-babel-parser
  • and rebuild the path/traverse of babel
  • its for build cli-code-tools,NOT for creat-runtime

install

  • npm install nv-js-parse

usage

basic

const {tree,parse,unparse,pprint_ast} = require('nv-js-parse')

var code = `class T {
    #a = 1999
    get() {
      return this.#a
    }
}`

> var t = tree(code)
> t
 [program <Program> {"sourceType":"module","interpreter":null}] {}

  • astml is a simple syntax for manually writing ast

  • shape: %key <%type:String> %attr:Object %NL %listKey[%index:Int] <%type:String> %attr:Object %NL

       %type must be ast-node-type of estree/ts/flow/jsx
       %key AND %listKey  must be visitor/list-visitor of %type 

    > t.show_astml()
    program <Program> {"sourceType":"module","interpreter":null}
        body[0] <ClassDeclaration> {}
            id <Identifier> {"name":"T"}
            body <ClassBody> {}
                body[0] <ClassPrivateProperty> {"static":false}
                    key <PrivateName> {}
                        id <Identifier> {"name":"a"}
                    value <NumericLiteral> {"value":1999}
                body[1] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":false,"kind":"method"}
                    key <Identifier> {"name":"get"}
                    body <BlockStatement> {}
                        body[0] <ReturnStatement> {}
                            argument <MemberExpression> {"computed":false}
                                object <ThisExpression> {}
                                property <PrivateName> {}
                                    id <Identifier> {"name":"a"}



        > t.show_code()
        class T {
          #a = 1999;

          get() {
            return this.#a;
          }

        }



        > t.get_all_ast_bracket_paths()
        [
          '',
          '["body"]["0"]',
          '["body"]["0"]["id"]',
          '["body"]["0"]["body"]',
          '["body"]["0"]["body"]["body"]["0"]',
          '["body"]["0"]["body"]["body"]["0"]["key"]',
          '["body"]["0"]["body"]["body"]["0"]["key"]["id"]',
          '["body"]["0"]["body"]["body"]["0"]["value"]',
          '["body"]["0"]["body"]["body"]["1"]',
          '["body"]["0"]["body"]["body"]["1"]["key"]',
          '["body"]["0"]["body"]["body"]["1"]["body"]',
          '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]',
          '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]',
          '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["object"]',
          '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["property"]',
          '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["property"]["id"]'
        ]
        > t.ast["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["property"]["id"]
        Node {
          type: 'Identifier',
          start: 67,
          end: 68,
          loc: SourceLocation {
            start: Position { line: 4, column: 23 },
            end: Position { line: 4, column: 24 },
            filename: undefined,
            identifierName: 'a'
          },
          name: 'a'
        }

const2let

  • for debug using

  • actually ,const is a runtime-check feature

      /*
      > function tst() {
      ...     const a;
          const a;
                ^
    
      Uncaught SyntaxError: Missing initializer in const declaration
      >     a=100
      100
      > }
      }
      ^
    
      */
    
      cd =`function tst() {
          const a;
          a=100
      }`
    
    
      > cd =`function tst() {
           const a;
          a=100
      }`
      'function tst() {\n    const a;\n    a=100\n}'
      >
      > const2let(cd)
      'function tst() {\n  let a;\n  a = 100;\n}'
      >

hoist_func_decl

  • stage0, func declaration hoist

  • not the final ,only hoist to first ance-block, not to function block

       var cd =`function A () {
             let x = 0
             console.log(tst())
             {
                console.log(tst())
                function tst() {return(x+1)}
             }
             function tst() {return(x)}
       }`
    
    
        s0 = split_var_decl(cd)
        s1 = split_var_declor(s0)
        s2 = hoist_var(s1)
        s3 = hoist_func_decl(s2)
    
       > console.log(s3)
       function A() {
         function tst() {
           return x;
         }
    
         let x;
         x = 0;
         console.log(tst());
         {
           function tst() {
             return x + 1;
           }
    
           console.log(tst());
         }
       }

fdecl2fexpr

  • must be used after hoist_func_decl

                var cd = `
                    function tst(u,v) {
                         let a=100;
                         function inner() {
                             var x;
                             function tst() {}
                         }
                    }
                `
    
              > console.log(fdecl2fexpr(cd))
              var tst = function tst(u, v) {
                let a = 100;
    
                var inner = function inner() {
                  var x;
    
                  var tst = function tst() {};
                };
              };

cdecl2cexpr

  • class declaration to class expression

       var cd = `
           class A {
               method() {
                   class B {}
                   class C {}
                   function tst() {
                       class D {}
                   }
               }
           }
       `
    
    
       > console.log(cdecl2cexpr(cd))
       let A = class A {
         method() {
           let B = class B {};
           let C = class C {};
    
           function tst() {
             let D = class D {};
           }
         }
    
       };

split_var_decl

  • for debug AND hoist using

const {split_var_decl} = require("nv-js-parse")
var code = `
    function tst() {
        let a,b=3,c;
        return(a+b+c)
}`


> console.log(split_var_decl(code))
function tst() {
  let a;
  let b = 3;
  let c;
  return a + b + c;
}

var code = `
    function tst() {
        let x,[{a,b},c]=[{a:666,b:777},3],y;
        return(a+b+c)
}`

> console.log(split_var_decl(code))
function tst() {
  let x;
  let [{
    a,
    b
  }, c] = [{
    a: 666,
    b: 777
  }, 3];
  let y;
  return a + b + c;
}

> tst()
1446
>


    >      var cd = `function tst() {
    ...          var a,b=8;
    ...          for(let i=0,j;i<3;i++,j++) {let {x,y}={}}
    ...          var c = a+b
    ...      }`
    > console.log(split_var_decl(cd))
    function tst() {
      var a;
      var b = 8;
      {                               //----------------
        let i = 0;
        let j;

        for (; i < 3; i++, j++) {
          let {
            x,
            y
          } = {};
        }
      }                             //------------------special handle of for AND forin AND forof
      var c = a + b;
    }

split_var_declor

  • for debug AND hoist using
  • must be used after split_var_decl

      var cd = `
          function tst(u,v) {
              let x,e,ee;
              let [{a,b=e='EEEEE',...f},c=333,d,...g]=[{a:666,b:777},3];
              let [{aa,bb=ee='1111111',...ff},cc=333,dd,...gg]=[{aa:666,bb:777},3];
              let [] = [],[,] =[],[...args] = [1,2],{...D} = {1:2,3:4},[A] = [1,2],{B} = {B:2,3:4},[C=10] = [],{E=999} = {};
              return([u,v,x,a,b,e,f,c,d,g,aa,bb,ee,ff,cc,dd,gg,args,D,A,B,C,E])
          }
      `
      
      /*
      > eval(`(${cd})(100,500)`)
      [
        100,                500,
        undefined,          666,
        777,                undefined,
        {},                 3,
        undefined,          [],
        666,                777,
        undefined,          {},
        3,                  undefined,
        [],                 [ 1, 2 ],
        { '1': 2, '3': 4 }, 1,
        2,                  10,
        999
      ]
      >
      
      */
      s0 = split_var_decl(cd)
      console.log(s0)
      /*
      function tst(u, v) {
        let x;
        let e;
        let ee;
        let [{
          a,
          b = e = 'EEEEE',
          ...f
        }, c = 333, d, ...g] = [{
          a: 666,
          b: 777
        }, 3];
        let [{
          aa,
          bb = ee = '1111111',
          ...ff
        }, cc = 333, dd, ...gg] = [{
          aa: 666,
          bb: 777
        }, 3];
        let [] = [];
        let [,] = [];
        let [...args] = [1, 2];
        let { ...D
        } = {
          1: 2,
          3: 4
        };
        let [A] = [1, 2];
        let {
          B
        } = {
          B: 2,
          3: 4
        };
        let [C = 10] = [];
        let {
          E = 999
        } = {};
        return [u, v, x, a, b, e, f, c, d, g, aa, bb, ee, ff, cc, dd, gg, args, D, A, B, C, E];
      }
      
      */
      /*
      > eval(`(${s0})(100,500)`)
      [
        100,                500,
        undefined,          666,
        777,                undefined,
        {},                 3,
        undefined,          [],
        666,                777,
        undefined,          {},
        3,                  undefined,
        [],                 [ 1, 2 ],
        { '1': 2, '3': 4 }, 1,
        2,                  10,
        999
      ]
      >
      
      */
      s1 = split_var_declor(s0)
      console.log(s1)
      
      /*
      function tst(u, v) {
        let x;
        let e;
        let ee;
        let a;
        let b;
        let f;
        let c;
        let d;
        let g;
        [{
          a,
          b = e = 'EEEEE',
          ...f
        }, c = 333, d, ...g] = [{
          a: 666,
          b: 777
        }, 3];
        let aa;
        let bb;
        let ff;
        let cc;
        let dd;
        let gg;
        [{
          aa,
          bb = ee = '1111111',
          ...ff
        }, cc = 333, dd, ...gg] = [{
          aa: 666,
          bb: 777
        }, 3];
        [] = [];
        [,] = [];
        let args;
        [...args] = [1, 2];
        let D;
        ({ ...D
        } = {
          1: 2,
          3: 4
        });
        let A;
        [A] = [1, 2];
        let B;
        ({
          B
        } = {
          B: 2,
          3: 4
        });
        let C;
        [C = 10] = [];
        let E;
        ({
          E = 999
        } = {});
        return [u, v, x, a, b, e, f, c, d, g, aa, bb, ee, ff, cc, dd, gg, args, D, A, B, C, E];
      }
      
      */
      
      /*
      > eval(`(${s1})(100,500)`)
      [
        100,                500,
        undefined,          666,
        777,                undefined,
        {},                 3,
        undefined,          [],
        666,                777,
        undefined,          {},
        3,                  undefined,
        [],                 [ 1, 2 ],
        { '1': 2, '3': 4 }, 1,
        2,                  10,
        999
      ]
      >
      
      */



      var cd = `function tst() {for(let i=1,[x,y]=[888];i<3;i++) {}}`
      s0 = split_var_decl(cd)
      s1 = split_var_declor(s0)
      console.log(s1)

      /*
         function tst() {
           {
             let i;
             i = 1;
             let x;
             let y;
             [x, y] = [888];
         
             for (; i < 3; i++) {}
           }
         }
      */


      var cd = `function tst() {for(let i;i<3;i++) {}}`
      s0 = split_var_decl(cd)
      s1 = split_var_declor(s0)
      console.log(s1)

       /*
       function tst() {
         {
           let i;
       
           for (; i < 3; i++) {}
         }
       }
       */

     var cd = `
         async function tst() {
             let arr =[];
             let d = {};
             let g = (async function *(){})();
             for(let i=1,y;i<3;i++) {}
             for(let ele of arr) {}
             for(let k in d) {}
             for await (let  each of g) {}
         }
     `

      s0 = split_var_decl(cd)
      s1 = split_var_declor(s0)
      console.log(s1)
       /*
       async function tst() {
         let arr;
         arr = [];
         let d;
         d = {};
         let g;
       
         g = async function* () {}();
       
         {
           let i;
           i = 1;
           let y;
       
           for (; i < 3; i++) {}
         }
         {
           let ele;
       
           for (ele of arr) {}
         }
         {
           let k;
       
           for (k in d) {}
         }
         {
           let each;
       
           for await (each of g) {}
         }
       }
        */

hoist_var

  • must be used after split_var_decl -> split_var_declor

      const {
          split_var_decl,
          split_var_declor,
          tree,
          hoist_var,
      } = require("nv-js-parse")
        
                var cd = `
                    function tst(u,v) {
                        let x;
                        {
                            var y=888;
                            {
                                var [z,{w,r}] = [1,{w:2,r:3}];
                                 let A;
                            }
                        }
                    }
                `
                  
                s0 = split_var_decl(cd)
                s1 = split_var_declor(s0)
                s2 = hoist_var(s1)
        
        
      > console.log(s2)
      function tst(u, v) {
        let x;
        var y;
        var z;
        var w;
        var r;
        {
          y = 888;
          {
            [z, {
              w,
              r
            }] = [1, {
              w: 2,
              r: 3
            }];
            let A;
          }
        }
      }

rare special cases

    > var cd =`
    ... function tst() {
    ...   var a;
    ...   {
    .....     var a;
    .....     a = 13;
    .....   }
    ... }`
    >
    > hoist_var(cd)
    'function tst() {\n  var a;\n  var a;\n  {\n    a = 13;\n  }\n}'
    > console.log(hoist_var(cd))
    function tst() {
      var a;
      var a;
      {
        a = 13;
      }
    }






    var cd =`
    var tst;

    tst = function tst() {
      var a;
      {
        var a;
      }
    };
    `

    > var cd =`
    ... var tst;
    ...
    ... tst = function tst() {
    ...   var a;
    ...   {
    .....     var a;
    .....   }
    ... };
    ... `
    > console.log(hoist_var(cd))
    var tst;

    tst = function tst() {
      var a;
      var a;
      {}
    };
    >

merge_dupe_var_decl

  • must be used after hoist_var

    var cd = `
    function tst() {
      var a;
      var a;
      {
        a = 13;
      }
    }`

    merge_dupe_var_decl(cd)


    > console.log(merge_dupe_var_decl(cd))
    [
      ‍ [        id <Identifier> {"name":"tst"}] {},
      ‍ [                    id <Identifier> {"name":"a"}] {},
      ‍ [                    id <Identifier> {"name":"a"}] {},
      ‍ [                        left <Identifier> {"name":"a"}] {}
    ]
    function tst() {
      var a;
      {
        a = 13;
      }
    }

###when conflict with params-

var cd= `function tst(a) {
    var a;
    return(a)
}`


> console.log(merge_dupe_var_decl(cd))
function tst(a) {
  return a;
}

split_nonidlval_asgn_expr

  • must be used after split_var_declor
  • if the AssignmentExpression left(LVal) is NOT direct Identifier
  • (such as MemberExpression,ArrayPattern,ObjectPattern....)
  • it will split it to three part, see below

    var cd =`[z,{w,r}] = [1,{w:2,r:3}]`

    console.log(split_nonidlval_asgn_expr(cd))

    /*
        let ___swapper_b1cf8a9c_$AssignmentExpression___ = [1, {
          w: 2,
          r: 3
        }];

        [z, {
          w,
          r
        }] = ___swapper_b1cf8a9c_$AssignmentExpression___;


    */

          var cd = `
            function tst(u,v) {
                let x;
                {
                    var y=888;
                    {
                        var [z,{w,r}] = [1,{w:2,r:3}];
						var [u,{v},...X] = [10,{v:20}];
                        let A;
						var B=D=E=1111
                    }
                }
				var [z,{w,r}] = [10,{w:20,r:30}];
            }
        `
        
        s0 = split_var_decl(cd)
        s1 = split_var_declor(s0)
        s2 = hoist_var(s1)
        s3 = split_nonidlval_asgn_expr(s2)
		s4 = merge_dupe_var_decl(s3)
		console.log(s4)
		
    /*
    function tst(u, v) {
      var y;
      var z;
      var w;
      var r;
      var X;
      var B;
      let x;
      {
        y = 888;
        {
          let ___swapper_ec071153_$AssignmentExpression___ = [1, {
            w: 2,
            r: 3
          }];
          [z, {
            w,
            r
          }] = ___swapper_ec071153_$AssignmentExpression___;
          let ___swapper_fcc8fd5d_$AssignmentExpression___ = [10, {
            v: 20
          }];
          [u, {
            v
          }, ...X] = ___swapper_fcc8fd5d_$AssignmentExpression___;
          let A;
          B = D = E = 1111;
        }
      }
      let ___swapper_b72b9d99_$AssignmentExpression___ = [10, {
        w: 20,
        r: 30
      }];
      [z, {
        w,
        r
      }] = ___swapper_b72b9d99_$AssignmentExpression___;
    }
    */

var_to_let

  • must be used after merge_dupe_var_decl

      var cd = `
      function tst() {
        var a;
        var a;
        {
          a = 13;
        }
      }`
    
      var s0 = merge_dupe_var_decl(cd)
      var s1 = var2let(s0)
      > console.log(s1)
      function tst() {
        let a;
        {
          a = 13;
        }
      }

split_rtrn_stmt

  • move argument of return-statement out

const {split_rtrn_stmt} = require("nv-js-parse");


    var cd =`
    function tst(a,b,c) {
        function inner() {
            return(c*3)
        }
        return((a+b+inner()))
    }
    `
 
    console.log(split_rtrn_stmt(cd))




    function tst(a, b, c) {
      function inner() {
        let ___rslt_0296616b_$ReturnStatement___;

        ___rslt_0296616b_$ReturnStatement___ = c * 3;
        return ___rslt_0296616b_$ReturnStatement___;
      }

      let ___rslt_32b00b98_$ReturnStatement___;

      ___rslt_32b00b98_$ReturnStatement___ = a + b + inner();
      return ___rslt_32b00b98_$ReturnStatement___;
    }

split_thrw_stmt

    var src = `
    function tst() {
        throw(new Error("!!"));
        {
            throw a;
        }
    }
    `

    > console.log(x.split_thrw_stmt(src))
    function tst() {
      let ___rslt_2a23863e_$ThrowStatement___;

      ___rslt_2a23863e_$ThrowStatement___ = new Error("!!");
      throw ___rslt_2a23863e_$ThrowStatement___;
      {
        let ___rslt_91675550_$ThrowStatement___;

        ___rslt_91675550_$ThrowStatement___ = a;
        throw ___rslt_91675550_$ThrowStatement___;
      }
    }

ternery to if-else

    const {conexpr_to_ifelse} = require("nv-js-parse");

    var cd0 = `function tst(a,b,c,d,e) {return(a?b:c?d:e)}`;

    /*
    > function tst(a,b,c,d,e) {return(a?b:c?d:e)}
    > tst(true,false,true,'d','e')
    false
    >
    */

    console.log(conexpr_to_ifelse(cd0));

    /*
    function tst(a, b, c, d, e) {
      return (() => {
        if (a) {
          return b;
        } else {
          return (() => {
            if (c) {
              return d;
            } else {
              return e;
            }
          })();
        }
      })();
    }

    > tst(true,false,true,'d','e')
    false
    >

    */



    var cd1 = `function tst(a,b,c,d,e) {return((a?b:c)?d:e)}`;

    /*
    function tst(a,b,c,d,e) {return((a?b:c)?d:e)}
    > tst(true,false,true,'d','e')
    'e'
    >
    */

    console.log(conexpr_to_ifelse(cd1));

    /*
    function tst(a, b, c, d, e) {
      return (() => {
        if ((() => {
          if (a) {
            return b;
          } else {
            return c;
          }
        })()) {
          return d;
        } else {
          return e;
        }
      })();
    }

    > tst(true,false,true,'d','e')
    'e'
    >

    */

    var cd2 = `
        function tst(a,b,c,d,e) {
            let x = a?b:null
            function inner() {
                let y = a?(
                   c?d:e
                ):(
                   d?100:(e?200:300)
                )
            }
            return(inner())
        }
    `

    console.log(conexpr_to_ifelse(cd2));

    /*
    function tst(a, b, c, d, e) {
      let x = (() => {
        if (a) {
          return b;
        } else {
          return null;
        }
      })();

      function inner() {
        let y = (() => {
          if (a) {
            return (() => {
              if (c) {
                return d;
              } else {
                return e;
              }
            })();
          } else {
            return (() => {
              if (d) {
                return 100;
              } else {
                return (() => {
                  if (e) {
                    return 200;
                  } else {
                    return 300;
                  }
                })();
              }
            })();
          }
        })();
      }

      return inner();
    }
    */

tree

  • read-only

    const {tree} = require("nv-js-parse");
    
    
    var cd2 =`
        function outter() {
            let a ;
            function inner() {
                b
                a;
                {
                    a;
                }
            }
        }
    `
    
    var t = tree(cd2);
    var arr = t.$sdfs()
    var ids = arr.filter(r=>r.path.node.type==='Identifier')
    
    > ids.map(r=>r.path.node.name)
    [ 'outter', 'a', 'inner', 'b', 'a', 'a' ]
    >
    > ids[0].get_closure_scope_nd()
     [Program] {}
    >
    
    > ids[1].get_closure_scope_nd().show_code()
    
    > ids[1].get_ast().name
    'a'
    > ids[1].get_closure_scope_nd().show_code()
    function outter() {
      let a;
    
      function inner() {
        b;
        a;
        {
          a;
        }
      }
    }
    
    > ids[2].get_ast().name
    'inner'
    > ids[2].get_closure_scope_nd().show_code()
    function outter() {
      let a;
    
      function inner() {
        b;
        a;
        {
          a;
        }
      }
    }
    
    > ids[3].get_ast().name
    'b'
    > var top = ids[3].get_closure_scope_nd()
     [Program] {}
    >
    > top.path.scope.globals
    [Object: null prototype] {
      b: Node {
        type: 'Identifier',
        start: 80,
        end: 81,
        loc: SourceLocation {
          start: [Position],
          end: [Position],
          filename: undefined,
          identifierName: 'b'
        },
        name: 'b'
      }
    }
    >
    
    > ids[5].get_ast().name
    'a'
    >
    > ids[5].get_closure_scope_nd().show_code()
    function outter() {
      let a;
    
      function inner() {
        b;
        a;
        {
          a;
        }
      }
    }
    
    
    
    var cd3 = `
       function tst(A,B) {
           function inner() {
               return(A)
           }
       }
    `
    
    
    var t = tree(cd3);
    var arr = t.$sdfs()
    var ids = arr.filter(r=>r.path.node.type==='Identifier')
    ids.map(r=>r.path.node.name)
    [ 'tst', 'A', 'B', 'inner', 'A' ]
    
    > ids[1].get_closure_scope_nd().show_code()
    function tst(A, B) {
      function inner() {
        return A;
      }
    }
    undefined
    > ids[1].get_ast().name
    'A'
    > ids[1].get_closure_scope_nd().show_code()
    function tst(A, B) {
      function inner() {
        return A;
      }
    }
    > ids[4].get_ast().name
    'A'
    > ids[4].get_closure_scope_nd().show_code()
    function tst(A, B) {
      function inner() {
        return A;
      }
    }

binding

      var t = tree(`
           let P;
           function X([tst=666,{a,b}]){
               let uuu=y;
               class C {}
           }
           try{}catch({e}) { let vvv;}
           var D = { s(u,{v}){} }
           class U {}
           {let m;}
           for(let j=0;j<5;j++) {}
           for(let k in X) {}
           for(let ele of X) {}
      `)
      t.get_decl_ids().map(r=>r.get_sig_plstr())
      /*

      [
        'body-declarations-id',
        'body-id',
        'params-elements-left',
        'params-elements-properties-key',
        'params-elements-properties-key',
        'body-body-declarations-id',
        'body-body-id',
        'param-properties-key',
        'body-body-declarations-id',
        'body-declarations-id',
        'params',
        'params-properties-key',
        'body-id',
        'body-declarations-id',
        'init-declarations-id',
        'left-declarations-id',
        'left-declarations-id'
      ]
      */
      var fdecl = t.FunctionDeclaration()[0];

      /*
      > fdecl.show_code()
      function X([tst = 666, {
        a,
        b
      }]) {
        let uuu = y;

        class C {}
      }

      */

      > fdecl.get_binding_def_ids()
      {
        var: [],
        let: [
          ‍ [                    id <Identifier> {"name":"uuu"}] {}
        ],
        const: [],
        fdecl: [],
        cdecl: [
          ‍ [                id <Identifier> {"name":"C"}] {}
        ],
        params: [
          ‍ [                left <Identifier> {"name":"tst"}] {},
          ‍ [                    value <Identifier> {"name":"a"}] {},
          ‍ [                    value <Identifier> {"name":"b"}] {}
        ],
        global: [],
        catch_param: []
      }
      >


        var cd = `
        function tst() {
            let [{
                      a,
                      b = e = 'EEEEE',
                      ...f
                    }, 
                    c = 333, d, 
                    [A,B,C,{E,F}],
                    ...g
          ] =[];
        }
        `


        var t = tree(cd);
        var fdecl = t.$sdfs()[1]

        > fdecl.get_decl_ids().map(r=>r.ast.name)
        [
          'a', 'b', 'f', 'c',
          'd', 'A', 'B', 'C',
          'E', 'F', 'g'
        ]
        >


        function tst() {
            let [{
                      a,
                      b = e = 'EEEEE',               //identifier-e ast-path-sign not match
                      ...f
                    },
                    c = 333, d,
                    [A,B,C,{E,F}],
                    ...g
          ] =[{},undefined,undefined,[1,2,3,{}]];
        }

        /*
        > tst()
        > e
        'EEEEE'                   //e is global

        */

decl id type

  • for static trace using

      var cd = `
          function tst(a,{b}) {
              let c;
              {
                 var d;
              }
              try{}catch(e){}
          }
          let _f1       = function (f) {}
          const _lambda = (g)=> {}
          class C {
              method(h,[j]) {}
              #method([k,{l}]){}
          }
          let O = {m(n){}}
          try{}catch({p}){}
          for(let i=0;i<5;i++) {}
          for(let {I}={I:0};i<5;i++) {}
          for(let ele of []) {}
          for(let [ELE] of [[1],[2]]) {}
          for(let k in {}) {}
          for(let {length} in [0,1,2,3,4,5,6,7,8,9,10]) {}              //this is a valid syntax
      `
    
      var t = tree(cd)
    
      > ids = t.get_decl_ids()
      [
        ‍ [        id <Identifier> {"name":"tst"}] {},
        ‍ [        params[0] <Identifier> {"name":"a"}] {},
        ‍ [                value <Identifier> {"name":"b"}] {},
        ‍ [                    id <Identifier> {"name":"c"}] {},
        ‍ [                        id <Identifier> {"name":"d"}] {},
        ‍ [                    param <Identifier> {"name":"e"}] {},
        ‍ [            id <Identifier> {"name":"_f1"}] {},
        ‍ [                params[0] <Identifier> {"name":"f"}] {},
        ‍ [            id <Identifier> {"name":"_lambda"}] {},
        ‍ [                params[0] <Identifier> {"name":"g"}] {},
        ‍ [        id <Identifier> {"name":"C"}] {},
        ‍ [                params[0] <Identifier> {"name":"h"}] {},
        ‍ [                    elements[0] <Identifier> {"name":"j"}] {},
        ‍ [                    elements[0] <Identifier> {"name":"k"}] {},
        ‍ [                            value <Identifier> {"name":"l"}] {},
        ‍ [            id <Identifier> {"name":"O"}] {},
        ‍ [                    params[0] <Identifier> {"name":"n"}] {},
        ‍ [                    value <Identifier> {"name":"p"}] {},
        ‍ [                id <Identifier> {"name":"i"}] {},
        ‍ [                        value <Identifier> {"name":"I"}] {},
        ‍ [                id <Identifier> {"name":"ele"}] {},
        ‍ [                    elements[0] <Identifier> {"name":"ELE"}] {},
        ‍ [                id <Identifier> {"name":"k"}] {},
        ‍ [                        value <Identifier> {"name":"length"}] {}
      ]
      >
    
    
      > ids[0].is_fdecl_id()
      true
      > ids[1].is_fdecl_param_id()
      true
      > ids[2].is_fdecl_param_id()
      true
      >
      > ids[3].is_let_decl_id()
      true
      >
      > ids[4].is_var_decl_id()
      true
      >
      > ids[5].is_catch_param_id()
      true
      >
      > ids[6].is_let_decl_id()
      true
      >
      > ids[7].is_fexpr_param_id()
      true
      >
      > ids[8].is_const_decl_id()
      true
      >
      > ids[9].is_arrow_param_id()
      true
      >
      > ids[10].is_cdecl_id()
      true
      >
      > ids[11].is_cls_method_param_id()
      true
      >
      > ids[12].is_cls_method_param_id()
      true
      >
      > ids[13].is_cls_priv_method_param_id()
      true
      >
      > ids[14].is_cls_priv_method_param_id()
      true
      >
      > ids[15].is_let_decl_id()
      true
      >
      > ids[16].is_obj_method_param_id()
      true
      >
      > ids[17].is_catch_param_id()
      true
      >
      > ids[18].is_for_init_id()
      true
      >
      > ids[19].is_for_init_id()
      true
      >
      > ids[20].is_forof_id()
      true
      > ids[21].is_forof_id()
      true
      > ids[22].is_forin_id()
      true
      > ids[23].is_forin_id()
      true
      >

find escaped id

    var cd = `
        function tst(a) {
            let b=10,c={'key':X};
            a = b+c ;
            {
                let u = 5;
                a = a + u;
            }
            return(a)
        }
    `

    var t = tree(cd)
    var f = t.$fstch()

    > f.get_decl_ids()
    [
      ‍ [        params[0] <Identifier> {"name":"a"}] {},
      ‍ [                    id <Identifier> {"name":"b"}] {},
      ‍ [                    id <Identifier> {"name":"c"}] {},
      ‍ [                        id <Identifier> {"name":"u"}] {}          //后代block内的
    ]
    >

    > f.get_own_local_decl_ids()
    {
      var: [],
      let: [
        ‍ [                    id <Identifier> {"name":"b"}] {},
        ‍ [                    id <Identifier> {"name":"c"}] {}
      ],
      const: [],
      fdecl: [],
      cdecl: [],
      params: [
        ‍ [        params[0] <Identifier> {"name":"a"}] {}
      ],
      global: [],
      catch_param: []
    }
    >

    > f.get_own_local_escaped_decl_ids()
    [
      ‍ [        params[0] <Identifier> {"name":"a"}] {}            // 参数 a 被里层 block 使用
    ]
    >

    > f.get_own_local_noescaped_decl_ids()
    [
      ‍ [                    id <Identifier> {"name":"b"}] {},
      ‍ [                    id <Identifier> {"name":"c"}] {}
    ]
    >

    > f.get_nolocal_refed_ids()
    [
      ‍ [                            value <Identifier> {"name":"X"}] {}
    ]
    >




    > f.get_nodecl_notation_ids()
    [
      ‍ [                            value <Identifier> {"name":"X"}] {},
      ‍ [                    left <Identifier> {"name":"a"}] {},
      ‍ [                        left <Identifier> {"name":"b"}] {},
      ‍ [                        right <Identifier> {"name":"c"}] {},
      ‍ [                        left <Identifier> {"name":"a"}] {},             //<a> = a + u
      ‍ [                            left <Identifier> {"name":"a"}] {},         //  a = <a> + u
      ‍ [                            right <Identifier> {"name":"u"}] {},        // a = a + <u>
      ‍ [                argument <Identifier> {"name":"a"}] {}
    ]
    >
    > f.get_own_local_nodecl_ids()
    [
      ‍ [                    left <Identifier> {"name":"a"}] {},              //<a>=b+c
      ‍ [                        left <Identifier> {"name":"b"}] {},         //a=<b>+c
      ‍ [                        right <Identifier> {"name":"c"}] {},        //a=b+<c>
      ‍ [                argument <Identifier> {"name":"a"}] {}              //return(<a>)
    ]
    >

TAC format

  • used in a special js-runtime

  • normally useless

      > const {tree} = require("nv-js-parse")
      > var src =`ReactDOM.render(<App />, document.getElementById('root'));`
      > var t = tree(src,{plugins:["typescript","jsx"]})
    
      > t.$sdfs()
      [
        ‍ [program <Program> {"sourceType":"module","interpreter":null}] {},
        ‍ [    body[0] <ExpressionStatement> {}] {},
        ‍ [        expression <CallExpression> {}] {},
        ‍ [            callee <MemberExpression> {"computed":false}] {},
        ‍ [                object <Identifier> {"name":"ReactDOM"}] {},
        ‍ [                property <Identifier> {"name":"render"}] {},
        ‍ [            arguments[0] <JSXElement> {}] {},
        ‍ [                openingElement <JSXOpeningElement> {"selfClosing":true}] {},
        ‍ [                    name <JSXIdentifier> {"name":"App"}] {},
        ‍ [            arguments[1] <CallExpression> {}] {},
        ‍ [                callee <MemberExpression> {"computed":false}] {},
        ‍ [                    object <Identifier> {"name":"document"}] {},
        ‍ [                    property <Identifier> {"name":"getElementById"}] {},
        ‍ [                arguments[0] <StringLiteral> {"value":"root"}] {}
      ]
      >
    
      // K = listKey:AstString | Key:AstString
      // T = K@TYPE
      // Attr = Object
      // Ele  = [T,Attr?,Array<Ele>?]
      //
    
      > var tac = t.to_tac()
      > console.dir(tac,{depth:null})
      [
        'program@Program',{ sourceType: 'module', interpreter: null }, [
          'body@ExpressionStatement', [
            'expression@CallExpression', [
              'callee@MemberExpression',{ computed: false },[
                'object@Identifier',{ name: 'ReactDOM' },
                'property@Identifier',{ name: 'render' }
              ],
              'arguments@JSXElement',[
                'openingElement@JSXOpeningElement',{ selfClosing: true },[
                    'name@JSXIdentifier', { name: 'App' }
                 ]
              ],
              'arguments@CallExpression',[
                'callee@MemberExpression',{ computed: false },[
                  'object@Identifier',{ name: 'document' },
                  'property@Identifier',{ name: 'getElementById' }
                ],
                'arguments@StringLiteral',{ value: 'root' }
              ]
            ]
          ]
        ]
      ]

rplc_nodecl_undef_with_void0

    var code =`
    function tst() {
        let a = undefined;                          //============================>this undefined is right-hand  and on global,SHOULD-BE-REPLACED
        function inner() {
            let undefined = 999       //this undefined is left-hand and local #0
            return(undefined)          //this undefined is #0
        }
        console.log(1,inner())           //999
        function inner2() {
            function undefined () {     //this undefined is left-hand and local   #1
                return(undefined)       //this undefined is #1
            }
            return(undefined)          //this undefined is #1
        }
        console.log(2,inner2())           //[Function: undefined]
        function inner3() {
            let undefined =888;        //this undefined is left-hand and local #2
            let r = (()=> {
                return(undefined)      //this undefined is #2
            })();
            return(r)
        }
        console.log(3,inner3())                  //888
        /////
        function inner4() {
             try {
                 x = undefined ;   // ============================>this undefined is right-hand  and on global ,SHOULD-BE-REPLACED
                 throw(x)
             } catch(e){
                 return(e)
             }
        }
        console.log(4,inner4())    // undefined
        /////
        function inner5() {
           class undefined {
              m() {return(undefined)}                   //class undefined
           }
           t= new undefined()
           return(t)
        }
        console.log(5,inner5())   //undefined {}
        ////
        function inner6() {
           class C {
              undefined() {return(undefined)}            //global undefined coz classMethod
           }
           t= new C()
           return(t.undefined())
        }
        console.log(6,inner6())           //undefined
        /////
        function inner7() {
           let D= {
              undefined() {return(undefined)}            //global undefined coz ObjectMethod
           }
           return(D.undefined())
        }
        console.log(7,inner7())          //undefined
        /////
        function inner8() {
             function undefined() {
                 console.log('in fdecl',undefined)
                 return(undefined)                //function, coz FunctionDeclaration
             }
             console.log('in outter',undefined)
             return(undefined())
        }
        console.log(8,inner8())          //[Function: undefined]
        ////
        function inner9() {
             let _f = function undefined() {
                 console.log('A',undefined===_f)   //true
                 return(undefined)                //function coz FunctionExpression
             }
             console.log('B:',undefined===_f)    //false
             return(_f())
        }
        console.log(9,inner9())
    }
    `

    /*
    > tst()
    1 999
    2 [Function: undefined]
    3 888
    4 undefined
    5 undefined {}
    6 undefined
    7 undefined
    in outter [Function: undefined]
    in fdecl [Function: undefined]
    8 [Function: undefined]
    B: false
    A true
    9 [Function: undefined]
    undefined

    */

    console.log(rplc_nodecl_undef_with_void0(code))

    /*
    function tst() {
      let a = void 0; //============================>this undefined is right-hand  and on global,SHOULD-BE-REPLACED

      function inner() {
        let undefined = 999; //this undefined is left-hand and local #0

        return undefined; //this undefined is #0
      }

      console.log(1, inner()); //999

      function inner2() {
        function undefined() {
          //this undefined is left-hand and local   #1
          return undefined; //this undefined is #1
        }

        return undefined; //this undefined is #1
      }

      console.log(2, inner2()); //[Function: undefined]

      function inner3() {
        let undefined = 888; //this undefined is left-hand and local #2

        let r = (() => {
          return undefined; //this undefined is #2
        })();

        return r;
      }

      console.log(3, inner3()); //888
      /////

      function inner4() {
        try {
          x = void 0; // ============================>this undefined is right-hand  and on global ,SHOULD-BE-REPLACED

          throw x;
        } catch (e) {
          return e;
        }
      }

      console.log(4, inner4()); // undefined
      /////

      function inner5() {
        class undefined {
          m() {
            return undefined;
          } //class undefined


        }

        t = new undefined();
        return t;
      }

      console.log(5, inner5()); //undefined {}
      ////

      function inner6() {
        class C {
          undefined() {
            return void 0;
          } //global undefined coz classMethod


        }

        t = new C();
        return t.undefined();
      }

      console.log(6, inner6()); //undefined
      /////

      function inner7() {
        let D = {
          undefined() {
            return void 0;
          } //global undefined coz ObjectMethod


        };
        return D.undefined();
      }

      console.log(7, inner7()); //undefined
      /////

      function inner8() {
        function undefined() {
          console.log('in fdecl', undefined);
          return undefined; //function, coz FunctionDeclaration
        }

        console.log('in outter', undefined);
        return undefined();
      }

      console.log(8, inner8()); //[Function: undefined]
      ////

      function inner9() {
        let _f = function undefined() {
          console.log('A', undefined === _f); //true

          return undefined; //function coz FunctionExpression
        };

        console.log('B:', void 0 === _f); //false

        return _f();
      }

      console.log(9, inner9());
    }


    */

    /*
    > tst()
    1 999
    2 [Function: undefined]
    3 888
    4 undefined
    5 undefined {}
    6 undefined
    7 undefined
    in outter [Function: undefined]
    in fdecl [Function: undefined]
    8 [Function: undefined]
    B: false
    A true
    9 [Function: undefined]

    */

get funclike description

  • funclike: it is for convert a func/lambda/method to a single-param-function-without-any-lexical-binding

  • used in nvlang for fctx grammar

  • similiar to with , but NOT permit any lexical VarDeclaration

  • for tracing purpose

      {
        FunctionParent: [
          'FunctionDeclaration',
          'FunctionExpression',
          'ObjectMethod',
          'ArrowFunctionExpression',
          'ClassMethod',
          'ClassPrivateMethod'
        ]
      }

    var t = tree(`
        function tst(a,{b,c},...args) {
            let A;
            let B;
            let {x,y} = {};
        }
    `)

    /*
    > f.get_desc_of_funclike()
    [
      'tst',                                       //name
      'FunctionDeclaration',                       //ast-type
      { generator: false, async: false },          //attribs
      {
        A: null,
        B: null,
        x: null,
        y: null,
        a: null,
        b: null,
        c: null,
        args: []
      }                                            //---ctx after extract all params AND lexical-binding
    ]
    >
    */

signed-pl

  • find all declaration/def ids in a file, and generate a unique-path
  • it is used in nvlang for gproc grammar, which NOT permit any local variable

> t.$sdfs().filter(nd=>nd.is_decl_id()).map(id=>id.get_id_plsign())
[
  'body-0-declarations-0-id:traverse',
  'body-1-declarations-0-id-properties-0-value:SimpleStack',
  'body-1-declarations-0-id-properties-1-value:DPGT',
  'body-1-declarations-0-id-properties-2-value:is_int',
  'body-1-declarations-0-id-properties-3-value:is_str',
  'body-2-declarations-0-id-properties-0-value:Root',
  'body-3-declarations-0-id:ary_clu',
  .....

for stmt to while

    var cd = `
    function tst() {
        for(let i=0;i<999;i++) {
            console.log(i);
            let b = i +666
        }
    }`


    console.log(for_stmt_to_while(cd))
    /*
    function tst() {
      {
        let i = 0;

        while (i < 999) {
          console.log(i);
          let b = i + 666;
          i++
        }
      }
    }

    */


    var cd = `
    async function tst() {
        let b;
        for(let i=0;i<999;i++) {
            await i;
            console.log(i);
            b = i +666;
            if(b>1500) {
                break
            }
        }
        return(b)
    }`

    console.log(for_stmt_to_while(cd))
    /*
    async function tst() {
      let b;
      {
        let i = 0;

        while (i < 999) {
          await i;
          console.log(i);
          b = i + 666;

          if (b > 1500) {
            break;
          }

          i++
        }
      }
      return b;
    }

    */

fmt-una-expr

  • wrap UnaryExpression in a SequenceExpression
  • normally useless

    > x.fmt_una_expr('!a')
    '!(0, a);'
    >


    > x.fmt_una_expr('!(typeof u.v)')
    '!(0, typeof (0, u.v));'
    >

replace update-expression WITH a closure

  • update-expr is boring to do static tracing

    var cd =`
    function tst(arr) {
        let v = 100;
        let d = {prop:100}
        arr = arr.forEach(
            nd => {
               v = v++;
               v = v--;
               v = ++v;
               --v;
               d.prop++;
               d.prop=++d.prop;
               d.prop--;
               d.prop=--d.prop;
            }
        )
        return([v,d])
    }
    `

    /*
    > tst([1,1,1])
    [ 100, { prop: 100 } ]
    >

    */

    console.log(rplc_updt_expr_with_closure(cd))


    /*
    function tst(arr) {
      let v = 100;
      let d = {
        prop: 100
      };
      arr = arr.forEach(nd => {
        v = (() => {
          let old_val = v;
          let new_val = old_val + 1;
          v = new_val;
          return old_val;                                    // v++  postfix-rtrn-old
        })();

        v = (() => {
          let old_val = v;
          let new_val = old_val - 1;
          v = new_val;
          return old_val;                                  //v--   postfix-rtrn-old
        })();

        v = (() => {
          let old_val = v;
          let new_val = old_val + 1;
          v = new_val;
          return new_val;                                 //++v  prefix-rtrn-new
        })();

        (() => {
          let old_val = v;
          let new_val = old_val - 1;
          v = new_val;
          return new_val;                                  //--v  prefix-rtrn-new
        })();

        (() => {
          let old_val = d.prop;
          let new_val = old_val + 1;
          d.prop = new_val;
          return old_val;
        })();

        d.prop = (() => {
          let old_val = d.prop;
          let new_val = old_val + 1;
          d.prop = new_val;
          return new_val;
        })();

        (() => {
          let old_val = d.prop;
          let new_val = old_val - 1;
          d.prop = new_val;
          return old_val;
        })();

        d.prop = (() => {
          let old_val = d.prop;
          let new_val = old_val - 1;
          d.prop = new_val;
          return new_val;
        })();
      });
      return [v, d];
    }

    */

    > tst([1,1,1])
    [ 100, { prop: 100 } ]
    >

get_completion_parent_nd

  • get the completion parent closure/block of
  • return/throw/break/continue

    var src = `
    function tst() {
        var m=0
        xx:while(m<3){
            console.log("here")
            i = 0;
            n = 0;
            while (i < 5) {
               i++;
               if (i === 3) {
                  continue xx;
               }
               n += i;
            }
            m=m+1
        }
        function inner() {
            for(let i=0;i<5;i++){
                break
                return(i)
            }
        }
    }
    `

    //return

    var t = tree(src);
    var rtrn_stmt = t.ReturnStatement()[0];
    > rtrn_stmt
     [69:                            body[1] <ReturnStatement> {}] {}
    >
    > var completion = rtrn_stmt.get_completion_parent_nd()

    > completion
     [54:            body[2] <FunctionDeclaration> {"generator":false,"async":false}] {}
    >
    > completion.show_code()
    function inner() {
      for (let i = 0; i < 5; i++) {
        break;
        return i;
      }
    }


    //break
    > var brk_stmt = t.BreakStatement()[0]

    > brk_stmt
     [68:                            body[0] <BreakStatement> {}] {}
    >
    > var completion = brk_stmt.get_completion_parent_nd()
    > completion
     [57:                    body[0] <ForStatement> {}] {}
    > completion.show_code()
    for (let i = 0; i < 5; i++) {
      break;
      return i;
    }


    //continue label

    > var conti_stmt = t.ContinueStatement()[0]
    undefined
    > conti_stmt
     [42:                                        body[0] <ContinueStatement> {}] {}
    >
    > var completion = conti_stmt.get_completion_parent_nd()
    undefined
    > completion
     [10:                body <WhileStatement> {}] {}
    >
    > completion.show_code()
    while (m < 3) {
      console.log("here");
      i = 0;
      n = 0;

      while (i < 5) {
        i++;

        if (i === 3) {
          continue xx;
        }

        n += i;
      }

      m = m + 1;
    }
    > completion.$parent()
     [8:            body[1] <LabeledStatement> {}] {}
    > completion.$parent().show_code()
    xx: while (m < 3) {
      console.log("here");
      i = 0;
      n = 0;

      while (i < 5) {
        i++;

        if (i === 3) {
          continue xx;
        }

        n += i;
      }

      m = m + 1;
    }

get_completion_check_points

  • find break/continue 's corresponding block/forin/forof/for/while/dowhile/switch
  • find return/throw 's corresponding func-decl/func-expr/cls-method/obj-method/arrow/cls-priv-method

    var src = `
    function tst() {
        while(true) {
            return(100)
        }
        try {
            return(200)
        } catch(e) {
             ()=> {
                 return('!!')
             }
        } finally {
        }
        {
           throw(400)
        }
    }`

    > var t = tree(src)
    > t.FunctionDeclaration()[0]
     [1:    body[0] <FunctionDeclaration> {"generator":false,"async":false}] {}
    > var fdecl = t.FunctionDeclaration()[0]
    > fdecl.get_rtrn_check_points()
    [
      ‍ [7:                    body[0] <ReturnStatement> {}] {},
      ‍ [11:                    body[0] <ReturnStatement> {}] {}
    ]
    > var rtrns = fdecl.get_rtrn_check_points()
    > rtrns
    [
      ‍ [7:                    body[0] <ReturnStatement> {}] {},
      ‍ [11:                    body[0] <ReturnStatement> {}] {}
    ]
    > rtrns.map(nd=>nd.show_code())
    return 100;
    return 200;

rm_sibs_after_completion

  • remove following-sibs of completion-node ,see below

    var src = `
    function tst() {
        try {
           let a = 1;
           return(a);
           let b = a*2;
           console.log(b)               //-----------------------------remove
        } catch(e) {
           LBL:for(let a in M) {
             while(true) {
                  if(x) {
                      break;
                      console.log(x)     //-----------------------------remove
                  } else if(y) {
                       continue LBL;
                       console.log(666)   //-----------------------------remove
                  } else {
                       switch(XX) {
                          case(0): {
                          }
                          case(1): {
                              break;
                              console.log(UUU)  //-----------------------------remove
                          }
                       }
                  }
             }
          }
        }
    }
    `

    console.log(x.rm_sibs_after_completion(src))


    /*
    function tst() {
      try {
        let a = 1;
        return a;
      } catch (e) {
        LBL: for (let a in M) {
          while (true) {
            if (x) {
              break;
            } else if (y) {
              continue LBL;
            } else {
              switch (XX) {
                case 0:
                  {}

                case 1:
                  {
                    break;
                  }
              }
            }
          }
        }
      }
    }

    */

tailize_try_catch_final

why

  • finalizer of try-statement is confusing
  • its write-order is at last, but its executing order is just before return/throw in try/catch
  • but the write-order of try/catch is BEFORE finalizer
  • I can NOT understand this
  • so transform the finalizer AND make it "reasonable"

example

    > function tst() {
    ...     try {
    .....         console.log(`before-return-in-try`)
                                                         //<====  #0
    .....         return(`i-am-returned`)
    .....     } finally {
    .....         console.log(`finalizer write after try-block`)
    .....     }
    ... }
    >
    > tst()
    before-return-in-try
    finalizer write after try-block   // 
    'i-am-returned'
    >
    >

step

    1. this will take the return-statement|throw-statement out from try-stmt-block|try-catch-handler
    1. convert 【return-statement|throw-statement in 1.】 to a 【if/esle block】
    1. convert try-stmt-finalizer to 【a block】
    1. delete the original try-stmt-finalizer
    1. put the 【if/esle block in 2.】 after 【converted-block-from-try-stmt-finalizer in 3.】
    1. generate a 【block-contain-return|throw】
    1. put the 【block-contain-return|throw in 6.】 at end

purpose

  • its purpose is to tailized rtrn/thrw of try-stmt AND transform the finalizer to its proper position
  • to make the write/read order same-as the execution-order
  • coz, the finally block is boring for static-tracing
  • hard to explain , just see the below examples,example is easy to understand

input

    var src =`
    function tst() {
        let a = 100;

            try {
                let a = (()=>{
                        try {
                                throw(1);
                                    console.log("unreachable")
                            } catch(e) {
                                return(e);
                                    console.log("unreachable")
                            } finally {
                                console.log('inner')
                            }
                    })();
                    if(a>0) {
                            return(a*2);
                            console.log("unreachable")
                    } else {
                        return(a*3)
                            console.log("unreachable")
                    }

            } catch ({e}) {
                console.log("unreachable")
            } finally {
                let arr = [a,a*2,a*3]
                console.log(arr)
            }

            let c = a*3;
            return(c)

    }
    `


    /*
    > tst()
    inner
    [ 100, 200, 300 ]
    2
    >

    */

output

   > console.log(x.tailize_try_catch_final(src))


    function tst() {
      let a = 100;
      //outer-try-catch-final
      {
        let ___τfinalización = [undefined, undefined];
        //outer-try-block
        {
          let a = (() => {
            //inner-  try-catch-final
            {
              let ___τfinalización = [undefined, undefined];
              //inner-try-block
              {
                ___τfinalización = [false, 1];
              }
              //inner-catch-handle
              if (___τfinalización[0] === false) {
                let ___τcatch_clause_value = ___τfinalización[1];
                {
                  let e = ___τcatch_clause_value;
                  ___τfinalización = [true, e];
                }
              } else {}
              //inner-final-block
              {
                console.log('inner');
              }
              //inner-tailized-completion-of-try-catch-final-stmt
              if (___τfinalización[0] === undefined) {} else if (___τfinalización[0] === true) {
                return ___τfinalización[1];
              } else {
                throw ___τfinalización[1];
              }
            }
          })();

          if (a > 0) {
            ___τfinalización = [true, a * 2];
          } else {
            ___τfinalización = [true, a * 3];
          }
        }

        //outer-catch-handle
        if (___τfinalización[0] === false) {
          let ___τcatch_clause_value = ___τfinalización[1];
          {
            let {
              e
            } = ___τcatch_clause_value;
            console.log("unreachable");
          }
        } else {}
        
        //outer-final-block
        {
          let arr = [a, a * 2, a * 3];
          console.log(arr);
        }

        //out-tailized-completion-of-try-catch-final-stmt
        if (___τfinalización[0] === undefined) {} else if (___τfinalización[0] === true) {
          return ___τfinalización[1];
        } else {
          throw ___τfinalización[1];
        }
      }
      let c = a * 3;
      return c;
    }


    /*
    > tst()
    inner
    [ 100, 200, 300 ]
    2
    >

    */

fmt-asgn-expr

  • must used after split_var_decl AND split_var_declor

 replace the below with a = a<op> b

      OP_TO_BINOP: {
        '+=': '+',
        '-=': '-',
        '/=': '/',
        '%=': '%',
        '*=': '*',
        '**=': '**',
        '&=': '&',
        '|=': '|',
        '>>=': '>>',
        '>>>=': '>>>',
        '<<=': '<<',
        '^=': '^',
        '||=': '||',
        '&&=': '&&',
        '??=': '??'
      },

  for example:
       a+=999
       will be replaced to 
          a = a + 999;

  this is for functionize-bin-operator, which will remove all bin-operator
  normally useless

    var  cd =`
        function tst() {