libbundle-ast combines multiple Oak modules into a single bundled AST with proper module system initialization for standalone execution.
bundleAST := import('bundle-ast')
{ wrapBundle: wrapBundle } := import('bundle-ast')
Creates a bundled AST from multiple parsed modules.
Parameters:
modules- List of[modulePath, moduleAST]pairsentryModuleName- Name of the entry point module to execute
Returns: Block AST node containing all modules and initialization code
{ wrapBundle: wrapBundle } := import('bundle-ast')
modules := [
['main.oak', mainAST]
['lib/utils.oak', utilsAST]
['lib/helpers.oak', helpersAST]
]
bundled := wrapBundle(modules, 'main.oak')
// bundled is a block containing:
// 1. All module wrapper functions
// 2. Module initialization table
// 3. Entry point invocation
The generated bundle has this structure:
{
type: :block
exprs: [
module1WrapperFunction // fn { ... }
module2WrapperFunction // fn { ... }
...
moduleNWrapperFunction // fn { ... }
entryPointCall // __oak_module_import('main.oak')
]
decls: []
}
Each module is wrapped in a function via __oak_modularize:
// Generated structure
__oak_modularize('module.oak', function() {
// Original module code
return { exports }
}){ wrapBundle: wrapBundle } := import('bundle-ast')
syntax := import('syntax')
// Parse modules
main := syntax.parse(readFile('main.oak'))
utils := syntax.parse(readFile('utils.oak'))
modules := [
['main.oak', main]
['utils.oak', utils]
]
bundled := wrapBundle(modules, 'main.oak')
{ wrapBundle: wrapBundle } := import('bundle-ast')
fn compileProject(entryPoint) {
// 1. Resolve all imports
modules := resolveModules(entryPoint)
// 2. Parse each module
parsedModules := modules |> map(fn([path, code]) {
[path, parseOakCode(code)]
})
// 3. Analyze each module
analyzedModules := parsedModules |> map(fn([path, ast]) {
[path, analyzeNode(ast, true, ?)]
})
// 4. Bundle into single AST
bundled := wrapBundle(analyzedModules, entryPoint)
// 5. Generate code
codegen(bundled)
}
{ wrapBundle: wrapBundle } := import('bundle-ast')
fn bundleWithVirtualFS(modules, entry, vfsFiles) {
// Create module with embedded VFS
vfsModule := createVFSModule(vfsFiles)
// Add VFS to modules
allModules := [['__vfs', vfsModule]] |> append(modules)
// Bundle with VFS included
wrapBundle(allModules, entry)
}
The bundle creates a table mapping module names to their wrapper functions:
{
'main.oak': __oak_modularize('main.oak', mainFunc)
'lib/utils.oak': __oak_modularize('lib/utils.oak', utilsFunc)
'lib/helpers.oak': __oak_modularize('lib/helpers.oak', helpersFunc)
}The bundle ends with a call to load the entry module:
__oak_module_import('main.oak')This triggers:
- Module table lookup
- Module function execution
- Caching of module exports
- Return of cached exports
Module paths are used as-is:
'main.oak' // Entry point
'lib/utils.oak' // Relative to entry
'/abs/path.oak' // Absolute path
Each module wrapped with __oak_modularize:
__oak_modularize(moduleName, moduleFunction)Returns a callable that:
- Executes module function once
- Caches module exports
- Returns cached exports on subsequent calls
Uses synthetic tokens for generated nodes:
{ pos: [0, 1, 0], type: :stringLiteral, val: moduleName }
{ pos: [0, 1, 0], type: :identifier, val: '__oak_modularize' }
- Load bundle: Execute bundled code
- Register modules: Store module functions in table
- Import entry: Call
__oak_module_import(entryModule) - Resolve imports: Load dependencies on demand
- Cache exports: Store module return values
- Return result: Entry module's exports
// build.oak uses bundle-ast
modules := collectModules(entry)
bundled := wrapBundle(modules, entry)
output := codegen(bundled)
writeFile(outputPath, output)
// pack.oak uses bundle-ast via build
bundled := buildAndBundle(entry, includes)
executable := createExecutable(bundled, vfsFiles)
Each module AST should be a transformed module wrapper:
{
type: :function
name: '' // Anonymous
args: []
body: {
type: :block
exprs: [/* module code */]
decls: [/* module declarations */]
}
}
- No dynamic imports (all modules known at bundle time)
- Module paths must be string literals
- Circular dependencies not specially handled
- No code splitting
- No lazy loading
- Bundle size includes all modules (no tree shaking here)
Bundle-ast doesn't optimize, but bundled AST can be:
- Dead code eliminated
- Minified
- Constant folded
- Inlined
- Application bundling: Combine app modules
- Library distribution: Single-file libraries
- Code deployment: Deploy as one unit
- Static analysis: Analyze entire program
- Tree shaking: Enable cross-module optimization
- build.md - Build system
- ast-transform.md - Module wrapping
- ast-analyze.md - Semantic analysis
- pack.md - Create executables