Skip to content

Latest commit

 

History

History
244 lines (179 loc) · 10.2 KB

README.md

File metadata and controls

244 lines (179 loc) · 10.2 KB

FScript logo

FScript

Build (main) NuGet Language NuGet Runtime

FScript is a lightweight, embeddable interpreter with an F#/ML-style language.

It is designed for host applications that need:

  • a concise functional scripting language,
  • strong static checks (Hindley-Milner type inference),
  • controlled host extensibility,
  • and a clear sandbox/security boundary.

Why FScript

  • F#/ML lineage: immutable data, expressions-first style, pattern matching, let/fun, algebraic modeling.
  • Interpreter pipeline: lexer -> parser -> type inference -> evaluator.
  • Host-first extensibility: add external functions with explicit type schemes and runtime implementations.
  • Security-aware embedding: script capabilities are defined by what the host exposes.

Compilation

FScript also compiles to optimized .NET assemblies and independently buildable C# projects. The .NET backend supports self-contained single-file and Native AOT executables, including typed FFI bindings.

See Compilation for target selection, .NET output, C# projects, and optimization behavior.

Language Snapshot

FScript currently includes:

  • bindings and functions: let, zero-argument functions such as let f () = ..., let rec, and mutual recursion, lambdas,
  • control flow: if/elif/else, match, for ... in ... do,
  • data: list, option, tuple, map, record, discriminated unions,
  • pattern matching: list, option, tuple, record, union cases,
  • optional type annotations on parameters,
  • type declarations: records and unions (including recursive forms),
  • interpolation, pipeline operator, typeof type tokens, and nameof identifier tokens for host workflows.
  • unified brace literals for records/maps ({ Field = value }, { [key] = value }, {} for empty map), with map keys typed as string, int, bool, or a union whose cases all have no payload. Optional key annotations use postfix syntax such as string map[int].

Getting Started Tutorial

If you are new to FScript, start with the progressive tutorial:

It covers installation, syntax basics, flow control, collections, pattern matching, stdlib usage, includes, and host/export concepts.

Installation

CLI via .NET Tool

dotnet tool install --global MagnusOpera.FScript

To update:

dotnet tool update --global MagnusOpera.FScript

To install in a local tool manifest instead:

dotnet new tool-manifest
dotnet tool install MagnusOpera.FScript

CLI via Homebrew

brew install magnusopera/tap/fscript

Embeddable language via NuGet

  • MagnusOpera.FScript.Language
  • MagnusOpera.FScript.Runtime
  • MagnusOpera.FScript.Extensibility (independent SDK for extension authors)

VS Code Extension

FScript has a first-party VS Code extension with syntax highlighting and Language Server features (diagnostics, completion, hover, symbols, go-to-definition, references, rename, semantic tokens, inlay hints).

  • VS Code Marketplace: https://marketplace.visualstudio.com/items?itemName=MagnusOpera.fscript
  • Open VSX: https://open-vsx.org/extension/MagnusOpera/fscript

The extension uses automatic .NET runtime acquisition via .NET Install Tool and falls back to dotnet from PATH when needed. Source lives in vscode-fscript/.

Repository Development

Building from source requires Make, the latest stable Terrabuild executable on PATH, and a running Docker engine. make build uses Terrabuild to prepare a container with the .NET SDK, Node.js, and native build tools. CI uses Terrabuild 0.207.2 or newer to restore cached test reports and render cached operation logs. Shared tool versions are defined in WORKSPACE.

See the Terrabuild guide for setup, caching, and container-based test commands such as make tb-test and make tb-check. The make test and dotnet run commands below use the host .NET SDK; make test also requires Node.js and npm on the host.

Build

make build

Test

make test

Run a script

dotnet run --project src/FScript -- samples/types-showcase.fss

Run a script with script arguments (after --):

dotnet run --project src/FScript -- samples/fibonacci.fss -- 10

Run the vintage BASIC sample interpreter:

dotnet run --project src/FScript -- samples/basic/basic.fss -- helloworld.bas

Optional sandbox root override:

dotnet run --project src/FScript -- --root /tmp/sandbox samples/types-showcase.fss

Disable default runtime externs (Registry.all):

dotnet run --project src/FScript -- --no-default-externs samples/types-showcase.fss

Share a configured external-function environment with VS Code:

fscript scripts/build.fss
# Override automatic selection when the manifest is elsewhere:
fscript --config ./fscript.toml scripts/build.fss

The CLI loads fscript.toml beside the script automatically; explicit --config selects a different location. See environment configuration for the schema, flag precedence, workspace selection, and trust rules.

Load user extern providers from an assembly (repeatable):

dotnet run --project src/FScript -- --extern-assembly ./MyExterns.dll samples/types-showcase.fss

Run a script from stdin:

cat samples/types-showcase.fss | dotnet run --project src/FScript -- -r .

Run stdin mode with script arguments:

cat samples/types-showcase.fss | dotnet run --project src/FScript -- -r . -- foo bar

Show CLI version:

dotnet run --project src/FScript -- version

In CLI execution modes, scripts get:

  • stdlib type Environment = { ScriptName: string option; Arguments: string list }
  • stdlib type FsKind = File of string | Directory of string | Missing
  • CLI-injected let Env = ...

Start REPL:

dotnet run --project src/FScript --

The CLI automatically loads fscript.toml beside the entry script, or in the working directory for stdin/REPL. It does not search parent directories. Use --config to select another manifest or --no-config to skip discovery.

Useful samples:

Interpreter Architecture

The core engine lives in src/FScript.Language and runs in four stages:

  1. Lexing: indentation-aware tokenization.
  2. Parsing: AST construction with expression/layout rules.
  3. Type inference: Hindley-Milner inference + unification + optional annotations.
  4. Evaluation: typed AST evaluation with immutable values and pattern matching.

Host integration lives in src/FScript.Runtime.

Extensibility Model

FScript is extended through host-provided externs. Registrations can also expose host-managed types with immutable visible fields and opaque host state; scripts can read and transport them but cannot construct or update them. See the embedding guide for a complete example.

Each extern declares:

  • a public name (for script calls),
  • a type scheme,
  • arity,
  • implementation.

Built-in host extern families include Fs.*, Console.*, Json.*, Xml.*, Regex.*, hashing, and GUID helpers. Task.*, List.*, Map.*, and Option.* are provided by the embedded stdlib prelude.

For details and extension workflow, see docs/specs/external-functions.md.

Sandbox and Security

FScript runs in-process. Security is capability-based:

  • scripts can only do what exposed externs allow,
  • core language evaluation is deterministic over in-memory values,
  • side effects and external I/O are controlled at host extern boundaries.

Operational controls (timeouts, cancellation, resource limits, process/container isolation) are host responsibilities.

See docs/specs/sandbox-and-security.md for the full model and checklist.

Documentation

Website development commands:

make website-install
make website-build
make website
make website-version version=X.Y.Z

Changelog

License

This project is licensed under the MIT License.
See LICENSE.