かならず Program で始まる
- type
- body: [Statement]
- ExpressionStatement, VariableDeclaration, EmptyStatement, DebuggerStatement, TryStatement が入る?
{ type: 'Program',
body: [ { type: 'ExpressionStatement', expression: [Object] } ] }
bodyはExpressionStatementの配列
代入
a *= 1;
{ type: 'AssignmentExpression',
operator: '*=',
left: { type: 'Identifier', name: 'a' },
right: { type: 'Literal', value: 1, raw: '1' } }
ObjectPattern や ArrayPattern の中に代入式があると AssignmentPattern になる……???
> esprima.parse('[a=0] = [1]').body[0].expression.left
{ type: 'ArrayPattern',
elements:
[ { type: 'AssignmentPattern',
operator: '=',
left: [Object],
right: [Object] } ] }
> esprima.parse('[a=0] = [1]').body[0].expression.left.elements[0]
{ type: 'AssignmentPattern',
operator: '=',
left: { type: 'Identifier', name: 'a' },
right: { type: 'Literal', value: 0, raw: '0' } }
> esprima.parse('[1]').body[0].expression
{ type: 'ArrayExpression',
elements: [ { type: 'Literal', value: 1, raw: '1' } ] }
> e.parse('let [a,] = 0').body[0]
{ type: 'VariableDeclaration',
declarations: [ { type: 'VariableDeclarator', id: [Object], init: [Object] } ],
kind: 'let' }
> esprima.parse('() => 1').body[0].expression
{ type: 'ArrowFunctionExpression',
id: null,
params: [],
defaults: [],
body: { type: 'Literal', value: 1, raw: '1' },
generator: false,
expression: true }
body : [ExpressionStatement] を持つ
> esprima.parse('{1}').body[0]
{ type: 'BlockStatement',
body: [ { type: 'ExpressionStatement', expression: [Object] } ] }
バイナリ演算
> esprima.parse('0b11 & 0b01').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'BinaryExpression',
operator: '&',
left: { type: 'Literal', value: 3, raw: '0b11' },
right: { type: 'Literal', value: 1, raw: '0b01' } } }
ループのbreak
> esprima.parse('while(1){ break;}').body[0]
{ type: 'WhileStatement',
test: { type: 'Literal', value: 1, raw: '1' },
body: {
type: 'BlockStatement', body: [ {
type: 'BreakStatement', label: null
} ]
}
}
関数呼び出し
> esprima.parse('a()').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'CallExpression',
callee: { type: 'Identifier', name: 'a' },
arguments: [] } }
> esprima.parse('try {} catch(e) {}').body[0]
{ type: 'TryStatement',
block: { type: 'BlockStatement', body: [] },
guardedHandlers: [],
handlers: [ { type: 'CatchClause', param: [Object], body: [Object] } ],
handler:
{ type: 'CatchClause',
param: { type: 'Identifier', name: 'e' },
body: { type: 'BlockStatement', body: [] } },
finalizer: null }
- type
- body : [MethodDefinition]
> esprima.parse('class A extends B { constructor(){} yo () {} static go(){} }').body[0].body
{ type: 'ClassBody',
body:
[ { type: 'MethodDefinition',
key: [Object],
computed: false,
value: [Object],
kind: 'constructor',
static: false },
{ type: 'MethodDefinition',
key: [Object],
computed: false,
value: [Object],
kind: 'method',
static: false },
{ type: 'MethodDefinition',
key: [Object],
computed: false,
value: [Object],
kind: 'method',
static: true } ] }
- type
- id
- superClass
- body (ClassBody)
> esprima.parse('class A extends B { constructor(){} yo () {} static go(){} }').body[0]
{ type: 'ClassDeclaration',
id: { type: 'Identifier', name: 'A' },
superClass: { type: 'Identifier', name: 'B' },
body: { type: 'ClassBody', body: [ [Object], [Object], [Object] ] } }
ClassDeclarationの式バージョン
> esprima.parse('a = class A {}').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'AssignmentExpression',
operator: '=',
left: { type: 'Identifier', name: 'a' },
right:
{ type: 'ClassExpression',
id: [Object],
superClass: null,
body: [Object] } } }
三項演算子
true ? 1 : 2
{ type: 'ConditionalExpression',
test: { type: 'Literal', value: true, raw: 'true' },
consequent: { type: 'Literal', value: 1, raw: '1' },
alternate: { type: 'Literal', value: 2, raw: '2' } }
- type
- label (LabeledStatementの名前)
> esprima.parse('while(1){ continue; }').body[0]
{ type: 'WhileStatement',
test: { type: 'Literal', value: 1, raw: '1' },
body: { type: 'BlockStatement', body: [ [Object] ] } }
> esprima.parse('while(1){ continue; }').body[0].body
{ type: 'BlockStatement',
body: [ { type: 'ContinueStatement', label: null } ] }
> esprima.parse('do{}while(1)').body[0]
{ type: 'DoWhileStatement',
body: { type: 'BlockStatement', body: [] },
test: { type: 'Literal', value: 1, raw: '1' } }
> esprima.parse('debugger;').body[0]
{ type: 'DebuggerStatement' }
> esprima.parse(';').body[0]
{ type: 'EmptyStatement' }
> esprima.parse('export * from "foo";', {sourceType: 'module'}).body[0];
{ type: 'ExportAllDeclaration',
source: { type: 'Literal', value: 'foo', raw: '"foo"' } }
{ type: 'ExportDefaultDeclaration',
declaration: { type: 'Literal', value: 123, raw: '123' } }
> esprima.parse('export const A = 123', {sourceType: 'module'}).body[0];
{ type: 'ExportNamedDeclaration',
declaration:
{ type: 'VariableDeclaration',
declarations: [ [Object] ],
kind: 'const' },
specifiers: [],
source: null }
> esprima.parse('export const A = 123', {sourceType: 'module'}).body[0].declaration;
{ type: 'VariableDeclaration',
declarations: [ { type: 'VariableDeclarator', id: [Object], init: [Object] } ],
kind: 'const' }
as で名前指定してexportするやつ
> esprima.parse('export {a, b}', {sourceType: 'module'}).body[0];
{ type: 'ExportNamedDeclaration',
declaration: null,
specifiers:
[ { type: 'ExportSpecifier', exported: [Object], local: [Object] },
{ type: 'ExportSpecifier', exported: [Object], local: [Object] } ],
source: null }
> esprima.parse('export {_A as A}', {sourceType: 'module'}).body[0];
{ type: 'ExportNamedDeclaration',
declaration: null,
specifiers: [ { type: 'ExportSpecifier', exported: [Object], local: [Object] } ],
source: null }
> esprima.parse('export {_A as A}', {sourceType: 'module'}).body[0].specifiers[0];
{ type: 'ExportSpecifier',
exported: { type: 'Identifier', name: 'A' },
local: { type: 'Identifier', name: '_A' } }
- type
- expression:
1
{ type: 'ExpressionStatement',
expression: { type: 'Literal', value: 1, raw: '1' } }
- init, test, update : 式
- body : 文
> esprima.parse('for (1;2;3) { 1; }').body
[ { type: 'ForStatement',
init: { type: 'Literal', value: 1, raw: '1' },
test: { type: 'Literal', value: 2, raw: '2' },
update: { type: 'Literal', value: 3, raw: '3' },
body: { type: 'BlockStatement', body: [Object] } } ]
> esprima.parse('for (let i = 0; i < 10; i++) a[i] = i;').body
[ { type: 'ForStatement',
init:
{ type: 'VariableDeclaration',
declarations: [Object],
kind: 'let' },
test:
{ type: 'BinaryExpression',
operator: '<',
left: [Object],
right: [Object] },
update:
{ type: 'UpdateExpression',
operator: '++',
argument: [Object],
prefix: false },
body: { type: 'ExpressionStatement', expression: [Object] } } ]
省略
省略
関数宣言の文 暗黙的にグローバル変数となる
function f(){}
{ type: 'FunctionDeclaration',
id: { type: 'Identifier', name: 'f' },
params: [],
defaults: [],
body: { type: 'BlockStatement', body: [] },
generator: false,
expression: false }
関数式
var g = function f(){}
{ type: 'VariableDeclaration',
declarations: [ {
type: 'VariableDeclarator',
id: { type: 'Identifier', name: 'g' }
init: { type: 'FunctionExpression',
id: { type: 'Identifier', name: 'f' },
params: [],
defaults: [],
body: { type: 'BlockStatement', body: [] },
generator: false,
expression: false }
} ],
kind: 'var' }
識別子
a
{ type: 'Identifier', name: 'a' }
- test : 式
- consequent, alternate : 文
> esprima.parse('if (1) 1; else 2;').body
[ { type: 'IfStatement',
test: { type: 'Literal', value: 1, raw: '1' },
consequent: { type: 'ExpressionStatement', expression: [Object] },
alternate: { type: 'ExpressionStatement', expression: [Object] } } ]
- type
- specifiers : [ImportDefaultSpecifier]
- source
> esprima.parse('import a from "A"', {sourceType: 'module'}).body[0];
{ type: 'ImportDeclaration',
specifiers: [ { type: 'ImportDefaultSpecifier', local: [Object] } ],
source: { type: 'Literal', value: 'A', raw: '"A"' } }
> esprima.parse('import * as AAA from "A"', {sourceType: 'module'}).body[0];
{ type: 'ImportDeclaration',
specifiers: [ { type: 'ImportNamespaceSpecifier', local: [Object] } ],
source: { type: 'Literal', value: 'A', raw: '"A"' } }
> esprima.parse('import a from "A"', {sourceType: 'module'}).body[0].specifiers;
[ { type: 'ImportDefaultSpecifier',
local: { type: 'Identifier', name: 'a' } } ]
> esprima.parse('import * as AAA from "A"', {sourceType: 'module'}).body[0].specifiers[0];
{ type: 'ImportNamespaceSpecifier',
local: { type: 'Identifier', name: 'AAA' } }
> esprima.parse('import {a as A, b as B} from "A"', {sourceType: 'module'}).body[0].specifiers
[ { type: 'ImportSpecifier',
local: { type: 'Identifier', name: 'A' },
imported: { type: 'Identifier', name: 'a' } },
{ type: 'ImportSpecifier',
local: { type: 'Identifier', name: 'B' },
imported: { type: 'Identifier', name: 'b' } } ]
"hoi"
{ type: 'Literal', value: 'hoi', raw: '"hoi"' }
3
{ type: 'Literal', value: 3, raw: '3' }
breakやcontinueで使う
> esprima.parse('yo: 1;').body
[ { type: 'LabeledStatement',
label: { type: 'Identifier', name: 'yo' },
body: { type: 'ExpressionStatement', expression: [Object] } } ]
> esprima.parse('a: while(1){ b:while(1){ break b; } break a; }').body
[ { type: 'LabeledStatement',
label: { type: 'Identifier', name: 'a' },
body: { type: 'WhileStatement', test: [Object], body: [Object] } } ]
実行例
> a: while(1){ b:while(1){ console.log('b');break b; } console.log('a');break a; }
b
a
undefined
論理式
> esprima.parse('a || b').body
[ { type: 'ExpressionStatement',
expression:
{ type: 'LogicalExpression',
operator: '||',
left: [Object],
right: [Object] } } ]
メンバー演算子
object . property
という形式
a.b
{ type: 'MemberExpression',
computed: false,
object: { type: 'Identifier', name: 'a' },
property: { type: 'Identifier', name: 'b' } }
new.targetのことっぽい 2.4.1だとまだ未実装 http://www.2ality.com/2015/02/es6-classes-final.html
クラスのメソッド定義
> esprima.parse('class A{ x () {1;} }').body[0];
{ type: 'ClassDeclaration',
id: { type: 'Identifier', name: 'A' },
superClass: null,
body: { type: 'ClassBody', body: [ [Object] ] } }
> esprima.parse('class A{ x (a) {1;} }').body[0].body.body
[ { type: 'MethodDefinition',
key: { type: 'Identifier', name: 'x' },
computed: false,
value:
{ type: 'FunctionExpression',
id: null,
params: [Object],
defaults: [],
body: [Object],
generator: false,
expression: false },
kind: 'method',
static: false } ]
new A
と new A()
で違いは無いのか、マジか
> esprima.parse('new A').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'NewExpression',
callee: { type: 'Identifier', name: 'A' },
arguments: [] } }
> esprima.parse('new A()').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'NewExpression',
callee: { type: 'Identifier', name: 'A' },
arguments: [] } }
> esprima.parse('new A(1)').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'NewExpression',
callee: { type: 'Identifier', name: 'A' },
arguments: [ [Object] ] } }
> esprima.parse('new A(1)').body[0].expression.arguments
[ { type: 'Literal', value: 1, raw: '1' } ]
Objectの式
- type
- properties : [Property]
> esprima.parse('{a:1}').body[0]
{ type: 'BlockStatement',
body: [ { type: 'LabeledStatement', label: [Object], body: [Object] } ] }
> esprima.parse('a = {a:1}').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'AssignmentExpression',
operator: '=',
left: { type: 'Identifier', name: 'a' },
right: { type: 'ObjectExpression', properties: [Object] } } }
> esprima.parse('a = {a:1}').body[0].expression.right
{ type: 'ObjectExpression',
properties:
[ { type: 'Property',
key: [Object],
computed: false,
value: [Object],
kind: 'init',
method: false,
shorthand: false } ] }
1個目はオブジェクトじゃないのか〜
> esprima.parse('var { m: month, y: year } = today();').body[0].declarations[0].id;
{ type: 'ObjectPattern',
properties:
[ { type: 'Property',
key: [Object],
computed: false,
value: [Object],
kind: 'init',
method: false,
shorthand: false },
{ type: 'Property',
key: [Object],
computed: false,
value: [Object],
kind: 'init',
method: false,
shorthand: false } ] }
Object定義する時の、一つ一つのプロパティ
> esprima.parse('a = {a:1}').body[0].expression.right.properties[0]
{ type: 'Property',
key: { type: 'Identifier', name: 'a' },
computed: false,
value: { type: 'Literal', value: 1, raw: '1' },
kind: 'init',
method: false,
shorthand: false }
> esprima.parse('function f (a, ...b){ }').body[0]
{ type: 'FunctionDeclaration',
id: { type: 'Identifier', name: 'f' },
params:
[ { type: 'Identifier', name: 'a' },
{ type: 'RestElement', argument: [Object] } ],
defaults: [],
body: { type: 'BlockStatement', body: [] },
generator: false,
expression: false }
> esprima.parse('function f (a, ...b){ }').body[0].params[1]
{ type: 'RestElement',
argument: { type: 'Identifier', name: 'b' } }
> esprima.parse('function f(){return 1;}').body[0].body.body[0]
{ type: 'ReturnStatement',
argument: { type: 'Literal', value: 1, raw: '1' } }
,
演算子?で式を並べた時、式の集合を SequenceExpression
と呼ぶ
> esprima.parse('a,b').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'SequenceExpression',
expressions: [ [Object], [Object] ] } }
この時、最後の式の値が返る 実行例
> a = (1,2,3);
3
> esprima.parse('a(...b)').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'CallExpression',
callee: { type: 'Identifier', name: 'a' },
arguments: [ [Object] ] } }
> esprima.parse('a(...b)').body[0].expression.arguments
[ { type: 'SpreadElement',
argument: { type: 'Identifier', name: 'b' } } ]
クラス定義内の super
.
> esprima.parse('class A { yo(){ super(); } }').body[0].body.body[0].value.body.body[0].expression
{ type: 'CallExpression',
callee: { type: 'Super' },
arguments: [] } }
> esprima.parse('switch(a){ case 1: 1; default: 0; }').body[0].cases[0]
{ type: 'SwitchCase',
test: { type: 'Literal', value: 1, raw: '1' },
consequent: [ { type: 'ExpressionStatement', expression: [Object] } ] }
> esprima.parse('switch(a){}').body[0]
{ type: 'SwitchStatement',
discriminant: { type: 'Identifier', name: 'a' },
cases: [] }
> esprima.parse('switch(a){ case 1: 1; default: 0; }').body[0]
{ type: 'SwitchStatement',
discriminant: { type: 'Identifier', name: 'a' },
cases:
[ { type: 'SwitchCase', test: [Object], consequent: [Object] },
{ type: 'SwitchCase', test: null, consequent: [Object] } ] }
> esprima.parse('raw`42`').body[0].expression
{ type: 'TaggedTemplateExpression',
tag: { type: 'Identifier', name: 'raw' },
quasi:
{ type: 'TemplateLiteral',
quasis: [
{ type: 'TemplateElement', value: [Object], tail: true }
],
expressions: [] } }
> esprima.parse('`hello ${a}, wassa`').body[0].expression
{ type: 'TemplateLiteral',
quasis:
[ {
type: 'TemplateElement',
value: { raw: 'hello ', cooked: 'hello ' },
tail: false
}, {
type: 'TemplateElement',
value: { raw: ', wassa', cooked: ', wassa' },
tail: true
} ],
expressions: [ { type: 'Identifier', name: 'a' } ] }
this
{ type: 'ThisExpression' },
> esprima.parse('throw "yo"').body[0]
{ type: 'ThrowStatement',
argument: { type: 'Literal', value: 'yo', raw: '"yo"' } }
> esprima.parse('try {1} catch(e) {2} finally {3}').body[0]
{ type: 'TryStatement',
block: { type: 'BlockStatement', body: [ [Object] ] },
guardedHandlers: [],
handlers: [ { type: 'CatchClause', param: [Object], body: [Object] } ],
handler:
{ type: 'CatchClause',
param: { type: 'Identifier', name: 'e' },
body: { type: 'BlockStatement', body: [Object] } },
finalizer: { type: 'BlockStatement', body: [ [Object] ] } }
catch, finally は try の子供になるのか〜
単項演算子
> esprima.parse('!a').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'UnaryExpression',
operator: '!',
argument: { type: 'Identifier', name: 'a' },
prefix: true } }
> esprima.parse('++a').body[0]
{ type: 'ExpressionStatement',
expression:
{ type: 'UpdateExpression',
operator: '++',
argument: { type: 'Identifier', name: 'a' },
prefix: true } }
> esprima.parse('var a = 1, b = 2;').body[0].declarations[0]
{ type: 'VariableDeclarator',
id: { type: 'Identifier', name: 'a' },
init: { type: 'Literal', value: 1, raw: '1' } }
- type
- declarations : [VariableDeclarator]
- kind : 'var' | 'let' | 'const'
> esprima.parse('var a = 1, b = 2;').body[0]
{ type: 'VariableDeclaration',
declarations:
[ { type: 'VariableDeclarator', id: [Object], init: [Object] },
{ type: 'VariableDeclarator', id: [Object], init: [Object] } ],
kind: 'var' }
> esprima.parse('while(3)1;').body[0]
{ type: 'WhileStatement',
test: { type: 'Literal', value: 3, raw: '3' },
body:
{ type: 'ExpressionStatement',
expression: { type: 'Literal', value: 1, raw: '1' } } }
> esprima.parse('with (console) log("yo"); ').body[0]
{ type: 'WithStatement',
object: { type: 'Identifier', name: 'console' },
body:
{ type: 'ExpressionStatement',
expression: { type: 'CallExpression', callee: [Object], arguments: [Object] } } }
> esprima.parse('function* g(){ yield 1; }').body[0].body.body[0].expression
{ type: 'YieldExpression',
argument: { type: 'Literal', value: 1, raw: '1' },
delegate: false }
> esprima.parse('function* g(){ yield* g2; }').body[0].body.body[0].expression
{ type: 'YieldExpression',
argument: { type: 'Identifier', name: 'g2' },
delegate: true }
delegate知らなかった、便利
ちなみにgenerator定義はFunctionExpression、FunctionDeclarationである
> esprima.parse('function* g(){ yield 1; }').body[0]
{ type: 'FunctionDeclaration',
id: { type: 'Identifier', name: 'g' },
params: [],
defaults: [],
body: { type: 'BlockStatement', body: [ [Object] ] },
generator: true,
expression: false }
> esprima.parse('f = function*(){ yield 1; }').body[0].expression.right
{ type: 'FunctionExpression',
id: null,
params: [],
defaults: [],
body: { type: 'BlockStatement', body: [ [Object] ] },
generator: true,
expression: false }