Glimpse

A library for parsing, loading, and typechecking a complete Gleam project. It wraps the AST produced by glance with:

Glimpse is not filesystem-aware: modules are loaded externally through a loader function. It mirrors the official Gleam compiler’s behavior closely; it has been validated with differential mutation testing against the real compiler across a wide range of popular Gleam projects.

Glimpse 1.0.0-rc.1 is available on hex.pm.

Docs: https://hexdocs.pm/glimpse/ Repo: https://github.com/dusty-phillips/glimpse

Install

gleam add glimpse

Quickstart

Load a package, then typecheck it for the Erlang target:

import gleam/io
import gleam/result
import glimpse
import glimpse/target
import glimpse/typecheck

fn load_module(module_name: String) -> Result(String, Nil) {
  // read the module contents from the filesystem here
  Ok("<contents of " <> module_name <> ".gleam>")
}

pub fn main() {
  let package =
    glimpse.load_package("my_package", load_module)
    |> result.map(typecheck.package(_, target.Erlang))

  case package {
    Ok(_) -> io.println("typechecked ok")
    Error(_) -> io.println("typecheck failed")
  }
}

The package is loaded with a loader function and returned with inferred types filled in; you can then iterate the modules and inspect the resolved AST.

Loading packages

glimpse.load_package accepts the package name and a function that takes a module name and returns that module’s contents. The loader is called with the main module (the package name) and, recursively, for every module that is imported:

pub fn load_glimpse_package(
  project: project.Project,
) -> Result(glimpse.Package, errors.Error) {
  glimpse.load_package(project.name, fn(module_name) {
    let path =
      filepath.join(project.build_src_dir(project), module_name <> ".gleam")
    filesystem.read(path)
  })
  |> result.map_error(fn(error) {
    case error {
      glimpse.LoadError(error) -> error
      glimpse.ParseError(glance_error, name, content) ->
        errors.GlanceParseError(glance_error, name, content)
    }
  })
}

Typechecking

Glimpse is a full Hindley-Milner type checker with exhaustiveness checking, across module boundaries. typecheck.package sorts the modules by their dependencies and checks each in turn, returning the package with inferred types filled in:

pub fn package(
  package: glimpse.Package,
  target: target.Target,
) -> Result(glimpse.Package, error.GlimpseError(a))

Targets

@target(erlang) / @target(javascript) definitions that are not active for the target being checked are filtered out before typechecking, mirroring the real compiler. Pass target.Erlang or target.Javascript. Experimental backends can use target.Named(name) so a @target(python) definition is active when checking for target.Named("python"); the same matching applies to @external(...) annotations.

Lower-level entry points

glimpse/typecheck also checks a single module, constant, or function against an existing type environment:

Errors

Functions return a Result, with errors reported as glimpse/error’s GlimpseError:

Because Glimpse is not filesystem-aware, it cannot discover dev-only modules on its own. Set Package.dev_dependencies to those module names after loading so that a source module importing one is reported as an ImportError, mirroring the real compiler’s src/dev split.

Development

The repo ships two dev tools in dev/. Pass their arguments after a -- separator:

gleam test                                # Run the unit tests
gleam run -m dev_check                    # Typecheck glimpse against itself
gleam run -m dev_check -- --typecheck <root>
gleam run -m mutate_check -- --root <root> --src <src_rel> [--jobs <n>] [--kind <kind>] [--count] [--both] [--resume]
Search Document