Skip to content

Commit

Permalink
a
Browse files Browse the repository at this point in the history
  • Loading branch information
zuisong committed Dec 19, 2023
1 parent 2a89f47 commit 2d85c1a
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 49 deletions.
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand All @@ -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"
13 changes: 8 additions & 5 deletions src/bin/chen_lang.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
extern crate clap;

use std::{
fs::OpenOptions,
io::{self, Read},
Expand All @@ -10,6 +11,7 @@ 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 {
Expand All @@ -19,9 +21,9 @@ 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::<Level>().unwrap()),
#[arg(value_parser =
PossibleValuesParser::new([ "ERROR", "WARN", "INFO", "DEBUG", "TRACE"])
.map(| s | s.parse::< Level > ().unwrap()),
)]
log_level: Level,
}
Expand All @@ -42,13 +44,13 @@ enum SubCommand {

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 {
Expand All @@ -74,6 +76,7 @@ fn run_file(code_file: String) -> Result<()> {
chen_lang::run(code)?;
Ok(())
}

fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
}
94 changes: 88 additions & 6 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, i32>,
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<String, i32>, 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 {
Expand All @@ -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);
}
}
3 changes: 0 additions & 3 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,6 @@ pub fn parse_assign(line: &[Token]) -> Result<Assign> {
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..])?)
Expand Down
2 changes: 0 additions & 2 deletions src/tests/parse_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::boxed;

use crate::expression::{Assign, FunctionCall, If};
use crate::token::Operator;
use crate::{
Expand Down
41 changes: 20 additions & 21 deletions src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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((
Expand Down Expand Up @@ -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::<i32>()
.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::<i32>().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),
Expand Down Expand Up @@ -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<char>, loc: &Location) -> Result<(Token, Location), TokenError> {
fn parse_token(input: &str, loc: &Location) -> Result<(Token, Location), TokenError> {

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, nightly)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, nightly)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, stable)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, stable)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (macOS-latest, stable)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (macOS-latest, stable)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (macOS-latest, nightly)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (macOS-latest, nightly)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (windows-latest, nightly)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (windows-latest, nightly)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (windows-latest, stable)

function `parse_token` is never used

Check warning on line 209 in src/token.rs

View workflow job for this annotation

GitHub Actions / build (windows-latest, stable)

function `parse_token` is never used
let chars: Vec<char> = input.chars().collect();
let cur = *chars.get(loc.index).unwrap_or(&' ');
let next = *chars.get(loc.index + 1).unwrap_or(&' ');
let res = match cur {
Expand Down Expand Up @@ -301,12 +300,12 @@ fn parse_token(chars: &Vec<char>, loc: &Location) -> Result<(Token, Location), T

/// 代码转成token串
pub fn tokenlizer(code: String) -> anyhow::Result<Vec<Token>> {
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) {
Expand Down
2 changes: 1 addition & 1 deletion src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down

0 comments on commit 2d85c1a

Please sign in to comment.