This document describes the host-facing interface of FScript.Language:
- running the interpreter pipeline,
- discovering script functions,
- invoking functions,
- supported host-visible types and values.
Note on CLI host behavior:
- The
fscriptCLI injectslet Envinto script execution. - The
Environmenttype is provided by stdlib. - That injection is a CLI host convenience, not part of the
FScript.Languagecore API contract. - Hosts can provide filesystem denied glob patterns through
HostContext.DeniedPathGlobs.
Reference MagnusOpera.FScript.Language and use namespace FScript.Language.
Primary entry points are in module FScript:
FScript.parse : string -> ProgramFScript.infer : Program -> TypeInfer.TypedProgramFScript.inferWithExterns : ExternalFunction list -> Program -> TypeInfer.TypedProgramFScript.eval : TypeInfer.TypedProgram -> ValueFScript.evalWithExterns : ExternalFunction list -> TypeInfer.TypedProgram -> ValueFScript.run : string -> Value(parse + infer + eval without externs)
open FScript.Language
let source = "let inc x = x + 1\ninc 41"
let result = FScript.run source
match result with
| VInt n -> printfn "Result: %d" n
| other -> printfn "Unexpected value: %s" (Pretty.valueToString other)Use inferWithExterns and evalWithExterns when the script needs host functions.
open FScript.Language
let toUpperExtern =
{ Name = "toUpper"
Scheme = Forall([], TFun(TString, TString))
Arity = 1
Impl =
function
| [ VString s ] -> VString (s.ToUpperInvariant())
| _ -> raise (EvalException { Message = "toUpper expects string"; Span = Span.mk (Span.pos 0 0) (Span.pos 0 0) }) }
let source = "toUpper \"fscript\""
let program = FScript.parse source
let typed = FScript.inferWithExterns [ toUpperExtern ] program
let result = FScript.evalWithExterns [ toUpperExtern ] typedUse FScript.Runtime.ScriptHost when a host needs reusable loading and direct function invocation.
Only top-level exported bindings are exposed through this API.
open FScript.Language
open FScript.Runtime
let externs = Registry.all { RootDirectory = "."; DeniedPathGlobs = [] }
let loaded = ScriptHost.loadSource externs "[<export>] let add x y = x + y"
let result = ScriptHost.invoke loaded "add" [ VInt 1L; VInt 2L ]After inference, function descriptors can be produced with Descriptor.describeFunctions.
open FScript.Language
let src = "let add x y = x + y\nlet rec fact n = if n = 0 then 1 else n * fact (n - 1)"
let typed = src |> FScript.parse |> FScript.infer
let functions =
Descriptor.describeFunctions typed Map.empty
for f in functions do
let args = f.Parameters |> List.map Types.typeToString |> String.concat " -> "
printfn "%s : %s -> %s" f.Name args (Types.typeToString f.ReturnType)FunctionDescriptor exposes:
NameParameters(Type list)ReturnType(Type)Scheme(Scheme option)IsRecursiveSpan
Function invocation is expression-based: evaluate a script where the target function is called.
open FScript.Language
let src = "let add x y = x + y\nadd 1 2"
let value = FScript.run srcYou can also evaluate to a function value:
open FScript.Language
let value = FScript.run "let add1 x = x + 1\nadd1"
match value with
| VClosure _ -> printfn "Function value returned"
| _ -> printfn "Not a function"nameof returns the bound identifier name as a string and type-checks that the identifier exists.
open FScript.Language
let src = "let run_step x = x\nnameof run_step"
let value = FScript.run src
// value = VString "run_step"Host-visible static types are represented by Type:
TUnitTIntTFloatTBoolTStringTList of TypeTTuple of Type listTRecord of Map<string, Type>TMap of Type * TypeTOption of TypeTFun of Type * TypeTNamed of stringTUnion of string * Map<string, Type option>TTypeTokenTVar of int
Use Types.typeToString for display/diagnostics.
The postfix script type syntax 'a map corresponds to TMap(TString, 'a).
Evaluation returns Value:
VUnitVInt of int64VFloat of floatVBool of boolVString of stringVList of Value listVTuple of Value listVRecord of Map<string, Value>VMap of Map<MapKey, Value>VOption of Value optionVUnionCase of string * string * Value optionVUnionCtor of string * stringVTypeToken of TypeVClosure of string * Expr * Env refVExternal of ExternalFunction * Value list
Use Pretty.valueToString for a readable string form.
FScript.Language raises typed exceptions with source spans:
ParseException(ParseError)TypeException(TypeError)EvalException(EvalError)
Each error contains:
MessageSpan(Line/Columninformation)
Use import-aware parsing when executing scripts from disk.
open FScript.Language
let root = "/path/to/workspace"
let entry = "/path/to/workspace/main.fss"
let program = FScript.parseFileWithIncludes root entry
let typed = FScript.infer program
let value = FScript.eval typedUse ScriptHost when you want to invoke exported functions repeatedly.
open FScript.Language
open FScript.Runtime
let hostContext = { RootDirectory = "."; DeniedPathGlobs = [] }
let externs = Registry.all hostContext
let loaded =
ScriptHost.loadFile externs "./script.fss"
let r1 = ScriptHost.invoke loaded "run" [ VString "build" ]
let r2 = ScriptHost.invoke loaded "run" [ VString "test" ]Use resolver-backed loading when the entry script source is in memory and imports must be resolved by the host.
open System.IO
open FScript.Language
open FScript.Runtime
let root = "/virtual/workspace"
let entryFile = Path.Combine(root, "main.fss")
let entrySource = "import \"shared.fss\" as Shared\n[<export>] let run x = Shared.add1 x"
let embeddedSources =
Map [
Path.Combine(root, "shared.fss"), "let add1 x = x + 1"
]
let resolver path = embeddedSources |> Map.tryFind path
let externs = Registry.all { RootDirectory = root; DeniedPathGlobs = [] }
let loaded =
ScriptHost.loadSourceWithIncludes externs root entryFile entrySource resolver
let result = ScriptHost.invoke loaded "run" [ VInt 41L ]Define a typed external function and pass it to inference/evaluation.
open FScript.Language
let envExtern =
{ Name = "Env.get"
Scheme = Forall([], TFun(TString, TOption TString))
Arity = 1
Impl =
function
| [ VString key ] ->
System.Environment.GetEnvironmentVariable(key)
|> Option.ofObj
|> VOption
| _ ->
raise (EvalException { Message = "Env.get expects one string"; Span = Span.mk (Span.pos 0 0) (Span.pos 0 0) }) }
let src = "Env.get \"HOME\""
let program = FScript.parse src
let typed = FScript.inferWithExterns [ envExtern ] program
let value = FScript.evalWithExterns [ envExtern ] typedAfter inference, get function descriptors to expose callable surface in hosts.
open FScript.Language
let typed = "[<export>] let run x = x" |> FScript.parse |> FScript.infer
let descriptors = Descriptor.describeFunctions typed Map.emptyUse FScript.Runtime.ExportSignatures.fromTypedProgram when a host needs exported function signatures from typed AST without executing script bodies.
open FScript.Language
open FScript.Runtime
let typed = "[<export>] let add (x: int) (y: int) = x + y" |> FScript.parse |> FScript.infer
let signatures = ExportSignatures.fromTypedProgram typed