blueprint_engine_parser/
lib.rs

1use blueprint_engine_core::{BlueprintError, Result, SourceLocation, Span};
2use blueprint_starlark_syntax::codemap::CodeMap;
3use blueprint_starlark_syntax::dialect::{Dialect, DialectTypes};
4use blueprint_starlark_syntax::syntax::module::AstModuleFields;
5use blueprint_starlark_syntax::syntax::AstModule;
6
7pub use blueprint_starlark_syntax::syntax::ast::{
8    AssignOp, AssignTarget, AssignTargetP, AstArgument, AstExpr, AstLiteral, AstParameter,
9    AstPayload, AstStmt, Clause, Expr, ExprP, ForClause, Parameter, ParameterP, Stmt, StmtP,
10};
11pub use blueprint_starlark_syntax::syntax::def::{DefParam, DefParams};
12
13pub struct ParsedModule {
14    pub codemap: CodeMap,
15    pub statement: AstStmt,
16}
17
18impl ParsedModule {
19    pub fn statements(&self) -> &AstStmt {
20        &self.statement
21    }
22}
23
24pub fn parse(filename: &str, content: &str) -> Result<ParsedModule> {
25    let dialect = Dialect {
26        enable_f_strings: true,
27        enable_lambda: true,
28        enable_keyword_only_arguments: true,
29        enable_top_level_stmt: true,
30        enable_types: DialectTypes::Enable,
31        ..Dialect::Standard
32    };
33
34    match AstModule::parse(filename, content.to_owned(), &dialect) {
35        Ok(module) => {
36            let (codemap, statement, _dialect, _) = module.into_parts();
37            Ok(ParsedModule { codemap, statement })
38        }
39        Err(e) => {
40            let location = SourceLocation {
41                file: Some(filename.to_string()),
42                line: 1,
43                column: 1,
44                span: None,
45            };
46            Err(BlueprintError::ParseError {
47                location,
48                message: e.to_string(),
49            })
50        }
51    }
52}
53
54pub fn get_location(
55    codemap: &CodeMap,
56    span: blueprint_starlark_syntax::codemap::Span,
57) -> SourceLocation {
58    let file_span = codemap.file_span(span);
59    let loc = file_span.resolve();
60    SourceLocation {
61        file: Some(loc.file.clone()),
62        line: loc.span.begin.line + 1,
63        column: loc.span.begin.column + 1,
64        span: Some(Span {
65            start: span.begin().get() as usize,
66            end: span.end().get() as usize,
67        }),
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_parse_simple() {
77        let result = parse("test.star", "x = 1 + 2");
78        assert!(result.is_ok());
79    }
80
81    #[test]
82    fn test_parse_function() {
83        let code = r#"
84def hello(name):
85    print("Hello, " + name)
86"#;
87        let result = parse("test.star", code);
88        assert!(result.is_ok());
89    }
90
91    #[test]
92    fn test_parse_lambda() {
93        let result = parse("test.star", "f = lambda x: x * 2");
94        assert!(result.is_ok());
95    }
96
97    #[test]
98    fn test_parse_error() {
99        let result = parse("test.star", "x = ");
100        assert!(result.is_err());
101    }
102}