1#![doc(
4 html_logo_url = "https://ling-lang.org/images/logo.svg",
5 html_favicon_url = "https://ling-lang.org/images/logo.svg"
6)]
7
8pub mod astviz;
9pub mod borrowck;
10pub mod codegen;
11#[cfg(not(target_arch = "wasm32"))]
12pub mod convert;
13pub mod core;
14pub mod diag;
15pub mod entry;
16pub mod gfx;
17pub mod lexer;
18pub mod lexicon;
19pub mod mir;
20pub mod parser;
21pub mod polyglot;
22pub mod runtime;
23pub mod semantic;
24pub mod utils;
25pub mod visualize;
26
27#[cfg(not(target_arch = "wasm32"))]
28pub use ling_audio;
29
30pub use core::{CompilerConfig, LingCompiler, OptimizationLevel};
32pub use lexicon::{CanonicalToken, Lexicon, LexiconRegistry};
33pub use polyglot::{normalize_source, ScriptDetector};
34
35pub const VERSION: &str = env!("CARGO_PKG_VERSION");
37
38pub fn run(source: &str) -> Result<(), String> {
41 run_named(source, None, None)
42}
43
44pub fn unpack_resources(app: &str, resources: &[(&str, &[u8])]) {
51 if resources.is_empty() {
52 return;
53 }
54 let base = std::env::temp_dir().join(format!("ling-pack-{app}"));
55 for (rel, bytes) in resources {
56 let dst = base.join(rel);
57 if let Some(parent) = dst.parent() {
58 let _ = std::fs::create_dir_all(parent);
59 }
60 let _ = std::fs::write(&dst, bytes);
61 }
62 let _ = std::env::set_current_dir(&base);
63}
64
65pub fn run_file(source: &str, source_dir: Option<std::path::PathBuf>) -> Result<(), String> {
67 run_named(source, source_dir, None)
68}
69
70pub fn run_named(
74 source: &str,
75 source_dir: Option<std::path::PathBuf>,
76 file: Option<&str>,
77) -> Result<(), String> {
78 let lang = diag::OutputLang::from_env();
79 let program = parser::parse(source).map_err(|e| diag::render_parse(&e, source, file, lang))?;
80 let mut interp = runtime::Interpreter::new();
81 interp.source_dir = source_dir;
82 match interp.run_program(&program) {
83 Ok(()) => Ok(()),
84 Err(msg) => {
85 let trace = interp.take_error_trace();
86 Err(diag::render_runtime(&msg, source, file, &trace, lang))
87 },
88 }
89}
90
91#[cfg(not(target_arch = "wasm32"))]
99pub fn run_jit(
100 source: &str,
101 source_dir: Option<std::path::PathBuf>,
102 file: Option<&str>,
103) -> Result<(), String> {
104 let lang = diag::OutputLang::from_env();
105 let has_entry = parser::parse(source)
106 .map(|p| entry::entry_name(&p.items).is_some())
107 .unwrap_or(true);
108 if !has_entry {
109 return run_named(source, source_dir, file);
110 }
111 let compiler = LingCompiler::new(CompilerConfig::default());
112 match compiler.compile_and_run_jit_source(source, source_dir.clone()) {
113 Ok(()) => Ok(()),
114 Err(core::LingError::Parse(m)) => Err(diag::render_parse(&m, source, file, lang)),
115 Err(core::LingError::Mir(m)) => Err(m),
116 Err(_) => run_named(source, source_dir, file),
117 }
118}
119
120pub fn detect_language(source: &str) -> &'static str {
122 let languages: &[(&[&str], &str)] = &[
123 (
124 &[
125 "令", "灵符", "执", "函", "核", "若", "否则", "历", "于", "配", "归", "印", "格式",
126 ],
127 "Chinese (中文)",
128 ),
129 (
130 &[
131 "束縛",
132 "実行",
133 "もし",
134 "一方",
135 "ために",
136 "試す",
137 "待つ",
138 "帰る",
139 ],
140 "Japanese (日本語)",
141 ),
142 (
143 &["바인드", "만약", "동안", "출력", "시작"],
144 "Korean (한국어)",
145 ),
146 (
147 &[
148 "связать",
149 "сделать",
150 "если",
151 "иначе",
152 "пока",
153 "для",
154 "вернуть",
155 "вывести",
156 ],
157 "Russian (русский)",
158 ),
159 (
160 &[
161 "ผูก",
162 "ทำ",
163 "ถ้า",
164 "มิฉะนั้น",
165 "สำหรับ",
166 "คืน",
167 "พิมพ์",
168 "รูปแบบ",
169 "เริ่ม",
170 ],
171 "Thai (ภาษาไทย)",
172 ),
173 (
174 &["बाँधो", "करो", "अगर", "जबकि", "वापस", "सत्य"],
175 "Hindi (हिन्दी)",
176 ),
177 (
178 &["ربط", "افعل", "إذا", "وإلا", "بينما", "أعد"],
179 "Arabic (العربية)",
180 ),
181 (
182 &["enlazar", "hacer", "mientras", "retornar", "verdadero"],
183 "Spanish (Español)",
184 ),
185 (
186 &["lier", "faire", "sinon", "tantque", "retourner", "vrai"],
187 "French (Français)",
188 ),
189 (
190 &["binden", "machen", "wenn", "solange", "zurück", "wahr"],
191 "German (Deutsch)",
192 ),
193 (
194 &["ligar", "fazer", "enquanto", "retornar", "verdadeiro"],
195 "Portuguese (Português)",
196 ),
197 ];
198
199 let best = languages
200 .iter()
201 .map(|(keywords, lang)| {
202 let count = keywords.iter().filter(|&&k| source.contains(k)).count();
203 (count, *lang)
204 })
205 .max_by_key(|&(count, _)| count);
206
207 match best {
208 Some((count, lang)) if count > 0 => lang,
209 _ => "English",
210 }
211}