1use crate::ast::Span;
7use crate::error::{Result, ShapeError, SourceLocation};
8use pest::Parser;
9use pest::iterators::Pair;
10use pest_derive::Parser;
11
12pub fn pair_span(pair: &Pair<Rule>) -> Span {
14 let span = pair.as_span();
15 Span::new(span.start(), span.end())
16}
17
18pub(crate) fn pair_location(pair: &Pair<Rule>) -> SourceLocation {
20 let span = pair.as_span();
21 let (line, col) = span.start_pos().line_col();
22 let source_line = span.start_pos().line_of().to_string();
23 let length = span.end() - span.start();
24
25 SourceLocation::new(line, col)
26 .with_length(length)
27 .with_source_line(source_line)
28}
29
30pub mod data_sources;
32pub mod expressions;
33pub mod extensions;
34pub mod functions;
35pub mod items;
36pub mod modules;
37pub mod preprocessor;
38pub mod queries;
39pub mod resilient;
40pub mod statements;
41pub mod stream;
42pub mod string_literals;
43pub mod time;
44pub mod types;
45
46#[cfg(test)]
47mod tests;
48
49use crate::ast::{Item, Program};
50
51#[derive(Parser)]
52#[grammar = "src/shape.pest"]
53pub struct ShapeParser;
54
55pub fn parse_program(input: &str) -> Result<Program> {
57 let processed = preprocessor::preprocess_semicolons(input);
58 let pairs = ShapeParser::parse(Rule::program, &processed).map_err(|e| {
59 let structured = crate::error::pest_converter::convert_pest_error(&e, &processed);
61 ShapeError::StructuredParse(Box::new(structured))
62 })?;
63
64 let mut items = Vec::new();
65
66 for pair in pairs {
67 if pair.as_rule() == Rule::program {
68 for inner in pair.into_inner() {
69 match inner.as_rule() {
70 Rule::item => {
71 items.push(parse_item(inner)?);
72 }
73 Rule::item_recovery => {
74 let span = inner.as_span();
75 let text = inner.as_str().trim();
76 let preview = if text.len() > 40 {
77 format!("{}...", &text[..40])
78 } else {
79 text.to_string()
80 };
81 return Err(ShapeError::ParseError {
82 message: format!("Syntax error near: {}", preview),
83 location: Some(
84 pair_location(&inner).with_length(span.end() - span.start()),
85 ),
86 });
87 }
88 _ => {}
89 }
90 }
91 }
92 }
93
94 Ok(Program { items })
95}
96
97pub fn parse_item(pair: pest::iterators::Pair<Rule>) -> Result<Item> {
99 let pair_loc = pair_location(&pair);
100 let inner = pair
101 .into_inner()
102 .next()
103 .ok_or_else(|| ShapeError::ParseError {
104 message: "expected item content".to_string(),
105 location: Some(pair_loc.clone().with_hint(
106 "provide a pattern, query, function, variable declaration, or expression",
107 )),
108 })?;
109
110 let span = pair_span(&inner);
111
112 match inner.as_rule() {
113 Rule::query => Ok(Item::Query(queries::parse_query(inner)?, span)),
114 Rule::variable_decl => Ok(Item::VariableDecl(items::parse_variable_decl(inner)?, span)),
115 Rule::assignment => {
116 let inner_loc = pair_location(&inner);
117 let mut inner = inner.into_inner();
118 let pattern_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
119 message: "expected pattern in assignment".to_string(),
120 location: Some(inner_loc.clone()),
121 })?;
122 let pattern = items::parse_pattern(pattern_pair)?;
123 let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
124 message: "expected value expression in assignment".to_string(),
125 location: Some(inner_loc.with_hint("provide a value after '='")),
126 })?;
127 let value = expressions::parse_expression(value_pair)?;
128 Ok(Item::Assignment(
129 crate::ast::Assignment { pattern, value },
130 span,
131 ))
132 }
133 Rule::expression_stmt => {
134 let inner_loc = pair_location(&inner);
135 let expr_pair = inner
136 .into_inner()
137 .next()
138 .ok_or_else(|| ShapeError::ParseError {
139 message: "expected expression in statement".to_string(),
140 location: Some(inner_loc),
141 })?;
142 let expr = expressions::parse_expression(expr_pair)?;
143 Ok(Item::Expression(expr, span))
144 }
145 Rule::import_stmt => Ok(Item::Import(modules::parse_import_stmt(inner)?, span)),
146 Rule::module_decl => Ok(Item::Module(modules::parse_module_decl(inner)?, span)),
147 Rule::pub_item => Ok(Item::Export(modules::parse_export_item(inner)?, span)),
148 Rule::struct_type_def => Ok(Item::StructType(types::parse_struct_type_def(inner)?, span)),
149 Rule::native_struct_type_def => Ok(Item::StructType(
150 types::parse_native_struct_type_def(inner)?,
151 span,
152 )),
153 Rule::builtin_type_decl => Ok(Item::BuiltinTypeDecl(
154 types::parse_builtin_type_decl(inner)?,
155 span,
156 )),
157 Rule::type_alias_def => Ok(Item::TypeAlias(types::parse_type_alias_def(inner)?, span)),
158 Rule::trait_def => Ok(Item::Trait(types::parse_trait_def(inner)?, span)),
159 Rule::enum_def => Ok(Item::Enum(types::parse_enum_def(inner)?, span)),
160 Rule::extern_native_function_def => Ok(Item::ForeignFunction(
161 functions::parse_extern_native_function_def(inner)?,
162 span,
163 )),
164 Rule::foreign_function_def => Ok(Item::ForeignFunction(
165 functions::parse_foreign_function_def(inner)?,
166 span,
167 )),
168 Rule::function_def => Ok(Item::Function(functions::parse_function_def(inner)?, span)),
169 Rule::builtin_function_decl => Ok(Item::BuiltinFunctionDecl(
170 functions::parse_builtin_function_decl(inner)?,
171 span,
172 )),
173 Rule::stream_def => Ok(Item::Stream(stream::parse_stream_def(inner)?, span)),
174 Rule::test_def => Err(ShapeError::ParseError {
175 message: "Embedded test definitions are no longer supported in this refactor"
176 .to_string(),
177 location: None,
178 }),
179 Rule::statement => Ok(Item::Statement(statements::parse_statement(inner)?, span)),
180 Rule::extend_statement => Ok(Item::Extend(
181 extensions::parse_extend_statement(inner)?,
182 span,
183 )),
184 Rule::impl_block => Ok(Item::Impl(extensions::parse_impl_block(inner)?, span)),
185 Rule::optimize_statement => Ok(Item::Optimize(
186 extensions::parse_optimize_statement(inner)?,
187 span,
188 )),
189 Rule::annotation_def => Ok(Item::AnnotationDef(
190 extensions::parse_annotation_def(inner)?,
191 span,
192 )),
193 Rule::datasource_def => Ok(Item::DataSource(
194 data_sources::parse_datasource_def(inner)?,
195 span,
196 )),
197 Rule::query_decl => Ok(Item::QueryDecl(
198 data_sources::parse_query_decl(inner)?,
199 span,
200 )),
201 Rule::comptime_block => {
202 let block_pair = inner
203 .into_inner()
204 .next()
205 .ok_or_else(|| ShapeError::ParseError {
206 message: "expected block after 'comptime'".to_string(),
207 location: None,
208 })?;
209 let block_expr = expressions::control_flow::parse_block_expr(block_pair)?;
210 let stmts = expressions::primary::block_items_to_statements(block_expr, span);
211 Ok(Item::Comptime(stmts, span))
212 }
213 _ => Err(ShapeError::ParseError {
214 message: format!("unexpected item type: {:?}", inner.as_rule()),
215 location: Some(pair_location(&inner)),
216 }),
217 }
218}
219
220pub use expressions::parse_expression;
222pub use items::{parse_pattern, parse_variable_decl};
223pub use types::parse_type_annotation;
224
225pub fn parse_expression_str(input: &str) -> Result<crate::ast::Expr> {
229 let pairs = ShapeParser::parse(Rule::expression, input).map_err(|e| {
230 let structured = crate::error::pest_converter::convert_pest_error(&e, input);
231 ShapeError::StructuredParse(Box::new(structured))
232 })?;
233
234 let pair = pairs
235 .into_iter()
236 .next()
237 .ok_or_else(|| ShapeError::ParseError {
238 message: "Expected expression".to_string(),
239 location: None,
240 })?;
241
242 expressions::parse_expression(pair)
243}