Skip to content

Commit d9c95ce

Browse files
authored
Type Checker Support
Type Checker
2 parents 775e903 + 8cc822e commit d9c95ce

File tree

16 files changed

+256
-113
lines changed

16 files changed

+256
-113
lines changed

YukimiScript.CodeGen.Lua/Lua.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ let generateLua (Intermediate scenes) : string =
4444
| Symbol "nil" -> "nil"
4545
| Symbol x -> "api." + x
4646
| Integer x -> string x
47-
| Number x -> string x
47+
| Real x -> string x
4848
| String x -> "\"" + Constants.string2literal x + "\"")
4949

5050
if not <| List.isEmpty args then

YukimiScript.CommandLineTool/Compile.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ let private findRepeat (items: (string * Elements.DebugInformation) seq) =
5252

5353
let checkRepeat errStringing (dom: Dom) =
5454
dom.Externs
55-
|> Seq.map (fun (Elements.ExternCommand (cmd, _), dbg) -> cmd, dbg)
55+
|> Seq.map (fun (Elements.ExternCommand (cmd, _), _, dbg) -> cmd, dbg)
5656
|> findRepeat
5757
|> Seq.tryHead
5858
|> function
@@ -74,7 +74,7 @@ let checkRepeat errStringing (dom: Dom) =
7474
|> unwrapDomException errStringing
7575

7676
dom.Macros
77-
|> Seq.map (fun (s, _, dbg) -> s.Name, dbg)
77+
|> Seq.map (fun (s, _, _, dbg) -> s.Name, dbg)
7878
|> findRepeat
7979
|> Seq.tryHead
8080
|> function

YukimiScript.Parser.Test/TestConstants.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ let testNumbers () =
3131

3232
for _ in 0 .. 16 do
3333
let i = float (rnd.Next()) + rnd.NextDouble()
34-
testConstant (string i) <| Number i
34+
testConstant (string i) <| Real i
3535
let j = -(float (rnd.Next()) + rnd.NextDouble())
36-
testConstant (string j) <| Number j
36+
testConstant (string j) <| Real j
3737

38-
testConstant "- 176.00" <| Number -176.0
38+
testConstant "- 176.00" <| Real -176.0
3939

4040

4141
[<Test>]

YukimiScript.Parser.Test/TestStatments.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ let testCommandCall () =
1616
Integer -256 ]
1717
NamedArgs =
1818
[ "effect", Symbol "a"
19-
"camera", Number -2.0 ] }
19+
"camera", Real -2.0 ] }

YukimiScript.Parser/Constants.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ let private numberParser, integerParser =
3333
do! literal "."
3434
let! b = unsignedIntegerString
3535

36-
return Number <| float (sign + a + "." + b)
36+
return Real <| float (sign + a + "." + b)
3737
}
3838
|> name "number"
3939

YukimiScript.Parser/Diagram.fs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ exception DiagramMacroErrorException of DebugInformation
2727
exception CannotFindSceneException of string
2828

2929

30-
let analyze (files: (string * Dom) list) : Result<Diagram> =
30+
let analyze (files: (string * Dom) list) : Result<Diagram, exn> =
3131
try
3232
let fileNodes, arrows =
3333
files
@@ -45,6 +45,10 @@ let analyze (files: (string * Dom) list) : Result<Diagram> =
4545
let p = { Parameter = "target"; Default = None }
4646

4747
matchArguments debug [ p ] c
48+
|> Result.bind (
49+
TypeChecker.checkApplyTypeCorrect
50+
debug
51+
[ "target", TypeChecker.Types.string ])
4852
|> function
4953
| Ok [ "target", (String target) ] -> Some target
5054
| Error e -> raise e

YukimiScript.Parser/Dom.fs

Lines changed: 80 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ namespace YukimiScript.Parser
22

33
open YukimiScript.Parser.Parser
44
open YukimiScript.Parser.Elements
5+
open YukimiScript.Parser.TypeChecker
56

67

78
type Dom =
89
{ HangingEmptyLine: DebugInformation list
9-
Externs: (ExternDefination * DebugInformation) list
10-
Macros: (MacroDefination * Block * DebugInformation) list
10+
Externs: (ExternDefination * BlockParamTypes * DebugInformation) list
11+
Macros: (MacroDefination * BlockParamTypes * Block * DebugInformation) list
1112
Scenes: (SceneDefination * Block * DebugInformation) list }
1213

1314

@@ -46,6 +47,9 @@ module Dom =
4647
exception ExternRepeatException of name: string * debugInfo: DebugInformation seq
4748

4849

50+
exception ExternCannotHasContentException of name: string * DebugInformation
51+
52+
4953
let private saveCurrentBlock state =
5054
match state.CurrentBlock with
5155
| None -> state
@@ -56,17 +60,33 @@ module Dom =
5660
Macros =
5761
match label with
5862
| MacroDefination x ->
59-
(x, List.rev block, debugInfo)
60-
:: state.Result.Macros
61-
| SceneDefination _ -> state.Result.Macros
62-
| _ -> raise UnknownException
63+
let block = List.rev block
64+
match Macro.parametersTypeFromBlock x.Param block with
65+
| Ok t -> (x, t, block, debugInfo) :: state.Result.Macros
66+
| Error e -> raise e
67+
| _ -> state.Result.Macros
6368
Scenes =
6469
match label with
65-
| MacroDefination _ -> state.Result.Scenes
6670
| SceneDefination x ->
6771
(x, List.rev block, debugInfo)
6872
:: state.Result.Scenes
69-
| _ -> raise UnknownException } }
73+
| _ -> state.Result.Scenes
74+
Externs =
75+
match label with
76+
| ExternDefination (ExternCommand (n, p)) ->
77+
if
78+
List.forall (fst >> function
79+
| CommandCall c when c.Callee = "__type" -> true
80+
| EmptyLine -> true
81+
| _ -> false) block
82+
then
83+
match Macro.parametersTypeFromBlock p block with
84+
| Ok t ->
85+
(ExternCommand (n, p), t, debugInfo)
86+
:: state.Result.Externs
87+
| Error e -> raise e
88+
else raise <| ExternCannotHasContentException (n, debugInfo)
89+
| _ -> state.Result.Externs} }
7090

7191

7292
let private analyzeFold state (line, debugInfo) =
@@ -98,75 +118,62 @@ module Dom =
98118
| Line.Text x -> pushOperation <| Text x
99119
| SceneDefination scene -> Ok <| setLabel state (SceneDefination scene)
100120
| MacroDefination macro -> Ok <| setLabel state (MacroDefination macro)
101-
| ExternDefination (ExternCommand (name, param)) ->
102-
let nextState = saveCurrentBlock state
103-
104-
{ nextState with
105-
Result =
106-
{ nextState.Result with
107-
Externs =
108-
(ExternCommand(name, param), debugInfo)
109-
:: nextState.Result.Externs } }
110-
|> Ok
121+
| ExternDefination extern' -> Ok <| setLabel state (ExternDefination extern')
111122

112123

113124
exception CannotDefineSceneInLibException of string
114125

115126

116-
let analyze (fileName: string) (x: Parsed seq) : Result<Dom> =
117-
let finalState =
118-
x
119-
|> Seq.indexed
120-
|> Seq.map
121-
(fun (lineNumber, { Line = line; Comment = comment }) ->
122-
line,
123-
{ LineNumber = lineNumber + 1
124-
Comment = comment
125-
File = fileName })
126-
|> Seq.fold
127-
(fun state x -> Result.bind (fun state -> analyzeFold state x) state)
128-
(Ok { Result = empty; CurrentBlock = None })
129-
|> Result.map saveCurrentBlock
130-
131-
finalState
132-
|> Result.map
133-
(fun x ->
134-
{ Scenes = List.rev x.Result.Scenes
135-
Macros = List.rev x.Result.Macros
136-
Externs = List.rev x.Result.Externs
137-
HangingEmptyLine = List.rev x.Result.HangingEmptyLine })
138-
127+
let analyze (fileName: string) (x: Parsed seq) : Result<Dom, exn> =
128+
try
129+
let finalState =
130+
x
131+
|> Seq.indexed
132+
|> Seq.map
133+
(fun (lineNumber, { Line = line; Comment = comment }) ->
134+
line,
135+
{ LineNumber = lineNumber + 1
136+
Comment = comment
137+
File = fileName })
138+
|> Seq.fold
139+
(fun state x -> Result.bind (fun state -> analyzeFold state x) state)
140+
(Ok { Result = empty; CurrentBlock = None })
141+
|> Result.map saveCurrentBlock
142+
143+
finalState
144+
|> Result.map
145+
(fun x ->
146+
{ Scenes = List.rev x.Result.Scenes
147+
Macros = List.rev x.Result.Macros
148+
Externs = List.rev x.Result.Externs
149+
HangingEmptyLine = List.rev x.Result.HangingEmptyLine })
150+
with e -> Error e
139151

140152
let expandTextCommands (x: Dom) : Dom =
141-
let mapBlock (defination, block, debugInfo) =
142-
let block =
143-
block
144-
|> List.collect
145-
(function
146-
| Text x, debugInfo ->
147-
[ if debugInfo.Comment.IsSome then
148-
EmptyLine, debugInfo
153+
let mapBlock =
154+
List.collect (function
155+
| Text x, debugInfo ->
156+
[ if debugInfo.Comment.IsSome then
157+
EmptyLine, debugInfo
149158

150-
yield! Text.expandTextBlock x debugInfo ]
151-
| x -> [ x ])
152-
153-
defination, block, debugInfo
159+
yield! Text.expandTextBlock x debugInfo ]
160+
| x -> [ x ])
154161

155162
{ x with
156-
Scenes = List.map mapBlock x.Scenes
157-
Macros = List.map mapBlock x.Macros }
163+
Scenes = List.map (fun (def, block, d) -> def, mapBlock block, d) x.Scenes
164+
Macros = List.map (fun (def, t, b, d) -> def, t, mapBlock b, d) x.Macros }
158165

159166

160167
let expandUserMacros (x: Dom) =
161168
let macros =
162-
List.map (fun (a, b, _) -> a, b) x.Macros
169+
List.map (fun (a, t, b, _) -> a, t, b) x.Macros
163170

164171
x.Scenes
165172
|> List.map
166173
(fun (sceneDef, block, debugInfo) ->
167174
Macro.expandBlock macros block
168175
|> Result.map (fun x -> sceneDef, x, debugInfo))
169-
|> ParserMonad.switchResultList
176+
|> ParserMonad.sequenceRL
170177
|> Result.map (fun scenes -> { x with Scenes = scenes })
171178

172179

@@ -183,51 +190,52 @@ module Dom =
183190
exception ExternCommandDefinationNotFoundException of string * DebugInformation
184191

185192

186-
let private systemCommands =
193+
let private systemCommands : (ExternDefination * BlockParamTypes) list =
187194
let parse str =
188195
TopLevels.topLevels
189196
|> ParserMonad.run str
190197
|> function
191198
| Ok (ExternDefination x) -> x
192199
| _ -> failwith "Bug here!"
193200

194-
[ parse "- extern __text_begin character=null"
195-
parse "- extern __text_type text"
196-
parse "- extern __text_pushMark mark"
197-
parse "- extern __text_popMark mark"
198-
parse "- extern __text_end hasMore" ]
199-
201+
[ parse "- extern __text_begin character=null", [ "character", Types.symbol ]
202+
parse "- extern __text_type text", [ "text", Types.string ]
203+
parse "- extern __text_pushMark mark", [ "mark", Types.symbol ]
204+
parse "- extern __text_popMark mark", [ "mark", Types.symbol ]
205+
parse "- extern __text_end hasMore", [ "hasMore", Types.symbol] ]
200206

201-
let linkToExternCommands (x: Dom) : Result<Dom> =
202-
let externs = systemCommands @ List.map fst x.Externs
203207

208+
let linkToExternCommands (x: Dom) : Result<Dom, exn> =
209+
let externs = systemCommands @ List.map (fun (x, t, _) -> x, t) x.Externs
210+
204211
let linkSingleCommand (op, debugInfo) =
205212
match op with
206213
| Text _ -> Error MustExpandTextBeforeLinkException
207214
| CommandCall c ->
208-
match List.tryFind (fun (ExternCommand (name, _)) -> name = c.Callee) externs with
215+
match List.tryFind (fun (ExternCommand (name, _), _) -> name = c.Callee) externs with
209216
| None ->
210217
Error
211218
<| ExternCommandDefinationNotFoundException(c.Callee, debugInfo)
212-
| Some (ExternCommand (_, param)) ->
219+
| Some (ExternCommand (_, param), t) ->
213220
Macro.matchArguments debugInfo param c
221+
|> Result.bind (checkApplyTypeCorrect debugInfo t)
214222
|> Result.map
215223
(fun args ->
216224
let args =
217225
List.map (fun { Parameter = param } -> List.find (fst >> (=) param) args |> snd) param
218226

219227
CommandCall
220228
{ c with
221-
UnnamedArgs = args
222-
NamedArgs = [] })
229+
UnnamedArgs = args
230+
NamedArgs = [] })
223231
| x -> Ok x
224232
|> Result.map (fun x -> x, debugInfo)
225233

226234
let linkToExternCommands (sceneDef, block, debugInfo) =
227235
List.map linkSingleCommand block
228-
|> ParserMonad.switchResultList
236+
|> ParserMonad.sequenceRL
229237
|> Result.map (fun block -> sceneDef, (block: Block), debugInfo)
230238

231239
List.map linkToExternCommands x.Scenes
232-
|> ParserMonad.switchResultList
240+
|> ParserMonad.sequenceRL
233241
|> Result.map (fun scenes -> { x with Scenes = scenes })

YukimiScript.Parser/EditorHelper.fs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ open YukimiScript.Parser
44
open YukimiScript.Parser.Elements
55

66

7-
type Runner<'State> = 'State -> CommandCall -> Result<'State>
7+
type Runner<'State> = 'State -> CommandCall -> Result<'State, exn>
88

99

10-
let rec run (state: 'State) (runner: Runner<'State>) (ops: Block) : Result<'State> =
10+
let rec run (state: 'State) (runner: Runner<'State>) (ops: Block) : Result<'State, exn> =
1111
match Seq.tryHead ops with
1212
| None -> Ok state
1313
| Some (EmptyLine, _) -> run state runner <| List.tail ops
@@ -30,6 +30,6 @@ let dispatch (dispatcher: CommandCall -> Runner<'State>) : Runner<'State> = fun
3030

3131

3232
type RunnerWrapper<'TState>(init: 'TState, mainRunner: Runner<'TState>) =
33-
member _.Run(state: 'TState, ops: Block) : Result<'TState> = run state mainRunner ops
33+
member _.Run(state: 'TState, ops: Block) : Result<'TState, exn> = run state mainRunner ops
3434

35-
member x.Run(ops: Block) : Result<'TState> = x.Run(init, ops)
35+
member x.Run(ops: Block) : Result<'TState, exn> = x.Run(init, ops)

YukimiScript.Parser/Elements.fs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
namespace YukimiScript.Parser.Elements
22

3-
open YukimiScript.Parser
4-
53

64
type Constant =
75
| String of string
8-
| Number of float
6+
| Real of float
97
| Integer of int32
108
| Symbol of string
119

@@ -76,12 +74,12 @@ module Operation =
7674
exception CanNotConvertToOperationException of Line
7775

7876

79-
let ofLine: Line -> Result<Operation> =
77+
let ofLine: Line -> Operation =
8078
function
81-
| Line.Text t -> Ok <| Text t
82-
| Line.CommandCall c -> Ok <| CommandCall c
83-
| Line.EmptyLine -> Ok <| EmptyLine
84-
| x -> Error <| CanNotConvertToOperationException x
79+
| Line.Text t -> Text t
80+
| Line.CommandCall c -> CommandCall c
81+
| Line.EmptyLine -> EmptyLine
82+
| x -> raise <| CanNotConvertToOperationException x
8583

8684

8785
type Block = (Operation * DebugInformation) list

YukimiScript.Parser/ErrorStringing.fs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ open YukimiScript.Parser.Macro
77
open YukimiScript.Parser.ParserMonad
88
open YukimiScript.Parser.TopLevels
99
open YukimiScript.Parser.Diagram
10+
open YukimiScript.Parser.TypeChecker
1011
open System.IO
1112

1213

@@ -21,6 +22,15 @@ let header (debug: Elements.DebugInformation) =
2122

2223
let schinese: ErrorStringing =
2324
function
25+
| TypeChecker.TypeCheckFailedException (d, i, ParameterType (name, _), a) ->
26+
header d
27+
+ "" + string (i + 1) + "个参数的类型应当为" + name + ",但传入了" +
28+
match a with
29+
| Int' -> "int"
30+
| Real' -> "real"
31+
| String' -> "string"
32+
| Symbol' -> "symbol"
33+
+ ""
2434
| InvalidSymbolException -> "非法符号。"
2535
| InvalidStringCharException x -> "字符串中存在非法字符\"" + x + "\""
2636
| HangingOperationException debug -> header debug + "存在悬浮操作。"

0 commit comments

Comments
 (0)