Skip to main content

conlang/
main.rs

1//! Tests the lexer\
2
3use cl_ast::{
4    Annotation, At, Bind, DefaultTypes, Expr, Pat, Use,
5    fold::Foldable,
6    macro_matcher::{Match, Subst},
7    visit::Walk,
8};
9use cl_interpret::{convalue::ConValue, env::Environment, interpret::Interpret};
10use cl_lexer::{EOF, LexError, Lexer};
11use cl_parser::{Parse, ParseError, Parser, inliner::ModuleInliner};
12use cl_structures::span::Span;
13use cl_token::{TKind, Token};
14// use cl_typeck::Collector;
15use repline::prebaked::*;
16use std::{
17    error::Error,
18    io::{IsTerminal, stdin},
19    marker::PhantomData,
20};
21
22mod builtin;
23
24fn banner() {
25    println!("--- conlang v{} 💪🦈 ---", env!("CARGO_PKG_VERSION"))
26}
27
28fn clear() {
29    print!("\x1b[H\x1b[2J\x1b[3J");
30}
31
32fn main() -> Result<(), Box<dyn Error>> {
33    let mut verbose = Verbosity::from(std::env::var("DO_VERBOSE").as_deref().unwrap_or_default());
34    let mut parsing = ParseMode::from(std::env::var("DO_PARSING").as_deref().unwrap_or_default());
35    let mut env = builtin::get_env();
36    let color = parsing.color();
37    let begin = verbose.begin();
38    banner();
39
40    if stdin().is_terminal() {
41        read_and_mut(color, begin, "  > ", |rl, line| match line.trim_end() {
42            "" => Ok(Response::Continue),
43            "exit" => Ok(Response::Break),
44            "help" => {
45                println!("Parsing: {parsing:?} (expr, pat, bind, use, tokens)");
46                println!("Verbose: {verbose:?} (pretty, debug, quiet)");
47                Ok(Response::Deny)
48            }
49            "clear" => {
50                clear();
51                banner();
52                Ok(Response::Deny)
53            }
54            "macro" => {
55                if let Err(e) = subst() {
56                    println!("\x1b[31m{e}\x1b[0m");
57                }
58                Ok(Response::Accept)
59            }
60            line @ ("run" | "tokens" | "expr" | "pat" | "bind" | "use") => {
61                parsing = ParseMode::from(line);
62                println!("Parse mode set to '{parsing:?}'");
63                rl.set_color(parsing.color());
64                Ok(Response::Accept)
65            }
66            line @ ("quiet" | "debug" | "debugpretty" | "dp" | "frob" | "pretty") => {
67                verbose = Verbosity::from(line);
68                println!("Verbosity set to '{verbose:?}'");
69                rl.set_begin(verbose.begin());
70                Ok(Response::Accept)
71            }
72            _ if line.ends_with("\n\n") => {
73                parsing.with()(&mut env, line, verbose);
74                Ok(Response::Accept)
75            }
76            _ => Ok(Response::Continue),
77        })?;
78    } else {
79        let doc = std::io::read_to_string(stdin())?;
80        parsing.with()(&mut env, &doc, verbose);
81    }
82    Ok(())
83}
84
85fn subst() -> Result<(), Box<dyn Error>> {
86    let mut rl = repline::Repline::new("\x1b[35mexp", " >", "?>");
87    let exp = rl.read()?;
88    let exp: At<Expr> = Parser::new(Lexer::new("<interactive>".into(), &exp)).parse(0)?;
89    let mut exp = inline_modules(exp).0;
90    println!("\x1b[G\x1b[J{exp}");
91
92    rl.accept();
93
94    loop {
95        rl.set_color("\x1b[36mpat");
96        let pat = rl.read()?;
97        rl.accept();
98        print!("\x1b[G\x1b[J");
99        let mut p = Parser::new(Lexer::new("<interactive>".into(), &pat));
100
101        let Ok(pat) = p.parse::<Expr>(0) else {
102            println!("{exp}");
103            continue;
104        };
105
106        if p.next_if(TKind::Arrow).is_err() {
107            let Some(Subst { exp, pat }) = exp.match_with(&pat) else {
108                println!("Match failed: {exp} <- {pat}");
109                continue;
110            };
111            let mut pats: Vec<_> = pat.into_iter().collect();
112            pats.sort_by_key(|(a, _)| a.to_ref());
113            for (name, pat) in pats {
114                println!("{name}: {pat}")
115            }
116            let mut exprs: Vec<_> = exp.into_iter().collect();
117            exprs.sort_by_key(|(a, _)| a.to_ref());
118            for (name, expr) in exprs.iter() {
119                println!("{name}: {expr}")
120            }
121            continue;
122        }
123
124        let sub: Expr = p.parse(0)?;
125        if exp.apply_rule(&pat, &sub) {
126            println!("{exp}");
127        } else {
128            println!("No match: {pat} in {exp}\n")
129        }
130    }
131}
132
133fn plural(count: usize) -> &'static str {
134    match count {
135        1 => "",
136        _ => "s",
137    }
138}
139
140fn tokens<'e: 't, 't, T: Parse<'t> + ?Sized>(
141    _: &'e mut Environment,
142    document: &'t str,
143    verbose: Verbosity,
144) {
145    let _: PhantomData<T>; // for lifetime variance
146    let mut lexer = Lexer::new("<interactive>".into(), document);
147    loop {
148        match (lexer.scan(), verbose) {
149            (Err(LexError { res: EOF, .. }), _) => {
150                break;
151            }
152            (Err(e), _) => {
153                println!("\x1b[31m{e}\x1b[0m");
154                break;
155            }
156            (Ok(Token { lexeme, kind, span: Span { path: _, head, tail } }), Verbosity::Pretty) => {
157                println!("{kind:?}\x1b[11G {head:<4} {tail:<4} {lexeme:?}")
158            }
159            (Ok(token), Verbosity::Debug) => {
160                println!("{token:?}")
161            }
162            _ => {}
163        }
164    }
165}
166
167fn parse<'env: 't, 't, T>(_: &'env mut Environment, document: &'t str, verbose: Verbosity)
168where
169    T: Parse<'t>
170        + Annotation
171        + for<'a> Walk<'a, DefaultTypes>
172        + Foldable<DefaultTypes, DefaultTypes>,
173    <T as Foldable<DefaultTypes, DefaultTypes>>::Out: Annotation,
174{
175    let mut parser = Parser::new(Lexer::new("<interactive>".into(), document));
176    for idx in 0..6 {
177        match (
178            parser
179                .parse::<At<T, _>>(T::Prec::default())
180                .map(inline_modules),
181            verbose,
182        ) {
183            (Err(e @ ParseError::EOF(_)), _) => {
184                println!(
185                    "\x1b[92m{e} (total {} byte{}, {idx} expression{})\x1b[0m",
186                    document.len(),
187                    plural(document.len()),
188                    plural(idx),
189                );
190                break;
191            }
192            (Err(e), _) => {
193                println!("\x1b[91m{e}\x1b[0m");
194                break;
195            }
196            (Ok(At(expr, span)), Verbosity::Pretty) => {
197                println!("\x1b[{}m{span:?}:\n{expr}", (idx + 5) % 6 + 31);
198            }
199            // (Ok(At(expr, span)), Verbosity::Frob) => {
200            //     println!("\x1b[{}m{span}:\n", (idx + 5) % 6 + 31);
201            //     let _ = expr.visit_in(&mut Collector::new());
202            // }
203            (Ok(expr), Verbosity::Debug) => {
204                println!("\x1b[{}m{expr:?}", (idx + 5) % 6 + 31);
205            }
206            (Ok(expr), Verbosity::DebugPretty) => {
207                println!("\x1b[{}m{expr:#?}", (idx + 5) % 6 + 31);
208            }
209            _ => {}
210        }
211    }
212}
213
214fn run<'env: 't, 't>(env: &'env mut Environment, document: &'t str, verbose: Verbosity) {
215    let mut parser = Parser::new(Lexer::new("<interactive>".into(), document));
216    for idx in 0..6 {
217        match (
218            parser
219                .parse::<At<Expr>>(0)
220                .map(inline_modules)
221                .map(|expr| expr.interpret(env)),
222            verbose,
223        ) {
224            (Err(ParseError::EOF(_)), _) => break,
225            (Err(e), _) => {
226                println!("\x1b[91m{e}\x1b[0m");
227                break;
228            }
229            (Ok(Ok(ConValue::Empty)), Verbosity::Pretty) => {}
230            (Ok(Ok(value)), Verbosity::Pretty) => {
231                println!("\x1b[{}m{value}", (idx + 5) % 6 + 31);
232            }
233            (Ok(Err(error)), Verbosity::Pretty) => {
234                println!("\x1b[{}m{error}", (idx + 5) % 6 + 31);
235            }
236            (Ok(value), Verbosity::Debug) => {
237                println!("\x1b[{}m{value:?}", (idx + 5) % 6 + 31);
238            }
239            (Ok(value), Verbosity::DebugPretty) => {
240                println!("\x1b[{}m{value:#?}", (idx + 5) % 6 + 31);
241            }
242            _ => {}
243        }
244    }
245}
246
247fn inline_modules<T>(expr: At<T>) -> At<T::Out>
248where
249    T: Annotation + Foldable<DefaultTypes, DefaultTypes>,
250    T::Out: Annotation,
251{
252    let mut mi = ModuleInliner::new(".");
253    let At(expr, span) = expr;
254    let Ok(expr) = expr.fold_in(&mut mi);
255    if let Some((io_errs, parse_errs)) = mi.into_errs() {
256        for (path, err) in io_errs {
257            println!("{}: {err}", path.display());
258        }
259        for (path, err) in parse_errs {
260            println!("{}: {err}", path.display());
261        }
262    }
263
264    At(expr, span)
265}
266
267#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
268enum Verbosity {
269    #[default]
270    Pretty,
271    Debug,
272    DebugPretty,
273    Frob,
274    Quiet,
275}
276
277impl From<&str> for Verbosity {
278    fn from(value: &str) -> Self {
279        match value {
280            "quiet" | "false" | "0" | "no" => Verbosity::Quiet,
281            "debug" | "d" => Verbosity::Debug,
282            "debugpretty" | "debug_pretty" | "dp" => Verbosity::DebugPretty,
283            "frob" => Verbosity::Frob,
284            "pretty" => Verbosity::Pretty,
285            _ => Default::default(),
286        }
287    }
288}
289
290impl Verbosity {
291    fn begin(self) -> &'static str {
292        match self {
293            Self::Pretty => " .> ",
294            Self::Debug => " ?> ",
295            Self::DebugPretty => " #> ",
296            Self::Frob => "🐸> ",
297            Self::Quiet => " _> ",
298        }
299    }
300}
301
302#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
303enum ParseMode {
304    #[default]
305    Expr,
306    Pat,
307    Bind,
308    Use,
309    Tokens,
310    Run,
311}
312
313impl From<&str> for ParseMode {
314    fn from(value: &str) -> Self {
315        match value {
316            "expr" => Self::Expr,
317            "pat" => Self::Pat,
318            "bind" => Self::Bind,
319            "use" => Self::Use,
320            "tokens" => Self::Tokens,
321            "run" => Self::Run,
322            _ => Default::default(),
323        }
324    }
325}
326impl ParseMode {
327    fn with<'env: 'a, 'a>(&self) -> fn(&'env mut Environment, &'a str, Verbosity) {
328        match self {
329            Self::Expr => parse::<'env, 'a, Expr>,
330            Self::Pat => parse::<'env, 'a, Pat>,
331            Self::Bind => parse::<'env, 'a, Bind>,
332            Self::Use => parse::<'env, 'a, Use>,
333            Self::Tokens => tokens::<'env, 'a, dyn Parse<'a, Prec = ()>>,
334            Self::Run => run::<'env, 'a>,
335        }
336    }
337
338    fn color(&self) -> &'static str {
339        match self {
340            Self::Expr => "\x1b[36m",
341            Self::Pat => "\x1b[35m",
342            Self::Bind => "\x1b[34m",
343            Self::Use => "\x1b[33m",
344            Self::Tokens => "\x1b[32m",
345            Self::Run => "\x1b[31m",
346        }
347    }
348}