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

「Go言語でつくるインタプリタ」を Rust で移植してみた / "Write An Interpreter In Go" In Rust

「Go言語でつくるインタプリタ」を Rust で移植してみた / "Write An Interpreter In Go" In Rust

RustのLT会 Shinjuku.rs #7 @FORCIA
https://forcia.connpass.com/event/146253/

Kei Shiratsuchi

November 19, 2019
Tweet

More Decks by Kei Shiratsuchi

Other Decks in Programming

Transcript

  1. ʮGo ݴޠͰͭ͘ΔΠϯλϓϦλʯΛ

    Rust ͰҠ২ͯ͠Έͨ
    ന౔ܛ, Kei Shiratsuchi, @kei_s
    RustͷLTձ Shinjuku.rs #7, 2019.11.19(Tue)

    View full-size slide

  2. ࣗݾ঺հ
    • ന౔ɹܛʢγϥπνɹέΠʣ@kei_s
    • גࣜձࣾϨτϦό
    • ࣗવݴޠॲཧɺԻ੠ೝࣝɺػցֶश
    • ੢৽॓
    • ʮձࣾର߅ͷͲࣗຫେձʯͰ༗໊ͳ৽॓ࡾҪϏϧ
    • Ruby on Rails / JavaScript / Python / Elixir
    • Rust ͸ࠓճॳΊͯ৮ͬͨʢͷͰɺποίϛ׻ܴ…ʣ

    View full-size slide

  3. ϨτϦόηϛφʔ
    • ฐࣾͰ݄Ұճ։࠵͍ͯ͠Δࣾ֎ެ
    ։ηϛφʔ
    • ൃදΛ YouTube Ͱ࿥ը഑৴
    • ࠓճͷ࿩Λ1͔͚࣌ؒͯઆ໌͍ͯ͠
    ΔͷͰɺڵຯ͕͋Ε͹ͪ͜Β΋Ͳ
    ͏ͧ
    • https://www.youtube.com/watch?v=zdq1lUo7b-I

    View full-size slide

  4. ֓ཁ
    • ʰGo ݴޠͰ࡞ΔΠϯλϓϦλʱ
    • https://www.oreilly.co.jp/books/9784873118222/
    • ΛɺRust Ͱ࠶ݱ͢Δ
    • https://github.com/kei-s/waiir
    • Write An Interpreter In Rust
    • ຊฤɺ෇࿥(ϚΫϩγεςϜ)Λ׬ྃ
    • ίϛοτίϝϯτʹ೔هΛॻ͍ͨ

    View full-size slide

  5. Go ݴޠͰͭ͘ΔΠϯλϓϦλ

    View full-size slide

  6. Go ݴޠͰͭ͘ΔΠϯλϓϦλ
    • ΦϦδφϧͷϓϩάϥϛϯάݴޠͷΠϯλϓϦλΛɺGo ͰΠν͔
    Βͭ͘Δ
    • ֎෦ϥΠϒϥϦΛ࢖༻͠ͳ͍
    • ϓϩάϥϜʢจࣈྻʣ →

    → ࣈ۟ղੳ →ʢτʔΫϯྻʣ→

    → ߏจղੳ →ʢந৅ߏจ໦ʣ→

    → ධՁ →ʢ࣮ߦ݁Ռʣ

    View full-size slide

  7. ࠓճ࡞Δݴޠ “Monkey”
    • Cݴޠ෩ͷߏจ
    • ม਺ଋറ
    • ੔਺ͱਅِ஋
    • ࢉज़ࣜ
    • จࣈྻσʔλܕ
    • ഑ྻσʔλܕ
    • ϋογϡσʔλܕ
    • ؔ਺

    let age = 1;
    let name = "Monkey";
    let result = 10 * (20 / 2);
    let myArray = [1, 2, 3, 4, 5];
    let myHash = {"name": ”Hi", "age": 28};
    myArray[0] // => 1
    myHash["name"] // => ”Hi"
    let add = fn(a, b) { return a + b; };
    let add = fn(a, b) { a + b; };
    add(1, 2);

    View full-size slide

  8. ࠓճ࡞Δݴޠ “Monkey”
    let twice = fn(f, x) { return f(f(x)); };
    let addTwo = fn(x) { return x + 2; };
    twice(addTwo, 2); // => 6
    let fibonacci = fn(x) {
    if (x == 0) {
    0
    } else {
    if (x == 1) {
    1
    } else {
    fibonacci(x - 1) + fibonacci(x - 2);
    }
    }
    };
    • Ϋϩʔδϟ
    • ؔ਺ͷ࠶ؼݺͼग़͠
    • ୈҰڃͷߴ֊ؔ਺

    View full-size slide

  9. σϞ
    • cargo build --release ͯ͠ target/release/waiir Ͱ REPL ىಈ
    • ΋͘͠͸ cargo run
    • ෳ਺ߦΛड͚෇͚ΒΕͳ͍ͷͰ஫ҙ

    View full-size slide

  10. Go ͔Β Rust ΁

    View full-size slide

  11. Go ͔Β Rust ΁
    • ͠ΜͲ͔ͬͨͱ͜Ζ
    2. nil Λฦͤͳ͍
    3. ΠϯλʔϑΣʔε͔Β࣮ମΛऔΕͳ͍
    4. ؀ڥͷॴ༗ݖ

    View full-size slide

  12. nil Λฦͤͳ͍
    • ະ࣮૷ͷτʔΫϯͷॲཧ
    Ͱ nil Λฦͯ͠αϘΕͳ͍
    • Result ͰΤϥʔΛฦ͢
    func (p *Parser) parseStatement() ast.Statement {
    switch p.curToken.Type {
    case token.LET:
    return p.parseLetStatement()
    default:
    return nil
    }
    }
    fn parse_statement(&mut self, cur_token: Token) -> Result {
    Ok(
    match cur_token.t {
    TokenType::Let => Statement::LetStatement(self.parse_let_statement()?),
    _ => return Err(ParseError{message: String::from("not implemented")})
    }
    )
    }

    View full-size slide

  13. ΠϯλʔϑΣʔε͔Β࣮ମΛऔΕͳ͍
    • Go Ͱ͸ΠϯλʔϑΣʔε͔Β࣮ମΛऔΕΔ
    • ast.Expression ͱͯ͠౉͖ͬͯͨ exp Λɺast.Boolean Ͱ͋Δ͔
    νΣοΫ͍ͯ͠Δ
    • Rust ͷ trait Ͱ͸ෆՄೳ
    func testBooleanLiteral(t *testing.T, exp ast.Expression, value bool) bool {
    bo, ok := exp.(*ast.Boolean)
    if !ok {
    t.Errorf("exp not *ast.Boolean. got=%T", exp)
    return false
    }

    View full-size slide

  14. ΠϯλʔϑΣʔε͔Β࣮ମΛऔΕͳ͍
    • Enum ͷྻڍࢠʹ࣮ࡍͷσʔλΛ֨ೲ͠ɺύλʔϯϚο
    νͰ࣮ମΛ࢖͏
    enum Expression {
    Integer(IntegerExpression),
    Boolean(BooleanExpression),
    ...
    }
    #[test]
    fn test_boolean_expressions() {
    ...
    if let Expression::Boolean(boolean) = &stmt.expression {
    assert_eq!(boolean.value, *expected);
    } else {
    assert!(false, "program.statements[0] is not ast::BooleanExpression")
    }

    View full-size slide

  15. ؀ڥͷॴ༗ݖ
    • let a = 1; Λอଘ͢ΔͨΊʹɺΩʔ ”a”ɺ஋ Integer(1) ͱͯ͠อଘ͢Δ
    • ஋Λଋറ͢ΔͨΊͷɺ؀ڥ(Environment)ɻத਎͸ϋογϡϚοϓ
    type Environment struct {
    store map[string]Object
    }
    func (e *Environment) Get(name string) (Object, bool) {
    obj, ok := e.store[name]
    return obj, ok
    }
    func (e *Environment) Set(name string, val Object) Object {
    e.store[name] = val
    return val
    }

    View full-size slide

  16. ؀ڥͷॴ༗ݖ
    • ؔ਺͕ఆٛ͞ΕͨΒɺ؀ڥΛؔ਺ΦϒδΣΫτʹ౉͠
    ͓ͯ͘
    • ࣮ߦ࣌ʹɺͦͷ؀ڥΛݩʹ࣮ߦ͢Δ
    func Eval(node ast.Node, env *object.Environment) object.Object {
    ...
    case *ast.FunctionLiteral:
    params := node.Parameters
    body := node.Body
    return &object.Function{Parameters: params, Env: env, Body: body}

    View full-size slide

  17. ؀ڥͷॴ༗ݖ
    • Rust ൛Ͱ͸࠷ॳɺؔ਺ΦϒδΣΫτ͕࣋ͭ env ͸ clone() ͯ͠౉͍ͯͨ͠
    • ͔͠͠࠶ؼؔ਺ͰΤϥʔ
    • ؔ਺ΦϒδΣΫτ͕࣋ͭ env ʹɺޙ͔Β { “fibonacci”: ؔ਺ΦϒδΣΫτ} Λొ
    ࿥͠ͳ͍ͱ͍͚ͳ͍ͨΊ
    impl_eval!(FunctionLiteral => (self, env) {
    Object::Function(Function {
    parameters: self.parameters.clone(),
    body: *self.body.clone(),
    env: env.clone(),
    })
    });
    let fibonacci = fn(x) {
    ...
    fibonacci(x - 1) + fibonacci(x - 2);
    };

    View full-size slide

  18. ؀ڥͷॴ༗ݖ
    • Rc/RefCell Λ࢖ͬͯղܾ͠
    ͨ
    • ಉҰͷ env Λผʑʹॴ
    ༗ͤ͞ΔͨΊʹ Rc Λ࢖
    ͏
    • Env ΛมߋͰ͖ΔΑ͏
    ʹ RefCell Λ࢖͏
    impl Environment {
    pub fn new() -> Rc> {
    let store = HashMap::new();
    let env = Environment { store, outer: None };
    Rc::new(RefCell::new(env))
    }
    }
    impl_eval!(FunctionLiteral => (self, env) {
    Object::Function(Function {
    parameters: self.parameters.clone(),
    body: *self.body.clone(),
    env: Rc::clone(&env),
    })
    });

    View full-size slide

  19. ·ͱΊ
    • Go Ͱ؆୯ʹͰ͖͍ͯͨͱ͜Ζ͕ Rust ͩͱϋϚΔ
    • ͱͯ΋Α͍ Rust ͷษڧʹͳͬͨʂ
    • ίϯύΠϧΤϥʔʹಋ͔ΕͯίʔσΟϯά͢Δײ͡

    View full-size slide

  20. ࠓޙ
    • ஌ࣝෆ଍ͷͨΊɺແବʹ clone() ͯ͠ޡຐԽ͍ͯ͠ΔՕॴ͕͍ͭ͘
    ΋͋Δ…
    • ΍ͬͺΓϥΠϑλΠϜཧղ͠੾Ε͍ͯͳ͍
    • HashMap ʹొ࿥ͨ͠ value ͷॴ༗ݖ೉͍͠
    • ొ࿥ͨ͠ value Λͦͷ··มߋ͍ͨ͠৔߹Ͳ͏͢Ε͹ྑ͍…?
    • Rust తʹ៉ྷʹ͢ΔͱɺGo ͰͷΞʔΩςΫνϟ͔Β͔ͳΓဃ཭
    ͦ͠͏…

    View full-size slide