reqlang-expr 0.9.0

A tiny (bytecode compiled, stack VM interpreted) expression language for reqlang's templating engine.
Documentation
//! Parser and associated types

use crate::errors::{ExprErrorS, SyntaxError};
use crate::ast;
use crate::lexer::Token;
use crate::span::Spanned;

grammar<'err>(source: &str, errors: &'err mut Vec<ExprErrorS>);

pub Expr: ast::Expr = {
    ExprIdentifier,
    ExprCall,
    ExprString,
    ExprNumber,
    ExprBool,
    <e:!> => {
        errors.push(SyntaxError::from_parser_error(e.error, source));
        ast::Expr::Error
    }
};

// Boolean Expressions

ExprBool: ast::Expr = {
    "true" => ast::Expr::Bool(ast::ExprBool(true).into()),
    "false" => ast::Expr::Bool(ast::ExprBool(false).into()),
};

// Number Expressions

ExprNumber: ast::Expr = {
    number => ast::Expr::Number(ast::ExprNumber(<>).into())
};

// String Expressions

ExprString: ast::Expr = {
    string => ast::Expr::String(ast::ExprString(<>).into())
};

// Call Expressions

CallCallee = ExprS;
CallArgs = Args<ExprS>;
ExprCall: ast::Expr = {
    "(" <callee:CallCallee> <args:CallArgs> ")" => ast::Expr::Call(ast::ExprCall {
        callee: callee.into(),
        args
    }.into())
}

// Identifier Expressions

ExprIdentifier: ast::Expr = {
    <name:identifier> =>
        ast::Expr::Identifier(ast::ExprIdentifier::new(&name).into()),
    <ty:ty> =>
       ast::Expr::Identifier(ast::ExprIdentifier::new(&ty).into()),
    <ty:ty> "<" <subty:ty> ">" =>
        ast::Expr::Identifier(ast::ExprIdentifier::new(&format!("{}<{}>", ty, subty)).into()),
    "Fn" "(" <args:Seperated<ty, ",">> ")" "->" <return_ty:ty> => {
        let id = format!("Fn({}) -> {}", args.join(", "), return_ty);

        ast::Expr::Identifier(ast::ExprIdentifier::new(&id).into())
    },
    "Fn" "(" <args:Seperated<ty, ",">> "," "..." <varg:ty> ")" "->" <return_ty:ty> => {
        let id = format!("Fn({}, ...{}) -> {}", args.join(", "), varg, return_ty);

        ast::Expr::Identifier(ast::ExprIdentifier::new(&id).into())
    },
    "Fn" "(" "..." <varg:ty> ")" "->" <return_ty:ty> => {
        let id = format!("Fn(...{}) -> {}", varg, return_ty);

        ast::Expr::Identifier(ast::ExprIdentifier::new(&id).into())
    },
}

// Utility Types

ExprS = Spanned<Expr>;

Spanned<T>: Spanned<T> = <l:@L> <t:T> <r:@R> =>
    (t, l..r);

#[inline]
Args<E>: Vec<E> = {
    <first:E> <mut args:(<E>)*> => {
        args.insert(0, first);
        args
    },
    () => Vec::new(),
}

#[inline]
Seperated<E, T>: Vec<E> = {
    <first:E> <mut args:(T <E>)*> => {
        args.insert(0, first);
        args
    },
    () => Vec::new(),
}

extern {
    type Location = usize;
    type Error = ExprErrorS;

    enum Token {
        "(" => Token::LParan,
        ")" => Token::RParan,
        "," => Token::Comma,
        "<" => Token::LAngle,
        ">" => Token::RAngle,
        "->" => Token::Arrow,
        "Fn" => Token::Fn,
        "..." => Token::ThreeDot,
        "true" => Token::True,
        "false" => Token::False,
        string => Token::String(<String>),
        number => Token::Number(<f64>),
        identifier => Token::Identifier(<String>),
        ty => Token::Type(<String>)
    }
}