1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! # About
//!
//! `zypo-parser` is the primary parser implementation for the `zypo-rs`
//! reference compiler. This package uses the [LALRPOP](https://github.com/lalrpop/lalrpop)
//! library, a yacc-like `LR(1)` parser combiner for Rust. This crate also
//! contains the AST (*abstract-syntax-tree*) for Zypo and all public AST structures,
//! enums and associated functions are avalible at the base-level of this crate.
//!
//! *Please beware as this package is heavily work-in-progress and is developed
//! alongside the main Zypo compiler as a sub-package. If you are looking for
//! the base `zypo-rs` compiler, you may find it
//! [here](https://gitlab.com/zypo/zypo-rs)*.
//!
//! # Examples
//!
//! Shortcut for parsing an AST or panicing if there is an error in any of the
//! given input:
//!
//! ```rust
//! use zypo_parser::{
//!     Function,
//!     VarType,
//!     Parameter,
//!     ast_result
//! }; // All but ast_result are from the AST. ast_result is the shortcut func
//!
//! fn main() {
//!     let input = "fun shortcut_test_func(my_param: int) {}";
//!     let expected = vec![
//!         Function {
//!             ident: "shortcut_test_func".to_string(),
//!             params: vec![
//!                 Parameter { ident: "my_param".to_string(), ty: VarType::Int }
//!             ],
//!             body: vec![],
//!             return_type: VarType::Void
//!         }
//!     ];
//!
//!     assert_eq!(ast_result(input), expected);
//! }
//! ```
//!
//! More controllable but lower-level `LALRPOP` bind for manually handling the
//! generated parsing errors:
//!
//! ```rust
//! use zypo_parser::{
//!     Function,
//!     VarType,
//!     parser
//! }; // Function and VarType are from the AST, parser is generated by LALRPOP
//!
//! fn main() {
//!     let input = "fun test_func() {}";
//!     let expected = vec![
//!         Function {
//!             ident: "test_func".to_string(),
//!             params: vec![],
//!             body: vec![],
//!             return_type: VarType::Void
//!         }
//!     ];
//!
//!     assert_eq!(parser::GrammarParser::new().parse(input).unwrap(), expected);
//! }
//! ```

#[macro_use]
extern crate lalrpop_util;

mod ast;

lalrpop_mod!(pub parser, "/grammar.rs");

pub use ast::*;

/// Gets the abstract syntax tree generated from the parser of `zypo-rs`. This
/// function will panic is parsing fails and is intended for developers aiming
/// to implament the parser into code generation.
///
/// Please see [Function] for more infomation of what this will immidiatly
/// return.
///
/// # Examples
///
/// Basic function with 2 defined parameters:
///
/// ```rust
/// use zypo_parser::{
///     VarType,
///     Function,
///     Parameter,
///     ast_result
/// };
///
/// fn main() {
///     let input = "fun test_function(my_int: int, some_string: str) {}";
///     let expected = vec![
///         Function {
///             ident: "test_function".to_string(),
///             params: vec![
///                 Parameter { ident: "my_int".to_string(), ty: VarType::Int },
///                 Parameter { ident: "some_string".to_string(), ty: VarType::Str }
///             ],
///             body: vec![],
///             return_type: VarType::Void
///         }
///     ];
///
///     assert_eq!(ast_result(input), expected);
/// }
/// ```
pub fn ast_result(input: &str) -> Vec<Function> {
    parser::GrammarParser::new().parse(input).unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Tests for the correct output of a basic function decleration with no
    /// defined body.
    #[test]
    fn basic_function_ast() {
        let input_str = "fun hello_there(hi: str) {}";
        let expected = vec![Function {
            ident: "hello_there".to_string(),
            params: vec![Parameter {
                ident: "hi".to_string(),
                ty: VarType::Str,
            }],
            body: vec![],
            return_type: VarType::Void,
        }];

        assert_eq!(ast_result(input_str), expected);
    }

    /// Tests a simple variable statement inside of the function
    #[test]
    fn while_loop_ast() {
        let input_str = "fun test_while() { var x: int = 54; }";
        let expected = vec![Function {
            ident: "test_while".to_string(),
            params: vec![],
            body: vec![StatementNode::Variable(Variable {
                ident: "x".to_string(),
                ty: VarType::Int,
                body: Box::new(ExpressionNode::Constant(Constant::Int(54))),
            })],
            return_type: VarType::Void,
        }];

        assert_eq!(ast_result(input_str), expected);
    }
}