1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! # Abstract Syntax Tree (AST) Module
//!
//! This module provides the Abstract Syntax Tree representation for Rash,
//! a Rust-to-Shell transpiler. The AST is designed to represent a safe
//! subset of Rust that can be reliably transpiled to POSIX shell scripts.
//!
//! ## Overview
//!
//! The AST module consists of:
//! - **Restricted AST**: A limited subset of Rust syntax that ensures safe shell generation
//! - **Validation**: Compile-time checks for safety and correctness
//! - **Visitor Pattern**: For AST traversal and transformation
//!
//! ## Examples
//!
//! ### Creating a Simple AST
//!
//! ```rust
//! use bashrs::ast::{RestrictedAst, Function, Stmt, Expr, Type};
//! use bashrs::ast::restricted::Literal;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create a simple "Hello, World!" function
//! let main_fn = Function {
//! name: "main".to_string(),
//! params: vec![],
//! body: vec![
//! Stmt::Expr(Expr::FunctionCall {
//! name: "println".to_string(),
//! args: vec![Expr::Literal(Literal::Str("Hello, World!".to_string()))],
//! })
//! ],
//! return_type: Type::Void,
//! };
//!
//! let ast = RestrictedAst {
//! functions: vec![main_fn],
//! entry_point: "main".to_string(),
//! };
//!
//! // Validate the AST
//! assert!(ast.validate().is_ok());
//! # Ok(())
//! # }
//! ```
//!
//! ### Variable Usage
//!
//! ```rust
//! use bashrs::ast::{RestrictedAst, Function, Stmt, Expr, Type};
//! use bashrs::ast::restricted::Literal;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let main_fn = Function {
//! name: "main".to_string(),
//! params: vec![],
//! body: vec![
//! // Create a variable
//! Stmt::Let {
//! name: "user".to_string(),
//! value: Expr::FunctionCall {
//! name: "env".to_string(),
//! args: vec![Expr::Literal(Literal::Str("USER".to_string()))],
//! },
//! declaration: true,
//! },
//! // Use the variable
//! Stmt::Expr(Expr::FunctionCall {
//! name: "echo".to_string(),
//! args: vec![
//! Expr::Variable("user".to_string())
//! ],
//! })
//! ],
//! return_type: Type::Void,
//! };
//!
//! let ast = RestrictedAst {
//! functions: vec![main_fn],
//! entry_point: "main".to_string(),
//! };
//!
//! // Variables must be valid identifiers
//! assert!(ast.validate().is_ok());
//! # Ok(())
//! # }
//! ```
//!
//! ### Invalid AST Example
//!
//! ```rust
//! use bashrs::ast::{RestrictedAst, Function, Stmt, Expr, Type};
//! use bashrs::ast::restricted::{Literal, BinaryOp};
//!
//! # fn main() {
//! // Functions cannot have empty names
//! let invalid_fn = Function {
//! name: "".to_string(), // Empty function name!
//! params: vec![],
//! body: vec![
//! Stmt::Expr(Expr::Literal(Literal::Str("test".to_string())))
//! ],
//! return_type: Type::Void,
//! };
//!
//! let ast = RestrictedAst {
//! functions: vec![invalid_fn],
//! entry_point: "main".to_string(),
//! };
//!
//! // This will fail validation
//! assert!(ast.validate().is_err());
//! # }
//! ```
pub use ;
use crate;
/// Validate that an AST conforms to Rash restrictions
///
/// # Examples
///
/// ```rust
/// use bashrs::ast::{validate, RestrictedAst, Function, Type};
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let ast = RestrictedAst {
/// functions: vec![
/// Function {
/// name: "main".to_string(),
/// params: vec![],
/// body: vec![],
/// return_type: Type::Void,
/// }
/// ],
/// entry_point: "main".to_string(),
/// };
///
/// // Validate the AST
/// validate(&ast)?;
/// # Ok(())
/// # }
/// ```