A Lua-based compiler and runtime for the Zork Implementation Language (ZIL).
This project provides a runtime environment for executing ZIL programs, including the classic Zork adventure games.
For a repo-level system summary, see ARCHITECTURE.md. Agent-specific guidance lives in AGENTS.md.
- ZIL to Lua Compilation: Compiles ZIL source code to Lua for execution
- Require System: Load .zil files using Lua's
require()function, just like moonscript - Source Mapping: Error messages automatically reference ZIL source files instead of generated Lua files (see SOURCE_MAPPING.md)
- Interactive Gameplay: Full support for classic text adventure games
- Comprehensive Testing: Unit and integration tests for all components
- Lua 5.4 or compatible version
To run the game in interactive mode:
lua main.luaThis will compile the ZIL files specified in main.lua and start the interactive game.
The project includes comprehensive testing at multiple levels: unit tests (134+), integration tests, game walkthroughs, and pure ZIL tests.
make test # Run all tests (unit + integration)
make test-unit # Run unit tests only
make test-integration # Run integration tests only
make test-pure-zil # Run pure ZIL tests (new!)- Unit Tests: Parser (60 tests), Compiler (44 tests), Runtime (25 tests), Source Mapping (5 tests)
- Integration Tests: Zork1 game tests, parser/runtime tests, horror game tests
- Parser/Runtime Tests: Directions, containers, light, take, pronouns
- Pure ZIL Tests: Self-contained tests written entirely in ZIL using ASSERT function
You can now write tests entirely in ZIL without Lua wrappers:
<ROUTINE TEST-MY-FEATURE ()
<TELL "Testing..." CR>
<ASSERT T "This passes">
<ASSERT <==? 5 5> "Numbers match">
<ASSERT <FSET? ,APPLE ,TAKEBIT> "Apple is takeable">
<TELL "All tests completed!" CR>>
<ROUTINE GO () <TEST-MY-FEATURE>>Run with the generic test runner:
lua5.4 run-zil-test.lua tests.my-testFeatures:
- ASSERT checks condition and prints [PASS] or [FAIL]
- Combine with ZIL operators:
==?,FSET?,LOC, etc. - Simple, minimal setup
- Only ZIL test files needed - one generic Lua runner for all tests
For integration test documentation, see tests/TESTS.md.
main.lua- Main entry point for running the gamezilscript/- ZIL runtime implementationinit.lua- Main module for require system (loads when yourequire "zilscript")base.lua- Core loader functionality for .zil filesbootstrap.lua- Core runtime functions and globals (includes ASSERT function)parser.lua- ZIL parsercompiler.lua- ZIL to Lua compilerevaluate.lua- Expression evaluatorruntime.lua- Runtime loader utilitiessourcemap.lua- Source mapping for error messages
tests/- Test framework and test filesrun_tests.lua- Integration test runner- Pure ZIL test examples (test-simple-new.zil, test-insert-file.zil, etc.)
zork1_basic.lua- Basic integration testszork1_walkthrough.lua- Extended integration testsunit/- Unit tests directorytest_framework.lua- Unit testing frameworktest_parser.lua- Parser unit teststest_compiler.lua- Compiler unit teststest_runtime.lua- Runtime unit testsrun_all.lua- Unit test runner
infocom/zork1/- Zork 1 game filesbooks/blackwood-horror/- Additional adventure files
The list of ZIL files to compile is specified in main.lua:
local files = {
"infocom/zork1/globals.zil",
"infocom/zork1/parser.zil",
"infocom/zork1/verbs.zil",
"infocom/zork1/syntax.zil",
"books/blackwood-horror/horror.zil",
"infocom/zork1/main.zil",
}You can modify this list to load different ZIL files or create your own adventure.
The ZIL runtime now supports a require-based loading system similar to moonscript, allowing you to load .zil files using Lua's standard require() function.
-- Initialize the ZIL loader
require "zil"
-- Now you can require .zil files just like Lua modules
-- This will automatically compile and load infocom/zork1/actions.zil
local actions = require "infocom.zork1.actions"When you require "zil":
- The ZIL loader is automatically installed into Lua's package system
- A
package.zilpathis created (similar topackage.path) that tells Lua where to find .zil files - When you
requirea module, Lua will search for both .lua and .zil files - If a .zil file is found, it's automatically compiled to Lua and executed
- The compiled module is cached by Lua's require system (no recompilation on subsequent requires)
require "zil" -- Initialize the loader
-- Load ZIL modules
local test = require "tests.test-require" -- Loads tests/test-require.zil
-- The compiled code is cached
local test2 = require "tests.test-require" -- Reuses cached versionFor a complete example, see examples/require_example.lua.
The zil module also provides utility functions:
local zil = require "zil"
-- Compile ZIL code to Lua
local lua_code = zil.to_lua('<ROUTINE FOO () <RETURN 1>>')
-- Load ZIL code from a string
local chunk = zil.loadstring('<ROUTINE BAR () <TELL "Hello">>')
-- Load and execute a ZIL file
zil.dofile("myfile.zil")
-- Manage the loader
zil.remove_loader() -- Remove the ZIL loader
zil.insert_loader() -- Re-insert the ZIL loaderBy default, .zil files are compiled to Lua in memory only. For debugging purposes, you can enable saving of the compiled .lua files:
local zil = require "zil"
-- Enable saving compiled .lua files for modules
zil.config.save_lua = true
-- Now when you require a .zil module, it will save the compiled .lua file
require "mymodule" -- Creates mymodule.zil.lua
-- Disable to stop saving files
zil.config.save_lua = falseWhen enabled, each .zil module loaded via require() will save its compiled Lua code to a .zil.lua file in the same directory. This is useful for:
- Debugging compilation issues
- Understanding how ZIL code translates to Lua
- Examining generated code for performance analysis
Note: The generated .zil.lua files are automatically excluded from git via .gitignore.
The ZIL runtime is modular and well-tested, with a compiler architecture inspired by TypeScript:
- Parser (
zilscript/parser.lua): Parses ZIL source code into AST - Compiler (
zilscript/compiler/): Compiles ZIL AST to Lua code (12 focused modules)- Core modules:
init,buffer,utils,value,fields,forms,toplevel,print_node - TypeScript-inspired modules ✨:
visitor,diagnostics,emitter,checker
- Core modules:
- Runtime (
zilscript/runtime.lua): Executes compiled Lua code - Bootstrap (
zilscript/bootstrap.lua): Core runtime functions and globals - Source Mapping (
zilscript/sourcemap.lua): Maps Lua errors back to ZIL source locations
See zilscript/compiler/README.md for detailed compiler module documentation.
- Source Mapping: Error messages reference ZIL source files, not generated Lua files (see SOURCE_MAPPING.md)
- Modular Compiler: Clean separation of concerns across 12 focused modules
- TypeScript-Inspired Architecture: Visitor pattern, diagnostic collection, semantic checking, and structured emission
- Test Infrastructure: 149+ unit test assertions plus comprehensive integration tests
- Test Assertions: Built-in test commands for verifying game state
Generated Lua files (with zil_ prefix) are created during compilation and excluded from git via .gitignore.
See individual game files for their respective licenses.