Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JavaScript ASTことはじめ /JavaScript AST

JavaScript ASTことはじめ /JavaScript AST

メドレー開発本部の社内勉強会「TechLunch」で、JavaScript ASTについて紹介させていただきました。

発表者:平木聡

D879794ea42768ea417f970914430d56?s=128

Medley Inc.

June 22, 2018
Tweet

Transcript

  1. JavaScript AST͜ͱ͸͡Ί

  2. Agenda • JavaScript ASTͱ͸Կ͔? • JavaScript ASTͷجૅ஌ࣝ • JavaScript AST࢖ͬͯԿ͔ͯ͠ΈΔ

  3. JavaScript ASTͱ͸Կ͔?

  4. ͦ΋ͦ΋ASTͱ͸ ͦ΋ͦ΋AST͸ந৅ߏจ໦ͷӳޠ໊Ͱ͋Δabstract syntax treeͷུ শʹͳΓ·͢ɻίϯύΠϥͱ͔ΠϯλϓϦλͳͲͷݴޠॲཧܥͷ தؒॲཧʹྑ͘࢖ΘΕΔख๏Ͱ͢ɻ(ͳ͓؊ػೳͷ਺஋ʹ΋ಉ͡ ASTͱ͍͏ུশ͕͋Δ໛༷) h"ps:/ /en.wikipedia.org/wiki/Abstractsyntaxtree

  5. ͦ΋ͦ΋ASTͱ͸ ΩϞͱͯ͠͸ॻ͔Ε͍ͯΔϓϩάϥϜΛߏจղੳͯ͠ߏ଄Խʹෆ ཁͳ෦෼͸࡟আͯ͠ɺ໦ߏ଄ͱͯ͠දݱ͍ͯ͠Δσʔλʹ͢Δͱ ͍͏ͱ͜ΖͰ͢ɻ

  6. ͦ΋ͦ΋ASTͱ͸ ͜ͷASTࣗମ͸ಛʹJSݻ༗ͷ΋ͷͱ͍͏Θ͚Ͱ͸ͳ͘ɺ৭ʑͳݴ ޠͰ࢖ΘΕ͍ͯ·͢ɻྫ͑͹JavaͰ࢖ΘΕΔIDEͷEclipseͰ΋Java ͷߏจղੳʹ࢖ͬͯͨΓ͢ΔͬΆ͍Ͱ͢ɻ h"p:/ /www.eclipse.org/ar1cles/Ar1cle- JavaCodeManipula1on_AST/index.html ͜ͷASTʹ͍ۙख๏Ͱ(ݫີʹ͸ҧ͏)ߏங͞Ε͍ͯΔͷ͕਎ۙͰ͍ ͏ͱDOMͩͬͨΓ΋͠·͢ɻ

  7. JavaScript AST͸Ͳ͜Ͱ࢖ΘΕ͍ͯΔͷ͔? • React • Babel • UglifyJS • ESLint

    • PowerAssert ͳͲͳͲ
  8. JavaScript AST͸Ͳ͜Ͱ࢖ΘΕ͍ͯΔͷ͔? ҰྫͰ͕͢ݱࡏͷϑϩϯτΤϯυ։ൃʹ͸͔ܽͤͳ͍ϓϩμΫτ ͸େମ࢖ΘΕͯΔΜ͡Όͳ͍Ͱ͠ΐ͏͔ɻ มΘΓμωͱͯ͠ಠࣗʹJSͷϚΫϩΛ࡞ΕΔsweet-js/sweet-core ͳΜ͔Ͱ΋࢖ΘΕ͍ͯ·͢ɻ

  9. JavaScriptք۾ͰͷASTͷաڈ JSք۾ͰͷASTͷऔΓѻ͍ͳͲͷ࿩͸ผʹྺ࢙Λશ෦஌ͬͯΔΘ ͚͡Όͳ͍ΜͰ͕͢ɺ͔͍ͭ·ΉͱҎԼͷΑ͏ͳྲྀΕʹͳΔ͔ ΋ɻ

  10. JavaScriptք۾ͰͷASTͷաڈ • FirefoxͰ࢖ΘΕ͍ͯͨSpiderMonkyͰ2010೥ʹParser API͕౥ ࡌ͞Εͨ • Parser APIͷJSϙʔτͷzaach/reflect.js͕2011೥4݄͘Β͍ʹϦ Ϧʔε

  11. JavaScriptք۾ͰͷASTͷաڈ • JavaScript ASTͰຊ֨తʹ࢖ΘΕͩͨ͠jquery/esprima͕2011೥ 11݄͘Β͍ʹϦϦʔε • ݩʑ͸࡞ऀͷAriya͞ΜͷݸਓϓϩδΣΫτ͚ͩͬͨͲɺ3೥ ͘Β͍લʹjQueryࡒஂʹҠ؅ • esprima஗͍͗ͬͯͬͯ͢acornjs/acorn͕ొ৔

  12. JavaScriptք۾ͰͷASTͷաڈ • ࠷ॳ͸acorn࢖ͬͯͨBabel͕೿ੜͤͯࣗ͞લͰbabel/babylonΛ 2012೥9݄͘Β͍͔Β࡞ͬͨΓ • ࢓༷֎ͷ͜ͱ΋Ͱ͖ΔΑ͏ʹ֦ு͞ΕͯΔ • JavaScript ASTΛ࡞ΔϥΠϒϥϦ͕৭ʑग़͖ͯͯޓ׵ੑ͕͋ͬͨ Γແ͔ͬͨΓͱ͍͏ঢ়گͩͬͨͷΛ2015೥ʹjQueryࡒஂ΍

    Mozilla΋ೖͬͯestree/estreeͱ͍͏JavaScript ASTͷඪ४ن͕֨ Ͱ͖Δ
  13. JavaScriptք۾ͰͷASTͷաڈ ͜Μͳײ͡Ͱݱࡏ৭ʑͳϓϩμΫτͰ࢖ΘΕ͍ͯΔJavaScript AST ϥΠϒϥϦ͕৭ʑͰ͖͖ͯ·ͨ͠ɻ ༗໊ॴΛϐοΫΞοϓ͚ͨͩ͠ͳΜͰɺѥྲྀͷύʔα΋৭ʑ͋Γ ྫ͑͹ESLintͳΜ͔͸ݱࡏesprimaͱޓ׵ੑ͕͋Δeslint/espreeͱ ͍͏ύʔαΛࣗલͰ࡞ͬͯ࢖ͬͯͨΓ͠·͢ɻ

  14. JavaScript ASTͷجૅ஌ࣝ

  15. JavaScript AST͸࣮ࡍͲΜͳίʔυʹͳΔͷ͔ JavaScript AST͸ιʔείʔυΛ໦ߏ଄ʹม׵ͯ͠ɺ࠷ऴతʹ JSONܗࣜʹͯ͠දݱ͍͖ͯ͠·͢ɻ ԼهͷΑ͏ͳ؆୯ͳJSίʔυΛྫʹऔΓ·͢ɻ var hello = 'Hello

    World'; function sayHello() { console.log(hello) }
  16. JavaScript AST͸࣮ࡍͲΜͳίʔυʹͳΔͷ͔ ࠓճ͸acornΛ࢖ͬͯASTʹม׵͢ΔͱԼهͷΑ͏ͳJSONܗ͕ࣜ Ͱ͖·͢ɻ { "type": "Program", "start": 0, "end":

    69, "body": [ { "type": "VariableDeclaration", "start": 0, "end": 26, "declarations": [ { "type": "VariableDeclarator", "start": 4, "end": 25, "id": { "type": "Identifier", "start": 4, "end": 9, "name": "hello" }, "init": { "type": "Literal", "start": 12, "end": 25, "value": "Hello World", "raw": "'Hello World'" } } ], "kind": "var" }, { "type": "FunctionDeclaration", "start": 27, "end": 69, "id": { "type": "Identifier", "start": 36, "end": 44, "name": "sayHello" }, "generator": false, "expression": false, "params": [], "body": { "type": "BlockStatement", "start": 47, "end": 69, "body": [ { "type": "ExpressionStatement", "start": 49, "end": 67, "expression": { "type": "CallExpression", "start": 49, "end": 67, "callee": { "type": "MemberExpression", "start": 49, "end": 60, "object": { "type": "Identifier", "start": 49, "end": 56, "name": "console" }, "property": { "type": "Identifier", "start": 57, "end": 60, "name": "log" }, "computed": false }, "arguments": [ { "type": "Identifier", "start": 61, "end": 66, "name": "hello" } ] } } ] } } ], "sourceType": "module" }
  17. JavaScript AST͸࣮ࡍͲΜͳίʔυʹͳΔͷ͔ શવಡΊͳ͍ͱࢥ͏ͷͰɺ෼͔Γ΍͍͢Α͏ͳπϦʔܗࣜͷεΫ γϣ͕ͪ͜Βɻ

  18. JavaScript ASTͷม׵ϧʔϧ ͲͷΑ͏ʹม׵͞ΕΔ͔?ͷϧʔϧ͸࢖͏ύʔαͷυΩϡϝϯτ ΍ɺParser API - Mozilla | MDNɺestree/estree: The

    ESTree Specͳ Μ͔Λࢀߟʹ͠·͢ɻ΋͏ͪΐ͍ಥͬ͜Μͩ࿩Ͱ͍͏ͱ ECMAScriptͷ࢓༷ॻ΋߹ΘͤͯಡΉͱΑ͍͔΋͠Εͳ͍Ͱ͢ɻ • h#ps:/ /developer.mozilla.org/en-US/docs/Mozilla/Projects/ SpiderMonkey/Parser_API • h#ps:/ /github.com/estree/estree • h#ps:/ /www.ecma-internaEonal.org/ecma-262/8.0/index.html
  19. ύʔαͰม׵͞Εͨ΋ͷͨͪͷઆ໌ ͞Βͬͱࠓճͷ΋ͷΛୈೋ֊૚·Ͱઆ໌͢Δͱɺ͜Μͳײ͡Ͱ͢ • Program • ϧʔτʹͳΔΦϒδΣΫτ • Կ͸ͳ͘ͱ΋ઈରʹม׵͢Δͱ࡞ΒΕΔ • ϓϩάϥϜ͸શ෦͜ͷ߲໨ͷbodyʹ໦ߏ଄Ͱ֨ೲ͞ΕΔ

  20. ύʔαͰม׵͞Εͨ΋ͷͨͪͷઆ໌ • VariableDeclaration • var hello = 'Hello World';ͷ෦෼ •

    ม਺એݴ͸͜ͷ߲໨ʹͳΔ • kind͕ม਺એݴͷΩʔϫʔυͷछྨʹͳΔɻ • declarations͕એݴ͞Ε͍ͯΔ಺༰Λ֨ೲ͍ͯ͠Δ෦෼ • ม਺໊΍ॳظ஋ʹԿ͕ೖ͍ͬͯΔͳͲ͕֨ೲ
  21. ύʔαͰม׵͞Εͨ΋ͷͨͪͷઆ໌ • FunctionDeclaration • function sayHello() { console.log(hello) }ͷ෦ ෼

    • ؔ਺એݴ͸͜ͷ߲໨ʹͳΔ • id͕ؔ਺໊ͳͲ֨ೲ͍ͯ͠Δ෦෼ • params͸ࠓճۭ͕ͩɺԾҾ਺Λ֨ೲ͍ͯ͠Δ෦෼
  22. ݸੑ๛͔ͳύʔαͨͪ Ͳͷύʔαʔ΋جຊͱͯ͠͸͜ΕΒͷ߲໨͸ESTreeͰఆٛ͞Εͯ ͍Δ΋ͷΛ࢖͍ͬͯΔͷͰ͕͢ɺࡉ͔͍ҧ͍͕͋ͬͨΓɺ bablylonͷΑ͏ʹಠࣗͰ৭ʑͳ߲໨ΛೖΕ͍ͯͨΓ͢Δͱ͍͏ײ ͡ʹͳ͍͖ͬͯ·͢ɻ h"ps:/ /github.com/babel/babylon/blob/master/ast/spec.md

  23. JavaScript ASTͷ࢖͍Ͳ͜Ζ ͜͜·Ͱجຊతͳ࿩Λ͖ͯ͠·͕ͨ͠ɺͰ͸JavaScript ASTΛࣗ෼ ୡͰ࢖͏৔߹…Ͳ͏͍͏ͱ͖Ͱ͠ΐ͏͔?ͺͬͱࢥ͍ͭ͘ͱ͜Ζ͸ ͜Μͳײ͔͡ͳ͋ͱɻ - babelͷϓϥάΠϯ࡞੒ - eslintͷϓϥάΠϯ࡞੒

    - ࣗલͰιʔείʔυΛมߋ͢Δ(APIมߋͳΜ͔ͷ)πʔϧ࡞Δͱ͖
  24. JavaScript ASTͷ࢖͍Ͳ͜Ζ ݸਓతʹ͸ڊਓͷݞʹ৐͔ͬΓ͍ͨͷͰɺ༻్͕ϓϥάΠϯ࡞੒ ʹͳͬͨΓͯ͠·͕͢ɺJavaScript ASTͷ࢓૊ΈΛ࢖͑͹ࣗલͷτ ϥϯεύΠϥΛ࡞ͬͨΓ΋Ͱ͖Δ͸ͣͰ͢ɻ ࣮ࡍʹJavaScript ASTΛ࢖ͬͯJSΛੜ੒͢Δʹ͸ɺ঺հͨ͠ύʔα ͷଞʹASTΛtraverseͯ͠ॲཧ͢ΔϥΠϒϥϦ(estraverseͳͲ)΍ AST͔ΒJSΛੜ੒͢ΔϥΠϒϥϦ(escodegenͳͲ)͕ඞཁʹͳΓ·

    ͢ɻ
  25. JavaScript AST࢖ͬͯԿ͔ͯ͠ΈΔ

  26. AST Explore ࠷ޙʹͪΐͬͱ࣮ͨ͠ྫΛ͝঺հͯ͠ऴΘΓ·͕͢ɺͦͷલʹ JavaScript ASTΛѻ͏ͷʹແͯ͘͸ͳΒͳ͍πʔϧ͕͋ΔͷͰ঺ հɻ

  27. AST Explore AST Explore: h.p:/ /astexplorer.net/

  28. AST Explore ͜ͷαΠτ͸JavaScript AST͚ͩͰ͸ͳ͘ଞͷ৭ʑͳݴޠͷύʔα ΍ίʔυδΣωϨʔλ͕ΦϯϥΠϯͰ؆୯ʹͰ͖ΔΑ͏ʹͳͬͯ ͍ΔαΠτͰ͢ɻ JSBin΍JSFiddleͷAST൛ͱ͍͏ײ͡ɻSave͢ΔͱύʔϚϦϯΫ࡞ ͬͯ͘ΕͨΓASTͷπϦʔ͕ݟ΍͔ͬͨ͢Γ͢ΔπʔϧͰ͢ɻ ࢖͍͍ͨύʔα΍δΣωϨʔλ΋৭ʑͳछྨ͔Βબ΂·͢ɻࠓճ ͷྫ΋͜ͷπʔϧ࢖ͬͯ঺հ͠·͢ɻ

  29. var Ͱॻ͔ΕͨJSΛconstʹॻ͖͔͑Δ ύʔα: babylon v7 / τϥϯεύΠϥ: babel7 DEMO: varΩϥΠ

  30. Vue.js 1.xܥ͔Β2.xܥͷϚΠάϨʔγϣϯʹ଱͑Δ ύʔα: acorn / τϥϯεύΠϥ: jscodeshi/ h"ps:/ /vuejs.org/v2/guide/migra4on.html#a"ached-removed DEMO:

    a(atchͷϚΠάϨʔγϣϯ
  31. ऴΘΓ

  32. ࢀߟ • h#ps:/ /speakerdeck.com/michaelficarra/spidermonkey-parser- api-a-standard-for-structured-js-representa;ons • h#p:/ /azu.github.io/slide/JSojisan/#1 • h#ps:/

    /efcl.info/2016/03/06/ast-first-step/ • h#ps:/ /efcl.info/2015/02/26/recent-js-ast/ • h#ps:/ /medium.com/@jotadeveloper/abstract-syntax-trees-on- javascript-534e33361fc7
  33. ࢀߟ • h#ps:/ /www.sitepoint.com/understanding-asts-building-babel- plugin/ • h#ps:/ /github.com/jamiebuilds/babel-handbook • h#ps:/

    /github.com/facebook/jscodeshi<