[RUST/WASM-BINDGEN] 미니 언어를 실행하는 웹 어셈블리 만들기
■ 미니 언어를 실행하는 웹 어셈블리를 만드는 방법을 보여준다. ▶ Cargo.toml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[package] name = "test_library" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib", "rlib"] [dependencies] peg = "0.7" wasm-bindgen = "0.2" |
▶ src/node.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#[derive(Debug, Clone)] pub enum Node { Nop, Number(i64), // 숫자 값 Expression(char, Box<Node>, Box<Node>), // 계산식 If(Box<Node>, Box<Vec<Node>>, Box<Vec<Node>>), // if문 For(String, i64, i64, Box<Vec<Node>>), // for문 Print(Box<Node>), // print문(계산 출력) PrintString(String), // print문(문자열 출력) SetVariable(String, Box<Node>), // 변수 대입 GetVariable(String) // 변수 참조 } impl Node { pub fn expression(operator : char, left_value : Node, right_value : Node) -> Node { return Node::Expression(operator, Box::new(left_value), Box::new(right_value)); } pub fn if_(condition_node : Node, true_node_vector : Vec<Node>, false_node_vector : Vec<Node>) -> Node { return Node::If(Box::new(condition_node), Box::new(true_node_vector), Box::new(false_node_vector)); } } |
▶ src/parser.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
use peg; use crate::node; peg::parser! ( pub grammar custom_language() for str { pub rule parse() -> Vec<node::Node> = value : sentences() rule sentences() -> Vec<node::Node> = sentence() ** end_of_line() rule sentence() -> node::Node = print() / if() / for() / let() / _ { node::Node::Nop } rule print() -> node::Node = "print" _ "\"" value : $([^ '"']*) "\"" { node::Node::PrintString(value.to_string()) } / "print" _ value : calc() { node::Node::Print(Box::new(value)) } rule if() -> node::Node = "if" _ value : if_cond() { value } rule if_cond() -> node::Node = if_elif() / if_else() / if_true_only() rule if_elif() -> node::Node = condition_node : calc() true_node_vector : block() lf() "elif" _ false_node_vector : if_cond() { node::Node::if_(condition_node, true_node_vector, vec![false_node_vector]) } rule if_else() -> node::Node = condition_node : calc() true_node_vector : block() lf() "else" _ false_node_vector : block() { node::Node::if_(condition_node, true_node_vector, false_node_vector) } rule if_true_only() -> node::Node = condition_node : calc() true_node_vector : block() { node::Node::if_(condition_node, true_node_vector, vec![]) } rule block() -> Vec<node::Node> = "{" _ value : sentences() _ "}" _ { value } rule for() -> node::Node = "for" _ variable_name : word() _ "=" _ start : number() _ "to" _ end : number() _ body : block() { node::Node::For(variable_name, start, end, Box::new(body)) } rule let() -> node::Node = variable_name : word() _ "=" _ value : calc() { node::Node::SetVariable(variable_name, Box::new(value))} rule calc() -> node::Node = comp() rule comp() -> node::Node = left : expr() "==" _ right : comp() { node::Node::expression('=', left, right) } / left : expr() "!=" _ right : comp() { node::Node::expression('!', left, right) } / left : expr() ">" _ right : comp() { node::Node::expression('>', left, right) } / left : expr() ">=" _ right : comp() { node::Node::expression('g', left, right) } / left : expr() "<" _ right : comp() { node::Node::expression('<', left, right) } / left : expr() "<=" _ right : comp() { node::Node::expression('l', left, right) } / expr() rule expr() -> node::Node = left : term() "+" _ right : calc() { node::Node::expression('+', left, right) } / left : term() "-" _ right : calc() { node::Node::expression('-', left, right) } / term() rule term() -> node::Node = left : val() "*" _ right : term() { node::Node::expression('*', left, right) } / left : val() "/" _ right : term() { node::Node::expression('/', left, right) } / left : val() "%" _ right : term() { node::Node::expression('%', left, right) } / val() rule val() -> node::Node = "(" _ value : calc() _ ")" _ { value } / value : number() _ { node::Node::Number(value) } / value : word() _ { node::Node::GetVariable(value) } rule number() -> i64 = value : $(['0'..='9']+) { value.parse().unwrap() } rule word() -> String = value : $(['a'..='z'|'A'..='Z'|'_']+ ['0'..='9']*) { String::from(value) } rule end_of_line() = [';' | '\n']+ _ // 문장 나누기 rule lf() = _ ['\n']* _ // 줄바꿈 rule _ = [' ' | '\t']* // 공백문자 } ); |
▶ src/runner.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
use std::collections; use crate::node; use crate::parser; struct Context { variable_hashmap : collections::HashMap<String, i64>, output : String } fn run_node(context : &mut Context, node : node::Node) -> i64 { match node { node::Node::Number(value) => value, node::Node::Expression(operator, left_value, right_value) => { return calculate(operator, run_node(context, *left_value), run_node(context, *right_value)); }, node::Node::GetVariable(variable_name) => { return match context.variable_hashmap.get(&variable_name) { Some(value) => *value, None => 0 }; }, node::Node::SetVariable(variable_name, node) => { let value : i64 = run_node(context, *node); context.variable_hashmap.insert(variable_name, value); return value; }, node::Node::If(condition_node_box, true_node_vector_box, false_node_vector_box) => { let result : i64 = run_node(context, *condition_node_box); if result > 0 { return run_nodes(context, &*true_node_vector_box); } else { return run_nodes(context, &*false_node_vector_box); } }, node::Node::For(control_variable_name, start_value, end_value, body_node_vector_box) => { let mut result : i64 = 0; let node_vector : Vec<node::Node> = *body_node_vector_box; for i in start_value..=end_value { context.variable_hashmap.insert(control_variable_name.clone(), i); result = run_nodes(context, &node_vector); } return result; }, node::Node::PrintString(value) => { context.output += &format!("{}\n", value); return 0; }, node::Node::Print(node_box) => { let value : i64 = run_node(context, *node_box); context.output += &format!("{}\n", value); return value; }, _ => 0 } } fn calculate(operator : char, left_value : i64, right_value : i64) -> i64 { return match operator { '+' => left_value + right_value, '-' => left_value - right_value, '*' => left_value * right_value, '/' => left_value / right_value, '%' => left_value % right_value, '=' => if left_value == right_value {1} else {0}, '!' => if left_value != right_value {1} else {0}, '>' => if left_value > right_value {1} else {0}, 'g' => if left_value >= right_value {1} else {0}, '<' => if left_value < right_value {1} else {0}, 'l' => if left_value <= right_value {1} else {0}, _ => 0 }; } fn run_nodes(context : &mut Context, node_vector : &Vec<node::Node>) -> i64 { let mut result : i64 = 0; node_vector.iter().for_each(|node : &node::Node| { result = run_node(context, node.clone()); }); return result; } pub fn run(source : &str) -> String { let node_vector : Vec<node::Node> = match parser::custom_language::parse(source) { Ok(res) => res, Err(e) => return e.to_string() }; let mut context : Context = Context { variable_hashmap : collections::HashMap::new(), output : String::new() }; let result = run_nodes(&mut context, &node_vector); if context.output == "" { return format!("{}", result); } else { return context.output.clone(); } } |
▶