sipha 3.0.0

PEG parser, syntax trees, and code generation
Documentation
use crate::parse::{builder::BuiltGraph, insn::Insn};
use proc_macro2::TokenStream;
use quote::quote;

pub(super) fn quote_insns_table(graph: &BuiltGraph) -> TokenStream {
    let insns: Vec<TokenStream> = graph.insns.iter().map(insn_tokens).collect();
    quote! {
        static INSNS: &[Insn] = &[ #( #insns ),* ];
    }
}

#[allow(clippy::too_many_lines)]
fn insn_tokens(insn: &Insn) -> TokenStream {
    match insn {
        Insn::Byte { byte, on_fail } => quote! {
            Insn::Byte { byte: #byte, on_fail: #on_fail }
        },
        Insn::ByteEither { a, b, on_fail } => quote! {
            Insn::ByteEither { a: #a, b: #b, on_fail: #on_fail }
        },
        Insn::ByteIn3 { a, b, c, on_fail } => quote! {
            Insn::ByteIn3 { a: #a, b: #b, c: #c, on_fail: #on_fail }
        },
        Insn::ByteRange { lo, hi, on_fail } => quote! {
            Insn::ByteRange { lo: #lo, hi: #hi, on_fail: #on_fail }
        },
        Insn::Class {
            class,
            label_id,
            on_fail,
        } => {
            let [w0, w1, w2, w3] = class.0;
            quote! {
                Insn::Class {
                    class: CharClass([#w0, #w1, #w2, #w3]),
                    label_id: #label_id,
                    on_fail: #on_fail,
                }
            }
        }
        Insn::Literal { lit_id, on_fail } => quote! {
            Insn::Literal { lit_id: #lit_id, on_fail: #on_fail }
        },
        Insn::LiteralSmall {
            len,
            bytes,
            on_fail,
        } => {
            let [b0, b1, b2, b3, b4, b5, b6, b7] = *bytes;
            quote! {
                Insn::LiteralSmall { len: #len, bytes: [#b0, #b1, #b2, #b3, #b4, #b5, #b6, #b7], on_fail: #on_fail }
            }
        }
        Insn::EndOfInput { on_fail } => quote! {
            Insn::EndOfInput { on_fail: #on_fail }
        },
        Insn::AnyChar { on_fail } => quote! {
            Insn::AnyChar { on_fail: #on_fail }
        },
        Insn::Char { codepoint, on_fail } => quote! {
            Insn::Char { codepoint: #codepoint, on_fail: #on_fail }
        },
        Insn::CharRange { lo, hi, on_fail } => quote! {
            Insn::CharRange { lo: #lo, hi: #hi, on_fail: #on_fail }
        },
        Insn::Fail => quote! { Insn::Fail },
        Insn::Jump { target } => quote! {
            Insn::Jump { target: #target }
        },
        Insn::Call { rule } => quote! {
            Insn::Call { rule: #rule }
        },
        Insn::Return => quote! { Insn::Return },
        Insn::Choice { alt } => quote! {
            Insn::Choice { alt: #alt }
        },
        Insn::Commit { target } => quote! {
            Insn::Commit { target: #target }
        },
        Insn::BackCommit { target } => quote! {
            Insn::BackCommit { target: #target }
        },
        Insn::NegBackCommit { target } => quote! {
            Insn::NegBackCommit { target: #target }
        },
        Insn::PartialCommit { target } => quote! {
            Insn::PartialCommit { target: #target }
        },
        Insn::ByteDispatch { table_id } => quote! {
            Insn::ByteDispatch { table_id: #table_id }
        },
        Insn::ConsumeWhileClass {
            class,
            label_id,
            min,
            on_fail,
        } => {
            let [w0, w1, w2, w3] = class.0;
            quote! {
                Insn::ConsumeWhileClass {
                    class: CharClass([#w0, #w1, #w2, #w3]),
                    label_id: #label_id,
                    min: #min,
                    on_fail: #on_fail,
                }
            }
        }
        Insn::IfFlag { flag_id, on_fail } => quote! {
            Insn::IfFlag { flag_id: #flag_id, on_fail: #on_fail }
        },
        Insn::IfNotFlag { flag_id, on_fail } => quote! {
            Insn::IfNotFlag { flag_id: #flag_id, on_fail: #on_fail }
        },
        Insn::PushFlags { mask_id } => quote! {
            Insn::PushFlags { mask_id: #mask_id }
        },
        Insn::PopFlags => quote! { Insn::PopFlags },
        Insn::NodeBegin { kind, field } => {
            let field_ts = field.map_or_else(|| quote! { None }, |f| quote! { Some(#f) });
            quote! {
                Insn::NodeBegin { kind: #kind, field: #field_ts }
            }
        }
        Insn::NodeEnd => quote! { Insn::NodeEnd },
        Insn::TokenBegin { kind, is_trivia } => quote! {
            Insn::TokenBegin { kind: #kind, is_trivia: #is_trivia }
        },
        Insn::TokenEnd => quote! { Insn::TokenEnd },
        Insn::CaptureBegin { tag } => quote! {
            Insn::CaptureBegin { tag: #tag }
        },
        Insn::CaptureEnd { tag } => quote! {
            Insn::CaptureEnd { tag: #tag }
        },
        Insn::RecordExpectedLabel { label_id } => quote! {
            Insn::RecordExpectedLabel { label_id: #label_id }
        },
        Insn::PushDiagnosticContext { label_id } => quote! {
            Insn::PushDiagnosticContext { label_id: #label_id }
        },
        Insn::PopDiagnosticContext => quote! { Insn::PopDiagnosticContext },
        Insn::SetHint { hint_id } => {
            let id = hint_id.0;
            quote! { Insn::SetHint { hint_id: SymbolId(#id) } }
        }
        Insn::TracePoint { label_id } => {
            let id = label_id.0;
            quote! { Insn::TracePoint { label_id: SymbolId(#id) } }
        }
        Insn::RecoverUntil { sync_rule, resume } => quote! {
            Insn::RecoverUntil { sync_rule: #sync_rule, resume: #resume }
        },
        Insn::RecoveryResume => quote! { Insn::RecoveryResume },
        Insn::Accept => quote! { Insn::Accept },
    }
}