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 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) = ¤t_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}