fork of https://github.com/tree-sitter/tree-sitter-graph
at main 23 kB view raw
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}