fork of https://github.com/tree-sitter/tree-sitter-graph
1// -*- coding: utf-8 -*-
2// ------------------------------------------------------------------------------------------------
3// Copyright © 2021, tree-sitter authors.
4// Licensed under either of Apache License, Version 2.0, or MIT license, at your option.
5// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
6// ------------------------------------------------------------------------------------------------
7
8//! Defines the AST structure of a graph DSL file
9
10use regex::Regex;
11use std::collections::HashMap;
12use std::collections::HashSet;
13use std::fmt;
14use tree_sitter::CaptureQuantifier;
15use tree_sitter::Language;
16use tree_sitter::Query;
17
18use crate::parser::Range;
19use crate::Identifier;
20use crate::Location;
21
22/// A graph DSL file
23#[derive(Debug)]
24pub struct File {
25 pub language: Language,
26 /// The expected global variables used in this file
27 pub globals: Vec<Global>,
28 /// The scoped variables that are inherited by child nodes
29 pub inherited_variables: HashSet<Identifier>,
30 /// The combined query of all stanzas in the file
31 pub query: Option<Query>,
32 /// The list of stanzas in the file
33 pub stanzas: Vec<Stanza>,
34 /// Attribute shorthands defined in the file
35 pub shorthands: AttributeShorthands,
36}
37
38impl File {
39 pub fn new(language: Language) -> File {
40 File {
41 language,
42 globals: Vec::new(),
43 inherited_variables: HashSet::new(),
44 query: None,
45 stanzas: Vec::new(),
46 shorthands: AttributeShorthands::new(),
47 }
48 }
49}
50
51/// A global variable
52#[derive(Debug, Eq, PartialEq)]
53pub struct Global {
54 /// The name of the global variable
55 pub name: Identifier,
56 /// The quantifier of the global variable
57 pub quantifier: CaptureQuantifier,
58 /// Default value
59 pub default: Option<String>,
60 pub location: Location,
61}
62
63/// One stanza within a file
64#[derive(Debug)]
65pub struct Stanza {
66 /// The tree-sitter query for this stanza
67 pub query: Query,
68 /// The list of statements in the stanza
69 pub statements: Vec<Statement>,
70 /// Capture index of the full match in the stanza query
71 pub full_match_stanza_capture_index: usize,
72 /// Capture index of the full match in the file query
73 pub full_match_file_capture_index: usize,
74 pub range: Range,
75}
76
77/// A statement that can appear in a graph DSL stanza
78#[derive(Debug, Eq, PartialEq)]
79pub enum Statement {
80 // Variables
81 DeclareImmutable(DeclareImmutable),
82 DeclareMutable(DeclareMutable),
83 Assign(Assign),
84 Expr(ExpressionStatement),
85 // Graph nodes
86 CreateGraphNode(CreateGraphNode),
87 AddGraphNodeAttribute(AddGraphNodeAttribute),
88 // Edges
89 CreateEdge(CreateEdge),
90 AddEdgeAttribute(AddEdgeAttribute),
91 // Regular expression
92 Scan(Scan),
93 // Debugging
94 Print(Print),
95 // If
96 If(If),
97 // ForIn
98 ForIn(ForIn),
99}
100
101impl std::fmt::Display for Statement {
102 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
103 match self {
104 Self::DeclareImmutable(stmt) => stmt.fmt(f),
105 Self::DeclareMutable(stmt) => stmt.fmt(f),
106 Self::Assign(stmt) => stmt.fmt(f),
107 Self::Expr(stmt) => stmt.fmt(f),
108 Self::CreateGraphNode(stmt) => stmt.fmt(f),
109 Self::AddGraphNodeAttribute(stmt) => stmt.fmt(f),
110 Self::CreateEdge(stmt) => stmt.fmt(f),
111 Self::AddEdgeAttribute(stmt) => stmt.fmt(f),
112 Self::Scan(stmt) => stmt.fmt(f),
113 Self::Print(stmt) => stmt.fmt(f),
114 Self::If(stmt) => stmt.fmt(f),
115 Self::ForIn(stmt) => stmt.fmt(f),
116 }
117 }
118}
119
120/// An `attr` statement that adds an attribute to an edge
121#[derive(Debug, Eq, PartialEq)]
122pub struct AddEdgeAttribute {
123 pub source: Expression,
124 pub sink: Expression,
125 pub attributes: Vec<Attribute>,
126 pub location: Location,
127}
128
129impl From<AddEdgeAttribute> for Statement {
130 fn from(statement: AddEdgeAttribute) -> Statement {
131 Statement::AddEdgeAttribute(statement)
132 }
133}
134
135impl std::fmt::Display for AddEdgeAttribute {
136 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
137 write!(f, "attr ({} -> {})", self.source, self.sink)?;
138 for attr in &self.attributes {
139 write!(f, " {}", attr)?;
140 }
141 write!(f, " at {}", self.location)
142 }
143}
144
145/// An `attr` statement that adds an attribute to a graph node
146#[derive(Debug, Eq, PartialEq)]
147pub struct AddGraphNodeAttribute {
148 pub node: Expression,
149 pub attributes: Vec<Attribute>,
150 pub location: Location,
151}
152
153impl From<AddGraphNodeAttribute> for Statement {
154 fn from(statement: AddGraphNodeAttribute) -> Statement {
155 Statement::AddGraphNodeAttribute(statement)
156 }
157}
158
159impl std::fmt::Display for AddGraphNodeAttribute {
160 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
161 write!(f, "attr ({})", self.node)?;
162 for attr in &self.attributes {
163 write!(f, " {}", attr)?;
164 }
165 write!(f, " at {}", self.location)
166 }
167}
168
169/// An `expression` statement whose output is ignored
170#[derive(Debug, Eq, PartialEq)]
171pub struct ExpressionStatement {
172 pub value: Expression,
173 pub location: Location,
174}
175
176impl From<ExpressionStatement> for Statement {
177 fn from(statement: ExpressionStatement) -> Statement {
178 Statement::Expr(statement)
179 }
180}
181
182impl std::fmt::Display for ExpressionStatement {
183 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
184 write!(
185 f,
186 "{} at {}",
187 self.value, self.location,
188 )
189 }
190}
191
192/// A `set` statement that updates the value of a mutable variable
193#[derive(Debug, Eq, PartialEq)]
194pub struct Assign {
195 pub variable: Variable,
196 pub value: Expression,
197 pub location: Location,
198}
199
200impl From<Assign> for Statement {
201 fn from(statement: Assign) -> Statement {
202 Statement::Assign(statement)
203 }
204}
205
206impl std::fmt::Display for Assign {
207 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
208 write!(
209 f,
210 "set {} = {} at {}",
211 self.variable, self.value, self.location,
212 )
213 }
214}
215
216/// The name and value of an attribute
217#[derive(Debug, Eq, PartialEq)]
218pub struct Attribute {
219 pub name: Identifier,
220 pub value: Expression,
221}
222
223impl std::fmt::Display for Attribute {
224 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
225 write!(f, "{} = {}", self.name, self.value)
226 }
227}
228
229/// An `edge` statement that creates a new edge
230#[derive(Debug, Eq, PartialEq)]
231pub struct CreateEdge {
232 pub source: Expression,
233 pub sink: Expression,
234 pub location: Location,
235}
236
237impl From<CreateEdge> for Statement {
238 fn from(statement: CreateEdge) -> Statement {
239 Statement::CreateEdge(statement)
240 }
241}
242
243impl std::fmt::Display for CreateEdge {
244 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
245 write!(
246 f,
247 "edge {} -> {} at {}",
248 self.source, self.sink, self.location,
249 )
250 }
251}
252
253/// A `node` statement that creates a new graph node
254#[derive(Debug, Eq, PartialEq)]
255pub struct CreateGraphNode {
256 pub node: Variable,
257 pub location: Location,
258}
259
260impl From<CreateGraphNode> for Statement {
261 fn from(statement: CreateGraphNode) -> Statement {
262 Statement::CreateGraphNode(statement)
263 }
264}
265
266impl std::fmt::Display for CreateGraphNode {
267 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
268 write!(f, "node {} at {}", self.node, self.location)
269 }
270}
271
272/// A `let` statement that declares a new immutable variable
273#[derive(Debug, Eq, PartialEq)]
274pub struct DeclareImmutable {
275 pub variable: Variable,
276 pub value: Expression,
277 pub location: Location,
278}
279
280impl From<DeclareImmutable> for Statement {
281 fn from(statement: DeclareImmutable) -> Statement {
282 Statement::DeclareImmutable(statement)
283 }
284}
285
286impl std::fmt::Display for DeclareImmutable {
287 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
288 write!(
289 f,
290 "let {} = {} at {}",
291 self.variable, self.value, self.location,
292 )
293 }
294}
295
296/// A `var` statement that declares a new mutable variable
297#[derive(Debug, Eq, PartialEq)]
298pub struct DeclareMutable {
299 pub variable: Variable,
300 pub value: Expression,
301 pub location: Location,
302}
303
304impl From<DeclareMutable> for Statement {
305 fn from(statement: DeclareMutable) -> Statement {
306 Statement::DeclareMutable(statement)
307 }
308}
309
310impl std::fmt::Display for DeclareMutable {
311 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
312 write!(
313 f,
314 "var {} = {} at {}",
315 self.variable, self.value, self.location,
316 )
317 }
318}
319
320/// A `print` statement that prints out some debugging information
321#[derive(Debug, Eq, PartialEq)]
322pub struct Print {
323 pub values: Vec<Expression>,
324 pub location: Location,
325}
326
327impl From<Print> for Statement {
328 fn from(statement: Print) -> Statement {
329 Statement::Print(statement)
330 }
331}
332
333impl std::fmt::Display for Print {
334 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
335 write!(f, "print")?;
336 for val in &self.values {
337 write!(f, " {},", val)?;
338 }
339 write!(f, " at {}", self.location)
340 }
341}
342
343/// A `scan` statement that matches regular expressions against a string
344#[derive(Debug, Eq, PartialEq)]
345pub struct Scan {
346 pub value: Expression,
347 pub arms: Vec<ScanArm>,
348 pub location: Location,
349}
350
351impl From<Scan> for Statement {
352 fn from(statement: Scan) -> Statement {
353 Statement::Scan(statement)
354 }
355}
356
357impl std::fmt::Display for Scan {
358 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
359 write!(f, "scan {} {{ ... }} at {}", self.value, self.location)
360 }
361}
362
363/// One arm of a `scan` statement
364#[derive(Debug)]
365pub struct ScanArm {
366 pub regex: Regex,
367 pub statements: Vec<Statement>,
368 pub location: Location,
369}
370
371impl Eq for ScanArm {}
372
373impl PartialEq for ScanArm {
374 fn eq(&self, other: &ScanArm) -> bool {
375 self.regex.as_str() == other.regex.as_str() && self.statements == other.statements
376 }
377}
378
379impl std::fmt::Display for ScanArm {
380 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
381 write!(f, "{:?} {{ ... }}", self.regex.as_str())
382 }
383}
384
385/// A `cond` conditional statement that selects the first branch with a matching condition
386#[derive(Debug, Eq, PartialEq)]
387pub struct If {
388 pub arms: Vec<IfArm>,
389 pub location: Location,
390}
391
392impl From<If> for Statement {
393 fn from(statement: If) -> Statement {
394 Statement::If(statement)
395 }
396}
397
398impl std::fmt::Display for If {
399 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
400 let mut first = true;
401 for arm in &self.arms {
402 if first {
403 first = false;
404 write!(f, "if {} {{ ... }}", DisplayConditions(&arm.conditions))?;
405 } else {
406 if !arm.conditions.is_empty() {
407 write!(f, " elif {} {{ ... }}", DisplayConditions(&arm.conditions))?;
408 } else {
409 write!(f, " else {{ ... }}")?;
410 }
411 }
412 }
413 write!(f, " at {}", self.location)
414 }
415}
416
417/// One arm of a `cond` statement
418#[derive(Debug, PartialEq, Eq)]
419pub struct IfArm {
420 pub conditions: Vec<Condition>,
421 pub statements: Vec<Statement>,
422 pub location: Location,
423}
424
425struct DisplayConditions<'a>(&'a Vec<Condition>);
426
427#[derive(Debug, PartialEq, Eq)]
428pub enum Condition {
429 Some {
430 value: Expression,
431 location: Location,
432 },
433 None {
434 value: Expression,
435 location: Location,
436 },
437 Bool {
438 value: Expression,
439 location: Location,
440 },
441}
442
443impl std::fmt::Display for DisplayConditions<'_> {
444 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
445 let mut first = true;
446 for condition in self.0.iter() {
447 if first {
448 first = false;
449 write!(f, "{}", condition)?;
450 } else {
451 write!(f, ", {}", condition)?;
452 }
453 }
454 Ok(())
455 }
456}
457
458impl std::fmt::Display for Condition {
459 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
460 match self {
461 Condition::Some { value, .. } => {
462 write!(f, "some {}", value)
463 }
464 Condition::None { value, .. } => {
465 write!(f, "none {}", value)
466 }
467 Condition::Bool { value, .. } => {
468 write!(f, "{}", value)
469 }
470 }
471 }
472}
473
474/// A `for in` statement
475#[derive(Debug, Eq, PartialEq)]
476pub struct ForIn {
477 pub variable: UnscopedVariable,
478 pub value: Expression,
479 pub statements: Vec<Statement>,
480 pub location: Location,
481}
482
483impl From<ForIn> for Statement {
484 fn from(statement: ForIn) -> Statement {
485 Statement::ForIn(statement)
486 }
487}
488
489impl std::fmt::Display for ForIn {
490 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
491 write!(
492 f,
493 "for {} in {} {{ ... }} at {}",
494 self.variable, self.value, self.location,
495 )
496 }
497}
498
499/// A reference to a variable
500#[derive(Debug, Eq, PartialEq)]
501pub enum Variable {
502 Scoped(ScopedVariable),
503 Unscoped(UnscopedVariable),
504}
505
506impl std::fmt::Display for Variable {
507 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
508 match self {
509 Variable::Scoped(variable) => variable.fmt(f),
510 Variable::Unscoped(variable) => variable.fmt(f),
511 }
512 }
513}
514
515/// A reference to a scoped variable
516#[derive(Debug, Eq, PartialEq)]
517pub struct ScopedVariable {
518 pub scope: Box<Expression>,
519 pub name: Identifier,
520 pub location: Location,
521}
522
523impl From<ScopedVariable> for Variable {
524 fn from(variable: ScopedVariable) -> Variable {
525 Variable::Scoped(variable)
526 }
527}
528
529impl std::fmt::Display for ScopedVariable {
530 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
531 write!(f, "{}.{}", self.scope, self.name)
532 }
533}
534
535/// A reference to a global or local variable
536#[derive(Debug, Eq, PartialEq)]
537pub struct UnscopedVariable {
538 pub name: Identifier,
539 pub location: Location,
540}
541
542impl From<UnscopedVariable> for Variable {
543 fn from(variable: UnscopedVariable) -> Variable {
544 Variable::Unscoped(variable)
545 }
546}
547
548impl std::fmt::Display for UnscopedVariable {
549 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
550 write!(f, "{}", self.name)
551 }
552}
553
554/// An expression that can appear in a graph DSL file
555#[derive(Debug, Eq, PartialEq)]
556pub enum Expression {
557 // Literals
558 FalseLiteral,
559 NullLiteral,
560 TrueLiteral,
561 // Constants
562 IntegerConstant(IntegerConstant),
563 StringConstant(StringConstant),
564 // Literals
565 ListLiteral(ListLiteral),
566 SetLiteral(SetLiteral),
567 // Comprehensions
568 ListComprehension(ListComprehension),
569 SetComprehension(SetComprehension),
570 // Syntax nodes
571 Capture(Capture),
572 // Variables
573 Variable(Variable),
574 // Functions
575 Call(Call),
576 // Regular expression
577 RegexCapture(RegexCapture),
578}
579
580impl std::fmt::Display for Expression {
581 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
582 match self {
583 Expression::FalseLiteral => write!(f, "false"),
584 Expression::NullLiteral => write!(f, "#null"),
585 Expression::TrueLiteral => write!(f, "true"),
586 Expression::IntegerConstant(expr) => expr.fmt(f),
587 Expression::StringConstant(expr) => expr.fmt(f),
588 Expression::ListLiteral(expr) => expr.fmt(f),
589 Expression::SetLiteral(expr) => expr.fmt(f),
590 Expression::ListComprehension(expr) => expr.fmt(f),
591 Expression::SetComprehension(expr) => expr.fmt(f),
592 Expression::Capture(expr) => expr.fmt(f),
593 Expression::Variable(expr) => expr.fmt(f),
594 Expression::Call(expr) => expr.fmt(f),
595 Expression::RegexCapture(expr) => expr.fmt(f),
596 }
597 }
598}
599
600/// A function call
601#[derive(Debug, Eq, PartialEq)]
602pub struct Call {
603 pub function: Identifier,
604 pub parameters: Vec<Expression>,
605}
606
607impl From<Call> for Expression {
608 fn from(expr: Call) -> Expression {
609 Expression::Call(expr)
610 }
611}
612
613impl std::fmt::Display for Call {
614 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
615 write!(f, "({}", self.function)?;
616 for arg in &self.parameters {
617 write!(f, " {}", arg)?;
618 }
619 write!(f, ")")
620 }
621}
622
623/// A capture expression that references a syntax node
624#[derive(Debug, Eq, PartialEq)]
625pub struct Capture {
626 /// The name of the capture
627 pub name: Identifier,
628 /// The suffix of the capture
629 pub quantifier: CaptureQuantifier,
630 /// Capture index in the merged file query
631 pub file_capture_index: usize,
632 /// Capture index in the stanza query
633 pub stanza_capture_index: usize,
634 pub location: Location,
635}
636
637impl From<Capture> for Expression {
638 fn from(expr: Capture) -> Expression {
639 Expression::Capture(expr)
640 }
641}
642
643impl std::fmt::Display for Capture {
644 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
645 write!(f, "@{}", self.name)
646 }
647}
648
649/// An integer constant
650#[derive(Debug, Eq, PartialEq)]
651pub struct IntegerConstant {
652 pub value: u32,
653}
654
655impl From<IntegerConstant> for Expression {
656 fn from(expr: IntegerConstant) -> Expression {
657 Expression::IntegerConstant(expr)
658 }
659}
660
661impl std::fmt::Display for IntegerConstant {
662 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
663 write!(f, "{}", self.value)
664 }
665}
666
667/// An ordered list of values
668#[derive(Debug, Eq, PartialEq)]
669pub struct ListLiteral {
670 pub elements: Vec<Expression>,
671}
672
673impl From<ListLiteral> for Expression {
674 fn from(expr: ListLiteral) -> Expression {
675 Expression::ListLiteral(expr)
676 }
677}
678
679impl std::fmt::Display for ListLiteral {
680 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
681 write!(f, "[")?;
682 let mut first = true;
683 for elem in &self.elements {
684 if first {
685 write!(f, "{}", elem)?;
686 first = false;
687 } else {
688 write!(f, ", {}", elem)?;
689 }
690 }
691 write!(f, "]")
692 }
693}
694
695/// An list comprehension
696#[derive(Debug, Eq, PartialEq)]
697pub struct ListComprehension {
698 pub element: Box<Expression>,
699 pub variable: UnscopedVariable,
700 pub value: Box<Expression>,
701 pub location: Location,
702}
703
704impl From<ListComprehension> for Expression {
705 fn from(expr: ListComprehension) -> Expression {
706 Expression::ListComprehension(expr)
707 }
708}
709
710impl std::fmt::Display for ListComprehension {
711 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
712 write!(
713 f,
714 "[ {} for {} in {} ]",
715 self.element, self.variable, self.value
716 )
717 }
718}
719
720/// A reference to one of the regex captures in a `scan` statement
721#[derive(Debug, Eq, PartialEq)]
722pub struct RegexCapture {
723 pub match_index: usize,
724}
725
726impl From<RegexCapture> for Expression {
727 fn from(expr: RegexCapture) -> Expression {
728 Expression::RegexCapture(expr)
729 }
730}
731
732impl std::fmt::Display for RegexCapture {
733 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
734 write!(f, "${}", self.match_index)
735 }
736}
737
738/// An unordered set of values
739#[derive(Debug, Eq, PartialEq)]
740pub struct SetLiteral {
741 pub elements: Vec<Expression>,
742}
743
744impl From<SetLiteral> for Expression {
745 fn from(expr: SetLiteral) -> Expression {
746 Expression::SetLiteral(expr)
747 }
748}
749
750impl std::fmt::Display for SetLiteral {
751 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
752 write!(f, "{{")?;
753 let mut first = true;
754 for elem in &self.elements {
755 if first {
756 write!(f, "{}", elem)?;
757 first = false;
758 } else {
759 write!(f, ", {}", elem)?;
760 }
761 }
762 write!(f, "}}")
763 }
764}
765
766/// An set comprehension
767#[derive(Debug, Eq, PartialEq)]
768pub struct SetComprehension {
769 pub element: Box<Expression>,
770 pub variable: UnscopedVariable,
771 pub value: Box<Expression>,
772 pub location: Location,
773}
774
775impl From<SetComprehension> for Expression {
776 fn from(expr: SetComprehension) -> Expression {
777 Expression::SetComprehension(expr)
778 }
779}
780
781impl std::fmt::Display for SetComprehension {
782 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
783 write!(
784 f,
785 "{{ {} for {} in {} }}",
786 self.element, self.variable, self.value
787 )
788 }
789}
790
791/// A string constant
792#[derive(Debug, Eq, PartialEq)]
793pub struct StringConstant {
794 pub value: String,
795}
796
797impl From<StringConstant> for Expression {
798 fn from(expr: StringConstant) -> Expression {
799 Expression::StringConstant(expr)
800 }
801}
802
803impl std::fmt::Display for StringConstant {
804 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
805 write!(f, "{:?}", self.value)
806 }
807}
808
809impl From<String> for Expression {
810 fn from(value: String) -> Expression {
811 Expression::StringConstant(StringConstant { value }.into())
812 }
813}
814
815impl From<UnscopedVariable> for Expression {
816 fn from(variable: UnscopedVariable) -> Expression {
817 Expression::Variable(variable.into())
818 }
819}
820
821impl From<ScopedVariable> for Expression {
822 fn from(variable: ScopedVariable) -> Expression {
823 Expression::Variable(variable.into())
824 }
825}
826
827/// Attribute shorthands
828#[derive(Debug, Eq, PartialEq)]
829pub struct AttributeShorthands(HashMap<Identifier, AttributeShorthand>);
830
831impl AttributeShorthands {
832 pub fn new() -> Self {
833 Self(HashMap::new())
834 }
835
836 pub fn get(&self, name: &Identifier) -> Option<&AttributeShorthand> {
837 self.0.get(name)
838 }
839
840 pub fn add(&mut self, shorthand: AttributeShorthand) {
841 self.0.insert(shorthand.name.clone(), shorthand);
842 }
843
844 pub fn iter(&self) -> impl Iterator<Item = &AttributeShorthand> {
845 self.0.values()
846 }
847
848 pub fn into_iter(self) -> impl Iterator<Item = AttributeShorthand> {
849 self.0.into_values()
850 }
851}
852
853/// An attribute shorthand
854#[derive(Debug, Eq, PartialEq)]
855pub struct AttributeShorthand {
856 pub name: Identifier,
857 pub variable: UnscopedVariable,
858 pub attributes: Vec<Attribute>,
859 pub location: Location,
860}
861
862impl std::fmt::Display for AttributeShorthand {
863 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
864 write!(f, "attribute {} = {} =>", self.name, self.variable,)?;
865 for attr in &self.attributes {
866 write!(f, " {}", attr)?;
867 }
868 write!(f, " at {}", self.location)
869 }
870}