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