Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
dotNET Platform
fsharp
提交
4cc8ca3f
F
fsharp
项目概览
dotNET Platform
/
fsharp
12 个月 前同步成功
通知
0
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
fsharp
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
4cc8ca3f
编写于
10月 18, 2019
作者:
B
Brett V. Forsgren
提交者:
GitHub
10月 18, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
allow fsi evaluations to be cancelled (#7736)
上级
e6309b0b
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
49 addition
and
18 deletion
+49
-18
src/fsharp/FSharp.Compiler.Private.Scripting/FSharpScript.fs
src/fsharp/FSharp.Compiler.Private.Scripting/FSharpScript.fs
+4
-2
src/fsharp/fsi/fsi.fs
src/fsharp/fsi/fsi.fs
+17
-14
src/fsharp/fsi/fsi.fsi
src/fsharp/fsi/fsi.fsi
+3
-2
tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs
...Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs
+25
-0
未找到文件。
src/fsharp/FSharp.Compiler.Private.Scripting/FSharpScript.fs
浏览文件 @
4cc8ca3f
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
namespace
FSharp
.
Compiler
.
Scripting
namespace
FSharp
.
Compiler
.
Scripting
open
System
open
System
open
System
.
Threading
open
FSharp
.
Compiler
.
Interactive
.
Shell
open
FSharp
.
Compiler
.
Interactive
.
Shell
type
FSharpScript
(?
captureInput
:
bool
,
?
captureOutput
:
bool
,
?
additionalArgs
:
string
[]
)
as
this
=
type
FSharpScript
(?
captureInput
:
bool
,
?
captureOutput
:
bool
,
?
additionalArgs
:
string
[]
)
as
this
=
...
@@ -42,8 +43,9 @@ type FSharpScript(?captureInput: bool, ?captureOutput: bool, ?additionalArgs: st
...
@@ -42,8 +43,9 @@ type FSharpScript(?captureInput: bool, ?captureOutput: bool, ?additionalArgs: st
member
__.
ErrorProduced
=
errorProduced
.
Publish
member
__.
ErrorProduced
=
errorProduced
.
Publish
member
__.
Eval
(
code
:
string
)
=
member
__.
Eval
(
code
:
string
,
?
cancellationToken
:
CancellationToken
)
=
let
ch
,
errors
=
fsi
.
EvalInteractionNonThrowing
code
let
cancellationToken
=
defaultArg
cancellationToken
CancellationToken
.
None
let
ch
,
errors
=
fsi
.
EvalInteractionNonThrowing
(
code
,
cancellationToken
)
match
ch
with
match
ch
with
|
Choice1Of2
v
->
Ok
(
v
),
errors
|
Choice1Of2
v
->
Ok
(
v
),
errors
|
Choice2Of2
ex
->
Error
(
ex
),
errors
|
Choice2Of2
ex
->
Error
(
ex
),
errors
...
...
src/fsharp/fsi/fsi.fs
浏览文件 @
4cc8ca3f
...
@@ -1888,7 +1888,8 @@ type internal FsiInteractionProcessor
...
@@ -1888,7 +1888,8 @@ type internal FsiInteractionProcessor
///
///
/// #directive comes through with other definitions as a SynModuleDecl.HashDirective.
/// #directive comes through with other definitions as a SynModuleDecl.HashDirective.
/// We split these out for individual processing.
/// We split these out for individual processing.
let
rec
execParsedInteractions
(
ctok
,
tcConfig
,
istate
,
action
,
errorLogger
:
ErrorLogger
,
lastResult
:
option
<
FsiInteractionStepStatus
>)
=
let
rec
execParsedInteractions
(
ctok
,
tcConfig
,
istate
,
action
,
errorLogger
:
ErrorLogger
,
lastResult
:
option
<
FsiInteractionStepStatus
>,
cancellationToken
:
CancellationToken
)
=
cancellationToken
.
ThrowIfCancellationRequested
()
let
action
,
nextAction
,
istate
=
let
action
,
nextAction
,
istate
=
match
action
with
match
action
with
|
None
->
None
,
None
,
istate
|
None
->
None
,
None
,
istate
...
@@ -1935,7 +1936,7 @@ type internal FsiInteractionProcessor
...
@@ -1935,7 +1936,7 @@ type internal FsiInteractionProcessor
|
Some
action
,
_
->
|
Some
action
,
_
->
let
istate
,
cont
=
ExecInteraction
(
ctok
,
tcConfig
,
istate
,
action
,
errorLogger
)
let
istate
,
cont
=
ExecInteraction
(
ctok
,
tcConfig
,
istate
,
action
,
errorLogger
)
match
cont
with
match
cont
with
|
Completed
_
->
execParsedInteractions
(
ctok
,
tcConfig
,
istate
,
nextAction
,
errorLogger
,
Some
cont
)
|
Completed
_
->
execParsedInteractions
(
ctok
,
tcConfig
,
istate
,
nextAction
,
errorLogger
,
Some
cont
,
cancellationToken
)
|
CompletedWithReportedError
e
->
istate
,
CompletedWithReportedError
e
(* drop nextAction on error *)
|
CompletedWithReportedError
e
->
istate
,
CompletedWithReportedError
e
(* drop nextAction on error *)
|
EndOfFile
->
istate
,
defaultArg
lastResult
(
Completed
None
)
(* drop nextAction on EOF *)
|
EndOfFile
->
istate
,
defaultArg
lastResult
(
Completed
None
)
(* drop nextAction on EOF *)
|
CtrlC
->
istate
,
CtrlC
(* drop nextAction on CtrlC *)
|
CtrlC
->
istate
,
CtrlC
(* drop nextAction on CtrlC *)
...
@@ -1962,9 +1963,9 @@ type internal FsiInteractionProcessor
...
@@ -1962,9 +1963,9 @@ type internal FsiInteractionProcessor
stopProcessingRecovery
e
range0
;
stopProcessingRecovery
e
range0
;
istate
,
CompletedWithReportedError
e
istate
,
CompletedWithReportedError
e
let
mainThreadProcessParsedInteractions
ctok
errorLogger
(
action
,
istate
)
=
let
mainThreadProcessParsedInteractions
ctok
errorLogger
(
action
,
istate
)
cancellationToken
=
istate
|>
mainThreadProcessAction
ctok
(
fun
ctok
tcConfig
istate
->
istate
|>
mainThreadProcessAction
ctok
(
fun
ctok
tcConfig
istate
->
execParsedInteractions
(
ctok
,
tcConfig
,
istate
,
action
,
errorLogger
,
None
))
execParsedInteractions
(
ctok
,
tcConfig
,
istate
,
action
,
errorLogger
,
None
,
cancellationToken
))
let
parseExpression
(
tokenizer
:
LexFilter
.
LexFilter
)
=
let
parseExpression
(
tokenizer
:
LexFilter
.
LexFilter
)
=
reusingLexbufForParsing
tokenizer
.
LexBuffer
(
fun
()
->
reusingLexbufForParsing
tokenizer
.
LexBuffer
(
fun
()
->
...
@@ -1997,8 +1998,8 @@ type internal FsiInteractionProcessor
...
@@ -1997,8 +1998,8 @@ type internal FsiInteractionProcessor
/// During processing of startup scripts, this runs on the main thread.
/// During processing of startup scripts, this runs on the main thread.
///
///
/// This is blocking: it reads until one chunk of input have been received, unless IsPastEndOfStream is true
/// This is blocking: it reads until one chunk of input have been received, unless IsPastEndOfStream is true
member
__.
ParseAndExecOneSetOfInteractionsFromLexbuf
(
runCodeOnMainThread
,
istate
:
FsiDynamicCompilerState
,
tokenizer
:
LexFilter
.
LexFilter
,
errorLogger
)
=
member
__.
ParseAndExecOneSetOfInteractionsFromLexbuf
(
runCodeOnMainThread
,
istate
:
FsiDynamicCompilerState
,
tokenizer
:
LexFilter
.
LexFilter
,
errorLogger
,
?
cancellationToken
:
CancellationToken
)
=
let
cancellationToken
=
defaultArg
cancellationToken
CancellationToken
.
None
if
tokenizer
.
LexBuffer
.
IsPastEndOfStream
then
if
tokenizer
.
LexBuffer
.
IsPastEndOfStream
then
let
stepStatus
=
let
stepStatus
=
if
fsiInterruptController
.
FsiInterruptStdinState
=
StdinEOFPermittedBecauseCtrlCRecentlyPressed
then
if
fsiInterruptController
.
FsiInterruptStdinState
=
StdinEOFPermittedBecauseCtrlCRecentlyPressed
then
...
@@ -2022,7 +2023,7 @@ type internal FsiInteractionProcessor
...
@@ -2022,7 +2023,7 @@ type internal FsiInteractionProcessor
// After we've unblocked and got something to run we switch
// After we've unblocked and got something to run we switch
// over to the run-thread (e.g. the GUI thread)
// over to the run-thread (e.g. the GUI thread)
let
res
=
istate
|>
runCodeOnMainThread
(
fun
ctok
istate
->
mainThreadProcessParsedInteractions
ctok
errorLogger
(
action
,
istate
)
)
let
res
=
istate
|>
runCodeOnMainThread
(
fun
ctok
istate
->
mainThreadProcessParsedInteractions
ctok
errorLogger
(
action
,
istate
)
cancellationToken
)
if
!
progress
then
fprintfn
fsiConsoleOutput
.
Out
"Just called runCodeOnMainThread, res = %O..."
res
;
if
!
progress
then
fprintfn
fsiConsoleOutput
.
Out
"Just called runCodeOnMainThread, res = %O..."
res
;
res
)
res
)
...
@@ -2093,7 +2094,8 @@ type internal FsiInteractionProcessor
...
@@ -2093,7 +2094,8 @@ type internal FsiInteractionProcessor
member
__.
LoadDummyInteraction
(
ctok
,
errorLogger
)
=
member
__.
LoadDummyInteraction
(
ctok
,
errorLogger
)
=
setCurrState
(
currState
|>
InteractiveCatch
errorLogger
(
fun
istate
->
fsiDynamicCompiler
.
EvalParsedDefinitions
(
ctok
,
errorLogger
,
istate
,
true
,
false
,
[]
)
|>
fst
,
Completed
None
)
|>
fst
)
setCurrState
(
currState
|>
InteractiveCatch
errorLogger
(
fun
istate
->
fsiDynamicCompiler
.
EvalParsedDefinitions
(
ctok
,
errorLogger
,
istate
,
true
,
false
,
[]
)
|>
fst
,
Completed
None
)
|>
fst
)
member
__.
EvalInteraction
(
ctok
,
sourceText
,
scriptFileName
,
errorLogger
)
=
member
__.
EvalInteraction
(
ctok
,
sourceText
,
scriptFileName
,
errorLogger
,
?
cancellationToken
)
=
let
cancellationToken
=
defaultArg
cancellationToken
CancellationToken
.
None
use
_
unwind1
=
ErrorLogger
.
PushThreadBuildPhaseUntilUnwind
(
ErrorLogger
.
BuildPhase
.
Interactive
)
use
_
unwind1
=
ErrorLogger
.
PushThreadBuildPhaseUntilUnwind
(
ErrorLogger
.
BuildPhase
.
Interactive
)
use
_
unwind2
=
ErrorLogger
.
PushErrorLoggerPhaseUntilUnwind
(
fun
_
->
errorLogger
)
use
_
unwind2
=
ErrorLogger
.
PushErrorLoggerPhaseUntilUnwind
(
fun
_
->
errorLogger
)
use
_
scope
=
SetCurrentUICultureForThread
fsiOptions
.
FsiLCID
use
_
scope
=
SetCurrentUICultureForThread
fsiOptions
.
FsiLCID
...
@@ -2102,7 +2104,7 @@ type internal FsiInteractionProcessor
...
@@ -2102,7 +2104,7 @@ type internal FsiInteractionProcessor
currState
currState
|>
InteractiveCatch
errorLogger
(
fun
istate
->
|>
InteractiveCatch
errorLogger
(
fun
istate
->
let
expr
=
ParseInteraction
tokenizer
let
expr
=
ParseInteraction
tokenizer
mainThreadProcessParsedInteractions
ctok
errorLogger
(
expr
,
istate
)
)
mainThreadProcessParsedInteractions
ctok
errorLogger
(
expr
,
istate
)
cancellationToken
)
|>
commitResult
|>
commitResult
member
this
.
EvalScript
(
ctok
,
scriptPath
,
errorLogger
)
=
member
this
.
EvalScript
(
ctok
,
scriptPath
,
errorLogger
)
=
...
@@ -2592,25 +2594,26 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i
...
@@ -2592,25 +2594,26 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i
fsiInteractionProcessor
.
EvalExpression
(
ctok
,
sourceText
,
dummyScriptFileName
,
errorLogger
)
fsiInteractionProcessor
.
EvalExpression
(
ctok
,
sourceText
,
dummyScriptFileName
,
errorLogger
)
|>
commitResultNonThrowing
errorOptions
dummyScriptFileName
errorLogger
|>
commitResultNonThrowing
errorOptions
dummyScriptFileName
errorLogger
member
x
.
EvalInteraction
(
sourceText
)
:
unit
=
member
x
.
EvalInteraction
(
sourceText
,
?
cancellationToken
)
:
unit
=
// Explanation: When the user of the FsiInteractiveSession object calls this method, the
// Explanation: When the user of the FsiInteractiveSession object calls this method, the
// code is parsed, checked and evaluated on the calling thread. This means EvalExpression
// code is parsed, checked and evaluated on the calling thread. This means EvalExpression
// is not safe to call concurrently.
// is not safe to call concurrently.
let
ctok
=
AssumeCompilationThreadWithoutEvidence
()
let
ctok
=
AssumeCompilationThreadWithoutEvidence
()
let
cancellationToken
=
defaultArg
cancellationToken
CancellationToken
.
None
fsiInteractionProcessor
.
EvalInteraction
(
ctok
,
sourceText
,
dummyScriptFileName
,
errorLogger
)
fsiInteractionProcessor
.
EvalInteraction
(
ctok
,
sourceText
,
dummyScriptFileName
,
errorLogger
,
cancellationToken
)
|>
commitResult
|>
commitResult
|>
ignore
|>
ignore
member
x
.
EvalInteractionNonThrowing
(
sourceText
)
=
member
x
.
EvalInteractionNonThrowing
(
sourceText
,
?
cancellationToken
)
=
// Explanation: When the user of the FsiInteractiveSession object calls this method, the
// Explanation: When the user of the FsiInteractiveSession object calls this method, the
// code is parsed, checked and evaluated on the calling thread. This means EvalExpression
// code is parsed, checked and evaluated on the calling thread. This means EvalExpression
// is not safe to call concurrently.
// is not safe to call concurrently.
let
ctok
=
AssumeCompilationThreadWithoutEvidence
()
let
ctok
=
AssumeCompilationThreadWithoutEvidence
()
let
cancellationToken
=
defaultArg
cancellationToken
CancellationToken
.
None
let
errorOptions
=
TcConfig
.
Create
(
tcConfigB
,
validate
=
false
).
errorSeverityOptions
let
errorOptions
=
TcConfig
.
Create
(
tcConfigB
,
validate
=
false
).
errorSeverityOptions
let
errorLogger
=
CompilationErrorLogger
(
"EvalInteraction"
,
errorOptions
)
let
errorLogger
=
CompilationErrorLogger
(
"EvalInteraction"
,
errorOptions
)
fsiInteractionProcessor
.
EvalInteraction
(
ctok
,
sourceText
,
dummyScriptFileName
,
errorLogger
)
fsiInteractionProcessor
.
EvalInteraction
(
ctok
,
sourceText
,
dummyScriptFileName
,
errorLogger
,
cancellationToken
)
|>
commitResultNonThrowing
errorOptions
"input.fsx"
errorLogger
|>
commitResultNonThrowing
errorOptions
"input.fsx"
errorLogger
member
x
.
EvalScript
(
scriptPath
)
:
unit
=
member
x
.
EvalScript
(
scriptPath
)
:
unit
=
...
...
src/fsharp/fsi/fsi.fsi
浏览文件 @
4cc8ca3f
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
module
public
FSharp
.
Compiler
.
Interactive
.
Shell
module
public
FSharp
.
Compiler
.
Interactive
.
Shell
open
System
.
IO
open
System
.
IO
open
System
.
Threading
open
FSharp
.
Compiler
open
FSharp
.
Compiler
open
FSharp
.
Compiler
.
SourceCodeServices
open
FSharp
.
Compiler
.
SourceCodeServices
...
@@ -146,7 +147,7 @@ type FsiEvaluationSession =
...
@@ -146,7 +147,7 @@ type FsiEvaluationSession =
///
///
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
/// by input from 'stdin'.
/// by input from 'stdin'.
member
EvalInteraction
:
code
:
string
->
unit
member
EvalInteraction
:
code
:
string
*
?
cancellationToken
:
CancellationToken
->
unit
/// Execute the code as if it had been entered as one or more interactions, with an
/// Execute the code as if it had been entered as one or more interactions, with an
/// implicit termination at the end of the input. Stop on first error, discarding the rest
/// implicit termination at the end of the input. Stop on first error, discarding the rest
...
@@ -155,7 +156,7 @@ type FsiEvaluationSession =
...
@@ -155,7 +156,7 @@ type FsiEvaluationSession =
///
///
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
/// Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered
/// by input from 'stdin'.
/// by input from 'stdin'.
member
EvalInteractionNonThrowing
:
code
:
string
->
Choice
<
FsiValue
option
,
exn
>
*
FSharpErrorInfo
[]
member
EvalInteractionNonThrowing
:
code
:
string
*
?
cancellationToken
:
CancellationToken
->
Choice
<
FsiValue
option
,
exn
>
*
FSharpErrorInfo
[]
/// Execute the given script. Stop on first error, discarding the rest
/// Execute the given script. Stop on first error, discarding the rest
/// of the script. Errors are sent to the output writer, a 'true' return value indicates there
/// of the script. Errors are sent to the output writer, a 'true' return value indicates there
...
...
tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs
浏览文件 @
4cc8ca3f
...
@@ -3,8 +3,10 @@
...
@@ -3,8 +3,10 @@
namespace
FSharp
.
Compiler
.
Scripting
.
UnitTests
namespace
FSharp
.
Compiler
.
Scripting
.
UnitTests
open
System
open
System
open
System
.
Diagnostics
open
System
.
IO
open
System
.
IO
open
System
.
Threading
open
System
.
Threading
open
System
.
Threading
.
Tasks
open
FSharp
.
Compiler
.
Interactive
.
Shell
open
FSharp
.
Compiler
.
Interactive
.
Shell
open
FSharp
.
Compiler
.
Scripting
open
FSharp
.
Compiler
.
Scripting
open
FSharp
.
Compiler
.
SourceCodeServices
open
FSharp
.
Compiler
.
SourceCodeServices
...
@@ -107,3 +109,26 @@ type InteractiveTests() =
...
@@ -107,3 +109,26 @@ type InteractiveTests() =
match
result
with
match
result
with
|
Ok
(_)
->
Assert
.
Fail
(
"expected a failure"
)
|
Ok
(_)
->
Assert
.
Fail
(
"expected a failure"
)
|
Error
(
ex
)
->
Assert
.
IsInstanceOf
<
FileNotFoundException
>(
ex
)
|
Error
(
ex
)
->
Assert
.
IsInstanceOf
<
FileNotFoundException
>(
ex
)
[<
Test
>]
member
_.
``Evaluation can be cancelled``
()
=
use
script
=
new
FSharpScript
()
let
sleepTime
=
10000
let
mutable
result
=
None
let
mutable
wasCancelled
=
false
use
tokenSource
=
new
CancellationTokenSource
()
let
eval
()
=
try
result
<-
Some
(
script
.
Eval
(
sprintf
"System.Threading.Thread.Sleep(%d)
\n
2"
sleepTime
,
tokenSource
.
Token
))
// if execution gets here (which it shouldn't), the value `2` will be returned
with
|
:?
OperationCanceledException
->
wasCancelled
<-
true
let
sw
=
Stopwatch
.
StartNew
()
let
evalTask
=
Task
.
Run
(
eval
)
// cancel and wait for finish
tokenSource
.
Cancel
()
evalTask
.
GetAwaiter
()
.
GetResult
()
// ensure we cancelled and didn't complete the sleep or evaluation
Assert
.
True
(
wasCancelled
)
Assert
.
LessOrEqual
(
sw
.
ElapsedMilliseconds
,
sleepTime
)
Assert
.
AreEqual
(
None
,
result
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录