datex_core/ast/
binding.rs

1use crate::ast::assignment_operation::{
2    AssignmentOperator, assignment_operation,
3};
4use crate::ast::error::error::ParseError;
5use crate::ast::error::pattern::Pattern;
6use crate::ast::lexer::Token;
7use crate::ast::r#type::{r#type, type_declaration};
8use crate::ast::utils::whitespace;
9use crate::ast::{
10    DatexExpression, DatexParserTrait, ParserRecoverExt, TypeExpression,
11    VariableKind,
12};
13use chumsky::prelude::*;
14pub type VariableId = usize;
15
16fn create_variable_declaration(
17    name: String,
18    value: DatexExpression,
19    type_annotation: Option<TypeExpression>,
20    kind: VariableKind,
21) -> DatexExpression {
22    DatexExpression::VariableDeclaration {
23        id: None,
24        kind,
25        name,
26        type_annotation,
27        init_expression: Box::new(value),
28    }
29}
30
31/// A variable assignment (e.g. `x = 42` or `y += 1`)
32pub fn variable_assignment<'a>(
33    expression: impl DatexParserTrait<'a>,
34) -> impl DatexParserTrait<'a> {
35    let assignment_op = assignment_operation();
36
37    select! { Token::Identifier(name) => name }
38        .then(assignment_op)
39        .then(expression)
40        .map(|((var_name, op), expr)| {
41            DatexExpression::VariableAssignment(
42                op,
43                None,
44                var_name.to_string(),
45                Box::new(expr),
46            )
47        })
48        .labelled(Pattern::Declaration)
49        .as_context()
50}
51pub fn deref_assignment<'a>(
52    expression: impl DatexParserTrait<'a>,
53    unary: impl DatexParserTrait<'a>,
54) -> impl DatexParserTrait<'a> {
55    let assignment_op = assignment_operation();
56
57    just(Token::Star)
58        .repeated()
59        .at_least(1)
60        .count()
61        .then(unary)
62        .then(assignment_op)
63        .then(expression)
64        .map(
65            |(
66                ((deref_count, deref_expression), operator),
67                assigned_expression,
68            )| {
69                DatexExpression::DerefAssignment {
70                    operator,
71                    deref_count,
72                    deref_expression: Box::new(deref_expression),
73                    assigned_expression: Box::new(assigned_expression),
74                }
75            },
76        )
77        // FIXME #369 assignment instead of declaration
78        .labelled(Pattern::Declaration)
79        .as_context()
80}
81
82/// A variable declaration (e.g. `var x: u32 = 42` or `const y = "Hello"`)
83pub fn variable_declaration<'a>(
84    union: impl DatexParserTrait<'a>,
85) -> impl DatexParserTrait<'a> {
86    let type_annotation = just(Token::Colon)
87        .padded_by(whitespace())
88        .ignore_then(r#type())
89        .or_not();
90
91    let assignment_op = assignment_operation();
92    let keyword = select! {
93        Token::Variable => VariableKind::Var,
94        Token::Const    => VariableKind::Const,
95    };
96
97    keyword
98        .padded_by(whitespace())
99        .then(select! { Token::Identifier(s) => s })
100        .then(type_annotation)
101        .then(assignment_op)
102        .then(union.clone())
103        .map(|((((kind, var_name), annotation), op), expr)| {
104            if op != AssignmentOperator::Assign {
105                return Err(ParseError::new_custom(format!(
106                    "Cannot use '{}' operator in variable declaration",
107                    op
108                )));
109            }
110
111            Ok(create_variable_declaration(
112                var_name.to_string(),
113                expr,
114                annotation,
115                kind,
116            ))
117        })
118        .recover_invalid()
119        .labelled(Pattern::Declaration)
120        .as_context()
121}
122
123/// A declaration or assignment, e.g. `var x = 42;`, `const x = 69`, `x = 43;`, or `type x = 42`
124pub fn declaration_or_assignment<'a>(
125    expression: impl DatexParserTrait<'a>,
126    unary: impl DatexParserTrait<'a>,
127) -> impl DatexParserTrait<'a> {
128    choice((
129        type_declaration(),
130        variable_declaration(expression.clone()),
131        deref_assignment(expression.clone(), unary),
132        variable_assignment(expression),
133    ))
134}