npm.io
1.4.25 • Published 2 years ago

nv-js-parse

Licence
ISC
Version
1.4.25
Deps
7
Size
1.1 MB
Vulns
0
Weekly
0

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() {
            let a=10;
            a+=8;
            {
                a-=a*2;
                function inner() {
                  return(a = a / a);
                }
                a**=inner()
            }
            return(a)
        }
    `

    console.log(x.fmt_asgn_expr(cd))
    /*
        function tst() {
          let a = 10;
          a = a + 8;
          {
            a = a - a * 2;

            function inner() {
              return a = a / a;
            }

            a = a ** inner();
          }
          return a;
        }        
    */
funcize-bin-expr
  • convert binary-expr to a function, such as a+b , a-b ...
  • it is pre-step for converting javascript to a list-format (which can be describe in a list-only-style-ast)
  • this list-format can-be interpreted char-by-char from remote js-source input without handling precedence
  • normally useless
    var cd = `
    function tst() {
        let c = a+b;
        {
            let e = c - d;
            function inner() {
               return(e/f)
            }
            let g = inner();
            h = g % i *j ** k & l | m >> n >>> o << p ^ q == r === s != t !== u in v instanceof w > x < y >= z <= $;
            return(h)
        }
    }
    `

    console.log(funcize_bin_expr(cd))

    //// <@nv-binop-func>
    const ___add = (a,b)=>a+b;
    const ___sub = (a,b)=>a-b;
    const ___div = (a,b)=>a/b;
    const ___mod = (a,b)=>a%b;
    const ___mul = (a,b)=>a*b;
    const ___pow = (a,b)=>a**b;
    const ___band = (a,b)=>a&b;
    const ___bor = (a,b)=>a|b;
    const ___shr = (a,b)=>a>>b;
    const ___ushr = (a,b)=>a>>>b;
    const ___shl = (a,b)=>a<<b;
    const ___bxor = (a,b)=>a^b;
    const ___eq = (a,b)=>a==b;
    const ___teq = (a,b)=>a===b;
    const ___neq = (a,b)=>a!=b;
    const ___nteq = (a,b)=>a!==b;
    const ___in = (a,b)=>(a in b);
    const ___instof = (a,b)=>(a instanceof b);
    const ___gt = (a,b)=>a>b;
    const ___lt = (a,b)=>a<b;
    const ___ge = (a,b)=>a>=b;
    const ___le = (a,b)=>a<=b;

    const ___lor=(a,b)=>a||b;
    const ___land=(a,b)=>a&&b;
    const ___nc=(a,b)=>a??b;
    

    //// </@nv-binop-func>


    function tst() {
      let c = ___add(a, b);

      {
        let e = ___sub(c, d);

        function inner() {
          return ___div(e, f);
        }

        let g = inner();
        h = ___bor(
              ___band(
                  ___mul(
                      ___mod(g, i),
                      ___pow(j, k)
                  ),
                  l
              ),
              ___bxor(
                  ___shl(
                      ___ushr(
                          ___shr(m, n),
                          o
                      ),
                      p
                  ),
                  ___nteq(
                      ___neq(
                          ___teq(
                              ___eq(q, r),
                              s
                          ),
                          t
                      ),
                      ___le(
                          ___ge(
                              ___lt(
                                  ___gt(
                                      ___instof(
                                          ___in(u, v),
                                          w
                                      ),
                                      x
                                  ),
                                  y
                              ),
                              z
                         ),
                         $
                    )
                  )
                )
            );
        return h;
      }
    }
json-literal
  • if nd is a json-literal
  • json-literal matches the below condition
  0.  the node must be 
      ObjectExpression OR 
      ArrayExpression  OR
      NullLiteral      OR
      BooleanLiteral   OR
      StringLiteral    OR
      NumericLiteral   

  1.  only  


    NumericLiteral  OR
    BooleanLiteral  OR
    NullLiteral     OR
    StringLiteral   OR 
    Identifier      OR
    NumericLiteral  OR
    ArrayExpression OR
    ObjectProperty  

    permitted in the des-tree 

  2. if Identifier
     
     the Identifier must be key-of-ObjectProperty  AND
     the-parent-ObjectProperty's computed === false AND
     the-parent-ObjectProperty's shorthand === false 
    > var t = tree(`let ___json___ ={a:100,"b":[1,true,false,null,'str'],["c"]:3333,5555:5555}`)
    > var nd = t.$sdfs()[4];
    > nd.to_json_if_json_lit()
    { '5555': 5555, a: 100, b: [ 1, true, false, null, 'str' ], c: 3333 }
    >
pure template literal
  0. all the expressions must be one of:
 
      BigIntLiteral
  BooleanLiteral
  NullLiteral
  NumericLiteral
  RegExpLiteral
  StringLiteral  
               
      UndefinedRefToGlobal  
      JSONliteral         

      PureTemplateLiteral  // recursive  

  this is for reduce unecessary  nodes in compile-time 
	 var t = tree("`${[1,2,3]}`")
	 var tmplit = t.TemplateLiteral()[0];
	 tmplit.get_cond_pair_for_pure_tmplit()
	 > [ true, '1,2,3' ]
	 
	 var t = tree("`a${[1,2,3]}`")
	 var tmplit = t.TemplateLiteral()[0];
	 tmplit.get_cond_pair_for_pure_tmplit()
	 > [ true, 'a1,2,3' ]
	 
	 var t = tree("`${[1,2,3]}b`")
	 var tmplit = t.TemplateLiteral()[0];
	 tmplit.get_cond_pair_for_pure_tmplit() 
	 > [ true, '1,2,3b' ]
	 
	 var t = tree("`a${[1,2,3]}b`")
	 var tmplit = t.TemplateLiteral()[0];
	 tmplit.get_cond_pair_for_pure_tmplit() 
	 > [ true, 'a1,2,3b' ]
	 
	 
	 var t = tree("`m ${`x ${[1,2,3]} yz`} n`")
	 var tmplit = t.TemplateLiteral()[0];
	 /*
	    > `m ${`x ${[1,2,3]} yz`} n`
	    'm x 1,2,3 yz n'
	    > 
	    > tmplit.get_cond_pair_for_pure_tmplit()
	    [ true, 'm x 1,2,3 yz n' ]
	    > 
	    > 
	 */             

	> x.rplc_pure_temlit_with_str_lit("let V  = `m ${`x ${[1,2,3]} yz`} n`")
	'let V = "m x 1,2,3 yz n";'
	> 
cls_find_same_name_gtst_mthds
  //FIND methods ARE (BOTH setter AND getter) (VIA method-name) IF (method key-node is NOT expr)

var cd =`
class Cls {
    get get_only() {}
    method() {}
    ////
    get gt1() {}
    set ["gt1"](v) {}
    ////
    method2() {}
    set set_only(v) {}
    ////
    get [100]() {}
    set ["100"](v) {}
    ////
}
`
var t = tree(cd);

> t.cls_find_same_name_gtst_mthds()
Map(1) {
  ‍ [3:        body <ClassBody> {}] {} => {
    '100': {
      getter: ‍ [24:            body[6] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":true,"kind":"get"}] {},
      setter: ‍ [27:            body[7] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":true,"kind":"set"}] {}
    },
    gt1: {
      getter: ‍ [10:            body[2] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":false,"kind":"get"}] {},
      setter: ‍ [13:            body[3] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":true,"kind":"set"}] {}
    }
  }
}
> 
find import-source/import-arg/require-arg
    var cd =`
    const babel = require("@babel/parser");
    function wrap() {
         const _cjs_loader = require('internal/modules/cjs/loader');
    }
    import defaultExport1 from "module-name1";
    import * as name2 from "module-name2";
    import { export3 } from "module-name3";
    import { export4 as alias } from "module-name4";
    import { export50 , export51 } from "module-name5";
    import { foo , bar } from "module-name/path/to/specific/un-exported/file";
    import defaultExport6, * as name from "module-name6";
    import "module-name7";
    var promise = import("module-name8");
    `;

    x.get_non_dynamic_impt_and_require_src(cd)

    > x.get_non_dynamic_impt_and_require_src(cd)
    [
      '@babel/parser',
      'internal/modules/cjs/loader',
      'module-name1',
      'module-name2',
      'module-name3',
      'module-name4',
      'module-name5',
      'module-name/path/to/specific/un-exported/file',
      'module-name6',
      'module-name7',
      'module-name8'
    ]
    >
try-spread-if-can
 remove redudancy ary-ptrn OR ary-expr:
           

var cd = `
    const [a,b,...[c,d]] = [1,2,3,4,5];
	{
		 let v = [a,b,...[c,d]]
	}
`

console.log(try_spread_if_can(cd))
/*
const [a, b, c, d] = [1, 2, 3, 4, 5];
{
  let v = [a, b, c, d];
}

*/
find all bad access before initialization id
	var {find_all_bad_access_before_initialization_id} = require("./index")
	var cd = `
	var outter = 999;
	function tst(es) { 
	    outter = 888;
	    {
		a = es[0];
		let es = [1,2,3];
	    }
	    let outter;
	    return(outter)
	}
	/*
	tst([11,22])
	ReferenceError: Cannot access 'outter' before initialization
	    at tst (REPL30:2:12)

	*/
	`


	var bad = find_all_bad_access_before_initialization_id(cd)

	/*
	[
	  {
	    defined_at: [ [ 9, 8 ], [ 9, 14 ], 'outter' ],
	    access_at: [ [ 4, 4 ], [ 4, 10 ], 'outter = 888' ],
	    scope_code: 'function tst(es) {\n' +
	      '  outter = 888;\n' +
	      '  {\n' +
	      '    a = es[0];\n' +
	      '    let es = [1, 2, 3];\n' +
	      '  }\n' +
	      '  let outter;\n' +
	      '  return outter;\n' +
	      '}'
	  },
	  {
	    defined_at: [ [ 7, 12 ], [ 7, 14 ], 'es = [1, 2, 3]' ],
	    access_at: [ [ 6, 12 ], [ 6, 14 ], 'es[0]' ],
	    scope_code: '{\n  a = es[0];\n  let es = [1, 2, 3];\n}'
	  }
	]
	*/
        // just for repl testing  in  nvlang,  USELESS 

        allow struct 

        struct C {}   IS SAME AS
        class  C {}
        // just for repl testing in nvtype , USELESS

        allow generic Type with constructor, the velow is valid
           class C {
               constructor<T1,T2,T3>(p0:T1|T2,p1:T2|T3) {}  
           }

API

  • tree(code)

  • parse(code)

  • unparse(ast)

  • pprint_ast(ast) //add default dark style color for print

  • light_code(code,color_dict,decoratorsBeforeExport=true,rtrn=false) //self-define node color

  • const2let(code)

  • hoist_func_decl(code)

  • fdecl2fexpr(code)

  • cdecl2cexpr(code)

  • split_var_decl(code)

  • split_var_declor(code)

  • hoist_var(code)

  • split_nonidlval_asgn_expr(code)

  • merge_dupe_var_decl(code)

  • var_to_let(code)

  • split_rtrn_stmt(code)

  • split_thrw_stmt(code)

  • rplc_nodecl_undef_with_void0(code)

  • for_stmt_to_while(code)

  • rm_sibs_after_completion(code)

  • tailize_try_catch_final(code)

  • fmt_asgn_expr(code)

  • funcize_bin_expr(code)

  • get_non_dynamic_impt_and_require_src(code)

LICENSE

  • ISC