Support loading files in config dir

This commit is contained in:
PaddiM8 2022-01-01 02:35:33 +01:00
parent dae1e9f290
commit e6f3483a54
4 changed files with 57 additions and 9 deletions

View File

@ -9,10 +9,10 @@ use std::io::Read;
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let app = App::new("kalk") let app = App::new("kalker")
.author(env!("CARGO_PKG_AUTHORS")) .author(env!("CARGO_PKG_AUTHORS"))
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.usage("kalk [options] [input]") .usage("kalker [options] [input]")
.action(default_action) .action(default_action)
.flag( .flag(
Flag::new("input-file", FlagType::String) Flag::new("input-file", FlagType::String)
@ -55,6 +55,10 @@ fn default_action(context: &Context) {
.int_flag("precision") .int_flag("precision")
.unwrap_or(output::DEFAULT_PRECISION as isize) as u32; .unwrap_or(output::DEFAULT_PRECISION as isize) as u32;
if let Some(input_file_path) = get_input_file_by_name("default") {
load_input_file(&input_file_path, precision, &mut parser_context);
}
if let Ok(input_file_path) = context.string_flag("input-file") { if let Ok(input_file_path) = context.string_flag("input-file") {
load_input_file(&input_file_path, precision, &mut parser_context); load_input_file(&input_file_path, precision, &mut parser_context);
} }
@ -68,7 +72,20 @@ fn default_action(context: &Context) {
} }
} }
fn load_input_file(file_name: &str, precision: u32, parser_context: &mut parser::Context) { pub(crate) fn get_input_file_by_name(name: &str) -> Option<String> {
let mut path = dirs::config_dir()?;
path.push("kalker");
path.push(name);
path.set_extension("kalker");
if path.exists() {
Some(path.to_str()?.to_string())
} else {
None
}
}
pub fn load_input_file(file_name: &str, precision: u32, parser_context: &mut parser::Context) {
let mut file_content = String::new(); let mut file_content = String::new();
File::open(&file_name) File::open(&file_name)
.expect("Couldn't find file.") .expect("Couldn't find file.")
@ -77,7 +94,9 @@ fn load_input_file(file_name: &str, precision: u32, parser_context: &mut parser:
// Parse the input file content, resulting in the symbol table being filled out. // Parse the input file content, resulting in the symbol table being filled out.
// Output is not needed here. // Output is not needed here.
parser::eval(parser_context, &file_content, precision).expect("Failed to parse input file."); if let Err(error) = parser::eval(parser_context, &file_content, precision) {
eprintln!("{}", error.to_string());
}
} }
fn get_env_angle_unit() -> String { fn get_env_angle_unit() -> String {

View File

@ -74,6 +74,16 @@ pub fn start(mut parser: &mut parser::Context, precision: u32) {
} }
fn eval_repl(parser: &mut parser::Context, input: &str, precision: u32) { fn eval_repl(parser: &mut parser::Context, input: &str, precision: u32) {
if input.starts_with("load ") {
let file_name = &input[5..];
if let Some(file_path) = crate::get_input_file_by_name(file_name) {
crate::load_input_file(&file_path, precision, parser);
} else {
println!("Unable to find '{}'", file_name);
}
return;
}
match input { match input {
"" => eprint!(""), "" => eprint!(""),
"clear" => print!("\x1B[2J"), "clear" => print!("\x1B[2J"),
@ -96,7 +106,7 @@ impl Highlighter for LineHighlighter {
let reg = Regex::new( let reg = Regex::new(
r"(?x) r"(?x)
(?P<op>([+\-/*%^!×÷]|if|otherwise)) | (?P<op>([+\-/*%^!×÷]|if|otherwise|load|exit|clear|help)) |
(?P<radix>0[box][a-zA-Z0-9]+) | (?P<radix>0[box][a-zA-Z0-9]+) |
(?P<identifier>[^!-@\s_|^\[\]\{\}¹²³]+(_\d+)?)", (?P<identifier>[^!-@\s_|^\[\]\{\}¹²³]+(_\d+)?)",
) )

View File

@ -42,6 +42,7 @@ pub enum TokenKind {
ClosedBrace, ClosedBrace,
Comma, Comma,
Semicolon, Semicolon,
Newline,
EOF, EOF,
} }
@ -97,7 +98,7 @@ impl<'a> Lexer<'a> {
return eof; return eof;
}; };
while c == ' ' || c == '\t' || c == '\r' || c == '\n' { while c == ' ' || c == '\t' || c == '\r' {
if let None = self.advance() { if let None = self.advance() {
return eof; return eof;
} }
@ -141,6 +142,7 @@ impl<'a> Lexer<'a> {
'<' => build(TokenKind::LessThan, "", span), '<' => build(TokenKind::LessThan, "", span),
',' => build(TokenKind::Comma, "", span), ',' => build(TokenKind::Comma, "", span),
';' => build(TokenKind::Semicolon, "", span), ';' => build(TokenKind::Semicolon, "", span),
'\n' => build(TokenKind::Newline, "", span),
'%' => build(TokenKind::Percent, "", span), '%' => build(TokenKind::Percent, "", span),
'\'' => build(TokenKind::Tick, "", span), '\'' => build(TokenKind::Tick, "", span),
'≠' => build(TokenKind::NotEquals, "", span), '≠' => build(TokenKind::NotEquals, "", span),
@ -350,7 +352,7 @@ fn is_valid_identifier(c: Option<&char>) -> bool {
match c { match c {
'+' | '-' | '/' | '*' | '%' | '^' | '!' | '(' | ')' | '=' | '.' | ',' | ';' | '|' '+' | '-' | '/' | '*' | '%' | '^' | '!' | '(' | ')' | '=' | '.' | ',' | ';' | '|'
| '⌊' | '⌋' | '⌈' | '⌉' | '[' | ']' | '{' | '}' | 'π' | '√' | 'τ' | 'ϕ' | 'Γ' | '<' | '⌊' | '⌋' | '⌈' | '⌉' | '[' | ']' | '{' | '}' | 'π' | '√' | 'τ' | 'ϕ' | 'Γ' | '<'
| '>' | '≠' | '≥' | '≤' | '×' | '÷' => false, | '>' | '≠' | '≥' | '≤' | '×' | '÷' | '\n' => false,
_ => !c.is_digit(10) || is_superscript(c) || is_subscript(c), _ => !c.is_digit(10) || is_superscript(c) || is_subscript(c),
} }
} else { } else {

View File

@ -205,6 +205,8 @@ pub fn parse(context: &mut Context, input: &str) -> Result<Vec<Stmt>, CalcError>
if match_token(context, TokenKind::Semicolon) { if match_token(context, TokenKind::Semicolon) {
advance(context); advance(context);
} }
skip_newlines(context);
} }
Ok(statements) Ok(statements)
@ -283,6 +285,7 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
fn parse_piecewise(context: &mut Context) -> Result<Expr, CalcError> { fn parse_piecewise(context: &mut Context) -> Result<Expr, CalcError> {
advance(context); advance(context);
skip_newlines(context);
let mut pieces = Vec::new(); let mut pieces = Vec::new();
let mut reached_otherwise = false; let mut reached_otherwise = false;
@ -314,10 +317,18 @@ fn parse_piecewise(context: &mut Context) -> Result<Expr, CalcError> {
return Err(CalcError::ExpectedIf); return Err(CalcError::ExpectedIf);
} }
advance(context); if match_token(context, TokenKind::Semicolon) {
previous(context).kind == TokenKind::Semicolon && !reached_otherwise advance(context);
}
skip_newlines(context);
(previous(context).kind == TokenKind::Semicolon
|| previous(context).kind == TokenKind::Newline)
&& !reached_otherwise
} {} } {}
advance(context);
Ok(Expr::Piecewise(pieces)) Ok(Expr::Piecewise(pieces))
} }
@ -864,6 +875,12 @@ fn is_at_end(context: &Context) -> bool {
context.pos >= context.tokens.len() || peek(context).kind == TokenKind::EOF context.pos >= context.tokens.len() || peek(context).kind == TokenKind::EOF
} }
fn skip_newlines(context: &mut Context) {
while match_token(context, TokenKind::Newline) {
advance(context);
}
}
fn string_to_num(value: &str) -> Result<f64, CalcError> { fn string_to_num(value: &str) -> Result<f64, CalcError> {
let base = get_base(value)?; let base = get_base(value)?;
if let Some(result) = crate::radix::parse_float_radix(&value.replace(" ", ""), base) { if let Some(result) = crate::radix::parse_float_radix(&value.replace(" ", ""), base) {