Fix running multiple times, add reedline

This commit is contained in:
JT 2021-07-22 18:04:50 +12:00
parent 4deed7c836
commit c25209eb34
5 changed files with 148 additions and 85 deletions

View file

@ -6,3 +6,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
reedline = {git = "https://github.com/jntrnr/reedline"}

View file

@ -69,6 +69,7 @@ fn is_special_item(block_level: &[BlockKind], c: u8, special_tokens: &[u8]) -> b
pub fn lex_item( pub fn lex_item(
input: &[u8], input: &[u8],
curr_offset: &mut usize, curr_offset: &mut usize,
span_offset: usize,
additional_whitespace: &[u8], additional_whitespace: &[u8],
special_tokens: &[u8], special_tokens: &[u8],
) -> (Span, Option<ParseError>) { ) -> (Span, Option<ParseError>) {
@ -156,7 +157,7 @@ pub fn lex_item(
*curr_offset += 1; *curr_offset += 1;
} }
let span = Span::new(token_start, *curr_offset); let span = Span::new(span_offset + token_start, span_offset + *curr_offset);
// If there is still unclosed opening delimiters, close them and add // If there is still unclosed opening delimiters, close them and add
// synthetic closing characters to the accumulated token. // synthetic closing characters to the accumulated token.
@ -196,7 +197,7 @@ pub fn lex(
) -> (Vec<Token>, Option<ParseError>) { ) -> (Vec<Token>, Option<ParseError>) {
let mut error = None; let mut error = None;
let mut curr_offset = span_offset; let mut curr_offset = 0;
let mut output = vec![]; let mut output = vec![];
let mut is_complete = true; let mut is_complete = true;
@ -242,7 +243,7 @@ pub fn lex(
curr_offset += 1; curr_offset += 1;
output.push(Token::new( output.push(Token::new(
TokenContents::Semicolon, TokenContents::Semicolon,
Span::new(idx, idx + 1), Span::new(span_offset + idx, span_offset + idx + 1),
)); ));
} else if c == b'\n' || c == b'\r' { } else if c == b'\n' || c == b'\r' {
// If the next character is a newline, we're looking at an EOL (end of line) token. // If the next character is a newline, we're looking at an EOL (end of line) token.
@ -250,7 +251,10 @@ pub fn lex(
let idx = curr_offset; let idx = curr_offset;
curr_offset += 1; curr_offset += 1;
if !additional_whitespace.contains(&c) { if !additional_whitespace.contains(&c) {
output.push(Token::new(TokenContents::Eol, Span::new(idx, idx + 1))); output.push(Token::new(
TokenContents::Eol,
Span::new(span_offset + idx, span_offset + idx + 1),
));
} }
} else if c == b'#' { } else if c == b'#' {
// If the next character is `#`, we're at the beginning of a line // If the next character is `#`, we're at the beginning of a line
@ -272,7 +276,7 @@ pub fn lex(
if start != curr_offset { if start != curr_offset {
output.push(Token::new( output.push(Token::new(
TokenContents::Comment, TokenContents::Comment,
Span::new(start, curr_offset), Span::new(span_offset + start, span_offset + curr_offset),
)); ));
} }
} else if c == b' ' || c == b'\t' || additional_whitespace.contains(&c) { } else if c == b' ' || c == b'\t' || additional_whitespace.contains(&c) {
@ -284,6 +288,7 @@ pub fn lex(
let (span, err) = lex_item( let (span, err) = lex_item(
input, input,
&mut curr_offset, &mut curr_offset,
span_offset,
additional_whitespace, additional_whitespace,
special_tokens, special_tokens,
); );

View file

@ -3,20 +3,10 @@ use std::sync::Arc;
use engine_q::{ParserState, ParserWorkingSet, Signature, SyntaxShape}; use engine_q::{ParserState, ParserWorkingSet, Signature, SyntaxShape};
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
if let Some(path) = std::env::args().nth(1) {
let mut parser_state = Arc::new(ParserState::new()); let mut parser_state = Arc::new(ParserState::new());
let mut working_set = ParserWorkingSet::new(Some(parser_state.clone())); let mut working_set = ParserWorkingSet::new(Some(parser_state.clone()));
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')); let sig = Signature::build("where").required("cond", SyntaxShape::RowCondition, "condition");
working_set.add_decl(sig.into());
// let sig = Signature::build("bar")
// .named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'))
// .switch("--rock", "rock!!", Some('r'));
// working_set.add_decl(sig.into());
let sig =
Signature::build("where").required("cond", SyntaxShape::RowCondition, "condition");
working_set.add_decl(sig.into()); working_set.add_decl(sig.into());
let sig = Signature::build("if") let sig = Signature::build("if")
@ -63,6 +53,14 @@ fn main() -> std::io::Result<()> {
.required("block", SyntaxShape::Block, "body of the definition"); .required("block", SyntaxShape::Block, "body of the definition");
working_set.add_decl(sig.into()); working_set.add_decl(sig.into());
// let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
// working_set.add_decl(sig.into());
// let sig = Signature::build("bar")
// .named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'))
// .switch("--rock", "rock!!", Some('r'));
// working_set.add_decl(sig.into());
let sig = Signature::build("add"); let sig = Signature::build("add");
working_set.add_decl(sig.into()); working_set.add_decl(sig.into());
let sig = Signature::build("add it"); let sig = Signature::build("add it");
@ -72,9 +70,9 @@ fn main() -> std::io::Result<()> {
.required("x", SyntaxShape::Int, "x value") .required("x", SyntaxShape::Int, "x value")
.required("y", SyntaxShape::Int, "y value"); .required("y", SyntaxShape::Int, "y value");
working_set.add_decl(sig.into()); working_set.add_decl(sig.into());
ParserState::merge_working_set(&mut parser_state, working_set); ParserState::merge_working_set(&mut parser_state, working_set);
if let Some(path) = std::env::args().nth(1) {
// let file = std::fs::read(&path)?; // let file = std::fs::read(&path)?;
// let (output, err) = working_set.parse_file(&path, file); // let (output, err) = working_set.parse_file(&path, file);
@ -99,7 +97,48 @@ fn main() -> std::io::Result<()> {
Ok(()) Ok(())
} else { } else {
println!("specify file to lex"); use reedline::{DefaultPrompt, FileBackedHistory, Reedline, Signal};
let mut line_editor =
Reedline::new().with_history(Box::new(FileBackedHistory::new(1000)))?;
let prompt = DefaultPrompt::new(1);
let mut current_line = 1;
loop {
let input = line_editor.read_line(&prompt)?;
match input {
Signal::Success(s) => {
if s.trim() == "exit" {
break;
}
println!("input: '{}'", s);
let mut working_set = ParserWorkingSet::new(Some(parser_state.clone()));
let (output, err) = working_set.parse_file(
&format!("line_{}", current_line),
s.as_bytes(),
false,
);
ParserState::merge_working_set(&mut parser_state, working_set);
println!("{:#?}", parser_state);
println!("{:#?}", output);
println!("Error: {:?}", err);
}
Signal::CtrlC => {
println!("Ctrl-c");
}
Signal::CtrlD => {
break;
}
Signal::CtrlL => {
line_editor.clear_screen()?;
}
}
current_line += 1;
}
Ok(()) Ok(())
} }
} }

View file

@ -549,6 +549,7 @@ impl ParserWorkingSet {
pub fn parse_internal_call( pub fn parse_internal_call(
&mut self, &mut self,
command_span: Span,
spans: &[Span], spans: &[Span],
decl_id: usize, decl_id: usize,
) -> (Box<Call>, Span, Option<ParseError>) { ) -> (Box<Call>, Span, Option<ParseError>) {
@ -567,7 +568,7 @@ impl ParserWorkingSet {
// The index into the spans of argument data given to parse // The index into the spans of argument data given to parse
// Starting at the first argument // Starting at the first argument
let mut spans_idx = 1; let mut spans_idx = 0;
while spans_idx < spans.len() { while spans_idx < spans.len() {
let arg_span = spans[spans_idx]; let arg_span = spans[spans_idx];
@ -615,8 +616,17 @@ impl ParserWorkingSet {
let end = if decl.signature.rest_positional.is_some() { let end = if decl.signature.rest_positional.is_some() {
spans.len() spans.len()
} else { } else {
println!("num_positionals: {}", decl.signature.num_positionals());
println!("positional_idx: {}", positional_idx);
println!("spans.len(): {}", spans.len());
println!("spans_idx: {}", spans_idx);
let remainder = decl.signature.num_positionals() - positional_idx; let remainder = decl.signature.num_positionals() - positional_idx;
if remainder > spans.len() {
spans.len()
} else {
spans.len() - remainder + 1 spans.len() - remainder + 1
}
}; };
let (arg, err) = let (arg, err) =
@ -632,7 +642,7 @@ impl ParserWorkingSet {
spans_idx += 1; spans_idx += 1;
} }
let err = check_call(spans[0], &decl.signature, &call); let err = check_call(command_span, &decl.signature, &call);
error = error.or(err); error = error.or(err);
// FIXME: type unknown // FIXME: type unknown
@ -651,6 +661,7 @@ impl ParserWorkingSet {
let mut new_name = name.to_vec(); let mut new_name = name.to_vec();
new_name.push(b' '); new_name.push(b' ');
new_name.extend(self.get_span_contents(spans[pos])); new_name.extend(self.get_span_contents(spans[pos]));
if let Some(did) = self.find_decl(&new_name) { if let Some(did) = self.find_decl(&new_name) {
decl_id = did; decl_id = did;
} else { } else {
@ -660,11 +671,12 @@ impl ParserWorkingSet {
pos += 1; pos += 1;
} }
// parse internal command // parse internal command
let (call, span, err) = self.parse_internal_call(&spans[(pos - 1)..], decl_id); let (call, _, err) =
self.parse_internal_call(span(&spans[0..pos]), &spans[pos..], decl_id);
( (
Expression { Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span, span: span(spans),
}, },
err, err,
) )
@ -1757,7 +1769,8 @@ impl ParserWorkingSet {
if name == b"def" { if name == b"def" {
if let Some(decl_id) = self.find_decl(b"def") { if let Some(decl_id) = self.find_decl(b"def") {
let (call, call_span, err) = self.parse_internal_call(spans, decl_id); let (call, call_span, err) =
self.parse_internal_call(spans[0], &spans[1..], decl_id);
if err.is_some() { if err.is_some() {
return ( return (
@ -1813,7 +1826,8 @@ impl ParserWorkingSet {
if name == b"let" { if name == b"let" {
if let Some(decl_id) = self.find_decl(b"let") { if let Some(decl_id) = self.find_decl(b"let") {
let (call, call_span, err) = self.parse_internal_call(spans, decl_id); let (call, call_span, err) =
self.parse_internal_call(spans[0], &spans[1..], decl_id);
return ( return (
Statement::Expression(Expression { Statement::Expression(Expression {
@ -1890,16 +1904,18 @@ impl ParserWorkingSet {
pub fn parse_file( pub fn parse_file(
&mut self, &mut self,
fname: &str, fname: &str,
contents: Vec<u8>, contents: &[u8],
scoped: bool, scoped: bool,
) -> (Block, Option<ParseError>) { ) -> (Block, Option<ParseError>) {
let mut error = None; let mut error = None;
let (output, err) = lex(&contents, 0, &[], &[]); let span_offset = self.next_span_start();
error = error.or(err);
self.add_file(fname.into(), contents); self.add_file(fname.into(), contents);
let (output, err) = lex(&contents, span_offset, &[], &[]);
error = error.or(err);
let (output, err) = lite_parse(&output); let (output, err) = lite_parse(&output);
error = error.or(err); error = error.or(err);
@ -1912,9 +1928,11 @@ impl ParserWorkingSet {
pub fn parse_source(&mut self, source: &[u8], scoped: bool) -> (Block, Option<ParseError>) { pub fn parse_source(&mut self, source: &[u8], scoped: bool) -> (Block, Option<ParseError>) {
let mut error = None; let mut error = None;
let span_offset = self.next_span_start();
self.add_file("source".into(), source.into()); self.add_file("source".into(), source.into());
let (output, err) = lex(source, 0, &[], &[]); let (output, err) = lex(source, span_offset, &[], &[]);
error = error.or(err); error = error.or(err);
let (output, err) = lite_parse(&output); let (output, err) = lite_parse(&output);

View file

@ -205,10 +205,10 @@ impl ParserWorkingSet {
} }
} }
pub fn add_file(&mut self, filename: String, contents: Vec<u8>) -> usize { pub fn add_file(&mut self, filename: String, contents: &[u8]) -> usize {
let next_span_start = self.next_span_start(); let next_span_start = self.next_span_start();
self.file_contents.extend(&contents); self.file_contents.extend(contents);
let next_span_end = self.next_span_start(); let next_span_end = self.next_span_start();
@ -354,7 +354,7 @@ mod parser_state_tests {
#[test] #[test]
fn add_file_gives_id() { fn add_file_gives_id() {
let mut parser_state = ParserWorkingSet::new(Some(Arc::new(ParserState::new()))); let mut parser_state = ParserWorkingSet::new(Some(Arc::new(ParserState::new())));
let id = parser_state.add_file("test.nu".into(), vec![]); let id = parser_state.add_file("test.nu".into(), &[]);
assert_eq!(id, 0); assert_eq!(id, 0);
} }
@ -365,7 +365,7 @@ mod parser_state_tests {
let parent_id = parser_state.add_file("test.nu".into(), vec![]); let parent_id = parser_state.add_file("test.nu".into(), vec![]);
let mut working_set = ParserWorkingSet::new(Some(Arc::new(parser_state))); let mut working_set = ParserWorkingSet::new(Some(Arc::new(parser_state)));
let working_set_id = working_set.add_file("child.nu".into(), vec![]); let working_set_id = working_set.add_file("child.nu".into(), &[]);
assert_eq!(parent_id, 0); assert_eq!(parent_id, 0);
assert_eq!(working_set_id, 1); assert_eq!(working_set_id, 1);
@ -378,7 +378,7 @@ mod parser_state_tests {
let mut parser_state = Arc::new(parser_state); let mut parser_state = Arc::new(parser_state);
let mut working_set = ParserWorkingSet::new(Some(parser_state.clone())); let mut working_set = ParserWorkingSet::new(Some(parser_state.clone()));
working_set.add_file("child.nu".into(), vec![]); working_set.add_file("child.nu".into(), &[]);
ParserState::merge_working_set(&mut parser_state, working_set); ParserState::merge_working_set(&mut parser_state, working_set);