Skip to content
Snippets Groups Projects
forge_grammar.lalrpop 7.62 KiB
Newer Older
Louis's avatar
Louis committed
use crate::lexer::ScriptTokenType;
use crate::parser::ast::*;
use crate::runtime::numbers::Number;

grammar<'a>;

pub Program: Program = {
    ExpressionList => Program(<>)
};

Block: Option<ExpressionList> = {
    "{" <ExpressionList?> "}" => <>,
};

ExpressionList: ExpressionList = {
Louis's avatar
Louis committed
    <e:Expression> <b:";"?> => {
        ExpressionList {
            expressions: vec![e],
            is_void: b.is_some(),
        }
    },
    <e:Expression> ";" <mut ls:ExpressionList> => {
        let mut new = vec![e];
        new.append(&mut ls.expressions);

        ExpressionList {
            expressions: new,
            is_void: ls.is_void,
Louis's avatar
Louis committed
pub Expression: Expression = {
    ValueExpression => Expression::Value(<>),
    VoidExpression => Expression::Void(<>),
};

VoidExpression: VoidExpression = {
Louis's avatar
Louis committed
    AsVoid<PrintStmt> => <>,
    AsVoid<ImportStmt> => <>,
    AsVoid<ExportStmt> => <>,
Louis's avatar
Louis committed

ValueExpression: ValueExpression = {
Louis's avatar
Louis committed
    AsValue<Literal> => <>,
    AsValue<Identifier> => <>,
    AsValue<IfStatement> => <>,
    "(" <lhs:ValueExpression> "+" <rhs:ValueExpression> ")" => ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Add },
Louis's avatar
Louis committed
    "typeof" <expr:ValueExpression> => TypeofValue(Box::new(expr)).into(),
    "-" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Negate },
    "!" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Not },
Louis's avatar
Louis committed
    "(" <expr:ValueExpression> ")" => GroupedExpression { inner: Box::new(expr) }.into(),
}
Louis's avatar
Louis committed

Louis's avatar
Louis committed
//ValueExpression: ValueExpression = {
//    #[precedence(level="100")]
//    "(" <expr:ValueExpression> ")" => GroupedExpression { inner: Box::new(expr) }.into(),
//    #[precedence(level="0")]
//    Literal => ValueExpression::Literal(<>),
//    #[precedence(level="0")]
//    Identifier => <>.into(),
//
//    #[precedence(level="2")]
//    "typeof" <expr:ValueExpression> => TypeofValue(Box::new(expr)).into(),
//    #[precedence(level="2")]
//    "-" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Negate },
//    #[precedence(level="2")]
//    "!" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Not },
//
//    #[precedence(level = "3")]
//    IfStatement => <>.into(),
//
//    #[precedence(level="4")] #[assoc(side="left")]
//    <lhs:ValueExpression> "*" <rhs:ValueExpression> => {
//        ValueExpression::Binary {
//            lhs: Box::new(lhs),
//            rhs: Box::new(rhs),
//            operator: BinaryOp::Multiply,
//        }
//    },
//    #[precedence(level="4")] #[assoc(side="left")]
//    <lhs:ValueExpression> "/" <rhs:ValueExpression> => {
//        ValueExpression::Binary {
//            lhs: Box::new(lhs),
//            rhs: Box::new(rhs),
//            operator: BinaryOp::Divide,
//        }
//    },
//    #[precedence(level="6")] #[assoc(side="left")]
//    <lhs:ValueExpression> "+" <rhs:ValueExpression> => {
//        ValueExpression::Binary {
//            lhs: Box::new(lhs),
//            rhs: Box::new(rhs),
//            operator: BinaryOp::Add,
//        }
//    },
//    #[precedence(level="6")] #[assoc(side="left")]
//    <lhs:ValueExpression> "-" <rhs:ValueExpression> => {
//        ValueExpression::Binary {
//            lhs: Box::new(lhs),
//            rhs: Box::new(rhs),
//            operator: BinaryOp::Subtract,
//        }
//    },
//};
Louis's avatar
Louis committed
AsVoid<R>: VoidExpression = {
    R => <>.into()
}
AsValue<R>: ValueExpression = {
    R => <>.into()
}
Louis's avatar
Louis committed
TypeofStmt: TypeofValue = {
    "typeof" <ValueExpression> => TypeofValue(Box::new(<>))
}

PrintStmt: Print = {
    "print" <expr:ValueExpression> => Print { expr: Box::new(expr) },
}
ImportStmt: Import = {
    "import" "{" <items:IdentifierList> "}" "from" <source:StringValue> => Import { source, items },
}
ExportStmt: Export = {
    "export" "{" <items:IdentifierList> "}" => Export { items },
}

IfStatement: Conditional = {
    BareIfStatement => Conditional { blocks: vec![<>], fallback: None },
Louis's avatar
Louis committed
    <fi:BareIfStatement> "else" <bl:Block> => Conditional { blocks: vec![fi], fallback: bl },
    <fi:BareIfStatement> "else" <ls:IfStatement> => {
        let mut ls = ls;
        let mut new = vec![fi];
        new.append(&mut ls.blocks);
        Conditional {
            blocks: new,
            fallback: ls.fallback,
        }
    }
};

BareIfStatement: GuardedBlock = {
    "if" <guard:ValueExpression> <bl:Block> => {
        GuardedBlock {
            block: bl.unwrap_or_default(),
            guard: Box::new(guard),
        }
    }
};

ParameterList = ListOf<ValueExpression>;
IdentifierList = ListOf<IdentifierNode>;

IdentifierNode: IdentifierNode = {
    IdentifierAlias => IdentifierNode::Alias(<>),
    Identifier => IdentifierNode::Direct(<>),
};

IdentifierAlias: IdentifierAlias = {
    <base:Identifier> "as" <alias:Identifier> => IdentifierAlias(base.0, alias.0),
};

Identifier: Identifier = {
    "identifier" => Identifier(String::from(<>))
};
Louis's avatar
Louis committed

Literal: LiteralNode = {
    "boolean" => LiteralNode::Boolean(<>),
    "null" => LiteralNode::Null,
    "float" => LiteralNode::Number(Number::Float(<>)),
    "integer" => LiteralNode::Number(Number::Integer(<>)),
    "string" => LiteralNode::String(String::from(<>)),
    "owned_string" => LiteralNode::String(<>),
Louis's avatar
Louis committed

StringValue: String = {
    "string" => String::from(<>),
    "owned_string" => <>,
};

ListOf<T>: Vec<T> = {
    <mut v:(<T> ",")+> <e:T?> => match e {
        None => v,
        Some(e) => {
            v.push(e);
            v
        }
    }
};
Louis's avatar
Louis committed

extern {
    type Location = usize;
Louis's avatar
Louis committed
    type Error = String;
Louis's avatar
Louis committed

Louis's avatar
Louis committed
    enum ScriptTokenType {
Louis's avatar
Louis committed
        "(" => ScriptTokenType::LeftParen,
        ")" => ScriptTokenType::RightParen,
        "{" => ScriptTokenType::LeftBrace,
        "}" => ScriptTokenType::RightBrace,
        "," => ScriptTokenType::Comma,
        "." => ScriptTokenType::Dot,
        "-" => ScriptTokenType::Minus,
        "+" => ScriptTokenType::Plus,
        ";" => ScriptTokenType::Semicolon,
        "/" => ScriptTokenType::Slash,
        "*" => ScriptTokenType::Asterisk,
        "!" => ScriptTokenType::Bang,
        "!=" => ScriptTokenType::BangEqual,
        "=" => ScriptTokenType::Equal,
        "==" => ScriptTokenType::EqualEqual,
        ">" => ScriptTokenType::Greater,
        ">=" => ScriptTokenType::GreaterEqual,
        "<" => ScriptTokenType::Less,
        "<=" => ScriptTokenType::LessEqual,
        "||" => ScriptTokenType::DoublePipe,
        "&&" => ScriptTokenType::DoubleAmpersand,
        "%" => ScriptTokenType::Modulo,
        "^" => ScriptTokenType::Caret,
        "struct" => ScriptTokenType::Class,
        "else" => ScriptTokenType::Else,
        "fn" => ScriptTokenType::Function,
        "for" => ScriptTokenType::For,
        "if" => ScriptTokenType::If,
        "null" => ScriptTokenType::Null,
        "print" => ScriptTokenType::Print,
        "return" => ScriptTokenType::Return,
        "super" => ScriptTokenType::Super,
        "this" => ScriptTokenType::This,
        "let" => ScriptTokenType::Let,
        "while" => ScriptTokenType::While,
        "export" => ScriptTokenType::Export,
        "import" => ScriptTokenType::Import,
        "as" => ScriptTokenType::Alias,
        "from" => ScriptTokenType::From,
        "typeof" => ScriptTokenType::Typeof,
        "finally" => ScriptTokenType::Finally,
        "boolean" => ScriptTokenType::Boolean(<bool>),
        "float" => ScriptTokenType::Float(<f64>),
        "integer" => ScriptTokenType::Integer(<i64>),
        "owned_string" => ScriptTokenType::OwnedString(<String>),
Louis's avatar
Louis committed
        "string" => ScriptTokenType::String(<String>),
        "identifier" => ScriptTokenType::Identifier(<String>),
Louis's avatar
Louis committed
    }
}