From 6d268de26707170939ece8f2419be6b89ae6087e Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 21 Dec 2020 18:10:25 +0100 Subject: [PATCH 1/9] Add isVerbatim to SynConst.String. --- src/fsharp/CheckComputationExpressions.fs | 2 +- src/fsharp/CheckExpressions.fs | 12 +++---- src/fsharp/SyntaxTree.fs | 6 ++-- src/fsharp/lex.fsl | 28 +++++++-------- src/fsharp/lexhelp.fs | 12 +++---- src/fsharp/lexhelp.fsi | 4 +-- src/fsharp/pars.fsy | 27 +++++++------- src/fsharp/service/ServiceLexing.fs | 6 ++-- tests/service/Symbols.fs | 43 ++++++++++++++++++++++- 9 files changed, 92 insertions(+), 48 deletions(-) diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs index a8bd308b7ed..218be43e713 100644 --- a/src/fsharp/CheckComputationExpressions.fs +++ b/src/fsharp/CheckComputationExpressions.fs @@ -1917,7 +1917,7 @@ let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, c if nelems > 0 && List.forall (function SynExpr.Const (SynConst.UInt16 _, _) -> true | _ -> false) elems then SynExpr.Const (SynConst.UInt16s (Array.ofList (List.map (function SynExpr.Const (SynConst.UInt16 x, _) -> x | _ -> failwith "unreachable") elems)), m) elif nelems > 0 && List.forall (function SynExpr.Const (SynConst.Byte _, _) -> true | _ -> false) elems - then SynExpr.Const (SynConst.Bytes (Array.ofList (List.map (function SynExpr.Const (SynConst.Byte x, _) -> x | _ -> failwith "unreachable") elems), m), m) + then SynExpr.Const (SynConst.Bytes (Array.ofList (List.map (function SynExpr.Const (SynConst.Byte x, _) -> x | _ -> failwith "unreachable") elems), false, m), m) else SynExpr.ArrayOrList (isArray, elems, m) else if elems.Length > 500 then diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index b30ae9cd30c..642fc0161c5 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -810,7 +810,7 @@ let TcConst cenv ty m env c = | SynConst.Measure(SynConst.UInt64 i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.puint64_tcr c; Const.UInt64 i | SynConst.Measure(SynConst.UIntPtr i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.punativeint_tcr c; Const.UIntPtr i | SynConst.Char c -> unif cenv.g.char_ty; Const.Char c - | SynConst.String (s, _) -> unif cenv.g.string_ty; Const.String s + | SynConst.String (s, _, _) -> unif cenv.g.string_ty; Const.String s | SynConst.UserNum _ -> error (InternalError(FSComp.SR.tcUnexpectedBigRationalConstant(), m)) | SynConst.Measure _ -> error (Error(FSComp.SR.tcInvalidTypeForUnitsOfMeasure(), m)) | SynConst.UInt16s _ -> error (InternalError(FSComp.SR.tcUnexpectedConstUint16Array(), m)) @@ -4414,7 +4414,7 @@ and TcStaticConstantParameter cenv (env: TcEnv) tpenv kind (StripParenTypes v) i | SynConst.Single n when typeEquiv g g.float32_ty kind -> record(g.float32_ty); box (n: single) | SynConst.Double n when typeEquiv g g.float_ty kind -> record(g.float_ty); box (n: double) | SynConst.Char n when typeEquiv g g.char_ty kind -> record(g.char_ty); box (n: char) - | SynConst.String (s, _) when s <> null && typeEquiv g g.string_ty kind -> record(g.string_ty); box (s: string) + | SynConst.String (s, _, _) when s <> null && typeEquiv g g.string_ty kind -> record(g.string_ty); box (s: string) | SynConst.Bool b when typeEquiv g g.bool_ty kind -> record(g.bool_ty); box (b: bool) | _ -> fail() v, tpenv @@ -4794,7 +4794,7 @@ and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p match pat with | SynPat.Const (c, m) -> match c with - | SynConst.Bytes (bytes, m) -> + | SynConst.Bytes (bytes, _, m) -> UnifyTypes cenv env m ty (mkByteArrayTy cenv.g) TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) ty (SynPat.ArrayOrList (true, [ for b in bytes -> SynPat.Const(SynConst.Byte b, m) ], m)) @@ -5425,7 +5425,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = | SynExpr.DotIndexedGet _ | SynExpr.DotIndexedSet _ | SynExpr.TypeApp _ | SynExpr.Ident _ | SynExpr.LongIdent _ | SynExpr.App _ | SynExpr.DotGet _ -> error(Error(FSComp.SR.tcExprUndelayed(), synExpr.Range)) - | SynExpr.Const (SynConst.String (s, m), _) -> + | SynExpr.Const (SynConst.String (s, _, m), _) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) TcConstStringExpr cenv overallTy env m tpenv s @@ -6784,7 +6784,7 @@ and TcConstExpr cenv overallTy env m tpenv c = match c with // NOTE: these aren't "really" constants - | SynConst.Bytes (bytes, m) -> + | SynConst.Bytes (bytes, _, m) -> UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g) Expr.Op (TOp.Bytes bytes, [], [], m), tpenv @@ -6810,7 +6810,7 @@ and TcConstExpr cenv overallTy env m tpenv c = let i64 = int64 s SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromInt64", SynExpr.Const (SynConst.Int64 i64, m), m) with _ -> - SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromString", SynExpr.Const (SynConst.String (s, m), m), m) + SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromString", SynExpr.Const (SynConst.String (s, false, m), m), m) if suffix <> "I" then expr diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index 6e9b68280c6..7756b7b4547 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -139,13 +139,13 @@ type SynConst = | UserNum of value: string * suffix: string /// F# syntax: verbatim or regular string, e.g. "abc" - | String of text: string * range: range + | String of text: string * isVerbatim: bool * range: range /// F# syntax: verbatim or regular byte string, e.g. "abc"B. /// /// Also used internally in the typechecker once an array of unit16 constants /// is detected, to allow more efficient processing of large arrays of uint16 constants. - | Bytes of bytes: byte[] * range: range + | Bytes of bytes: byte[] * isVerbatim: bool * range: range /// Used internally in the typechecker once an array of unit16 constants /// is detected, to allow more efficient processing of large arrays of uint16 constants. @@ -157,7 +157,7 @@ type SynConst = /// Gets the syntax range of this construct member c.Range dflt = match c with - | SynConst.String (_, m0) | SynConst.Bytes (_, m0) -> m0 + | SynConst.String (_, _, m0) | SynConst.Bytes (_, _, m0) -> m0 | _ -> dflt /// Represents an unchecked syntax tree of F# unit of measure annotations. diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index 8317f4f5a92..2bd97c857d2 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -136,18 +136,18 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = let m = lexbuf.LexemeRange let startp = lexbuf.StartPos let fin = - LexerStringFinisher (fun buf kind isPart cont -> + LexerStringFinisher (fun buf kind isPart isVerbatim cont -> // Adjust the start-of-token mark back to the true start of the token lexbuf.StartPos <- startp - if kind.IsByteString then + if kind.IsByteString then if kind.IsInterpolated then fail args lexbuf (FSComp.SR.lexByteStringMayNotBeInterpolated()) () - BYTEARRAY (Lexhelp.stringBufferAsBytes buf, cont) + BYTEARRAY (Lexhelp.stringBufferAsBytes buf, isVerbatim, cont) elif Lexhelp.stringBufferIsBytes buf then - BYTEARRAY (Lexhelp.stringBufferAsBytes buf, cont) + BYTEARRAY (Lexhelp.stringBufferAsBytes buf, isVerbatim, cont) else fail args lexbuf (FSComp.SR.lexByteArrayCannotEncode()) () - BYTEARRAY (Lexhelp.stringBufferAsBytes buf, cont) + BYTEARRAY (Lexhelp.stringBufferAsBytes buf, isVerbatim, cont) elif kind.IsInterpolated then let s = Lexhelp.stringBufferAsString buf if kind.IsInterpolatedFirst then @@ -162,7 +162,7 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = INTERP_STRING_END (s, cont) else let s = Lexhelp.stringBufferAsString buf - STRING (s, cont)) + STRING (s, isVerbatim, cont)) buf,fin,m @@ -1124,13 +1124,13 @@ and singleQuoteString sargs skip = parse | '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false cont + fin.Finish buf kind false false cont } | '"''B' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf { kind with IsByteString = true } false cont + fin.Finish buf { kind with IsByteString = true } false false cont } | ("{{" | "}}") @@ -1147,7 +1147,7 @@ and singleQuoteString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.SingleQuote, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true cont + fin.Finish buf kind true false cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, kind, m)) @@ -1214,13 +1214,13 @@ and verbatimString sargs skip = parse | '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false cont + fin.Finish buf kind false true cont } | '"''B' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf { kind with IsByteString = true } false cont + fin.Finish buf { kind with IsByteString = true } false true cont } | newline @@ -1244,7 +1244,7 @@ and verbatimString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.Verbatim, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true cont + fin.Finish buf kind true true cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.Verbatim, kind, m)) @@ -1297,7 +1297,7 @@ and tripleQuoteString sargs skip = parse | '"' '"' '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false cont } + fin.Finish buf kind false false cont } | newline { let (buf, _fin, m, kind, args) = sargs @@ -1340,7 +1340,7 @@ and tripleQuoteString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.TripleQuote, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true cont + fin.Finish buf kind true false cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.TripleQuote, kind, m)) diff --git a/src/fsharp/lexhelp.fs b/src/fsharp/lexhelp.fs index 767dcae116f..b4f7779d2f3 100644 --- a/src/fsharp/lexhelp.fs +++ b/src/fsharp/lexhelp.fs @@ -120,14 +120,14 @@ let stringBufferAsBytes (buf: ByteBuffer) = Array.init (bytes.Length / 2) (fun i -> bytes.[i*2]) type LexerStringFinisher = - | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> LexerContinuation -> token) + | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> LexerContinuation -> token) - member fin.Finish (buf: ByteBuffer) kind isInterpolatedStringPart cont = + member fin.Finish (buf: ByteBuffer) kind isInterpolatedStringPart isVerbatim cont = let (LexerStringFinisher f) = fin - f buf kind isInterpolatedStringPart cont + f buf kind isInterpolatedStringPart isVerbatim cont static member Default = - LexerStringFinisher (fun buf kind isPart cont -> + LexerStringFinisher (fun buf kind isPart isVerbatim cont -> if kind.IsInterpolated then let s = stringBufferAsString buf if kind.IsInterpolatedFirst then @@ -141,9 +141,9 @@ type LexerStringFinisher = else INTERP_STRING_END (s, cont) elif kind.IsByteString then - BYTEARRAY (stringBufferAsBytes buf, cont) + BYTEARRAY (stringBufferAsBytes buf, isVerbatim, cont) else - STRING (stringBufferAsString buf, cont) + STRING (stringBufferAsString buf, isVerbatim, cont) ) let addUnicodeString (buf: ByteBuffer) (x:string) = diff --git a/src/fsharp/lexhelp.fsi b/src/fsharp/lexhelp.fsi index f7cf0b25d6d..efaeae71792 100644 --- a/src/fsharp/lexhelp.fsi +++ b/src/fsharp/lexhelp.fsi @@ -55,9 +55,9 @@ val reusingLexbufForParsing: UnicodeLexing.Lexbuf -> (unit -> 'a) -> 'a val usingLexbufForParsing: UnicodeLexing.Lexbuf * string -> (UnicodeLexing.Lexbuf -> 'a) -> 'a type LexerStringFinisher = - | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> LexerContinuation -> token) + | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> LexerContinuation -> token) - member Finish: buf: ByteBuffer -> kind: LexerStringKind -> isInterpolatedStringPart: bool -> cont: LexerContinuation -> token + member Finish: buf: ByteBuffer -> kind: LexerStringKind -> isInterpolatedStringPart: bool -> isVerbatim: bool -> cont: LexerContinuation -> token static member Default: LexerStringFinisher diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index cfce563057b..02f517d795e 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -195,8 +195,8 @@ let rangeOfLongIdent(lid:LongIdent) = %} // Producing these changes the lex state, e.g. string --> token, or nesting level of braces in interpolated strings -%token BYTEARRAY -%token STRING +%token BYTEARRAY +%token STRING %token INTERP_STRING_BEGIN_END %token INTERP_STRING_BEGIN_PART %token INTERP_STRING_PART @@ -647,7 +647,7 @@ hashDirectiveArgs: /* One argument to a #directive */ hashDirectiveArg: | stringOrKeywordString - { $1 } + { fst $1 } /*--------------------------------------------------------------------------*/ @@ -2240,7 +2240,7 @@ inlineAssemblyTyconRepr: | HASH stringOrKeywordString HASH { libraryOnlyError (lhs parseState) let lhsm = lhs parseState - let ilType = ParseAssemblyCodeType $2 parseState.LexBuffer.SupportsFeature (rhs parseState 2) + let ilType = ParseAssemblyCodeType (fst $2) parseState.LexBuffer.SupportsFeature (rhs parseState 2) SynTypeDefnSimpleRepr.LibraryOnlyILAssembly (box ilType, lhsm) } classOrInterfaceOrStruct: @@ -2665,7 +2665,7 @@ cPrototype: let rhsExpr = SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.Ident (ident("failwith", rhs parseState 6)), - SynExpr.Const (SynConst.String("extern was not given a DllImport attribute", rhs parseState 8), rhs parseState 8), + SynExpr.Const (SynConst.String("extern was not given a DllImport attribute", false, rhs parseState 8), rhs parseState 8), mRhs) (fun attrs _ -> let bindingId = SynPat.LongIdent (LongIdentWithDots([nm], []), None, Some noInferredTypars, SynArgPats.Pats [SynPat.Tuple(false, args, argsm)], vis, nmm) @@ -2909,10 +2909,12 @@ rawConstant: { SynConst.UserNum $1 } | stringOrKeywordString - { SynConst.String ($1, lhs parseState) } + { let s, isVerbatim = $1 + SynConst.String (s, isVerbatim, lhs parseState) } | BYTEARRAY - { SynConst.Bytes (fst $1, lhs parseState) } + { let (v, isVerbatim, _) = $1 + SynConst.Bytes (v, isVerbatim, lhs parseState) } rationalConstant: | INT32 INFIX_STAR_DIV_MOD_OP INT32 @@ -3851,7 +3853,7 @@ declExpr: dynamicArg: | IDENT - { let con = SynConst.String ($1, rhs parseState 1) + { let con = SynConst.String ($1, false, rhs parseState 1) let arg2 = SynExpr.Const (con, con.Range (rhs parseState 1)) arg2 } @@ -4491,7 +4493,7 @@ forLoopDirection: inlineAssemblyExpr: | HASH stringOrKeywordString opt_inlineAssemblyTypeArg optCurriedArgExprs optInlineAssemblyReturnTypes HASH { libraryOnlyWarning (lhs parseState) - let s, sm = $2, rhs parseState 2 + let s, sm = fst $2, rhs parseState 2 (fun m -> let ilInstrs = ParseAssemblyCodeInstructions s parseState.LexBuffer.SupportsFeature sm SynExpr.LibraryOnlyILAssembly (box ilInstrs, $3, List.rev $4, $5, m)) } @@ -5072,7 +5074,7 @@ atomType: | NULL { let m = rhs parseState 1 - SynType.StaticConstant(SynConst.String (null, m), m) } + SynType.StaticConstant(SynConst.String (null, false, m), m) } | CONST atomicExpr { let e, _ = $2 @@ -5528,8 +5530,9 @@ colonOrEquals: /* A literal string or a string from a keyword like __SOURCE_FILE__ */ stringOrKeywordString: - | STRING { fst $1 } - | KEYWORD_STRING { $1 } + | STRING { let (s, isVerbatim, _) = $1 + s, isVerbatim } + | KEYWORD_STRING { $1, false } interpolatedStringFill: | declExpr diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs index 2e8931a697e..dd943a94bef 100755 --- a/src/fsharp/service/ServiceLexing.fs +++ b/src/fsharp/service/ServiceLexing.fs @@ -34,7 +34,7 @@ type Positions = Position * Position module FSharpTokenTag = let Identifier = tagOfToken (IDENT "a") - let String = tagOfToken (STRING ("a", LexCont.Default)) + let String = tagOfToken (STRING ("a", false, LexCont.Default)) let IDENT = tagOfToken (IDENT "a") let STRING = String @@ -385,8 +385,8 @@ module internal LexerStateEncoding = | INTERP_STRING_END (_, cont) | LBRACE cont | RBRACE cont - | BYTEARRAY (_, cont) - | STRING (_, cont) -> cont + | BYTEARRAY (_, _, cont) + | STRING (_, _, cont) -> cont | _ -> prevLexcont // Note that this will discard all lexcont state, including the ifdefStack. diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index 983d9555c8f..abb2ffab480 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -287,4 +287,45 @@ module SyntaxExpressions = assertRange 2 4 3 14 doRange assertRange 4 4 5 18 doBangRange | _ -> - failwith "Could not find SynExpr.Do" \ No newline at end of file + failwith "Could not find SynExpr.Do" +module VerbatimStrings = + let getBindingConstValue (parseResults: ParsedInput option) bindingName = + parseResults + |> Option.bind (fun tree -> + match tree with + | ParsedInput.ImplFile (ParsedImplFileInput(modules = modules)) -> + modules + |> List.tryPick (function + | SynModuleOrNamespace(decls = decls) -> + decls + |> List.tryPick (function + | SynModuleDecl.Let(bindings = bindings) -> + bindings + |> List.tryPick (function + | SynBinding.Binding(_, _, _, _, _, _, _, SynPat.Named(ident = ident), _, SynExpr.Const (c, _), _, _) when ident.idText = bindingName -> Some c + | _ -> None) + | _ -> None + ) + ) + | _ -> None + ) + + [] + [] + [] + [] + [] + let ``SynConst.String tracks verbatim-ness`` (bindingName: string, isVerbatim: bool) = + let parseResults = getParseResults """ + let string1 = "yo" + let string2 = @"yo" + let bytes1 = "yo"B + let bytes2 = @"yo"B + """ + match getBindingConstValue parseResults bindingName with + | Some (SynConst.String(_, verbatim, _)) -> + verbatim |> should equal isVerbatim + | Some (SynConst.Bytes(_, verbatim, _)) -> + verbatim |> should equal isVerbatim + | _ -> + failwithf "Couldn't find const named %s" bindingName \ No newline at end of file From 76ec78f9b0abbc67b640076b339f313f209bf9a7 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 21 Dec 2020 18:52:49 +0100 Subject: [PATCH 2/9] Fix SurfaceAreaTest. --- .../SurfaceArea.netstandard.fs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 2f2f63d424f..1a6d5fdcfa9 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -6640,6 +6640,8 @@ FSharp.Compiler.SyntaxTree+SynConst+Byte: Byte Item FSharp.Compiler.SyntaxTree+SynConst+Byte: Byte get_Item() FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] bytes FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] get_bytes() +FSharp.Compiler.SyntaxTree+SynConst+Bytes: Boolean get_isVerbatim() +FSharp.Compiler.SyntaxTree+SynConst+Bytes: Boolean isVerbatim FSharp.Compiler.SyntaxTree+SynConst+Bytes: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.SyntaxTree+SynConst+Bytes: FSharp.Compiler.Text.Range range FSharp.Compiler.SyntaxTree+SynConst+Char: Char Item @@ -6668,6 +6670,11 @@ FSharp.Compiler.SyntaxTree+SynConst+String: FSharp.Compiler.Text.Range get_range FSharp.Compiler.SyntaxTree+SynConst+String: FSharp.Compiler.Text.Range range FSharp.Compiler.SyntaxTree+SynConst+String: System.String get_text() FSharp.Compiler.SyntaxTree+SynConst+String: System.String text +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isVerbatim() +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isVerbatim +FSharp.Compiler.SyntaxTree+SynConst+String: range Range(range) +FSharp.Compiler.SyntaxTree+SynConst+String: range get_range() +FSharp.Compiler.SyntaxTree+SynConst+String: range range FSharp.Compiler.SyntaxTree+SynConst+Tags: Int32 Bool FSharp.Compiler.SyntaxTree+SynConst+Tags: Int32 Byte FSharp.Compiler.SyntaxTree+SynConst+Tags: Int32 Bytes @@ -6771,7 +6778,7 @@ FSharp.Compiler.SyntaxTree+SynConst: Int32 Tag FSharp.Compiler.SyntaxTree+SynConst: Int32 get_Tag() FSharp.Compiler.SyntaxTree+SynConst: SynConst NewBool(Boolean) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewByte(Byte) -FSharp.Compiler.SyntaxTree+SynConst: SynConst NewBytes(Byte[], FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTree+SynConst: SynConst NewBytes(Byte[], Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewChar(Char) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewDecimal(System.Decimal) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewDouble(Double) @@ -6782,7 +6789,7 @@ FSharp.Compiler.SyntaxTree+SynConst: SynConst NewIntPtr(Int64) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewMeasure(SynConst, SynMeasure) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewSByte(SByte) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewSingle(Single) -FSharp.Compiler.SyntaxTree+SynConst: SynConst NewString(System.String, FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTree+SynConst: SynConst NewString(System.String, Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt16(UInt16) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt16s(UInt16[]) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt32(UInt32) From c0ad52f865d6bada4798d41feb7c5120c7d6a972 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 21 Dec 2020 21:24:27 +0100 Subject: [PATCH 3/9] Keep track of triple quote in SynConst.String. --- src/fsharp/CheckExpressions.fs | 8 +- src/fsharp/SyntaxTree.fs | 4 +- src/fsharp/lex.fsl | 20 ++-- src/fsharp/lexhelp.fs | 10 +- src/fsharp/lexhelp.fsi | 4 +- src/fsharp/pars.fsy | 29 ++--- src/fsharp/service/ServiceLexing.fs | 4 +- .../SurfaceArea.netstandard.fs | 4 +- tests/service/Symbols.fs | 110 +++++++++++------- 9 files changed, 113 insertions(+), 80 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 642fc0161c5..a2863fc2f8d 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -810,7 +810,7 @@ let TcConst cenv ty m env c = | SynConst.Measure(SynConst.UInt64 i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.puint64_tcr c; Const.UInt64 i | SynConst.Measure(SynConst.UIntPtr i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.punativeint_tcr c; Const.UIntPtr i | SynConst.Char c -> unif cenv.g.char_ty; Const.Char c - | SynConst.String (s, _, _) -> unif cenv.g.string_ty; Const.String s + | SynConst.String (s, _, _, _) -> unif cenv.g.string_ty; Const.String s | SynConst.UserNum _ -> error (InternalError(FSComp.SR.tcUnexpectedBigRationalConstant(), m)) | SynConst.Measure _ -> error (Error(FSComp.SR.tcInvalidTypeForUnitsOfMeasure(), m)) | SynConst.UInt16s _ -> error (InternalError(FSComp.SR.tcUnexpectedConstUint16Array(), m)) @@ -4414,7 +4414,7 @@ and TcStaticConstantParameter cenv (env: TcEnv) tpenv kind (StripParenTypes v) i | SynConst.Single n when typeEquiv g g.float32_ty kind -> record(g.float32_ty); box (n: single) | SynConst.Double n when typeEquiv g g.float_ty kind -> record(g.float_ty); box (n: double) | SynConst.Char n when typeEquiv g g.char_ty kind -> record(g.char_ty); box (n: char) - | SynConst.String (s, _, _) when s <> null && typeEquiv g g.string_ty kind -> record(g.string_ty); box (s: string) + | SynConst.String (s, _, _, _) when s <> null && typeEquiv g g.string_ty kind -> record(g.string_ty); box (s: string) | SynConst.Bool b when typeEquiv g g.bool_ty kind -> record(g.bool_ty); box (b: bool) | _ -> fail() v, tpenv @@ -5425,7 +5425,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = | SynExpr.DotIndexedGet _ | SynExpr.DotIndexedSet _ | SynExpr.TypeApp _ | SynExpr.Ident _ | SynExpr.LongIdent _ | SynExpr.App _ | SynExpr.DotGet _ -> error(Error(FSComp.SR.tcExprUndelayed(), synExpr.Range)) - | SynExpr.Const (SynConst.String (s, _, m), _) -> + | SynExpr.Const (SynConst.String (s, _, _, m), _) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) TcConstStringExpr cenv overallTy env m tpenv s @@ -6810,7 +6810,7 @@ and TcConstExpr cenv overallTy env m tpenv c = let i64 = int64 s SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromInt64", SynExpr.Const (SynConst.Int64 i64, m), m) with _ -> - SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromString", SynExpr.Const (SynConst.String (s, false, m), m), m) + SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromString", SynExpr.Const (SynConst.String (s, false, false, m), m), m) if suffix <> "I" then expr diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index 7756b7b4547..00c60c42703 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -139,7 +139,7 @@ type SynConst = | UserNum of value: string * suffix: string /// F# syntax: verbatim or regular string, e.g. "abc" - | String of text: string * isVerbatim: bool * range: range + | String of text: string * isVerbatim: bool * isTripleQuote: bool * range: range /// F# syntax: verbatim or regular byte string, e.g. "abc"B. /// @@ -157,7 +157,7 @@ type SynConst = /// Gets the syntax range of this construct member c.Range dflt = match c with - | SynConst.String (_, _, m0) | SynConst.Bytes (_, _, m0) -> m0 + | SynConst.String (_, _, _, m0) | SynConst.Bytes (_, _, m0) -> m0 | _ -> dflt /// Represents an unchecked syntax tree of F# unit of measure annotations. diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index 2bd97c857d2..cd58306ef8d 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -136,7 +136,7 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = let m = lexbuf.LexemeRange let startp = lexbuf.StartPos let fin = - LexerStringFinisher (fun buf kind isPart isVerbatim cont -> + LexerStringFinisher (fun buf kind isPart isVerbatim isTripleQuote cont -> // Adjust the start-of-token mark back to the true start of the token lexbuf.StartPos <- startp if kind.IsByteString then @@ -162,7 +162,7 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = INTERP_STRING_END (s, cont) else let s = Lexhelp.stringBufferAsString buf - STRING (s, isVerbatim, cont)) + STRING (s, isVerbatim, isTripleQuote, cont)) buf,fin,m @@ -1124,13 +1124,13 @@ and singleQuoteString sargs skip = parse | '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false false cont + fin.Finish buf kind false false false cont } | '"''B' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf { kind with IsByteString = true } false false cont + fin.Finish buf { kind with IsByteString = true } false false false cont } | ("{{" | "}}") @@ -1147,7 +1147,7 @@ and singleQuoteString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.SingleQuote, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true false cont + fin.Finish buf kind true false false cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, kind, m)) @@ -1214,13 +1214,13 @@ and verbatimString sargs skip = parse | '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false true cont + fin.Finish buf kind false true false cont } | '"''B' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf { kind with IsByteString = true } false true cont + fin.Finish buf { kind with IsByteString = true } false true false cont } | newline @@ -1244,7 +1244,7 @@ and verbatimString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.Verbatim, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true true cont + fin.Finish buf kind true true false cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.Verbatim, kind, m)) @@ -1297,7 +1297,7 @@ and tripleQuoteString sargs skip = parse | '"' '"' '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false false cont } + fin.Finish buf kind false false true cont } | newline { let (buf, _fin, m, kind, args) = sargs @@ -1340,7 +1340,7 @@ and tripleQuoteString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.TripleQuote, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true false cont + fin.Finish buf kind true false true cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.TripleQuote, kind, m)) diff --git a/src/fsharp/lexhelp.fs b/src/fsharp/lexhelp.fs index b4f7779d2f3..ad37e0d01a5 100644 --- a/src/fsharp/lexhelp.fs +++ b/src/fsharp/lexhelp.fs @@ -120,14 +120,14 @@ let stringBufferAsBytes (buf: ByteBuffer) = Array.init (bytes.Length / 2) (fun i -> bytes.[i*2]) type LexerStringFinisher = - | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> LexerContinuation -> token) + | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> bool -> LexerContinuation -> token) - member fin.Finish (buf: ByteBuffer) kind isInterpolatedStringPart isVerbatim cont = + member fin.Finish (buf: ByteBuffer) kind isInterpolatedStringPart isVerbatim isTripleQuote cont = let (LexerStringFinisher f) = fin - f buf kind isInterpolatedStringPart isVerbatim cont + f buf kind isInterpolatedStringPart isVerbatim isTripleQuote cont static member Default = - LexerStringFinisher (fun buf kind isPart isVerbatim cont -> + LexerStringFinisher (fun buf kind isPart isVerbatim isTripleQuote cont -> if kind.IsInterpolated then let s = stringBufferAsString buf if kind.IsInterpolatedFirst then @@ -143,7 +143,7 @@ type LexerStringFinisher = elif kind.IsByteString then BYTEARRAY (stringBufferAsBytes buf, isVerbatim, cont) else - STRING (stringBufferAsString buf, isVerbatim, cont) + STRING (stringBufferAsString buf, isVerbatim, isTripleQuote, cont) ) let addUnicodeString (buf: ByteBuffer) (x:string) = diff --git a/src/fsharp/lexhelp.fsi b/src/fsharp/lexhelp.fsi index efaeae71792..cc54762a443 100644 --- a/src/fsharp/lexhelp.fsi +++ b/src/fsharp/lexhelp.fsi @@ -55,9 +55,9 @@ val reusingLexbufForParsing: UnicodeLexing.Lexbuf -> (unit -> 'a) -> 'a val usingLexbufForParsing: UnicodeLexing.Lexbuf * string -> (UnicodeLexing.Lexbuf -> 'a) -> 'a type LexerStringFinisher = - | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> LexerContinuation -> token) + | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> bool -> LexerContinuation -> token) - member Finish: buf: ByteBuffer -> kind: LexerStringKind -> isInterpolatedStringPart: bool -> isVerbatim: bool -> cont: LexerContinuation -> token + member Finish: buf: ByteBuffer -> kind: LexerStringKind -> isInterpolatedStringPart: bool -> isVerbatim: bool -> isTripleQuote: bool -> cont: LexerContinuation -> token static member Default: LexerStringFinisher diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index 02f517d795e..40b3795d7df 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -196,7 +196,7 @@ let rangeOfLongIdent(lid:LongIdent) = // Producing these changes the lex state, e.g. string --> token, or nesting level of braces in interpolated strings %token BYTEARRAY -%token STRING +%token STRING %token INTERP_STRING_BEGIN_END %token INTERP_STRING_BEGIN_PART %token INTERP_STRING_PART @@ -647,7 +647,8 @@ hashDirectiveArgs: /* One argument to a #directive */ hashDirectiveArg: | stringOrKeywordString - { fst $1 } + { let s, _, _ = $1 + s } /*--------------------------------------------------------------------------*/ @@ -2239,8 +2240,9 @@ braceBarFieldDeclListCore: inlineAssemblyTyconRepr: | HASH stringOrKeywordString HASH { libraryOnlyError (lhs parseState) - let lhsm = lhs parseState - let ilType = ParseAssemblyCodeType (fst $2) parseState.LexBuffer.SupportsFeature (rhs parseState 2) + let lhsm = lhs parseState + let s, _, _ = $2 + let ilType = ParseAssemblyCodeType s parseState.LexBuffer.SupportsFeature (rhs parseState 2) SynTypeDefnSimpleRepr.LibraryOnlyILAssembly (box ilType, lhsm) } classOrInterfaceOrStruct: @@ -2665,7 +2667,7 @@ cPrototype: let rhsExpr = SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.Ident (ident("failwith", rhs parseState 6)), - SynExpr.Const (SynConst.String("extern was not given a DllImport attribute", false, rhs parseState 8), rhs parseState 8), + SynExpr.Const (SynConst.String("extern was not given a DllImport attribute", false, false, rhs parseState 8), rhs parseState 8), mRhs) (fun attrs _ -> let bindingId = SynPat.LongIdent (LongIdentWithDots([nm], []), None, Some noInferredTypars, SynArgPats.Pats [SynPat.Tuple(false, args, argsm)], vis, nmm) @@ -2909,8 +2911,8 @@ rawConstant: { SynConst.UserNum $1 } | stringOrKeywordString - { let s, isVerbatim = $1 - SynConst.String (s, isVerbatim, lhs parseState) } + { let s, isVerbatim, isTripleQuote = $1 + SynConst.String (s, isVerbatim, isTripleQuote, lhs parseState) } | BYTEARRAY { let (v, isVerbatim, _) = $1 @@ -3853,7 +3855,7 @@ declExpr: dynamicArg: | IDENT - { let con = SynConst.String ($1, false, rhs parseState 1) + { let con = SynConst.String ($1, false, false, rhs parseState 1) let arg2 = SynExpr.Const (con, con.Range (rhs parseState 1)) arg2 } @@ -4493,7 +4495,7 @@ forLoopDirection: inlineAssemblyExpr: | HASH stringOrKeywordString opt_inlineAssemblyTypeArg optCurriedArgExprs optInlineAssemblyReturnTypes HASH { libraryOnlyWarning (lhs parseState) - let s, sm = fst $2, rhs parseState 2 + let (s, _, _), sm = $2, rhs parseState 2 (fun m -> let ilInstrs = ParseAssemblyCodeInstructions s parseState.LexBuffer.SupportsFeature sm SynExpr.LibraryOnlyILAssembly (box ilInstrs, $3, List.rev $4, $5, m)) } @@ -5074,7 +5076,7 @@ atomType: | NULL { let m = rhs parseState 1 - SynType.StaticConstant(SynConst.String (null, false, m), m) } + SynType.StaticConstant(SynConst.String (null, false, false, m), m) } | CONST atomicExpr { let e, _ = $2 @@ -5530,9 +5532,10 @@ colonOrEquals: /* A literal string or a string from a keyword like __SOURCE_FILE__ */ stringOrKeywordString: - | STRING { let (s, isVerbatim, _) = $1 - s, isVerbatim } - | KEYWORD_STRING { $1, false } + | STRING + { let (s, isVerbatim, isTripleQuote, _) = $1 + s, isVerbatim, isTripleQuote } + | KEYWORD_STRING { $1, false, false } interpolatedStringFill: | declExpr diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs index dd943a94bef..14c2e211921 100755 --- a/src/fsharp/service/ServiceLexing.fs +++ b/src/fsharp/service/ServiceLexing.fs @@ -34,7 +34,7 @@ type Positions = Position * Position module FSharpTokenTag = let Identifier = tagOfToken (IDENT "a") - let String = tagOfToken (STRING ("a", false, LexCont.Default)) + let String = tagOfToken (STRING ("a", false, false, LexCont.Default)) let IDENT = tagOfToken (IDENT "a") let STRING = String @@ -386,7 +386,7 @@ module internal LexerStateEncoding = | LBRACE cont | RBRACE cont | BYTEARRAY (_, _, cont) - | STRING (_, _, cont) -> cont + | STRING (_, _, _, cont) -> cont | _ -> prevLexcont // Note that this will discard all lexcont state, including the ifdefStack. diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 1a6d5fdcfa9..cfe9ce35825 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -6672,6 +6672,8 @@ FSharp.Compiler.SyntaxTree+SynConst+String: System.String get_text() FSharp.Compiler.SyntaxTree+SynConst+String: System.String text FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isVerbatim() FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isVerbatim +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isTripleQuote +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isTripleQuote() FSharp.Compiler.SyntaxTree+SynConst+String: range Range(range) FSharp.Compiler.SyntaxTree+SynConst+String: range get_range() FSharp.Compiler.SyntaxTree+SynConst+String: range range @@ -6789,7 +6791,7 @@ FSharp.Compiler.SyntaxTree+SynConst: SynConst NewIntPtr(Int64) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewMeasure(SynConst, SynMeasure) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewSByte(SByte) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewSingle(Single) -FSharp.Compiler.SyntaxTree+SynConst: SynConst NewString(System.String, Boolean, FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTree+SynConst: SynConst NewString(System.String, Boolean, Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt16(UInt16) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt16s(UInt16[]) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt32(UInt32) diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index abb2ffab480..497e46560d1 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -288,44 +288,72 @@ module SyntaxExpressions = assertRange 4 4 5 18 doBangRange | _ -> failwith "Could not find SynExpr.Do" -module VerbatimStrings = - let getBindingConstValue (parseResults: ParsedInput option) bindingName = - parseResults - |> Option.bind (fun tree -> - match tree with - | ParsedInput.ImplFile (ParsedImplFileInput(modules = modules)) -> - modules - |> List.tryPick (function - | SynModuleOrNamespace(decls = decls) -> - decls - |> List.tryPick (function - | SynModuleDecl.Let(bindings = bindings) -> - bindings - |> List.tryPick (function - | SynBinding.Binding(_, _, _, _, _, _, _, SynPat.Named(ident = ident), _, SynExpr.Const (c, _), _, _) when ident.idText = bindingName -> Some c - | _ -> None) - | _ -> None - ) - ) - | _ -> None - ) - - [] - [] - [] - [] - [] - let ``SynConst.String tracks verbatim-ness`` (bindingName: string, isVerbatim: bool) = - let parseResults = getParseResults """ - let string1 = "yo" - let string2 = @"yo" - let bytes1 = "yo"B - let bytes2 = @"yo"B - """ - match getBindingConstValue parseResults bindingName with - | Some (SynConst.String(_, verbatim, _)) -> - verbatim |> should equal isVerbatim - | Some (SynConst.Bytes(_, verbatim, _)) -> - verbatim |> should equal isVerbatim - | _ -> - failwithf "Couldn't find const named %s" bindingName \ No newline at end of file + +module Strings = + let getBindingConstValue (parseResults: ParsedInput option) bindingName = + parseResults + |> Option.bind + (fun tree -> + match tree with + | ParsedInput.ImplFile (ParsedImplFileInput (modules = modules)) -> + modules + |> List.tryPick + (function + | SynModuleOrNamespace (decls = decls) -> + decls + |> List.tryPick + (function + | SynModuleDecl.Let (bindings = bindings) -> + bindings + |> List.tryPick + (function + | SynBinding.Binding (_, + _, + _, + _, + _, + _, + _, + SynPat.Named (ident = ident), + _, + SynExpr.Const (c, _), + _, + _) when ident.idText = bindingName -> Some c + | _ -> None) + | _ -> None)) + | _ -> None) + + [] + [] + [] + [] + [] + let ``SynConst.String tracks verbatim-ness`` (bindingName: string, isVerbatim: bool) = + let parseResults = + getParseResults + """ + let string1 = "yo" + let string2 = @"yo" + let bytes1 = "yo"B + let bytes2 = @"yo"B + """ + + match getBindingConstValue parseResults bindingName with + | Some (SynConst.String (_, verbatim, _, _)) -> verbatim |> should equal isVerbatim + | Some (SynConst.Bytes (_, verbatim, _)) -> verbatim |> should equal isVerbatim + | _ -> failwithf "Couldn't find const named %s" bindingName + + [] + [] + [] + let ``SynConst.String tracks triple quotes`` (bindingName: string, isTripleQuote: bool) = + let parseResults = + getParseResults + """ + let string1 = "yo" + let string2 = \"\"\"yo\"\"\" + """ + + match getBindingConstValue parseResults bindingName with + | Some (SynConst.String (_, _, tripleQuote_, _)) -> tripleQuote_ |> should equal isTripleQuote + | _ -> failwithf "Couldn't find const named %s" bindingName \ No newline at end of file From b76be5a3024f809683f713ffbc9647f7894406e9 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 21 Dec 2020 21:48:00 +0100 Subject: [PATCH 4/9] Update triple quote tests. --- tests/service/Symbols.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index 497e46560d1..7f1faf58a35 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -349,10 +349,10 @@ module Strings = let ``SynConst.String tracks triple quotes`` (bindingName: string, isTripleQuote: bool) = let parseResults = getParseResults - """ - let string1 = "yo" + " + let string1 = \"yo\" let string2 = \"\"\"yo\"\"\" - """ + " match getBindingConstValue parseResults bindingName with | Some (SynConst.String (_, _, tripleQuote_, _)) -> tripleQuote_ |> should equal isTripleQuote From 15f7276b7be9b62b9b5290dfece46ca093722a08 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 24 Dec 2020 13:17:31 +0100 Subject: [PATCH 5/9] Correct SurfaceArea.netstandard.fs. --- .../SurfaceArea.netstandard.fs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index cfe9ce35825..82077518901 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -6638,10 +6638,10 @@ FSharp.Compiler.SyntaxTree+SynConst+Bool: Boolean Item FSharp.Compiler.SyntaxTree+SynConst+Bool: Boolean get_Item() FSharp.Compiler.SyntaxTree+SynConst+Byte: Byte Item FSharp.Compiler.SyntaxTree+SynConst+Byte: Byte get_Item() -FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] bytes -FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] get_bytes() FSharp.Compiler.SyntaxTree+SynConst+Bytes: Boolean get_isVerbatim() FSharp.Compiler.SyntaxTree+SynConst+Bytes: Boolean isVerbatim +FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] bytes +FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] get_bytes() FSharp.Compiler.SyntaxTree+SynConst+Bytes: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.SyntaxTree+SynConst+Bytes: FSharp.Compiler.Text.Range range FSharp.Compiler.SyntaxTree+SynConst+Char: Char Item @@ -6666,17 +6666,14 @@ FSharp.Compiler.SyntaxTree+SynConst+SByte: SByte Item FSharp.Compiler.SyntaxTree+SynConst+SByte: SByte get_Item() FSharp.Compiler.SyntaxTree+SynConst+Single: Single Item FSharp.Compiler.SyntaxTree+SynConst+Single: Single get_Item() +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isTripleQuote() +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isVerbatim() +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isTripleQuote +FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isVerbatim FSharp.Compiler.SyntaxTree+SynConst+String: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.SyntaxTree+SynConst+String: FSharp.Compiler.Text.Range range FSharp.Compiler.SyntaxTree+SynConst+String: System.String get_text() FSharp.Compiler.SyntaxTree+SynConst+String: System.String text -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isVerbatim() -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isVerbatim -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isTripleQuote -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isTripleQuote() -FSharp.Compiler.SyntaxTree+SynConst+String: range Range(range) -FSharp.Compiler.SyntaxTree+SynConst+String: range get_range() -FSharp.Compiler.SyntaxTree+SynConst+String: range range FSharp.Compiler.SyntaxTree+SynConst+Tags: Int32 Bool FSharp.Compiler.SyntaxTree+SynConst+Tags: Int32 Byte FSharp.Compiler.SyntaxTree+SynConst+Tags: Int32 Bytes From 8f7f932205bddd1e4415724766b69c420cea9190 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 5 Jan 2021 21:09:25 +0100 Subject: [PATCH 6/9] Refactor to SynStringKind and SynByteStringKind. --- src/fsharp/CheckComputationExpressions.fs | 2 +- src/fsharp/CheckExpressions.fs | 8 +-- src/fsharp/SyntaxTree.fs | 19 ++++- src/fsharp/pars.fsy | 15 ++-- .../SurfaceArea.netstandard.fs | 65 ++++++++++++++--- tests/service/Symbols.fs | 71 +++++++++++++------ 6 files changed, 136 insertions(+), 44 deletions(-) diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs index 218be43e713..31ca729a399 100644 --- a/src/fsharp/CheckComputationExpressions.fs +++ b/src/fsharp/CheckComputationExpressions.fs @@ -1917,7 +1917,7 @@ let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, c if nelems > 0 && List.forall (function SynExpr.Const (SynConst.UInt16 _, _) -> true | _ -> false) elems then SynExpr.Const (SynConst.UInt16s (Array.ofList (List.map (function SynExpr.Const (SynConst.UInt16 x, _) -> x | _ -> failwith "unreachable") elems)), m) elif nelems > 0 && List.forall (function SynExpr.Const (SynConst.Byte _, _) -> true | _ -> false) elems - then SynExpr.Const (SynConst.Bytes (Array.ofList (List.map (function SynExpr.Const (SynConst.Byte x, _) -> x | _ -> failwith "unreachable") elems), false, m), m) + then SynExpr.Const (SynConst.Bytes (Array.ofList (List.map (function SynExpr.Const (SynConst.Byte x, _) -> x | _ -> failwith "unreachable") elems), SynByteStringKind.Regular, m), m) else SynExpr.ArrayOrList (isArray, elems, m) else if elems.Length > 500 then diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index a2863fc2f8d..4724e7b2d09 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -810,7 +810,7 @@ let TcConst cenv ty m env c = | SynConst.Measure(SynConst.UInt64 i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.puint64_tcr c; Const.UInt64 i | SynConst.Measure(SynConst.UIntPtr i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.punativeint_tcr c; Const.UIntPtr i | SynConst.Char c -> unif cenv.g.char_ty; Const.Char c - | SynConst.String (s, _, _, _) -> unif cenv.g.string_ty; Const.String s + | SynConst.String (s, _, _) -> unif cenv.g.string_ty; Const.String s | SynConst.UserNum _ -> error (InternalError(FSComp.SR.tcUnexpectedBigRationalConstant(), m)) | SynConst.Measure _ -> error (Error(FSComp.SR.tcInvalidTypeForUnitsOfMeasure(), m)) | SynConst.UInt16s _ -> error (InternalError(FSComp.SR.tcUnexpectedConstUint16Array(), m)) @@ -4414,7 +4414,7 @@ and TcStaticConstantParameter cenv (env: TcEnv) tpenv kind (StripParenTypes v) i | SynConst.Single n when typeEquiv g g.float32_ty kind -> record(g.float32_ty); box (n: single) | SynConst.Double n when typeEquiv g g.float_ty kind -> record(g.float_ty); box (n: double) | SynConst.Char n when typeEquiv g g.char_ty kind -> record(g.char_ty); box (n: char) - | SynConst.String (s, _, _, _) when s <> null && typeEquiv g g.string_ty kind -> record(g.string_ty); box (s: string) + | SynConst.String (s, _, _) when s <> null && typeEquiv g g.string_ty kind -> record(g.string_ty); box (s: string) | SynConst.Bool b when typeEquiv g g.bool_ty kind -> record(g.bool_ty); box (b: bool) | _ -> fail() v, tpenv @@ -5425,7 +5425,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = | SynExpr.DotIndexedGet _ | SynExpr.DotIndexedSet _ | SynExpr.TypeApp _ | SynExpr.Ident _ | SynExpr.LongIdent _ | SynExpr.App _ | SynExpr.DotGet _ -> error(Error(FSComp.SR.tcExprUndelayed(), synExpr.Range)) - | SynExpr.Const (SynConst.String (s, _, _, m), _) -> + | SynExpr.Const (SynConst.String (s, _, m), _) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) TcConstStringExpr cenv overallTy env m tpenv s @@ -6810,7 +6810,7 @@ and TcConstExpr cenv overallTy env m tpenv c = let i64 = int64 s SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromInt64", SynExpr.Const (SynConst.Int64 i64, m), m) with _ -> - SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromString", SynExpr.Const (SynConst.String (s, false, false, m), m), m) + SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromString", SynExpr.Const (SynConst.String (s, SynStringKind.Regular, m), m), m) if suffix <> "I" then expr diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index 00c60c42703..ad7e61c292c 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -81,6 +81,19 @@ type SynTypar = | Typar(id, _, _) -> id.idRange +/// Indicate if the string had a special format +[] +type SynStringKind = + | Regular + | Verbatim + | TripleQuote + +/// Indicate if the byte string had a special format +[] +type SynByteStringKind = + | Regular + | Verbatim + /// The unchecked abstract syntax tree of constants in F# types and expressions. [] type SynConst = @@ -139,13 +152,13 @@ type SynConst = | UserNum of value: string * suffix: string /// F# syntax: verbatim or regular string, e.g. "abc" - | String of text: string * isVerbatim: bool * isTripleQuote: bool * range: range + | String of text: string * synStringKind :SynStringKind * range: range /// F# syntax: verbatim or regular byte string, e.g. "abc"B. /// /// Also used internally in the typechecker once an array of unit16 constants /// is detected, to allow more efficient processing of large arrays of uint16 constants. - | Bytes of bytes: byte[] * isVerbatim: bool * range: range + | Bytes of bytes: byte[] * synByteStringKind: SynByteStringKind * range: range /// Used internally in the typechecker once an array of unit16 constants /// is detected, to allow more efficient processing of large arrays of uint16 constants. @@ -157,7 +170,7 @@ type SynConst = /// Gets the syntax range of this construct member c.Range dflt = match c with - | SynConst.String (_, _, _, m0) | SynConst.Bytes (_, _, m0) -> m0 + | SynConst.String (_, _, m0) | SynConst.Bytes (_, _, m0) -> m0 | _ -> dflt /// Represents an unchecked syntax tree of F# unit of measure annotations. diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index 40b3795d7df..f3d8701ec62 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -2667,7 +2667,7 @@ cPrototype: let rhsExpr = SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.Ident (ident("failwith", rhs parseState 6)), - SynExpr.Const (SynConst.String("extern was not given a DllImport attribute", false, false, rhs parseState 8), rhs parseState 8), + SynExpr.Const (SynConst.String("extern was not given a DllImport attribute", SynStringKind.Regular, rhs parseState 8), rhs parseState 8), mRhs) (fun attrs _ -> let bindingId = SynPat.LongIdent (LongIdentWithDots([nm], []), None, Some noInferredTypars, SynArgPats.Pats [SynPat.Tuple(false, args, argsm)], vis, nmm) @@ -2912,11 +2912,16 @@ rawConstant: | stringOrKeywordString { let s, isVerbatim, isTripleQuote = $1 - SynConst.String (s, isVerbatim, isTripleQuote, lhs parseState) } + let synStringKind = + if isVerbatim then SynStringKind.Verbatim + elif isTripleQuote then SynStringKind.TripleQuote + else SynStringKind.Regular + SynConst.String (s, synStringKind, lhs parseState) } | BYTEARRAY { let (v, isVerbatim, _) = $1 - SynConst.Bytes (v, isVerbatim, lhs parseState) } + let synByteStringKind = if isVerbatim then SynByteStringKind.Verbatim else SynByteStringKind.Regular + SynConst.Bytes (v, synByteStringKind, lhs parseState) } rationalConstant: | INT32 INFIX_STAR_DIV_MOD_OP INT32 @@ -3855,7 +3860,7 @@ declExpr: dynamicArg: | IDENT - { let con = SynConst.String ($1, false, false, rhs parseState 1) + { let con = SynConst.String ($1, SynStringKind.Regular, rhs parseState 1) let arg2 = SynExpr.Const (con, con.Range (rhs parseState 1)) arg2 } @@ -5076,7 +5081,7 @@ atomType: | NULL { let m = rhs parseState 1 - SynType.StaticConstant(SynConst.String (null, false, false, m), m) } + SynType.StaticConstant(SynConst.String (null, SynStringKind.Regular, m), m) } | CONST atomicExpr { let e, _ = $2 diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 82077518901..1a5d6162abb 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -6612,6 +6612,28 @@ FSharp.Compiler.SyntaxTree+SynBindingReturnInfo: SynBindingReturnInfo NewSynBind FSharp.Compiler.SyntaxTree+SynBindingReturnInfo: SynType get_typeName() FSharp.Compiler.SyntaxTree+SynBindingReturnInfo: SynType typeName FSharp.Compiler.SyntaxTree+SynBindingReturnInfo: System.String ToString() +FSharp.Compiler.SyntaxTree+SynByteStringKind+Tags: Int32 Regular +FSharp.Compiler.SyntaxTree+SynByteStringKind+Tags: Int32 Verbatim +FSharp.Compiler.SyntaxTree+SynByteStringKind: Boolean Equals(SynByteStringKind) +FSharp.Compiler.SyntaxTree+SynByteStringKind: Boolean Equals(System.Object) +FSharp.Compiler.SyntaxTree+SynByteStringKind: Boolean Equals(System.Object, System.Collections.IEqualityComparer) +FSharp.Compiler.SyntaxTree+SynByteStringKind: Boolean IsRegular +FSharp.Compiler.SyntaxTree+SynByteStringKind: Boolean IsVerbatim +FSharp.Compiler.SyntaxTree+SynByteStringKind: Boolean get_IsRegular() +FSharp.Compiler.SyntaxTree+SynByteStringKind: Boolean get_IsVerbatim() +FSharp.Compiler.SyntaxTree+SynByteStringKind: FSharp.Compiler.SyntaxTree+SynByteStringKind+Tags +FSharp.Compiler.SyntaxTree+SynByteStringKind: Int32 CompareTo(SynByteStringKind) +FSharp.Compiler.SyntaxTree+SynByteStringKind: Int32 CompareTo(System.Object) +FSharp.Compiler.SyntaxTree+SynByteStringKind: Int32 CompareTo(System.Object, System.Collections.IComparer) +FSharp.Compiler.SyntaxTree+SynByteStringKind: Int32 GetHashCode() +FSharp.Compiler.SyntaxTree+SynByteStringKind: Int32 GetHashCode(System.Collections.IEqualityComparer) +FSharp.Compiler.SyntaxTree+SynByteStringKind: Int32 Tag +FSharp.Compiler.SyntaxTree+SynByteStringKind: Int32 get_Tag() +FSharp.Compiler.SyntaxTree+SynByteStringKind: SynByteStringKind Regular +FSharp.Compiler.SyntaxTree+SynByteStringKind: SynByteStringKind Verbatim +FSharp.Compiler.SyntaxTree+SynByteStringKind: SynByteStringKind get_Regular() +FSharp.Compiler.SyntaxTree+SynByteStringKind: SynByteStringKind get_Verbatim() +FSharp.Compiler.SyntaxTree+SynByteStringKind: System.String ToString() FSharp.Compiler.SyntaxTree+SynComponentInfo: Boolean get_preferPostfix() FSharp.Compiler.SyntaxTree+SynComponentInfo: Boolean preferPostfix FSharp.Compiler.SyntaxTree+SynComponentInfo: FSharp.Compiler.Text.Range Range @@ -6638,12 +6660,12 @@ FSharp.Compiler.SyntaxTree+SynConst+Bool: Boolean Item FSharp.Compiler.SyntaxTree+SynConst+Bool: Boolean get_Item() FSharp.Compiler.SyntaxTree+SynConst+Byte: Byte Item FSharp.Compiler.SyntaxTree+SynConst+Byte: Byte get_Item() -FSharp.Compiler.SyntaxTree+SynConst+Bytes: Boolean get_isVerbatim() -FSharp.Compiler.SyntaxTree+SynConst+Bytes: Boolean isVerbatim FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] bytes FSharp.Compiler.SyntaxTree+SynConst+Bytes: Byte[] get_bytes() FSharp.Compiler.SyntaxTree+SynConst+Bytes: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.SyntaxTree+SynConst+Bytes: FSharp.Compiler.Text.Range range +FSharp.Compiler.SyntaxTree+SynConst+Bytes: SynByteStringKind get_synByteStringKind() +FSharp.Compiler.SyntaxTree+SynConst+Bytes: SynByteStringKind synByteStringKind FSharp.Compiler.SyntaxTree+SynConst+Char: Char Item FSharp.Compiler.SyntaxTree+SynConst+Char: Char get_Item() FSharp.Compiler.SyntaxTree+SynConst+Decimal: System.Decimal Item @@ -6666,12 +6688,10 @@ FSharp.Compiler.SyntaxTree+SynConst+SByte: SByte Item FSharp.Compiler.SyntaxTree+SynConst+SByte: SByte get_Item() FSharp.Compiler.SyntaxTree+SynConst+Single: Single Item FSharp.Compiler.SyntaxTree+SynConst+Single: Single get_Item() -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isTripleQuote() -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean get_isVerbatim() -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isTripleQuote -FSharp.Compiler.SyntaxTree+SynConst+String: Boolean isVerbatim FSharp.Compiler.SyntaxTree+SynConst+String: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.SyntaxTree+SynConst+String: FSharp.Compiler.Text.Range range +FSharp.Compiler.SyntaxTree+SynConst+String: SynStringKind get_synStringKind() +FSharp.Compiler.SyntaxTree+SynConst+String: SynStringKind synStringKind FSharp.Compiler.SyntaxTree+SynConst+String: System.String get_text() FSharp.Compiler.SyntaxTree+SynConst+String: System.String text FSharp.Compiler.SyntaxTree+SynConst+Tags: Int32 Bool @@ -6777,7 +6797,7 @@ FSharp.Compiler.SyntaxTree+SynConst: Int32 Tag FSharp.Compiler.SyntaxTree+SynConst: Int32 get_Tag() FSharp.Compiler.SyntaxTree+SynConst: SynConst NewBool(Boolean) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewByte(Byte) -FSharp.Compiler.SyntaxTree+SynConst: SynConst NewBytes(Byte[], Boolean, FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTree+SynConst: SynConst NewBytes(Byte[], SynByteStringKind, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewChar(Char) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewDecimal(System.Decimal) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewDouble(Double) @@ -6788,7 +6808,7 @@ FSharp.Compiler.SyntaxTree+SynConst: SynConst NewIntPtr(Int64) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewMeasure(SynConst, SynMeasure) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewSByte(SByte) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewSingle(Single) -FSharp.Compiler.SyntaxTree+SynConst: SynConst NewString(System.String, Boolean, Boolean, FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTree+SynConst: SynConst NewString(System.String, SynStringKind, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt16(UInt16) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt16s(UInt16[]) FSharp.Compiler.SyntaxTree+SynConst: SynConst NewUInt32(UInt32) @@ -8688,6 +8708,33 @@ FSharp.Compiler.SyntaxTree+SynStaticOptimizationConstraint: Int32 get_Tag() FSharp.Compiler.SyntaxTree+SynStaticOptimizationConstraint: SynStaticOptimizationConstraint NewWhenTyparIsStruct(SynTypar, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynStaticOptimizationConstraint: SynStaticOptimizationConstraint NewWhenTyparTyconEqualsTycon(SynTypar, SynType, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynStaticOptimizationConstraint: System.String ToString() +FSharp.Compiler.SyntaxTree+SynStringKind+Tags: Int32 Regular +FSharp.Compiler.SyntaxTree+SynStringKind+Tags: Int32 TripleQuote +FSharp.Compiler.SyntaxTree+SynStringKind+Tags: Int32 Verbatim +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean Equals(SynStringKind) +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean Equals(System.Object) +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean Equals(System.Object, System.Collections.IEqualityComparer) +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean IsRegular +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean IsTripleQuote +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean IsVerbatim +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean get_IsRegular() +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean get_IsTripleQuote() +FSharp.Compiler.SyntaxTree+SynStringKind: Boolean get_IsVerbatim() +FSharp.Compiler.SyntaxTree+SynStringKind: FSharp.Compiler.SyntaxTree+SynStringKind+Tags +FSharp.Compiler.SyntaxTree+SynStringKind: Int32 CompareTo(SynStringKind) +FSharp.Compiler.SyntaxTree+SynStringKind: Int32 CompareTo(System.Object) +FSharp.Compiler.SyntaxTree+SynStringKind: Int32 CompareTo(System.Object, System.Collections.IComparer) +FSharp.Compiler.SyntaxTree+SynStringKind: Int32 GetHashCode() +FSharp.Compiler.SyntaxTree+SynStringKind: Int32 GetHashCode(System.Collections.IEqualityComparer) +FSharp.Compiler.SyntaxTree+SynStringKind: Int32 Tag +FSharp.Compiler.SyntaxTree+SynStringKind: Int32 get_Tag() +FSharp.Compiler.SyntaxTree+SynStringKind: SynStringKind Regular +FSharp.Compiler.SyntaxTree+SynStringKind: SynStringKind TripleQuote +FSharp.Compiler.SyntaxTree+SynStringKind: SynStringKind Verbatim +FSharp.Compiler.SyntaxTree+SynStringKind: SynStringKind get_Regular() +FSharp.Compiler.SyntaxTree+SynStringKind: SynStringKind get_TripleQuote() +FSharp.Compiler.SyntaxTree+SynStringKind: SynStringKind get_Verbatim() +FSharp.Compiler.SyntaxTree+SynStringKind: System.String ToString() FSharp.Compiler.SyntaxTree+SynTypar: Boolean get_isCompGen() FSharp.Compiler.SyntaxTree+SynTypar: Boolean isCompGen FSharp.Compiler.SyntaxTree+SynTypar: FSharp.Compiler.Text.Range Range @@ -9419,6 +9466,7 @@ FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynAttributeList FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynBinding FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynBindingKind FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynBindingReturnInfo +FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynByteStringKind FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynComponentInfo FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynConst FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynEnumCase @@ -9447,6 +9495,7 @@ FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynSimplePat FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynSimplePatAlternativeIdInfo FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynSimplePats FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynStaticOptimizationConstraint +FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynStringKind FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynTypar FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynTyparDecl FSharp.Compiler.SyntaxTree: FSharp.Compiler.SyntaxTree+SynType diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index 7f1faf58a35..fa3f8a7a203 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -290,7 +290,7 @@ module SyntaxExpressions = failwith "Could not find SynExpr.Do" module Strings = - let getBindingConstValue (parseResults: ParsedInput option) bindingName = + let getBindingConstValue (parseResults: ParsedInput option) = parseResults |> Option.bind (fun tree -> @@ -318,42 +318,67 @@ module Strings = _, SynExpr.Const (c, _), _, - _) when ident.idText = bindingName -> Some c + _) -> Some c | _ -> None) | _ -> None)) | _ -> None) - [] - [] - [] - [] [] - let ``SynConst.String tracks verbatim-ness`` (bindingName: string, isVerbatim: bool) = + let ``SynConst.String with SynStringKind.Regular`` () = let parseResults = getParseResults """ - let string1 = "yo" - let string2 = @"yo" - let bytes1 = "yo"B - let bytes2 = @"yo"B + let s = "yo" """ - match getBindingConstValue parseResults bindingName with - | Some (SynConst.String (_, verbatim, _, _)) -> verbatim |> should equal isVerbatim - | Some (SynConst.Bytes (_, verbatim, _)) -> verbatim |> should equal isVerbatim - | _ -> failwithf "Couldn't find const named %s" bindingName + match getBindingConstValue parseResults with + | Some (SynConst.String (_, kind, _)) -> kind |> should equal SynStringKind.Regular + | _ -> failwithf "Couldn't find const" - [] - [] [] - let ``SynConst.String tracks triple quotes`` (bindingName: string, isTripleQuote: bool) = + let ``SynConst.String with SynStringKind.Verbatim`` () = + let parseResults = + getParseResults + """ + let s = @"yo" + """ + + match getBindingConstValue parseResults with + | Some (SynConst.String (_, kind, _)) -> kind |> should equal SynStringKind.Verbatim + | _ -> failwithf "Couldn't find const" + + [] + let ``SynConst.String with SynStringKind.TripleQuote`` () = let parseResults = getParseResults " - let string1 = \"yo\" - let string2 = \"\"\"yo\"\"\" + let s = \"\"\"yo\"\"\" " - match getBindingConstValue parseResults bindingName with - | Some (SynConst.String (_, _, tripleQuote_, _)) -> tripleQuote_ |> should equal isTripleQuote - | _ -> failwithf "Couldn't find const named %s" bindingName \ No newline at end of file + match getBindingConstValue parseResults with + | Some (SynConst.String (_, kind, _)) -> kind |> should equal SynStringKind.TripleQuote + | _ -> failwithf "Couldn't find const" + + [] + let ``SynConst.Bytes with SynByteStringKind.Regular`` () = + let parseResults = + getParseResults + """ +let bytes = "yo"B + """ + + match getBindingConstValue parseResults with + | Some (SynConst.Bytes (_, kind, _)) -> kind |> should equal SynByteStringKind.Regular + | _ -> failwithf "Couldn't find const" + + [] + let ``SynConst.Bytes with SynByteStringKind.Verbatim`` () = + let parseResults = + getParseResults + """ +let bytes = @"yo"B + """ + + match getBindingConstValue parseResults with + | Some (SynConst.Bytes (_, kind, _)) -> kind |> should equal SynByteStringKind.Verbatim + | _ -> failwithf "Couldn't find const" From 0aebae101476e3802952466c75038aea646b2ee5 Mon Sep 17 00:00:00 2001 From: nojaf Date: Sun, 17 Jan 2021 15:06:33 +0100 Subject: [PATCH 7/9] Refactored boolean arguments with LexerStringFinisherContext. --- src/fsharp/lex.fsl | 22 +++++++++++++--------- src/fsharp/lexhelp.fs | 18 ++++++++++++++---- src/fsharp/lexhelp.fsi | 9 +++++++-- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index cd58306ef8d..becca5475d5 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -136,9 +136,13 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = let m = lexbuf.LexemeRange let startp = lexbuf.StartPos let fin = - LexerStringFinisher (fun buf kind isPart isVerbatim isTripleQuote cont -> + LexerStringFinisher (fun buf kind context cont -> // Adjust the start-of-token mark back to the true start of the token lexbuf.StartPos <- startp + let isPart = context.HasFlag(LexerStringFinisherContext.InterpolatedPart) + let isVerbatim = context.HasFlag(LexerStringFinisherContext.Verbatim) + let isTripleQuote = context.HasFlag(LexerStringFinisherContext.TripleQuote) + if kind.IsByteString then if kind.IsInterpolated then fail args lexbuf (FSComp.SR.lexByteStringMayNotBeInterpolated()) () @@ -1124,13 +1128,13 @@ and singleQuoteString sargs skip = parse | '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false false false cont + fin.Finish buf kind (enum(0)) cont } | '"''B' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf { kind with IsByteString = true } false false false cont + fin.Finish buf { kind with IsByteString = true } (enum(0)) cont } | ("{{" | "}}") @@ -1147,7 +1151,7 @@ and singleQuoteString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.SingleQuote, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true false false cont + fin.Finish buf kind LexerStringFinisherContext.InterpolatedPart cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, kind, m)) @@ -1214,13 +1218,13 @@ and verbatimString sargs skip = parse | '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false true false cont + fin.Finish buf kind LexerStringFinisherContext.Verbatim cont } | '"''B' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf { kind with IsByteString = true } false true false cont + fin.Finish buf { kind with IsByteString = true } LexerStringFinisherContext.Verbatim cont } | newline @@ -1244,7 +1248,7 @@ and verbatimString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.Verbatim, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true true false cont + fin.Finish buf kind (enum(3)) cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.Verbatim, kind, m)) @@ -1297,7 +1301,7 @@ and tripleQuoteString sargs skip = parse | '"' '"' '"' { let (buf, fin, _m, kind, args) = sargs let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind false false true cont } + fin.Finish buf kind (enum(4)) cont } | newline { let (buf, _fin, m, kind, args) = sargs @@ -1340,7 +1344,7 @@ and tripleQuoteString sargs skip = parse let m2 = lexbuf.LexemeRange args.stringNest <- (1, LexerStringStyle.TripleQuote, m2) :: args.stringNest let cont = LexCont.Token(args.ifdefStack, args.stringNest) - fin.Finish buf kind true false true cont + fin.Finish buf kind (enum(5)) cont else addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.TripleQuote, kind, m)) diff --git a/src/fsharp/lexhelp.fs b/src/fsharp/lexhelp.fs index ad37e0d01a5..f4655c9c826 100644 --- a/src/fsharp/lexhelp.fs +++ b/src/fsharp/lexhelp.fs @@ -119,15 +119,25 @@ let stringBufferAsBytes (buf: ByteBuffer) = let bytes = buf.Close() Array.init (bytes.Length / 2) (fun i -> bytes.[i*2]) +[] +type LexerStringFinisherContext = + | InterpolatedPart = 1 + | Verbatim = 2 + | TripleQuote = 4 + type LexerStringFinisher = - | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> bool -> LexerContinuation -> token) + | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> LexerStringFinisherContext -> LexerContinuation -> token) - member fin.Finish (buf: ByteBuffer) kind isInterpolatedStringPart isVerbatim isTripleQuote cont = + member fin.Finish (buf: ByteBuffer) kind context cont = let (LexerStringFinisher f) = fin - f buf kind isInterpolatedStringPart isVerbatim isTripleQuote cont + f buf kind context cont static member Default = - LexerStringFinisher (fun buf kind isPart isVerbatim isTripleQuote cont -> + LexerStringFinisher (fun buf kind context cont -> + let isPart = context.HasFlag(LexerStringFinisherContext.InterpolatedPart) + let isVerbatim = context.HasFlag(LexerStringFinisherContext.Verbatim) + let isTripleQuote = context.HasFlag(LexerStringFinisherContext.TripleQuote) + if kind.IsInterpolated then let s = stringBufferAsString buf if kind.IsInterpolatedFirst then diff --git a/src/fsharp/lexhelp.fsi b/src/fsharp/lexhelp.fsi index cc54762a443..e3f1053fb24 100644 --- a/src/fsharp/lexhelp.fsi +++ b/src/fsharp/lexhelp.fsi @@ -54,10 +54,15 @@ val reusingLexbufForParsing: UnicodeLexing.Lexbuf -> (unit -> 'a) -> 'a val usingLexbufForParsing: UnicodeLexing.Lexbuf * string -> (UnicodeLexing.Lexbuf -> 'a) -> 'a +type LexerStringFinisherContext = + | InterpolatedPart = 1 + | Verbatim = 2 + | TripleQuote = 4 + type LexerStringFinisher = - | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> bool -> bool -> bool -> LexerContinuation -> token) + | LexerStringFinisher of (ByteBuffer -> LexerStringKind -> LexerStringFinisherContext -> LexerContinuation -> token) - member Finish: buf: ByteBuffer -> kind: LexerStringKind -> isInterpolatedStringPart: bool -> isVerbatim: bool -> isTripleQuote: bool -> cont: LexerContinuation -> token + member Finish: buf: ByteBuffer -> kind: LexerStringKind -> context: LexerStringFinisherContext -> cont: LexerContinuation -> token static member Default: LexerStringFinisher From 94634817a7511217934f7163812f5204c69eefed Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 1 Feb 2021 18:38:21 +0100 Subject: [PATCH 8/9] Add SynStringKind to SynExpr.InterpolatedString. --- src/fsharp/CheckExpressions.fs | 2 +- src/fsharp/SyntaxTree.fs | 1 + src/fsharp/SyntaxTreeOps.fs | 2 +- src/fsharp/lex.fsl | 4 +- src/fsharp/lexhelp.fs | 4 +- src/fsharp/pars.fsy | 17 ++++++--- src/fsharp/service/ServiceLexing.fs | 8 ++-- src/fsharp/service/ServiceParseTreeWalk.fs | 2 +- src/fsharp/service/ServiceUntypedParse.fs | 2 +- .../SurfaceArea.netstandard.fs | 4 +- tests/service/Symbols.fs | 37 +++++++++++++++++-- 11 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 4724e7b2d09..8be4fa32aa5 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -5429,7 +5429,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) TcConstStringExpr cenv overallTy env m tpenv s - | SynExpr.InterpolatedString (parts, m) -> + | SynExpr.InterpolatedString (parts, _, m) -> checkLanguageFeatureError cenv.g.langVersion LanguageFeature.StringInterpolation m CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index ad7e61c292c..7be3b52e981 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -1028,6 +1028,7 @@ type SynExpr = /// Note the string ranges include the quotes, verbatim markers, dollar sign and braces | InterpolatedString of contents: SynInterpolatedStringPart list * + synStringKind :SynStringKind * range: range /// Gets the syntax range of this construct diff --git a/src/fsharp/SyntaxTreeOps.fs b/src/fsharp/SyntaxTreeOps.fs index 3fd1ce32224..c3287c241fd 100644 --- a/src/fsharp/SyntaxTreeOps.fs +++ b/src/fsharp/SyntaxTreeOps.fs @@ -735,7 +735,7 @@ let rec synExprContainsError inpExpr = | SynExpr.LetOrUseBang (rhs=e1;body=e2;andBangs=es) -> walkExpr e1 || walkExprs [ for (_,_,_,_,e,_) in es do yield e ] || walkExpr e2 - | SynExpr.InterpolatedString (parts, _m) -> + | SynExpr.InterpolatedString (parts, _, _m) -> walkExprs (parts |> List.choose (function | SynInterpolatedStringPart.String _ -> None diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index becca5475d5..d15f70c1d29 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -156,9 +156,9 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = let s = Lexhelp.stringBufferAsString buf if kind.IsInterpolatedFirst then if isPart then - INTERP_STRING_BEGIN_PART (s, cont) + INTERP_STRING_BEGIN_PART (s, isTripleQuote, cont) else - INTERP_STRING_BEGIN_END (s, cont) + INTERP_STRING_BEGIN_END (s, isTripleQuote, cont) else if isPart then INTERP_STRING_PART (s, cont) diff --git a/src/fsharp/lexhelp.fs b/src/fsharp/lexhelp.fs index f4655c9c826..3810ed596be 100644 --- a/src/fsharp/lexhelp.fs +++ b/src/fsharp/lexhelp.fs @@ -142,9 +142,9 @@ type LexerStringFinisher = let s = stringBufferAsString buf if kind.IsInterpolatedFirst then if isPart then - INTERP_STRING_BEGIN_PART (s, cont) + INTERP_STRING_BEGIN_PART (s, isTripleQuote, cont) else - INTERP_STRING_BEGIN_END (s, cont) + INTERP_STRING_BEGIN_END (s, isTripleQuote, cont) else if isPart then INTERP_STRING_PART (s, cont) diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index f3d8701ec62..2b037f7e811 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -197,8 +197,8 @@ let rangeOfLongIdent(lid:LongIdent) = // Producing these changes the lex state, e.g. string --> token, or nesting level of braces in interpolated strings %token BYTEARRAY %token STRING -%token INTERP_STRING_BEGIN_END -%token INTERP_STRING_BEGIN_PART +%token INTERP_STRING_BEGIN_END +%token INTERP_STRING_BEGIN_PART %token INTERP_STRING_PART %token INTERP_STRING_END %token LBRACE RBRACE @@ -4255,7 +4255,9 @@ atomicExprAfterType: { $1 } | interpolatedString - { SynExpr.InterpolatedString($1, rhs parseState 1) } + { let parts, isTripleQuote = $1 + let synStringKind = if isTripleQuote then SynStringKind.TripleQuote else SynStringKind.Regular + SynExpr.InterpolatedString(parts, synStringKind, rhs parseState 1) } | NULL { SynExpr.Null (lhs parseState) } @@ -5568,17 +5570,20 @@ interpolatedStringParts: /* INTERP_STRING_BEGIN_PART int32 INTERP_STRING_PART int32 INTERP_STRING_END */ interpolatedString: | INTERP_STRING_BEGIN_PART interpolatedStringFill interpolatedStringParts - { SynInterpolatedStringPart.String (fst $1, rhs parseState 1) :: SynInterpolatedStringPart.FillExpr $2 :: $3 } + { let s, isTripleQuote, _ = $1 + SynInterpolatedStringPart.String (s, rhs parseState 1) :: SynInterpolatedStringPart.FillExpr $2 :: $3, isTripleQuote } | INTERP_STRING_BEGIN_END - { [ SynInterpolatedStringPart.String (fst $1, rhs parseState 1) ] } + { let s, isTripleQuote, _ = $1 + [ SynInterpolatedStringPart.String (s, rhs parseState 1) ], isTripleQuote } | INTERP_STRING_BEGIN_PART interpolatedStringParts { + let s, isTripleQuote, _ = $1 let rbrace = parseState.InputEndPosition 1 let lbrace = parseState.InputStartPosition 2 reportParseErrorAt (mkSynRange rbrace lbrace) (FSComp.SR.parsEmptyFillInInterpolatedString()) - SynInterpolatedStringPart.String (fst $1, rhs parseState 1) :: $2 } + SynInterpolatedStringPart.String (s, rhs parseState 1) :: $2, isTripleQuote } opt_HIGH_PRECEDENCE_APP: | HIGH_PRECEDENCE_BRACK_APP { } diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs index 14c2e211921..a828eac55bf 100755 --- a/src/fsharp/service/ServiceLexing.fs +++ b/src/fsharp/service/ServiceLexing.fs @@ -38,8 +38,8 @@ module FSharpTokenTag = let IDENT = tagOfToken (IDENT "a") let STRING = String - let INTERP_STRING_BEGIN_END = tagOfToken (INTERP_STRING_BEGIN_END ("a", LexCont.Default)) - let INTERP_STRING_BEGIN_PART = tagOfToken (INTERP_STRING_BEGIN_PART ("a", LexCont.Default)) + let INTERP_STRING_BEGIN_END = tagOfToken (INTERP_STRING_BEGIN_END ("a", false, LexCont.Default)) + let INTERP_STRING_BEGIN_PART = tagOfToken (INTERP_STRING_BEGIN_PART ("a", false, LexCont.Default)) let INTERP_STRING_PART = tagOfToken (INTERP_STRING_PART ("a", LexCont.Default)) let INTERP_STRING_END = tagOfToken (INTERP_STRING_END ("a", LexCont.Default)) let LPAREN = tagOfToken LPAREN @@ -379,9 +379,9 @@ module internal LexerStateEncoding = | LINE_COMMENT cont | STRING_TEXT cont | EOF cont - | INTERP_STRING_BEGIN_PART (_, cont) + | INTERP_STRING_BEGIN_PART (_, _, cont) | INTERP_STRING_PART (_, cont) - | INTERP_STRING_BEGIN_END (_, cont) + | INTERP_STRING_BEGIN_END (_, _, cont) | INTERP_STRING_END (_, cont) | LBRACE cont | RBRACE cont diff --git a/src/fsharp/service/ServiceParseTreeWalk.fs b/src/fsharp/service/ServiceParseTreeWalk.fs index e7748415c3c..46a9b180937 100755 --- a/src/fsharp/service/ServiceParseTreeWalk.fs +++ b/src/fsharp/service/ServiceParseTreeWalk.fs @@ -214,7 +214,7 @@ module public AstTraversal = | SynExpr.Const (_synConst, _range) -> None - | SynExpr.InterpolatedString (parts, _) -> + | SynExpr.InterpolatedString (parts, _, _) -> [ for part in parts do match part with | SynInterpolatedStringPart.String _ -> () diff --git a/src/fsharp/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs index 9a9d83f059a..40c3dc27a1b 100755 --- a/src/fsharp/service/ServiceUntypedParse.fs +++ b/src/fsharp/service/ServiceUntypedParse.fs @@ -445,7 +445,7 @@ type FSharpParseFileResults(errors: FSharpDiagnostic[], input: ParsedInput optio | SynExpr.Paren (e, _, _, _) -> yield! walkExpr false e - | SynExpr.InterpolatedString (parts, _) -> + | SynExpr.InterpolatedString (parts, _, _) -> yield! walkExprs [ for part in parts do match part with | SynInterpolatedStringPart.String _ -> () diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 1a5d6162abb..cfcf10f9d6c 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -7062,6 +7062,8 @@ FSharp.Compiler.SyntaxTree+SynExpr+InterpolatedString: FSharp.Compiler.Text.Rang FSharp.Compiler.SyntaxTree+SynExpr+InterpolatedString: FSharp.Compiler.Text.Range range FSharp.Compiler.SyntaxTree+SynExpr+InterpolatedString: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTree+SynInterpolatedStringPart] contents FSharp.Compiler.SyntaxTree+SynExpr+InterpolatedString: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTree+SynInterpolatedStringPart] get_contents() +FSharp.Compiler.SyntaxTree+SynExpr+InterpolatedString: SynStringKind get_synStringKind() +FSharp.Compiler.SyntaxTree+SynExpr+InterpolatedString: SynStringKind synStringKind FSharp.Compiler.SyntaxTree+SynExpr+JoinIn: FSharp.Compiler.Text.Range get_lhsRange() FSharp.Compiler.SyntaxTree+SynExpr+JoinIn: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.SyntaxTree+SynExpr+JoinIn: FSharp.Compiler.Text.Range lhsRange @@ -7652,7 +7654,7 @@ FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewIfThenElse(SynExpr, SynExpr, Micr FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewImplicitZero(FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewInferredDowncast(SynExpr, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewInferredUpcast(SynExpr, FSharp.Compiler.Text.Range) -FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewInterpolatedString(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTree+SynInterpolatedStringPart], FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewInterpolatedString(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTree+SynInterpolatedStringPart], SynStringKind, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewJoinIn(SynExpr, FSharp.Compiler.Text.Range, SynExpr, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewLambda(Boolean, Boolean, SynSimplePats, SynExpr, Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTree+SynPat],FSharp.Compiler.SyntaxTree+SynExpr]], FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewLazy(SynExpr, FSharp.Compiler.Text.Range) diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index fa3f8a7a203..fe957fb4317 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -290,7 +290,7 @@ module SyntaxExpressions = failwith "Could not find SynExpr.Do" module Strings = - let getBindingConstValue (parseResults: ParsedInput option) = + let getBindingExpressionValue (parseResults: ParsedInput option) = parseResults |> Option.bind (fun tree -> @@ -314,15 +314,20 @@ module Strings = _, _, _, - SynPat.Named (ident = ident), + SynPat.Named _, _, - SynExpr.Const (c, _), + e, _, - _) -> Some c + _) -> Some e | _ -> None) | _ -> None)) | _ -> None) + let getBindingConstValue parseResults = + match getBindingExpressionValue parseResults with + | Some (SynExpr.Const(c,_)) -> Some c + | _ -> None + [] let ``SynConst.String with SynStringKind.Regular`` () = let parseResults = @@ -382,3 +387,27 @@ let bytes = @"yo"B match getBindingConstValue parseResults with | Some (SynConst.Bytes (_, kind, _)) -> kind |> should equal SynByteStringKind.Verbatim | _ -> failwithf "Couldn't find const" + + [] + let ``SynExpr.InterpolatedString with SynStringKind.TripleQuote`` () = + let parseResults = + getParseResults + " + let s = $\"\"\"yo {42}\"\"\" + " + + match getBindingExpressionValue parseResults with + | Some (SynExpr.InterpolatedString(_, kind, _)) -> kind |> should equal SynStringKind.TripleQuote + | _ -> failwithf "Couldn't find const" + + [] + let ``SynExpr.InterpolatedString with SynStringKind.Regular`` () = + let parseResults = + getParseResults + """ + let s = $"yo {42}" + """ + + match getBindingExpressionValue parseResults with + | Some (SynExpr.InterpolatedString(_, kind, _)) -> kind |> should equal SynStringKind.Regular + | _ -> failwithf "Couldn't find const" \ No newline at end of file From f28a7963622757870ee1c32636ba44c551b3a6d6 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 2 Feb 2021 08:35:07 +0100 Subject: [PATCH 9/9] Replace booleans with SynStringKind / SynByteStringKind. --- src/fsharp/lex.fsl | 29 +++++++++++++------ src/fsharp/lexhelp.fs | 26 +++++++++++++---- src/fsharp/pars.fsy | 44 +++++++++++++---------------- src/fsharp/service/ServiceLexing.fs | 9 +++--- 4 files changed, 65 insertions(+), 43 deletions(-) diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index d15f70c1d29..e48cb044552 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -143,22 +143,28 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = let isVerbatim = context.HasFlag(LexerStringFinisherContext.Verbatim) let isTripleQuote = context.HasFlag(LexerStringFinisherContext.TripleQuote) - if kind.IsByteString then + if kind.IsByteString then + let synByteStringKind = if isVerbatim then SynByteStringKind.Verbatim else SynByteStringKind.Regular if kind.IsInterpolated then fail args lexbuf (FSComp.SR.lexByteStringMayNotBeInterpolated()) () - BYTEARRAY (Lexhelp.stringBufferAsBytes buf, isVerbatim, cont) + BYTEARRAY (Lexhelp.stringBufferAsBytes buf, synByteStringKind, cont) elif Lexhelp.stringBufferIsBytes buf then - BYTEARRAY (Lexhelp.stringBufferAsBytes buf, isVerbatim, cont) + BYTEARRAY (Lexhelp.stringBufferAsBytes buf, synByteStringKind, cont) else fail args lexbuf (FSComp.SR.lexByteArrayCannotEncode()) () - BYTEARRAY (Lexhelp.stringBufferAsBytes buf, isVerbatim, cont) + BYTEARRAY (Lexhelp.stringBufferAsBytes buf, synByteStringKind, cont) elif kind.IsInterpolated then let s = Lexhelp.stringBufferAsString buf - if kind.IsInterpolatedFirst then + if kind.IsInterpolatedFirst then + let synStringKind = + if isTripleQuote then + SynStringKind.TripleQuote + else + SynStringKind.Regular if isPart then - INTERP_STRING_BEGIN_PART (s, isTripleQuote, cont) + INTERP_STRING_BEGIN_PART (s, synStringKind, cont) else - INTERP_STRING_BEGIN_END (s, isTripleQuote, cont) + INTERP_STRING_BEGIN_END (s, synStringKind, cont) else if isPart then INTERP_STRING_PART (s, cont) @@ -166,7 +172,14 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) = INTERP_STRING_END (s, cont) else let s = Lexhelp.stringBufferAsString buf - STRING (s, isVerbatim, isTripleQuote, cont)) + let synStringKind = + if isVerbatim then + SynStringKind.Verbatim + elif isTripleQuote then + SynStringKind.TripleQuote + else + SynStringKind.Regular + STRING (s, synStringKind, cont)) buf,fin,m diff --git a/src/fsharp/lexhelp.fs b/src/fsharp/lexhelp.fs index 3810ed596be..fe86184e0eb 100644 --- a/src/fsharp/lexhelp.fs +++ b/src/fsharp/lexhelp.fs @@ -18,6 +18,7 @@ open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.SourceCodeServices.PrettyNaming open FSharp.Compiler.Text open FSharp.Compiler.Text.Range +open FSharp.Compiler.SyntaxTree /// The "mock" filename used by fsi.exe when reading from stdin. /// Has special treatment by the lexer, i.e. __SOURCE_DIRECTORY__ becomes GetCurrentDirectory() @@ -140,20 +141,33 @@ type LexerStringFinisher = if kind.IsInterpolated then let s = stringBufferAsString buf - if kind.IsInterpolatedFirst then + if kind.IsInterpolatedFirst then + let synStringKind = + if isTripleQuote then + SynStringKind.TripleQuote + else + SynStringKind.Regular if isPart then - INTERP_STRING_BEGIN_PART (s, isTripleQuote, cont) + INTERP_STRING_BEGIN_PART (s, synStringKind, cont) else - INTERP_STRING_BEGIN_END (s, isTripleQuote, cont) + INTERP_STRING_BEGIN_END (s, synStringKind, cont) else if isPart then INTERP_STRING_PART (s, cont) else INTERP_STRING_END (s, cont) - elif kind.IsByteString then - BYTEARRAY (stringBufferAsBytes buf, isVerbatim, cont) + elif kind.IsByteString then + let synByteStringKind = if isVerbatim then SynByteStringKind.Verbatim else SynByteStringKind.Regular + BYTEARRAY (stringBufferAsBytes buf, synByteStringKind, cont) else - STRING (stringBufferAsString buf, isVerbatim, isTripleQuote, cont) + let synStringKind = + if isVerbatim then + SynStringKind.Verbatim + elif isTripleQuote then + SynStringKind.TripleQuote + else + SynStringKind.Regular + STRING (stringBufferAsString buf, synStringKind, cont) ) let addUnicodeString (buf: ByteBuffer) (x:string) = diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index 2b037f7e811..ef216619d09 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -195,10 +195,10 @@ let rangeOfLongIdent(lid:LongIdent) = %} // Producing these changes the lex state, e.g. string --> token, or nesting level of braces in interpolated strings -%token BYTEARRAY -%token STRING -%token INTERP_STRING_BEGIN_END -%token INTERP_STRING_BEGIN_PART +%token BYTEARRAY +%token STRING +%token INTERP_STRING_BEGIN_END +%token INTERP_STRING_BEGIN_PART %token INTERP_STRING_PART %token INTERP_STRING_END %token LBRACE RBRACE @@ -647,7 +647,7 @@ hashDirectiveArgs: /* One argument to a #directive */ hashDirectiveArg: | stringOrKeywordString - { let s, _, _ = $1 + { let s, _ = $1 s } @@ -2241,7 +2241,7 @@ inlineAssemblyTyconRepr: | HASH stringOrKeywordString HASH { libraryOnlyError (lhs parseState) let lhsm = lhs parseState - let s, _, _ = $2 + let s, _ = $2 let ilType = ParseAssemblyCodeType s parseState.LexBuffer.SupportsFeature (rhs parseState 2) SynTypeDefnSimpleRepr.LibraryOnlyILAssembly (box ilType, lhsm) } @@ -2911,16 +2911,11 @@ rawConstant: { SynConst.UserNum $1 } | stringOrKeywordString - { let s, isVerbatim, isTripleQuote = $1 - let synStringKind = - if isVerbatim then SynStringKind.Verbatim - elif isTripleQuote then SynStringKind.TripleQuote - else SynStringKind.Regular + { let s, synStringKind = $1 SynConst.String (s, synStringKind, lhs parseState) } | BYTEARRAY - { let (v, isVerbatim, _) = $1 - let synByteStringKind = if isVerbatim then SynByteStringKind.Verbatim else SynByteStringKind.Regular + { let (v, synByteStringKind, _) = $1 SynConst.Bytes (v, synByteStringKind, lhs parseState) } rationalConstant: @@ -4255,8 +4250,7 @@ atomicExprAfterType: { $1 } | interpolatedString - { let parts, isTripleQuote = $1 - let synStringKind = if isTripleQuote then SynStringKind.TripleQuote else SynStringKind.Regular + { let parts, synStringKind = $1 SynExpr.InterpolatedString(parts, synStringKind, rhs parseState 1) } | NULL @@ -4502,7 +4496,7 @@ forLoopDirection: inlineAssemblyExpr: | HASH stringOrKeywordString opt_inlineAssemblyTypeArg optCurriedArgExprs optInlineAssemblyReturnTypes HASH { libraryOnlyWarning (lhs parseState) - let (s, _, _), sm = $2, rhs parseState 2 + let (s, _), sm = $2, rhs parseState 2 (fun m -> let ilInstrs = ParseAssemblyCodeInstructions s parseState.LexBuffer.SupportsFeature sm SynExpr.LibraryOnlyILAssembly (box ilInstrs, $3, List.rev $4, $5, m)) } @@ -5540,9 +5534,9 @@ colonOrEquals: /* A literal string or a string from a keyword like __SOURCE_FILE__ */ stringOrKeywordString: | STRING - { let (s, isVerbatim, isTripleQuote, _) = $1 - s, isVerbatim, isTripleQuote } - | KEYWORD_STRING { $1, false, false } + { let (s, synStringKind, _) = $1 + s, synStringKind } + | KEYWORD_STRING { $1, SynStringKind.Regular } interpolatedStringFill: | declExpr @@ -5570,20 +5564,20 @@ interpolatedStringParts: /* INTERP_STRING_BEGIN_PART int32 INTERP_STRING_PART int32 INTERP_STRING_END */ interpolatedString: | INTERP_STRING_BEGIN_PART interpolatedStringFill interpolatedStringParts - { let s, isTripleQuote, _ = $1 - SynInterpolatedStringPart.String (s, rhs parseState 1) :: SynInterpolatedStringPart.FillExpr $2 :: $3, isTripleQuote } + { let s, synStringKind, _ = $1 + SynInterpolatedStringPart.String (s, rhs parseState 1) :: SynInterpolatedStringPart.FillExpr $2 :: $3, synStringKind } | INTERP_STRING_BEGIN_END - { let s, isTripleQuote, _ = $1 - [ SynInterpolatedStringPart.String (s, rhs parseState 1) ], isTripleQuote } + { let s, synStringKind, _ = $1 + [ SynInterpolatedStringPart.String (s, rhs parseState 1) ], synStringKind } | INTERP_STRING_BEGIN_PART interpolatedStringParts { - let s, isTripleQuote, _ = $1 + let s, synStringKind, _ = $1 let rbrace = parseState.InputEndPosition 1 let lbrace = parseState.InputStartPosition 2 reportParseErrorAt (mkSynRange rbrace lbrace) (FSComp.SR.parsEmptyFillInInterpolatedString()) - SynInterpolatedStringPart.String (s, rhs parseState 1) :: $2, isTripleQuote } + SynInterpolatedStringPart.String (s, rhs parseState 1) :: $2, synStringKind } opt_HIGH_PRECEDENCE_APP: | HIGH_PRECEDENCE_BRACK_APP { } diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs index a828eac55bf..6747a94ee82 100755 --- a/src/fsharp/service/ServiceLexing.fs +++ b/src/fsharp/service/ServiceLexing.fs @@ -24,6 +24,7 @@ open FSharp.Compiler.SourceCodeServices open FSharp.Compiler.Text open FSharp.Compiler.Text.Pos open FSharp.Compiler.Text.Range +open FSharp.Compiler.SyntaxTree open Internal.Utilities @@ -34,12 +35,12 @@ type Positions = Position * Position module FSharpTokenTag = let Identifier = tagOfToken (IDENT "a") - let String = tagOfToken (STRING ("a", false, false, LexCont.Default)) + let String = tagOfToken (STRING ("a", SynStringKind.Regular, LexCont.Default)) let IDENT = tagOfToken (IDENT "a") let STRING = String - let INTERP_STRING_BEGIN_END = tagOfToken (INTERP_STRING_BEGIN_END ("a", false, LexCont.Default)) - let INTERP_STRING_BEGIN_PART = tagOfToken (INTERP_STRING_BEGIN_PART ("a", false, LexCont.Default)) + let INTERP_STRING_BEGIN_END = tagOfToken (INTERP_STRING_BEGIN_END ("a", SynStringKind.Regular, LexCont.Default)) + let INTERP_STRING_BEGIN_PART = tagOfToken (INTERP_STRING_BEGIN_PART ("a", SynStringKind.Regular, LexCont.Default)) let INTERP_STRING_PART = tagOfToken (INTERP_STRING_PART ("a", LexCont.Default)) let INTERP_STRING_END = tagOfToken (INTERP_STRING_END ("a", LexCont.Default)) let LPAREN = tagOfToken LPAREN @@ -386,7 +387,7 @@ module internal LexerStateEncoding = | LBRACE cont | RBRACE cont | BYTEARRAY (_, _, cont) - | STRING (_, _, _, cont) -> cont + | STRING (_, _, cont) -> cont | _ -> prevLexcont // Note that this will discard all lexcont state, including the ifdefStack.