1use std::fmt::{Debug, Display, Formatter};
2use std::num::NonZeroU32;
3use tanzim_source::Source;
4
5#[derive(Debug, Clone, PartialEq)]
13pub struct Location {
14 pub source: Source,
15 pub line: Option<NonZeroU32>,
16 pub column: Option<NonZeroU32>,
17 pub length: Option<NonZeroU32>,
19 pub snippet: String,
24}
25
26fn position(value: usize) -> Option<NonZeroU32> {
31 NonZeroU32::new(u32::try_from(value).unwrap_or(u32::MAX))
32}
33
34impl Location {
35 pub fn in_source(
40 source: Source,
41 line: Option<usize>,
42 column: Option<usize>,
43 length: Option<usize>,
44 ) -> Self {
45 Self {
46 source,
47 line: line.and_then(position),
48 column: column.and_then(position),
49 length: length.and_then(position),
50 snippet: String::new(),
51 }
52 }
53
54 pub fn in_text(
60 source: Source,
61 text: &str,
62 line: Option<usize>,
63 column: Option<usize>,
64 length: Option<usize>,
65 ) -> Self {
66 let mut snippet = String::new();
67 if let Some(line_number) = line {
68 let highlight = length.unwrap_or(1).max(1);
69 let lines: Vec<&str> = text.split('\n').collect();
70 let offending = line_number.saturating_sub(1);
71 let start = offending.saturating_sub(3);
72 let end = (offending + 4).min(lines.len());
73 let gutter_width = end.to_string().len();
74 let mut rows: Vec<String> = Vec::new();
75 for (offset, line_text) in lines[start..end].iter().enumerate() {
76 let display_line = start + offset + 1;
77 let number = display_line.to_string();
78 let pad = gutter_width.saturating_sub(number.len());
79 let mut row = String::from(" ");
80 for _ in 0..pad {
81 row.push(' ');
82 }
83 row.push_str(&number);
84 row.push_str(" | ");
85 row.push_str(line_text);
86 rows.push(row);
87 if display_line == line_number {
88 let mut caret = String::from(" ");
89 for _ in 0..pad + number.len() + 1 {
90 caret.push(' ');
91 }
92 caret.push_str("| ");
93 if let Some(column_number) = column {
94 for _ in 1..column_number {
95 caret.push(' ');
96 }
97 }
98 for _ in 0..highlight {
99 caret.push('^');
100 }
101 rows.push(caret);
102 }
103 }
104 snippet = rows.join("\n");
105 }
106 Self {
107 source,
108 line: line.and_then(position),
109 column: column.and_then(position),
110 length: length.and_then(position),
111 snippet,
112 }
113 }
114
115 pub fn at(
118 source_name: &str,
119 resource: &str,
120 line: Option<usize>,
121 column: Option<usize>,
122 length: Option<usize>,
123 ) -> Self {
124 Self::in_source(
125 Source::named(source_name).with_resource(resource),
126 line,
127 column,
128 length,
129 )
130 }
131
132 pub fn source_name(&self) -> &str {
134 self.source.source()
135 }
136
137 pub fn resource(&self) -> &str {
139 self.source.resource()
140 }
141
142 pub fn with_length(mut self, length: usize) -> Self {
143 self.length = position(length);
144 self
145 }
146}
147
148impl Display for Location {
149 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
150 let resource = self.source.resource();
151 if resource.is_empty() {
152 write!(f, "{}", self.source.source())?;
153 } else {
154 write!(f, "{}:{}", self.source.source(), resource)?;
155 }
156 match (self.line, self.column) {
157 (Some(line), Some(column)) => write!(f, ":{line}:{column}"),
158 (Some(line), None) => write!(f, ":{line}"),
159 _ => Ok(()),
160 }
161 }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166pub enum ValueType {
167 Bool,
168 Int,
169 Float,
170 String,
171 List,
172 Map,
173 Null,
174}
175
176impl Display for ValueType {
177 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
178 f.write_str(match self {
179 Self::Bool => "boolean",
180 Self::Int => "integer",
181 Self::Float => "float",
182 Self::String => "string",
183 Self::List => "list",
184 Self::Map => "map",
185 Self::Null => "null",
186 })
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Default)]
192pub struct Map {
193 entries: Vec<(String, LocatedValue)>,
194}
195
196impl Map {
197 pub fn new() -> Self {
198 Self::default()
199 }
200
201 pub fn len(&self) -> usize {
202 self.entries.len()
203 }
204
205 pub fn is_empty(&self) -> bool {
206 self.entries.is_empty()
207 }
208
209 pub fn contains_key(&self, key: &str) -> bool {
210 for index in (0..self.entries.len()).rev() {
211 if self.entries[index].0 == key {
212 return true;
213 }
214 }
215 false
216 }
217
218 pub fn get(&self, key: &str) -> Option<&LocatedValue> {
219 for index in (0..self.entries.len()).rev() {
220 if self.entries[index].0 == key {
221 return Some(&self.entries[index].1);
222 }
223 }
224 None
225 }
226
227 pub fn get_mut(&mut self, key: &str) -> Option<&mut LocatedValue> {
228 let mut found = None;
229 for index in (0..self.entries.len()).rev() {
230 if self.entries[index].0 == key {
231 found = Some(index);
232 break;
233 }
234 }
235 if let Some(index) = found {
236 Some(&mut self.entries[index].1)
237 } else {
238 None
239 }
240 }
241
242 pub fn insert(&mut self, key: String, value: LocatedValue) -> Option<LocatedValue> {
243 let old = self.remove(&key);
244 self.entries.push((key, value));
245 old
246 }
247
248 pub fn remove(&mut self, key: &str) -> Option<LocatedValue> {
249 let mut found = None;
250 for index in (0..self.entries.len()).rev() {
251 if self.entries[index].0 == key {
252 found = Some(index);
253 break;
254 }
255 }
256 if let Some(index) = found {
257 Some(self.entries.remove(index).1)
258 } else {
259 None
260 }
261 }
262
263 pub fn entries(&self) -> &[(String, LocatedValue)] {
264 &self.entries
265 }
266
267 pub fn entries_mut(&mut self) -> &mut Vec<(String, LocatedValue)> {
268 &mut self.entries
269 }
270}
271
272impl Display for Map {
273 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
274 let alternate = f.alternate();
275 let mut map = f.debug_map();
276 for (key, value) in &self.entries {
277 if alternate {
278 map.entry(key, &format_args!("{:#}", value));
279 } else {
280 map.entry(key, &format_args!("{}", value));
281 }
282 }
283 map.finish()
284 }
285}
286
287#[derive(Debug, Clone, PartialEq)]
289pub enum Value {
290 Bool(bool),
291 Int(isize),
292 Float(f64),
293 String(String),
294 List(Vec<LocatedValue>),
295 Map(Map),
296 Null,
297}
298
299#[derive(Debug, Clone, PartialEq, Default)]
304pub struct Comment {
305 before: Vec<String>,
306 after: Option<String>,
307}
308
309impl Comment {
310 pub fn new() -> Self {
311 Self::default()
312 }
313
314 pub fn before(&self) -> &[String] {
316 &self.before
317 }
318
319 pub fn before_mut(&mut self) -> &mut Vec<String> {
320 &mut self.before
321 }
322
323 pub fn after(&self) -> Option<&str> {
325 self.after.as_deref()
326 }
327
328 pub fn after_mut(&mut self) -> &mut Option<String> {
329 &mut self.after
330 }
331
332 pub fn with_before(mut self, lines: impl IntoIterator<Item = impl Into<String>>) -> Self {
334 self.before = lines.into_iter().map(|l| l.into()).collect();
335 self
336 }
337
338 pub fn with_after(mut self, text: Option<impl Into<String>>) -> Self {
340 self.after = text.map(|t| t.into());
341 self
342 }
343
344 pub fn set_before(&mut self, lines: impl IntoIterator<Item = impl Into<String>>) {
346 self.before = lines.into_iter().map(|l| l.into()).collect();
347 }
348
349 pub fn set_after(&mut self, text: Option<impl Into<String>>) {
351 self.after = text.map(|t| t.into());
352 }
353}
354
355#[derive(Debug, Clone, PartialEq)]
361pub struct LocatedValue {
362 value: Value,
363 location: Location,
364 comment: Comment,
365}
366
367impl LocatedValue {
368 pub fn new(value: impl Into<Value>, location: impl Into<Location>) -> Self {
370 Self {
371 value: value.into(),
372 location: location.into(),
373 comment: Comment::new(),
374 }
375 }
376
377 pub fn value(&self) -> &Value {
380 &self.value
381 }
382
383 pub fn value_mut(&mut self) -> &mut Value {
384 &mut self.value
385 }
386
387 pub fn into_value(self) -> Value {
388 self.value
389 }
390
391 pub fn with_value(mut self, value: impl Into<Value>) -> Self {
392 self.value = value.into();
393 self
394 }
395
396 pub fn set_value(&mut self, value: impl Into<Value>) {
397 self.value = value.into();
398 }
399
400 pub fn location(&self) -> &Location {
403 &self.location
404 }
405
406 pub fn location_mut(&mut self) -> &mut Location {
407 &mut self.location
408 }
409
410 pub fn with_location(mut self, location: impl Into<Location>) -> Self {
411 self.location = location.into();
412 self
413 }
414
415 pub fn set_location(&mut self, location: impl Into<Location>) {
416 self.location = location.into();
417 }
418
419 pub fn comment(&self) -> &Comment {
422 &self.comment
423 }
424
425 pub fn comment_mut(&mut self) -> &mut Comment {
426 &mut self.comment
427 }
428
429 pub fn with_comment(mut self, comment: Comment) -> Self {
430 self.comment = comment;
431 self
432 }
433
434 pub fn set_comment(&mut self, comment: Comment) {
435 self.comment = comment;
436 }
437}
438
439impl Display for LocatedValue {
440 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
441 if f.alternate() {
442 let mut map = f.debug_map();
443 map.entry(&"value", &format_args!("{:#}", self.value));
444 map.entry(
445 &"location",
446 &format_args!("{:?}", self.location.to_string()),
447 );
448 if !self.comment.before.is_empty() || self.comment.after.is_some() {
449 map.entry(&"comment_before", &self.comment.before.as_slice());
450 if let Some(after) = &self.comment.after {
451 map.entry(&"comment_after", &after.as_str());
452 }
453 }
454 map.finish()
455 } else {
456 write!(f, "{}", self.value)
457 }
458 }
459}
460
461impl AsRef<Value> for Value {
462 fn as_ref(&self) -> &Value {
463 self
464 }
465}
466
467impl AsRef<Value> for LocatedValue {
468 fn as_ref(&self) -> &Value {
469 &self.value
470 }
471}
472
473impl Value {
474 pub fn new_map() -> Self {
475 Self::Map(Map::new())
476 }
477
478 pub fn new_list() -> Self {
479 Self::List(Vec::new())
480 }
481
482 pub fn new_string() -> Self {
483 Self::String(String::new())
484 }
485
486 pub fn is_bool(&self) -> bool {
487 matches!(self, Self::Bool(_))
488 }
489
490 pub fn as_bool(&self) -> Option<bool> {
491 match self {
492 Self::Bool(value) => Some(*value),
493 _ => None,
494 }
495 }
496
497 pub fn into_bool(self) -> Option<bool> {
498 match self {
499 Self::Bool(value) => Some(value),
500 _ => None,
501 }
502 }
503
504 pub fn bool_mut(&mut self) -> Option<&mut bool> {
505 match self {
506 Self::Bool(value) => Some(value),
507 _ => None,
508 }
509 }
510
511 pub fn is_int(&self) -> bool {
512 matches!(self, Self::Int(_))
513 }
514
515 pub fn as_int(&self) -> Option<isize> {
516 match self {
517 Self::Int(value) => Some(*value),
518 _ => None,
519 }
520 }
521
522 pub fn into_int(self) -> Option<isize> {
523 match self {
524 Self::Int(value) => Some(value),
525 _ => None,
526 }
527 }
528
529 pub fn int_mut(&mut self) -> Option<&mut isize> {
530 match self {
531 Self::Int(value) => Some(value),
532 _ => None,
533 }
534 }
535
536 pub fn is_float(&self) -> bool {
537 matches!(self, Self::Float(_))
538 }
539
540 pub fn as_float(&self) -> Option<f64> {
541 match self {
542 Self::Float(value) => Some(*value),
543 _ => None,
544 }
545 }
546
547 pub fn into_float(self) -> Option<f64> {
548 match self {
549 Self::Float(value) => Some(value),
550 _ => None,
551 }
552 }
553
554 pub fn float_mut(&mut self) -> Option<&mut f64> {
555 match self {
556 Self::Float(value) => Some(value),
557 _ => None,
558 }
559 }
560
561 pub fn is_string(&self) -> bool {
562 matches!(self, Self::String(_))
563 }
564
565 pub fn as_string(&self) -> Option<&String> {
566 match self {
567 Self::String(value) => Some(value),
568 _ => None,
569 }
570 }
571
572 pub fn into_string(self) -> Option<String> {
573 match self {
574 Self::String(value) => Some(value),
575 _ => None,
576 }
577 }
578
579 pub fn string_mut(&mut self) -> Option<&mut String> {
580 match self {
581 Self::String(value) => Some(value),
582 _ => None,
583 }
584 }
585
586 pub fn is_list(&self) -> bool {
587 matches!(self, Self::List(_))
588 }
589
590 pub fn as_list(&self) -> Option<&Vec<LocatedValue>> {
591 match self {
592 Self::List(value) => Some(value),
593 _ => None,
594 }
595 }
596
597 pub fn into_list(self) -> Option<Vec<LocatedValue>> {
598 match self {
599 Self::List(value) => Some(value),
600 _ => None,
601 }
602 }
603
604 pub fn list_mut(&mut self) -> Option<&mut Vec<LocatedValue>> {
605 match self {
606 Self::List(value) => Some(value),
607 _ => None,
608 }
609 }
610
611 pub fn is_map(&self) -> bool {
612 matches!(self, Self::Map(_))
613 }
614
615 pub fn as_map(&self) -> Option<&Map> {
616 match self {
617 Self::Map(value) => Some(value),
618 _ => None,
619 }
620 }
621
622 pub fn into_map(self) -> Option<Map> {
623 match self {
624 Self::Map(value) => Some(value),
625 _ => None,
626 }
627 }
628
629 pub fn map_mut(&mut self) -> Option<&mut Map> {
630 match self {
631 Self::Map(value) => Some(value),
632 _ => None,
633 }
634 }
635
636 pub fn is_null(&self) -> bool {
637 matches!(self, Self::Null)
638 }
639
640 pub fn type_name(&self) -> ValueType {
641 match self {
642 Self::Bool(_) => ValueType::Bool,
643 Self::Int(_) => ValueType::Int,
644 Self::Float(_) => ValueType::Float,
645 Self::String(_) => ValueType::String,
646 Self::List(_) => ValueType::List,
647 Self::Map(_) => ValueType::Map,
648 Self::Null => ValueType::Null,
649 }
650 }
651}
652
653impl Display for Value {
654 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
655 match self {
656 Self::Bool(value) => write!(f, "{value}"),
657 Self::Int(value) => write!(f, "{value}"),
658 Self::Float(value) => write!(f, "{value}"),
659 Self::String(value) => write!(f, "{value:?}"),
660 Self::List(values) => {
661 let alternate = f.alternate();
662 let mut list = f.debug_list();
663 for value in values {
664 if alternate {
665 list.entry(&format_args!("{:#}", value));
666 } else {
667 list.entry(&format_args!("{}", value));
668 }
669 }
670 list.finish()
671 }
672 Self::Map(value) => Display::fmt(value, f),
673 Self::Null => f.write_str("null"),
674 }
675 }
676}