oak 0.8.0

A typed parser generator syntax extension for Parsing Expression Grammar (PEG).
Documentation
// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// We compile in a bottom-up manner. For example, in `"let" . / "fn" id`, the expression `id` is compiled first, then `"fn"` and then the first branch. We use the trait `CompileExpr` for implementing the compiler of a new combinator. Its method `compile_expr` takes two parameters, the first one is the `context` and the second is the continuation `cont`. The advantage of the bottom-up compilation is that, when compiling a combinator, this combinator can control the future with `cont`. The continuation `cont` contains two attributes: `success` and `failure` representing what has to be done in case of success or failure of the current compiled combinator.

pub mod rtype;
pub mod value;
mod grammar;
mod rule;
mod str_literal;
mod sequence;
mod choice;
mod any_single_char;
mod repeat;
mod optional;
mod syntactic_predicate;
mod character_class;
mod non_terminal;
mod semantic_action;
mod spanned_expr;

pub use quote::quote;
pub use syn::parse_quote;

pub use back::compiler::grammar::*;
pub use back::context::*;
use back::compiler::str_literal::*;
use back::compiler::sequence::*;
use back::compiler::choice::*;
use back::compiler::any_single_char::*;
use back::compiler::repeat::*;
use back::compiler::optional::*;
use back::compiler::syntactic_predicate::*;
use back::compiler::character_class::*;
use back::compiler::non_terminal::*;
use back::compiler::semantic_action::*;
use back::compiler::spanned_expr::*;

pub enum CompilerKind
{
  Recognizer,
  Parser
}

pub trait CompileExpr
{
  fn compile_expr<'a>(&self, context: &mut Context<'a>, cont: Continuation) -> syn::Expr;
}

pub type ExprCompilerFn = fn(&TGrammar, usize) -> Box<dyn CompileExpr>;

pub fn parser_compiler(grammar: &TGrammar, idx: usize) -> Box<dyn CompileExpr> {
  if grammar[idx].ty == Type::Unit {
    recognizer_compiler(grammar, idx)
  }
  else {
    match grammar.expr_by_index(idx) {
      StrLiteral(lit) => Box::new(StrLiteralCompiler::parser(lit)),
      CharacterClass(classes) => Box::new(CharacterClassCompiler::parser(classes)),
      AnySingleChar => Box::new(AnySingleCharCompiler::parser()),
      Sequence(seq) => Box::new(SequenceCompiler::parser(seq)),
      Choice(choices) => Box::new(ChoiceCompiler::parser(choices)),
      ZeroOrOne(expr_idx) => Box::new(OptionalCompiler::parser(expr_idx)),
      ZeroOrMore(expr_idx) => Box::new(RepeatCompiler::parser(expr_idx, 0)),
      OneOrMore(expr_idx) => Box::new(RepeatCompiler::parser(expr_idx, 1)),
      NonTerminalSymbol(id) => Box::new(NonTerminalCompiler::parser(id, idx)),
      ExternalNonTerminalSymbol(path) => Box::new(NonTerminalCompiler::external_parser(path, idx)),
      SemanticAction(expr_idx, boxed, action) => Box::new(SemanticActionCompiler::parser(expr_idx, boxed, action, idx)),
      TypeAscription(expr_idx, _) => parser_compiler(grammar, expr_idx),
      SpannedExpr(expr_idx) => Box::new(SpannedExprCompiler::parser(expr_idx, false)),
      RangeExpr(expr_idx) => Box::new(SpannedExprCompiler::parser(expr_idx, true)),
      NotPredicate(_)
    | AndPredicate(_) => unreachable!(
        "BUG: Syntactic predicate can not be compiled to parser (they do not generate data)."),
    }
  }
}

pub fn recognizer_compiler(grammar: &TGrammar, idx: usize) -> Box<dyn CompileExpr> {
  match grammar.expr_by_index(idx) {
    StrLiteral(lit) => Box::new(StrLiteralCompiler::recognizer(lit)),
    CharacterClass(classes) => Box::new(CharacterClassCompiler::recognizer(classes)),
    AnySingleChar => Box::new(AnySingleCharCompiler::recognizer()),
    Sequence(seq) => Box::new(SequenceCompiler::recognizer(seq)),
    Choice(choices) => Box::new(ChoiceCompiler::recognizer(choices)),
    ZeroOrOne(expr_idx) => Box::new(OptionalCompiler::recognizer(expr_idx)),
    ZeroOrMore(expr_idx) => Box::new(RepeatCompiler::recognizer(expr_idx, 0)),
    OneOrMore(expr_idx) => Box::new(RepeatCompiler::recognizer(expr_idx, 1)),
    NotPredicate(expr_idx) => Box::new(SyntacticPredicateCompiler::recognizer(expr_idx, Kind::Not)),
    AndPredicate(expr_idx) => Box::new(SyntacticPredicateCompiler::recognizer(expr_idx, Kind::And)),
    NonTerminalSymbol(id) => Box::new(NonTerminalCompiler::recognizer(id)),
    ExternalNonTerminalSymbol(path) => Box::new(NonTerminalCompiler::external_recognizer(path)),
      SemanticAction(expr_idx, _, _)
    | TypeAscription(expr_idx, _)
    | SpannedExpr(expr_idx)
    | RangeExpr(expr_idx) => recognizer_compiler(grammar, expr_idx),
  }
}