1use std::fmt;
23use std::sync::Arc;
24
25use beck_diag::Span;
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct Scope(pub u32);
31
32#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct ScopeSet(Arc<[Scope]>);
38
39impl ScopeSet {
40 pub fn empty() -> ScopeSet {
41 ScopeSet(Arc::from([] as [Scope; 0]))
42 }
43
44 pub fn is_empty(&self) -> bool {
45 self.0.is_empty()
46 }
47
48 pub fn len(&self) -> usize {
49 self.0.len()
50 }
51
52 pub fn contains(&self, s: Scope) -> bool {
53 self.0.binary_search(&s).is_ok()
54 }
55
56 pub fn insert(&self, s: Scope) -> ScopeSet {
57 if self.contains(s) {
58 return self.clone();
59 }
60 let mut v = self.0.to_vec();
61 v.push(s);
62 v.sort_unstable();
63 ScopeSet(Arc::from(v))
64 }
65
66 pub fn remove(&self, s: Scope) -> ScopeSet {
67 if !self.contains(s) {
68 return self.clone();
69 }
70 let v: Vec<Scope> = self.0.iter().copied().filter(|x| *x != s).collect();
71 ScopeSet(Arc::from(v))
72 }
73
74 pub fn flip(&self, s: Scope) -> ScopeSet {
80 if self.contains(s) {
81 self.remove(s)
82 } else {
83 self.insert(s)
84 }
85 }
86
87 pub fn is_subset_of(&self, other: &ScopeSet) -> bool {
89 let (mut i, mut j) = (0, 0);
90 while i < self.0.len() {
91 if j >= other.0.len() {
92 return false;
93 }
94 match self.0[i].cmp(&other.0[j]) {
95 std::cmp::Ordering::Equal => {
96 i += 1;
97 j += 1;
98 }
99 std::cmp::Ordering::Greater => j += 1,
100 std::cmp::Ordering::Less => return false,
101 }
102 }
103 true
104 }
105}
106
107impl fmt::Debug for ScopeSet {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "{{")?;
110 for (i, s) in self.0.iter().enumerate() {
111 if i > 0 {
112 write!(f, ",")?;
113 }
114 write!(f, "{}", s.0)?;
115 }
116 write!(f, "}}")
117 }
118}
119
120#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
122pub struct Symbol {
123 pub name: Arc<str>,
124 pub scopes: ScopeSet,
125}
126
127impl Symbol {
128 pub fn new(name: impl AsRef<str>) -> Symbol {
129 Symbol {
130 name: Arc::from(name.as_ref()),
131 scopes: ScopeSet::empty(),
132 }
133 }
134
135 pub fn as_str(&self) -> &str {
136 &self.name
137 }
138
139 pub fn with_scopes(&self, scopes: ScopeSet) -> Symbol {
140 Symbol {
141 name: self.name.clone(),
142 scopes,
143 }
144 }
145}
146
147impl fmt::Debug for Symbol {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 if self.scopes.is_empty() {
150 write!(f, "{}", self.name)
151 } else {
152 write!(f, "{}{:?}", self.name, self.scopes)
153 }
154 }
155}
156
157impl fmt::Display for Symbol {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 f.write_str(&self.name)
160 }
161}
162
163#[derive(Clone, Debug)]
166pub enum Lit {
167 Int(i64),
168 Float(f64),
169 Str(Arc<str>),
170 Bool(bool),
171 Keyword(Arc<str>),
174}
175
176impl PartialEq for Lit {
177 fn eq(&self, other: &Self) -> bool {
178 match (self, other) {
179 (Lit::Int(a), Lit::Int(b)) => a == b,
180 (Lit::Float(a), Lit::Float(b)) => a.to_bits() == b.to_bits(),
181 (Lit::Str(a), Lit::Str(b)) => a == b,
182 (Lit::Bool(a), Lit::Bool(b)) => a == b,
183 (Lit::Keyword(a), Lit::Keyword(b)) => a == b,
184 _ => false,
185 }
186 }
187}
188
189impl Eq for Lit {}
190
191impl Lit {
192 pub fn type_name(&self) -> &'static str {
193 match self {
194 Lit::Int(_) => "int",
195 Lit::Float(_) => "float",
196 Lit::Str(_) => "str",
197 Lit::Bool(_) => "bool",
198 Lit::Keyword(_) => "keyword",
199 }
200 }
201}
202
203#[derive(Clone, Debug, PartialEq)]
204pub enum Head {
205 Sym(Symbol),
206 Lit(Lit),
207}
208
209#[derive(Clone, Debug, Default)]
211pub struct Meta {
212 pub span: Span,
213 pub expansion: Vec<(Arc<str>, Span)>,
215 pub doc: Option<Arc<str>>,
222}
223
224impl Meta {
225 pub fn at(span: Span) -> Meta {
226 Meta {
227 span,
228 expansion: Vec::new(),
229 doc: None,
230 }
231 }
232}
233
234impl PartialEq for Node {
241 fn eq(&self, other: &Self) -> bool {
242 self.structurally_eq(other)
243 }
244}
245
246impl Eq for Node {}
247
248#[derive(Clone, Debug)]
249pub struct Node {
250 pub head: Head,
251 pub args: Vec<Node>,
252 pub applied: bool,
259 pub meta: Meta,
260}
261
262pub mod sym {
265 pub const MODULE: &str = "module";
266 pub const DEF: &str = "def";
267 pub const PARAMS: &str = "params";
268 pub const TYPARAMS: &str = "typarams";
271 pub const REST: &str = "rest";
273 pub const RETURNS: &str = "returns";
274 pub const ANNOT: &str = ":";
275 pub const FN: &str = "fn";
276 pub const CALL: &str = "call";
277 pub const DOT: &str = ".";
278 pub const IF: &str = "if";
279 pub const LET: &str = "let";
280 pub const VAR: &str = "var";
281 pub const SET: &str = "set";
282 pub const DO: &str = "do";
283 pub const RETURN: &str = "return";
284 pub const MATCH: &str = "match";
285 pub const CASE: &str = "case";
286 pub const FOR: &str = "for";
287 pub const WHILE: &str = "while";
288 pub const LIST: &str = "list";
289 pub const MAP: &str = "map-lit";
290 pub const RECORD: &str = "record";
291 pub const MODEL: &str = "model";
292 pub const UNION: &str = "union";
293 pub const VARIANT: &str = "variant";
294 pub const FIELD: &str = "field";
295 pub const TYPE: &str = "type";
296 pub const NEWTYPE: &str = "newtype";
297 pub const TRAIT: &str = "trait";
298 pub const IMPL: &str = "impl";
299 pub const IMPORT: &str = "import";
300 pub const MACRO: &str = "macro";
301 pub const QUOTE: &str = "quote";
302 pub const UNQUOTE: &str = "unquote";
303 pub const SPLICE: &str = "unquote-splicing";
304 pub const DECORATE: &str = "decorate";
305 pub const ON: &str = "on";
306 pub const RENDER: &str = "render";
309 pub const UI: &str = "ui";
310 pub const RAISE: &str = "raise";
312 pub const ROW: &str = "row";
314 pub const IDENTITY: &str = "identity";
324 pub const TRY: &str = "try";
332 pub const PARALLEL: &str = "parallel";
340 pub const KW_ARG: &str = "kw";
341 pub const WILDCARD: &str = "_";
342 pub const SERVICE: &str = "service";
343 pub const STYLES: &str = "styles";
344 pub const DOCUMENT: &str = "document";
345
346 pub const TEST: &str = "test";
349 pub const PROPERTY: &str = "property";
351 pub const GIVEN: &str = "given";
353 pub const WHEN: &str = "when";
355 pub const EXPECT: &str = "expect";
357 pub const EXPECT_CONTAINS: &str = "expect-contains";
360 pub const EXPECT_SNAPSHOT: &str = "expect-snapshot";
361 pub const EXPECT_FOLD: &str = "expect-fold";
363 pub const EXPECT_PLACE: &str = "expect-place";
365 pub const EXPECT_FLOW: &str = "expect-flow";
367 pub const EXPECT_WIRE: &str = "expect-wire";
369 pub const EXPECT_EFFECT: &str = "expect-effect";
372 pub const STUB: &str = "stub";
374 pub const STUB_ARMS: &str = "arms";
377
378 pub const RESERVED_FORMS: &[&str] = &[
384 CALL, DO, FN, IF, LIST, MAP, MATCH, QUOTE, RECORD, RETURN, SET, UNQUOTE, SPLICE, KW_ARG,
385 DOT,
386 ];
387}
388
389impl Node {
390 pub fn sym(name: impl AsRef<str>, span: Span) -> Node {
391 Node {
392 head: Head::Sym(Symbol::new(name)),
393 args: Vec::new(),
394 applied: false,
395 meta: Meta::at(span),
396 }
397 }
398
399 pub fn symbol(sym: Symbol, span: Span) -> Node {
400 Node {
401 head: Head::Sym(sym),
402 args: Vec::new(),
403 applied: false,
404 meta: Meta::at(span),
405 }
406 }
407
408 pub fn lit(lit: Lit, span: Span) -> Node {
409 Node {
410 head: Head::Lit(lit),
411 args: Vec::new(),
412 applied: false,
413 meta: Meta::at(span),
414 }
415 }
416
417 pub fn form(head: impl AsRef<str>, args: Vec<Node>, span: Span) -> Node {
418 Node {
419 head: Head::Sym(Symbol::new(head)),
420 args,
421 applied: true,
422 meta: Meta::at(span),
423 }
424 }
425
426 pub fn form_sym(head: Symbol, args: Vec<Node>, span: Span) -> Node {
427 Node {
428 head: Head::Sym(head),
429 args,
430 applied: true,
431 meta: Meta::at(span),
432 }
433 }
434
435 pub fn span(&self) -> Span {
436 self.meta.span
437 }
438
439 pub fn head_sym(&self) -> Option<&Symbol> {
440 match &self.head {
441 Head::Sym(s) => Some(s),
442 Head::Lit(_) => None,
443 }
444 }
445
446 pub fn head_name(&self) -> Option<&str> {
447 self.head_sym().map(|s| s.as_str())
448 }
449
450 pub fn as_lit(&self) -> Option<&Lit> {
451 match &self.head {
452 Head::Lit(l) if !self.applied => Some(l),
453 _ => None,
454 }
455 }
456
457 pub fn as_str_lit(&self) -> Option<&str> {
458 match self.as_lit() {
459 Some(Lit::Str(s)) => Some(s),
460 _ => None,
461 }
462 }
463
464 pub fn as_keyword(&self) -> Option<&str> {
465 match self.as_lit() {
466 Some(Lit::Keyword(k)) => Some(k),
467 _ => None,
468 }
469 }
470
471 pub fn as_var(&self) -> Option<&Symbol> {
473 match &self.head {
474 Head::Sym(s) if !self.applied => Some(s),
475 _ => None,
476 }
477 }
478
479 pub fn is_form(&self, head: &str) -> bool {
481 self.applied && self.head_name() == Some(head)
482 }
483
484 pub fn has_head(&self, head: &str) -> bool {
486 self.head_name() == Some(head)
487 }
488
489 pub fn arg(&self, i: usize) -> Option<&Node> {
490 self.args.get(i)
491 }
492
493 pub fn structurally_eq(&self, other: &Node) -> bool {
496 let heads = match (&self.head, &other.head) {
497 (Head::Sym(a), Head::Sym(b)) => a.name == b.name && a.scopes == b.scopes,
498 (Head::Lit(a), Head::Lit(b)) => a == b,
499 _ => false,
500 };
501 heads
502 && self.applied == other.applied
503 && self.args.len() == other.args.len()
504 && self
505 .args
506 .iter()
507 .zip(&other.args)
508 .all(|(a, b)| a.structurally_eq(b))
509 }
510
511 pub fn map_symbols(&self, f: &mut impl FnMut(&Symbol) -> Symbol) -> Node {
513 let head = match &self.head {
514 Head::Sym(s) => Head::Sym(f(s)),
515 Head::Lit(l) => Head::Lit(l.clone()),
516 };
517 Node {
518 head,
519 args: self.args.iter().map(|a| a.map_symbols(f)).collect(),
520 applied: self.applied,
521 meta: self.meta.clone(),
522 }
523 }
524
525 pub fn add_scope(&self, s: Scope) -> Node {
527 self.map_symbols(&mut |sym| sym.with_scopes(sym.scopes.insert(s)))
528 }
529
530 pub fn flip_scope(&self, s: Scope) -> Node {
532 self.map_symbols(&mut |sym| sym.with_scopes(sym.scopes.flip(s)))
533 }
534
535 pub fn with_expansion(&self, name: Arc<str>, at: Span) -> Node {
537 let mut meta = self.meta.clone();
538 meta.expansion.push((name.clone(), at));
539 Node {
540 head: self.head.clone(),
541 args: self
542 .args
543 .iter()
544 .map(|a| a.with_expansion(name.clone(), at))
545 .collect(),
546 applied: self.applied,
547 meta,
548 }
549 }
550
551 pub fn node_count(&self) -> usize {
552 1 + self.args.iter().map(Node::node_count).sum::<usize>()
553 }
554}
555
556#[cfg(test)]
557mod tests {
558 use super::*;
559
560 #[test]
561 fn scope_sets_are_sorted_sets_with_subset_and_flip() {
562 let e = ScopeSet::empty();
563 let a = e.insert(Scope(3)).insert(Scope(1)).insert(Scope(3));
564 assert_eq!(a.len(), 2);
565 assert!(e.is_subset_of(&a));
566 assert!(!a.is_subset_of(&e));
567 assert!(a.is_subset_of(&a));
568
569 let flipped = a.flip(Scope(1));
570 assert!(!flipped.contains(Scope(1)));
571 assert!(flipped.flip(Scope(1)).is_subset_of(&a) && a.is_subset_of(&flipped.flip(Scope(1))));
572
573 let b = e.insert(Scope(2));
574 assert!(!b.is_subset_of(&a));
575 assert!(!a.is_subset_of(&b));
576 }
577
578 #[test]
579 fn flipping_a_scope_over_a_tree_is_an_involution() {
580 let n = Node::form(
581 "def",
582 vec![Node::sym("x", Span::NONE), Node::sym("y", Span::NONE)],
583 Span::NONE,
584 );
585 assert!(n
586 .flip_scope(Scope(7))
587 .flip_scope(Scope(7))
588 .structurally_eq(&n));
589 assert!(!n.flip_scope(Scope(7)).structurally_eq(&n));
590 }
591
592 #[test]
593 fn structural_equality_ignores_spans() {
594 let mut map = beck_diag::SourceMap::new();
595 let f = map.add("a", "xy");
596 let a = Node::sym("x", Span::new(f, 0..1));
597 let b = Node::sym("x", Span::new(f, 1..2));
598 assert!(a.structurally_eq(&b));
599 }
600}