From a9a67acdcee005f85c3e43274a049f4fa934754a Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 6 May 2026 10:48:13 +0300 Subject: [PATCH] Add comment parsing --- lysp/example0.lysp | 31 ++++++++++++++++++++++++------- lysp/example1.lysp | 1 + src/compile/block.rs | 33 ++++++++++++++++++++++++--------- src/main.rs | 14 +++++++++++++- src/parse.rs | 38 ++++++++++++++++++++++++++++++++++---- 5 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 lysp/example1.lysp diff --git a/lysp/example0.lysp b/lysp/example0.lysp index aebe489..aa5fbc0 100644 --- a/lysp/example0.lysp +++ b/lysp/example0.lysp @@ -1,3 +1,5 @@ +;; vi:ft=lisp:sw=2:ts=2 + (defun return-1 () 1) (assert (= 1 (return-1))) (assert (< 1 2 3 4)) @@ -16,11 +18,26 @@ (setq a 1) (assert (= a 1)) -(assert (= 6 - (let (a 1) - (let (b 2) - (+ a b 3) - ) + +(assert + (= + 6 + ;; Non-sequential let: bindings will be visible only inside the block + (let + (a 1) + (let + (a 100 b (+ a 2)) + (+ b 3) + ) ) -)) -(assert (/= (let (a 2) a) a)) + ;; Sequential let: bindings are visible immediately in the asignments + (let + (a 100) + (let* + (a 1 b (+ a 2)) + (+ b 3) + ) + ) + ) +) + diff --git a/lysp/example1.lysp b/lysp/example1.lysp new file mode 100644 index 0000000..2475ed0 --- /dev/null +++ b/lysp/example1.lysp @@ -0,0 +1 @@ +;; vi:ft=lisp:sw=2:ts=2 diff --git a/src/compile/block.rs b/src/compile/block.rs index 08c42f1..6217049 100644 --- a/src/compile/block.rs +++ b/src/compile/block.rs @@ -21,7 +21,7 @@ pub struct CompiledFunction { struct LocalScope { start_index: u32, - locals: Vec>, + locals: Vec<(Rc, bool)>, } pub struct FunctionBlock { @@ -40,21 +40,26 @@ pub struct LocalBlock<'a> { } impl LocalScope { - pub fn get_or_insert(&mut self, value: Rc) -> Result, CompileError> { - let index = if let Some(index) = self.locals.iter().position(|v| *v == value) { + pub fn get_or_insert(&mut self, value: Rc, visible: bool) -> Result, CompileError> { + let index = if let Some(index) = self.locals.iter().position(|v| v.0 == value) { + self.locals[index].1 = visible; index } else { let index = self.locals.len(); - self.locals.push(value); + self.locals.push((value, visible)); index } + self.start_index as usize; Ok(U::new(index as u32).unwrap()) } + pub fn make_visible(&mut self, index: U<16>) { + self.locals[usize::from(index) - self.start_index as usize].1 = true; + } + pub fn get(&self, value: &str) -> Option> { self.locals .iter() - .position(|v| v.as_ref() == value) + .position(|v| v.0.as_ref() == value && v.1) .map(|v| v + self.start_index as usize) .and_then(|v| U::new(v as u32)) } @@ -196,15 +201,16 @@ impl<'a> LocalBlock<'a> { &mut self, identifier: &Rc, value: CompileValue, - ) -> Result<(), CompileError> { + visible: bool, + ) -> Result, CompileError> { let index = self .function .local_scope_mut() .unwrap() - .get_or_insert(identifier.clone())?; + .get_or_insert(identifier.clone(), visible)?; self.compile_push(value)?; self.function.emit(Instruction::SetLocal(index)); - Ok(()) + Ok(index) } fn compile_push(&mut self, value: CompileValue) -> Result<(), CompileError> { @@ -405,9 +411,18 @@ impl<'a> LocalBlock<'a> { fn compile_let(&mut self, binding: &LetExpression) -> Result { self.function.push_local_scope(); + let mut indices = vec![]; for pair in &binding.bindings { let value = self.compile_expression(&pair.value)?; - self.compile_set_local(&pair.identifier, value)?; + let index = self.compile_set_local(&pair.identifier, value, binding.sequential)?; + indices.push(index); + } + if !binding.sequential { + // Make let bindings visible + let scope = self.function.local_scope_mut().unwrap(); + for index in indices { + scope.make_visible(index); + } } for expr in &binding.body.head { self.compile_statement(expr)?; diff --git a/src/main.rs b/src/main.rs index 7b9d8e9..5235f23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use lysp::{ CompilationModule, CompileError, Expression, FunctionBody, FunctionSignature, ParseError, }, error::EvalError, - parse::parse_value, + parse::{parse_value, skip_comment_and_whitespace}, vm::{ machine::{EvalResult, Machine, MachineError}, prelude, @@ -57,6 +57,12 @@ fn run_interactive(vm: &mut Machine) -> Result<(), Error> { let mut i = input.trim_start(); while !i.is_empty() { + i = match skip_comment_and_whitespace(i) { + Ok((i, _)) => i, + Err(e) => { + todo!("{e:?}") + } + }; let result = parse_value(i); let (o, value) = match result { Ok(r) => r, @@ -148,6 +154,12 @@ fn run_module>(vm: &mut Machine, path: P) -> Result<(), Error> { let mut i = input.trim_start(); while !i.is_empty() { + i = match skip_comment_and_whitespace(i) { + Ok((i, _)) => i, + Err(e) => { + todo!("{e:?}") + } + }; let result = parse_value(i); let (o, value) = match result { Ok(r) => r, diff --git a/src/parse.rs b/src/parse.rs index e110533..0680b9b 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,10 +1,10 @@ use nom::{ - FindToken, IResult, Input, Parser, + AsChar, FindToken, IResult, Input, Parser, branch::alt, bytes::streaming::tag, character::{ anychar, - streaming::{char, multispace0, one_of}, + streaming::{char, one_of}, }, combinator::{map, map_res, opt, recognize, value}, error::{Error, ErrorKind, FromExternalError, ParseError}, @@ -169,8 +169,8 @@ fn parse_list_or_nil(input: &str) -> IResult<&str, Value> { map( delimited( char('('), - many0(preceded(multispace0, parse_value)), - preceded(multispace0, char(')')), + many0(preceded(skip_comment_and_whitespace, parse_value)), + preceded(skip_comment_and_whitespace, char(')')), ), Value::list_or_nil, ) @@ -190,6 +190,36 @@ fn parse_boolean(input: &str) -> IResult<&str, Value> { .parse(input) } +pub fn skip_comment_and_whitespace(mut input: &str) -> IResult<&str, ()> { + let mut in_comment = false; + while let Some(ch) = input.chars().next() { + let next = input.ceil_char_boundary(1); + if next >= input.len() { + break; + } + + if ch == ';' { + in_comment = true; + } + + if in_comment { + if ch.is_newline() { + in_comment = false; + } + + input = &input[next..]; + continue; + } else if ch.is_whitespace() || ch.is_newline() { + input = &input[next..]; + continue; + } + + break; + } + input = input.trim_start(); + Ok((input, ())) +} + pub fn parse_value(input: &str) -> IResult<&str, Value> { alt(( parse_list_or_nil,