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
//! Top-level declaration parsers
//!
//! Parsers for function declarations and static variable/constant declarations.
//!
//! # Function Definition Example:
//! ```rust
//! let source_code = "\
//! function f(a, b)
//!   return (a + 1) * b
//! end
//! ";
//! # use lualite::parser::declaration::function_decl;
//! let (_remaining, parsed_ast) = function_decl(source_code).expect("parse error");
//!
//! # use lualite::ast::{FunctionDecl, Identifier, Statement, Expression, BinaryOperator, IntegerLiteral};
//! let expected_ast = FunctionDecl {
//!   name: Identifier("f".to_owned()),
//!   params: vec![Identifier("a".to_owned()), Identifier("b".to_owned())],
//!   body: vec![
//!     Statement::ReturnStatement(Some(Expression::Binary {
//!       left: Box::new(Expression::Binary {
//!         left: Box::new(Expression::Identifier(Identifier("a".to_owned()))),
//!         op: BinaryOperator::Add,
//!         right: Box::new(Expression::Integer(IntegerLiteral(1_i64))),
//!       }),
//!       op: BinaryOperator::Mul,
//!       right: Box::new(Expression::Identifier(Identifier("b".to_owned()))),
//!     })),
//!   ],
//! };
//!
//! assert_eq!(parsed_ast, expected_ast);
//! ```
//!
//! # Static Declaration Example:
//! ```rust
//! let source_code = "\
//! static SIZE = 512
//! ";
//! # use lualite::parser::declaration::static_decl;
//! let (_remaining, parsed_ast) = static_decl(source_code).expect("parse error");
//!
//! # use lualite::ast::{StaticDecl, Identifier, Expression, IntegerLiteral};
//! let expected_ast = StaticDecl {
//!   name: Identifier("SIZE".to_owned()),
//!   value: Some(Expression::Integer(IntegerLiteral(512_i64))),
//! };
//!
//! assert_eq!(parsed_ast, expected_ast);
//! ```
//!
//! The `declaration` parser can parse either declaration type and returns a
//! [`Declaration`] which is an enum of
//! either a function declaration or a static declaration.

use nom::{
  IResult,
  branch::alt,
  bytes::complete::tag,
  combinator::map,
  multi::separated_list0,
  sequence::{delimited, tuple},
};
use crate::ast::{Identifier, FunctionDecl, StaticDecl, Declaration};
use super::atomic::{identifier, keyword};
use super::statement::body;
use super::expression::expression;
use super::whitespace;

/// Parses any declaration
pub fn declaration(s: &str) -> IResult<&str, Declaration> {
  alt((
    map(function_decl, |fd| Declaration::Function(fd)),
    map(static_decl, |sd| Declaration::Static(sd)),
  ))(s)
}

/// Parses a function declaration
pub fn function_decl(s: &str) -> IResult<&str, FunctionDecl> {
  map(
    tuple((
      whitespace,
      keyword("function"),
      whitespace,
      identifier,
      whitespace,
      params_list,
      body,
      whitespace,
      keyword("end"),
    )),
    |(_, _function, _, name, _, params, body, _, _end)| FunctionDecl { name, params, body },
  )(s)
}

/// Parses a static declaration
pub fn static_decl(s: &str) -> IResult<&str, StaticDecl> {
  map(
    tuple((
      whitespace,
      keyword("static"),
      whitespace,
      identifier,
      whitespace,
      tag("="),
      whitespace,
      expression,
    )),
    |(_, _static, _, name, _, _equals, _, value)| StaticDecl { name, value: Some(value) },
  )(s)
}

fn params_list(s: &str) -> IResult<&str, Vec<Identifier>> {
  delimited(
    tag("("),
    separated_list0(
      tag(","),
      delimited(whitespace, identifier, whitespace),
    ),
    tag(")"),
  )(s)
}