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

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

garebare
August 01, 2020

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

NEWDEBUGで話した内容です

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); })