neutron_engine/iris/
mod.rs1pub mod token;
9pub mod lexer;
10pub mod parser;
11pub mod interpreter;
12pub mod value;
13
14
15use std::fs;
16use std::path::Path;
17use self::parser::{Expr, Stmt};
18
19pub fn run_file(path: &str) -> Result<(), String> {
21 let source = fs::read_to_string(path)
22 .map_err(|e| format!("Failed to read '{}': {}", path, e))?;
23 let base = Path::new(path).parent().unwrap_or(Path::new("."));
24 let file_name = Path::new(path).file_name().unwrap_or_default().to_str().unwrap_or("");
25 run_with_base(&source, base.to_str().unwrap_or("."), Some(file_name))
26}
27
28pub fn run(source: &str) -> Result<(), String> {
30 run_with_base(source, ".", None)
31}
32
33pub fn run_with_base(source: &str, base_path: &str, entry_file: Option<&str>) -> Result<(), String> {
35 if source_declares_foundation(source) {
36 validate_foundation_source(source)?;
37 }
38
39 let tokens = lexer::tokenize(source)?;
40 let ast = parser::parse(&tokens)?;
41
42 if ast_declares_foundation(&ast) {
43 validate_foundation_source(source)?;
44 validate_foundation_ast(&ast)?;
45 }
46
47 let mut interp = interpreter::Interpreter::new().with_base_path(base_path);
48 if let Some(file) = entry_file {
49 interp.mark_imported(file);
50 }
51 interp.execute(&ast)?;
52 interp.invoke_main_if_present()?;
53 Ok(())
54}
55
56fn ast_declares_foundation(stmts: &[Stmt]) -> bool {
57 stmts.iter().any(|stmt| match stmt {
58 Stmt::SystemIris { traits } => traits.iter().any(|trait_name| {
59 trait_name.eq_ignore_ascii_case("foundation")
60 }),
61 _ => false,
62 })
63}
64
65fn source_declares_foundation(source: &str) -> bool {
66 source.lines().any(|line| {
67 let code = line.split("//").next().unwrap_or("").to_ascii_lowercase();
68 code.contains("system") && code.contains("iris") && code.contains("foundation")
69 })
70}
71
72fn validate_foundation_source(source: &str) -> Result<(), String> {
73 for (line_index, line) in source.lines().enumerate() {
74 let code = line.split("//").next().unwrap_or("");
75 let compact = code.split_whitespace().collect::<String>();
76 if compact.contains("#[no_std]") {
77 return Err(foundation_error(
78 "#[no_std]",
79 line_index + 1,
80 code.find("#[no_std]").map(|i| i + 1).unwrap_or(1),
81 ));
82 }
83
84 let lowercase = code.to_ascii_lowercase();
85 if let Some(column) = lowercase.find("using namespace std") {
86 return Err(foundation_error(
87 "using namespace std",
88 line_index + 1,
89 column + 1,
90 ));
91 }
92 }
93
94 Ok(())
95}
96
97fn validate_foundation_ast(stmts: &[Stmt]) -> Result<(), String> {
98 for stmt in stmts {
99 validate_foundation_stmt(stmt)?;
100 }
101
102 Ok(())
103}
104
105fn validate_foundation_stmt(stmt: &Stmt) -> Result<(), String> {
106 match stmt {
107 Stmt::Expr(expr) => validate_foundation_expr(expr),
108 Stmt::Let { value, .. } | Stmt::Const { value, .. } => validate_foundation_expr(value),
109 Stmt::Fn { body, .. } | Stmt::Block(body) | Stmt::While { body, .. } | Stmt::For { body, .. } => {
110 for stmt in body {
111 validate_foundation_stmt(stmt)?;
112 }
113 Ok(())
114 }
115 Stmt::If { condition, then_branch, else_branch } => {
116 validate_foundation_expr(condition)?;
117 for stmt in then_branch {
118 validate_foundation_stmt(stmt)?;
119 }
120 if let Some(stmts) = else_branch {
121 for stmt in stmts {
122 validate_foundation_stmt(stmt)?;
123 }
124 }
125 Ok(())
126 }
127 Stmt::Return(Some(expr)) => validate_foundation_expr(expr),
128 Stmt::Return(None) | Stmt::Break | Stmt::Continue | Stmt::Import { .. } | Stmt::SystemIris { .. } => Ok(()),
129 }
130}
131
132fn validate_foundation_expr(expr: &Expr) -> Result<(), String> {
133 match expr {
134 Expr::Call { callee, args } => {
135 if let Expr::Identifier(name) = callee.as_ref() {
136 if is_std_builtin(name) {
137 return Err(foundation_std_required_error(name));
138 }
139 }
140 validate_foundation_expr(callee)?;
141 for arg in args {
142 validate_foundation_expr(arg)?;
143 }
144 Ok(())
145 }
146 Expr::Array(elements) => {
147 for expr in elements {
148 validate_foundation_expr(expr)?;
149 }
150 Ok(())
151 }
152 Expr::Object(pairs) => {
153 for (_, expr) in pairs {
154 validate_foundation_expr(expr)?;
155 }
156 Ok(())
157 }
158 Expr::Binary { left, right, .. } => {
159 validate_foundation_expr(left)?;
160 validate_foundation_expr(right)
161 }
162 Expr::Unary { expr, .. } => validate_foundation_expr(expr),
163 Expr::Index { object, index } => {
164 validate_foundation_expr(object)?;
165 validate_foundation_expr(index)
166 }
167 Expr::Member { object, .. } => validate_foundation_expr(object),
168 Expr::Assign { target, value } => {
169 validate_foundation_expr(target)?;
170 validate_foundation_expr(value)
171 }
172 Expr::Lambda { body, .. } => {
173 for stmt in body {
174 validate_foundation_stmt(stmt)?;
175 }
176 Ok(())
177 }
178 Expr::Null | Expr::Bool(_) | Expr::Number(_) | Expr::String(_) | Expr::Identifier(_) => Ok(()),
179 }
180}
181
182fn is_std_builtin(name: &str) -> bool {
183 matches!(
184 name,
185 "print"
186 | "println"
187 | "input"
188 | "len"
189 | "typeof"
190 | "push"
191 | "pop"
192 | "keys"
193 | "values"
194 | "range"
195 | "str"
196 | "num"
197 | "system"
198 | "fs_read"
199 | "fs_write"
200 | "env_get"
201 | "sleep"
202 | "proc_list"
203 )
204}
205
206fn foundation_error(rule: &str, line: usize, column: usize) -> String {
207 format!(
208 "\x1b[31mFoundation error: '{}' is not allowed in Iris Foundation mode at line {}, column {}. Iris Foundation owns std access, memory safety, ownership, borrow-checkers, and leak safety.\x1b[0m",
209 rule, line, column
210 )
211}
212
213fn foundation_std_required_error(name: &str) -> String {
214 format!(
215 "\x1b[31mFoundation error: Iris Foundation cannot run standard runtime calls without the std namespace. Use std::{}(...) instead of {}(...).\x1b[0m",
216 name, name
217 )
218}
219
220pub fn repl() {
222 use std::io::{self, Write};
223
224 println!("Iris REPL v0.1.0");
225 println!("Type 'exit' or press Ctrl+C to quit.\n");
226
227 let mut interp = interpreter::Interpreter::new();
228
229 loop {
230 print!("iris> ");
231 io::stdout().flush().unwrap();
232
233 let mut input = String::new();
234 if io::stdin().read_line(&mut input).is_err() {
235 break;
236 }
237
238 let input = input.trim();
239 if input == "exit" || input == "quit" {
240 break;
241 }
242 if input.is_empty() {
243 continue;
244 }
245
246 match lexer::tokenize(input) {
247 Ok(tokens) => {
248 match parser::parse(&tokens) {
249 Ok(ast) => {
250 match interp.execute(&ast) {
251 Ok(result) => {
252 if !matches!(result, value::Value::Null) {
253 println!("{}", result);
254 }
255 }
256 Err(e) => eprintln!("Runtime error: {}", e),
257 }
258 }
259 Err(e) => eprintln!("Parse error: {}", e),
260 }
261 }
262 Err(e) => eprintln!("Lex error: {}", e),
263 }
264 }
265}
266