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

Rustで自作言語のインタプリタ作って Webで動くようにした話

Avatar for garebare garebare
August 01, 2020

Rustで自作言語のインタプリタ作って Webで動くようにした話

NEWDEBUGで話した内容です

Avatar for garebare

garebare

August 01, 2020
Tweet

More Decks by garebare

Other Decks in Programming

Transcript

  1. 抽象構文木 まず木構造の根幹を定義し、要 素になる構造体の定義 配列には一つの型しか入らない ので列挙型も定義 #[derive(Debug, Clone)] pub enum Types

    { Number(NumberAST), Variable(VariableAST), } #[derive(Debug)] pub struct RootAST { pub node: Vec<Types>, } #[derive(Debug, Clone)] pub struct NumberAST { pub val: i64, pub node: Vec<Types>, } pub struct VariableAST{ pub name: String, pub node: Vec<Types>, }
  2. 抽象構文木 let a = 1; を字句解析したものから このような木を作ります 解析した要素をどんどん RootAST に放り込む

    これをいろんな構文や文字列な どに対応させる RootAST { node:[VariableAST (name:”a”, node:[NumberAST {val:1, node[] })] }
  3. 変数の保存 変数だった場合は構文木をそのま ま配列に保存しちゃう その配列から使うもの取得するよう にする match { asts::Types::Variable(var) => {

    let var_contents = vec_variable.variable(var, vec_function); let mut var_ast = asts::VariableAST::new(&var.name); if !var.muttable { var_ast.muttable = false; } match var_contents { Some(content) => { var_ast.node.push(content); vec_variable.push(asts::Types::Variable(var_ast)); } None => {} } }
  4. 変数の中身を取り出す 総当りして中に入ってる構文木を返す 変数のスコープを考えて変数が入っている 配列をリバース 関数も同じ感じの処理をしている 総当りなので改善したい for vars in var_vec

    { for var in vars { let mut in_var = asts::VariableAST::new(""); match var { asts::Types::Variable(in_vars) => { in_var = in_vars; is_mutable = in_var.muttable; } _ => { let err = error::Error::new(&var); err.exit("This is not a variable"); } } . . . } }
  5. package.json { "author": "You <[email protected]>", "name": "rust-webpack-template", "version": "0.1.0", "scripts":

    { "devbuild": "webpack", "devstart": "webpack-dev-server --open -d", "start": "node ./js/server.js", "test": "cargo test && wasm-pack test --headless" }, "devDependencies": { "@wasm-tool/wasm-pack-plugin": "^1.1.0", "copy-webpack-plugin": "^5.0.3", "webpack": "^4.42.0", "webpack-cli": "^3.3.3", "webpack-dev-server": "^3.7.1", "rimraf": "^3.0.0" } }
  6. webpack.config.js const path = require("path"); const CopyPlugin = require("copy-webpack-plugin"); const

    WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin"); module.exports = { mode: "production", entry: { index: "./js/index.js" }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name].js" }, devServer: { contentBase: path.resolve(__dirname, "./dist"), }, plugins: [ new CopyPlugin([ path.resolve(__dirname, "static") ]), new WasmPackPlugin({ crateDirectory: __dirname, }), ]
  7. lib.rs #[wasm_bindgen] を付けるとエ クスポートできる #[wasm_bindgen] pub fn run(string:&str) { output_result("Run......\n");

    let mut lexer = lexer::lexers::Lexer::new(string); let tokens = lexer.start(); let mut pars = ast::parsing::Parsing::new(&tokens); let result = parse.parsing(); interpreter::interpreters::run(result); output_result("\n......Done"); }
  8. index.js wasm は pkg に出力される コールバックから使える const wasm = import("../pkg/index.js");

    document.getElementById("run").onclick = function () { document.getElementById("result").textContent = ""; wasm.then(mod => { try { let code = document.getElementById("code").value; mod.run(code); } catch (error) { document.getElementById("result").textContent = "Error!" console.log(error); } }); }
  9. server.js MINE Type に wasm を追加しない と実行することができない const express =

    require('express'); const path = require('path'); express.static.mime.define({'application/wasm': ['wasm']}); var app = express(); app.use('/', express.static(path.resolve(__dirname, "../dist"))); app.listen(process.env.PORT, function () { console.log('Example app listening on port' + process.env.PORT); })