diff --git a/CHANGELOG.md b/CHANGELOG.md index d9875a3b6..6b3cf0494 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased +- Add full support for comments in lisp (#489) - Add parenthesis matching to editor (#488) - Upgrade smoltcp from 0.8.2 to 0.9.1 (#484) - Update rust to nightly-2022-12-21 (#485) diff --git a/doc/lisp.md b/doc/lisp.md index 9482c7f22..bf1bdc330 100644 --- a/doc/lisp.md +++ b/doc/lisp.md @@ -187,3 +187,4 @@ Rewrite parts of the code and add new functions and examples. ### 0.5.0 (unpublished) - Rename or add aliases to many functions +- Add full support for line and inline comments diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 444ec38fe..a4a07cefc 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -1,6 +1,5 @@ -use super::{Err, Exp, Env, Function}; +use super::{Err, Exp, Env, Function, parse_eval}; use super::env::{env_get, env_set, function_env}; -use super::parse::parse; use super::expand::expand; use super::string; @@ -130,15 +129,13 @@ fn eval_do_args(args: &[Exp], env: &mut Rc>) -> Result { fn eval_load_args(args: &[Exp], env: &mut Rc>) -> Result { ensure_length_eq!(args, 1); let path = string(&args[0])?; - let mut code = fs::read_to_string(&path).or(Err(Err::Reason("Could not read file".to_string())))?; + let mut input = fs::read_to_string(&path).or(Err(Err::Reason(format!("File not found '{}'", path))))?; loop { - let (rest, exp) = parse(&code)?; - let exp = expand(&exp, env)?; - eval(&exp, env)?; + let (rest, _) = parse_eval(&input, env)?; if rest.is_empty() { break; } - code = rest; + input = rest; } Ok(Exp::Bool(true)) } diff --git a/src/usr/lisp/mod.rs b/src/usr/lisp/mod.rs index 1e02be79d..58458d80e 100644 --- a/src/usr/lisp/mod.rs +++ b/src/usr/lisp/mod.rs @@ -182,16 +182,11 @@ pub fn byte(exp: &Exp) -> Result { // REPL -fn parse_eval(exp: &str, env: &mut Rc>) -> Result { - let (_, exp) = parse(exp)?; +fn parse_eval(input: &str, env: &mut Rc>) -> Result<(String, Exp), Err> { + let (rest, exp) = parse(input)?; let exp = expand(&exp, env)?; let exp = eval(&exp, env)?; - Ok(exp) -} - -fn strip_comments(s: &str) -> String { - // FIXME: This doesn't handle `#` inside a string - s.split('#').next().unwrap().into() + Ok((rest, exp)) } fn lisp_completer(line: &str) -> Vec { @@ -221,33 +216,29 @@ fn repl(env: &mut Rc>) -> Result<(), ExitCode> { prompt.history.load(history_file); prompt.completion.set(&lisp_completer); - while let Some(line) = prompt.input(&prompt_string) { - if line == "(quit)" { + while let Some(input) = prompt.input(&prompt_string) { + if input == "(quit)" { break; } - if line.is_empty() { + if input.is_empty() { println!(); continue; } - match parse_eval(&line, env) { - Ok(res) => { - println!("{}\n", res); + match parse_eval(&input, env) { + Ok((_, exp)) => { + println!("{}\n", exp); } Err(e) => match e { Err::Reason(msg) => println!("{}Error:{} {}\n", csi_error, csi_reset, msg), }, } - prompt.history.add(&line); + prompt.history.add(&input); prompt.history.save(history_file); } Ok(()) } pub fn main(args: &[&str]) -> Result<(), ExitCode> { - let line_color = Style::color("Yellow"); - let error_color = Style::color("LightRed"); - let reset = Style::reset(); - let env = &mut default_env(); // Store args in env @@ -269,37 +260,27 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { if args[1] == "-h" || args[1] == "--help" { return help(); } - let pathname = args[1]; - if let Ok(code) = api::fs::read_to_string(pathname) { - let mut block = String::new(); - let mut opened = 0; - let mut closed = 0; - for (i, line) in code.split('\n').enumerate() { - let line = strip_comments(line); - if !line.is_empty() { - opened += line.matches('(').count(); - closed += line.matches(')').count(); - block.push_str(&line); - if closed >= opened { - if let Err(e) = parse_eval(&block, env) { - match e { - Err::Reason(msg) => { - eprintln!("{}Error:{} {}", error_color, reset, msg); - eprintln!(); - eprintln!(" {}{}:{} {}", line_color, i, reset, line); - return Err(ExitCode::Failure); - } - } + let path = args[1]; + if let Ok(mut input) = api::fs::read_to_string(path) { + loop { + match parse_eval(&input, env) { + Ok((rest, _)) => { + if rest.is_empty() { + break; } - block.clear(); - opened = 0; - closed = 0; + input = rest; + } + Err(Err::Reason(msg)) => { + let csi_error = Style::color("LightRed"); + let csi_reset = Style::reset(); + eprintln!("{}Error:{} {}", csi_error, csi_reset, msg); + return Err(ExitCode::Failure); } } } Ok(()) } else { - error!("File not found '{}'", pathname); + error!("File not found '{}'", path); Err(ExitCode::Failure) } } @@ -320,7 +301,7 @@ fn test_lisp() { macro_rules! eval { ($e:expr) => { - format!("{}", parse_eval($e, env).unwrap()) + format!("{}", parse_eval($e, env).unwrap().1) }; } diff --git a/src/usr/lisp/parse.rs b/src/usr/lisp/parse.rs index a77d1756c..4caf2bd5e 100644 --- a/src/usr/lisp/parse.rs +++ b/src/usr/lisp/parse.rs @@ -4,6 +4,7 @@ use alloc::string::String; use alloc::string::ToString; use alloc::vec; +use nom::Err::Error; use nom::IResult; use nom::branch::alt; use nom::bytes::complete::escaped_transform; @@ -91,7 +92,15 @@ fn parse_quasiquote(input: &str) -> IResult<&str, Exp> { Ok((input, Exp::List(list))) } +use nom::sequence::pair; +use alloc::format; + +fn parse_comment(input: &str) -> IResult<&str, ()> { + value((), pair(char('#'), is_not("\n")))(input) +} + fn parse_exp(input: &str) -> IResult<&str, Exp> { + let (input, _) = opt(parse_comment)(input)?; delimited(multispace0, alt(( parse_num, parse_bool, parse_str, parse_list, parse_quote, parse_quasiquote, parse_unquote_splice, parse_unquote, parse_splice, parse_sym )), multispace0)(input) @@ -100,6 +109,10 @@ fn parse_exp(input: &str) -> IResult<&str, Exp> { pub fn parse(input: &str)-> Result<(String, Exp), Err> { match parse_exp(input) { Ok((input, exp)) => Ok((input.to_string(), exp)), - Err(_) => Err(Err::Reason("Could not parse input".to_string())), + Err(Error(err)) if !err.input.is_empty() => { + let line = err.input.lines().next().unwrap(); + Err(Err::Reason(format!("Could not parse '{}'", line))) + } + _ => Err(Err::Reason(format!("Could not parse input"))), } } diff --git a/www/calculator.html b/www/calculator.html index 988690b06..411df9b1a 100644 --- a/www/calculator.html +++ b/www/calculator.html @@ -3,7 +3,7 @@ MOROS Calculator - +

MOROS Calculator

diff --git a/www/editor.html b/www/editor.html index cd66828fe..ffb888074 100644 --- a/www/editor.html +++ b/www/editor.html @@ -3,7 +3,7 @@ MOROS Editor - +

MOROS Editor

diff --git a/www/filesystem.html b/www/filesystem.html index 9531b2f82..f28cc712d 100644 --- a/www/filesystem.html +++ b/www/filesystem.html @@ -3,7 +3,7 @@ MOROS Filesystem - +

MOROS Filesystem

diff --git a/www/index.html b/www/index.html index a565df8ba..c3f7d36c9 100644 --- a/www/index.html +++ b/www/index.html @@ -3,7 +3,7 @@ MOROS: Obscure Rust Operating System - +

MOROS: Obscure Rust Operating System

diff --git a/www/lisp.html b/www/lisp.html index 212ea58f2..21cf7dc5a 100644 --- a/www/lisp.html +++ b/www/lisp.html @@ -3,7 +3,7 @@ MOROS Lisp - +

MOROS Lisp

@@ -220,6 +220,7 @@

0.5.0 (unpublished)

  • Rename or add aliases to many functions
  • +
  • Add full support for line and inline comments
diff --git a/www/manual.html b/www/manual.html index 9de23936f..f0161fe0f 100644 --- a/www/manual.html +++ b/www/manual.html @@ -3,7 +3,7 @@ MOROS Manual - +

MOROS Manual

diff --git a/www/network.html b/www/network.html index 54b0b4936..d3c94fdb2 100644 --- a/www/network.html +++ b/www/network.html @@ -3,7 +3,7 @@ MOROS Network - +

MOROS Network

diff --git a/www/regex.html b/www/regex.html index c60475460..a5a691302 100644 --- a/www/regex.html +++ b/www/regex.html @@ -3,7 +3,7 @@ MOROS Regular Expression Engine - +

MOROS Regular Expression Engine

diff --git a/www/shell.html b/www/shell.html index ae2db0fd1..28b7d4c38 100644 --- a/www/shell.html +++ b/www/shell.html @@ -3,7 +3,7 @@ MOROS Shell - +

MOROS Shell

diff --git a/www/syscalls.html b/www/syscalls.html index dcc946135..5e0f914fe 100644 --- a/www/syscalls.html +++ b/www/syscalls.html @@ -3,7 +3,7 @@ MOROS Syscalls - +

MOROS Syscalls

diff --git a/www/test.html b/www/test.html index a199c282c..b9a43c8ee 100644 --- a/www/test.html +++ b/www/test.html @@ -3,7 +3,7 @@ MOROS - +

MOROS