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),
|
Integer(i64),
|
||||||
Unit,
|
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 {
|
struct GlobalArgs {
|
||||||
subcommand: Option<Subcommand>,
|
subcommand: Option<Subcommand>,
|
||||||
|
@ -44,7 +52,7 @@ fn usage(exit_code: i32) -> ! {
|
||||||
|
|
||||||
fn parse_global_args() -> Result<GlobalArgs, ParseArgsError> {
|
fn parse_global_args() -> Result<GlobalArgs, ParseArgsError> {
|
||||||
let mut subcommand = None;
|
let mut subcommand = None;
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args().skip(1);
|
||||||
|
|
||||||
while let Some(arg) = args.next() {
|
while let Some(arg) = args.next() {
|
||||||
match arg.as_str() {
|
match arg.as_str() {
|
||||||
|
@ -61,6 +69,46 @@ fn parse_global_args() -> Result<GlobalArgs, ParseArgsError> {
|
||||||
return Ok(GlobalArgs { subcommand });
|
return Ok(GlobalArgs { subcommand });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run() -> crate::Result<()> {
|
fn repl() -> ! {
|
||||||
Ok(())
|
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,
|
Unknown,
|
||||||
|
|
||||||
File(Arc<Box<Path>>),
|
File(Arc<Box<Path>>),
|
||||||
|
|
||||||
|
Repl(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -166,16 +168,12 @@ impl<'a> Lexer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg!(&self.collected);
|
|
||||||
Ok(self.produce(BareToken::Integer(
|
Ok(self.produce(BareToken::Integer(
|
||||||
self.collected
|
self.collected
|
||||||
.iter()
|
.iter()
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e: ParseIntError| {
|
.map_err(|e: ParseIntError| self.produce_error(e.into()))?,
|
||||||
dbg!(&e);
|
|
||||||
self.produce_error(e.into())
|
|
||||||
})?,
|
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +186,7 @@ impl<'a> Iterator for Lexer<'a> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if self.done && !self.sent_eof {
|
if self.done && !self.sent_eof {
|
||||||
|
self.sent_eof = true;
|
||||||
return Some(Ok(Token {
|
return Some(Ok(Token {
|
||||||
location: None,
|
location: None,
|
||||||
token: BareToken::EndOfFile,
|
token: BareToken::EndOfFile,
|
||||||
|
@ -309,9 +308,10 @@ mod test {
|
||||||
t(pos(1), BareToken::Integer(3)),
|
t(pos(1), BareToken::Integer(3)),
|
||||||
t(pos(3), BareToken::Plus),
|
t(pos(3), BareToken::Plus),
|
||||||
t(pos(5), BareToken::Integer(9)),
|
t(pos(5), BareToken::Integer(9)),
|
||||||
|
t(Option::None, BareToken::EndOfFile),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
assert_eq!(tokens?.len(), 3);
|
assert_eq!(tokens?.len(), 4);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::{iter::Peekable, vec::IntoIter};
|
||||||
|
|
||||||
use crate::{ast::*, lexer};
|
use crate::{ast::*, lexer};
|
||||||
|
|
||||||
struct Parser {
|
pub struct Parser {
|
||||||
num_tokens_parsed: usize,
|
num_tokens_parsed: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue