Initial Commit
This commit is contained in:
		
							
								
								
									
										121
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
//! Tests the lexer
 | 
			
		||||
#[allow(unused_imports)]
 | 
			
		||||
use doughlang::{
 | 
			
		||||
    ast::{
 | 
			
		||||
        Expr,
 | 
			
		||||
        matcher::{Match, Subst},
 | 
			
		||||
    },
 | 
			
		||||
    lexer::{LexError, Lexer},
 | 
			
		||||
    parser::{ParseError, Parser},
 | 
			
		||||
    span::Span,
 | 
			
		||||
    token::{TKind, Token},
 | 
			
		||||
};
 | 
			
		||||
use repline::prebaked::*;
 | 
			
		||||
use std::{
 | 
			
		||||
    error::Error,
 | 
			
		||||
    io::{IsTerminal, stdin},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    if stdin().is_terminal() {
 | 
			
		||||
        read_and("\x1b[32m", " >", "?>", |line| match line.trim_end() {
 | 
			
		||||
            "" => Ok(Response::Continue),
 | 
			
		||||
            "exit" => Ok(Response::Break),
 | 
			
		||||
            "clear" => {
 | 
			
		||||
                print!("\x1b[H\x1b[2J");
 | 
			
		||||
                Ok(Response::Deny)
 | 
			
		||||
            }
 | 
			
		||||
            "pat" => {
 | 
			
		||||
                if let Err(e) = subst() {
 | 
			
		||||
                    println!("\x1b[31m{e}\x1b[0m");
 | 
			
		||||
                }
 | 
			
		||||
                Ok(Response::Deny)
 | 
			
		||||
            }
 | 
			
		||||
            _ => {
 | 
			
		||||
                parse(line);
 | 
			
		||||
                Ok(Response::Accept)
 | 
			
		||||
            }
 | 
			
		||||
        })?;
 | 
			
		||||
    } else {
 | 
			
		||||
        let doc = std::io::read_to_string(stdin())?;
 | 
			
		||||
        lex(&doc);
 | 
			
		||||
        parse(&doc);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn lex(document: &str) {
 | 
			
		||||
    let mut lexer = Lexer::new(document);
 | 
			
		||||
    loop {
 | 
			
		||||
        match lexer.scan() {
 | 
			
		||||
            Ok(Token { lexeme, kind, span: Span { head, tail } }) => {
 | 
			
		||||
                println!(
 | 
			
		||||
                    "{kind:?}\x1b[11G {head:<4} {tail:<4} {}",
 | 
			
		||||
                    lexeme.escape_debug()
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                eprintln!("{e}");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn subst() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    let mut rl = repline::Repline::new("\x1b[35mexp", " >", "?>");
 | 
			
		||||
    let exp = rl.read()?;
 | 
			
		||||
    let mut exp: Expr = Parser::new(Lexer::new(&exp)).parse(0)?;
 | 
			
		||||
    println!("\x1b[G\x1b[J{exp}");
 | 
			
		||||
 | 
			
		||||
    rl.accept();
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        rl.set_color("\x1b[36mpat");
 | 
			
		||||
        let pat = rl.read()?;
 | 
			
		||||
        rl.accept();
 | 
			
		||||
        print!("\x1b[G\x1b[J");
 | 
			
		||||
        let mut p = Parser::new(Lexer::new(&pat));
 | 
			
		||||
 | 
			
		||||
        let Ok(pat) = p.parse::<Expr>(0) else {
 | 
			
		||||
            println!("{exp}");
 | 
			
		||||
            continue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if p.next_if(TKind::Colon).is_err() {
 | 
			
		||||
            let Some(Subst { exp, pat }) = exp.construct(&pat) else {
 | 
			
		||||
                continue;
 | 
			
		||||
            };
 | 
			
		||||
            for (name, pat) in pat.iter() {
 | 
			
		||||
                println!("{name}: {pat}")
 | 
			
		||||
            }
 | 
			
		||||
            for (name, expr) in exp.iter() {
 | 
			
		||||
                println!("{name}: {expr}")
 | 
			
		||||
            }
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let sub: Expr = p.parse(0)?;
 | 
			
		||||
        if exp.apply_rule(&pat, &sub) {
 | 
			
		||||
            println!("{exp}");
 | 
			
		||||
        } else {
 | 
			
		||||
            println!("No match: {pat} in {exp}\n")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn parse(document: &str) {
 | 
			
		||||
    let mut parser = Parser::new(Lexer::new(document));
 | 
			
		||||
    loop {
 | 
			
		||||
        match parser.parse::<Expr>(0) {
 | 
			
		||||
            // Err(ParseError::FromLexer(LexError { res: "EOF", .. })) => break,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                println!("\x1b[31m{e}\x1b[0m");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            Ok(v) => {
 | 
			
		||||
                println!("{v}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user