From 5355b7cb98e33a9a8a14c92e74cd335042a2119a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0=20=D0=A3=D0=BA=D1=80=D0=B0?= =?UTF-8?q?=D1=97=D0=BD=D1=96!=20=D0=93=D0=B5=D1=80=D0=BE=D1=8F=D0=BC=20?= =?UTF-8?q?=D1=81=D0=BB=D0=B0=D0=B2=D0=B0!?= <777696+ncave@users.noreply.github.com> Date: Thu, 24 Oct 2024 06:19:07 +0000 Subject: [PATCH] [All/Rust] Removed Regex.Replace from hot paths (#3937) --- src/Fable.Cli/CHANGELOG.md | 1 + src/Fable.Transforms/FSharp2Fable.Util.fs | 25 +++++--- .../Rust/AST/Rust.AST.Adapters.fs | 58 +++++++++++-------- src/Fable.Transforms/Rust/Fable2Rust.fs | 15 ++--- 4 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/Fable.Cli/CHANGELOG.md b/src/Fable.Cli/CHANGELOG.md index 3914ef46d..86672406c 100644 --- a/src/Fable.Cli/CHANGELOG.md +++ b/src/Fable.Cli/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [Rust] Fixed try finally handler order of execution (by @ncave) * [JS/TS/Python/Rust] Fixed String.StartsWith/EndsWith (#3934) (by @ncave) +* [All/Rust] Removed Regex.Replace from hot paths (by @ncave) ## 4.22.0 - 2024-10-02 diff --git a/src/Fable.Transforms/FSharp2Fable.Util.fs b/src/Fable.Transforms/FSharp2Fable.Util.fs index e5ed029b9..6ed4956ab 100644 --- a/src/Fable.Transforms/FSharp2Fable.Util.fs +++ b/src/Fable.Transforms/FSharp2Fable.Util.fs @@ -609,19 +609,27 @@ module Helpers = name.Replace('.', '_').Replace('`', '$') let cleanNameAsRustIdentifier (name: string) = - // name |> Naming.sanitizeIdentForbiddenChars - let name = Regex.Replace(name, @"[\s`'"".]", "_") - let name = if name.Length > 0 && Char.IsDigit(name, 0) then "_" + name else name - let name = - Regex.Replace(name, @"[^\w]", (fun c -> String.Format(@"_{0:x4}", int c.Value[0]))) - - name + if name |> String.exists (fun c -> not (c = '_' || Char.IsLetterOrDigit(c))) then + name + |> String.collect ( + function + | '_' + | ' ' + | '`' + | '.' + | '\'' + | '\"' -> "_" + | c when Char.IsLetterOrDigit(c) -> string c + | c -> String.Format(@"_{0:x4}", int c) + ) + else + name let memberNameAsRustIdentifier (name: string) part = let f = cleanNameAsRustIdentifier @@ -1692,7 +1700,8 @@ module Identifiers = // The F# compiler sometimes adds a numeric suffix. Remove it because it's not deterministic. // See https://github.com/fable-compiler/Fable/issues/2869#issuecomment-1169574962 if fsRef.IsCompilerGenerated then - Regex.Replace(fsRef.CompiledName, @"\d+$", "", RegexOptions.Compiled) + // Regex.Replace(fsRef.CompiledName, @"\d+$", "", RegexOptions.Compiled) + fsRef.CompiledName.TrimEnd([| '0'; '1'; '2'; '3'; '4'; '5'; '6'; '7'; '8'; '9' |]) else fsRef.CompiledName diff --git a/src/Fable.Transforms/Rust/AST/Rust.AST.Adapters.fs b/src/Fable.Transforms/Rust/AST/Rust.AST.Adapters.fs index 7940f9bce..c19cd6f8e 100644 --- a/src/Fable.Transforms/Rust/AST/Rust.AST.Adapters.fs +++ b/src/Fable.Transforms/Rust/AST/Rust.AST.Adapters.fs @@ -164,34 +164,44 @@ type System.String with Some(self.Chars(self.Length - 1)) member self.escape_debug() = - // escapes \\, \', \", \t, \r, \n, [\x00-\x1F] - let res = self.Replace("\\", @"\\").Replace("\'", @"\'").Replace("\"", @"\""") - - let res = res.Replace("\t", @"\t").Replace("\r", @"\r").Replace("\n", @"\n") - - let res = - System.Text.RegularExpressions.Regex.Replace( - res, - @"[\x00-\x1F]", - fun c -> System.String.Format(@"\u{0}{1:x4}{2}", "{", int c.Value[0], "}") + if + self + |> String.exists (fun c -> c = '\\' || c = '\'' || c = '\"' || System.Char.IsControl(c)) + then + self + |> String.collect ( + function + | '\t' -> @"\t" + | '\r' -> @"\r" + | '\n' -> @"\n" + | '\\' -> @"\\" + | '\'' -> @"\'" + | '\"' -> @"\""" + | c when System.Char.IsControl(c) -> System.String.Format(@"\u{0}{1:x4}{2}", "{", int c, "}") + | c -> string c ) - - res + else + self member self.escape_default() = - // escapes \\, \', \", \t, \r, \n, [^\x20-\x7F] - let res = self.Replace("\\", @"\\").Replace("\'", @"\'").Replace("\"", @"\""") - - let res = res.Replace("\t", @"\t").Replace("\r", @"\r").Replace("\n", @"\n") - - let res = - System.Text.RegularExpressions.Regex.Replace( - res, - @"[^\x20-\x7F]", - fun c -> System.String.Format(@"\u{0}{1:x4}{2}", "{", int c.Value[0], "}") + if + self + |> String.exists (fun c -> c = '\\' || c = '\'' || c = '\"' || c < '\x20' || c > '\x7e') + then + self + |> String.collect ( + function + | '\t' -> @"\t" + | '\r' -> @"\r" + | '\n' -> @"\n" + | '\\' -> @"\\" + | '\'' -> @"\'" + | '\"' -> @"\""" + | c when c < '\x20' || c > '\x7e' -> System.String.Format(@"\u{0}{1:x4}{2}", "{", int c, "}") + | c -> string c ) - - res + else + self type System.Text.StringBuilder with diff --git a/src/Fable.Transforms/Rust/Fable2Rust.fs b/src/Fable.Transforms/Rust/Fable2Rust.fs index 3dd0ffa99..91fe2e366 100644 --- a/src/Fable.Transforms/Rust/Fable2Rust.fs +++ b/src/Fable.Transforms/Rust/Fable2Rust.fs @@ -488,8 +488,8 @@ module TypeInfo = | _ -> isTypeOfType com isCopyableType isCopyableEntity entNames typ let isCopyableEntity com entNames (ent: Fable.Entity) = - not (ent.IsInterface) - && ent.IsValueType + ent.IsValueType + && not (ent.IsInterface) && not (hasMutableFields com ent) && (isEntityOfType com isCopyableType entNames ent) @@ -2946,13 +2946,10 @@ module Util = let typ = fableExpr.Type let nameOpt = tryGetIdentName fableExpr let patOpt = makeUnionCasePatOpt com ctx typ nameOpt tag - - match patOpt with - | Some pat -> - let expr = makeRefForPatternMatch com ctx typ nameOpt fableExpr - let letExpr = mkLetExpr pat expr - letExpr - | _ -> failwith "unreachable" + let pat = patOpt |> Option.defaultValue WILD_PAT + let expr = makeRefForPatternMatch com ctx typ nameOpt fableExpr + let letExpr = mkLetExpr pat expr + letExpr let makeTest isSome thenValue elseValue = if isSome then