1#![warn(missing_docs)]
2
3use dashmap::DashMap;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::sync::Arc;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct Span {
14 pub start: u32,
15 pub end: u32,
16}
17
18impl Span {
19 pub fn new(start: u32, end: u32) -> Self {
20 Self { start, end }
21 }
22
23 pub fn unknown() -> Self {
24 Self { start: 0, end: 0 }
25 }
26}
27
28impl Default for Span {
29 fn default() -> Self {
30 Self::unknown()
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
36pub struct Loc {
37 pub source_id: u32,
38 pub span: Span,
39}
40
41impl Loc {
42 pub fn new(source_id: u32, start: u32, end: u32) -> Self {
43 Self {
44 source_id,
45 span: Span::new(start, end),
46 }
47 }
48
49 pub fn unknown() -> Self {
51 Self {
52 source_id: 0,
53 span: Span::unknown(),
54 }
55 }
56
57 pub fn is_unknown(&self) -> bool {
58 self.source_id == 0
59 }
60}
61
62impl Default for Loc {
63 fn default() -> Self {
64 Self::unknown()
65 }
66}
67
68pub struct SourceEntry {
70 pub path: String,
71 pub content: Arc<String>,
72 pub line_map: LineMap,
73}
74
75pub struct LineMap {
77 line_starts: Vec<u32>,
78}
79
80impl LineMap {
81 pub fn new(content: &str) -> Self {
82 let mut line_starts = vec![0];
83 for (i, c) in content.char_indices() {
84 if c == '\n' {
85 line_starts.push((i + 1) as u32);
86 }
87 }
88 Self { line_starts }
89 }
90
91 pub fn lookup(&self, offset: u32) -> (u32, u32) {
92 let line = match self.line_starts.binary_search(&offset) {
93 Ok(line) => line,
94 Err(line) => line - 1,
95 };
96 let col = offset - self.line_starts[line];
97 (line as u32 + 1, col + 1)
98 }
99}
100
101pub struct SourceManager {
103 sources: DashMap<u32, SourceEntry>,
104 next_id: std::sync::atomic::AtomicUsize,
105}
106
107impl SourceManager {
108 pub fn new() -> Self {
109 Self {
110 sources: DashMap::new(),
111 next_id: std::sync::atomic::AtomicUsize::new(1),
112 }
113 }
114
115 pub fn register(&self, path: &str, content: String) -> u32 {
116 let id = self
117 .next_id
118 .fetch_add(1, std::sync::atomic::Ordering::SeqCst) as u32;
119 let line_map = LineMap::new(&content);
120 let entry = SourceEntry {
121 path: path.to_string(),
122 content: Arc::new(content),
123 line_map,
124 };
125 self.sources.insert(id, entry);
126 id
127 }
128
129 pub fn get(&self, id: u32) -> Option<dashmap::mapref::one::Ref<'_, u32, SourceEntry>> {
130 self.sources.get(&id)
131 }
132}
133
134impl Default for SourceManager {
135 fn default() -> Self {
136 Self::new()
137 }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
143pub enum Intent {
144 Map,
146 Reduce,
148 StateUpdate,
150 Branch,
152 Loop,
154 LifeCycle,
156 Meta,
158 Trap,
160}
161
162#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
165pub enum Context {
166 Linear,
168 RefCounting,
170 Async,
172 Comptime,
174 GPU,
176 SIMD,
178 Safe,
180 General,
182}
183
184#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
186pub struct IntentNode {
187 pub intent: Intent,
188 pub contexts: Vec<Context>,
189 pub attributes: HashMap<String, String>,
191}
192
193impl IntentNode {
194 pub fn new(intent: Intent) -> Self {
195 Self {
196 intent,
197 contexts: vec![Context::General],
198 attributes: HashMap::new(),
199 }
200 }
201
202 pub fn with_context(mut self, context: Context) -> Self {
203 self.contexts.push(context);
204 self
205 }
206
207 pub fn with_attribute(mut self, key: &str, value: &str) -> Self {
208 self.attributes.insert(key.to_string(), value.to_string());
209 self
210 }
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct ChomskyError {
216 pub kind: Box<ChomskyErrorKind>,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub enum ChomskyErrorKind {
221 UirError {
222 kind: String, details: String,
224 },
225 FrontendError {
226 stage: String, file: Option<String>,
228 line: Option<u32>,
229 message: String,
230 },
231 BackendError {
232 target: String, stage: String, message: String,
235 },
236 IoError {
237 path: Option<String>,
238 operation: String,
239 message: String,
240 },
241 Unknown {
242 code: i32,
243 message: String,
244 },
245}
246
247impl ChomskyErrorKind {
248 pub fn key(&self) -> &str {
249 match self {
250 Self::UirError { .. } => "uir_error",
251 Self::FrontendError { .. } => "frontend_error",
252 Self::BackendError { .. } => "backend_error",
253 Self::IoError { .. } => "io_error",
254 Self::Unknown { .. } => "unknown",
255 }
256 }
257}
258
259impl std::fmt::Display for ChomskyError {
260 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261 match &*self.kind {
262 ChomskyErrorKind::UirError { kind, details } => {
263 write!(f, "UIR Error [{}]: {}", kind, details)
264 }
265 ChomskyErrorKind::FrontendError {
266 stage,
267 file,
268 line,
269 message,
270 } => {
271 let loc = match (file, line) {
272 (Some(file), Some(line)) => format!("{}:{}", file, line),
273 (Some(file), None) => file.clone(),
274 _ => "unknown location".to_string(),
275 };
276 write!(f, "Frontend Error [{} at {}]: {}", stage, loc, message)
277 }
278 ChomskyErrorKind::BackendError {
279 target,
280 stage,
281 message,
282 } => write!(f, "Backend Error [{} - {}]: {}", target, stage, message),
283 ChomskyErrorKind::IoError {
284 path,
285 operation,
286 message,
287 } => {
288 let p = path.as_deref().unwrap_or("unknown path");
289 write!(f, "IO Error [{} on {}]: {}", operation, p, message)
290 }
291 ChomskyErrorKind::Unknown { code, message } => {
292 write!(f, "Unknown Error ({}): {}", code, message)
293 }
294 }
295 }
296}
297
298impl std::error::Error for ChomskyError {}
299
300impl ChomskyError {
301 pub fn new(kind: ChomskyErrorKind) -> Self {
302 Self {
303 kind: Box::new(kind),
304 }
305 }
306
307 pub fn uir_error(msg: impl Into<String>) -> Self {
308 Self::new(ChomskyErrorKind::UirError {
309 kind: "General".to_string(),
310 details: msg.into(),
311 })
312 }
313
314 pub fn frontend_error(msg: impl Into<String>) -> Self {
315 Self::new(ChomskyErrorKind::FrontendError {
316 stage: "General".to_string(),
317 file: None,
318 line: None,
319 message: msg.into(),
320 })
321 }
322
323 pub fn backend_error(msg: impl Into<String>) -> Self {
324 Self::new(ChomskyErrorKind::BackendError {
325 target: "Unknown".to_string(),
326 stage: "General".to_string(),
327 message: msg.into(),
328 })
329 }
330
331 pub fn io_error(msg: impl Into<String>) -> Self {
332 Self::new(ChomskyErrorKind::IoError {
333 path: None,
334 operation: "Unknown".to_string(),
335 message: msg.into(),
336 })
337 }
338
339 pub fn unknown(msg: impl Into<String>) -> Self {
340 Self::new(ChomskyErrorKind::Unknown {
341 code: -1,
342 message: msg.into(),
343 })
344 }
345}
346
347impl From<std::io::Error> for ChomskyError {
348 fn from(err: std::io::Error) -> Self {
349 Self::io_error(err.to_string())
350 }
351}
352
353pub type ChomskyResult<T> = Result<T, ChomskyError>;