kast_ast/
syntax.rs

1use super::*;
2use noisy_float::prelude::*;
3use std::collections::{HashMap, HashSet};
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
6pub struct Priority(R64);
7
8impl Priority {
9    pub fn new(raw: f64) -> Self {
10        Self(R64::new(raw))
11    }
12}
13
14#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
15pub enum Associativity {
16    Left,
17    Right,
18}
19
20#[derive(Debug)]
21pub enum SyntaxDefinitionPart {
22    Keyword(String),
23    UnnamedBinding,
24    NamedBinding(String),
25}
26
27#[derive(Debug)]
28pub struct SyntaxDefinition {
29    pub name: String,
30    pub priority: Priority,
31    pub associativity: Associativity,
32    pub parts: Vec<SyntaxDefinitionPart>,
33}
34
35impl SyntaxDefinition {
36    pub fn binding_power(&self) -> BindingPower {
37        BindingPower {
38            priority: self.priority,
39            associativity: self.associativity,
40        }
41    }
42}
43
44#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
45pub struct BindingPower {
46    pub priority: Priority,
47    pub associativity: Associativity,
48}
49
50#[derive(Debug, Eq, PartialEq, Hash, Clone)]
51pub enum Edge {
52    Value,
53    Keyword(String),
54}
55impl Edge {
56    pub fn is_open_bracket(&self) -> bool {
57        match self {
58            Self::Keyword(keyword) => is_open_bracket(keyword),
59            Self::Value => false,
60        }
61    }
62}
63
64pub fn is_open_bracket(s: &str) -> bool {
65    s.chars().any(|c| "([{".contains(c))
66}
67
68#[derive(Clone, Debug)]
69pub struct ParseNode {
70    pub finish: Option<Parc<SyntaxDefinition>>,
71    pub next: HashMap<Edge, ParseNode>,
72    pub binding_power: Option<BindingPower>,
73    pub is_open_paren: bool,
74}
75
76impl ParseNode {
77    fn new(is_open_paren: bool, binding_power: Option<BindingPower>) -> Self {
78        Self {
79            finish: None,
80            next: HashMap::new(),
81            binding_power,
82            is_open_paren,
83        }
84    }
85    pub fn with_power(is_open_paren: bool, binding_power: BindingPower) -> Self {
86        Self::new(is_open_paren, Some(binding_power))
87    }
88    /// write what is expected after this node (a value or on of the keywords)
89    pub fn format_possible_continuations(&self) -> impl std::fmt::Display + '_ {
90        struct Format<'a>(&'a ParseNode);
91        impl std::fmt::Display for Format<'_> {
92            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93                for (i, edge) in self.0.next.keys().enumerate() {
94                    if i != 0 {
95                        write!(f, " or ")?;
96                    }
97                    match edge {
98                        Edge::Value => write!(f, "a value")?,
99                        Edge::Keyword(keyword) => write!(f, "{keyword:?}")?,
100                    }
101                }
102                Ok(())
103            }
104        }
105        Format(self)
106    }
107}
108
109#[derive(Clone, Debug)]
110pub struct Syntax {
111    pub(crate) keywords: HashSet<String>,
112    pub(crate) root_without_start_value: ParseNode,
113    pub(crate) root_with_start_value: ParseNode,
114}
115
116impl Syntax {
117    pub fn empty() -> Self {
118        Self {
119            keywords: HashSet::new(),
120            root_without_start_value: ParseNode::new(false, None),
121            root_with_start_value: ParseNode::new(false, None),
122        }
123    }
124
125    pub fn insert(&mut self, definition: Parc<SyntaxDefinition>) -> Result<(), ErrorMessage> {
126        let binding_power = definition.binding_power();
127        let skip;
128        let mut current_node = match definition.parts[0] {
129            SyntaxDefinitionPart::Keyword(_) => {
130                skip = 0;
131                &mut self.root_without_start_value
132            }
133            _ => {
134                skip = 1;
135                &mut self.root_with_start_value
136            }
137        };
138        for part in definition.parts.iter().skip(skip) {
139            let edge = match part {
140                SyntaxDefinitionPart::Keyword(keyword) => {
141                    self.keywords.insert(keyword.clone());
142                    Edge::Keyword(keyword.clone())
143                }
144                SyntaxDefinitionPart::UnnamedBinding | SyntaxDefinitionPart::NamedBinding(_) => {
145                    Edge::Value
146                }
147            };
148            let is_open_bracket = edge.is_open_bracket();
149            let next_node = current_node
150                .next
151                .entry(edge)
152                .or_insert_with(|| ParseNode::with_power(is_open_bracket, binding_power));
153            if next_node.binding_power != Some(binding_power) {
154                return error!("different binding power");
155            }
156            current_node = next_node;
157        }
158        if let Some(current) = &current_node.finish {
159            return error!(
160                "Conficting syntax definitions: {:?} and {:?}",
161                current.name, definition.name,
162            );
163        }
164        current_node.finish = Some(definition);
165        Ok(())
166    }
167}