LLuce

Modules

A file is a module.

import#

import name          binds the sibling file `name.luc`
import std.name      binds a module embedded in the compiler

Both bind the bare name, so call sites read math.sqrt(x) and only the import line records where the module came from.

An import reaches the imported file's top level:

name.func(args)
name.Struct(field = expr, ...)
name.Struct.member(args)
name.constant
p: name.Struct              in an annotation

Scope stays per file. Nothing is visible without an import, and using a namespace you did not import is luce.sema.import.

Modules may import each other; the graph loads each file once, so cross-file mutual recursion works. A module importing itself is luce.import.self. The whole graph compiles as one program and writes one module file.

Errors inside an imported file render at the path it was really opened from, with the source line and a caret.

Sibling resolution#

A sibling import names the file exactly, including its case, and the file must be an ordinary file. A case-insensitive filesystem would happily open Geo.luc for import geo, so the directory entry is checked rather than the open — a program that builds on one machine builds on the machine that ships it.

Deliberately absent: package managers, search paths, conditional imports, re-exports, and any as clause.

The std. namespace#

std is reserved. No module name is. The two namespaces are disjoint, so a math.luc beside your program is exactly what import math reaches, and a standard module can neither be shadowed nor make a file of yours unreachable.

Three rules keep it honest.

WrittenDiagnostic
import std.nopeluce.import.standard — the error lists the modules that exist
import stdluce.import.reserved — the namespace is not a module, so no std.luc can ever be imported
import std.math and import math togetherluce.import.collision — one binding, two modules; rename the file
main.luc
import std.nope

func main():
    print("x")
luce check — the program is refused
luce: compile failed
main.luc:1:1: there is no standard module std.nope; the standard library is std.math, std.files, std.strings [luce.import.standard]
    import std.nope
    ^~~~~~~~~~~~~~~

Standard modules are ordinary Luce source embedded in the compiler. They obey every language rule including the host gate: import std.files inside a program compiled without host access is a compile error, because file access genuinely does not exist there.

The modules are math, strings and files.

Multi-file programs#

shapes.luc
let unit = 1.0

struct Rect:
    width: Float
    height: Float

    func area(r: Rect) -> Float:
        return r.width * r.height

func square(side: Float) -> Rect:
    return Rect(width = side, height = side)
main.luc
import shapes

func main():
    let r = shapes.square(3.0)
    print(f"{r.width}x{r.height} area {shapes.Rect.area(r)} unit {shapes.unit}")
Output
3x3 area 9 unit 1