Skip to content

Repository files navigation

Flynt 1 beta 1

A programming language built from scratch. The compiler is flyntc, source files use .flt.

A companion project to NanoOs: the language is built for an operating system with its own bootloader, its own kernel and its own libc. That means the compiler must be able to run inside that system, not only on a host.

beta is not decoration. Programs run on an interpreter; there is no machine code generator and no type checking yet. A version number that lies about readiness devalues every other promise the project makes.

./utils/build-script --test        # build and test
./build/flyntc --run test/hello.flt

Layout

Arranged after the Swift repository, and not out of imitation: this split survives moving the compiler inside another operating system, while a flat directory does not.

Directory Contents Language
stdlib/core standard library Flynt
lib, include, tools compiler: lexer, tree, parsing, evaluation C++
runtime runtime that generated code will link against C
utils one-command build Python
platform/darwin system information on macOS Objective-C
test tests C++ and Flynt

Why the library is written in Flynt itself. A library written in the language is the only honest proof that the language is usable. A compiler whose library is written in some other language proves nothing: it may be missing exactly what real code needs, and nobody would notice.

Why the compiler is C++. Classes and containers without a runtime, builds everywhere, no garbage collector. The same reasons the Swift compiler is written in C++.

Why the runtime is C and not C++. Generated code will call it directly, with no C++ alongside. C++ carries invisible baggage: stack unwinding, type tables, static initialisation order. A C runtime drags none of that in — it can be linked even against the NanoOs kernel.

Three principles

Arrived at after studying how the Swift parser is built (the swiftlang/swift-syntax repository, Apache 2.0). No code was taken from it — what was taken are the principles and the reasoning behind them.

1. Not a single byte is lost

A typical compiler throws away whitespace and comments right after lexing. The price shows up later: formatters, syntax highlighting and renaming each need their own parse, one that keeps whitespace, and it drifts apart from the main one.

So whitespace and comments are attached to tokens as trivia. That gives a property a machine can check: concatenating all tokens back reproduces the source file byte for byte. Such a test needs no expected output — the expected output is the input file itself, and any text will do, including deliberately broken text.

2. An error does not stop parsing

A parser that stops at the first error is only good for batch builds. An editor needs to parse unfinished text: while someone types, the file is syntactically invalid half of the time.

Instead of stopping, the parser builds "missing" and "unexpected" nodes. A tree always comes out, even out of garbage.

The cost is paid immediately. A resilient parser must make forward progress at every step, otherwise it does not crash but hangs — which is worse than crashing, because there is no sign of where. That mistake was made here and caught by a test on the input +++===.

3. Parsing does not depend on meaning

In C, the expression (x)*y cannot be parsed without knowing whether x is a type. That forces a name table into the parser and makes declaration order affect the grammar. Flynt has no such dependency.

Interpreter before code generator

A code generator answers two questions at once: what does the program mean, and how is that expressed in machine instructions. A mistake in the first is indistinguishable from a mistake in the second.

An interpreter answers only the first. Once it gives correct answers, the meaning of the language is pinned down — and the generator is then checked against it: one program must produce one result. That turns debugging the generator from guesswork into comparison.

Language recognition on GitHub

For GitHub to print "Flynt" in the language bar, the language has to be accepted into github/linguist. The submission material is in docs/linguist: the languages.yml entry, the highlighting grammar, and code samples.

To be honest about what is missing: Linguist accepts a language once it is actually in use — their bar is measured in hundreds of repositories by different authors. That is the one requirement no amount of work on the code can satisfy.

What Flynt will not be

  • Not a replacement for C in the kernel. The NanoOs kernel is written in C and will stay that way.
  • Not a garbage-collected language. A system with no swap and manual memory management is no place for collection pauses.
  • Not a copy of Swift. What was taken are parser construction techniques, not the language.

About

Flynt beta 1

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages