From e6f3483a542c1fc9f2fb28dce5a77088a5f0f010 Mon Sep 17 00:00:00 2001 From: PaddiM8 Date: Sat, 1 Jan 2022 02:35:33 +0100 Subject: [PATCH] Support loading files in config dir --- cli/src/main.rs | 27 +++++++++++++++++++++++---- cli/src/repl.rs | 12 +++++++++++- kalk/src/lexer.rs | 6 ++++-- kalk/src/parser.rs | 21 +++++++++++++++++++-- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index b4ae7cb..24dffe6 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -9,10 +9,10 @@ use std::io::Read; fn main() { let args: Vec = env::args().collect(); - let app = App::new("kalk") + let app = App::new("kalker") .author(env!("CARGO_PKG_AUTHORS")) .version(env!("CARGO_PKG_VERSION")) - .usage("kalk [options] [input]") + .usage("kalker [options] [input]") .action(default_action) .flag( Flag::new("input-file", FlagType::String) @@ -55,6 +55,10 @@ fn default_action(context: &Context) { .int_flag("precision") .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") { 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 { + 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(); File::open(&file_name) .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. // 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 { diff --git a/cli/src/repl.rs b/cli/src/repl.rs index 1ce5cff..90ece92 100644 --- a/cli/src/repl.rs +++ b/cli/src/repl.rs @@ -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) { + 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 { "" => eprint!(""), "clear" => print!("\x1B[2J"), @@ -96,7 +106,7 @@ impl Highlighter for LineHighlighter { let reg = Regex::new( r"(?x) - (?P([+\-/*%^!×÷]|if|otherwise)) | + (?P([+\-/*%^!×÷]|if|otherwise|load|exit|clear|help)) | (?P0[box][a-zA-Z0-9]+) | (?P[^!-@\s_|^⌊⌋⌈⌉\[\]\{\}≠≥≤⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎]+(_\d+)?)", ) diff --git a/kalk/src/lexer.rs b/kalk/src/lexer.rs index 4389e6b..bcc8f47 100644 --- a/kalk/src/lexer.rs +++ b/kalk/src/lexer.rs @@ -42,6 +42,7 @@ pub enum TokenKind { ClosedBrace, Comma, Semicolon, + Newline, EOF, } @@ -97,7 +98,7 @@ impl<'a> Lexer<'a> { return eof; }; - while c == ' ' || c == '\t' || c == '\r' || c == '\n' { + while c == ' ' || c == '\t' || c == '\r' { if let None = self.advance() { return eof; } @@ -141,6 +142,7 @@ impl<'a> Lexer<'a> { '<' => build(TokenKind::LessThan, "", span), ',' => build(TokenKind::Comma, "", span), ';' => build(TokenKind::Semicolon, "", span), + '\n' => build(TokenKind::Newline, "", span), '%' => build(TokenKind::Percent, "", span), '\'' => build(TokenKind::Tick, "", span), '≠' => build(TokenKind::NotEquals, "", span), @@ -350,7 +352,7 @@ fn is_valid_identifier(c: Option<&char>) -> bool { match c { '+' | '-' | '/' | '*' | '%' | '^' | '!' | '(' | ')' | '=' | '.' | ',' | ';' | '|' | '⌊' | '⌋' | '⌈' | '⌉' | '[' | ']' | '{' | '}' | 'π' | '√' | 'τ' | 'ϕ' | 'Γ' | '<' - | '>' | '≠' | '≥' | '≤' | '×' | '÷' => false, + | '>' | '≠' | '≥' | '≤' | '×' | '÷' | '\n' => false, _ => !c.is_digit(10) || is_superscript(c) || is_subscript(c), } } else { diff --git a/kalk/src/parser.rs b/kalk/src/parser.rs index 9dd34d9..9e4a18c 100644 --- a/kalk/src/parser.rs +++ b/kalk/src/parser.rs @@ -205,6 +205,8 @@ pub fn parse(context: &mut Context, input: &str) -> Result, CalcError> if match_token(context, TokenKind::Semicolon) { advance(context); } + + skip_newlines(context); } Ok(statements) @@ -283,6 +285,7 @@ fn parse_identifier_stmt(context: &mut Context) -> Result { fn parse_piecewise(context: &mut Context) -> Result { advance(context); + skip_newlines(context); let mut pieces = Vec::new(); let mut reached_otherwise = false; @@ -314,10 +317,18 @@ fn parse_piecewise(context: &mut Context) -> Result { return Err(CalcError::ExpectedIf); } - advance(context); - previous(context).kind == TokenKind::Semicolon && !reached_otherwise + if match_token(context, TokenKind::Semicolon) { + advance(context); + } + skip_newlines(context); + + (previous(context).kind == TokenKind::Semicolon + || previous(context).kind == TokenKind::Newline) + && !reached_otherwise } {} + advance(context); + 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 } +fn skip_newlines(context: &mut Context) { + while match_token(context, TokenKind::Newline) { + advance(context); + } +} + fn string_to_num(value: &str) -> Result { let base = get_base(value)?; if let Some(result) = crate::radix::parse_float_radix(&value.replace(" ", ""), base) {