├── .gitignore ├── example.he ├── src ├── ir.rs ├── helang.pest ├── main.rs ├── parser.rs └── interpreter.rs ├── Cargo.toml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /example.he: -------------------------------------------------------------------------------- 1 | u8 a = 1 | 2 | 3 2 | a[0] = 1 3 | a 4 | 5 | u8 forceCon = [68] 6 | 7 | forceCon[1 | 2 | 6 | 7 | 11 | 52 | 57 | 58 | 65] = 10 8 | 9 | print forceCon 10 | 11 | test5g 12 | -------------------------------------------------------------------------------- /src/ir.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub enum Literal { 3 | Number(i64), 4 | Array(Vec), 5 | } 6 | 7 | #[derive(Debug)] 8 | pub struct Ident(pub String); 9 | 10 | #[derive(Debug)] 11 | pub enum Expr { 12 | Lit(Literal), 13 | Index(Ident, Literal), 14 | Ident(Ident), 15 | } 16 | 17 | #[derive(Debug)] 18 | pub enum Stmt { 19 | Decl(Ident, Literal), 20 | Assign(Expr, Literal), 21 | Print(Expr), 22 | Test5G, 23 | } 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "helang" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0.62" 10 | clap = { version = "3.2.17", features = ["derive"] } 11 | pest = "2.2.1" 12 | pest_derive = "2.2.1" 13 | 14 | # inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm12-0"] } 15 | # salsa = { git = "https://github.com/salsa-rs/salsa.git", package = "salsa-2022" } 16 | 17 | [dev-dependencies] 18 | expect-test = "1.4.0" 19 | -------------------------------------------------------------------------------- /src/helang.pest: -------------------------------------------------------------------------------- 1 | program = _{ SOI ~ "\n"* ~ (stmt ~ "\n"+) * ~ stmt? ~ EOI } 2 | stmt = _{ declStmt | assignStmt | printStmt | test5gStmt | exprStmt } 3 | 4 | declStmt = { "u8" ~ ident ~ ("=" ~ literal)? } 5 | assignStmt = { expr ~ "=" ~ literal } 6 | printStmt = { "print" ~ expr } 7 | exprStmt = { expr } 8 | test5gStmt = { "test5g" } 9 | 10 | expr = _{ literal | indexExpr | ident } 11 | indexExpr = { ident ~ "[" ~ literal ~ "]" } 12 | 13 | literal = _{ array | number | arrayByLength } 14 | number = @{ ASCII_DIGIT+ } 15 | array = { number ~ ("|" ~ number)+ } 16 | arrayByLength = { "[" ~ number ~ "]" } 17 | ident = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* } 18 | 19 | WHITESPACE = _{ " " | "\t" } 20 | COMMENT = _{ "//" ~ (!"\n" ~ ANY)* } 21 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | use anyhow::Result; 4 | use clap::Parser; 5 | 6 | mod interpreter; 7 | mod ir; 8 | mod parser; 9 | 10 | #[derive(Parser, Debug)] 11 | #[clap(author, version, about, long_about = None)] 12 | struct Args { 13 | #[clap(value_parser)] 14 | source_file: Option, 15 | } 16 | 17 | fn main() -> Result<()> { 18 | let args = Args::parse(); 19 | let mut interpreter = interpreter::Interpreter::new(); 20 | if let Some(source_file) = args.source_file { 21 | let source = std::fs::read_to_string(source_file)?; 22 | let stmts = parser::parse(&source)?; 23 | interpreter.eval(stmts)?; 24 | } else { 25 | loop { 26 | let mut source = String::new(); 27 | write!(std::io::stdout(), "helang> ")?; 28 | std::io::stdout().flush()?; 29 | std::io::stdin().read_line(&mut source)?; 30 | match respond(&source, &mut interpreter) { 31 | Ok(()) => (), 32 | Err(e) => println!("{}", e), 33 | } 34 | } 35 | } 36 | Ok(()) 37 | } 38 | 39 | fn respond(source: &str, interpreter: &mut interpreter::Interpreter) -> Result<()> { 40 | let stmts = parser::parse(source)?; 41 | interpreter.eval(stmts)?; 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # helang-rs 2 | 3 | > Have you considered rEwRiTiNg iT iN rUsT? 4 | 5 | ## 介绍 6 | 7 | - 众所周知,一切漏洞都是**内存安全**问题。 8 | - "**~70%** of the vulnerabilities addressed through a security update each year continue to be memory safety issues." - [Microsoft Security Response Center](https://github.com/Microsoft/MSRC-Security-Research/blob/master/presentations/2019_02_BlueHatIL/2019_01%20-%20BlueHatIL%20-%20Trends%2C%20challenge%2C%20and%20shifts%20in%20software%20vulnerability%20mitigation.pdf) 9 | - 没有一个 C 语言项目实现了完全的内存安全。 10 | - 要不是 GCC 不努力,何同学又怎么会发现不了数组越界呢? 11 | - 使用 Rust 重写,你就可以自动获得 **✨100%✨** 的内存安全。 12 | - 如果一段程序可以被 Rust 重写,那它就一定会被 Rust 重写。 13 | 14 | ## 使用例 15 | 16 | 不加任何参数,你就可以与何同学直接对话: 17 | 18 | ```bash 19 | cargo run 20 | ``` 21 | 22 | ```helang 23 | helang> u8 forceCon = [68] 24 | helang> forceCon 25 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 26 | helang> forceCon[1 | 2 | 6 | 7 | 11 | 52 | 57 | 58 | 65] = 10 27 | helang> print forceCon 28 | 10 | 10 | 0 | 0 | 0 | 10 | 10 | 0 | 0 | 0 | 10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 10 | 0 | 0 | 0 | 0 | 10 | 10 | 0 | 0 | 0 | 0 | 0 | 0 | 10 | 0 | 0 | 0 29 | helang> forceCon[127] 30 | index 127 out of bounds 68 // 极为先进的内存安全检测 31 | helang> test5g 32 | 很残念,你的电脑并没有配备 5G 芯片。 33 | helang> 34 | ``` 35 | 36 | 或者,你可以指定源文件: 37 | 38 | ```bash 39 | cargo run example.he 40 | ``` 41 | 42 | > 我们保证,在开发过程中,没有一个野指针受到伤害。 43 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{bail, Result}; 2 | use pest::iterators::Pair; 3 | use pest::Parser; 4 | use pest_derive::Parser; 5 | 6 | use crate::ir::*; 7 | 8 | #[derive(Parser)] 9 | #[grammar = "helang.pest"] 10 | struct HelangParser; 11 | 12 | pub fn parse(source: &str) -> Result> { 13 | let pairs = HelangParser::parse(Rule::program, source)?; 14 | let mut stmts = vec![]; 15 | for pair in pairs { 16 | match pair.as_rule() { 17 | Rule::declStmt => { 18 | let stmt = parse_decl_stmt(pair)?; 19 | stmts.push(stmt); 20 | } 21 | Rule::assignStmt => { 22 | let stmt = parse_assign_stmt(pair)?; 23 | stmts.push(stmt); 24 | } 25 | Rule::printStmt => { 26 | let stmt = parse_print_stmt(pair)?; 27 | stmts.push(stmt); 28 | } 29 | Rule::exprStmt => { 30 | let stmt = parse_expr_stmt(pair)?; 31 | stmts.push(stmt); 32 | } 33 | Rule::test5gStmt => { 34 | stmts.push(Stmt::Test5G); 35 | } 36 | _ => (), 37 | } 38 | } 39 | Ok(stmts) 40 | } 41 | 42 | fn parse_decl_stmt(pair: Pair) -> Result { 43 | let mut iter = pair.into_inner(); 44 | let ident = iter.next().unwrap(); 45 | let ident = parse_ident(ident)?; 46 | let literal = iter.next().unwrap(); 47 | let literal = parse_literal(literal)?; 48 | 49 | Ok(Stmt::Decl(ident, literal)) 50 | } 51 | 52 | fn parse_assign_stmt(pair: Pair) -> Result { 53 | let mut iter = pair.into_inner(); 54 | let expr = iter.next().unwrap(); 55 | let expr = parse_expr(expr)?; 56 | let literal = iter.next().unwrap(); 57 | let literal = parse_literal(literal)?; 58 | Ok(Stmt::Assign(expr, literal)) 59 | } 60 | 61 | fn parse_print_stmt(pair: Pair) -> Result { 62 | let mut iter = pair.into_inner(); 63 | let expr = iter.next().unwrap(); 64 | let expr = parse_expr(expr)?; 65 | Ok(Stmt::Print(expr)) 66 | } 67 | 68 | fn parse_expr_stmt(pair: Pair) -> Result { 69 | let mut iter = pair.into_inner(); 70 | let expr = iter.next().unwrap(); 71 | let expr = parse_expr(expr)?; 72 | Ok(Stmt::Print(expr)) 73 | } 74 | 75 | fn parse_expr(pair: Pair) -> Result { 76 | match pair.as_rule() { 77 | Rule::ident => { 78 | let ident = parse_ident(pair)?; 79 | Ok(Expr::Ident(ident)) 80 | } 81 | Rule::indexExpr => { 82 | let mut iter = pair.into_inner(); 83 | let ident = iter.next().unwrap(); 84 | let ident = parse_ident(ident)?; 85 | let literal = iter.next().unwrap(); 86 | let literal = parse_literal(literal)?; 87 | Ok(Expr::Index(ident, literal)) 88 | } 89 | Rule::number | Rule::array | Rule::arrayByLength => { 90 | let literal = parse_literal(pair)?; 91 | Ok(Expr::Lit(literal)) 92 | } 93 | _ => bail!("unexpected expr: {:?}", pair.as_str()), 94 | } 95 | } 96 | 97 | fn parse_ident(pair: Pair) -> Result { 98 | if let Rule::ident = pair.as_rule() { 99 | let text = pair.as_str(); 100 | Ok(Ident(text.to_string())) 101 | } else { 102 | bail!("expected ident") 103 | } 104 | } 105 | 106 | fn parse_literal(pair: Pair) -> Result { 107 | match pair.as_rule() { 108 | Rule::number => { 109 | let text = pair.as_str(); 110 | let number = text.parse::()?; 111 | Ok(Literal::Number(number)) 112 | } 113 | Rule::array => { 114 | let mut iter = pair.into_inner(); 115 | let mut array = Vec::new(); 116 | while let Some(pair) = iter.next() { 117 | let text = pair.as_str(); 118 | let number = text.parse::()?; 119 | array.push(number); 120 | } 121 | Ok(Literal::Array(array)) 122 | } 123 | Rule::arrayByLength => { 124 | let mut iter = pair.into_inner(); 125 | let length = iter.next().unwrap().as_str().parse::()?; 126 | Ok(Literal::Array(vec![0; length as usize])) 127 | } 128 | _ => bail!("expected literal"), 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/interpreter.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt; 3 | 4 | use anyhow::{anyhow, bail, Result}; 5 | 6 | use crate::ir::*; 7 | 8 | pub struct Interpreter { 9 | globals: HashMap, 10 | } 11 | 12 | #[derive(Debug, Clone)] 13 | enum Value { 14 | Number(i64), 15 | Array(Vec), 16 | } 17 | 18 | impl fmt::Display for Value { 19 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { 20 | match self { 21 | Value::Number(n) => write!(f, "{}", n), 22 | Value::Array(a) => { 23 | for (i, v) in a.iter().enumerate() { 24 | if i > 0 { 25 | write!(f, " | ")?; 26 | } 27 | write!(f, "{}", v)?; 28 | } 29 | Ok(()) 30 | } 31 | } 32 | } 33 | } 34 | 35 | #[derive(Debug, Clone)] 36 | enum VarRef { 37 | Ident(String), 38 | Index(String, usize), 39 | Slice(String, Vec), 40 | } 41 | 42 | impl Interpreter { 43 | pub fn new() -> Self { 44 | Self { 45 | globals: HashMap::new(), 46 | } 47 | } 48 | 49 | pub fn eval(&mut self, stmts: Vec) -> Result<()> { 50 | for stmt in stmts { 51 | self.eval_stmt(stmt)?; 52 | } 53 | Ok(()) 54 | } 55 | 56 | pub fn eval_stmt(&mut self, stmt: Stmt) -> Result<()> { 57 | match stmt { 58 | Stmt::Decl(ident, literal) => { 59 | let value = self.eval_literal(literal)?; 60 | self.globals.insert(ident.0.clone(), value); 61 | } 62 | Stmt::Assign(assignee, literal) => { 63 | let value = self.eval_literal(literal)?; 64 | match assignee { 65 | Expr::Index(ident, index) => { 66 | let index = self.eval_literal(index)?; 67 | match (index, value) { 68 | (Value::Number(index), Value::Number(value)) => { 69 | if let Some(Value::Array(array)) = self.globals.get_mut(&ident.0) { 70 | if index == 0 { 71 | array.fill(value); 72 | } else { 73 | array 74 | .get_mut(index as usize - 1) 75 | .map(|v| *v = value) 76 | .ok_or(anyhow!( 77 | "index {} out of bounds {}", 78 | index, 79 | array.len() 80 | ))?; 81 | } 82 | } else { 83 | bail!("assigning to non-array"); 84 | } 85 | } 86 | (Value::Array(indices), Value::Number(value)) => { 87 | if let Some(Value::Array(array)) = self.globals.get_mut(&ident.0) { 88 | for index in indices { 89 | array 90 | .get_mut(index as usize - 1) 91 | .map(|v| *v = value) 92 | .ok_or(anyhow!( 93 | "index {} out of bounds {}", 94 | index, 95 | array.len() 96 | ))?; 97 | } 98 | } else { 99 | bail!("assigning to non-array"); 100 | } 101 | } 102 | _ => bail!("incompatible types"), 103 | } 104 | } 105 | Expr::Ident(ident) => { 106 | self.globals.insert(ident.0.clone(), value); 107 | } 108 | Expr::Lit(_) => bail!("cannot assign value to literal"), 109 | } 110 | } 111 | Stmt::Print(expr) => { 112 | let value = self.eval_expr(expr)?; 113 | println!("{}", value); 114 | } 115 | Stmt::Test5G => { 116 | println!("很残念,你的电脑并没有配备 5G 芯片。"); 117 | } 118 | } 119 | Ok(()) 120 | } 121 | 122 | fn eval_expr(&self, expr: Expr) -> Result { 123 | match expr { 124 | Expr::Lit(literal) => self.eval_literal(literal), 125 | Expr::Index(ident, literal) => { 126 | let var_ref = match literal { 127 | Literal::Number(index) => VarRef::Index(ident.0, index as usize), 128 | Literal::Array(indices) => VarRef::Slice( 129 | ident.0, 130 | indices.into_iter().map(|index| index as usize).collect(), 131 | ), 132 | }; 133 | self.eval_var_ref(var_ref) 134 | } 135 | Expr::Ident(ident) => { 136 | let var_ref = VarRef::Ident(ident.0); 137 | self.eval_var_ref(var_ref) 138 | } 139 | } 140 | } 141 | 142 | fn eval_literal(&self, literal: Literal) -> Result { 143 | match literal { 144 | Literal::Number(n) => Ok(Value::Number(n)), 145 | Literal::Array(array) => Ok(Value::Array(array)), 146 | } 147 | } 148 | 149 | fn eval_var_ref(&self, var_ref: VarRef) -> Result { 150 | let ident = match var_ref { 151 | VarRef::Ident(ref ident) => ident, 152 | VarRef::Index(ref ident, _) => ident, 153 | VarRef::Slice(ref ident, _) => ident, 154 | }; 155 | if let Some(value) = self.globals.get(ident) { 156 | match var_ref { 157 | VarRef::Ident(_) => Ok(value.clone()), 158 | VarRef::Index(_, index) => match value { 159 | Value::Array(array) => { 160 | if index == 0 { 161 | Ok(Value::Array(array.clone())) 162 | } else { 163 | Ok(Value::Number(*array.get(index - 1).ok_or(anyhow!( 164 | "index {} out of bounds {}", 165 | index, 166 | array.len() 167 | ))?)) 168 | } 169 | } 170 | _ => bail!("indexing non-array"), 171 | }, 172 | VarRef::Slice(_, indices) => match value { 173 | Value::Array(array) => { 174 | let mut result = Vec::new(); 175 | for index in indices { 176 | result.push(*array.get(index - 1).ok_or(anyhow!( 177 | "index {} out of bounds {}", 178 | index, 179 | array.len() 180 | ))?); 181 | } 182 | Ok(Value::Array(result)) 183 | } 184 | _ => bail!("cannot slice non-array"), 185 | }, 186 | } 187 | } else { 188 | bail!("undefined variable: {}", ident) 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.62" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305" 10 | 11 | [[package]] 12 | name = "atty" 13 | version = "0.2.14" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 16 | dependencies = [ 17 | "hermit-abi", 18 | "libc", 19 | "winapi", 20 | ] 21 | 22 | [[package]] 23 | name = "autocfg" 24 | version = "1.1.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 27 | 28 | [[package]] 29 | name = "bitflags" 30 | version = "1.3.2" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 33 | 34 | [[package]] 35 | name = "block-buffer" 36 | version = "0.10.2" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 39 | dependencies = [ 40 | "generic-array", 41 | ] 42 | 43 | [[package]] 44 | name = "cfg-if" 45 | version = "1.0.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 48 | 49 | [[package]] 50 | name = "clap" 51 | version = "3.2.17" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "29e724a68d9319343bb3328c9cc2dfde263f4b3142ee1059a9980580171c954b" 54 | dependencies = [ 55 | "atty", 56 | "bitflags", 57 | "clap_derive", 58 | "clap_lex", 59 | "indexmap", 60 | "once_cell", 61 | "strsim", 62 | "termcolor", 63 | "textwrap", 64 | ] 65 | 66 | [[package]] 67 | name = "clap_derive" 68 | version = "3.2.17" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa" 71 | dependencies = [ 72 | "heck", 73 | "proc-macro-error", 74 | "proc-macro2", 75 | "quote", 76 | "syn", 77 | ] 78 | 79 | [[package]] 80 | name = "clap_lex" 81 | version = "0.2.4" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 84 | dependencies = [ 85 | "os_str_bytes", 86 | ] 87 | 88 | [[package]] 89 | name = "cpufeatures" 90 | version = "0.2.2" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" 93 | dependencies = [ 94 | "libc", 95 | ] 96 | 97 | [[package]] 98 | name = "crypto-common" 99 | version = "0.1.6" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 102 | dependencies = [ 103 | "generic-array", 104 | "typenum", 105 | ] 106 | 107 | [[package]] 108 | name = "digest" 109 | version = "0.10.3" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 112 | dependencies = [ 113 | "block-buffer", 114 | "crypto-common", 115 | ] 116 | 117 | [[package]] 118 | name = "dissimilar" 119 | version = "1.0.4" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5" 122 | 123 | [[package]] 124 | name = "expect-test" 125 | version = "1.4.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3" 128 | dependencies = [ 129 | "dissimilar", 130 | "once_cell", 131 | ] 132 | 133 | [[package]] 134 | name = "generic-array" 135 | version = "0.14.6" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" 138 | dependencies = [ 139 | "typenum", 140 | "version_check", 141 | ] 142 | 143 | [[package]] 144 | name = "hashbrown" 145 | version = "0.12.3" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 148 | 149 | [[package]] 150 | name = "heck" 151 | version = "0.4.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 154 | 155 | [[package]] 156 | name = "helang" 157 | version = "0.1.0" 158 | dependencies = [ 159 | "anyhow", 160 | "clap", 161 | "expect-test", 162 | "pest", 163 | "pest_derive", 164 | ] 165 | 166 | [[package]] 167 | name = "hermit-abi" 168 | version = "0.1.19" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 171 | dependencies = [ 172 | "libc", 173 | ] 174 | 175 | [[package]] 176 | name = "indexmap" 177 | version = "1.9.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 180 | dependencies = [ 181 | "autocfg", 182 | "hashbrown", 183 | ] 184 | 185 | [[package]] 186 | name = "libc" 187 | version = "0.2.132" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" 190 | 191 | [[package]] 192 | name = "once_cell" 193 | version = "1.13.1" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" 196 | 197 | [[package]] 198 | name = "os_str_bytes" 199 | version = "6.3.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" 202 | 203 | [[package]] 204 | name = "pest" 205 | version = "2.2.1" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "69486e2b8c2d2aeb9762db7b4e00b0331156393555cff467f4163ff06821eef8" 208 | dependencies = [ 209 | "thiserror", 210 | "ucd-trie", 211 | ] 212 | 213 | [[package]] 214 | name = "pest_derive" 215 | version = "2.2.1" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "b13570633aff33c6d22ce47dd566b10a3b9122c2fe9d8e7501895905be532b91" 218 | dependencies = [ 219 | "pest", 220 | "pest_generator", 221 | ] 222 | 223 | [[package]] 224 | name = "pest_generator" 225 | version = "2.2.1" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "b3c567e5702efdc79fb18859ea74c3eb36e14c43da7b8c1f098a4ed6514ec7a0" 228 | dependencies = [ 229 | "pest", 230 | "pest_meta", 231 | "proc-macro2", 232 | "quote", 233 | "syn", 234 | ] 235 | 236 | [[package]] 237 | name = "pest_meta" 238 | version = "2.2.1" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "5eb32be5ee3bbdafa8c7a18b0a8a8d962b66cfa2ceee4037f49267a50ee821fe" 241 | dependencies = [ 242 | "once_cell", 243 | "pest", 244 | "sha-1", 245 | ] 246 | 247 | [[package]] 248 | name = "proc-macro-error" 249 | version = "1.0.4" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 252 | dependencies = [ 253 | "proc-macro-error-attr", 254 | "proc-macro2", 255 | "quote", 256 | "syn", 257 | "version_check", 258 | ] 259 | 260 | [[package]] 261 | name = "proc-macro-error-attr" 262 | version = "1.0.4" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 265 | dependencies = [ 266 | "proc-macro2", 267 | "quote", 268 | "version_check", 269 | ] 270 | 271 | [[package]] 272 | name = "proc-macro2" 273 | version = "1.0.43" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" 276 | dependencies = [ 277 | "unicode-ident", 278 | ] 279 | 280 | [[package]] 281 | name = "quote" 282 | version = "1.0.21" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 285 | dependencies = [ 286 | "proc-macro2", 287 | ] 288 | 289 | [[package]] 290 | name = "sha-1" 291 | version = "0.10.0" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" 294 | dependencies = [ 295 | "cfg-if", 296 | "cpufeatures", 297 | "digest", 298 | ] 299 | 300 | [[package]] 301 | name = "strsim" 302 | version = "0.10.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 305 | 306 | [[package]] 307 | name = "syn" 308 | version = "1.0.99" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" 311 | dependencies = [ 312 | "proc-macro2", 313 | "quote", 314 | "unicode-ident", 315 | ] 316 | 317 | [[package]] 318 | name = "termcolor" 319 | version = "1.1.3" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 322 | dependencies = [ 323 | "winapi-util", 324 | ] 325 | 326 | [[package]] 327 | name = "textwrap" 328 | version = "0.15.0" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 331 | 332 | [[package]] 333 | name = "thiserror" 334 | version = "1.0.32" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" 337 | dependencies = [ 338 | "thiserror-impl", 339 | ] 340 | 341 | [[package]] 342 | name = "thiserror-impl" 343 | version = "1.0.32" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" 346 | dependencies = [ 347 | "proc-macro2", 348 | "quote", 349 | "syn", 350 | ] 351 | 352 | [[package]] 353 | name = "typenum" 354 | version = "1.15.0" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 357 | 358 | [[package]] 359 | name = "ucd-trie" 360 | version = "0.1.4" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" 363 | 364 | [[package]] 365 | name = "unicode-ident" 366 | version = "1.0.3" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" 369 | 370 | [[package]] 371 | name = "version_check" 372 | version = "0.9.4" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 375 | 376 | [[package]] 377 | name = "winapi" 378 | version = "0.3.9" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 381 | dependencies = [ 382 | "winapi-i686-pc-windows-gnu", 383 | "winapi-x86_64-pc-windows-gnu", 384 | ] 385 | 386 | [[package]] 387 | name = "winapi-i686-pc-windows-gnu" 388 | version = "0.4.0" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 391 | 392 | [[package]] 393 | name = "winapi-util" 394 | version = "0.1.5" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 397 | dependencies = [ 398 | "winapi", 399 | ] 400 | 401 | [[package]] 402 | name = "winapi-x86_64-pc-windows-gnu" 403 | version = "0.4.0" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 406 | --------------------------------------------------------------------------------