feat: add repl subcommand
This commit is contained in:
parent
13835d9511
commit
18a01a7f29
4 changed files with 61 additions and 11 deletions
|
@ -14,3 +14,5 @@ pub enum Expression {
|
|||
Integer(i64),
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl Expression {}
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
use std::str::FromStr;
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
lexer::{self, Lexer, Source, Token},
|
||||
parser::Parser,
|
||||
};
|
||||
|
||||
struct GlobalArgs {
|
||||
subcommand: Option<Subcommand>,
|
||||
|
@ -44,7 +52,7 @@ fn usage(exit_code: i32) -> ! {
|
|||
|
||||
fn parse_global_args() -> Result<GlobalArgs, ParseArgsError> {
|
||||
let mut subcommand = None;
|
||||
let mut args = std::env::args();
|
||||
let mut args = std::env::args().skip(1);
|
||||
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
|
@ -61,6 +69,46 @@ fn parse_global_args() -> Result<GlobalArgs, ParseArgsError> {
|
|||
return Ok(GlobalArgs { subcommand });
|
||||
}
|
||||
|
||||
pub fn run() -> crate::Result<()> {
|
||||
Ok(())
|
||||
fn repl() -> ! {
|
||||
println!("lytlang repl (^D to stop)");
|
||||
print!("> ");
|
||||
std::io::stdout().flush().expect("failed to flush stdout");
|
||||
let mut iter = std::io::stdin().lines().enumerate().into_iter();
|
||||
while let Some((i, l)) = iter.next() {
|
||||
let s = match &l {
|
||||
Ok(s) => s.as_str(),
|
||||
Err(e) => {
|
||||
eprintln!("error reading line from stdin: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let tokens = match Lexer::new(s, Source::Repl(i)).collect() {
|
||||
Ok(tokens) => tokens,
|
||||
Err(e) => {
|
||||
eprintln!("error lexing input: {:?}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
match Parser::default().parse(tokens) {
|
||||
Ok(expr) => println!("< {:?}", expr),
|
||||
Err(e) => {
|
||||
eprintln!("error parsing tokens: {:?}", e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
println!("> ");
|
||||
std::io::stdout().flush().expect("failed to flush stdout");
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
pub fn run() -> crate::Result<()> {
|
||||
match parse_global_args()?.subcommand {
|
||||
Some(Subcommand::Repl) => repl(),
|
||||
Some(Subcommand::Help) => usage(0),
|
||||
None => {
|
||||
println!("no subcommand specified");
|
||||
usage(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ pub enum Source {
|
|||
Unknown,
|
||||
|
||||
File(Arc<Box<Path>>),
|
||||
|
||||
Repl(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
|
@ -166,16 +168,12 @@ impl<'a> Lexer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
dbg!(&self.collected);
|
||||
Ok(self.produce(BareToken::Integer(
|
||||
self.collected
|
||||
.iter()
|
||||
.collect::<String>()
|
||||
.parse()
|
||||
.map_err(|e: ParseIntError| {
|
||||
dbg!(&e);
|
||||
self.produce_error(e.into())
|
||||
})?,
|
||||
.map_err(|e: ParseIntError| self.produce_error(e.into()))?,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +186,7 @@ impl<'a> Iterator for Lexer<'a> {
|
|||
return None;
|
||||
}
|
||||
if self.done && !self.sent_eof {
|
||||
self.sent_eof = true;
|
||||
return Some(Ok(Token {
|
||||
location: None,
|
||||
token: BareToken::EndOfFile,
|
||||
|
@ -309,9 +308,10 @@ mod test {
|
|||
t(pos(1), BareToken::Integer(3)),
|
||||
t(pos(3), BareToken::Plus),
|
||||
t(pos(5), BareToken::Integer(9)),
|
||||
t(Option::None, BareToken::EndOfFile),
|
||||
]),
|
||||
);
|
||||
assert_eq!(tokens?.len(), 3);
|
||||
assert_eq!(tokens?.len(), 4);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{iter::Peekable, vec::IntoIter};
|
|||
|
||||
use crate::{ast::*, lexer};
|
||||
|
||||
struct Parser {
|
||||
pub struct Parser {
|
||||
num_tokens_parsed: usize,
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue