Include System Design
Overview
Seq supports a simple include system for code reuse. The design prioritizes:
- Minimal filesystem exposure
- Clear provenance (stdlib vs user code)
- Collision detection with good error messages
- Future extensibility to packages
Syntax
# Standard library (ships with compiler)
include std:http
include std:imath
# FFI bindings (C library wrappers)
include ffi:libedit
# Relative to current file
include "my-utils"
include "lib/helpers"
Rules
-
std:prefix - References stdlib bundled with compiler- Compiler knows where stdlib lives (not user’s concern)
- Example:
include std:httploadshttp.seqfrom stdlib
-
ffi:prefix - References FFI bindings for C libraries- Some bindings ship with compiler (e.g.,
ffi:libedit) - Others require
--ffi-manifestflag with a TOML manifest - Example:
include ffi:libeditloads readline-style functions - See FFI_GUIDE.md for full documentation
- Some bindings ship with compiler (e.g.,
-
Quoted string - Path relative to the including file
- No absolute paths allowed
- Paths can use
..to reference parent directories - Example:
include "lib/foo"loads./lib/foo.seq - Example:
include "../src/utils"from a tests directory - Example:
include "../../src/tokenizer"for deeper nesting
-
Extension omitted - Compiler adds
.seqautomatically -
Include once - Files are included at most once per compilation
- Duplicate includes are silently ignored
- Prevents diamond dependency issues
Collision Detection
If the same word is defined in multiple files:
Error: Word 'http-ok' is defined multiple times:
- stdlib/http.seq:45
- ./my-utils.seq:12
Hint: Rename one of the definitions to avoid collision.
All definitions are still global (no namespaces), but collisions are caught at compile time.
Implementation Notes
Compilation Pipeline
-
Resolve includes - Before parsing main file:
- Scan for include statements
- Resolve paths (stdlib vs relative)
- Load and parse included files
- Recursively process their includes
- Track included files to prevent duplicates
-
Merge programs - Combine all WordDefs into single Program
-
Check collisions - Before type checking:
- Build map of word name -> definition location
- Error if any word has multiple definitions
-
Continue normally - Type check and codegen as before
Stdlib Location
The compiler locates the stdlib in this order:
SEQ_STDLIBenvironment variable (if set to a valid directory)stdlib/directory relative to the compiler binary (for installed builds)- Embedded stdlib compiled into the binary (fallback)
Path Validation
Include paths are validated:
- Absolute Path Rejection - Absolute paths are rejected; all includes must be relative
- Empty Path Validation - Empty include paths are rejected
- Canonicalization - Paths are canonicalized to resolve symlinks and normalize
..segments - File Must Exist - The target
.seqfile must exist
Examples
Simple Program
include std:http
: main ( -- Int )
"Hello" http-ok io.write-line
0
;
With Local Utils
include std:http
include "utils"
: main ( -- Int )
get-greeting http-ok io.write-line
0
;
Where utils.seq in same directory:
: get-greeting ( -- String )
"Hello from utils!"
;
Collision Error
include std:http
include "my-http" # Also defines http-ok
Error: Word 'http-ok' is defined multiple times:
- stdlib/http.seq:45
- ./my-http.seq:3