Skip to main content

neutron_engine/iris/
mod.rs

1/// Iris Programming Language - Interpreter Module
2/// 
3/// Iris adalah bahasa scripting dengan paradigm hybrid:
4/// - Object-oriented (prototype-based seperti JavaScript)
5/// - Imperative (control flow seperti C/Rust)
6/// - Functional (first-class functions, closures)
7
8pub 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
19/// Run an Iris source file
20pub 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
28/// Run Iris source code directly
29pub fn run(source: &str) -> Result<(), String> {
30    run_with_base(source, ".", None)
31}
32
33/// Run with base path for imports
34pub 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
220/// REPL - Read Eval Print Loop
221pub 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