diff options
Diffstat (limited to 'crates/ide/src/syntax_highlighting')
6 files changed, 91 insertions, 112 deletions
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index e921784bf..8cc877c1c 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -12,7 +12,10 @@ use syntax::{ | |||
12 | SyntaxNode, SyntaxToken, T, | 12 | SyntaxNode, SyntaxToken, T, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag}; | 15 | use crate::{ |
16 | syntax_highlighting::tags::{HlOperator, HlPunct}, | ||
17 | Highlight, HlMod, HlTag, | ||
18 | }; | ||
16 | 19 | ||
17 | pub(super) fn element( | 20 | pub(super) fn element( |
18 | sema: &Semantics<RootDatabase>, | 21 | sema: &Semantics<RootDatabase>, |
@@ -132,7 +135,7 @@ pub(super) fn element( | |||
132 | INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), | 135 | INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), |
133 | BYTE => HlTag::ByteLiteral.into(), | 136 | BYTE => HlTag::ByteLiteral.into(), |
134 | CHAR => HlTag::CharLiteral.into(), | 137 | CHAR => HlTag::CharLiteral.into(), |
135 | QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow, | 138 | QUESTION => Highlight::new(HlTag::Operator(HlOperator::Other)) | HlMod::ControlFlow, |
136 | LIFETIME => { | 139 | LIFETIME => { |
137 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); | 140 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); |
138 | 141 | ||
@@ -146,8 +149,11 @@ pub(super) fn element( | |||
146 | } | 149 | } |
147 | } | 150 | } |
148 | p if p.is_punct() => match p { | 151 | p if p.is_punct() => match p { |
152 | T![&] if element.parent().and_then(ast::BinExpr::cast).is_some() => { | ||
153 | HlTag::Operator(HlOperator::Bitwise).into() | ||
154 | } | ||
149 | T![&] => { | 155 | T![&] => { |
150 | let h = HlTag::Operator.into(); | 156 | let h = HlTag::Operator(HlOperator::Other).into(); |
151 | let is_unsafe = element | 157 | let is_unsafe = element |
152 | .parent() | 158 | .parent() |
153 | .and_then(ast::RefExpr::cast) | 159 | .and_then(ast::RefExpr::cast) |
@@ -159,13 +165,18 @@ pub(super) fn element( | |||
159 | h | 165 | h |
160 | } | 166 | } |
161 | } | 167 | } |
162 | T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(), | 168 | T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => { |
169 | HlTag::Operator(HlOperator::Other).into() | ||
170 | } | ||
163 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | 171 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { |
164 | HlTag::Symbol(SymbolKind::Macro).into() | 172 | HlTag::Symbol(SymbolKind::Macro).into() |
165 | } | 173 | } |
166 | T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { | 174 | T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { |
167 | HlTag::BuiltinType.into() | 175 | HlTag::BuiltinType.into() |
168 | } | 176 | } |
177 | T![!] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
178 | HlTag::Operator(HlOperator::Logical).into() | ||
179 | } | ||
169 | T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { | 180 | T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { |
170 | HlTag::Keyword.into() | 181 | HlTag::Keyword.into() |
171 | } | 182 | } |
@@ -175,9 +186,9 @@ pub(super) fn element( | |||
175 | let expr = prefix_expr.expr()?; | 186 | let expr = prefix_expr.expr()?; |
176 | let ty = sema.type_of_expr(&expr)?; | 187 | let ty = sema.type_of_expr(&expr)?; |
177 | if ty.is_raw_ptr() { | 188 | if ty.is_raw_ptr() { |
178 | HlTag::Operator | HlMod::Unsafe | 189 | HlTag::Operator(HlOperator::Other) | HlMod::Unsafe |
179 | } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { | 190 | } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { |
180 | HlTag::Operator.into() | 191 | HlTag::Operator(HlOperator::Other).into() |
181 | } else { | 192 | } else { |
182 | HlTag::Punctuation(HlPunct::Other).into() | 193 | HlTag::Punctuation(HlPunct::Other).into() |
183 | } | 194 | } |
@@ -188,19 +199,43 @@ pub(super) fn element( | |||
188 | let expr = prefix_expr.expr()?; | 199 | let expr = prefix_expr.expr()?; |
189 | match expr { | 200 | match expr { |
190 | ast::Expr::Literal(_) => HlTag::NumericLiteral, | 201 | ast::Expr::Literal(_) => HlTag::NumericLiteral, |
191 | _ => HlTag::Operator, | 202 | _ => HlTag::Operator(HlOperator::Other), |
192 | } | 203 | } |
193 | .into() | 204 | .into() |
194 | } | 205 | } |
195 | _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | 206 | _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { |
196 | HlTag::Operator.into() | 207 | HlTag::Operator(HlOperator::Other).into() |
208 | } | ||
209 | T![+] | T![-] | T![*] | T![/] | T![+=] | T![-=] | T![*=] | T![/=] | ||
210 | if element.parent().and_then(ast::BinExpr::cast).is_some() => | ||
211 | { | ||
212 | HlTag::Operator(HlOperator::Arithmetic).into() | ||
213 | } | ||
214 | T![|] | T![&] | T![!] | T![^] | T![|=] | T![&=] | T![^=] | ||
215 | if element.parent().and_then(ast::BinExpr::cast).is_some() => | ||
216 | { | ||
217 | HlTag::Operator(HlOperator::Bitwise).into() | ||
218 | } | ||
219 | T![&&] | T![||] if element.parent().and_then(ast::BinExpr::cast).is_some() => { | ||
220 | HlTag::Operator(HlOperator::Logical).into() | ||
221 | } | ||
222 | T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=] | ||
223 | if element.parent().and_then(ast::BinExpr::cast).is_some() => | ||
224 | { | ||
225 | HlTag::Operator(HlOperator::Comparision).into() | ||
226 | } | ||
227 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => { | ||
228 | HlTag::Operator(HlOperator::Other).into() | ||
197 | } | 229 | } |
198 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(), | ||
199 | _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { | 230 | _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { |
200 | HlTag::Operator.into() | 231 | HlTag::Operator(HlOperator::Other).into() |
232 | } | ||
233 | _ if element.parent().and_then(ast::RangePat::cast).is_some() => { | ||
234 | HlTag::Operator(HlOperator::Other).into() | ||
235 | } | ||
236 | _ if element.parent().and_then(ast::RestPat::cast).is_some() => { | ||
237 | HlTag::Operator(HlOperator::Other).into() | ||
201 | } | 238 | } |
202 | _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(), | ||
203 | _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(), | ||
204 | _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(), | 239 | _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(), |
205 | kind => HlTag::Punctuation(match kind { | 240 | kind => HlTag::Punctuation(match kind { |
206 | T!['['] | T![']'] => HlPunct::Bracket, | 241 | T!['['] | T![']'] => HlPunct::Bracket, |
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 04fafd244..bc221d599 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -4,7 +4,7 @@ use std::mem; | |||
4 | 4 | ||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir::{InFile, Semantics}; | 6 | use hir::{InFile, Semantics}; |
7 | use ide_db::{call_info::ActiveParameter, SymbolKind}; | 7 | use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind}; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode}, | 9 | ast::{self, AstNode}, |
10 | AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, | 10 | AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, |
@@ -78,17 +78,6 @@ pub(super) fn ra_fixture( | |||
78 | } | 78 | } |
79 | 79 | ||
80 | const RUSTDOC_FENCE: &'static str = "```"; | 80 | const RUSTDOC_FENCE: &'static str = "```"; |
81 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ | ||
82 | "", | ||
83 | "rust", | ||
84 | "should_panic", | ||
85 | "ignore", | ||
86 | "no_run", | ||
87 | "compile_fail", | ||
88 | "edition2015", | ||
89 | "edition2018", | ||
90 | "edition2021", | ||
91 | ]; | ||
92 | 81 | ||
93 | /// Injection of syntax highlighting of doctests. | 82 | /// Injection of syntax highlighting of doctests. |
94 | pub(super) fn doc_comment( | 83 | pub(super) fn doc_comment( |
@@ -174,8 +163,7 @@ pub(super) fn doc_comment( | |||
174 | is_codeblock = !is_codeblock; | 163 | is_codeblock = !is_codeblock; |
175 | // Check whether code is rust by inspecting fence guards | 164 | // Check whether code is rust by inspecting fence guards |
176 | let guards = &line[idx + RUSTDOC_FENCE.len()..]; | 165 | let guards = &line[idx + RUSTDOC_FENCE.len()..]; |
177 | let is_rust = | 166 | let is_rust = is_rust_fence(guards); |
178 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); | ||
179 | is_doctest = is_codeblock && is_rust; | 167 | is_doctest = is_codeblock && is_rust; |
180 | continue; | 168 | continue; |
181 | } | 169 | } |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 1cec991aa..8128d231d 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -28,7 +28,7 @@ pub enum HlTag { | |||
28 | FormatSpecifier, | 28 | FormatSpecifier, |
29 | Keyword, | 29 | Keyword, |
30 | NumericLiteral, | 30 | NumericLiteral, |
31 | Operator, | 31 | Operator(HlOperator), |
32 | Punctuation(HlPunct), | 32 | Punctuation(HlPunct), |
33 | StringLiteral, | 33 | StringLiteral, |
34 | UnresolvedReference, | 34 | UnresolvedReference, |
@@ -87,6 +87,20 @@ pub enum HlPunct { | |||
87 | Other, | 87 | Other, |
88 | } | 88 | } |
89 | 89 | ||
90 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
91 | pub enum HlOperator { | ||
92 | /// |, &, !, ^, |=, &=, ^= | ||
93 | Bitwise, | ||
94 | /// +, -, *, /, +=, -=, *=, /= | ||
95 | Arithmetic, | ||
96 | /// &&, ||, ! | ||
97 | Logical, | ||
98 | /// >, <, ==, >=, <=, != | ||
99 | Comparision, | ||
100 | /// | ||
101 | Other, | ||
102 | } | ||
103 | |||
90 | impl HlTag { | 104 | impl HlTag { |
91 | fn as_str(self) -> &'static str { | 105 | fn as_str(self) -> &'static str { |
92 | match self { | 106 | match self { |
@@ -133,7 +147,13 @@ impl HlTag { | |||
133 | HlPunct::Other => "punctuation", | 147 | HlPunct::Other => "punctuation", |
134 | }, | 148 | }, |
135 | HlTag::NumericLiteral => "numeric_literal", | 149 | HlTag::NumericLiteral => "numeric_literal", |
136 | HlTag::Operator => "operator", | 150 | HlTag::Operator(op) => match op { |
151 | HlOperator::Bitwise => "bitwise", | ||
152 | HlOperator::Arithmetic => "arithmetic", | ||
153 | HlOperator::Logical => "logical", | ||
154 | HlOperator::Comparision => "comparision", | ||
155 | HlOperator::Other => "operator", | ||
156 | }, | ||
137 | HlTag::StringLiteral => "string_literal", | 157 | HlTag::StringLiteral => "string_literal", |
138 | HlTag::UnresolvedReference => "unresolved_reference", | 158 | HlTag::UnresolvedReference => "unresolved_reference", |
139 | HlTag::None => "none", | 159 | HlTag::None => "none", |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index b6d1cac4e..6ee6d85fb 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -76,7 +76,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
76 | <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> | 76 | <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> |
77 | <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> | 77 | <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
78 | <span class="comment documentation">///</span> | 78 | <span class="comment documentation">///</span> |
79 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span> | 79 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="logical injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span> |
80 | <span class="comment documentation">///</span> | 80 | <span class="comment documentation">///</span> |
81 | <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span> | 81 | <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span> |
82 | <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> | 82 | <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 973173254..c43bcb691 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -213,7 +213,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
213 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> | 213 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> |
214 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> | 214 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> |
215 | 215 | ||
216 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> | 216 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> |
217 | 217 | ||
218 | <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span> | 218 | <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span> |
219 | <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span> | 219 | <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index b4818060f..17cc6334b 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -2,8 +2,7 @@ use std::time::Instant; | |||
2 | 2 | ||
3 | use expect_test::{expect_file, ExpectFile}; | 3 | use expect_test::{expect_file, ExpectFile}; |
4 | use ide_db::SymbolKind; | 4 | use ide_db::SymbolKind; |
5 | use stdx::format_to; | 5 | use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear}; |
6 | use test_utils::{bench, bench_fixture, skip_slow_tests}; | ||
7 | 6 | ||
8 | use crate::{fixture, FileRange, HlTag, TextRange}; | 7 | use crate::{fixture, FileRange, HlTag, TextRange}; |
9 | 8 | ||
@@ -266,90 +265,27 @@ fn syntax_highlighting_not_quadratic() { | |||
266 | return; | 265 | return; |
267 | } | 266 | } |
268 | 267 | ||
269 | let mut measures = Vec::new(); | 268 | let mut al = AssertLinear::default(); |
270 | for i in 6..=10 { | 269 | while al.next_round() { |
271 | let n = 1 << i; | 270 | for i in 6..=10 { |
272 | let fixture = bench_fixture::big_struct_n(n); | 271 | let n = 1 << i; |
273 | let (analysis, file_id) = fixture::file(&fixture); | ||
274 | 272 | ||
275 | let time = Instant::now(); | 273 | let fixture = bench_fixture::big_struct_n(n); |
274 | let (analysis, file_id) = fixture::file(&fixture); | ||
276 | 275 | ||
277 | let hash = analysis | 276 | let time = Instant::now(); |
278 | .highlight(file_id) | ||
279 | .unwrap() | ||
280 | .iter() | ||
281 | .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) | ||
282 | .count(); | ||
283 | assert!(hash > n as usize); | ||
284 | 277 | ||
285 | let elapsed = time.elapsed(); | 278 | let hash = analysis |
286 | measures.push((n as f64, elapsed.as_millis() as f64)) | 279 | .highlight(file_id) |
287 | } | 280 | .unwrap() |
281 | .iter() | ||
282 | .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) | ||
283 | .count(); | ||
284 | assert!(hash > n as usize); | ||
288 | 285 | ||
289 | assert_linear(&measures) | 286 | let elapsed = time.elapsed(); |
290 | } | 287 | al.sample(n as f64, elapsed.as_millis() as f64); |
291 | |||
292 | /// Checks that a set of measurements looks like a linear function rather than | ||
293 | /// like a quadratic function. Algorithm: | ||
294 | /// | ||
295 | /// 1. Linearly scale input to be in [0; 1) | ||
296 | /// 2. Using linear regression, compute the best linear function approximating | ||
297 | /// the input. | ||
298 | /// 3. Compute RMSE and maximal absolute error. | ||
299 | /// 4. Check that errors are within tolerances and that the constant term is not | ||
300 | /// too negative. | ||
301 | /// | ||
302 | /// Ideally, we should use a proper "model selection" to directly compare | ||
303 | /// quadratic and linear models, but that sounds rather complicated: | ||
304 | /// | ||
305 | /// https://stats.stackexchange.com/questions/21844/selecting-best-model-based-on-linear-quadratic-and-cubic-fit-of-data | ||
306 | fn assert_linear(xy: &[(f64, f64)]) { | ||
307 | let (mut xs, mut ys): (Vec<_>, Vec<_>) = xy.iter().copied().unzip(); | ||
308 | normalize(&mut xs); | ||
309 | normalize(&mut ys); | ||
310 | let xy = xs.iter().copied().zip(ys.iter().copied()); | ||
311 | |||
312 | // Linear regression: finding a and b to fit y = a + b*x. | ||
313 | |||
314 | let mean_x = mean(&xs); | ||
315 | let mean_y = mean(&ys); | ||
316 | |||
317 | let b = { | ||
318 | let mut num = 0.0; | ||
319 | let mut denom = 0.0; | ||
320 | for (x, y) in xy.clone() { | ||
321 | num += (x - mean_x) * (y - mean_y); | ||
322 | denom += (x - mean_x).powi(2); | ||
323 | } | 288 | } |
324 | num / denom | ||
325 | }; | ||
326 | |||
327 | let a = mean_y - b * mean_x; | ||
328 | |||
329 | let mut plot = format!("y_pred = {:.3} + {:.3} * x\n\nx y y_pred\n", a, b); | ||
330 | |||
331 | let mut se = 0.0; | ||
332 | let mut max_error = 0.0f64; | ||
333 | for (x, y) in xy { | ||
334 | let y_pred = a + b * x; | ||
335 | se += (y - y_pred).powi(2); | ||
336 | max_error = max_error.max((y_pred - y).abs()); | ||
337 | |||
338 | format_to!(plot, "{:.3} {:.3} {:.3}\n", x, y, y_pred); | ||
339 | } | ||
340 | |||
341 | let rmse = (se / xs.len() as f64).sqrt(); | ||
342 | format_to!(plot, "\nrmse = {:.3} max error = {:.3}", rmse, max_error); | ||
343 | |||
344 | assert!(rmse < 0.05 && max_error < 0.1 && a > -0.1, "\nLooks quadratic\n{}", plot); | ||
345 | |||
346 | fn normalize(xs: &mut Vec<f64>) { | ||
347 | let max = xs.iter().copied().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap(); | ||
348 | xs.iter_mut().for_each(|it| *it /= max); | ||
349 | } | ||
350 | |||
351 | fn mean(xs: &[f64]) -> f64 { | ||
352 | xs.iter().copied().sum::<f64>() / (xs.len() as f64) | ||
353 | } | 289 | } |
354 | } | 290 | } |
355 | 291 | ||
@@ -371,7 +307,7 @@ fn benchmark_syntax_highlighting_parser() { | |||
371 | .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) | 307 | .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) |
372 | .count() | 308 | .count() |
373 | }; | 309 | }; |
374 | assert_eq!(hash, 1629); | 310 | assert_eq!(hash, 1632); |
375 | } | 311 | } |
376 | 312 | ||
377 | #[test] | 313 | #[test] |