pt_html/
pt_html.rs

1use regen::core::LangBuilder;
2use regen::grammar::{self, Tok};
3use regen::sdk::{
4    ASTParser, CreateParseTree, ParseTreeResultSemantic, TokenBlocks, TokenStream, TokenType,
5};
6use std::fs;
7
8fn main() {
9    // This example parses regen.grammar, and prints html code with prismjs classes
10
11    // This example is ran from the `docs` directory
12    let grammar_source = fs::read_to_string("../regen.grammar").unwrap();
13
14    // These is a wrapper regen::parse_language_from_grammar that creates
15    // a Language object from a grammar string. However, it does not store
16    // semantic info, so we can't use that here.
17
18    // Run tokenizer
19    let lex_output = grammar::tokenize(&grammar_source);
20
21    // Create token stream
22    // 200 is the stack size, meaning the AST can have depth <= 200
23    // which is plenty. The default stack size for CLI is 2048
24    let mut ts = TokenStream::new(&lex_output.tokens, 200);
25
26    // Generate AST (need the ASTParser trait)
27    let parser = grammar::Parser;
28    let asts = parser.parse_ast_all(&mut ts).unwrap(); // error if syntax error
29
30    // collect semantic info so far
31    let mut outer_tbs = TokenBlocks::new(&grammar_source);
32    lex_output.apply_semantic(&mut outer_tbs);
33    asts.iter()
34        .for_each(|ast| ast.apply_semantic(&mut outer_tbs, &None));
35
36    // Generate PT, because it fills in additional semantic info
37    // This requires a lang builder as a context, but we won't need it
38    let mut lang_builder: Box<LangBuilder> = Box::default();
39    for ast in &asts {
40        // if you don't need semantic you can use the parse_pt method
41        match ast.parse_pt_with_semantic(outer_tbs, lang_builder) {
42            ParseTreeResultSemantic::Ok { /*pt*/ ctx, tbs, .. } => {
43                outer_tbs = tbs;
44                lang_builder = ctx;
45            },
46            ParseTreeResultSemantic::Err { .. /*pt, ctx, tbs, err*/ } => {
47                // should not happen, but you also get the context and semantic info back here
48                unreachable!();
49            }
50        }
51    }
52
53    // now we have the semantic info in outer_tbs, we can convert it to HTML
54
55    let code = outer_tbs.get_html(to_prismjs);
56
57    println!("{}", code);
58}
59
60fn to_prismjs(t: Tok) -> String {
61    match t {
62        Tok::TComment => "token comment".to_owned(),
63        Tok::TKeyword => "token keyword".to_owned(),
64        Tok::TIdentifier => "".to_owned(),
65        Tok::TRegExp => "token regex".to_owned(),
66        Tok::TLiteral => "token string".to_owned(),
67        Tok::TSymbol => "token punctuation".to_owned(),
68        Tok::SToken => "token tag".to_owned(),
69        Tok::SVariable => "token attr-name".to_owned(),
70        Tok::SRule => "token class-name".to_owned(),
71        Tok::SSemantic => "token tag".to_owned(),
72        Tok::SHookName => "token function".to_owned(),
73        Tok::SHookType => "token regex".to_owned(),
74        Tok::SContextType => "token tag".to_owned(),
75        Tok::Decor { tag, base } => format!("{} {}", tag, to_prismjs(*base)),
76        _ => t.html_class().unwrap_or_default(),
77    }
78}