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

事前知識なしで理解する、静的検査のいろは / Introduction about static analysis without previous knowledge

Kuniwak
September 07, 2018

事前知識なしで理解する、静的検査のいろは / Introduction about static analysis without previous knowledge

私は Vim script の静的検査ツール「Vint」の開発者です。この発表では、Vint の開発を通じて学んだ静的検査ツールの仕組みと経験則を、事前知識のない方でも理解できるように詳解します。

この発表で触れるさまざまな基礎技術は、静的検査はもちろん、メタプログラミングやトランスパイラ、独自プログラミング言語の開発にも役立つ重要なものです。これらを技術の引き出しとして覚えておけば、今後の開発体験を豊かにしてくれることでしょう。

https://builderscon.io/tokyo/2018/session/0a3ee8c0-44ce-4cb9-9199-05b350887d79

Kuniwak

September 07, 2018
Tweet

More Decks by Kuniwak

Other Decks in Programming

Transcript

  1. ੩తݕࠪͷ͍Ζ͸
    ࣄલ஌ࣝͳ͠Ͱཧղ͢Δ
    Kuniwak - DeNA Co.,Ltd.

    2018.09.07 builderscon tokyo 2018

    View Slide

  2. "CPVUNF

    View Slide

  3. ,VOJXBL
    w ॴଐˠ
    w HJUIVCDPN,VOJXBL
    w RJJUBDPN,VOJXBL
    w ίϯϐϡʔλαΠΤϯεΛ

    ֶΜͰ͖͍ͯ·ͤΜ
    w ࣄલ஌ࣝͳ͠Ͱ੩తղੳ

    πʔϧΛ։ൃ͖ͯͨ͠

    View Slide

  4. ͜Ε·Ͱʹ͖ͭͬͯͨ͘

    ੩తݕࠪܥͷπʔϧͷ঺հ

    View Slide

  5. 7JNTDSJQUͷ੩తݕࠪπʔϧ
    https://github.com/Kuniwak/Vint

    View Slide

  6. $44ͷมߋ఺ΛՄࢹԽ͢Δπʔϧ
    https://github.com/mixi-inc/css-semdiff
    $ css-astdiff a.css b.css --verbose
    extra:
    .extra-1 {
    border: none;
    }
    missing:
    .missing-1 {
    border: none;
    }
    ---------------------------------
    1 extra rules and 1 missing rules

    View Slide

  7. मਖ਼ͷӨڹൣғΛڭ͑ͯ͘ΕΔπʔϧ
    https://twitter.com/orga_chem/status/674847225684475905
    ˞લ৬

    View Slide

  8. ͜ͷൃදΛฉ͘ͱ

    Θ͔Δ͜ͱ
    ͸͡Ίʹ

    View Slide

  9. ੩తղੳΛߏ੒͢Δ͍͔ͭ͘ͷߟ͑ํ
    ͕Θ͔ΔΑ͏ʹͳΔ
    ߟ͑ํ͑͞ཧղͰ͖Ε͹ɺ੩తղੳΛ

    ࣮૷͢Δͷ͸೉͘͠ͳ͍͜ͱ͕Θ͔Δ

    View Slide

  10. ΋͏ͪΐͬͱ۩ମతʹ
    ͜ͷൃදͷ໨ඪ

    View Slide

  11. if isEmpty('') {
    //CATCH_ME_IF_YOU_CAN
    }
    CATCH_ME_IF_YOU_CANͱॻ͔Εͨੜҙؾͳ

    ίϝϯτʢจࣈྻ಺ͷ͸/(ʣΛݕ஌͢Δ

    ੩తݕࠪΛ៉ྷʹ࣮૷Ͱ͖ΔΑ͏ʹͳΔ

    View Slide

  12. ؆୯͗͢ͳ͍ʁͱ

    ࢥͬͨ͋ͳͨ΁

    View Slide

  13. ಉ͡ϓϩάϥϜͰ࣍ͷίʔυ΋

    ղੳͰ͖·͔͢ʁ
    fake('', ' //CATCH_ME_IF_YOU_CAN ↩︎
    ')
    ͜Ε͸จࣈྻͳͷͰݕ஌ͯ͠͸͍͚ͳ͍
    ͜ͷվߦ͸ҙਤతͰ͢

    View Slide

  14. ͜ͷൃදͰ͸ɺҙ஍ѱͳέʔεʹ΋

    ରԠͰ͖Δ੩తղੳΛઆ໌͠·͢

    View Slide

  15. ੩తղੳͱ͸
    Ͱ͸ͬͦ͘͞

    View Slide

  16. ੩తݕࠪͱ͸ɺݕ͍ࠪͨ͠ϓϩάϥϜΛ

    ࣮ߦ͠ͳ͍··֤छͷҟৗΛݕࠪ͢Δख๏ͷ͜ͱ
    ݴޠ͝ͱʹ༷ʑͳ੩తݕࠪͷͨΊͷπʔϧ͕͋Δɿ
    w 1ZUIPOͳΒ1ZqBLFT΍NZQZͳͲ
    w 3VCZͳΒ3VCPDPQͳͲ
    w +BWB4DSJQUͳΒ&4-JOUͳͲ
    w +BWBͳΒ4QPU#VHTͳͲ

    View Slide

  17. ͜͜Ͱٙ໰
    ͳͥ੩తʹݕ͍ࠪͨ͠ͷ͔

    View Slide

  18. ݕ͍ࠪͨ͠ϓϩάϥϜΛ࣮ߦͯ͠ʢಈతʣ

    ݕࠪ͢Δ৔߹ɺݕࠪதʹ௨ա͍ͯ͠ͳ͍

    ίʔυ͸ݕࠪͰ͖ͳ͍
    isFoo = true
    if isFoo {
    }
    else {
    }
    ͪ͜Β͸ಈతʹݕࠪͰ͖Δ
    ͪ͜Β͸ಈతʹݕࠪͰ͖ͳ͍

    View Slide

  19. ੩తݕࠪ͸ಈతݕ͕ࠪۤखͳ

    ໢ཏతͳݕ͕ࠪಘҙ
    ͔͠͠੩తݕࠪ͸ಈతݕࠪ΄Ͳ

    ݕࠪ݁Ռ͕ਖ਼֬ʹͳΒͳ͍

    View Slide

  20. ੩తݕࠪΛ஌Δ͜ͱͰ

    ։ൃΛޮ཰ԽͰ͖Δཧ༝
    ͳΜͷ໾ʹཱͭͷ͔ٙ໰ͳ͋ͳͨ΁

    View Slide



  21. ίʔυϨϏϡʔͷҰ෦Λ

    ࣗಈԽͰ͖ΔΑ͏ʹͳΔ
    ศརͳࣾ಺πʔϧΛͭͬͯ͘

    ͋Γ͕͕ͨΒΕΔ
    طଘͷ੩తղੳπʔϧΛվྑɾ

    σόοάͰ͖ΔΑ͏ʹͳΔ

    View Slide

  22. ίʔυϨϏϡʔࣗಈԽͷྫ
    http://alpha.mixi.co.jp/entry/2015/12/20/000000
    $ css-astdiff a.css b.css --verbose
    extra:
    .extra-1 {
    border: none;
    }
    missing:
    .missing-1 {
    border: none;
    }
    ---------------------------------
    1 extra rules and 1 missing rules
    ߦͷ$44Λ

    ো֐θϩͰ-FTT΁

    Ҡߦͨ͠ࡍͷπʔϧ

    View Slide

  23. ศརͳࣾ಺πʔϧʢʁʣͷྫ
    https://twitter.com/orga_chem/status/674847225684475905
    ऍ໌
    WJTVBMJ[BUJPO͸ఘΊ·͕ͨ͠ɺ

    ґଘΛҰཡͰݟΒΕΔαʔϏε

    ͭͬͨ͘Βศརʹ࢖ΘΕ·ͨ͠

    View Slide

  24. શମతͳઆ໌ͷྲྀΕ
    ͜Ε͔Βͷ

    View Slide

  25. ֓೦Λཧղ͢Δ
    ந৅ߏจ໦Λཧղ͢Δ
    ந৅ߏจ໦ͷ࡞ΓํΛཧղ͢Δ
    ந৅ߏจ໦ͷѻ͍ํΛཧղ͢Δ
    ࡞ΓํΛཧղ͢Δ
    ؆୯ͳ੩తղੳΛ࣮૷͢Δ
    ੩తղੳͷσβΠϯύλʔϯΛ஌Δ
    ࣮ࡍͷ੩తղੳΛಡΉ

    View Slide

  26. ந৅ߏจ໦Λཧղ͢Δ
    ·ͣ͸

    View Slide

  27. ੩తݕࠪͰऔΓѻ͏୅දతͳ

    σʔλͷछྨ͸͍͔ͭ͋͘Δ

    View Slide

  28. ந৅ߏจ໦
    ίʔυΛ໦ߏ଄Ͱදݱͨ͠΋ͷ
    ଟ͘ͷ੩తղੳͷجຊ
    τʔΫϯྻ
    ίʔυͷখ͞ͳߏ੒୯ҐΛ

    ग़ݱॱʹฒ΂ͨ΋ͷ
    ελΠϧʹؔ͢Δ੩తղੳͰ

    Α͘࢖ΘΕΔ
    ੍ޚϑϩʔάϥϑ
    ίʔυͷ৚݅෼ذͳͲͷ

    ੍ޚߏ଄Λ࿈݁ͨ͠ϒϩοΫͰ

    දݱͨ͠΋ͷ
    ίʔϧάϥϑ
    ؔ਺ͷݺͼग़ؔ͠܎ΛάϥϑͰ

    දݱͨ͠΋ͷ
    ະ࢖༻ؔ਺ͷղੳͳͲʹΑ͘

    ࢖ΘΕΔ

    View Slide

  29. τʔΫϯྻ
    ίʔυͷখ͞ͳߏ੒୯ҐΛ

    ग़ݱॱʹฒ΂ͨ΋ͷ
    ελΠϧʹؔ͢Δ੩తղੳͰ

    Α͘࢖ΘΕΔ
    ੍ޚϑϩʔάϥϑ
    ίʔυͷ৚݅෼ذͳͲͷ

    ੍ޚߏ଄Λ࿈݁ͨ͠ϒϩοΫͰ

    දݱͨ͠΋ͷ
    ίʔϧάϥϑ
    ؔ਺ͷݺͼग़ؔ͠܎ΛάϥϑͰ

    දݱͨ͠΋ͷ
    ະ࢖༻ؔ਺ͷղੳͳͲʹΑ͘

    ࢖ΘΕΔ
    ந৅ߏจ໦
    ίʔυΛ໦ߏ଄Ͱදݱͨ͠΋ͷ
    ଟ͘ͷ੩తղੳͷجຊ ࠓճղઆ͢Δ΋ͷ

    View Slide

  30. if isEmpty('') {
    // COMMENT
    }
    1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    ந৅ߏจ໦
    ίʔυ

    View Slide

  31. if isEmpty('') {
    // COMMENT
    }
    ந৅ߏจ໦
    ίʔυ
    ˞4UBUFNFOU͸ʮจʯͷҙຯͳͷͰɺ*G4UBUFNFOU͸ʮJGจʯͷҙຯͰ͢
    1SPHSBN
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    *G4UBUFNFOU

    View Slide

  32. if isEmpty('') {
    // COMMENT
    }
    1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    *EFOUJpFS
    $PNNFOU
    'VOD$BMM
    ந৅ߏจ໦
    ίʔυ

    View Slide

  33. if isEmpty('') {
    // COMMENT
    }
    1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    *EFOUJpFS
    ந৅ߏจ໦
    ίʔυ

    View Slide

  34. if isEmpty('') {
    // COMMENT
    }
    1SPHSBN
    *G4UBUFNFOU
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    4USJOH-JUFSBM
    ந৅ߏจ໦
    ίʔυ

    View Slide

  35. if isEmpty('') {
    // COMMENT
    }
    1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    ந৅ߏจ໦
    ίʔυ

    View Slide

  36. if isEmpty('') {
    // COMMENT
    }
    ந৅ߏจ໦
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    1SPHSBN
    ίʔυ

    View Slide

  37. if isEmpty('') {
    // COMMENT
    }
    1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    ந৅ߏจ໦
    ίʔυ
    ந৅ߏจ໦͸ɺίʔυͷߏ଄Λ

    ໦ߏ଄ͷσʔλͱͯ͠දݱͨ͠΋ͷ

    View Slide

  38. ໦ߏ଄Ͱ͸1SPHSBN΍

    $PNNFOUͷΑ͏ͳ

    ໦Λߏ੒͢Δઅ఺ͷ͜ͱΛ

    ʮϊʔυʯͱݺͿ
    1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU

    View Slide

  39. ࣮ࡍͷϝδϟʔͳݴޠͷ

    ந৅ߏจ໦ΛݟͯΈΑ͏
    ந৅ߏจ໦͸ͳΜͱͳ͘Θ͔ͬͨͷͰ

    View Slide

  40. ϝδϟʔͳݴޠͷந৅ߏจ໦͸

    ҙ֎ͱ؆୯ʹΈΒΕΔ
    ݴޠʹΑͬͯ͸ඪ४ϥΠϒϥϦ͚ͩͰ

    ந৅ߏจ໦ΛΈΒΕͨΓ͢Δ

    View Slide

  41. 1ZUIPOͷந৅ߏจ໦ͷݟํ
    import ast
    source = "if is_empty(''):\n" \
    " pass\n"
    node = ast.parse(source, "sample.py")
    print(ast.dump(node))

    View Slide

  42. if is_empty(''):
    pass
    ந৅ߏจ໦
    1ZUIPO
    Module(
    body=[
    If(
    test=Call(
    func=Name(
    id='is_empty',
    ctx=Load()
    ),
    args=[
    Str(s='')
    ],
    keywords=[]
    ),
    body=[
    Pass()
    ],
    orelse=[]
    )
    ]
    )

    View Slide

  43. if is_empty(''):
    pass
    ந৅ߏจ໦
    1ZUIPO
    Module(
    body=[
    If(
    test=Call(
    func=Name(
    id='is_empty',
    ctx=Load()
    ),
    args=[
    Str(s='')
    ],
    keywords=[]
    ),
    body=[
    Pass()
    ],
    orelse=[]
    )
    ]
    )

    View Slide

  44. if is_empty(''):
    pass
    ந৅ߏจ໦
    1ZUIPO
    Module(
    body=[
    If(
    test=Call(
    func=Name(
    id='is_empty',
    ctx=Load()
    ),
    args=[
    Str(s='')
    ],
    keywords=[]
    ),
    body=[
    Pass()
    ],
    orelse=[]
    )
    ]
    )

    View Slide

  45. if is_empty(''):
    pass
    ந৅ߏจ໦
    1ZUIPO
    Module(
    body=[
    If(
    test=Call(
    func=Name(
    id='is_empty',
    ctx=Load()
    ),
    args=[
    Str(s='')
    ],
    keywords=[]
    ),
    body=[
    Pass()
    ],
    orelse=[]
    )
    ]
    )

    View Slide

  46. if is_empty(''):
    pass
    ந৅ߏจ໦
    1ZUIPO
    Module(
    body=[
    If(
    test=Call(
    func=Name(
    id='is_empty',
    ctx=Load()
    ),
    args=[
    Str(s='')
    ],
    keywords=[]
    ),
    body=[
    Pass()
    ],
    orelse=[]
    )
    ]
    )

    View Slide

  47. if is_empty(''):
    pass
    ந৅ߏจ໦
    1ZUIPO
    Module(
    body=[
    If(
    test=Call(
    func=Name(
    id='is_empty',
    ctx=Load()
    ),
    args=[
    Str(s='')
    ],
    keywords=[]
    ),
    body=[
    Pass()
    ],
    orelse=[]
    )
    ]
    )

    View Slide

  48. 3VCZͷந৅ߏจ໦ͷݟํ
    require 'ripper'
    require 'pp'
    example = <<~END
    if is_empty('')
    end
    END
    pp Ripper.sexp(example)

    View Slide

  49. ந৅ߏจ໦
    3VCZ
    [:program,
    [
    [:if,
    [:method_add_arg,
    [:fcall,
    [:@ident,
    "is_empty",
    [1, 3]
    ]
    ],
    [:arg_paren,
    [:args_add_block,
    [[:string_literal, [:string_content]]],
    false
    ]
    ]
    ],
    [[:void_stmt]],
    nil
    ]
    ]
    ]
    if is_empty('')
    end

    View Slide

  50. [:program,
    [
    [:if,
    [:method_add_arg,
    [:fcall,
    [:@ident,
    "is_empty",
    [1, 3]
    ]
    ],
    [:arg_paren,
    [:args_add_block,
    [[:string_literal, [:string_content]]],
    false
    ]
    ]
    ],
    [[:void_stmt]],
    nil
    ]
    ]
    ]
    ந৅ߏจ໦
    3VCZ
    if is_empty('')
    end

    View Slide

  51. [:program,
    [
    [:if,
    [:method_add_arg,
    [:fcall,
    [:@ident,
    "is_empty",
    [1, 3]
    ]
    ],
    [:arg_paren,
    [:args_add_block,
    [[:string_literal, [:string_content]]],
    false
    ]
    ]
    ],
    [[:void_stmt]],
    nil
    ]
    ]
    ]
    ந৅ߏจ໦
    3VCZ
    if is_empty('')
    end

    View Slide

  52. [:program,
    [
    [:if,
    [:method_add_arg,
    [:fcall,
    [:@ident,
    "is_empty",
    [1, 3]
    ]
    ],
    [:arg_paren,
    [:args_add_block,
    [[:string_literal, [:string_content]]],
    false
    ]
    ]
    ],
    [[:void_stmt]],
    nil
    ]
    ]
    ]
    ந৅ߏจ໦
    3VCZ
    if is_empty('')
    end

    View Slide

  53. [:program,
    [
    [:if,
    [:method_add_arg,
    [:fcall,
    [:@ident,
    "is_empty",
    [1, 3]
    ]
    ],
    [:arg_paren,
    [:args_add_block,
    [[:string_literal, [:string_content]]],
    false
    ]
    ]
    ],
    [[:void_stmt]],
    nil
    ]
    ]
    ]
    ந৅ߏจ໦
    3VCZ
    if is_empty('')
    end

    View Slide

  54. +BWB4DSJQUͷந৅ߏจ໦ͷݟํ
    import {default as Esprima} from "esprima";
    const program = "if (isEmpty('')) {\n"
    + "}\n";
    const node = Esprima.parseScript(program);
    console.log("%j", node);

    View Slide

  55. ந৅ߏจ໦
    +BWB4DSJQU
    {
    "type": "Program",
    "body": [
    {
    "type": "IfStatement",
    "test": {
    "type": "CallExpression",
    "callee": {
    "type": "Identifier",
    "name": "isEmpty"
    },
    "arguments": [
    {
    "type": "Literal",
    "value": "",
    "raw": "''"
    }
    ]
    },
    "consequent": {
    "type": "BlockStatement",
    "body": []
    },
    "alternate": null
    }
    ],
    "sourceType": "script"
    }
    if (isEmpty('')) {
    }

    View Slide

  56. ந৅ߏจ໦
    +BWB4DSJQU
    {
    "type": "Program",
    "body": [
    {
    "type": "IfStatement",
    "test": {
    "type": "CallExpression",
    "callee": {
    "type": "Identifier",
    "name": "isEmpty"
    },
    "arguments": [
    {
    "type": "Literal",
    "value": "",
    "raw": "''"
    }
    ]
    },
    "consequent": {
    "type": "BlockStatement",
    "body": []
    },
    "alternate": null
    }
    ],
    "sourceType": "script"
    }
    if (isEmpty('')) {
    }

    View Slide

  57. ந৅ߏจ໦
    +BWB4DSJQU
    if (isEmpty('')) {
    }
    {
    "type": "Program",
    "body": [
    {
    "type": "IfStatement",
    "test": {
    "type": "CallExpression",
    "callee": {
    "type": "Identifier",
    "name": "isEmpty"
    },
    "arguments": [
    {
    "type": "Literal",
    "value": "",
    "raw": "''"
    }
    ]
    },
    "consequent": {
    "type": "BlockStatement",
    "body": []
    },
    "alternate": null
    }
    ],
    "sourceType": "script"
    }

    View Slide

  58. ந৅ߏจ໦
    +BWB4DSJQU
    if (isEmpty('')) {
    }
    {
    "type": "Program",
    "body": [
    {
    "type": "IfStatement",
    "test": {
    "type": "CallExpression",
    "callee": {
    "type": "Identifier",
    "name": "isEmpty"
    },
    "arguments": [
    {
    "type": "Literal",
    "value": "",
    "raw": "''"
    }
    ]
    },
    "consequent": {
    "type": "BlockStatement",
    "body": []
    },
    "alternate": null
    }
    ],
    "sourceType": "script"
    }

    View Slide

  59. ந৅ߏจ໦
    +BWB4DSJQU
    {
    "type": "Program",
    "body": [
    {
    "type": "IfStatement",
    "test": {
    "type": "CallExpression",
    "callee": {
    "type": "Identifier",
    "name": "isEmpty"
    },
    "arguments": [
    {
    "type": "Literal",
    "value": "",
    "raw": "''"
    }
    ]
    },
    "consequent": {
    "type": "BlockStatement",
    "body": []
    },
    "alternate": null
    }
    ],
    "sourceType": "script"
    }
    if (isEmpty('')) {
    }

    View Slide

  60. ந৅ߏจ໦ͷ·ͱΊ
    w ந৅ߏจ໦͸ϓϩάϥϜΛ໦ߏ଄Ͱදݱͨ͠΋ͷ
    w ଟ͘ͷ੩తղੳʹந৅ߏจ໦͕ొ৔͢Δ
    w ϝδϟʔͳݴޠͰ͋Ε͹؆୯ʹΈΒΕΔ

    View Slide

  61. ந৅ߏจ໦Λͭ͘Δ

    ߏจղੳΛ஌Ζ͏
    ந৅ߏจ໦Λ׬શʹཧղͨ͠ͷͰ

    View Slide

  62. ϓϩάϥϜͷςΩετ͔Βந৅ߏจ໦Λ

    ࡞੒͢ΔॲཧΛߏจղੳͱݺͿ
    ߏจղੳΛ஌Δͱɺطଘͷߏจղੳ

    ϥΠϒϥϦΛ࢖͏ͱ͖ͷ஫ҙ఺͕Θ͔Δ
    ͨͱ͑͹ɺੑೳྼԽ͠΍͍͢෦෼ͳͲ͕Θ͔Δ

    View Slide

  63. ߏจղੳͷ୅දత࣮૷ख๏
    w ࠶ؼԼ߱๏
    w όοΫτϥοΫ͋Γ
    w ૉ௚ͳ࣮૷
    w 1BSTFS$PNCJOBUPS
    w 1BSTFS&YQSFTTJPO(SBNNBS
    w όοΫτϥοΫͳ͠
    w ʜ
    w ԋࢉࢠॱҐ๏
    w ʜ
    ࠓճղઆ͢Δ࣮૷

    View Slide

  64. ͪΌΜͱͨ͠ఆٛ͸೉͘͠ฉ͑͜Δ͕ɺ

    ࣮ࡍͷίʔυΛΈΕ͹͙͢ʹཧղͰ͖Δ
    श͏ΑΓ׳ΕΑ͏

    View Slide

  65. จ๏نଇͷ঺հ
    ࠓ͔ΒߏจղੳΛ࣮૷͢Δ

    View Slide

  66. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    := "if " <ࣜ> " {\n" <จ>* "}" "\n"
    <ࣜจ> := <ࣜ> "\n"
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    <ࣜ> := <จࣈྻϦςϥϧ> | <ؔ਺ݺͼग़ࣜ͠>
    <จࣈྻϦςϥϧ> := "'" ("\'" | [A-Z_ ])* "'"
    <ؔ਺ݺͼग़ࣜ͠> := <ؔ਺໊> "(" <ࣜ> ")"
    <ؔ਺໊> := [a-z] [a-z]*
    ͜ͷ··ͩͱΘ͔ΓͮΒ͍ͷͰɺ۩ମྫΛग़͠·͢

    View Slide

  67. ίϝϯτ͚ͩϓϩάϥϜ
    // COMMENT ↩︎
    EOF
    &0'͸ϑΝΠϧͷऴྃʢ&OEPG'JMFʣΛҙຯ͢Δه߸

    View Slide

  68. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    ͔͜͜ΒݟΔ
    // COMMENT ↩︎
    EOF

    View Slide

  69. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    จͷ܁Γฦ͠ʹଓ͍ͯ&0'͕͘Δ
    // COMMENT ↩︎
    EOF

    View Slide

  70. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    จͷத਎Λݟʹ͍͘
    // COMMENT ↩︎
    EOF

    View Slide

  71. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    จ͸͜ͷ͏ͪͷͲΕ͔ͭ
    // COMMENT ↩︎
    EOF

    View Slide

  72. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    ࠓճͷจ͸ίϝϯτจ
    // COMMENT ↩︎
    EOF

    View Slide

  73. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτจͷத਎Λݟʹ͍͘
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    // COMMENT ↩︎
    EOF

    View Slide

  74. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ʹଓ͍ͯӳେจࣈͱ@ͱۭന͕Կճ͔ଓ͍ͯɺվߦͰऴΘΔ
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    // COMMENT ↩︎
    EOF

    View Slide

  75. // COMMENT ↩︎
    EOF
    <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ

    View Slide

  76. // COMMENT ↩︎
    EOF
    <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    ίʔυͱͷରԠ͕Ͱ͖ͨΒɺݟͨॱ൪ΛٯʹḪ͍ͬͯ͘

    View Slide

  77. // COMMENT ↩︎
    EOF
    <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    จ΋ίϝϯτจͰରԠ͕औΕͨͷͰḪΔ
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ

    View Slide

  78. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    // COMMENT
    EOF
    ࠓճͷจ͸ճ܁Γฦ͚ͩ͠Ͱɺத਎͸ίϝϯτจ
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ

    View Slide

  79. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    // COMMENT
    EOF
    ࠷ޙ͸&0'ͰऴΘΔ
    ίϝϯτ͚ͩϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ

    View Slide

  80. ͜͜·ͰಡΊΕ͹ɺଞͷίʔυͷ

    จ๏نଇ΋ಡΊΔΑ͏ʹͳΔ

    View Slide

  81. print("TEXT")
    EOF
    ؔ਺ݺͼग़͚ͩ͠ϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ࣜจ> := <ࣜ> "\n"
    <ࣜ> := <จࣈྻϦςϥϧ> | <ؔ਺ݺͼग़ࣜ͠>
    <ؔ਺ݺͼग़͠> := <ؔ਺໊> "(" <ࣜ> ")"
    <ؔ਺໊> := [a-z] [a-z]*

    View Slide

  82. print("TEXT")
    EOF
    ؔ਺ݺͼग़͚ͩ͠ϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ࣜจ> := <ࣜ> "\n"
    <ࣜ> := <จࣈྻϦςϥϧ> | <ؔ਺ݺͼग़ࣜ͠>
    <ؔ਺ݺͼग़͠> := <ؔ਺໊> "(" <ࣜ> ")"
    <ؔ਺໊> := [a-z] [a-z]*
    ಉ͡Α͏ʹݟ͍͖ͯ·͠ΐ͏

    View Slide

  83. print("TEXT")
    EOF
    ؔ਺ݺͼग़͚ͩ͠ϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    <ࣜจ> := <ࣜ> "\n"
    <ࣜ> := <จࣈྻϦςϥϧ> | <ؔ਺ݺͼग़ࣜ͠>
    <ؔ਺ݺͼग़͠> := <ؔ਺໊> "(" <ࣜ> ")"
    <ؔ਺໊> := [a-z] [a-z]* <จࣈྻϦςϥϧ>

    View Slide

  84. EOF
    ۭͷϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    <ϓϩάϥϜ> := <จ>* EOF
    ࣮͸͜Ε΋จ๏نଇ্͸ଥ౰ͳϓϩάϥϜ

    View Slide

  85. EOF
    ۭͷϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    <ϓϩάϥϜ> := <จ>* EOF
    ܁Γฦ͠ճ

    View Slide

  86. ෆਖ਼ͳϓϩάϥϜ΋ΈͯΈΑ͏

    View Slide

  87. / INVALID
    EOF
    ෆਖ਼ͳϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    ద༻Ͱ͖Δจ๏نଇͳ͠

    View Slide

  88. / INVALID
    EOF
    ෆਖ਼ͳϓϩάϥϜ
    ద༻͞Εͨจ๏نଇ
    ͳ͠
    ͜ͷίʔυ͸ϓϩάϥϜͷจͷ͍ͣΕʹ΋

    ͋ͯ͸·Βͳ͍ͷͰɺϓϩάϥϜʹ͋ͯ͸·Βͳ͍
    ͜ͷঢ়گΛʮߏจΤϥʔʢTZOUBYFSSPSʣʯͱ͍͏

    View Slide

  89. จ๏نଇ·ͱΊ
    w จ๏نଇ͸۩ମྫΛߟ͑ΔͱΘ͔Γ΍͍͢
    w จ๏نଇʹ͋ͯ͸·Βͳ͍ͱ͖ߏจΤϥʔʹͳΔ

    View Slide

  90. ߏจղੳͷ࣮૷
    ͖ͬ͞ͷจ๏نଇʹରԠ͢Δ

    View Slide

  91. จ๏نଇͷࠨଆʢͷ෦෼ʣʹ

    ରԠ͢Δந৅ߏจ໦ͷϊʔυΛఆٛ͢Δ
    ఆٛͨ͠ϊʔυ͝ͱʹղੳؔ਺Λ༻ҙ͢Δ
    ߏจղੳͷ࣮૷खॱ

    View Slide

  92. <ϓϩάϥϜ> := <จ>* EOF
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    := "if " <ࣜ> " {\n" <จ>* "}" "\n"
    <ࣜจ> := <ࣜ> "\n"
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    <ࣜ> := <จࣈྻϦςϥϧ> | <ؔ਺ݺͼग़ࣜ͠>
    <จࣈྻϦςϥϧ> := "'" ("\'" | [A-Z_ ])* "'"
    <ؔ਺ݺͼग़ࣜ͠> := <ؔ਺໊> "(" <ࣜ> ")"
    <ؔ਺໊> := [a-z] [a-z]*
    ͜ͷ͝ͱʹந৅ߏจ໦ͷϊʔυΛఆٛ͢Δ

    View Slide

  93. 1SPHSBN
    4UBUFNFOU 4UBUFNFOU
    # <ϓϩάϥϜ> := <จ>*
    class ProgramNode(Node):
    def __init__(self, statement_nodes):
    # <ϓϩάϥϜ>͸ෳ਺ͷ<จ>͔ΒͳΔͷͰɺ
    # ؚ·ΕΔ<จ>Λ഑ྻͰอ࣋͢Δɻ
    self.statements = statement_nodes
    ϓϩάϥϜʹରԠ͢Δந৅ߏจ໦ͷϊʔυ
    จͷϊʔυͷ഑ྻ

    View Slide

  94. # <ϓϩάϥϜ> := <จ>*
    class ProgramNode(Node):
    def __init__(self, statement_nodes):
    # <ϓϩάϥϜ>͸ෳ਺ͷ<จ>͔ΒͳΔͷͰɺ
    # ؚ·ΕΔ<จ>Λ഑ྻͰอ࣋͢Δɻ
    self.statements = statement_nodes 4UBUFNFOU 4UBUFNFOU
    1SPHSBN

    View Slide

  95. # <ϓϩάϥϜ> := <จ>*
    class ProgramNode(Node):
    def __init__(self, statement_nodes):
    # <ϓϩάϥϜ>͸ෳ਺ͷ<จ>͔ΒͳΔͷͰɺ
    # ؚ·ΕΔ<จ>Λ഑ྻͰอ࣋͢Δɻ
    self.statements = statement_nodes
    1SPHSBN
    4UBUFNFOU 4UBUFNFOU

    View Slide

  96. # := "if " <ࣜ> " {\n" จ* "}" "\n"
    class IfStatementNode(Node):
    def __init__(self, condition_node, then_statements):
    # if ͷޙͷ৚݅෦ͷ <ࣜ> Λอ࣋͢Δɻ
    self.condition_node = condition_node
    # { ͱ } ͷؒͷෳ਺ͷ <จ> Λ഑ྻͱͯ͠อ࣋͢Δɻ
    self.then_statements = then_statements
    JGจʹରԠ͢Δந৅ߏจ໦ͷϊʔυ

    View Slide

  97. ಉ༷ʹ͢΂ͯͷʹରԠ͢Δ

    ந৅ߏจ໦ͷϊʔυΛఆٛ͠·͢

    View Slide

  98. ͢΂ͯͷϊʔυΛఆٛ͠ऴΘͬͨΒɺ

    ͜ΕΛ࡞੒͢Δؔ਺Λॻ͍͍ͯ͘

    View Slide

  99. ʹରԠ͢Δؔ਺ͷҾ਺ͱ໭Γ஋ʹ͸ɺ

    Α͋͘Δఆ൪ͷύλʔϯ͕͋Δ
    ͜ͷύλʔϯʹै͏ͱɺؔ਺Λ

    ૊Έ߹Θͤ΍͘͢ͳΔͷͰ͓֮͑ͯ͜͏

    View Slide

  100. ͍͖ͳΓϓϩάϥϜʹରԠ͢Δؔ਺Λ

    ॻ͘ͱઆ໌͕೉͍͠ͷͰɺίϝϯτจʹ

    ରԠ͢Δؔ਺͔Βઆ໌͢Δ

    View Slide

  101. # <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    def parse_comment_statement(text, index):
    # TODO: ͪΌΜͱ࣮૷͢Δ
    next_index = 1234 # TODO: Ծͷ࣮૷
    node = CommentStatementNode(
    comment_content=" COMMENT" # TODO: Ծͷ࣮૷
    )
    return node, next_index
    ίϝϯτจʹରԠ͢Δؔ਺ͷҾ਺ͱ໭Γ஋Λ֬ೝ͠Α͏
    ؔ਺ͷ಺෦͸·ͩԾͷ΋ͷͰɺ͋ͱͰ࣮૷͍ͯ͘͠

    View Slide

  102. # <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    def parse_comment_statement(text, index):
    # TODO: ͪΌΜͱ࣮૷͢Δ
    next_index = 1234 # TODO: Ծͷ࣮૷
    node = CommentStatementNode(
    comment_content=" COMMENT" # TODO: Ծͷ࣮૷
    )
    return node, next_index
    ʮQBSTFʯ͸ʮߏจղੳ͢Δʯͷҙຯ

    View Slide

  103. # <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    def parse_comment_statement(text, index):
    # TODO: ͪΌΜͱ࣮૷͢Δ
    next_index = 1234 # TODO: Ծͷ࣮૷
    node = CommentStatementNode(
    comment_content=" COMMENT" # TODO: Ծͷ࣮૷
    )
    return node, next_index
    ղੳ͍ͨ͠ςΩετશମ ղੳ͍ͨ͠ςΩετͷҐஔ

    View Slide

  104. # <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    def parse_comment_statement(text, index):
    # TODO: ͪΌΜͱ࣮૷͢Δ
    next_index = 1234 # TODO: Ծͷ࣮૷
    node = CommentStatementNode(
    comment_content=" COMMENT" # TODO: Ծͷ࣮૷
    )
    return node, next_index
    ղੳͰ͖ͨίϝϯτจʹ

    ରԠ͢Δந৅ߏจ໦ͷϊʔυ ίϝϯτจ͕ऴΘͬͨҐஔ

    View Slide

  105. ͱΓ͋͑ͣؔ਺ͷ࢖ΘΕํΛΈͯΈΑ͏

    View Slide

  106. (comment_node, next_index) = parse_comment_statement("// COMMENT\n", 0)
    ϓϩάϥϜͷઌ಄͔Βղੳ͢Δύλʔϯ ઌ಄ͳͷͰJOEFY͸
    ղੳ͕ऴΘͬͨҐஔ
    ίϝϯτจʹରԠ͢Δந৅ߏจ໦ͷϊʔυ

    View Slide

  107. (comment_node, next_index) = parse_comment_statement("'123'\n// COMMENT\n", 6)
    ϓϩάϥϜͷ్த͔Βղੳ͢Δύλʔϯ
    ղੳ͕ऴΘͬͨҐஔ
    ్தͷจࣈ໨͔Βղੳ͢Δ
    ίϝϯτจʹରԠ͢Δந৅ߏจ໦ͷϊʔυ

    View Slide

  108. (comment_node, next_index) = parse_comment_statement("'123'\n/ INVALID", 6)
    ղੳʹࣦഊ͢Δύλʔϯ
    ࣦഊͨ͠ΒҐஔ͸ಈ͔͞ͳ͍Ͱͷ··ʹ͢Δ
    ͜ͷΑ͏ʹɺࣦഊͨ͠ΒԿ΋ͳ͔ͬͨΑ͏ʹ

    ר͖໭Δ͜ͱΛʮόοΫτϥοΫʯͱݺͿ
    ղੳʹࣦഊͨ͠ͷͰ/POF
    ్தͷจࣈ໨͔Βղੳ͢Δ

    View Slide

  109. Ҿ਺
    w ղੳ͢Δจࣈྻશମͱ࢝ΊΔҐஔ
    ໭Γ஋
    w ղੳͰ͖ͨந৅ߏจ໦ͷϊʔυͱऴΘͬͨҐஔ
    w ࣦഊͨ͠Β/POFΛฦͯ͠ɺ

    Ґஔ͸ಈ͔͞ͳ͍
    ͜͜ͰҾ਺ͱ໭Γ஋Λ੔ཧ͠Α͏ɿ

    View Slide

  110. Ҿ਺
    w ղੳ͢Δจࣈྻશମͱ࢝ΊΔҐஔ
    ໭Γ஋
    w ղੳͰ͖ͨந৅ߏจ໦ͷϊʔυͱऴΘͬͨҐஔ
    w ࣦഊͨ͠Β/POFΛฦͯ͠ɺ

    Ґஔ͸ಈ͔͞ͳ͍
    ͜͜ͰҾ਺ͱ໭Γ஋Λ੔ཧ͠Α͏ɿ
    ؔ਺͕૊Έ߹Θͤ΍͘͢ͳΔͱ

    ݴ͍ͬͯͨͷ͸͜ͷ෦෼
    લͷؔ਺ʹΑΔղੳ͕ऴΘͬͨ

    Ґஔ͔Βɺ࣍ͷؔ਺ʹΑΔղੳΛ

    ࠶։͢ΔΠϝʔδ

    View Slide

  111. ࣮ࡍͷॲཧͷྲྀΕΛΈͯΈΑ͏
    Ҿ਺ͱ໭Γ஋͕ͳΜͱͳ͘Θ͔ͬͨͷͰ

    View Slide

  112. <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτจͷจ๏نଇͷಡΈํͷ͓͞Β͍ɿ
    ͸͡Ίʹ͕͋Δ
    ଓ͚ͯӳେจࣈ͔@͔ۭന͕ճҎ্ଓ͘
    ࠷ޙʹվߦ͕͋Δ

    View Slide

  113. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  114. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    ίϝϯτจʹରԠ͢Δؔ਺

    View Slide

  115. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ͜͜Ͱ͸͕JOEFYͷҐஔʹ͋Δ͔Ͳ͏͔֬ೝ͍ͯ͠Δ
    FYQFDU@LFZXPSE͸ޙͰઆ໌͢Δ͕ɺΛݟ͚ͭͨΒ

    JOEFYΛͷޙ·ͰҠಈͤ͞Δ
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  116. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ͕Έ͔ͭΒͳ͚Ε͹ίϝϯτจͰ͸ͳ͍ͷͰऴྃ
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  117. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ͜ͷ഑ྻʹίϝϯτ಺ͷจࣈΛ֨ೲ͍ͯ͘͠
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  118. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ίϝϯτ಺ͷจࣈ͸܁Γฦ͠ͳͷͰɺϧʔϓͰॲཧ͢Δ
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  119. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    JOEFYͷҐஔʹ<";@>͕͋Δ͔֬ೝ͍ͯ͠Δ
    FYQFDU@FJUIFSʹ͍ͭͯ͸ޙͰઆ໌͢Δ
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  120. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ΋͠<";@>ʹҰக͠ͳ͔ͬͨΒɺίϝϯτͷ

    ಺༰෦෼͕ऴΘͬͨͷͰɺϧʔϓ͔Β୤ग़
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  121. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ΋͠<";@>Ͱ͋Ε͹ɺίϝϯτจࣈྻ͕·ͩଓ͔͘΋

    ͠Εͳ͍ͷͰɺจࣈΛه࿥ͯ͠ϧʔϓΛ࠶։
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  122. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ίϝϯτ಺ͷจࣈ͕ऴΘͬͨͷͰɺ࠷ޙʹ

    վߦ͕͋Δ͔Ͳ͏͔֬ೝ͍ͯ͠Δ
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  123. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    aO͕ͳ͚Ε͹ɺίϝϯτจͰ͸ͳ͍ͷͰ/POFͱ

    ݩͷJOEFYΛฦ͢
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  124. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ه࿥͓͍ͯͨ͠ίϝϯτ಺ͷจࣈΛ݁߹ͯ͠ɺ

    ίϝϯτͷ಺༰จࣈྻΛ෮ݩ͢Δ
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  125. def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ෮ݩͨ͠ίϝϯτจࣈྻ͔ΒίϝϯτจʹରԠ͢Δ

    ந৅ߏจ໦ͷϊʔυΛ࡞੒ͯ͠ɺਐΊͨJOEFYͱฦ͢
    <ίϝϯτจ> := "//" [A-Z_ ]* "\n"

    View Slide

  126. <ίϝϯτจ> := "//" [A-Z_ ]* "\n"
    def parse_comment_statement(text, index):
    is_success, next_index = expect_keyword("//", text, index)
    if not is_success:
    return None, index
    comment_content_chars = []
    while True:
    comment_content_char, next_index = \
    expect_either(uppercase + [" ", "_"], text, next_index)
    if comment_content_char is None:
    break
    comment_content_chars.append(comment_content_char)
    is_success, next_index = expect_keyword("\n", text, next_index)
    if not is_success:
    return None, index
    comment_content_chars = "".join(comment_content_chars)
    return CommentStatementNode(comment_content_chars), next_index
    ίϝϯτจʹରԠ͢Δؔ਺Λॻ͚ͨ

    View Slide

  127. FYQFDUdͳؔ਺ͷ͸ͨΒ͖
    ్தͰͰ͖ͯͨFYQFDUd͕ؾʹͳΔํ΁

    View Slide

  128. ઌ΄ͲͷQBSTF@DPNNFOU@TUBUFNFOUͷ࣮૷࣌ʹ

    ͋Γ͕ͪͳϛε͕ɺJOEFYͷਐΊ๨Ε΍ਐΊ෯ͷؒҧ͍
    FYQFDU@LFZXPSE΍FYQFDU@FJUIFS͸͜ΕΒͷؒҧ͍Λ

    ༧๷͢ΔͨΊͷϢʔςΟϦςΟؔ਺

    View Slide

  129. text = "abc"
    is_success, next_index = expect_keyword("a", text, 0)
    is_success, next_index = expect_keyword("x", text, 0)
    Bͷ࣍ͷJOEFYͳͷͰ
    JOEFYͷҐஔʢͳͷͰઌ಄ʣʹB͕͋ΔͷͰ5SVF
    ͳ͍৔߹͸JOEFYΛม͑ͳ͍ͷͰ
    JOEFYͷҐஔʢͳͷͰઌ಄ʣʹY͸ͳ͍ͷͰ'BMTF

    View Slide

  130. ൺֱͨ͠จࣈྻͷ௕͚ͩ͞JOEFYΛਐΊΔͷͰɺ

    ਐΊ෯ͷؒҧ͍ͱਐΊ๨ΕΛ๷͛Δ
    ศརʜ

    View Slide

  131. def expect_keyword(expected, text, index):
    expected_len = len(expected)
    actual = text[index:index+expected_len]
    if actual != expected:
    return False, index
    return True, index + expected_len
    def expect_either(expected_list, text, index):
    for expected in expected_list:
    is_success, next_index = expect_keyword(expected, text, index)
    if is_success:
    return expected, next_index
    return None, index

    View Slide

  132. def expect_keyword(expected, text, index):
    expected_len = len(expected)
    actual = text[index:index+expected_len]
    if actual != expected:
    return False, index
    return True, index + expected_len
    def expect_either(expected_list, text, index):
    for expected in expected_list:
    is_success, next_index = expect_keyword(expected, text, index)
    if is_success:
    return expected, next_index
    return None, index
    ৄࡉͳ࣮૷͸͋ͱͰղಡͯ͠Έ͍ͯͩ͘͞ʂ

    View Slide

  133. ͜͜·ͰͰίϝϯτจͷ

    ղੳؔ਺Λ࣮૷Ͱ͖ͨ

    View Slide

  134. ࣍ʹɺจʹର͢Δؔ਺͔Βઌ΄Ͳ

    ࣮૷ͨ͠ίϝϯτจʹରԠ͢Δؔ਺Λ

    ࢖͏ํ๏ΛΈͯΈΑ͏
    ϙΠϯτ͸ɺจ๏نଇͷͷӈଆʹ͕

    ͋ͬͨΒରԠ͢Δղੳؔ਺ʹ೚ͤΔ͜ͱ

    View Slide

  135. <จ> := | <ࣜจ> | <ίϝϯτจ>
    จͷจ๏نଇͷಡΈํͷ͓͞Β͍ɿ
    จ͸ɺJGจɺࣜจɺίϝϯτจͷ͍ͣΕ͔

    View Slide

  136. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  137. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    ·ͣɺJGจʹରԠ͢Δؔ਺ͰղੳͰ͖Δ͔Ͳ͏͔ࢼ͢
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  138. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    ΋͠ɺJGจͱͯ͠ͷղੳʹ੒ޭ͢Ε͹จ͸JGจͩͬͨͱ͍͏͜ͱ
    JGจʹରԠ͢Δந৅ߏจ໦ͱɺJGจͷղੳͰਐΜͩJOEFYΛฦ͢
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  139. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    JGจͱͯ͠ͷղੳʹࣦഊͨ͠Βɺ࣍ʹࣜจͱͯ͠ͷղੳΛࢼ͢
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  140. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    ΋͠ɺࣜจͱͯ͠ͷղੳʹ੒ޭ͢Ε͹จ͸ࣜจͩͬͨͱ͍͏͜ͱ
    ࣜจʹରԠ͢Δந৅ߏจ໦ͱɺࣜจͷղੳͰਐΜͩJOEFYΛฦ͢
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  141. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    ࣜจͱͯ͠ͷղੳʹ΋ࣦഊͨ͠Βɺ࠷ޙʹίϝϯτจͱͯ͠ͷղੳΛࢼ͢
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  142. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    ΋͠ɺίϝϯτจͱͯ͠ͷղੳʹ੒ޭ͢Ε͹จ͸ίϝϯτจͩͬͨͱ͍͏͜ͱ
    ίϝϯτจʹରԠ͢Δந৅ߏจ໦ͱɺίϝϯτจͷղੳͰਐΜͩJOEFYΛฦ͢
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  143. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    JGจɺࣜจɺίϝϯτจͷ͍ͣΕͰ΋ͳ͚Ε͹ɺ

    จͰ͸ͳ͍ͷͰɺ/POFͱݩͷJOEFYΛฦͯ͠ऴྃ
    <จ> := | <ࣜจ> | <ίϝϯτจ>

    View Slide

  144. def parse_statement(text, index):
    if_statement_node, next_index = parse_if_statement(text, index)
    if if_statement_node is not None:
    return if_statement_node, next_index
    expr_statement_node, next_index = parse_expr_statement(text, index)
    if expr_statement_node is not None:
    return expr_statement_node, next_index
    comment_statement_node, next_index = parse_comment_statement(text, index)
    if comment_statement_node is not None:
    return comment_statement_node, next_index
    return None, index
    <จ> := | <ࣜจ> | <ίϝϯτจ>
    ͜ͷΑ͏ʹʹରԠ͢Δؔ਺Λఆ͍ٛͯ͘͠ͱɺ

    ࠷ऴతʹϓϩάϥϜʹରԠ͢Δؔ਺ΛఆٛͰ͖Δ
    ͜ͷϓϩάϥϜʹରԠ͢Δؔ਺͕ɺҰൠతʹ

    ఏڙ͞Ε͍ͯΔߏจղੳثͱݺ͹ΕΔ΋ͷ

    View Slide

  145. ࠓճͷઆ໌Ͱ৮Εͳ͔ͬͨ͜ͱ
    w ࣮༻తͳߏจղੳثʹ͢Δʹ͸ɺந৅ߏจ໦΍

    ߏจΤϥʔʹίʔυ্ͷҐஔ৘ใΛؚΊͨํ͕Α͍
    w όοΫτϥοΫ͋Γͷ࣮૷͸ɺ୯७͔͔ͭͳΓ޿͍ൣғͷ

    จ๏نଇΛղੳͰ͖Δ͕ɺܭࢉྔ͸େ͖͍
    w ࣮͸Ұ൪೉͍͠ͷ͸όάͷͳ͍จ๏نଇΛߟ͑Δ͜ͱ
    w όά͕͋Δͱߏจղੳث͕ແݶϧʔϓͨ͠Γ͢Δ

    View Slide

  146. ૉ௚ͳ࣮૷ͷ·ͱΊ
    w ࣮૷͸ҎԼͷεςοϓͰͰ͖Δɿ
    w ʹରԠ͢Δந৅ߏจ໦Λఆٛ͢Δ
    w ʹରԠ͢Δؔ਺Λఆٛ͢Δ
    w จ๏نଇͷӈଆʹ͕͋Δ৔߹͸ɺ

    ͦͷʹରԠ͢Δؔ਺ʹղੳΛ೚ͤΔ

    View Slide

  147. 1BSTFS$PNCJOBUPSͷҖྗ
    ΋ͬͱΤϨΨϯτͳํ๏Λνϥݟͤ

    View Slide

  148. ࠓճ঺հͨ͠ૉ௚ͳ࣮૷Λ1BSTFS$PNCJOBUPSͰ࣮૷͢Δͱɺ

    ಉ͡ॲཧͳͷʹڻ͘΄Ͳ࣮૷͕୹͘ͳΓɺ͔ͭ࠶ར༻ੑ্͕͕Δɿ
    parse_comment = sequence(
    string("//"),
    sequence(
    many(char(uppercase + ["_", " "])),
    string("\n")
    )
    )
    ؾʹͳΔਓ͸ɺεϥΠυ຤ඌͷࢀߟจݙ#Λࢀর

    View Slide

  149. ߏจղੳͷ·ͱΊ
    w ߏจղੳ͸ίʔυΛղੳͯ͠ந৅ߏจ໦Λ

    ࡞੒͢Δॲཧ
    w ͞·͟·ͳߏจղੳͷΞϧΰϦζϜ͕͋Δ
    w ࠓճ͸όοΫτϥοΫ͋Γͷ

    ࠶ؼԼ߱෼ੳΛૉ௚ʹ࣮૷ͨ͠

    View Slide

  150. ந৅ߏจ໦Λॲཧ͢Δ

    ୅දతͳ࣮૷ύλʔϯ
    ߏจղੳͷ͓࣍͸

    View Slide

  151. ͜Ε·Ͱ͸ɺந৅ߏจ໦ͷ֓ཁ΍࡞੒ํ๏ΛΈ͖ͯͨ
    ࣍ʹɺ͜͜Ͱ͸ந৅ߏจ໦Λ͔͋ͭ͏୅දతͳ

    ࣮૷ύλʔϯΛ঺հ͢Δ
    ΋ͬͱ΋සൟʹ࢖͏࣮૷ύλʔϯͱͯ͠ɺந৅ߏจ໦Λ

    ॱ൪ʹ୳ࡧ͍ͯ͘͠૸ࠪؔ਺Λ঺հ͢Δ

    View Slide

  152. ૸ࠪؔ਺
    ந৅ߏจ໦Λ͔͋ͭ͏୅දతύλʔϯ

    View Slide

  153. ૸ࠪؔ਺͸ɺந৅ߏจ໦ͷϊʔυΛॱʹḷ͍ͬͯͬͯɺ

    ϊʔυʹ๚ΕΔ཭ΕΔͨͼʹॲཧΛ࣮ߦ͢Δؔ਺
    traverse(node, on_enter, on_leave)
    PO@FOUFSͱPO@MFBWF͸ͲͪΒ΋ؔ਺Λ౉͢
    ϊʔυʹ๚ΕΔ཭ΕΔͱ࣮ߦ͞ΕΔ
    Կ͕ى͜Δ͔Θ͔ΓͮΒ͍ͷͰਤղ͠·͢

    View Slide

  154. def print_enter(node):
    print("enter: {node}".format(node=type(node)))
    def print_leave(node):
    print("leave: {node}".format(node=type(node)))
    traverse(node, print_enter, print_leave)
    PO@FOUFSͱPO@MFBWF͕Θ͔ΔΑ͏ʹQSJOU͢Δؔ਺Λ༻ҙ

    View Slide

  155. ͜ͷUSBWFSTFʹΑͬͯQSJOU͞ΕΔ݁ՌΛΈͯΈ·͠ΐ͏
    QSJOU݁Ռ
    1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU

    View Slide

  156. *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    1SPHSBN
    ·ͣ͸1SPHSBNʹ๚ΕΔʢFOUFS1SPHSBNΛQSJOUʣ
    FOUFS1SPHSBN
    QSJOU݁Ռ

    View Slide

  157. 1SPHSBN
    4USJOH-JUFSBM
    'VOD$BMM
    *EFOUJpFS
    $PNNFOU
    *G4UBUFNFOU
    ࣍ʹ1SPHSBNͷࢠͰ͋Δ*G4UBUFNFOU΁๚ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    QSJOU݁Ռ

    View Slide

  158. 1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    *EFOUJpFS
    $PNNFOU
    'VOD$BMM
    ࣍ʹ*G4UBUFNFOUͷࢠͰ͋Δ'VOD$BMMΛ๚ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    QSJOU݁Ռ

    View Slide

  159. 1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    *EFOUJpFS
    QSJOU݁Ռ
    ࣍ʹ'VOD$BMMͷࢠͰ͋Δ*EFOUJpFSΛ๚ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS

    View Slide

  160. 1SPHSBN
    *G4UBUFNFOU
    4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    *EFOUJpFS
    QSJOU݁Ռ
    *EFOUJpFSʹࢠ͸͍ͳ͍ͷͰɺ*EFOUJpFS͔Β཭ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS

    View Slide

  161. 1SPHSBN
    *G4UBUFNFOU
    'VOD$BMM $PNNFOU
    *EFOUJpFS 4USJOH-JUFSBM
    QSJOU݁Ռ
    'VOD$BMMͷ࣍ͷࢠͰ͋Δ4USJOH-JUFSBMΛ๚ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM

    View Slide

  162. 1SPHSBN
    *G4UBUFNFOU
    'VOD$BMM $PNNFOU
    *EFOUJpFS 4USJOH-JUFSBM
    QSJOU݁Ռ
    4USJOH-JUFSBMʹࢠ͸͍ͳ͍ͷͰɺ4USJOH-JUFSBM͔Β཭ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM
    MFBWF4USJOH-JUFSBM

    View Slide

  163. 1SPHSBN
    *G4UBUFNFOU
    $PNNFOU
    *EFOUJpFS 4USJOH-JUFSBM
    'VOD$BMM
    QSJOU݁Ռ
    'VOD$BMMͷ͢΂ͯͷࢠΛ๚໰ͨ͠ͷͰɺ'VOD$BMM͔Β཭ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM
    MFBWF4USJOH-JUFSBM
    MFBWF'VOD$BMM

    View Slide

  164. 1SPHSBN
    *G4UBUFNFOU
    *EFOUJpFS 4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    QSJOU݁Ռ
    *G4UBUFNFOUͷ࣍ͷࢠͰ͋Δ$PNNFOUΛ๚ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM
    MFBWF4USJOH-JUFSBM
    MFBWF'VOD$BMM
    FOUFS$PNNFOU

    View Slide

  165. 1SPHSBN
    *G4UBUFNFOU
    *EFOUJpFS 4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    QSJOU݁Ռ
    $PNNFOUʹࢠ͸͍ͳ͍ͷͰɺ$PNNFOU͔Β཭ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM
    MFBWF4USJOH-JUFSBM
    MFBWF'VOD$BMM
    FOUFS$PNNFOU
    MFBWF$PNNFOU

    View Slide

  166. 1SPHSBN
    *EFOUJpFS 4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    *G4UBUFNFOU
    QSJOU݁Ռ
    *G4UBUFNFOUͷ͢΂ͯͷࢠΛ๚໰ͨ͠ͷͰɺ཭ΕΔ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM
    MFBWF4USJOH-JUFSBM
    MFBWF'VOD$BMM
    FOUFS$PNNFOU
    MFBWF$PNNFOU
    MFBWF*G4UBUFNFOU

    View Slide

  167. *EFOUJpFS 4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    *G4UBUFNFOU
    1SPHSBN
    QSJOU݁Ռ
    1SPHSBNͷ͢΂ͯͷࢠΛ๚໰ͨ͠ͷͰɺ૸ࠪ׬ྃ
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM
    MFBWF4USJOH-JUFSBM
    MFBWF'VOD$BMM
    FOUFS$PNNFOU
    MFBWF$PNNFOU
    MFBWF*G4UBUFNFOU
    MFBWF1SPHSBN

    View Slide

  168. *EFOUJpFS 4USJOH-JUFSBM
    'VOD$BMM $PNNFOU
    *G4UBUFNFOU
    1SPHSBN
    QSJOU݁Ռ
    ཁ͢Δʹɺந৅ߏจ໦Λਂ͞༏ઌ୳ࡧ͢Δؔ਺
    FOUFS1SPHSBN
    FOUFS*G4UBUFNFOU
    FOUFS'VOD$BMM
    FOUFS*EFOUJpFS
    MFBWF*EFOUJpFS
    FOUFS4USJOH-JUFSBM
    MFBWF4USJOH-JUFSBM
    MFBWF'VOD$BMM
    FOUFS$PNNFOU
    MFBWF$PNNFOU
    MFBWF*G4UBUFNFOU
    MFBWF1SPHSBN

    View Slide

  169. ͜ͷΑ͏ͳந৅ߏจ໦Λ૸ࠪ͢Δؔ਺͕

    ༻ҙ͞Ε͍ͯΔͱɺ͞ΒʹޙͰ঺հ͢Δ

    ੩తݕࠪͷίʔυ͕ͱͯ΋ॻ͖΍͘͢ͳΔ

    View Slide

  170. ͢΂ͯͷந৅ߏจ໦ͷϊʔυʹɺࣗ਎ͷ

    ࢠͷҰཡΛฦؔ͢਺Λ௥Ճ͢Δ
    ϊʔυΛ๚ΕͨΒͷࢠͷҰཡΛऔಘͯ͠ɺ

    ࠶ؼతʹ๚Ε͍ͯؔ͘਺Λ࣮૷͢Δ
    ૸ࠪؔ਺ͷ࣮૷खॱ

    View Slide

  171. class Node:
    def children(self):
    raise NotImplementedError()
    class ProgramNode(Node):
    def __init__(self, statement_nodes):
    self.statements = statement_nodes
    def children(self):
    return self.statements
    ந৅ߏจ໦ͷϊʔυ͕ࣗ਎ͷࢠΛฦ͢Α͏ʹཁٻ͢ΔجఈΫϥεΛ༻ҙ

    View Slide

  172. class Node:
    def children(self):
    raise NotImplementedError()
    class ProgramNode(Node):
    def __init__(self, statement_nodes):
    self.statements = statement_nodes
    def children(self):
    return self.statements
    ͦΕͧΕͷந৅ߏจ໦ͷϊʔυʹ࣮૷ͯ͠΋Β͏

    View Slide

  173. class Node:
    def children(self):
    raise NotImplementedError()
    class ProgramNode(Node):
    def __init__(self, statement_nodes):
    self.statements = statement_nodes
    def children(self):
    return self.statements
    ϓϩάϥϜͷ͢΂ͯͷࢠͷҰཡΛ഑ྻͱͯ͠ฦ͢
    ࠓճ͸จͷ഑ྻҎ֎ʹࢠ͸ͳ͍ͷͰͦͷ··ฦͤ͹Α͍

    View Slide

  174. class IfStatementNode(Node):
    def __init__(self, condition_node, then_statements):
    self.condition_node = condition_node
    self.then_statements = then_statements
    def children(self):
    children = [self.condition_node]
    return children + self.then_statements
    ผͷέʔεͱͯ͠ɺJGจͷந৅ߏจ໦ͷϊʔυ΋ΈͯΈΑ͏

    View Slide

  175. class IfStatementNode(Node):
    def __init__(self, condition_node, then_statements):
    self.condition_node = condition_node
    self.then_statements = then_statements
    def children(self):
    children = [self.condition_node]
    return children + self.then_statements
    JGจͷࢠ͸৚݅෦ͷࣜͱɺ\^ͷதͷ

    ෳ਺ͷจͳͷͰɺ·ͱΊͯҰཡʹͯ͠ฦ͢

    View Slide

  176. class IfStatementNode(Node):
    def __init__(self, condition_node, then_statements):
    self.condition_node = condition_node
    self.then_statements = then_statements
    def children(self):
    children = [self.condition_node]
    return children + self.then_statements
    ಉ༷ʹɺ͢΂ͯͷந৅ߏจ໦ͷϊʔυʹDIJMESFOΛ࣮૷ͤ͞Δ

    View Slide

  177. ४උ͕੔ͬͨͷͰɺ૸ࠪؔ਺ͷ

    ຊମΛ࣮૷͍ͯ͘͠

    View Slide

  178. def traverse(node, on_enter=None, on_leave=None):
    if on_enter is not None:
    on_enter(node)
    for child in node.children():
    traverse(child, on_enter, on_leave)
    if on_leave is not None:
    on_leave(node)

    View Slide

  179. def traverse(node, on_enter=None, on_leave=None):
    if on_enter is not None:
    on_enter(node)
    for child in node.children():
    traverse(child, on_enter, on_leave)
    if on_leave is not None:
    on_leave(node)
    ந৅ߏจ໦ͷϊʔυΛ๚ΕͨͷͰPO@FOUFSΛ࣮ߦ͢Δ
    ΋͠PO@FOUFS͕লུ͞Ε͍ͯΔ৔߹͸Կ΋͠ͳ͍

    View Slide

  180. def traverse(node, on_enter=None, on_leave=None):
    if on_enter is not None:
    on_enter(node)
    for child in node.children():
    traverse(child, on_enter, on_leave)
    if on_leave is not None:
    on_leave(node)
    ந৅ߏจ໦ͷϊʔυ͔ΒࢠͷҰཡΛ

    औಘ͠ɺࢠΛ࠶ؼతʹ૸͍ࠪͯ͘͠

    View Slide

  181. def traverse(node, on_enter=None, on_leave=None):
    if on_enter is not None:
    on_enter(node)
    for child in node.children():
    traverse(child, on_enter, on_leave)
    if on_leave is not None:
    on_leave(node)
    ࢠͷ૸͕ࠪऴΘͬͨͷͰɺࠓͷϊʔυ͔Βୀग़͢Δ

    View Slide

  182. ͜͜·ͰͰ؆୯ʹ૸ࠪؔ਺Λ࣮૷Ͱ͖ͨ
    ૸ࠪؔ਺͸഑ྻͰ͍͏GPS&BDIͷΑ͏ͳ

    جૅతͳؔ਺ͩͱߟ͑ΔͱΘ͔Γ΍͍͢
    ͦͷͨΊɺͱͯ΋Ԡ༻ͷൣғ͕޿͍

    View Slide

  183. w ৚݅ʹ͋ͬͨந৅ߏจ໦ͷϊʔυͷநग़
    w ม਺ؔ਺ͷείʔϓղੳ
    w ʜ
    ૸ࠪؔ਺ͰͰ͖Δ͜ͱ

    View Slide

  184. found = find_nodes(node, condition)
    ৚݅ʹ͋ͬͨந৅ߏจ໦ͷϊʔυͷநग़
    ୳ࡧ͍ͨ͠ந৅ߏจ໦ ݕࡧ͍ͨ͠৚݅ͷؔ਺
    ͜ͷநग़ؔ਺͸૸ࠪؔ਺Λ࢖ͬͯ

    ؆୯ʹ࣮૷Ͱ͖Δ

    View Slide

  185. def find_nodes(node, condition):
    found_nodes = []
    def collect_nodes(entered_node):
    if not condition(entered_node):
    return
    found_nodes.append(entered_node)
    traverse(node, collect_nodes)
    return found_nodes

    View Slide

  186. def find_nodes(node, condition):
    found_nodes = []
    def collect_nodes(entered_node):
    if not condition(entered_node):
    return
    found_nodes.append(entered_node)
    traverse(node, collect_nodes)
    return found_nodes
    ݕࡧ৚݅ʹ͋ͯ͸·Δந৅ߏจ໦ͷϊʔυΛूΊΔ഑ྻ

    View Slide

  187. def find_nodes(node, condition):
    found_nodes = []
    def collect_nodes(entered_node):
    if not condition(entered_node):
    return
    found_nodes.append(entered_node)
    traverse(node, collect_nodes)
    return found_nodes
    ந৅ߏจ໦ͷϊʔυΛ๚ΕΔλΠϛϯάͰݕࡧ৚݅ͷ

    ؔ਺Λ࣮૷͠ɺ৚݅ʹ͋ͯ͸·ΔϊʔυΛूΊΔؔ਺

    View Slide

  188. def find_nodes(node, condition):
    found_nodes = []
    def collect_nodes(entered_node):
    if not condition(entered_node):
    return
    found_nodes.append(entered_node)
    traverse(node, collect_nodes)
    return found_nodes
    ந৅ߏจ໦ͷϊʔυΛूΊΔؔ਺Λ

    PO@FOUFSʹࢦఆͯ͠૸ࠪΛ։࢝

    View Slide

  189. def find_nodes(node, condition):
    found_nodes = []
    def collect_nodes(entered_node):
    if not condition(entered_node):
    return
    found_nodes.append(entered_node)
    traverse(node, collect_nodes)
    return found_nodes
    ݟ͔ͭͬͨந৅ߏจ໦ͷϊʔυͷ഑ྻΛฦ͢

    View Slide

  190. def find_nodes(node, condition):
    found_nodes = []
    def collect_nodes(entered_node):
    if not condition(entered_node):
    return
    found_nodes.append(entered_node)
    traverse(node, collect_nodes)
    return found_nodes
    ૸ࠪؔ਺Λ࢖͏͜ͱͰɺͱͯ΋؆୯ʹ࣮૷Ͱ͖ͨ

    View Slide

  191. ଞʹ΋ɺ૸ࠪؔ਺Λ࢖͏ͱείʔϓղੳΛ

    ࣮૷͠΍͘͢ͳΔ
    είʔϓղੳͱ͸ɺม਺ͷఆٛ͞Ε͍ͯΔ

    είʔϓΛղੳ͢Δ͜ͱͰɺະఆٛͷม਺΍

    ະ࢖༻ͷม਺Λݟ͚ͭΔख๏

    View Slide

  192. ίʔυ͕͔ͳΓ௕͘ͳΔͷͰɺ࣮ࡍͷίʔυ͸ׂѪ͢Δ͕ɺ

    େ·͔ʹҎԼͷखॱͰείʔϓΛղੳͰ͖Δɿ
    ؔ਺એݴͷߏจ໦΁ͷPO@FOUFSͰ

    είʔϓΦϒδΣΫτΛ࡞੒͢Δ
    ࡞੒ͨ͠είʔϓΦϒδΣΫτΛ

    ݱࡏͷείʔϓͷελοΫʹੵΉ
    ݟ͔ͭͬͨม਺એݴΛελοΫͷઌ಄ͷ

    είʔϓΦϒδΣΫτ΁Ճ͍͑ͯ͘
    ؔ਺એݴͷߏจ໦͔ΒͷPO@MFBWFͰ

    ઌ಄ͷείʔϓΦϒδΣΫτΛ

    ελοΫ͔ΒऔΓআ͘




    View Slide

  193. • https://github.com/estools/escope
    • https://github.com/rubocop-hq/rubocop

    ͷ VariableForce
    • https://github.com/Kuniwak/vint

    ͷ scope_plugin
    ࢀߟʹͳΔείʔϓղੳͷ࣮૷

    View Slide

  194. ૸ࠪؔ਺ͷ࣮૷Ͱઆ໌͠ͳ͔ͬͨ͜ͱ
    w ૸ࠪͷதஅ΍ࢠͷ୳ࡧͷεΩοϓػೳ
    w ύϑΥʔϚϯεվળͷͨΊʹॏཁ
    w ୈڃؔ਺Λ࢖Θͳ͍૸ࠪؔ਺ͷ࣮૷
    w ݴޠʹΑͬͯ͸ؔ਺ΛҾ਺ʹ౉ͤͳ͍͜ͱ΋͋Δ
    w ͦͷ৔߹͸(P'ͷ7JTJUPSύλʔϯͰ୅ସՄೳ

    View Slide

  195. ૸ࠪؔ਺ͷ·ͱΊ
    w ந৅ߏจ໦ͷ૸ࠪؔ਺Λఆ͓ٛͯ͘͠ͱศར
    w ૸ࠪؔ਺ͷ࣮૷͸೉͘͠ͳ͍
    w ૸ࠪؔ਺͸͞·͟·ͳॲཧ΁Ԡ༻Ͱ͖Δ

    View Slide

  196. ؆୯ͳ੩తղੳΛ

    ࣮૷ͯ͠ΈΑ͏
    Α͏΍͘ΰʔϧ

    View Slide

  197. if isEmpty('') {
    //CATCH_ME_IF_YOU_CAN
    }
    ͓୊͸ɺੜҙؾͳίϝϯτ਺Λใࠂ͢Δ੩తղੳ
    report_specific_comments(text)
    # Found 1 namaiki comments!

    View Slide

  198. ߏจղੳͯ͠ந৅ߏจ໦Λ࡞੒͢Δ
    ந৅ߏจ໦Λ૸ࠪͯ͠ྫͷίϝϯτΛूΊΔ
    ूΊͨίϝϯτΛใࠂ͢Δ
    ࣮૷ͷྲྀΕ

    View Slide

  199. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ίʔυ͔ΒੜҙؾͳίϝϯτΛݟ͚ͭͯ਺Λใࠂ͢Δؔ਺

    View Slide

  200. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ίʔυΛߏจղੳͯ͠ந৅ߏจ໦Λ࡞੒͢Δ

    View Slide

  201. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ߏจղੳʹࣦഊͨ͠ΒɺߏจΤϥʔΛදࣔ

    View Slide

  202. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ૸ࠪؔ਺ͷར༻ྫͱ࣮ͯ͠૷ͨ͠ɺݕࡧؔ਺Λ࢖ͬͯੜҙؾͳίϝϯτΛूΊΔ

    View Slide

  203. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ݕࡧؔ਺ͷ৚݅ʹࢦఆͨ͠ɺੜҙؾίϝϯτ͔Ͳ͏͔൑ఆ͢Δؔ਺

    View Slide

  204. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ·ͣɺந৅ߏจ໦͕ίϝϯτจͰͳ͚Ε͹ɺ

    ੜҙؾͳίϝϯτͰ͸ͳ͍ͷͰɺ'BMTFΛฦͯ͠ऴྃ

    View Slide

  205. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ίϝϯτจͩͬͨ৔߹ɺίϝϯτͷ಺༰ʹੜҙؾͳ

    ΋ͷؚ͕·Ε͍ͯΕ͹5SVFɺͦΕҎ֎͸'BMTFΛฦ͢

    View Slide

  206. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ઌ΄Ͳͷؔ਺Ͱ5SVF͕ฦ͞Εͨந৅ߏจ໦ʢੜҙؾͳίϝϯτʣ͕

    Ұཡʹͯ͠ฦ͞ΕΔ

    View Slide

  207. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ੜҙؾͳίϝϯτͷ਺Λใࠂͯ͠ऴྃ

    View Slide

  208. def report_namaiki_comments(text):
    node = parse_program(text)
    if node is None:
    print("Syntax Error!")
    return
    namaiki_comments = find_nodes(node, is_namaiki_comment)
    print("Found {count} comments!".format(count=len(namaiki_comments)))
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ߏจղੳثɾ૸ࠪؔ਺ɾݕࡧؔ਺Λ

    ૊Έ߹Θͤͯ࢖͏͜ͱͰɺͱͯ΋

    ؆୯ʹ੩తݕࠪΛ࣮૷Ͱ͖ͨ

    View Slide

  209. ؆୯ͳ੩తݕࠪͷ࣮૷·ͱΊ
    ੩తݕࠪ͸ɺߏจղੳثɾ૸ࠪؔ਺ɾݕࡧؔ਺Λ

    ૊Έ߹ΘͤΔ͜ͱͰɺ͘͝؆୯ʹ࣮૷Ͱ͖Δ

    View Slide

  210. ෳࡶͳ੩తղੳΛ

    ෼ׂ͢ΔςΫχοΫ
    ΰʔϧୡ੒ͷͦͷઌ΁

    View Slide

  211. ઌ΄Ͳ͸ͭͷ੩తݕࠪϧʔϧͷΈΛ࣮૷͕ͨ͠ɺ

    ݱ࣮ʹ͸ෳ਺ͷݕࠪϧʔϧΛ࣮૷͢Δ͜ͱ͕ଟ͍
    ͜ͷͱ͖ɺͲͷΑ͏ʹίʔυΛ෼ׂ͢Δ͔ʹΑͬͯ

    อकੑ͕େ͖͘มΘΔ

    View Slide

  212. ݕࠪϧʔϧʹΑΔ෼ׂΛ঺հ
    ༗໊ͳ੩తղੳπʔϧͷ൒਺Ҏ্͕࠾༻͍ͯ͠Δ

    View Slide

  213. ݕࠪϧʔϧʹΑΔ෼ׂͰ͸ɺͭͷݕࠪϧʔϧ͕

    ͭͷίϯϙʔωϯτʢΫϥεPSؔ਺ʣʹରԠ͢Δ
    ͜ΕʹΑͬͯݕࠪϧʔϧ͕͓ޓ͍ʹૄʹͳΓɺ

    ݕࠪϧʔϧͷ௥Ճमਖ਼࡟আΛ΍Γ΍͘͢ͳΔ

    View Slide

  214. class Policy:
    def get_violations(self, node):
    raise NotImplementedError()
    ݕࠪϧʔϧͷڞ௨ΠϯλʔϑΣʔεΛܾΊΔ

    View Slide

  215. class Policy:
    def get_violations(self, node):
    raise NotImplementedError()
    ந৅ߏจ໦ͷϊʔυ͔Βݟ͔ͭͬͨ໰୊Λɺจࣈྻͷ

    ഑ྻͱͯ͠ฦ͢ϝιουɻ͜ͷϝιου͸ɺ΄͔ͷ

    ίϯϙʔωϯτ಺Ͱ૸ࠪؔ਺͔Βݺ͹ΕΔΠϝʔδ

    View Slide

  216. class Policy:
    def get_violations(self, node):
    raise NotImplementedError()
    ྫ͑͹ɺҾ਺ʹੜҙؾͳίϝϯτจ͕͖ͨΒ

    ࢦఠϝοηʔδΛฦ࣮͢૷΍ɺJGจ͕͖ͨΒ

    ৚݅෦෼ͷࣜΛݕࠪ͢Δͧɺͱ͍͏࣮૷͕͋Γ͑Δ
    ॏཁͳͷ͸ɺݕࠪϧʔϧ͕ผͳΒผͷΫϥεʹ

    ෼ׂ࣮ͯ͠૷͢Δ͜ͱɻҰॹʹ͢Δͱอक͕େมʹͳΔ

    View Slide

  217. class NamaikiCommentPolicy(Policy):
    def get_violations(self, node):
    if not is_namaiki_comment(node):
    return []
    return ["FOUND YOU!"]
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    લʹ࣮૷ͨ͠ͷͱಉ͡ɺੜҙؾͳίϝϯτจΛࢦఠ͢Δݕࠪϧʔϧ

    View Slide

  218. class NamaikiCommentPolicy(Policy):
    def get_violations(self, node):
    if not is_namaiki_comment(node):
    return []
    return ["FOUND YOU!"]
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    Ҿ਺ͷந৅ߏจ໦ͷϊʔυ͕ੜҙؾͳίϝϯτจʼͳΒɺ

    ʮݟ͚ͭͨͧʂʯͱ͍͏ϝοηʔδΛฦ͢Α͏ʹ࣮૷

    View Slide

  219. class NamaikiCommentPolicy(Policy):
    def get_violations(self, node):
    if not is_namaiki_comment(node):
    return []
    return ["FOUND YOU!"]
    def is_namaiki_comment(entered_node):
    if not isinstance(entered_node, CommentStatementNode):
    return False
    comment_node = entered_node
    return "CATCH_ME_IF_YOU_CAN" in comment_node.comment_content
    ੜҙؾͳίϝϯτจΛ൑ఆ͢Δؔ਺͸લͷ΋ͷΛྲྀ༻

    View Slide

  220. class Policies(Policy):
    def __init__(self, policies):
    self.policies = policies
    def get_violations(self, node):
    return reduce(
    lambda violations, policy: violations + policy.get_violations(node),
    self.policies,
    []
    )
    ෳ਺ͷݕࠪϧʔϧΛଋͶΔݕࠪϧʔϧΛ४උ

    View Slide

  221. class Policies(Policy):
    def __init__(self, policies):
    self.policies = policies
    def get_violations(self, node):
    return reduce(
    lambda violations, policy: violations + policy.get_violations(node),
    self.policies,
    []
    )
    ݕࠪϧʔϧͱಉ͡ڞ௨ΠϯλʔϑΣʔεΛ࣮૷͢Δ

    View Slide

  222. class Policies(Policy):
    def __init__(self, policies):
    self.policies = policies
    def get_violations(self, node):
    return reduce(
    lambda violations, policy: violations + policy.get_violations(node),
    self.policies,
    []
    )
    ಺෦ͷෳ਺ͷݕࠪϧʔϧΛϧʔϓͯ͠ݕࠪͯ͠ɺ݁ՌΛ߹੒ͯ͠ฦ͢

    View Slide

  223. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)

    View Slide

  224. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ෳ਺ͷݕࠪϧʔϧͰ·ͱΊͯݕࠪ͢Δؔ਺

    View Slide

  225. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ༩͑ΒΕͯจࣈྻΛߏจղੳͯ͠ந৅ߏจ໦Λ࡞੒

    View Slide

  226. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ߏจղੳʹࣦഊͨ͠ΒɺߏจղੳࣦഊͷϝοηʔδΛ݁Ռͱͯ͠ฦ͢

    View Slide

  227. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ෳ਺ͷݕࠪϧʔϧΛଋͶͯɺͭͷݕࠪϧʔϧʹ·ͱΊΔ

    ʢ͜ͷྫͰ͸ɺੜҙؾͳίϝϯτΛݕࠪ͢Δϧʔϧ͚ͩʣ

    View Slide

  228. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ݕࠪϝοηʔδΛूΊΔ഑ྻΛ४උ

    View Slide

  229. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ༩͑ΒΕͨந৅ߏจ໦ͷϊʔυ͔ΒɺݕࠪϝοηʔδΛूΊΔؔ਺

    View Slide

  230. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ந৅ߏจ໦Λ૸ࠪͯ͠ɺݕࠪϝοηʔδΛूΊ͍ͯ͘

    View Slide

  231. def lint(text):
    node = parse_program(text)
    if node is None:
    return ["Syntax Error!"]
    policies = Policies([NamaikiCommentPolicy()])
    violations_buffer = []
    def collect_violations(entered_node):
    violations = policies.get_violations(entered_node)
    violations_buffer.append(violations)
    traverse(node, collect_violations)
    all_violations = []
    return reduce(add, violations_buffer, all_violations)
    ू·ͬͨݕࠪϝοηʔδΛͭͷ഑ྻʹ·ͱΊͯฦ͢

    View Slide

  232. text = "if isEmpty('') {\n// CATCH_ME_IF_YOU_CAN\n}\n"
    violations = lint(text)
    ෳ਺ͷݕࠪϧʔϧͰ੩తղੳͰ͖ΔΑ͏ʹͳͬͨ

    View Slide

  233. ݕࠪϧʔϧʹΑΔ෼ׂͷ·ͱΊ
    w ੩తݕࠪͷݕࠪϧʔϧ͸ݸผͷίϯϙʔωϯτ

    ͱ࣮ͯ͠૷͢Δͱอक͠΍͍͢
    w ଟ͘ͷ੩తݕࠪπʔϧ͸͜ͷύλʔϯʹԊͬͯ

    ࣮૷͞Ε͍ͯΔ

    View Slide

  234. ଞʹ΋࣮૷ύλʔϯ͸ͨ͘͞Μ͋Δ͕ɺ

    ࣌ؒͷ౎߹ʢͱࠓͷମྗʣͰ͸঺հ͖͠Εͳ͍
    ͞Βʹ஌Γ͍ͨํ͸ɺʮ7JNTDSJQUͷ-JOU࡞ऀʹ

    ΑΔ୭ಘσβΠϯύλʔϯʯͱ͍͏هࣄΛࢀর
    https://qiita.com/Kuniwak/items/d6a2d22711e4d7856edd

    View Slide

  235. ࣮ࡍͷ੩తݕࠪπʔϧͷ

    ࣮૷ΛಡΜͰΈΑ͏
    ීஈ࢖͍ͬͯΔ

    View Slide

  236. 1ZUIPO
    w ߏจղੳث
    w BTUQBSTFʢඪ४ϥΠϒϥϦʣ
    w ૸ࠪؔ਺
    w BTU/PEF7JTJUPSʢඪ४ϥΠϒϥϦʣ
    w ੩తݕࠪϧʔϧ
    w $IFDLFS53:ʢQZqBLFTͷQZqBLTDIFDLFSQZʣ

    View Slide

  237. 3VCZ
    w ߏจղੳث
    w 1BSTFS3VCZ

    (JU)VCͷXIJUFRVBSLQBSTFSͷMJCQBSTFSSVCZZ

    w ૸ࠪؔ਺
    w 3VCPDPQ"455SBWFSTBM

    3VCPDPQͷMJCSVCPDPQBTUUSBWFSTBMSC

    w ੩తݕࠪϧʔϧ
    w 3VCPDPQ$PQ-JOU&NQUZ&OTVSF

    3VCPDPQͷMJCSVCPDPQDPQMJOUFNQUZ@FOTVSFSC

    View Slide

  238. +BWB4DSJQU
    w ߏจղੳث
    w 1BSTFSʢ(JU)VCͷBDPSOKTBDPSOͷTSDTUBUFKT

    w ૸ࠪؔ਺
    w 5SBWFSTFUSBWFSTF

    &4-JOUͷMJCVUJMUSBWFSTFKT

    w ੩తݕࠪϧʔϧ
    w SVMFTOPFNQUZGVODUJPO

    &4-JOUͷMJCSVMFTOPFNQUZGVODUJPOKT

    View Slide

  239. ͜Ε·Ͱͷ஌ࣝʹΑͬͯ

    ࡞ΕΔΑ͏ʹͳΔ΋ͷ
    కΊ͘͘Γʹ

    View Slide

  240. ෳ਺ͷݕࠪϧʔϧʹΑΔ੩తݕࠪ
    https://github.com/Kuniwak/Vint

    View Slide

  241. $44ͷந৅ߏจ໦Λൺֱ͢Δπʔϧ
    https://github.com/mixi-inc/css-semdiff
    $ css-astdiff a.css b.css --verbose
    extra:
    .extra-1 {
    border: none;
    }
    missing:
    .missing-1 {
    border: none;
    }
    ---------------------------------
    1 extra rules and 1 missing rules

    View Slide

  242. ؆қతͳߏจղੳͰґଘؔ܎σʔλϕʔεΛ࡞੒
    https://twitter.com/orga_chem/status/674847225684475905

    View Slide

  243. ·ͱΊ
    ੩తղੳΛߏ੒͢Δجຊతͳߟ͑ํΛ঺հɿ
    w ந৅ߏจ໦
    w ߏจղੳ
    w ૸ࠪؔ਺
    w ݕࠪϧʔϧͷ෼ׂ
    ੩తղੳ͸ҙ֎ͱ؆୯ʹ࣮૷Ͱ͖·͢

    View Slide

  244. ࢀߟจݙ
    ͍·Ͳ͖ͷϓϩάϥϜݴޠͷ࡞ΓํʢஶSBOEZʣ
    https://www.amazon.co.jp/dp/4839919232
    .POBEJD1BSTFS$PNCJOBUPS
    http://www.cs.nott.ac.uk/~pszgmh/monparsing.pdf
    #
    "

    View Slide