tin 0.3.0

tin: a statically structurally typed embeddable programming language
Documentation
use lalrpop_util;

use crate::ast;
use crate::parser;

grammar<'err>(span: codespan::ByteSpan, errors: &'err mut Vec<lalrpop_util::ParseError<usize, Token<'input>, parser::Error>>);

extern {
    type Error = parser::Error;
}

match {
    r"(?x)
      (
        (?:0|[1-9]\d*)?(?:u8|u16|u32|u64) | # unsigned integral numbers
        (?:-?(?:0|[1-9]\d*))?(?:i8|i16|i32|i64) | # signed integral numbers
        (?:-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)?(?:f32|f64) # fractional numbers
      )" => NumberValue,
} else {
    r"/\*(\*[^/]|[^*])*\*/" => Comment,
    r"\p{XID_Start}\p{XID_Continue}*" => IdentifierName,
    r":\p{XID_Start}\p{XID_Continue}*" => SymbolLabel,
    r#""(?:[^"\\]|\\.)*""# => StringValue,
    _
}

#[inline]
Comma0<A>: Vec<A> = {
    <v:(<A> ",")*> <e: A?> => {
        let mut v = v;
        v.extend(e);
        v
    },
}

#[inline]
Comma1<A>: Vec<A> = {
    <v:(<A> ",")+> <e: A?> => {
        let mut v = v;
        v.extend(e);
        v
    },
}

#[inline]
Semi0<A>: Vec<A> = {
    <v:(<A> ";")*> <e: A> => {
        let mut v = v;
        v.push(e);
        v
    },
}

#[inline]
SemiRequired0<A>: Vec<A> = {
    <(<A> ";")*> => <>,
}

pub Module: ast::Module<parser::Context> = {
    <lo:@L> <ds:SemiRequired0<(Comment? <Definition>)>> <hi:@R> =>
        ast::Module { context: parser::Context::new(ast::Kind::Module, span, lo, hi), variables: ds },
}

Definition: ast::Variable<parser::Context> = {
    <lo:@L> <n:Identifier> "=" <i:Expression> <hi:@R> =>
        ast::Variable { context: parser::Context::new(ast::Kind::Variable, span, lo, hi), name: n, initializer: i },
}

pub Expression = { <ExpressionBiOpOr> }

// Left-to-right evaluation
ExpressionBiOpOr: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpOr, BiOperatorOr, ExpressionBiOpXor> => ast::Expression::BiOp(<>),
    ExpressionBiOpXor => <>,
}

// Left-to-right evaluation
ExpressionBiOpXor: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpXor, BiOperatorXor, ExpressionBiOpAnd> => ast::Expression::BiOp(<>),
    ExpressionBiOpAnd => <>,
}

// Left-to-right evaluation
ExpressionBiOpAnd: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpAnd, BiOperatorAnd, ExpressionBiOpCmp> => ast::Expression::BiOp(<>),
    ExpressionBiOpCmp => <>,
}

// No associativity; require parenthesis
ExpressionBiOpCmp: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpBOr, BiOperatorCmp, ExpressionBiOpBOr> => ast::Expression::BiOp(<>),
    ExpressionBiOpBOr => <>,
}

// Left-to-right evaluation
ExpressionBiOpBOr: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpBOr, BiOperatorBOr, ExpressionBiOpBXor> => ast::Expression::BiOp(<>),
    ExpressionBiOpBXor => <>,
}

// Left-to-right evaluation
ExpressionBiOpBXor: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpBXor, BiOperatorBXor, ExpressionBiOpBAnd> => ast::Expression::BiOp(<>),
    ExpressionBiOpBAnd => <>,
}

// Left-to-right evaluation
ExpressionBiOpBAnd: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpBAnd, BiOperatorBAnd, ExpressionBiOpShift> => ast::Expression::BiOp(<>),
    ExpressionBiOpShift => <>,
}

// Left-to-right evaluation
ExpressionBiOpShift: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpShift, BiOperatorShift, ExpressionBiOpSum> => ast::Expression::BiOp(<>),
    ExpressionBiOpSum => <>,
}

// Left-to-right evaluation
ExpressionBiOpSum: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpSum, BiOperatorSum, ExpressionBiOpFactor> => ast::Expression::BiOp(<>),
    ExpressionBiOpFactor => <>,
}

// Left-to-right evaluation
ExpressionBiOpFactor: ast::Expression<parser::Context> = {
    BiOp<ExpressionBiOpFactor, BiOperatorFactor, ExpressionUnOp> => ast::Expression::BiOp(<>),
    ExpressionUnOp => <>,
}

ExpressionUnOp: ast::Expression<parser::Context> = {
    UnOp => ast::Expression::UnOp(<>),
    ExpressionProjection => <>,
}

ExpressionProjection: ast::Expression<parser::Context> = {
    Select => ast::Expression::Select(<>),
    Apply => ast::Expression::Apply(<>),
    ExpressionAtom => <>,
}

ExpressionAtom: ast::Expression<parser::Context> = {
    Identifier => ast::Expression::Identifier(<>),
    NumberLiteral => ast::Expression::NumberLiteral(<>),
    StringLiteral => ast::Expression::StringLiteral(<>),
    Symbol => ast::Expression::Symbol(<>),
    Tuple => ast::Expression::Tuple(<>),
    Record => ast::Expression::Record(<>),
    Lambda => ast::Expression::Lambda(<>),
    "(" <Expression> ")" => <>,
    ! => { errors.push(<>.error); ast::Expression::Unknown },
}

UnOperator: ast::UnOperator = {
    "!" => ast::UnOperator::Not,
    "~!" => ast::UnOperator::BNot,
    "#^0" => ast::UnOperator::Cl0,
    "#^1" => ast::UnOperator::Cl1,
    "#^-" => ast::UnOperator::Cls,
    "#$0" => ast::UnOperator::Ct0,
    "#$1" => ast::UnOperator::Ct1,
    "#0" => ast::UnOperator::C0,
    "#1" => ast::UnOperator::C1,
    "^/" => ast::UnOperator::Sqrt,
}

UnOp: ast::UnOp<parser::Context> = {
    <lo:@L> <operator:UnOperator> <operand:ExpressionUnOp> <hi:@R> =>
       ast::UnOp { context: parser::Context::new(ast::Kind::UnOp, span, lo, hi), operator, operand: Box::new(operand) },
}

#[inline]
BiOp<L, O, R>: ast::BiOp<parser::Context> = {
    <lo:@L> <lhs:L> <operator:O> <rhs:R> <hi:@R> =>
       ast::BiOp { context: parser::Context::new(ast::Kind::BiOp, span, lo, hi), lhs: Box::new(lhs), operator, rhs: Box::new(rhs) },
}

BiOperatorFactor: ast::BiOperator = {
    "*" => ast::BiOperator::Mul,
    "/" => ast::BiOperator::Div,
    "%" => ast::BiOperator::Rem,
}

BiOperatorSum: ast::BiOperator = {
    "+" => ast::BiOperator::Add,
    "-" => ast::BiOperator::Sub,
}

BiOperatorShift: ast::BiOperator = {
    "<-<" => ast::BiOperator::RotL,
    ">->" => ast::BiOperator::RotR,
    "<<" => ast::BiOperator::ShL,
    ">>" => ast::BiOperator::ShR,
}

BiOperatorBAnd: ast::BiOperator = {
    "~&" => ast::BiOperator::BAnd,
    "~&!" => ast::BiOperator::BAndNot,
}

BiOperatorBOr: ast::BiOperator = {
    "~|" => ast::BiOperator::BOr,
    "~|!" => ast::BiOperator::BOrNot,
}

BiOperatorBXor: ast::BiOperator = {
    "~^" => ast::BiOperator::BXor,
    "~^!" => ast::BiOperator::BXorNot,
}

BiOperatorAnd: ast::BiOperator = {
    "&" => ast::BiOperator::And,
    "&!" => ast::BiOperator::AndNot,
}

BiOperatorOr: ast::BiOperator = {
    "|" => ast::BiOperator::Or,
    "|!" => ast::BiOperator::OrNot,
}

BiOperatorXor: ast::BiOperator = {
    "^" => ast::BiOperator::Xor,
    "^!" => ast::BiOperator::XorNot,
}

BiOperatorCmp: ast::BiOperator = {
    "==" => ast::BiOperator::Eq,
    "!=" => ast::BiOperator::Ne,
    "<" => ast::BiOperator::Lt,
    ">=" => ast::BiOperator::Ge,
    ">" => ast::BiOperator::Gt,
    "<=" => ast::BiOperator::Le,
    "<=>" => ast::BiOperator::Cmp,
}

Identifier: ast::Identifier<parser::Context> = {
    <lo:@L> <id:IdentifierName> <hi:@R> =>
        ast::Identifier { context: parser::Context::new(ast::Kind::Identifier, span, lo, hi), value: id.into() },
}

Tuple: ast::Tuple<parser::Context> = {
    <lo:@L> "(" ")" <hi:@R> =>
        ast::Tuple { context: parser::Context::new(ast::Kind::Tuple, span, lo, hi), fields: vec![] },
    <lo:@L> "(" <fs:Comma1<Expression>> ")" <hi:@R> =>
        ast::Tuple { context: parser::Context::new(ast::Kind::Tuple, span, lo, hi), fields: fs },
}

Record: ast::Record<parser::Context> = {
    <lo:@L> "{" <fs:Comma0<Field>> "}" <hi:@R> =>
        ast::Record { context: parser::Context::new(ast::Kind::Record, span, lo, hi), fields: fs },
}

Field: (ast::Identifier<parser::Context>, ast::Expression<parser::Context>) = {
     <Identifier> ":" <Expression> => (<>),
}

NumberLiteral: ast::NumberLiteral<parser::Context> = {
    <lo:@L> <v:NumberValue> <hi:@R> =>
        ast::NumberLiteral {
            context: parser::Context::new(ast::Kind::NumberLiteral, span, lo, hi),
            value: parser::util::parse_number_literal(span, lo, hi, v, errors),
        },
}

StringLiteral: ast::StringLiteral<parser::Context> = {
    <lo:@L> <v:StringValue> <hi:@R> =>
        ast::StringLiteral { context: parser::Context::new(ast::Kind::StringLiteral, span, lo, hi), value: parser::util::parse_escaped_string(span, lo, hi, v, errors) },
}

Symbol: ast::Symbol<parser::Context> = {
    <lo:@L> <label:SymbolLabel> <hi:@R> =>
        ast::Symbol { context: parser::Context::new(ast::Kind::Symbol, span, lo, hi), label: (&label[1..]).to_owned() },
}

Lambda: ast::Lambda<parser::Context> = {
    <lo:@L> "|" <params:Comma0<(Comment? <Parameter>)>> "|" <sig:Expression?> "{" <stmts:SemiRequired0<(Comment? <Statement>)>> <res:(Comment? <Expression>)> "}" <hi:@R> =>
        ast::Lambda { context: parser::Context::new(ast::Kind::Lambda, span, lo, hi), parameters: params, signature: sig.map(Box::new), statements: stmts, result: Box::new(res) },
}

Statement: ast::Statement<parser::Context> = {
    <Definition> => ast::Statement::Variable(<>),
    <Expression> => ast::Statement::Expression(<>),
}

Select: ast::Select<parser::Context> = {
    <lo:@L> <r:ExpressionProjection> "." <f:Identifier> <hi:@R> =>
        ast::Select { context: parser::Context::new(ast::Kind::Select, span, lo, hi), record: Box::new(r), field: f },
}

Apply: ast::Apply<parser::Context> = {
    <lo:@L> <e:ExpressionProjection> "(" <p:Comma0<Expression>> ")" <hi:@R> =>
        ast::Apply { context: parser::Context::new(ast::Kind::Apply, span, lo, hi), function: Box::new(e), parameters: p },
}

Parameter: ast::Parameter<parser::Context> = {
    <lo:@L> <name:Identifier> <signature:(":" <ExpressionAtom>)?> <hi:@R> =>
        ast::Parameter { context: parser::Context::new(ast::Kind::Parameter, span, lo, hi), name, signature },
}