Skip to content

Modules and Imports

Kelvra uses @import(...) for both source modules and native packages. That shared surface is one of the most important things to document clearly.

Use a string literal path that includes the filename:

const math = @import("./math.kel")
print(math.PI)
print(math.Add(1, 2))

Current source-module rules:

  • the import target must be a string literal
  • relative paths resolve from the importing file’s directory
  • REPL mode does not allow @import(...)

Capitalized top-level names are exported. Lowercase names stay private to the module.

fn Add(a i32, b i32) i32 { return a + b }
const PI f64 = 3.14159
type Vector struct {}
const { Add, PI } = @import("./math.kel")
const { Add as sum } = @import("./math.kel")
print(sum(10, 5))

The frontend and parser tests also cover typed destructuring imports:

const { Add: fn(i32, i32) i32, PI as Tau: f64 } =
@import("./math.kel")

Bare names resolve as package imports:

const nativeMath = @import("math")
const { addI64, greet } = @import("math")

Path-like imports such as "./math.kel" stay source imports. Bare names such as "math" or "window" resolve as package imports.

The current implementation looks for project/package metadata before falling back to package roots. The documented search locations include:

  • build/packages relative to the interpreter binary
  • extra roots passed with --package-path
  • packages/ relative to the importing source file or current working directory

Read Using Native Packages for the package-specific side of the model.

The test suite covers several failure modes:

  • missing exports
  • import cycles
  • non-string import arguments
  • type mismatches on typed import bindings
  • importing package handles through the wrong package type