LUA before Lua: a self-hosting compiler on the Apple //e
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
Back in Entry 8, I mentioned Back to the Future because it came out days before Ms. Albright started her work. But that really was more of Back to the Future Part II: us here, in 2026, revisiting 1985. We're more on the original timeline here while we peer back to 1985 from 2026.
You see, Ms. Albright is in many ways my Flux Capacitor here. I've gone back and, with her idea, moved forward to build this time capsule; everything in this entry is, alas, not hers; it could never have been.
It would be a shame for her work to not see the light of day; I've spent as much time as I have on this write-up, and a corresponding talk for JawnCon 2026, simply because this gem shouldn't be lost to time on a broken hard drive image that nobody ever sees.
This is where I finally answer the question of, "what can we do, with modern technology, based on Ms. Albright's work?"
In her final rung, it's clear where Ms. Albright is headed. She's got a stub editor, written in LUA, that isn't quite complete; she's got multiple runtimes for different kinds of programs; she's got games that her students built in it, demonstrating its capability, and defining its rightful place in the educational flow of things. Give kids Logo. Augment with LUA, which teaches them to reach; it doesn't beat them down with structure like Pascal.
If she had attained that - and indeed, it's possible that she did and it's lost in this drive image's corruption, or went on to live on another machine - she had the full replacement for the Apple Pascal system. Edit in ProDOS in a more friendly editor, like what came with the final version of Merlin-8, to which she was clearly accustomed; compile in ProDOS natively; generating binaries right in ProDOS as well, available to use, copy, and distribute with no fuss.
So I've built on her work, bringing it to everyone in a simple, usable medium: the web.
Write LUA on the left, see it run in my 2e emulator on the right.
I've included all of the example code that exists in her archive; go ahead and play the Snake game she fretted about wasting her time in her kitchen, or play the full port of the Integer Basic game AppleTrek, which stretches to use her full memory model that uses a RAM expansion card as-built. You can see her editor running, as I finished it off; or, run the artifacts that I've built on top of the whole ecosystem.
Since Ms. Albright was keen to show how this ecosystem was better than the p-System, I thought there might be no better way to do that than to port Wizardy I, written in Apple Pascal, to LUA. There's a disk image called "Proving Grounds" which shows the capability.
I thought the Wizardry series was nice, but it was really the Ultima series that I loved to play. So I've also built an Ultima-like engine in LUA, and crafted a simple scenario called Chippewa Falls, WI in which you play Ms. Albright, buying computer parts to take them to her school. It's maybe a 15 minute game as-is, merely as a demonstration of what is possible here.
My last piece of code is her last as well: her Editor lives in two places, both in the "examples" section (so you can see the code itself) and as a disk image (where you can see it actually saving and restoring disk files).
Lastly: this whole page is, itself, a full Apple //e emulator. It's a WASM compiled version of Aiie, which has graduated from its original Teensy 4.1 embedded emulator build (still maintained!) and is now a full cross-platform desktop emulator, as well has having this web version for the Lua2e playground. Drop any .woz disk image on the web page and it will boot; or give the URL fragment your own web-based .WOZ disk image and it will load.
Thanks for making it this far - I was going to end on something meaningful about recovery, and craft, and people who build things that nobody asked for. But the whole of this started because of a teacher who wanted fifteen-year-olds to have a...
Read more »Ms. Albright pushed this fairly far, from 1984 to 1987, when her drive apparently suffered some catastrophic corruption. In the state I found in my imaging, the boot block was trashed; the directory structure corrupted; some file content lost. I may some day recover more from this beast - I suspect there's a UCSD pascal partition buried in here, which was a common pattern at the time - but, for now, this is where her story wraps up and mine really begins.
In 1987, Ms. Albright measured her LUA against UCSD Pascal. She found hers to be slightly slower, and re-optimized the same way that Apple Pascal did: wrote a 65C02 update to make the code smaller and more efficient, and then tested again.
From my own measurements, the jump to 65C02 is worth 23 percent. Apple shipped Pascal 1.3 in 1986 with an interpreter that checked for the new chip and used its instructions. The same trick applies here: replace that if/else dispatch ladder with a singleJMP (OPTAB,X) through a table of addresses, drop the LDY #0 from LDA (ptr), use STZ. Measured at 1 MHz on the same benchmark, 213 million cycles down to 164 million, with no bytecode changes at all.
Before her final rung, her benchmarks show that she just couldn't compete with Pascal's performance, which is a shame (the p-System is, fundamentally, a pig).
These are my timings from her matched programs, same //e, cycle counts from an emulator:
p-System hers LOOP 46,184,684 86,305,138 FIB 36,378,393 47,405,466 ARRAY 80,615,362 265,051,888 SORT 158,549,605 365,241,720
Roughly twice as slow. Reading the dispatch against the handler source tells us why, and it's not really interesting (or surprising); her machine calls a subroutine to take values off of the stack; another one to put a value back; and performs the same operation 13 times to walk a loop once.
All of which she dealt with in her final rung, and once I understood her motivation, I can see the excitement that must have been in her eyes.
She made three fundamental changes, all of which are invisible to the coder in LUA:
Her result is 2.42x faster after these, which lands it 17% faster than p-code; and with the 65C02 changes she made after, it is a whopping 30% faster.
p-System rung 12 LOOP 46,184,684 33,995,771 FIB 36,378,393 34,106,801 ARRAY 80,615,362 65,538,571 SORT 158,549,605 151,591,612
Looking at the historical path for Lua, and comparing it to what Ms. Albright's LUA did: Lua had the same challenge. With Lua 5.0, the stack machine was replaced with a register machine - buying the same savings by changing how operands are addressed rather than by fusing pairs. Same diagnosis; opposite prescription. And 16 years apart.
By 1987 the language has for and break, table constructors, multiple assignment, t.x, t[k], t:m(), string escapes, real lexical closures, and arequire that hands you back a module. The compiler is 42KB of its own language and compiles itself - in a little over two hours at 1 MHz.
So: is it Lua? Here is the comparison. You are free to make your own determination; it cuts both ways.
Where she is ahead, with the Lua release that eventually got there:
Plus, of course, self-hosting - which Lua has never had. Its compiler is C and always has been.
Where she never arrives at all: repeat until, multiple return values, varargs, metatables, coroutines, floating point. All of those are in Lua, most of them from the first release.
So I think this is not a story about someone who invented Lua nine years early. It is a story about someone who invented a different language, which I find much more interesting.
And the unflattering reading deserves to be said out loud, because it is at least half correct.
Several of the things she reaches early are forced by the environment she lives in.
Integers because the 6502 has no FPU.
No globals because there is no global table to put them in.
One return value because the return protocol carries only one cell.
I'd posit that constraint is doing a great deal of the work that looks, from outside, like foresight. But you're free to have your own opinions on the matter; art is in the eye of the beholder.
Back to the Future opened on the third of July, 1985. The first compiler on this drive is stamped the eighth.
She saw the movie, or she didn't. Five days later she started writing a compiler by hand, in her own bytecode, because that is still the only thing the machine runs. And when files start coming out the other side of it, they have a new name:
Now, I know what you're thinking. You're doing some mental arithmetic.
The language you are thinking of was written in 1993, in Rio de Janeiro, by three very different people. The scholarly consensus here, which is to say me, alone, in a garage, has decided that this is purely a coincidence, for her name is Louise Ursula Albright.
She spends three more weekends on this, and boy, does this become even more interesting.
By this point, I'm really in to it. Late nights. Early mornings. Lunch breaks. Whenever I can find time to tear apart some of what she's done, I'm captive to her song.
In August 1985 the compiler is rewritten in its own language as a single .LUA source file. The hand-assembled compiler is used exactly one more time, on the //e, to translate that source into bytecode. After that, the compiler compiles its own source, and what comes out is byte-for-byte what the hand compiler produced.
4,202 bytes in. 4,202 bytes out. A shining piccolo in the vast array of kettle drums.
That equality is exactly the guarantee Ken Thompson describes in Reflections on Trusting Trust, which came out in 1984 and which I have no evidence whatsoever that she read.
You can see what the heap bought her in those same three weeks. Same program, before and after:
-- July 1985, no upvalues: the function is handed itself local fact = function(self, n) return n * self(self, n - 1) end -- August 1985, with upvalues: it calls itself by name local fact = function(n) return n * fact(n - 1) end
When you start writing your own language, everyone starts with the top one. You tell yourself it's temporary, and maybe that's true, or maybe you stop playing around with the language before you get farther.
In three weeks she was one of the ones that persisted.
From here, every compiler on the ladder is written in the language the rung below accepts and compiled by it, and the only hand-authored bytecode in the whole process is the initial bootstrap seed machine.
Brava, Ms. Albright.
Louise Albright did not call these rungs. She did not call them anything. It was me that painstakingly separated the files and reconstructed the narrative of what got built when; this is the organizational pattern that my brain applied to her data. Treat it accordingly.
In large part, I am the benefactor of her decision to buy a clock card. No, the Apple //e had no built-in clock; it had no way to, by default, timestamp files. Some programs asked you when you entered them what time and date it was.
Others just blindly accepted that they had no idea.
From what I see, I'm pretty sure she had a clock card. There's a fairly consistent set of dates, that play out a tune if you know how to look for the melody.
Thanksgiving. Christmas break. Summer. Spring break. Labor Day weekend. Thanksgiving. Christmas break. Not one of them falls during a term. She built the entire thing on school vacations.
The next rung is Christmas break, 1984, and its two outputs print like this:
1 2 6 24 120
And then
0 1 1 2 3 5 8 13 21 34 55
Take a minute to consider each of those. I bet you'll recognize them.
Factorials and Fibonacci, which is what everybody writes when they want to know whether their call stack works. She had a machine nobody else would ever use, a language with no name yet, and exactly one user, and she tested it the way you would have tested it. Or at least the way I would have tested it.
By the end of 1984 the machine has stack operations, local variables, arithmetic, control flow, simple I/O, and closures in the sense that functions are values that can be passed around.
Much like P.D.Q. Bach's left-handed sewer flute: this plays music, but it is not elegant. It is clunky, bespoke and not especially functional. What she is doing here is the final project of a good undergraduate compilers course. The difference is that nobody assigned it, nobody graded it... and she kept going for three more years.
This virtual machine of Ms. Albright's is not packaged like UCSD's, but in spirit it is the same animal: a stack machine with byte-coded instructions - one opcode plus inline operands; locals addressed by slot rather than by name; one constant pool per code unit, referenced by index; conditional jump on a popped boolean; 16-bit integer math.
Where it differs is more interesting, and some of it is ambition while other parts are just immaturity:
And then there is this one comment in the file, which shapes my opinion of everything that follows.
VPUSHB 11 ; apple home()
She's fundamentally calling the Apple ][ specific functionality a library. On the first weekend that her virtual machine exists; with no actual language for this to be a library in. There is no opcode in her instruction set that knows what an Apple is. Everything that touches the hardware, the text page, the keyboard strobe, the monitor'sHOME, sits behind a numbered call. Three of them at this point: poke is 1, key is 10, home is 11.
Everything on this drive that impressed me later is telegraphed by that one comment, and we will come back to it in a few years of Ms. Albright's time.
So, back to what's in the drive image: the myriad .S assembly files were, at first blush, not particularly interesting.
With Merlin already on the disk, and a bunch of .S files strewn around, there's nothing particularly interesting here. Yes, it's a bunch of assembly.
... for those that know 6502, that's all rather droll. She had something to do, did it, and I couldn't really care less about how. Not yet, at least.
But once I looked at HELLO.S, I became... curious.
Those are not traditional opcodes. What the heck *is* this? The 6502 has 56 instructions, which some of you will recognize on sight. Not one of those 56 is in this program.
The trick, of course, is on line 6 where she does `USE OPCODES` - a set of macro definitions that still don't mean anything to me; then line 7, the `PUT MACHINE` is an include of the entire MACHINE.S listing.
Wait a minute.
She wrote a virtual machine.
VM technology had existed in this form since the 1960s, and she wrote one in 1984, on a machine with 128 kilobytes, over a long Thanksgiving weekend, as far as anybody can tell, for fun.
For those of you that did not make a face and smell the smoke when I talked about the RIFA caps: this is not the kind of virtual machine you're thinking of. That kind is backed by a gargantuan vendor product. This is the kind that pretends to be a processor that does not exist, so you can write code for the exact computer you wish you had.
To understand what Ms. Albright built in this drive image, you have to understand what she was reacting to.
Pascal was designed by Niklaus Wirth in 1968 as a teaching language: strong typing and structure, deliberately forcing a programmer to think systematically about a program rather than just making it work. It was aimed squarely at two anti-patterns of the day, FORTRAN and BASIC goto-spaghetti, and the assembly and COBOL "just execute these instructions" style.
Then UCSD had a problem. Computing work was being done on the university's big expensive central machines, while students increasingly had access to cheap microcomputers, and every microcomputer had a different processor and architecture.
Ken Bowles's answer, in 1977, is the thing this whole project jives with: do not compile to machine-specific code. Compile to an abstract P-code, and build a virtual machine for it on each platform. In 1979 Apple shipped Apple Pascal and made it the language of the platform, and in 1984 the College Board made Pascal the AP Computer Science language, which is how it ended up in her classroom five periods a day.
So why the hate? The p-System was a complete contained development environment: OS, editor, compiler, runtime, debugger, file management, utilities. The language was verbose and formal. The environment was heavy and difficult to work with from outside.
You were either in Pascal, or you were outside of it. Working between the Pascal environment and the established ProDOS environment was truly messy.
I worked in Apple Pascal once - the summer of 1985, just as Back to the Future hit theaters - and one of the reasons I loved that movie so much was that it helped me escape from it.
So, 2026 comes around. I'm building a new workshop, moving old things out of storage, sorting stuff, picking up old projects along the way.
And this is really the first time I spent any time at all looking at what was actually *in* that hard drive image.
The ProFile itself has failed; a capacitor on its logic board is probably shorted, and that's now another future problem. And the interface card needs its own repair saga... this story isn't about the hardware any more from this point on. It's about a hard drive image.
This is where I need to make a deal with you, the reader.
I can't prove where this drive came from; its provenance is lost. I can prove that it has run. I have evidence that I sucked out its contents. And here is the deal: if we accept that this hard drive image came out of Chippewa Falls, Wisconsin, then everything else follows with the evidence.
So let me introduce the protagonist of this dissertion: Louise Ursula Albright, a high school mathemetics teacher who also taught "computers," and an apparent hater of Pascal. And I mean, who isn't? She's in good company.
The first look through the hard drive contents was underwhelming. AppleWorks, Copy II Plus, very normal stuff. A directory of obvious assembly code files for Merlin-8. Nothing that would make me want to spend time looking at the contents.
But digging in to the image a little deeper with my wozit utility, part of my wozzle library, I found that the image was at least slightly corrupted. Which lead to a multi-day effort of extracting, correcting, sorting and filing.
The first file that really caught my eye was an AppleWorks spreadsheet that ended with the words, "The Buick can wait."
Pricing the ProFile against a car - not a woman of unlimited means, but certainly one who means to do what she wants. I like her already.
A tithe is traditionally 10% of one's salary. That's what this drive cost her, near enough; and I'm aware that I'm about to propose something of faith to an audience where my average reader might own more computers than they do chairs.
We all tithe. Maybe we don't call it that, and some more than others; the results of our tithes just tend to arrive in boxes.
Yes, Ms. Albright and I share a set of beliefs that might as well be a religion.
The ProFile was Apple's first hard drive. Released in 1981, the WHOPPING 5MB version - targeted at the Apple /// - came in at about $3,500. The 10MB successor was more like $3,999 - roughly $17,000 in 2026 money, or about a tenth of a teacher's salary in 1984. Keep that in mind for the rest of this story; it will matter, later.

So after cleaning it all up, giving it a quick visual inspection, and deciding it was time to power on the beast, it did something it had been waiting for 40 years to do.
It let out the magic smoke.
Now, I'm sure most of you reading this just made a face. And can smell the smell of those RIFAs. For everyone else: these are line filter capacitors, which, over time, crack, take on moisture, and eventually release a quantity of smoke that has been waiting since 1983 to leave. No explosion; more of a resignation. We're done.
So I replaced them, of course.
The sheer quantity of pictures I have of what should have been a terribly boring exercise should tell you something about my state of mind. This was not just something to keep me occupied; every facet of it was like an archaeological dig.
And in the end, it worked! Which is to say, it powered up. Because it didn't actually work, which is worse: a thing that is dead, is a project. A thing that almost works is a time sink.
Now, the thing hanging off the back is another project here, that I documented at the time - the ProFile 10 Teensy-based reader. The Apple itself wouldn't read it, spitting out a variety of error messages like this:
... not very helpful, so I split the problem in half. And the reader circuit told me which half was at fault - the drive itself clearly operated, so either the //e still had some problem or the interface card was an issue.
The images I pulled off the drive went in to a folder to be forgotten for 5 years. The ProFile was prettily stacked with the rest of the //e, which got some use, but the ProFile was just for show. The interface card took up residence in an anti-static bag. And the rest of the pandemic played out around it.
Create an account to leave a comment. Already have an account? Log In.
Become a member to follow this project and never miss any updates