Conlang/libconlang/examples/parse_input.rs

52 lines
1.3 KiB
Rust

//! This example grabs input from stdin, lexes it, parses it, and prints the AST
#![allow(unused_imports)]
use conlang::{lexer::Lexer, parser::Parser, pretty_printer::PrettyPrintable, token::Token};
use std::{
error::Error,
io::{stdin, IsTerminal, Read},
path::{Path, PathBuf},
};
fn main() -> Result<(), Box<dyn Error>> {
let conf = Config::new();
if conf.paths.is_empty() {
take_stdin()?;
} else {
for path in conf.paths.iter().map(PathBuf::as_path) {
parse(&std::fs::read_to_string(path)?, Some(path));
}
}
Ok(())
}
struct Config {
paths: Vec<PathBuf>,
}
impl Config {
fn new() -> Self {
Config { paths: std::env::args().skip(1).map(PathBuf::from).collect() }
}
}
fn take_stdin() -> Result<(), Box<dyn Error>> {
if stdin().is_terminal() {
for line in stdin().lines() {
parse(&line?, None)
}
} else {
parse(&std::io::read_to_string(stdin())?, None)
}
Ok(())
}
fn parse(file: &str, path: Option<&Path>) {
use conlang::parser::error::Error;
match Parser::from(Lexer::new(file)).parse() {
Ok(ast) => ast.print(),
Err(e) if e.start().is_some() => println!("{:?}:{}", path.unwrap_or(Path::new("-")), e),
Err(e) => println!("{e}"),
}
println!();
}