Skip to main content

atmos/os_lib/aura/builtins/
modules_str_task.rs

1// 分割: aura/builtins.rs より機械的に移動(2026-07-16 リファクタ フェーズ6)。
2// ロジック不変。可視性のみ pub(crate) へ昇格し、親が pub(crate) use で再エクスポート。
3use super::*;
4
5/// `load("path.aura")` — ファイルを読み込んで現在の環境で評価し、最後の値を返す
6pub(crate) fn builtin_load(env: &mut Env, args: &[AST]) -> Result<Value, String> {
7    let vals = eval_args(env, args)?;
8    if vals.is_empty() {
9        return Err(String::from("USAGE: load(\"path.aura\")"));
10    }
11    let raw_path = unquote(&vals[0]);
12    let path = resolve_path(env, &raw_path)?;
13
14    let fs = crate::kernel::fs::get_fs();
15    let (_, bytes) = fs
16        .read_file(&path)
17        .ok_or_else(|| alloc::format!("load: file not found: {}", path))?;
18    let src = core::str::from_utf8(&bytes)
19        .map_err(|_| alloc::format!("load: invalid UTF-8 in {}", path))?;
20
21    let tokens = super::super::lexer::tokenize(src);
22    let asts = super::super::parser::parse(&tokens)
23        .map_err(|e| alloc::format!("load: parse error in {}: {}", path, e))?;
24
25    let mut last = Value::Nil;
26    for ast in &asts {
27        last = eval(env, ast)?;
28    }
29    Ok(last)
30}
31
32/// `require("path.aura")` — 同じパスが既にロード済みなら何もしない。未ロードなら load と同じ動作。
33/// ロード済みパスは環境変数 `__loaded__` (List of Str) で管理する。
34pub(crate) fn builtin_require(env: &mut Env, args: &[AST]) -> Result<Value, String> {
35    let vals = eval_args(env, args)?;
36    if vals.is_empty() {
37        return Err(String::from("USAGE: require(\"path.aura\")"));
38    }
39    let raw_path = unquote(&vals[0]);
40    let path = resolve_path(env, &raw_path)?;
41
42    // Check already loaded
43    let already = match env.get("__loaded__") {
44        Some(Value::List(list)) => list.iter().any(|v| {
45            if let Value::Str(s) = v {
46                s == &path
47            } else {
48                false
49            }
50        }),
51        _ => false,
52    };
53    if already {
54        return Ok(Value::Nil);
55    }
56
57    // Load and eval
58    let fs = crate::kernel::fs::get_fs();
59    let (_, bytes) = fs
60        .read_file(&path)
61        .ok_or_else(|| alloc::format!("require: file not found: {}", path))?;
62    let src = core::str::from_utf8(&bytes)
63        .map_err(|_| alloc::format!("require: invalid UTF-8 in {}", path))?;
64
65    let tokens = super::super::lexer::tokenize(src);
66    let asts = super::super::parser::parse(&tokens)
67        .map_err(|e| alloc::format!("require: parse error in {}: {}", path, e))?;
68
69    let mut last = Value::Nil;
70    for ast in &asts {
71        last = eval(env, ast)?;
72    }
73
74    // Mark as loaded
75    let mut loaded = match env.get("__loaded__") {
76        Some(Value::List(list)) => list,
77        _ => Vec::new(),
78    };
79    loaded.push(Value::Str(path));
80    env.set(String::from("__loaded__"), Value::List(loaded));
81
82    Ok(last)
83}
84
85// =========================================================================
86// str 名前空間の組み込み関数
87// =========================================================================
88
89pub(crate) fn builtin_str_split(env: &mut Env, args: &[AST]) -> Result<Value, String> {
90    let vals = eval_args(env, args)?;
91    if vals.len() != 2 {
92        return Err(String::from(
93            "str.split requires exactly 2 arguments: (str.split target delimiter)",
94        ));
95    }
96    let target = match &vals[0] {
97        Value::Str(s) => s,
98        _ => return Err(String::from("str.split first argument must be a string")),
99    };
100    let delim = match &vals[1] {
101        Value::Str(s) => s,
102        _ => return Err(String::from("str.split second argument must be a string")),
103    };
104
105    let parts: Vec<Value> = target
106        .split(delim)
107        .map(|s| Value::Str(String::from(s)))
108        .collect();
109    Ok(Value::List(parts))
110}
111
112pub(crate) fn builtin_str_join(env: &mut Env, args: &[AST]) -> Result<Value, String> {
113    let vals = eval_args(env, args)?;
114    if vals.len() != 2 {
115        return Err(String::from(
116            "str.join requires exactly 2 arguments: (str.join list delimiter)",
117        ));
118    }
119    let list = match &vals[0] {
120        Value::List(l) => l,
121        _ => return Err(String::from("str.join first argument must be a list")),
122    };
123    let delim = match &vals[1] {
124        Value::Str(s) => s,
125        _ => return Err(String::from("str.join second argument must be a string")),
126    };
127
128    let mut parts = Vec::new();
129    for val in list {
130        match val {
131            Value::Str(s) => parts.push(s.clone()),
132            _ => {
133                parts.push(val.to_string());
134            }
135        }
136    }
137    Ok(Value::Str(parts.join(delim)))
138}
139
140pub(crate) fn builtin_str_substring(env: &mut Env, args: &[AST]) -> Result<Value, String> {
141    let vals = eval_args(env, args)?;
142    if vals.len() != 2 && vals.len() != 3 {
143        return Err(String::from(
144            "str.substring requires 2 or 3 arguments: (str.substring target start [end])",
145        ));
146    }
147    let target = match &vals[0] {
148        Value::Str(s) => s,
149        _ => {
150            return Err(String::from(
151                "str.substring first argument must be a string",
152            ))
153        }
154    };
155    let start = match &vals[1] {
156        Value::Num(n) => n.to_i64().unwrap_or(0) as usize,
157        _ => {
158            return Err(String::from(
159                "str.substring second argument must be a number",
160            ))
161        }
162    };
163
164    let chars: Vec<char> = target.chars().collect();
165    let end = if vals.len() == 3 {
166        match &vals[2] {
167            Value::Num(n) => n.to_i64().unwrap_or(chars.len() as i64) as usize,
168            _ => {
169                return Err(String::from(
170                    "str.substring third argument must be a number",
171                ))
172            }
173        }
174    } else {
175        chars.len()
176    };
177
178    if start > chars.len() || start > end {
179        return Ok(Value::Str(String::new()));
180    }
181    let end = end.min(chars.len());
182    let sub: String = chars[start..end].iter().collect();
183    Ok(Value::Str(sub))
184}
185
186pub(crate) fn builtin_str_length(env: &mut Env, args: &[AST]) -> Result<Value, String> {
187    let vals = eval_args(env, args)?;
188    if vals.len() != 1 {
189        return Err(String::from(
190            "str.length requires exactly 1 argument: (str.length target)",
191        ));
192    }
193    let target = match &vals[0] {
194        Value::Str(s) => s,
195        _ => return Err(String::from("str.length argument must be a string")),
196    };
197
198    let len = target.chars().count();
199    Ok(Value::Num(BigInt::from_i64(len as i64)))
200}
201
202pub(crate) fn builtin_str_replace(env: &mut Env, args: &[AST]) -> Result<Value, String> {
203    let vals = eval_args(env, args)?;
204    if vals.len() != 3 {
205        return Err(String::from(
206            "str.replace requires exactly 3 arguments: (str.replace target from to)",
207        ));
208    }
209    let target = match &vals[0] {
210        Value::Str(s) => s,
211        _ => return Err(String::from("str.replace first argument must be a string")),
212    };
213    let from = match &vals[1] {
214        Value::Str(s) => s,
215        _ => return Err(String::from("str.replace second argument must be a string")),
216    };
217    let to = match &vals[2] {
218        Value::Str(s) => s,
219        _ => return Err(String::from("str.replace third argument must be a string")),
220    };
221
222    Ok(Value::Str(target.replace(from, to)))
223}
224
225// =========================================================================
226// task 名前空間の組み込み関数
227// =========================================================================
228
229pub(crate) struct ParallelArgs {
230    lambda: Value,
231    env: Env,
232}
233
234pub(crate) fn parallel_entry(arg: usize) {
235    let args = unsafe { Box::from_raw(arg as *mut ParallelArgs) };
236    if let Value::Lambda(arg_names, body_ast, closure_env) = args.lambda {
237        if arg_names.is_empty() {
238            let mut local_env = Env::with_parent(*closure_env);
239            let _ = eval(&mut local_env, &body_ast);
240        }
241    }
242}
243
244pub(crate) fn builtin_task_parallel(env: &mut Env, args: &[AST]) -> Result<Value, String> {
245    let vals = eval_args(env, args)?;
246    if vals.len() != 1 {
247        return Err(String::from(
248            "task.parallel requires exactly 1 argument: (task.parallel lambda)",
249        ));
250    }
251    let lambda = vals[0].clone();
252    if !matches!(lambda, Value::Lambda(_, _, _)) {
253        return Err(String::from(
254            "task.parallel argument must be a lambda function",
255        ));
256    }
257
258    let thread_args = Box::new(ParallelArgs {
259        lambda,
260        env: env.clone(),
261    });
262    let arg_ptr = Box::into_raw(thread_args) as usize;
263
264    let pid = crate::kernel::scheduler::spawn_with_arg(
265        parallel_entry,
266        arg_ptr,
267        crate::kernel::scheduler::Priority::Normal,
268        "aura_parallel",
269    );
270
271    if pid == 0 {
272        return Err(String::from("Failed to spawn parallel thread"));
273    }
274
275    Ok(Value::Nil)
276}
277
278pub(crate) struct ForkJoinTask {
279    lambda: Value,
280    env: Env,
281    state: Arc<ForkJoinState>,
282}
283
284pub(crate) struct ForkJoinState {
285    done: AtomicBool,
286    result: Mutex<Result<Value, String>>,
287}
288
289pub(crate) fn fork_join_entry(arg: usize) {
290    let task = unsafe { Box::from_raw(arg as *mut ForkJoinTask) };
291    let res = if let Value::Lambda(arg_names, body_ast, closure_env) = &task.lambda {
292        if !arg_names.is_empty() {
293            Err(String::from("fork_join lambda must take 0 arguments"))
294        } else {
295            let mut local_env = Env::with_parent(*closure_env.clone());
296            eval(&mut local_env, body_ast).and_then(|v| force_eval(&mut local_env, v))
297        }
298    } else {
299        Err(String::from("fork_join argument must be a lambda"))
300    };
301
302    *task.state.result.lock() = res;
303    task.state.done.store(true, Ordering::Release);
304}
305
306pub(crate) fn builtin_task_fork_join(env: &mut Env, args: &[AST]) -> Result<Value, String> {
307    let vals = eval_args(env, args)?;
308    if vals.len() != 1 {
309        return Err(String::from(
310            "task.fork_join requires exactly 1 argument: (task.fork_join lambda_list)",
311        ));
312    }
313    let list = match &vals[0] {
314        Value::List(l) => l,
315        _ => {
316            return Err(String::from(
317                "task.fork_join argument must be a list of lambdas",
318            ))
319        }
320    };
321
322    let mut states = Vec::with_capacity(list.len());
323
324    for lambda in list {
325        if !matches!(lambda, Value::Lambda(_, _, _)) {
326            return Err(String::from(
327                "task.fork_join list elements must be lambda functions",
328            ));
329        }
330        let state = Arc::new(ForkJoinState {
331            done: AtomicBool::new(false),
332            result: Mutex::new(Ok(Value::Nil)),
333        });
334        states.push(state.clone());
335
336        let fork_task = Box::new(ForkJoinTask {
337            lambda: lambda.clone(),
338            env: env.clone(),
339            state,
340        });
341        let arg_ptr = Box::into_raw(fork_task) as usize;
342
343        let pid = crate::kernel::scheduler::spawn_with_arg(
344            fork_join_entry,
345            arg_ptr,
346            crate::kernel::scheduler::Priority::Normal,
347            "aura_forkjoin",
348        );
349        if pid == 0 {
350            return Err(String::from("Failed to spawn fork_join thread"));
351        }
352    }
353
354    // すべてのスレッドの終了を yield_now() しつつスピン待機
355    loop {
356        let mut all_done = true;
357        for state in &states {
358            if !state.done.load(Ordering::Acquire) {
359                all_done = false;
360                break;
361            }
362        }
363        if all_done {
364            break;
365        }
366        crate::kernel::scheduler::yield_now();
367    }
368
369    // 結果の回収
370    let mut results = Vec::with_capacity(states.len());
371    for state in states {
372        let res = state.result.lock().clone()?;
373        results.push(res);
374    }
375
376    Ok(Value::List(results))
377}
378
379pub(crate) struct QueueState {
380    queue: Mutex<VecDeque<Value>>,
381    closed: AtomicBool,
382}
383
384pub(crate) static QUEUES: Mutex<Option<alloc::collections::BTreeMap<usize, Arc<QueueState>>>> =
385    Mutex::new(None);
386pub(crate) static NEXT_QUEUE_ID: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(1);
387
388pub(crate) fn get_queue_id(val: &Value) -> Result<usize, String> {
389    if let Value::Dict(d) = val {
390        if let (Some(Value::Str(t)), Some(Value::Num(id))) = (d.get("__type"), d.get("id")) {
391            if t == "queue" {
392                if let Some(id_usize) = id.to_i64().map(|x| x as usize) {
393                    return Ok(id_usize);
394                }
395            }
396        }
397    }
398    Err(String::from("Argument is not a valid queue dictionary"))
399}
400
401pub(crate) fn builtin_task_queue(_env: &mut Env, _args: &[AST]) -> Result<Value, String> {
402    let mut q_map = QUEUES.lock();
403    let id = NEXT_QUEUE_ID.fetch_add(1, Ordering::SeqCst);
404    let state = Arc::new(QueueState {
405        queue: Mutex::new(VecDeque::new()),
406        closed: AtomicBool::new(false),
407    });
408    q_map
409        .get_or_insert_with(alloc::collections::BTreeMap::new)
410        .insert(id, state);
411
412    let mut dict = alloc::collections::BTreeMap::new();
413    dict.insert(String::from("__type"), Value::Str(String::from("queue")));
414    dict.insert(String::from("id"), Value::Num(BigInt::from_i64(id as i64)));
415    Ok(Value::Dict(dict))
416}
417
418pub(crate) fn builtin_task_send(env: &mut Env, args: &[AST]) -> Result<Value, String> {
419    let vals = eval_args(env, args)?;
420    if vals.len() != 2 {
421        return Err(String::from(
422            "task.send requires exactly 2 arguments: (task.send queue value)",
423        ));
424    }
425    let q_id = get_queue_id(&vals[0])?;
426    let val = vals[1].clone();
427
428    let q_map = QUEUES.lock();
429    if let Some(map) = q_map.as_ref() {
430        if let Some(q_state) = map.get(&q_id) {
431            if q_state.closed.load(Ordering::Relaxed) {
432                return Err(String::from("Cannot send to a closed queue"));
433            }
434            q_state.queue.lock().push_back(val);
435            return Ok(Value::Nil);
436        }
437    }
438    Err(String::from("Invalid queue object"))
439}
440
441pub(crate) fn builtin_task_recv(env: &mut Env, args: &[AST]) -> Result<Value, String> {
442    let vals = eval_args(env, args)?;
443    if vals.len() != 1 {
444        return Err(String::from(
445            "task.recv requires exactly 1 argument: (task.recv queue)",
446        ));
447    }
448    let q_id = get_queue_id(&vals[0])?;
449
450    let q_state = {
451        let q_map = QUEUES.lock();
452        if let Some(map) = q_map.as_ref() {
453            if let Some(q_state) = map.get(&q_id) {
454                q_state.clone()
455            } else {
456                return Err(String::from("Invalid queue object"));
457            }
458        } else {
459            return Err(String::from("Invalid queue object"));
460        }
461    };
462
463    loop {
464        if q_state.closed.load(Ordering::Relaxed) {
465            let mut lock = q_state.queue.lock();
466            if let Some(val) = lock.pop_front() {
467                return Ok(val);
468            }
469            return Ok(Value::Nil);
470        }
471
472        {
473            let mut lock = q_state.queue.lock();
474            if let Some(val) = lock.pop_front() {
475                return Ok(val);
476            }
477        }
478        crate::kernel::scheduler::yield_now();
479    }
480}
481
482pub(crate) fn builtin_task_close(env: &mut Env, args: &[AST]) -> Result<Value, String> {
483    let vals = eval_args(env, args)?;
484    if vals.len() != 1 {
485        return Err(String::from(
486            "task.close requires exactly 1 argument: (task.close queue)",
487        ));
488    }
489    let q_id = get_queue_id(&vals[0])?;
490
491    let mut q_map = QUEUES.lock();
492    if let Some(map) = q_map.as_mut() {
493        if let Some(q_state) = map.remove(&q_id) {
494            q_state.closed.store(true, Ordering::SeqCst);
495            return Ok(Value::Nil);
496        }
497    }
498    Err(String::from("Invalid queue object"))
499}
500
501// =========================================================================
502// テンプレートリテラルのセキュリティガードとフォーマッタ実装
503// =========================================================================
504
505pub(crate) static TEMPLATE_GUARD: Mutex<Option<Value>> = Mutex::new(None);
506pub(crate) static TEMPLATE_POST_GUARD: Mutex<Option<Value>> = Mutex::new(None);
507
508pub(crate) struct FormatSpec {
509    pub(crate) alternate: bool,          // '#'
510    pub(crate) zero_pad: bool,           // '0'
511    pub(crate) width: usize,             // width
512    pub(crate) comma: bool,              // ','
513    pub(crate) precision: Option<usize>, // .precision
514    pub(crate) fmt_type: Option<char>,   // 'b', 'x', 'X', 'f', 'e', 'E'
515}
516