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
91pub fn detect_language(source: &str) -> &'static str {
93 let languages: &[(&[&str], &str)] = &[
94 (
95 &[
96 "令", "灵符", "执", "函", "核", "若", "否则", "历", "于", "配", "归", "印", "格式",
97 ],
98 "Chinese (中文)",
99 ),
100 (
101 &[
102 "束縛",
103 "実行",
104 "もし",
105 "一方",
106 "ために",
107 "試す",
108 "待つ",
109 "帰る",
110 ],
111 "Japanese (日本語)",
112 ),
113 (
114 &["바인드", "만약", "동안", "출력", "시작"],
115 "Korean (한국어)",
116 ),
117 (
118 &[
119 "связать",
120 "сделать",
121 "если",
122 "иначе",
123 "пока",
124 "для",
125 "вернуть",
126 "вывести",
127 ],
128 "Russian (русский)",
129 ),
130 (
131 &[
132 "ผูก",
133 "ทำ",
134 "ถ้า",
135 "มิฉะนั้น",
136 "สำหรับ",
137 "คืน",
138 "พิมพ์",
139 "รูปแบบ",
140 "เริ่ม",
141 ],
142 "Thai (ภาษาไทย)",
143 ),
144 (
145 &["बाँधो", "करो", "अगर", "जबकि", "वापस", "सत्य"],
146 "Hindi (हिन्दी)",
147 ),
148 (
149 &["ربط", "افعل", "إذا", "وإلا", "بينما", "أعد"],
150 "Arabic (العربية)",
151 ),
152 (
153 &["enlazar", "hacer", "mientras", "retornar", "verdadero"],
154 "Spanish (Español)",
155 ),
156 (
157 &["lier", "faire", "sinon", "tantque", "retourner", "vrai"],
158 "French (Français)",
159 ),
160 (
161 &["binden", "machen", "wenn", "solange", "zurück", "wahr"],
162 "German (Deutsch)",
163 ),
164 (
165 &["ligar", "fazer", "enquanto", "retornar", "verdadeiro"],
166 "Portuguese (Português)",
167 ),
168 ];
169
170 let best = languages
171 .iter()
172 .map(|(keywords, lang)| {
173 let count = keywords.iter().filter(|&&k| source.contains(k)).count();
174 (count, *lang)
175 })
176 .max_by_key(|&(count, _)| count);
177
178 match best {
179 Some((count, lang)) if count > 0 => lang,
180 _ => "English",
181 }
182}