Darklang Documentation

repository·main·Indexed 24 days ago

https://github.com/darklang/dark

An integrated language, editor, and infrastructure platform for creating backends and CLIs. Documentation covers database schema management via schema.sql and incremental migrations, the LibParser recursive-descent pipeline, LibDB SQLite-backed persistence, LibSerialization hashing and binary formats, and the WASM-based browser REPL.

Tokens
60.8K
Snippets
155
Records
380
Agent score
80%

What's inside Darklang

  1. Overview of Model Context Protocol (MCP) for Darklang

    main
    The Darklang implementation of the Model Context Protocol (MCP) enables communication between AI models and external tools or resources. Much like the Language Server Protocol (LSP), MCP utilizes JSON-RPC for communication between clients and servers. This allows AI models to access external data, execute code, and interact with various services through a standardized interface.
  2. Overview of LibDB persistence

    main

    LibDB provides SQLite-backed persistence for core Darklang services, including the package manager, branches, SCM operations, user databases, and execution traces. It serves as the persistent companion to the in-memory PT.PackageManager found in LibExecution.

    Key characteristics:

    • Content-Addressing: Items are content-addressed using SHA256 keys.
    • Branch Scoping: Locations (bindings of names to hashes) are scoped to specific branches.
  3. Understand the Language Server Protocol (LSP) implementation in Darklang

    main

    The @Darklang.LanguageServerProtocol module provides types and functions to support the Language Server Protocol (LSP) version 3.17.0. It is designed primarily as an LSP Server implementation.

    Key architectural components include:

    • common.dark: Contains the base types used across the protocol.
    • Spec-organized files: Most files are organized according to the sections of the official LSP specification.
    • io.dark: The intended entry point for handling incoming messages and dispatching responses and notifications to the client (currently reserved for future abstraction).
  4. Types of Dark test files

    main

    Test files in the testfiles directory are categorized by their purpose:

    • execution files: Used to test the Dark language and most of the standard library.
    • httpclient files: Used to test the HTTP Client in the standard library.
    • http-server files: Test the HTTP handlers hosted by darklang serve (driven through Stdlib.HttpServer.serve).
    • data directory: Houses static assets used as accessory data for tests.
  5. Overview of LibSerialization storage and hashing

    main

    LibSerialization is responsible for how code is stored on disk and how content-addressable hashes are produced. It consists of two primary components:

    1. Binary format: Used for the package store and on-disk caches. This format is subject to schema-stability rules to ensure data remains readable as the Project Type (PT) and Runtime (RT) evolve.
    2. Deterministic serialization (Hashing/Canonical.fs): Used specifically for hashing. This process skips identity-irrelevant fields—such as AST node IDs and descriptions—to ensure that the same logical code always produces the same hash.
  6. Overview of the LibParser pipeline

    main

    LibParser is a hand-written recursive-descent parser for Darklang source code. It transforms raw source text into a syntax tree through a multi-stage pipeline. The pipeline consists of:

    1. Lexing: Lexer.tokenize converts source into tokens and trivia (comments and positions), preserving whitespace text only for position tracking.
    2. Syntax Parsing: Parser.parseSyntax performs a shared private syntax pass.
    3. Lowering/Branching:
      • Tooling Path: Parser.parse produces a WrittenTypes tree along with syntax and structural diagnostics used for IDE/tooling support.
      • Execution Path: Parser.parseFor Mode performs structural and file-purpose validation, resulting in a ValidatedSourceFile. This is further lowered via WrittenTypesToProgramTypes into executable ProgramTypes.

    To ensure consistency, the two lowering paths are verified via differential testing to ensure their ProgramTypes output is identical.

    source
      │  Lexer.tokenize                  tokens + trivia
      ▼
      │  Parser.parseSyntax              shared private syntax pass
      ▼
      ├─ Parser.parse                    WrittenTypes tree + diagnostics
      │  └─ Builtins.Language.WrittenTypesToDarkTypes
      └─ Parser.parseFor Mode             ValidatedSourceFile
         └─ WrittenTypesToProgramTypes → executable ProgramTypes
  7. Understand Darklang REPL state and builtins

    main

    The WASM REPL has specific behaviors regarding state and available builtins:

    State Management

    • Package Items: Declarations of fn, type, or val become in-memory package items under the Repl owner. These are callable without qualification in subsequent entries, and redefinitions will take precedence.
    • Session Variables: A bare let x = ... declaration persists its bindings as session variables. These are injected into later entries as pre-loaded VM registers.
    • Scope Limitation: Declarations cannot close over session variables; package items are considered static.

    Builtins and Environment

    • Standard Library: Stdlib.* is provided via the package snapshot.
    • Core Builtins: Includes Builtins.Pure and Builtins.Http.Client (which uses fetch and is subject to CORS).
    • Browser I/O: Supports printLine and print (buffered into results) and pmGetLocationsBy* lookups used by the pretty-printer.
    • Output: The REPL output matches the behavior of dark eval.
  8. Understand the Darklang CLI data directory structure

    main

    The .darklang directory is the central data store for the Darklang CLI. It manages package definitions, settings, and logs.

    Directory Contents:

    • data.db: A SQLite database containing package definitions (including the standard library) and other CLI data.
    • logs/: A subdirectory containing CLI operation logs for debugging.
    • README.md: Documentation explaining the directory contents.

    Important Note on Portability: If you move the Darklang CLI executable, you must move the .darklang directory with it. If the directory is separated from the executable, you will lose your local package cache and settings, and updates to your local package store will not be preserved.

  9. How Vanilla JSON serialization works in Dark

    main

    Dark uses a "Vanilla" JSON serializer to handle arbitrary types. To prevent accidental breaking changes to serialization formats, Dark enforces strict allow-listing and testing requirements for any type intended for serialization.

    Requirements for using Vanilla serialization:

    1. Explicit Allow-listing: You must explicitly allow a type using Json.Vanilla.allow<type>(). Attempting to serialize or deserialize a type that has not been explicitly allowed will result in an exception.

      • Placement: The allow call should be placed in an init function within the same file that uses the serializer, rather than in the file where the type is defined.
      • Nesting: You only need to call allow for the top-level type being serialized; you do not need to explicitly allow all nested types within that structure.
    2. Mandatory Test Cases: Every top-level type that is serialized must have a corresponding test case. This ensures that any changes to the type's structure are caught via git diffs in the serialization artifacts.

      • Tests will fail if an allowed type lacks a test case.
      • Tests will fail if a test case exists for a type that hasn't been explicitly allowed.