From 849f5fd294f7df3ab7c0b872286e750c1734a492 Mon Sep 17 00:00:00 2001 From: zuisong Date: Tue, 12 Dec 2023 17:50:07 +0800 Subject: [PATCH] a --- Cargo.lock | 16 +++---- Cargo.toml | 14 ++++-- src/bin/chen_lang.rs | 18 ++++---- src/compiler.rs | 94 ++++++++++++++++++++++++++++++++++++++--- src/parse.rs | 4 -- src/tests/parse_test.rs | 2 - src/token.rs | 41 +++++++++--------- src/vm/mod.rs | 2 +- src/wasm/main.rs | 8 +--- 9 files changed, 139 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f1884e..2a561a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,9 +240,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.40" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -251,18 +251,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", @@ -444,9 +444,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.28" +version = "0.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 925529a..361875c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,10 @@ description = "A tiny programming language written in rust" anyhow = "1.0.75" clap = { version = "4.4.11", optional = true, features = ["derive"] } clap_complete = { version = "4.4.4", optional = true } -thiserror = "1.0.50" -tracing = "0.1.40" +thiserror = "1.0.51" +tracing = { version = "0.1.40" } tracing-subscriber = "0.3.18" -winnow = "0.5.28" +winnow = "0.5.30" [dev-dependencies] pretty_assertions = { version = "1.4.0", features = ["unstable"] } @@ -32,3 +32,11 @@ binaries = ["dep:clap", "dep:clap_complete"] wasm = [] default = ["binaries"] + + +[profile.release] +strip = true # Automatically strip symbols from the binary. +opt-level = "z" # Optimize for size. +lto = true +codegen-units = 1 +panic = "abort" diff --git a/src/bin/chen_lang.rs b/src/bin/chen_lang.rs index 489995e..5731293 100644 --- a/src/bin/chen_lang.rs +++ b/src/bin/chen_lang.rs @@ -1,15 +1,14 @@ -extern crate clap; use std::{ fs::OpenOptions, io::{self, Read}, }; use anyhow::{Ok, Result}; +use clap::builder::{TypedValueParser, ValueParser}; use clap::{builder::PossibleValuesParser, Command, CommandFactory, Parser}; use clap_complete::{generate, Generator, Shell}; use tracing::{debug, Level}; -use crate::clap::builder::TypedValueParser; #[derive(Parser, Debug)] #[command(author, version, about, long_about)] struct Args { @@ -19,10 +18,7 @@ struct Args { #[arg(short, long)] #[arg(default_value_t = Level::INFO)] #[arg(ignore_case = true)] - #[arg(value_parser= - PossibleValuesParser::new([ "ERROR", "WARN", "INFO", "DEBUG", "TRACE"]) - .map(|s| s.parse::().unwrap()), - )] + #[clap(value_parser = level_parser())] log_level: Level, } @@ -40,15 +36,20 @@ enum SubCommand { }, } +fn level_parser() -> impl Into { + PossibleValuesParser::new(["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]) + .try_map(|s| s.parse::()) +} + fn main() -> Result<()> { let matches = Args::parse(); - tracing_subscriber::fmt() + let _ = tracing_subscriber::fmt() .with_max_level(matches.log_level) .with_line_number(true) .with_file(true) .with_thread_names(true) .with_thread_ids(true) - .init(); + .try_init(); match matches.command { None => Args::command().print_help()?, Some(command) => match command { @@ -74,6 +75,7 @@ fn run_file(code_file: String) -> Result<()> { chen_lang::run(code)?; Ok(()) } + fn print_completions(gen: G, cmd: &mut Command) { generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout()); } diff --git a/src/compiler.rs b/src/compiler.rs index 37be993..3289b03 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -189,13 +189,70 @@ fn compile_statement( Statement::If(if_) => compile_if(pgrm, raw, locals, if_), Statement::Local(loc) => compile_local(pgrm, raw, locals, loc), Statement::Expression(e) => compile_expression(pgrm, raw, locals, e), - Statement::Loop(_) => { - todo!() - } - Statement::Assign(_) => { - todo!() - } + Statement::Loop(e) => compile_loop(pgrm, raw, locals, e), + Statement::Assign(e) => compile_assign(pgrm, raw, locals, e), + } +} + +fn compile_assign( + pgrm: &mut Program, + raw: &[char], + locals: &mut HashMap, + assign: Assign, +) { + // 编译右侧表达式 + compile_expression(pgrm, raw, locals, *assign.expr); + + // 生成 Store 指令 + let offset = locals[&assign.name]; + pgrm.instructions.push(Instruction::Store(offset)); +} + +fn compile_loop(pgrm: &mut Program, raw: &[char], locals: &mut HashMap, loop_: Loop) { + // 循环开始的标签 + let loop_start = format!("loop_start_{}", pgrm.instructions.len()); + + // 循环结束的标签 + let loop_end = format!("loop_end_{}", pgrm.instructions.len()); + + // 跳转到循环开始标签 + pgrm.instructions.push(Instruction::Jump(loop_end.clone())); + + // 插入循环开始标签 + pgrm.syms.insert( + loop_start.clone(), + Symbol { + location: pgrm.instructions.len() as i32, + narguments: 0, + nlocals: 0, + }, + ); + + // 编译循环条件表达式 + compile_expression(pgrm, raw, locals, loop_.test); + + // 如果条件满足,跳转到循环开始标签 + pgrm.instructions + .push(Instruction::JumpIfNotZero(loop_end.clone())); + + // 编译循环体语句 + for stmt in loop_.body { + compile_statement(pgrm, raw, locals, stmt); } + + // 跳转回循环开始标签,形成循环 + pgrm.instructions + .push(Instruction::Jump(loop_start.clone())); + + // 插入循环结束标签 + pgrm.syms.insert( + loop_end.clone(), + Symbol { + location: pgrm.instructions.len() as i32, + narguments: 0, + nlocals: 0, + }, + ); } pub fn compile(raw: &[char], ast: Ast) -> Program { @@ -210,3 +267,28 @@ pub fn compile(raw: &[char], ast: Ast) -> Program { pgrm } + +#[cfg(test)] +mod tests { + + #[test] + fn test_compile() { + let code: String = r#" + let i = 0 + for i<100{ + + print(i ) + i = i+1 + } + "# + .to_string(); + + let res = crate::parser(crate::token::tokenlizer(code).unwrap()).unwrap(); + + let pgrm = crate::compiler::compile(&['a'], res); + + dbg!(&pgrm); + + crate::vm::eval(pgrm); + } +} diff --git a/src/parse.rs b/src/parse.rs index 58dec87..a2b410d 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -5,7 +5,6 @@ use std::collections::VecDeque; use std::vec; use anyhow::Result; -use tracing::info; use crate::parse::OperatorPriority::*; use crate::*; @@ -310,9 +309,6 @@ pub fn parse_assign(line: &[Token]) -> Result { match &line[0] { Token::Identifier(name) => { assert_eq!(&line[1], &Token::Operator(Operator::Assign)); - - info!("{}:{} {:?}", file!(), line!(), &line); - let expr: Expression = match &line[2] { Token::Identifier(_) if line.get(3) == Some(&Token::LParen) => { Expression::FunctionCall(parse_func_call(&line[2..])?) diff --git a/src/tests/parse_test.rs b/src/tests/parse_test.rs index 347a8c9..41917f4 100644 --- a/src/tests/parse_test.rs +++ b/src/tests/parse_test.rs @@ -1,5 +1,3 @@ -use std::boxed; - use crate::expression::{Assign, FunctionCall, If}; use crate::token::Operator; use crate::{ diff --git a/src/token.rs b/src/token.rs index 4c2a0e0..499123c 100644 --- a/src/token.rs +++ b/src/token.rs @@ -121,7 +121,7 @@ pub enum Token { Space, } -fn parse_with_winnow(chars: &[u8]) -> IResult<&[u8], Token> { +fn parse_with_winnow(chars: &str) -> IResult<&str, Token> { alt(( separated_pair(tag("#"), not_line_ending, line_ending).map(|_| Token::Comment), alt(( @@ -156,18 +156,16 @@ fn parse_with_winnow(chars: &[u8]) -> IResult<&[u8], Token> { delimited(tag("\""), take_until0("\""), tag("\"")), delimited(tag("\'"), take_until0("\'"), tag("\'")), )) - .map(|s: &[u8]| Token::String(String::from_utf8_lossy(s).to_string())), + .map(|s: &str| Token::String(s.to_string())), // - (opt(tag("-")), digit1).try_map(|(sig, s): (Option<&[u8]>, &[u8])| { - String::from_utf8_lossy(s) - .parse::() - .map(|i| match sig { - Some(_) => Token::Int(i * -1), - None => Token::Int(i), - }) + (opt(tag("-")), digit1).try_map(|(sig, s): (Option<&str>, &str)| { + s.parse::().map(|i| match sig { + Some(_) => Token::Int(i * -1), + None => Token::Int(i), + }) }), - alphanumeric1.map(|arr| { - let s = String::from_utf8_lossy(arr); + alphanumeric1.map(|arr: &str| { + let s = arr; let token = match s.as_ref() { "let" => Token::Keyword(Keyword::LET), "return" => Token::Keyword(Keyword::RETURN), @@ -196,19 +194,20 @@ mod tests { #[test] fn test() { - assert_matches!(parse_with_winnow(b"-1"), Ok((b"", Token::Int(-1)))); + assert_matches!(parse_with_winnow("-1"), Ok(("", Token::Int(-1)))); assert_matches!( - parse_with_winnow(b"-a"), - Ok((b"a", Token::Operator(Operator::Subtract))) + parse_with_winnow("-a"), + Ok(("a", Token::Operator(Operator::Subtract))) ); - assert_matches!(parse_with_winnow(b"10a"), Ok((b"a", Token::Int(10)))); - assert_matches!(parse_with_winnow(b"\"aaaa\""), Ok((b"", Token::String(ref a))) if a == "aaaa"); - assert_matches!(parse_with_winnow(b"\'aaaa\'"),Ok((b"", Token::String(ref a))) if a == "aaaa"); - assert_matches!(parse_with_winnow(b"\'\'"), Ok((b"", Token::String(ref a))) if a== "" ); + assert_matches!(parse_with_winnow("10a"), Ok(("a", Token::Int(10)))); + assert_matches!(parse_with_winnow("\"aaaa\""), Ok(("", Token::String(ref a))) if a == "aaaa"); + assert_matches!(parse_with_winnow("\'aaaa\'"),Ok(("", Token::String(ref a))) if a == "aaaa"); + assert_matches!(parse_with_winnow("\'\'"), Ok(("", Token::String(ref a))) if a== "" ); } } -fn parse_token(chars: &Vec, loc: &Location) -> Result<(Token, Location), TokenError> { +fn parse_token(input: &str, loc: &Location) -> Result<(Token, Location), TokenError> { + let chars: Vec = input.chars().collect(); let cur = *chars.get(loc.index).unwrap_or(&' '); let next = *chars.get(loc.index + 1).unwrap_or(&' '); let res = match cur { @@ -301,12 +300,12 @@ fn parse_token(chars: &Vec, loc: &Location) -> Result<(Token, Location), T /// 代码转成token串 pub fn tokenlizer(code: String) -> anyhow::Result> { - let mut input = code.as_bytes(); + let mut input = code.as_str(); let mut tokens = vec![]; loop { - debug!("{}", String::from_utf8_lossy(input)); + debug!("{}", (input)); let (remain_input, token) = parse_with_winnow(&input).map_err(|e| anyhow!(e.to_string()))?; if !matches!(token, Token::Comment | Token::Space) { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index d50b450..da8250e 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -125,7 +125,7 @@ pub fn eval(pgrm: Program) { Instruction::LessThan => { let right = data.pop().unwrap(); let left = data.pop().unwrap(); - data.push(if left < right { 1 } else { 0 }); + data.push(if left < right { 0 } else { 1 }); pc += 1; } Instruction::Store(n) => { diff --git a/src/wasm/main.rs b/src/wasm/main.rs index 9f9ec9d..e8c12e8 100644 --- a/src/wasm/main.rs +++ b/src/wasm/main.rs @@ -1,11 +1,5 @@ -extern crate chen_lang; - use std::ffi::{CStr, CString}; -use std::mem; -use std::{ - os::raw::{c_char, c_void}, - rc::Rc, -}; +use std::os::raw::c_char; fn main() {}