|
| 1 | +# Embedding `FScript.Language` |
| 2 | + |
| 3 | +This document describes the host-facing interface of `FScript.Language`: |
| 4 | +- running the interpreter pipeline, |
| 5 | +- discovering script functions, |
| 6 | +- invoking functions, |
| 7 | +- supported host-visible types and values. |
| 8 | + |
| 9 | +## Namespace and entry points |
| 10 | + |
| 11 | +Reference `MagnusOpera.FScript.Language` and use namespace `FScript.Language`. |
| 12 | + |
| 13 | +Primary entry points are in module `FScript`: |
| 14 | + |
| 15 | +- `FScript.parse : string -> Program` |
| 16 | +- `FScript.infer : Program -> TypeInfer.TypedProgram` |
| 17 | +- `FScript.inferWithExterns : ExternalFunction list -> Program -> TypeInfer.TypedProgram` |
| 18 | +- `FScript.eval : TypeInfer.TypedProgram -> Value` |
| 19 | +- `FScript.evalWithExterns : ExternalFunction list -> TypeInfer.TypedProgram -> Value` |
| 20 | +- `FScript.run : string -> Value` (parse + infer + eval without externs) |
| 21 | + |
| 22 | +## Running scripts |
| 23 | + |
| 24 | +```fsharp |
| 25 | +open FScript.Language |
| 26 | +
|
| 27 | +let source = "let inc x = x + 1\ninc 41" |
| 28 | +let result = FScript.run source |
| 29 | +
|
| 30 | +match result with |
| 31 | +| VInt n -> printfn "Result: %d" n |
| 32 | +| other -> printfn "Unexpected value: %s" (Pretty.valueToString other) |
| 33 | +``` |
| 34 | + |
| 35 | +## Running with external functions |
| 36 | + |
| 37 | +Use `inferWithExterns` and `evalWithExterns` when the script needs host functions. |
| 38 | + |
| 39 | +```fsharp |
| 40 | +open FScript.Language |
| 41 | +
|
| 42 | +let toUpperExtern = |
| 43 | + { Name = "toUpper" |
| 44 | + Scheme = Forall([], TFun(TString, TString)) |
| 45 | + Arity = 1 |
| 46 | + Impl = |
| 47 | + function |
| 48 | + | [ VString s ] -> VString (s.ToUpperInvariant()) |
| 49 | + | _ -> raise (EvalException { Message = "toUpper expects string"; Span = Span.mk (Span.pos 0 0) (Span.pos 0 0) }) } |
| 50 | +
|
| 51 | +let source = "toUpper \"fscript\"" |
| 52 | +let program = FScript.parse source |
| 53 | +let typed = FScript.inferWithExterns [ toUpperExtern ] program |
| 54 | +let result = FScript.evalWithExterns [ toUpperExtern ] typed |
| 55 | +``` |
| 56 | + |
| 57 | +## Getting function metadata |
| 58 | + |
| 59 | +After inference, function descriptors can be produced with `Descriptor.describeFunctions`. |
| 60 | + |
| 61 | +```fsharp |
| 62 | +open FScript.Language |
| 63 | +
|
| 64 | +let src = "let add x y = x + y\nlet rec fact n = if n = 0 then 1 else n * fact (n - 1)" |
| 65 | +let typed = src |> FScript.parse |> FScript.infer |
| 66 | +
|
| 67 | +let functions = |
| 68 | + Descriptor.describeFunctions typed Map.empty |
| 69 | +
|
| 70 | +for f in functions do |
| 71 | + let args = f.Parameters |> List.map Types.typeToString |> String.concat " -> " |
| 72 | + printfn "%s : %s -> %s" f.Name args (Types.typeToString f.ReturnType) |
| 73 | +``` |
| 74 | + |
| 75 | +`FunctionDescriptor` exposes: |
| 76 | +- `Name` |
| 77 | +- `Parameters` (`Type list`) |
| 78 | +- `ReturnType` (`Type`) |
| 79 | +- `Scheme` (`Scheme option`) |
| 80 | +- `IsRecursive` |
| 81 | +- `Span` |
| 82 | + |
| 83 | +## Invoking functions |
| 84 | + |
| 85 | +Function invocation is expression-based: evaluate a script where the target function is called. |
| 86 | + |
| 87 | +```fsharp |
| 88 | +open FScript.Language |
| 89 | +
|
| 90 | +let src = "let add x y = x + y\nadd 1 2" |
| 91 | +let value = FScript.run src |
| 92 | +``` |
| 93 | + |
| 94 | +You can also evaluate to a function value: |
| 95 | + |
| 96 | +```fsharp |
| 97 | +open FScript.Language |
| 98 | +
|
| 99 | +let value = FScript.run "let add1 x = x + 1\nadd1" |
| 100 | +
|
| 101 | +match value with |
| 102 | +| VClosure _ -> printfn "Function value returned" |
| 103 | +| _ -> printfn "Not a function" |
| 104 | +``` |
| 105 | + |
| 106 | +## Supported types |
| 107 | + |
| 108 | +Host-visible static types are represented by `Type`: |
| 109 | + |
| 110 | +- `TUnit` |
| 111 | +- `TInt` |
| 112 | +- `TFloat` |
| 113 | +- `TBool` |
| 114 | +- `TString` |
| 115 | +- `TList of Type` |
| 116 | +- `TTuple of Type list` |
| 117 | +- `TRecord of Map<string, Type>` |
| 118 | +- `TStringMap of Type` |
| 119 | +- `TOption of Type` |
| 120 | +- `TFun of Type * Type` |
| 121 | +- `TNamed of string` |
| 122 | +- `TUnion of string * Map<string, Type option>` |
| 123 | +- `TTypeToken` |
| 124 | +- `TVar of int` |
| 125 | + |
| 126 | +Use `Types.typeToString` for display/diagnostics. |
| 127 | + |
| 128 | +## Runtime values |
| 129 | + |
| 130 | +Evaluation returns `Value`: |
| 131 | + |
| 132 | +- `VUnit` |
| 133 | +- `VInt of int64` |
| 134 | +- `VFloat of float` |
| 135 | +- `VBool of bool` |
| 136 | +- `VString of string` |
| 137 | +- `VList of Value list` |
| 138 | +- `VTuple of Value list` |
| 139 | +- `VRecord of Map<string, Value>` |
| 140 | +- `VStringMap of Map<string, Value>` |
| 141 | +- `VOption of Value option` |
| 142 | +- `VUnionCase of string * string * Value option` |
| 143 | +- `VUnionCtor of string * string` |
| 144 | +- `VTypeToken of Type` |
| 145 | +- `VClosure of string * Expr * Env ref` |
| 146 | +- `VExternal of ExternalFunction * Value list` |
| 147 | + |
| 148 | +Use `Pretty.valueToString` for a readable string form. |
| 149 | + |
| 150 | +## Errors |
| 151 | + |
| 152 | +`FScript.Language` raises typed exceptions with source spans: |
| 153 | + |
| 154 | +- `ParseException` (`ParseError`) |
| 155 | +- `TypeException` (`TypeError`) |
| 156 | +- `EvalException` (`EvalError`) |
| 157 | + |
| 158 | +Each error contains: |
| 159 | +- `Message` |
| 160 | +- `Span` (`Line`/`Column` information) |
0 commit comments