27
{ JS in JS The Narcissus Project 愚公/周爱民/aimingoo h8p://blog.csdn.net/aimingoo [email protected]

Js in js

  • Upload
    alipay

  • View
    17

  • Download
    3

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Js in js

{ JS  in  JS�

The  Narcissus  Project �

愚公/周爱民/aimingoo h8p://blog.csdn.net/aimingoo [email protected]

Page 2: Js in js

Ñ  new Ñ  with Ñ  function Ñ  object Ñ  eval

概要�

Page 3: Js in js

jsdefs.js� jsparse.js�

jsexec.js�

js.js�

h8ps://github.com/mozilla/narcissus/ h8p://lxr.mozilla.org/mozilla/source/js/narcissus �

Page 4: Js in js

Ñ  Script Ñ  Statements   Ñ  Statement Ñ  Expression Ñ  function �

parse �

Page 5: Js in js

jsdefs.js�l  tokens = ["END", "\n", ";", ...]� ==> { "END": 0, "\n": 1, ... }�

l  var END = 0, NEWLINE = 1, SEMICOLON = 2, COMMA = 3, ASSIGN = 4,�HOOK = 5, COLON = 6, CONDITIONAL = 7, OR = 8, AND = 9, BITWISE_OR = 10,�BITWISE_XOR = 11, BITWISE_AND = 12, EQ = 13, NE = 14, STRICT_EQ = 15,�STRICT_NE = 16, LT = 17, LE = 18, GE = 19, GT = 20, LSH = 21, RSH = 22,�URSH = 23, PLUS = 24, MINUS = 25, MUL = 26, ...�

l  opTypeNames = { '\n': "NEWLINE", ';': "SEMICOLON", ... }�l  keywords = { 'break': 55, 'case', ... }�l  assignOps = ['|', '^', '&', '<<', ...]� ==> { "|": 32, "^": 33, ... }�

标识符索引�

三张表格�

全局变量/常量�

Page 6: Js in js

jsparse.js�l  opPrecedence = {� 'SEMICOLON': 0� 'COMMA': 1,� 'ASSIGN': 2, 'HOOK': 3, 'COLON': 2,� ...�

优先级表�

l  opArity = {� 'COMMA': -2,� 'ASSIGN': 2,� 'HOOK': 3,� 'OR': 2,� ...�

操作数表�

Page 7: Js in js

jsparse.js  -­‐‑  代码结构(1) �var a, i = 100,� v = i + 100;��function t() {� var r = "abc"� function m() {� ...� }� ...� return r;�}��alert(t());�alert(i);�

语句块  Statements�

Script �

function  Script(t,  x)  {        var  n  =  Statements(t,  x);        n.type  =  SCRIPT;        ... } �

function  parse(s,  f,  l)  {        var  t  =  new  Tokenizer(s,  f,  l);        var  x  =  new  CompilerContext(false);        var  n  =  Script(t,  x);

function  Statements  (t,  x)  {        var  n  =  new  Node(t,  BLOCK);          while  (!t.done  &&                t.peek()  !=  RIGHT_CURLY)                n.push(Statement(t,  x));        ... } �

①�

③�

②�

函数  Function �

Page 8: Js in js

jsparse.js  -­‐‑  代码结构(2) �var a, i = 100,� v = i + 100;��function t() {��� ...����}��alert(t());�alert(i);�

语句块  Statements�

语句Statement �

function  Statements  (t,  x)  {        var  n  =  new  Node(t,  BLOCK);          while  (!t.done  &&                t.peek()  !=  RIGHT_CURLY)                n.push(Statement(t,  x));        ... } �

function  Statement(t,  x)  {        var  i,  label,  n,  n2,  ss,  8  =  t.get();        switch  (8)  {            case  FUNCTION:  ...            case  LEFT_CURLY:  ...            case  IF:                n  =  new  Node(t);                n.condition  =  ParenExpression(t,  x);                n.thenPart  =  Statement(t,  x);                n.elsePart  =  ...            default:                if  (8  ==  IDENTIFIER)  ... ....

①�

②�

Page 9: Js in js

jsparse.js  -­‐‑  代码结构(3) �var a, i = 100,� v = i + 100;��function t() {��� ...����}��alert(t());�alert(i);�

语句  Statement �

表达式 Expression �

function  Statement(t,  x)  {    ...    n.condition  =  ParenExpression(t,  x);    //  switch    n.discriminant  =      n2.caseLabel  =      //  for/for..in    n.object  =    n.setup  =    //  try..catch    n2.guard  =    //  other  ...    n.expression  =  Expression(t,  x); } �

function  ParenExpression(t,  x)  {        t.mustMatch(LEFT_PAREN);        var  n  =  Expression(t,  x);        t.mu(RIGHT_PAREN);        return  n; } �

if  (condition)  ....�

return  x�

①�

②�

Page 10: Js in js

jsparse.js  –  示例(1) �

var a, i = 100 , v = i + 100;�

①� ③�

Var  语句�

语句语法分隔符�

②�

Page 11: Js in js

type:SCRIPT [0]

type:IDENTIFIER value: 'a'

Variables(t,  x) �

Expression(t,  x,  COMMA) �

type:NUMBER value: 100

type:NUMBER value: 100

type:IDENTIFIER value: 'i'

type:VAR value: 'var' [0] [1] [2]

type:IDENTIFIER value: 'i' initializer:

type:IDENTIFIER value: 'v' initializer:

type:+ value: '+' [0] [1]

Statements(t,  x)�Script(t,  x) �

Statement  (t,  x)�Expression(t,  x,  COMMA) �

var a, i = 100 , v = i + 100;�

Page 12: Js in js

a, i = 100 , v = i + 100;�

jsparse.js  –  示例(2) �

②� ③� ④�

i = 100�操作数1�

操作数2�操作符�

- 读操作数(Operand)�- 读操作符(Operator)� - 检取已有操作数� - 继续读操作数�- 结束读操作符�- 结束读操作数�

①�

用“;”结束 的一般语句�

语句结束符“;”�⑤�“,”运算符�

Page 13: Js in js

type:SCRIPT [0]

type:IDENTIFIER value: 'a'

Expression(t,  x,  COMMA) �

type:NUMBER value: 100

type:NUMBER value: 100

type:IDENTIFIER value: 'i'

type:COMMA value: ',' [0] [1] [2]

type:+ value: '+' [0] [1]

Statements(t,  x)�Script(t,  x) �

Statement  (t,  x)�

type:SEMICOLON value: 'a' expression:

type:ASSIGN value: '=' [0] [1]

type:ASSIGN value: '=' [0] [1]

type:IDENTIFIER value: 'i'

type:IDENTIFIER value: ‘v'

a, i = 100 , v = i + 100;�

function  Expression(t,  x,  stop)      …  while  (operators.length)        reduce();    return  operands.pop(); } �

Page 14: Js in js

var a, i = 100,� v = i + 100;��function t(x,y) {� var r = "abc"� function m() {� ...� }� ...� return r;�}��alert(t());�alert(i);�

jsparse.js  -­‐‑  代码结构(4) �

函数  Function �

function  Script(t,  x)  {        var  n  =  Statements(t,  x);        n.type  =  SCRIPT;        n.funDecls  =  x.funDecls;        n.varDecls  =  x.varDecls;        return  n; } �

声明 Declared�

function  parse(s,  f,  l)  {        var  t  =  new  Tokenizer(s,  f,  l);        var  x  =  new  CompilerContext(false);        var  n  =  Script(t,  x);

function  Variables(t,  x)  {    x.varDecls.push(n2); … function  FunctionDefinition(t,  x,  …)    var  x2  =  new  CompilerContext(true);    f.body  =  Script(t,  x2); …    x.funDecls.push(f); …�

编译/语法分析期可决定的上下文�

②�

③�

①�

Page 15: Js in js

jsparse.js  –  示例(3) �var a, i = 100,� v = i + 100;��function t(x,y) {� var r = "abc"� function m() {� ...� }� ...� return r;�}��alert(t());�alert(i);�

②�

①�

type:SCRIPT - x.funDecls[0] - x.varDecls:[]

type:FUNCTION name:”t” params:[‘x’, ‘y’] body: functionForm:

type:SCRIPT - x2.funDecls[0] - x2.varDecls:[]

type:FUNCTION name:”m” params:[] body: functionForm:

type:SCRIPT - x2.funDecls[0] - x2.varDecls:[]

type:IDENTIFIER value: 'a'

type:IDENTIFIER value: 'i' initializer:

type:IDENTIFIER value: 'v' initializer:

Page 16: Js in js

jsparse.js  –  functionForm�function t() {� ...�}��{� function t() {� ...� }�}��x = function t() {�}�

var DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2;

Page 17: Js in js

Ñ  Script Ñ  Statements   Ñ  Statement Ñ  Expression Ñ  function �

exec�

Page 18: Js in js

语句-­‐‑语法树�

type:VAR value: 'var' [0] [1] [2]

type:FUNCTION name:”m” params:[] body: functionForm:

type:IF/FOR/TRY... value: condition: ...

type:... value:... expression:

type:SCRIPT funDecls[0] varDecls:[] [0] [1] [2] [3] ...

type:SCRIPT type:SCRIPT

...

type:NUMBER value: 100

type:IDENTIFIER value: 'i'

...

type:+ value: '+' [0] [1]

Page 19: Js in js

执行-­‐‑上下文环境�function  evaluate(s,  f,  l)  { …        var  x  =  ExecutionContext.current;        var  x2  =  new  ExecutionContext(GLOBAL_CODE);        ExecutionContext.current  =  x2;        execute(parse(s,  f,  l),  x2); …�

function  ExecutionContext(type)  {        this.type  =  type; } var  XCp  =  ExecutionContext.prototype; ExecutionContext.current  =  XCp.caller  =  XCp.callee  =  null; XCp.scope  =  {object:  global,  parent:  null}; XCp.thisObject  =  global; XCp.result  =  undefined; XCp.target  =  null; XCp.ecmaStrictMode  =  false;

var      GLOBAL_CODE  =  0,      EVAL_CODE  =  1,      FUNCTION_CODE  =  2;

var  global  =  {        //  Value  properties.        NaN:  NaN,  Infinity:    …,        //  Function  properties.        eval:    function  eval(s)  {  …        Function  :  …        Array  :  …        String:  …

②�

①�

Page 20: Js in js

jsexec.js  –  execute() �function execute(n, x) {� switch (n.type) {� case FUNCTION:� case SCRIPT:� case BLOCK:� case IF:� case ASSIGN:� case LT:� case DELETE:� case CALL:� case COMMA:� for (i = 0, j = n.length; i < j; i++)� v = getValue(execute(n[i], x));� break;� ...� ...� return v;�}�

function getValue(v) {� if (v instanceof Reference) {� ...� return v.base[v.propertyName]}� }� return v;�}�

a, i = 100, v = i + 100;�

Page 21: Js in js

jsexec.js  –  IDENTIFIER�

case IDENTIFIER:� for (s = x.scope; s; s = s.parent) {� if (n.value in s.object)� break;� }� v = new Reference(s && s.object, n.value, n);� break;�

Page 22: Js in js

jsexec.js  –  new �case NEW:�case NEW_WITH_ARGS:� r = execute(n[0], x);� f = getValue(r);� if (n.type == NEW) {� a = {};� a.length = 0;� } else {� a = execute(n[1], x);� }� if (isPrimitive(f) || typeof f.__construct__ != "function") {� throw new TypeError(r + " is not a constructor",� n[0].filename, n[0].lineno);� }� v = f.__construct__(a, x);� break;�

funtion Function() { }��// FOp: FunctionObject.prototype�FOp.__construct__ = function(a,x) {� var o = {}, p = this.prototype;� o.__proto__ = p;� var v = this.__call__(o, a, x);� if (isObject(v)) return v;� return o; �}�

Page 23: Js in js

jsexec.js  –  with �

case WITH:� r = execute(n.object, x);� t = toObject(getValue(r), r, n.object);� x.scope = {object: t, parent: x.scope};� try {� execute(n.body, x);� } finally {� x.scope = x.scope.parent;� }� break;�

Page 24: Js in js

jsexec.js  –  Object/Func.�

var global = {� ...� Object: Object,� Function: function Function(dummy) {� var p = "", b = "", n = arguments.length;� ...�� var f = FunctionDefinition(..., STATEMENT_FORM);� var s = {object: global, parent: null};� return new FunctionObject(f, s);� },�

function FunctionObject(node, scope) {� this.node = node;� this.scope = scope;� this.length = node.params;� var proto = {};� this.prototype = proto;� proto.constructor = this;�}�

Page 25: Js in js

jsexec.js  –  Function. � switch (n.type) {� case FUNCTION:� if (n.functionForm != DECLARED_FORM) {� if (!n.name || n.functionForm == STATEMENT_FORM) {� v = new FunctionObject(n, x.scope);� if (n.functionForm == STATEMENT_FORM)� x.scope.object[n.name] = v;� } else {� x.scope = {object: {}, parent: x.scope};� try {� v = new FunctionObject(n, x.scope);� x.scope.object[n.name] = v;� } finally {� x.scope = x.scope.parent;� }� }� }� break;�

Page 26: Js in js

jsexec.js  –  eval �var global = {� eval: function eval(s) {� if (typeof s != "string") return s;� var x = ExecutionContext.current;� var x2 = new ExecutionContext(EVAL_CODE);� x2.thisObject = x.thisObject;� x2.caller = x.caller;� x2.callee = x.callee;� x2.scope = x.scope;� ExecutionContext.current = x2;� try {� execute(parse(s), x2);� ...�

Page 27: Js in js

{ END. �