Skip to content

Commit

Permalink
Script mode support & comment support
Browse files Browse the repository at this point in the history
  • Loading branch information
BHznJNs committed Mar 12, 2023
1 parent cec21d9 commit fedfee3
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "calculator"
version = "1.1.1"
version = "1.2.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ An simple command-line calculator program writen with Rust.
= 1
```

- Goto supported
- Goto support

```text
> a = 10
Expand All @@ -33,6 +33,19 @@ An simple command-line calculator program writen with Rust.
= 31
```

- Comment support

```text
> 1 + 1 # plus
= 2
```

- Script execute support

```text
calculator.exe script
```

## Build-ins

- Functions
Expand Down
5 changes: 4 additions & 1 deletion src/compiler/tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub fn tokenizer(source: String) -> Result<TokenVec, ()> {
const POWER_ASCII : u8 = 94;
const EQUAL_ASCII : u8 = 61;

const NUMBER_SIGN_ASCII : u8 = 35;
const SPACE_ASCII : u8 = 32;
const RETURN_ASCII : u8 = 13;

Expand Down Expand Up @@ -208,7 +209,9 @@ pub fn tokenizer(source: String) -> Result<TokenVec, ()> {
},

SPACE_ASCII => {},
RETURN_ASCII => { break; },
// comment symbol
NUMBER_SIGN_ASCII => { break },
RETURN_ASCII => { break },
_ => {
println!("Unknown token: '{}' at index {}.", current as char, index);
return Err(());
Expand Down
23 changes: 23 additions & 0 deletions src/exec/attempt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::collections::HashMap;

use crate::compiler::compile;
use crate::computer::compute;
use crate::public::number::Number;
use crate::public::ast::ASTNode;

pub fn attempt(
input: String,
build_in_funcs: &HashMap<&str, fn(f64) -> f64>,
variables: &mut HashMap<String, Number>,
goto_statements: &mut HashMap<String, ASTNode>,
) -> Result<Number, ()> {
let root_node = compile::compile(input)?;
let result_num = compute::compute(
root_node,
build_in_funcs,
variables,
goto_statements,
)?;

Ok(result_num)
}
3 changes: 3 additions & 0 deletions src/exec/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod attempt;
pub mod repl;
pub mod run_script;
36 changes: 36 additions & 0 deletions src/exec/repl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::collections::HashMap;
use std::io::{self, Write};

use super::attempt::attempt;
use crate::public::number::Number;
use crate::public::ast::ASTNode;

pub fn repl(
build_in_funcs: &HashMap<&str, fn(f64) -> f64>,
variables: &mut HashMap<String, Number>,
goto_statements: &mut HashMap<String, ASTNode>,
) -> ! {
// print program name and version
println!("Calculator.rs v1.2.0");

loop {
print!("> ");
io::stdout().flush().unwrap();

let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.unwrap();

let result = attempt(
input,
build_in_funcs,
variables,
goto_statements,
);

if let Ok(num) = result {
println!("= {}", num);
}
}
}
62 changes: 62 additions & 0 deletions src/exec/run_script.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead};

use crate::exec::attempt::attempt;
use crate::public::number::Number;
use crate::public::ast::ASTNode;

type FileBuf = io::BufReader<File>;
fn read_lines(path: String) -> io::Result<io::Lines<FileBuf>> {
let file = File::open(path)?;
Ok(io::BufReader::new(file).lines())
}

pub fn run_script(
path: String,
build_in_funcs: &HashMap<&str, fn(f64) -> f64>,
variables: &mut HashMap<String, Number>,
goto_statements: &mut HashMap<String, ASTNode>,
) {
let mut script_lines =
if let Ok(lines) = read_lines(path) {
lines
} else {
println!("Invalid file.");
return
};

// cache last compute result,
// when the loop ends,
// print the final result.
let mut last_result = Number::NotANumber;
loop {
match script_lines.next() {
Some(item) => {
let mut script_line =
if let Ok(line) = item {
line
} else {
String::new()
};
script_line.push('\r');

last_result =
if let Ok(res_number) = attempt(
script_line,
build_in_funcs,
variables,
goto_statements
) {
res_number
} else {
Number::NotANumber
};
},
None => {
println!("{}", last_result);
break;
},
}
}
}
69 changes: 26 additions & 43 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,43 @@
mod public;
mod compiler;
mod computer;
mod exec;

use std::env;
use std::collections::HashMap;
use std::io::{self, Write};

use public::ast::ASTNode;
use public::number::Number;
use public::build_in;
use compiler::compile;
use computer::compute;
use exec::repl::repl;
use exec::run_script::run_script;

fn attempt(
input: String,
build_in_funcs: &HashMap<&str, fn(f64) -> f64>,
variables: &mut HashMap<String, Number>,
goto_statements: &mut HashMap<String, ASTNode>
) -> Result<Number, ()> {
let root_node = compile::compile(input)?;
let result_num = compute::compute(
root_node,
build_in_funcs,
variables,
goto_statements,
)?;

Ok(result_num)
}

fn main() -> ! {
fn main() {
let build_in_inst = build_in::BuildIn::init();
let build_in_funcs = build_in::build_in_funcs(&build_in_inst);
let mut variables = build_in::variables(&build_in_inst);
let mut goto_statements = HashMap::<String, ASTNode>::new();

// print program name and version
println!("Calculator.rs v1.1.1");

loop {
print!("> ");
io::stdout().flush().unwrap();

let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.unwrap();

let result = attempt(
input,
&build_in_funcs,
&mut variables,
&mut goto_statements,
);

if let Ok(num) = result {
println!("= {}", num);
let args: Vec<String> = env::args().collect();
match args.len() {
1 => {
// REPL mode
repl(
&build_in_funcs,
&mut variables,
&mut goto_statements,
);
},
2 => {
// script mode
run_script(
args[1].to_owned(),
&build_in_funcs,
&mut variables,
&mut goto_statements,
);
},
_ => {
println!("Too many args.");
}
}
}

0 comments on commit fedfee3

Please sign in to comment.