1use amarok_syntax::{Diagnostic, Expression, FileId, Program, Spanned, Statement};
11use pest::Parser;
12
13mod builders;
14mod grammar;
15
16use builders::{build_expression, build_program, build_statement};
17use grammar::{AmarokGrammar, Rule, pest_error_to_diagnostic};
18
19pub fn parse_program(source: &str) -> Result<Program, Diagnostic> {
28 let mut pairs = AmarokGrammar::parse(Rule::program, source)
29 .map_err(|error: pest::error::Error<Rule>| pest_error_to_diagnostic(&error))?;
30
31 let program_pair = pairs
32 .next()
33 .ok_or_else(|| Diagnostic::new("Expected a program, found nothing."))?;
34
35 build_program(program_pair)
36}
37
38pub fn parse_program_with_file_id(source: &str, file_id: FileId) -> Result<Program, Diagnostic> {
45 let mut program = parse_program(source).map_err(|mut diagnostic| {
46 if let Some(span) = diagnostic.span.as_mut() {
47 span.file_id = file_id;
48 }
49 diagnostic
50 })?;
51 set_program_file_id(&mut program, file_id);
52 Ok(program)
53}
54
55pub fn parse_statement(source: &str) -> Result<Spanned<Statement>, Diagnostic> {
61 let mut pairs = AmarokGrammar::parse(Rule::statement, source)
62 .map_err(|error: pest::error::Error<Rule>| pest_error_to_diagnostic(&error))?;
63
64 let statement_pair = pairs
65 .next()
66 .ok_or_else(|| Diagnostic::new("Expected a statement, found nothing."))?;
67
68 build_statement(statement_pair)
69}
70
71pub fn parse_expression(source: &str) -> Result<Spanned<Expression>, Diagnostic> {
77 let mut pairs = AmarokGrammar::parse(Rule::expression, source)
78 .map_err(|error: pest::error::Error<Rule>| pest_error_to_diagnostic(&error))?;
79
80 let expression_pair = pairs
81 .next()
82 .ok_or_else(|| Diagnostic::new("Expected an expression, found nothing."))?;
83
84 build_expression(expression_pair)
85}
86
87fn set_program_file_id(program: &mut Program, file_id: FileId) {
90 for statement in &mut program.statements {
91 set_statement_file_id(statement, file_id);
92 }
93}
94
95fn set_statement_file_id(statement: &mut Spanned<Statement>, file_id: FileId) {
96 statement.span.file_id = file_id;
97 match &mut statement.value {
98 Statement::Assignment { value, .. } => set_expression_file_id(value, file_id),
99 Statement::Expression { expression } => set_expression_file_id(expression, file_id),
100 Statement::Block { statements } => {
101 for child in statements {
102 set_statement_file_id(child, file_id);
103 }
104 }
105 Statement::If {
106 condition,
107 then_branch,
108 else_branch,
109 } => {
110 set_expression_file_id(condition, file_id);
111 for child in then_branch {
112 set_statement_file_id(child, file_id);
113 }
114 for child in else_branch {
115 set_statement_file_id(child, file_id);
116 }
117 }
118 Statement::While { condition, body } => {
119 set_expression_file_id(condition, file_id);
120 for child in body {
121 set_statement_file_id(child, file_id);
122 }
123 }
124 Statement::FunctionDefinition { body, .. } => {
125 for child in body {
126 set_statement_file_id(child, file_id);
127 }
128 }
129 Statement::Return { value } => {
130 if let Some(expression) = value {
131 set_expression_file_id(expression, file_id);
132 }
133 }
134 Statement::Use { .. } => {}
135 }
136}
137
138fn set_expression_file_id(expression: &mut Spanned<Expression>, file_id: FileId) {
139 expression.span.file_id = file_id;
140 match &mut expression.value {
141 Expression::Integer(_) | Expression::String(_) | Expression::Variable(_) => {}
142 Expression::Binary { left, right, .. } => {
143 set_expression_file_id(left, file_id);
144 set_expression_file_id(right, file_id);
145 }
146 Expression::FunctionCall { arguments, .. } => {
147 for argument in arguments {
148 set_expression_file_id(argument, file_id);
149 }
150 }
151 }
152}