|
| 1 | +module YukimiScript.Parser.TypeChecker |
| 2 | + |
| 3 | +open YukimiScript.Parser.Elements |
| 4 | + |
| 5 | + |
| 6 | +type SimpleType = |
| 7 | + | Int' |
| 8 | + | Real' |
| 9 | + | String' |
| 10 | + | Symbol' |
| 11 | + |
| 12 | + |
| 13 | +type ParameterType = ParameterType of name: string * Set<SimpleType> |
| 14 | + |
| 15 | + |
| 16 | +module Types = |
| 17 | + let any = ParameterType ("any", set [ Int'; Real'; String'; Symbol' ]) |
| 18 | + let int = ParameterType ("int", set [ Int' ]) |
| 19 | + let number = ParameterType ("number", set [ Int'; Real' ]) |
| 20 | + let real = ParameterType ("real", set [ Real' ]) |
| 21 | + let symbol = ParameterType ("symbol", set [ Symbol' ]) |
| 22 | + let void' = ParameterType ("void", set []) |
| 23 | + let all = [ any; int; number; real; symbol; void' ] |
| 24 | + |
| 25 | + |
| 26 | +let sumParameterType (ParameterType (n1, s1)) (ParameterType (n2, s2)) = |
| 27 | + ParameterType (n1 + " | " + n2, Set.union s1 s2) |
| 28 | + |
| 29 | + |
| 30 | +let checkType = |
| 31 | + function |
| 32 | + | String _ -> String' |
| 33 | + | Integer _ -> Int' |
| 34 | + | Real _ -> Real' |
| 35 | + | Symbol _ -> Symbol' |
| 36 | + |
| 37 | + |
| 38 | +exception TypeCheckFailedException of DebugInformation * int * ParameterType * SimpleType |
| 39 | + |
| 40 | + |
| 41 | +let matchType d i (ParameterType (t, types)) (argType: SimpleType) : Result<unit, exn> = |
| 42 | + if Set.contains argType types |
| 43 | + then Ok () |
| 44 | + else Error <| TypeCheckFailedException (d, i, (ParameterType (t, types)), argType) |
| 45 | + |
| 46 | + |
| 47 | +let matchCallTypes d (pars: ParameterType list) (argType: SimpleType list) = |
| 48 | + List.zip pars argType |> List.mapi (fun i (a, b) -> matchType d i a b) |
| 49 | + |> ParserMonad.sequenceRL |> Result.map ignore |
| 50 | + |
| 51 | + |
| 52 | +let matchCall d (pars: ParameterType list) (argType: Constant list) = |
| 53 | + argType |> List.map checkType |> matchCallTypes d pars |
| 54 | + |
| 55 | + |
| 56 | +exception IsNotAType of string |
| 57 | + |
| 58 | + |
| 59 | +let parametersTypeFromBlock (par: Parameter list) (b: Block) = |
| 60 | + let typeMacroParams = |
| 61 | + [ { Parameter = "param"; Default = None } |
| 62 | + { Parameter = "type"; Default = None } ] |
| 63 | + |
| 64 | + List.choose (function |
| 65 | + | CommandCall c, d when c.Callee = "__type" -> Some (c, d) |
| 66 | + | _ -> None) b |
| 67 | + |> List.map (fun (c, d) -> Macro.matchArguments d typeMacroParams c) |
| 68 | + |> ParserMonad.sequenceRL |
| 69 | + |> Result.bind (fun x -> |
| 70 | + let paramTypePairs = |
| 71 | + List.map (readOnlyDict >> fun x -> |
| 72 | + match x["param"], x["type"] with |
| 73 | + | Symbol par, Symbol t -> par, t |
| 74 | + | _ -> failwith "parametersTypeFromBlock: failed!") x |
| 75 | + |
| 76 | + par |
| 77 | + |> List.map (fun { Parameter = name; Default = _ } -> |
| 78 | + paramTypePairs |
| 79 | + |> List.filter (fst >> (=) name) |
| 80 | + |> List.map snd |
| 81 | + |> function |
| 82 | + | [] -> Ok Types.any |
| 83 | + | types -> |
| 84 | + types |
| 85 | + |> List.map (fun typeName -> |
| 86 | + Types.all |
| 87 | + |> List.tryFind (fun (ParameterType (n, _)) -> n = typeName) |
| 88 | + |> function |
| 89 | + | Some x -> Ok x |
| 90 | + | None -> Error <| IsNotAType typeName) |
| 91 | + |> ParserMonad.sequenceRL |
| 92 | + |> Result.map (List.reduce sumParameterType)) |
| 93 | + |> ParserMonad.sequenceRL) |
0 commit comments