diff --git a/README.md b/README.md index 60f250f..a4f0c34 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ fn main() { Operator precedence that does not bite (`x & 1 == 0` means what it says). - **Errors that talk like a person:** ``` - game.fn:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert) + game.fch:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert) 3 | i32 y = x | ^ ``` @@ -60,9 +60,9 @@ nix-shell # or install LLVM 21 + libclang + cmake + ni cmake -S . -B build -G Ninja ninja -C build -./build/finch run examples/hello.fn -./build/finch build examples/tour.fn -o tour && ./tour -tests/run.sh # 58 passed, 0 failed +./build/finch run examples/hello.fch +./build/finch build examples/tour.fch -o tour && ./tour +tests/run.sh # 59 passed, 0 failed tests/boot.sh # the compiler written in Finch builds itself ``` @@ -97,16 +97,16 @@ Pick the guide that fits you: | File | Shows | |---|---| -| [`examples/hello.fn`](examples/hello.fn) | the smallest program | -| [`examples/tour.fn`](examples/tour.fn) | variables, functions, conditions, loops | -| [`examples/guess.fn`](examples/guess.fn) | a guessing game: input, loops, C's `rand` | -| [`examples/todo.fn`](examples/todo.fn) | structs, arrays, strings and files | -| [`examples/structs.fn`](examples/structs.fn) | structs, arrays of structs, a linked list with `new`/`free` | -| [`examples/types.fn`](examples/types.fn) | sized numbers and pointers | -| [`examples/c_import.fn`](examples/c_import.fn) | `printf`, `math.h`, `malloc`/`free`, `stderr` | -| [`examples/window.fn`](examples/window.fn) | a GLFW + OpenGL window | -| [`examples/raylib.fn`](examples/raylib.fn) | raylib with C structs by value | -| [`examples/llvm.fn`](examples/llvm.fn) | Finch building LLVM IR through the LLVM-C API | +| [`examples/hello.fch`](examples/hello.fch) | the smallest program | +| [`examples/tour.fch`](examples/tour.fch) | variables, functions, conditions, loops | +| [`examples/guess.fch`](examples/guess.fch) | a guessing game: input, loops, C's `rand` | +| [`examples/todo.fch`](examples/todo.fch) | structs, arrays, strings and files | +| [`examples/structs.fch`](examples/structs.fch) | structs, arrays of structs, a linked list with `new`/`free` | +| [`examples/types.fch`](examples/types.fch) | sized numbers and pointers | +| [`examples/c_import.fch`](examples/c_import.fch) | `printf`, `math.h`, `malloc`/`free`, `stderr` | +| [`examples/window.fch`](examples/window.fch) | a GLFW + OpenGL window | +| [`examples/raylib.fch`](examples/raylib.fch) | raylib with C structs by value | +| [`examples/llvm.fch`](examples/llvm.fch) | Finch building LLVM IR through the LLVM-C API | | [`boot/`](boot/) | the Finch compiler, written in Finch | ## Roadmap diff --git a/README.pl.md b/README.pl.md index 135b94c..c7ff4ba 100644 --- a/README.pl.md +++ b/README.pl.md @@ -40,7 +40,7 @@ fn main() { powodować niezdefiniowane zachowanie. Priorytety operatorów nie gryzą (`x & 1 == 0` znaczy to, co widać). - **Błędy mówią po ludzku:** ``` - gra.fn:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert) + gra.fch:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert) 3 | i32 y = x | ^ ``` @@ -60,9 +60,9 @@ nix-shell # albo zainstaluj samodzielnie LLVM 21 + lib cmake -S . -B build -G Ninja ninja -C build -./build/finch run examples/hello.fn -./build/finch build examples/tour.fn -o tour && ./tour -tests/run.sh # 58 passed, 0 failed +./build/finch run examples/hello.fch +./build/finch build examples/tour.fch -o tour && ./tour +tests/run.sh # 59 passed, 0 failed tests/boot.sh # kompilator napisany w Finchu buduje sam siebie ``` @@ -97,16 +97,16 @@ Wybierz przewodnik dla siebie: | Plik | Pokazuje | |---|---| -| [`examples/hello.fn`](examples/hello.fn) | najmniejszy program | -| [`examples/tour.fn`](examples/tour.fn) | zmienne, funkcje, warunki, pętle | -| [`examples/guess.fn`](examples/guess.fn) | gra w zgadywanie: wejście, pętle, `rand` z C | -| [`examples/todo.fn`](examples/todo.fn) | struktury, tablice, teksty i pliki | -| [`examples/structs.fn`](examples/structs.fn) | struktury, tablice struktur, lista wiązana z `new`/`free` | -| [`examples/types.fn`](examples/types.fn) | liczby z rozmiarem i wskaźniki | -| [`examples/c_import.fn`](examples/c_import.fn) | `printf`, `math.h`, `malloc`/`free`, `stderr` | -| [`examples/window.fn`](examples/window.fn) | okno GLFW + OpenGL | -| [`examples/raylib.fn`](examples/raylib.fn) | raylib ze strukturami C przez wartość | -| [`examples/llvm.fn`](examples/llvm.fn) | Finch budujący LLVM IR przez API LLVM-C | +| [`examples/hello.fch`](examples/hello.fch) | najmniejszy program | +| [`examples/tour.fch`](examples/tour.fch) | zmienne, funkcje, warunki, pętle | +| [`examples/guess.fch`](examples/guess.fch) | gra w zgadywanie: wejście, pętle, `rand` z C | +| [`examples/todo.fch`](examples/todo.fch) | struktury, tablice, teksty i pliki | +| [`examples/structs.fch`](examples/structs.fch) | struktury, tablice struktur, lista wiązana z `new`/`free` | +| [`examples/types.fch`](examples/types.fch) | liczby z rozmiarem i wskaźniki | +| [`examples/c_import.fch`](examples/c_import.fch) | `printf`, `math.h`, `malloc`/`free`, `stderr` | +| [`examples/window.fch`](examples/window.fch) | okno GLFW + OpenGL | +| [`examples/raylib.fch`](examples/raylib.fch) | raylib ze strukturami C przez wartość | +| [`examples/llvm.fch`](examples/llvm.fch) | Finch budujący LLVM IR przez API LLVM-C | | [`boot/`](boot/) | kompilator Fincha napisany w Finchu | ## Plan rozwoju diff --git a/boot/ast.fn b/boot/ast.fch similarity index 100% rename from boot/ast.fn rename to boot/ast.fch diff --git a/boot/gen.fn b/boot/gen.fch similarity index 100% rename from boot/gen.fn rename to boot/gen.fch diff --git a/boot/lexer.fn b/boot/lexer.fch similarity index 100% rename from boot/lexer.fn rename to boot/lexer.fch diff --git a/boot/main.fn b/boot/main.fch similarity index 83% rename from boot/main.fn rename to boot/main.fch index 7071413..0e985e6 100644 --- a/boot/main.fn +++ b/boot/main.fch @@ -1,7 +1,7 @@ // finch-boot: the Finch compiler written in Finch. // -// finch-boot build [-o name] compile a program -// finch-boot ir print the LLVM IR +// finch-boot build [-o name] compile a program +// finch-boot ir print the LLVM IR // // It reads the program and the modules it imports, checks it, writes LLVM IR as text // and lets clang turn that into a program, linked with Finch's C runtime. @@ -42,6 +42,11 @@ struct Loader { fn load(ptr[Loader] l, str path, str module) { if !file_exists(path) { if module.len > 0 { + old := path.sub(0, path.len - 4) + ".fn" + if file_exists(old) { + print("error: found " + old + ", but Finch files now end in .fch: rename it to " + path) + exit(1) + } print("error: can't find the module '" + module + "' (looked for " + path + ")") } else { print("error: can't open '" + path + "'") @@ -59,15 +64,15 @@ fn load(ptr[Loader] l, str path, str module) { for name in imports { if !l.loaded.contains(name) { l.loaded.push(name) - load(l, dirOf(path) + "/" + name + ".fn", name) + load(l, dirOf(path) + "/" + name + ".fch", name) } } } fn usage() { print("finch-boot - the Finch compiler written in Finch") - print("usage: finch-boot build [-o name]") - print(" finch-boot ir ") + print("usage: finch-boot build [-o name]") + print(" finch-boot ir ") exit(1) } diff --git a/boot/parser.fn b/boot/parser.fch similarity index 100% rename from boot/parser.fn rename to boot/parser.fch diff --git a/docs/en/for-beginners.md b/docs/en/for-beginners.md index 6f17b69..f37b34b 100644 --- a/docs/en/for-beginners.md +++ b/docs/en/for-beginners.md @@ -92,11 +92,11 @@ fn main() { } ``` -3. Save it in the `Finch` folder as **`hello.fn`**. The `.fn` at the end tells everyone it is a Finch program. +3. Save it in the `Finch` folder as **`hello.fch`**. The `.fch` at the end tells everyone it is a Finch program. 4. In the Terminal, type: ```sh -./build/finch run hello.fn +./build/finch run hello.fch ``` You will see: @@ -652,14 +652,14 @@ fn main() { ``` ``` -hello.fn:3:11: error: there is no variable named 'agee' +hello.fch:3:11: error: there is no variable named 'agee' 3 | print(agee) | ^ ``` How to read it: -- `hello.fn` is the file, +- `hello.fch` is the file, - `3` is the **line** number, - `11` is how far into the line (the **column**), - then the explanation, and the line itself with a `^` pointing at the problem. @@ -816,7 +816,7 @@ fn main() { } ``` -`return` inside `main` ends the program. (A version with a random number is in `examples/guess.fn`.) +`return` inside `main` ends the program. (A version with a random number is in `examples/guess.fch`.) ### Project 7: Class average diff --git a/docs/en/for-engineers.md b/docs/en/for-engineers.md index 2e60de8..68bedff 100644 --- a/docs/en/for-engineers.md +++ b/docs/en/for-engineers.md @@ -48,7 +48,7 @@ Finch is a single-pass front end in front of LLVM: type checking and IR generati over the AST, with no intermediate representation of its own. ``` - main.fn ──► Loader::load() ── lex() ── parse() ──► Program (+ each imported module, recursively) + main.fch ──► Loader::load() ── lex() ── parse() ──► Program (+ each imported module, recursively) │ all `import "x.h"` ──► importHeaders() (libclang) ──► CImports │ @@ -100,7 +100,7 @@ Design decisions that shape the rest: | `src/abi.cpp` | 310 | System V x86-64 classification, C calls with structs by value, C-callable thunks | | `src/main.cpp` | 390 | Driver: CLI, loader, target machine, O2, object emission, runtime cache, linking, link-error advice, `run` | | `runtime/finch_rt.c` | 440 | The runtime library (§12) | -| `boot/*.fn` | 3080 | The self-hosted compiler (§17) | +| `boot/*.fch` | 3080 | The self-hosted compiler (§17) | --- @@ -198,7 +198,7 @@ All nodes are in `src/ast.h`: small class hierarchies with an explicit `kind`, d | `Member` | `MemberExpr` | `obj`, `field` (`.x`, `.len`, `.ptr`, `.value`) | | `Index` | `IndexExpr` | `obj`, `index` | | `ArrayLit` | `ArrayLitExpr` | `elems` | -| `Method` | `MethodExpr` | `obj`, `name`, `args`, `argNames`; also `module.fn(...)` | +| `Method` | `MethodExpr` | `obj`, `name`, `args`, `argNames`; also `module.fch(...)` | | StmtKind | Node | |---|---| @@ -236,7 +236,7 @@ Equality is structural; two `Struct`s are equal iff they share `info`. `Loader::load(path, module, from)` in `main.cpp` reads a file, appends it to `g_files` (positions carry the file index in `Pos::file`), lexes and parses it, then loads each `import name` that wasn't seen yet: -`name.fn` next to the importing file, or in a `FINCH_PATH` folder. The result is a `std::vector`, +`name.fch` next to the importing file, or in a `FINCH_PATH` folder. The result is a `std::vector`, main file first. Cycles are fine: a module is marked loaded before its own imports are followed. All files become **one LLVM module**. Each Finch module has a `ModuleScope` (functions, structs, the set @@ -597,7 +597,7 @@ string building (`concat`, `from_int/uint/float/char/bool`, `sub`, `trim`, `uppe ### 13.1 Importing headers `importHeaders(imports, dirs)` parses each `import "x.h"` as its own translation unit from an in-memory -`#include "x.h"`, with `-x c -std=gnu11`, `-I` for every `.fn` file's folder, and `-isystem` for each +`#include "x.h"`, with `-x c -std=gnu11`, `-I` for every `.fch` file's folder, and `-isystem` for each directory the system C compiler searches (read from `$CC -E -v -x c /dev/null`, which is what makes it work on NixOS). `gnu11` because glibc hides `M_PI` and friends in strict ISO mode. @@ -647,7 +647,7 @@ type and attributes, and rebuilds struct results the same way. struct parameters from registers or `byval` memory, calls the Finch function and lowers its result. Only C-compatible signatures are accepted. -`tests/run/c_structs.fn` exercises `{float,float}`, `{float,float,float}`, `{u8×4}`, `{double,int}`, +`tests/run/c_structs.fch` exercises `{float,float}`, `{float,float,float}`, `{u8×4}`, `{double,int}`, `{i64,i64}`, a 24-byte struct, a struct with a `char[8]`, nested structs, register exhaustion with 13 struct arguments, and callbacks taking and returning structs, against a C library compiled with `link "abi.c"`. The results match the same calls made from C. @@ -655,7 +655,7 @@ struct arguments, and callbacks taking and returning structs, against a C librar ### 13.4 Linking C code `link "name"` tries `pkg-config --libs name`, then `-lname`. `link "file.c"` compiles the file (relative -to the `.fn` file) with `$CC -O2 -fPIC -c` into a temporary object; `.o` and `.a` files are passed +to the `.fch` file) with `$CC -O2 -fPIC -c` into a temporary object; `.o` and `.a` files are passed through. When linking fails, `linkFailed()` maps undefined symbols back to the header that declared them and prints the `link` line to add. @@ -666,7 +666,7 @@ and prints the `link` line to add. - **Target:** `sys::getDefaultTargetTriple()`, CPU `generic`, `Reloc::PIC_`. The data layout is set on the module before any IR is built (alignment of loads/stores depends on it). - **Optimization:** `PassBuilder::buildPerModuleDefaultPipeline(O2)`: clang's `-O2` middle end. `-O0` - skips it (`finch ir file.fn -O0` shows `Codegen`'s raw output). + skips it (`finch ir file.fch -O0` shows `Codegen`'s raw output). - **Emission:** legacy `PassManager` + `addPassesToEmitFile(ObjectFile)`. - **Linking:** `$CC prog.o rt.o [user objects] -lm [libs]`. On Nix the cc wrapper turns `-L` paths into `RPATH`, so programs run without `LD_LIBRARY_PATH`. @@ -707,11 +707,11 @@ there's an obvious fix, how to fix it. There are no warnings. An LLVM verifier f | File | Contents | |---|---| -| `boot/lexer.fn` | the lexer (tokens are `{kind, text, line, col, nl}`; kinds are words, keywords and operators are their own kind) | -| `boot/ast.fn` | `Type` (`kind`, `elem` as a 0/1-element array, `name`, `module`), one generic `Node` for everything, `Program` | -| `boot/parser.fn` | the same grammar and newline rules as the C++ parser, precedence climbing for binary operators | -| `boot/gen.fn` | type checker + **textual LLVM IR** generator: scopes, places, coercions, copies, helpers, printing, runtime checks, array/str methods | -| `boot/main.fn` | loader for modules and the driver: writes `.ll`, runs `clang -O2 file.ll runtime/finch_rt.c` | +| `boot/lexer.fch` | the lexer (tokens are `{kind, text, line, col, nl}`; kinds are words, keywords and operators are their own kind) | +| `boot/ast.fch` | `Type` (`kind`, `elem` as a 0/1-element array, `name`, `module`), one generic `Node` for everything, `Program` | +| `boot/parser.fch` | the same grammar and newline rules as the C++ parser, precedence climbing for binary operators | +| `boot/gen.fch` | type checker + **textual LLVM IR** generator: scopes, places, coercions, copies, helpers, printing, runtime checks, array/str methods | +| `boot/main.fch` | loader for modules and the driver: writes `.ll`, runs `clang -O2 file.ll runtime/finch_rt.c` | It supports the core language: `int float bool char str`, `[]T`, structs (defaults, named/positional constructors), `ptr[T]`/`addr`/`new`/`free`/`null`, all statements except `defer`, modules, and the @@ -753,9 +753,9 @@ with the expected one. It takes about 2.3 s for the self-hosted compiler to comp ## 19. Testing -- `tests/run.sh`: every `tests/run/*.fn` with `fn main` must print exactly its `.out` (stdin from `.in` - if present); files without `main` are modules or helpers. Every `tests/fail/*.fn` must fail with the text - from its `// expect:` line. Currently **58 passed, 0 failed**. +- `tests/run.sh`: every `tests/run/*.fch` with `fn main` must print exactly its `.out` (stdin from `.in` + if present); files without `main` are modules or helpers. Every `tests/fail/*.fch` must fail with the text + from its `// expect:` line. Currently **59 passed, 0 failed**. - `MEMCHECK=1 tests/run.sh`: the same, plus valgrind on every program (no leaks, no invalid access). - `tests/boot.sh`: the self-hosting fixpoint and the subset run (§17). @@ -787,7 +787,7 @@ with the expected one. It takes about 2.3 s for the self-hosted compiler to comp | Function | Does | |---|---| -| `Loader::load` / `findModule` | read, lex, parse a file and recursively its modules / locate `name.fn` | +| `Loader::load` / `findModule` | read, lex, parse a file and recursively its modules / locate `name.fch` | | `hostMachine`, `optimize`, `emitObject` | target machine, O2 pipeline, object file | | `runtimeObject` | compile and cache the runtime | | `capture`, `libFlags`, `link` | run a command / pkg-config or `-l` / the link step, compiling `link "x.c"` files | @@ -858,7 +858,7 @@ with the expected one. It takes about 2.3 s for the self-hosted compiler to comp **A built-in function:** add the name to `isBuiltin()`, handle it in `call()`, implement it (in IR, or as a runtime function declared in `rt()`'s table), add `tests/run/` and `tests/fail/` cases. If it should -exist in the self-hosted compiler too, add it to `boot/gen.fn`'s `call()` and `runtimeDecls()`. +exist in the self-hosted compiler too, add it to `boot/gen.fch`'s `call()` and `runtimeDecls()`. **An array or str method:** add a branch in `arrayMethod()` or the str part of `method()`; if it changes the array, add its name to the `changing` sets in `method()` and `mutatesExpr()`, so borrowing stays correct. diff --git a/docs/en/for-technicians.md b/docs/en/for-technicians.md index 282b752..98ce4cc 100644 --- a/docs/en/for-technicians.md +++ b/docs/en/for-technicians.md @@ -38,7 +38,7 @@ compiler works inside. For that, see the [guide for engineers](for-engineers.md) ## 1. What Finch is -Finch is a **compiled** programming language. The `finch` tool translates your `.fn` +Finch is a **compiled** programming language. The `finch` tool translates your `.fch` file into a real program (a native executable, like the ones made from C), using the **LLVM** compiler toolkit, the same backend that powers clang, Rust and Swift. @@ -106,9 +106,9 @@ Finch's small runtime library, which is kept in `~/.cache/finch`. Set `CC` to us ## 3. The finch command ``` -finch run [args...] compile and run right away -finch build [-o name] compile into a program (default name: the file's name) -finch ir print the LLVM IR (for the curious) +finch run [args...] compile and run right away +finch build [-o name] compile into a program (default name: the file's name) +finch ir print the LLVM IR (for the curious) finch version show the version options: @@ -120,10 +120,10 @@ options: Examples: ```sh -finch run hello.fn # prints the output -finch run tool.fn input.txt -v # arguments after the file go to the program -finch build game.fn -o mygame # creates ./mygame -finch build game.fn -g -O0 # a build for the debugger +finch run hello.fch # prints the output +finch run tool.fch input.txt -v # arguments after the file go to the program +finch build game.fch -o mygame # creates ./mygame +finch build game.fch -g -O0 # a build for the debugger ``` `finch run` passes on your program's exit code. If the program crashes, it says how @@ -139,7 +139,7 @@ finch build game.fn -g -O0 # a build for the debugger several lines */ import "math.h" // C headers (optional), at the top -import shapes // Finch modules (optional): shapes.fn next to this file +import shapes // Finch modules (optional): shapes.fch next to this file link "m" // C libraries or C files to link (optional) struct Point { // your own types @@ -502,11 +502,11 @@ Using `.value`, `.field` or `[i]` on a `null` pointer **stops the program** with ## 16. Modules -Split a program into files. `import shapes` loads `shapes.fn` from the same folder (or from a +Split a program into files. `import shapes` loads `shapes.fch` from the same folder (or from a folder listed in the `FINCH_PATH` environment variable, separated by `:`). ```c -// shapes.fn +// shapes.fch struct Box { float w float h @@ -518,7 +518,7 @@ fn area(Box b) -> float { ``` ```c -// main.fn +// main.fch import shapes fn main() { @@ -540,7 +540,7 @@ fn main() { ```c import "stdio.h" import "GLFW/glfw3.h" // a path inside the system include folders -import "mylib.h" // a header next to your .fn file +import "mylib.h" // a header next to your .fch file ``` Finch reads the header with **libclang** (clang's C parser) and makes these usable: @@ -554,7 +554,7 @@ Finch reads the header with **libclang** (clang's C parser) and makes these usab ```c link "glfw" // uses libglfw.so (pkg-config is asked first, if installed) -link "helpers.c" // compile and link your own C file (next to the .fn file) +link "helpers.c" // compile and link your own C file (next to the .fch file) link "prebuilt.a" // or an object file / static library ``` @@ -617,7 +617,7 @@ Its parameters must be C types (numbers, pointers, C structs). ### Compile errors ``` -game.fn:12:9: error: 'score' must be int, but this is str +game.fch:12:9: error: 'score' must be int, but this is str 12 | score = "high" | ^ ``` @@ -643,9 +643,9 @@ Instead of undefined behavior (as in C), Finch stops with a message and exit cod ## 19. Debugging ```sh -finch build game.fn -g -O0 -o game +finch build game.fch -g -O0 -o game gdb ./game -(gdb) break game.fn:12 +(gdb) break game.fch:12 (gdb) run (gdb) bt # where are we, through which functions (gdb) info locals # all variables @@ -665,7 +665,7 @@ visible; without it the optimizer may remove some. | `… come from "x.h", but its library isn't linked` | Add `link "name"` at the top of the file. | | `the library 'x' wasn't found` | Not installed, or a wrong name. On Nix, add it to `shell.nix` and run inside `nix-shell`. | | `the C function 'f' can't be used from Finch yet` | It uses a union, bit fields or another unsupported type by value. Look for a variant that takes pointers. | -| `can't find the module 'x'` | Put `x.fn` next to the importing file, or set `FINCH_PATH`. | +| `can't find the module 'x'` | Put `x.fch` next to the importing file, or set `FINCH_PATH`. | | `couldn't build the Finch runtime` | No working C compiler. Install gcc or clang, or set `CC`. | | A library is not found when the program starts | It was linked from a folder the system doesn't search. Run inside the same `nix-shell`, or install it system-wide. | | `clang` inside `nix-shell` can't find `stdio.h` | You have an old `shell.nix`: `llvmPackages.clang` must be listed before `llvmPackages.libclang`. | @@ -692,7 +692,7 @@ Finch/ ``` ```sh -tests/run.sh # → 58 passed, 0 failed +tests/run.sh # → 59 passed, 0 failed MEMCHECK=1 tests/run.sh # the same under valgrind: no leaks, no bad memory access tests/boot.sh # the self-hosting check (needs clang) ``` diff --git a/docs/pl/dla-inzynierow.md b/docs/pl/dla-inzynierow.md index e71d9b1..79d97dc 100644 --- a/docs/pl/dla-inzynierow.md +++ b/docs/pl/dla-inzynierow.md @@ -48,7 +48,7 @@ Finch to jednoprzebiegowy front-end przed LLVM: sprawdzanie typów i generowanie po AST, bez własnej reprezentacji pośredniej. ``` - main.fn ──► Loader::load() ── lex() ── parse() ──► Program (+ każdy importowany moduł, rekurencyjnie) + main.fch ──► Loader::load() ── lex() ── parse() ──► Program (+ każdy importowany moduł, rekurencyjnie) │ wszystkie `import "x.h"` ──► importHeaders() (libclang) ──► CImports │ @@ -100,7 +100,7 @@ Decyzje, które kształtują resztę: | `src/abi.cpp` | 310 | Klasyfikacja System V x86-64, wywołania C ze strukturami przez wartość, wrappery wywoływalne z C | | `src/main.cpp` | 390 | Sterownik: CLI, ładowanie, maszyna docelowa, O2, emisja, cache runtime'u, linkowanie, porady przy błędach linkera, `run` | | `runtime/finch_rt.c` | 440 | Biblioteka uruchomieniowa (§12) | -| `boot/*.fn` | 3080 | Kompilator samohostujący (§17) | +| `boot/*.fch` | 3080 | Kompilator samohostujący (§17) | --- @@ -199,7 +199,7 @@ Wszystkie węzły są w `src/ast.h`: małe hierarchie klas z jawnym `kind`, rozg | `Member` | `MemberExpr` | `obj`, `field` (`.x`, `.len`, `.ptr`, `.value`) | | `Index` | `IndexExpr` | `obj`, `index` | | `ArrayLit` | `ArrayLitExpr` | `elems` | -| `Method` | `MethodExpr` | `obj`, `name`, `args`, `argNames`; także `modul.fn(...)` | +| `Method` | `MethodExpr` | `obj`, `name`, `args`, `argNames`; także `modul.fch(...)` | | StmtKind | Węzeł | |---|---| @@ -236,7 +236,7 @@ Równość jest strukturalna; dwa `Struct` są równe, gdy mają to samo `info`. `Loader::load(path, module, from)` w `main.cpp` czyta plik, dopisuje go do `g_files` (pozycje niosą indeks pliku w `Pos::file`), leksuje go i parsuje, a potem wczytuje każdy jeszcze niewidziany `import nazwa`: -`nazwa.fn` obok importującego pliku albo w folderze z `FINCH_PATH`. Wynik to `std::vector`, +`nazwa.fch` obok importującego pliku albo w folderze z `FINCH_PATH`. Wynik to `std::vector`, z głównym plikiem na początku. Cykle nie przeszkadzają: moduł jest oznaczany jako wczytany, zanim zaczniemy podążać za jego importami. @@ -605,7 +605,7 @@ własność (`copy`, `own`, `drop`, `from_c`), tablice (`reserve`, `make`, `resi ### 13.1 Import nagłówków `importHeaders(imports, dirs)` parsuje każdy `import "x.h"` jako osobną jednostkę translacji z pliku -w pamięci `#include "x.h"`, z `-x c -std=gnu11`, `-I` dla folderu każdego pliku `.fn` i `-isystem` dla +w pamięci `#include "x.h"`, z `-x c -std=gnu11`, `-I` dla folderu każdego pliku `.fch` i `-isystem` dla każdego katalogu przeszukiwanego przez systemowy kompilator C (odczytanego z `$CC -E -v -x c /dev/null`, dzięki czemu działa to na NixOS). `gnu11`, bo glibc w trybie ścisłego ISO ukrywa `M_PI` i podobne. @@ -657,7 +657,7 @@ i atrybutami, a wyniki-struktury odbudowuje w ten sam sposób. `cThunk(fn)` to odwrotność dla `addr(fn)`: wewnętrzna funkcja z sygnaturą C, która składa parametry-struktury z rejestrów albo pamięci `byval`, woła funkcję Fincha i obniża jej wynik. Akceptowane są tylko sygnatury zgodne z C. -`tests/run/c_structs.fn` sprawdza `{float,float}`, `{float,float,float}`, `{u8×4}`, `{double,int}`, +`tests/run/c_structs.fch` sprawdza `{float,float}`, `{float,float,float}`, `{u8×4}`, `{double,int}`, `{i64,i64}`, strukturę 24-bajtową, strukturę z `char[8]`, zagnieżdżone struktury, wyczerpanie rejestrów przy 13 argumentach-strukturach oraz wywołania zwrotne przyjmujące i zwracające struktury, na bibliotece C kompilowanej przez `link "abi.c"`. Wyniki zgadzają się z tymi samymi wywołaniami zrobionymi z C. @@ -665,7 +665,7 @@ kompilowanej przez `link "abi.c"`. Wyniki zgadzają się z tymi samymi wywołani ### 13.4 Linkowanie kodu C `link "nazwa"` próbuje `pkg-config --libs nazwa`, a potem `-lnazwa`. `link "plik.c"` kompiluje plik -(względem pliku `.fn`) przez `$CC -O2 -fPIC -c` do tymczasowego obiektu; pliki `.o` i `.a` przechodzą +(względem pliku `.fch`) przez `$CC -O2 -fPIC -c` do tymczasowego obiektu; pliki `.o` i `.a` przechodzą bez zmian. Gdy linkowanie się nie uda, `linkFailed()` mapuje niezdefiniowane symbole na nagłówek, który je zadeklarował, i wypisuje linijkę `link` do dopisania. @@ -676,7 +676,7 @@ je zadeklarował, i wypisuje linijkę `link` do dopisania. - **Cel:** `sys::getDefaultTargetTriple()`, CPU `generic`, `Reloc::PIC_`. Data layout jest ustawiany na module, zanim powstanie jakikolwiek IR (od niego zależy wyrównanie loadów i store'ów). - **Optymalizacja:** `PassBuilder::buildPerModuleDefaultPipeline(O2)`: środkowa część `-O2` z clanga. - `-O0` ją pomija (`finch ir plik.fn -O0` pokazuje surowe wyjście `Codegen`). + `-O0` ją pomija (`finch ir plik.fch -O0` pokazuje surowe wyjście `Codegen`). - **Emisja:** stary `PassManager` + `addPassesToEmitFile(ObjectFile)`. - **Linkowanie:** `$CC prog.o rt.o [obiekty użytkownika] -lm [biblioteki]`. Na Niksie wrapper cc zamienia ścieżki `-L` na `RPATH`, więc programy działają bez `LD_LIBRARY_PATH`. @@ -717,11 +717,11 @@ wypisuje `internal compiler error (please report)` i kończy proces z kodem 2. | Plik | Zawartość | |---|---| -| `boot/lexer.fn` | lekser (tokeny to `{kind, text, line, col, nl}`; rodzaje to słowa, a słowa kluczowe i operatory są swoim własnym rodzajem) | -| `boot/ast.fn` | `Type` (`kind`, `elem` jako tablica 0/1 elementów, `name`, `module`), jeden ogólny `Node` na wszystko, `Program` | -| `boot/parser.fn` | ta sama gramatyka i reguły nowych linii co parser C++, wspinanie się po priorytetach dla operatorów binarnych | -| `boot/gen.fn` | sprawdzanie typów + generator **tekstowego LLVM IR**: zasięgi, miejsca, konwersje, kopie, helpery, wypisywanie, kontrole, metody tablic i tekstów | -| `boot/main.fn` | ładowanie modułów i sterownik: zapisuje `.ll`, uruchamia `clang -O2 plik.ll runtime/finch_rt.c` | +| `boot/lexer.fch` | lekser (tokeny to `{kind, text, line, col, nl}`; rodzaje to słowa, a słowa kluczowe i operatory są swoim własnym rodzajem) | +| `boot/ast.fch` | `Type` (`kind`, `elem` jako tablica 0/1 elementów, `name`, `module`), jeden ogólny `Node` na wszystko, `Program` | +| `boot/parser.fch` | ta sama gramatyka i reguły nowych linii co parser C++, wspinanie się po priorytetach dla operatorów binarnych | +| `boot/gen.fch` | sprawdzanie typów + generator **tekstowego LLVM IR**: zasięgi, miejsca, konwersje, kopie, helpery, wypisywanie, kontrole, metody tablic i tekstów | +| `boot/main.fch` | ładowanie modułów i sterownik: zapisuje `.ll`, uruchamia `clang -O2 plik.ll runtime/finch_rt.c` | Obsługuje rdzeń języka: `int float bool char str`, `[]T`, struktury (wartości domyślne, konstruktory po nazwie i po kolei), `ptr[T]`/`addr`/`new`/`free`/`null`, wszystkie instrukcje poza `defer`, moduły oraz @@ -763,9 +763,9 @@ wynik z oczekiwanym. Kompilacja samego siebie zajmuje kompilatorowi samohostują ## 19. Testy -- `tests/run.sh`: każdy `tests/run/*.fn` z `fn main` musi wypisać dokładnie swój `.out` (stdin z `.in`, jeśli - jest); pliki bez `main` to moduły albo pliki pomocnicze. Każdy `tests/fail/*.fn` musi się nie udać z tekstem - z linijki `// expect:`. Obecnie **58 passed, 0 failed**. +- `tests/run.sh`: każdy `tests/run/*.fch` z `fn main` musi wypisać dokładnie swój `.out` (stdin z `.in`, jeśli + jest); pliki bez `main` to moduły albo pliki pomocnicze. Każdy `tests/fail/*.fch` musi się nie udać z tekstem + z linijki `// expect:`. Obecnie **59 passed, 0 failed**. - `MEMCHECK=1 tests/run.sh`: to samo plus valgrind na każdym programie (bez wycieków i złych dostępów). - `tests/boot.sh`: punkt stały samohostowania i przebieg na podzbiorze (§17). @@ -797,7 +797,7 @@ wynik z oczekiwanym. Kompilacja samego siebie zajmuje kompilatorowi samohostują | Funkcja | Robi | |---|---| -| `Loader::load` / `findModule` | czyta, leksuje i parsuje plik oraz rekurencyjnie jego moduły / szuka `nazwa.fn` | +| `Loader::load` / `findModule` | czyta, leksuje i parsuje plik oraz rekurencyjnie jego moduły / szuka `nazwa.fch` | | `hostMachine`, `optimize`, `emitObject` | maszyna docelowa, potok O2, plik obiektowy | | `runtimeObject` | kompiluje runtime i trzyma go w cache | | `capture`, `libFlags`, `link` | uruchamia polecenie / pkg-config albo `-l` / linkowanie, z kompilacją plików z `link "x.c"` | @@ -868,7 +868,7 @@ wynik z oczekiwanym. Kompilacja samego siebie zajmuje kompilatorowi samohostują **Funkcja wbudowana:** dodaj nazwę do `isBuiltin()`, obsłuż ją w `call()`, zaimplementuj (w IR albo jako funkcję runtime'u zadeklarowaną w tabeli `rt()`), dodaj przypadki w `tests/run/` i `tests/fail/`. Jeśli ma -istnieć też w kompilatorze samohostującym, dodaj ją do `call()` i `runtimeDecls()` w `boot/gen.fn`. +istnieć też w kompilatorze samohostującym, dodaj ją do `call()` i `runtimeDecls()` w `boot/gen.fch`. **Metoda tablicy albo tekstu:** dodaj gałąź w `arrayMethod()` albo w części `str` w `method()`; jeśli zmienia tablicę, dopisz jej nazwę do zbiorów `changing` w `method()` i `mutatesExpr()`, żeby pożyczanie diff --git a/docs/pl/dla-poczatkujacych.md b/docs/pl/dla-poczatkujacych.md index 4ff632e..7422f78 100644 --- a/docs/pl/dla-poczatkujacych.md +++ b/docs/pl/dla-poczatkujacych.md @@ -92,11 +92,11 @@ fn main() { } ``` -3. Zapisz plik w folderze `Finch` pod nazwą **`czesc.fn`**. Końcówka `.fn` mówi, że to program w Finchu. +3. Zapisz plik w folderze `Finch` pod nazwą **`czesc.fch`**. Końcówka `.fch` mówi, że to program w Finchu. 4. W Terminalu wpisz: ```sh -./build/finch run czesc.fn +./build/finch run czesc.fch ``` Zobaczysz: @@ -659,14 +659,14 @@ fn main() { ``` ``` -czesc.fn:3:11: error: there is no variable named 'wiekk' +czesc.fch:3:11: error: there is no variable named 'wiekk' 3 | print(wiekk) | ^ ``` Jak to czytać: -- `czesc.fn` to plik, +- `czesc.fch` to plik, - `3` to numer **linijki**, - `11` to który znak w linijce (**kolumna**), - potem wyjaśnienie, a pod nim ta linijka ze strzałką `^` wskazującą problem. @@ -823,7 +823,7 @@ fn main() { } ``` -`return` w `main` kończy program. (Wersja z losową liczbą jest w `examples/guess.fn`.) +`return` w `main` kończy program. (Wersja z losową liczbą jest w `examples/guess.fch`.) ### Projekt 7: Średnia ocen diff --git a/docs/pl/dla-technikow.md b/docs/pl/dla-technikow.md index e638005..1ee3e5e 100644 --- a/docs/pl/dla-technikow.md +++ b/docs/pl/dla-technikow.md @@ -38,7 +38,7 @@ kompilator działa w środku. Do tego służy [przewodnik dla inżynierów](dla- ## 1. Czym jest Finch -Finch to język **kompilowany**. Narzędzie `finch` tłumaczy plik `.fn` na prawdziwy program +Finch to język **kompilowany**. Narzędzie `finch` tłumaczy plik `.fch` na prawdziwy program (natywny plik wykonywalny, taki jak te z C). Korzysta przy tym z **LLVM**, tego samego zaplecza kompilatorów, na którym działają clang, Rust i Swift. @@ -107,9 +107,9 @@ Inny kompilator wskażesz zmienną `CC`. ## 3. Polecenie finch ``` -finch run [argumenty...] skompiluj i od razu uruchom -finch build [-o nazwa] skompiluj do programu (domyślna nazwa: nazwa pliku) -finch ir pokaż LLVM IR (dla ciekawskich) +finch run [argumenty...] skompiluj i od razu uruchom +finch build [-o nazwa] skompiluj do programu (domyślna nazwa: nazwa pliku) +finch ir pokaż LLVM IR (dla ciekawskich) finch version pokaż wersję opcje: @@ -121,10 +121,10 @@ opcje: Przykłady: ```sh -finch run hello.fn # wypisuje wynik -finch run narzedzie.fn dane.txt -v # argumenty po nazwie pliku trafiają do programu -finch build gra.fn -o mojagra # tworzy ./mojagra -finch build gra.fn -g -O0 # wersja dla debuggera +finch run hello.fch # wypisuje wynik +finch run narzedzie.fch dane.txt -v # argumenty po nazwie pliku trafiają do programu +finch build gra.fch -o mojagra # tworzy ./mojagra +finch build gra.fch -g -O0 # wersja dla debuggera ``` `finch run` przekazuje dalej kod wyjścia programu. Jeśli program się wysypie, powie jak @@ -140,7 +140,7 @@ finch build gra.fn -g -O0 # wersja dla debuggera kilka linijek */ import "math.h" // nagłówki C (opcjonalne), na górze -import ksztalty // moduły Fincha (opcjonalne): ksztalty.fn obok tego pliku +import ksztalty // moduły Fincha (opcjonalne): ksztalty.fch obok tego pliku link "m" // biblioteki albo pliki C do dolinkowania (opcjonalne) struct Punkt { // własne typy @@ -503,11 +503,11 @@ Użycie `.value`, `.pole` albo `[i]` na wskaźniku `null` **zatrzymuje program** ## 16. Moduły -Program możesz podzielić na pliki. `import ksztalty` wczytuje `ksztalty.fn` z tego samego folderu +Program możesz podzielić na pliki. `import ksztalty` wczytuje `ksztalty.fch` z tego samego folderu (albo z folderu wymienionego w zmiennej środowiskowej `FINCH_PATH`, rozdzielonych `:`). ```c -// ksztalty.fn +// ksztalty.fch struct Pudlo { float w float h @@ -519,7 +519,7 @@ fn pole(Pudlo p) -> float { ``` ```c -// main.fn +// main.fch import ksztalty fn main() { @@ -541,7 +541,7 @@ fn main() { ```c import "stdio.h" import "GLFW/glfw3.h" // ścieżka w systemowych katalogach nagłówków -import "mojalib.h" // nagłówek obok twojego pliku .fn +import "mojalib.h" // nagłówek obok twojego pliku .fch ``` Finch czyta nagłówek przez **libclang** (parser C z clanga) i udostępnia: @@ -555,7 +555,7 @@ Finch czyta nagłówek przez **libclang** (parser C z clanga) i udostępnia: ```c link "glfw" // używa libglfw.so (najpierw pyta pkg-config, jeśli jest) -link "pomocnicze.c" // skompiluj i dołącz własny plik C (obok pliku .fn) +link "pomocnicze.c" // skompiluj i dołącz własny plik C (obok pliku .fch) link "gotowe.a" // albo plik obiektowy / bibliotekę statyczną ``` @@ -618,7 +618,7 @@ Jej parametry muszą być typami C (liczby, wskaźniki, struktury C). ### Błędy kompilacji ``` -gra.fn:12:9: error: 'wynik' must be int, but this is str +gra.fch:12:9: error: 'wynik' must be int, but this is str 12 | wynik = "wysoki" | ^ ``` @@ -645,9 +645,9 @@ Zamiast niezdefiniowanego zachowania (jak w C) Finch zatrzymuje się z komunikat ## 19. Debugowanie ```sh -finch build gra.fn -g -O0 -o gra +finch build gra.fch -g -O0 -o gra gdb ./gra -(gdb) break gra.fn:12 +(gdb) break gra.fch:12 (gdb) run (gdb) bt # gdzie jesteśmy, przez które funkcje (gdb) info locals # wszystkie zmienne @@ -667,7 +667,7 @@ zmienne widoczne; bez niego optymalizator może część z nich usunąć. | `… come from "x.h", but its library isn't linked` | Dopisz `link "nazwa"` na górze pliku. | | `the library 'x' wasn't found` | Nie jest zainstalowana albo nazwa jest zła. Na Niksie dopisz ją do `shell.nix` i pracuj w `nix-shell`. | | `the C function 'f' can't be used from Finch yet` | Używa unii, pól bitowych albo innego nieobsługiwanego typu przez wartość. Poszukaj wariantu ze wskaźnikami. | -| `can't find the module 'x'` | Połóż `x.fn` obok importującego pliku albo ustaw `FINCH_PATH`. | +| `can't find the module 'x'` | Połóż `x.fch` obok importującego pliku albo ustaw `FINCH_PATH`. | | `couldn't build the Finch runtime` | Brak działającego kompilatora C. Zainstaluj gcc lub clang albo ustaw `CC`. | | Biblioteka nie znajduje się przy starcie programu | Zlinkowano ją z folderu, którego system nie przeszukuje. Uruchamiaj w tym samym `nix-shell` albo zainstaluj ją systemowo. | | `clang` w `nix-shell` nie widzi `stdio.h` | Masz stary `shell.nix`: `llvmPackages.clang` musi być przed `llvmPackages.libclang`. | @@ -694,7 +694,7 @@ Finch/ ``` ```sh -tests/run.sh # → 58 passed, 0 failed +tests/run.sh # → 59 passed, 0 failed MEMCHECK=1 tests/run.sh # to samo pod valgrindem: bez wycieków i złych dostępów do pamięci tests/boot.sh # sprawdzenie samohostowania (wymaga clanga) ``` diff --git a/examples/c_import.fn b/examples/c_import.fch similarity index 100% rename from examples/c_import.fn rename to examples/c_import.fch diff --git a/examples/guess.fn b/examples/guess.fch similarity index 100% rename from examples/guess.fn rename to examples/guess.fch diff --git a/examples/hello.fn b/examples/hello.fch similarity index 100% rename from examples/hello.fn rename to examples/hello.fch diff --git a/examples/llvm.fn b/examples/llvm.fch similarity index 100% rename from examples/llvm.fn rename to examples/llvm.fch diff --git a/examples/raylib.fn b/examples/raylib.fch similarity index 100% rename from examples/raylib.fn rename to examples/raylib.fch diff --git a/examples/structs.fn b/examples/structs.fch similarity index 100% rename from examples/structs.fn rename to examples/structs.fch diff --git a/examples/todo.fn b/examples/todo.fch similarity index 100% rename from examples/todo.fn rename to examples/todo.fch diff --git a/examples/tour.fn b/examples/tour.fch similarity index 100% rename from examples/tour.fn rename to examples/tour.fch diff --git a/examples/types.fn b/examples/types.fch similarity index 100% rename from examples/types.fn rename to examples/types.fch diff --git a/examples/window.fn b/examples/window.fch similarity index 100% rename from examples/window.fn rename to examples/window.fch diff --git a/shell.nix b/shell.nix index 7087ecf..3f44c9e 100644 --- a/shell.nix +++ b/shell.nix @@ -10,7 +10,7 @@ pkgs.mkShell { ninja pkg-config # finds the right flags for `link "..."` - # for examples/window.fn and examples/raylib.fn + # for examples/window.fch and examples/raylib.fch glfw libGL raylib diff --git a/src/ast.h b/src/ast.h index 6f72215..2cb02fb 100644 --- a/src/ast.h +++ b/src/ast.h @@ -298,10 +298,10 @@ struct Import { struct Link { Pos pos; - std::string lib; // "glfw" -> libglfw.so; "helpers.c" / ".o" / ".a" -> a file next to the .fn file + std::string lib; // "glfw" -> libglfw.so; "helpers.c" / ".o" / ".a" -> a file next to the .fch file }; -// One .fn file. +// One .fch file. struct Program { std::string module; // "" for the main file, else the module's name std::string path; diff --git a/src/cimport.h b/src/cimport.h index ecc3605..fe4be0d 100644 --- a/src/cimport.h +++ b/src/cimport.h @@ -52,5 +52,5 @@ struct CImports { std::map structs; }; -// `dirs`: folders searched first for "local.h" headers (the .fn files' folders). +// `dirs`: folders searched first for "local.h" headers (the .fch files' folders). CImports importHeaders(const std::vector &imports, const std::vector &dirs); diff --git a/src/main.cpp b/src/main.cpp index d120afa..e755330 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,9 +34,9 @@ static void usage() { std::fprintf(stderr, "Finch " FINCH_VERSION " - small, quick, sharp.\n\n" "usage:\n" - " finch run [args...] compile and run\n" - " finch build [-o name] compile to a program\n" - " finch ir show the generated LLVM IR\n" + " finch run [args...] compile and run\n" + " finch build [-o name] compile to a program\n" + " finch ir show the generated LLVM IR\n" " finch version show the version\n" "\n" " -l link a C library, same as link \"lib\" in the file\n" @@ -68,7 +68,12 @@ struct Loader { void load(const std::string &path, const std::string &module, Pos from) { std::string text; if (!readFile(path, text)) { - if (from.line) failAt(from.file, from.line, from.col, "can't find the module '" + module + "' (looked for " + path + ")"); + if (from.line) { + std::string old = path.substr(0, path.size() - 4) + ".fn"; + if (sys::fs::exists(old)) + failAt(from.file, from.line, from.col, "found " + old + ", but Finch files now end in .fch: rename it to " + path); + failAt(from.file, from.line, from.col, "can't find the module '" + module + "' (looked for " + path + ")"); + } std::fprintf(stderr, "error: can't open '%s'\n", path.c_str()); std::exit(1); } @@ -91,12 +96,12 @@ struct Loader { // next to the importing file, then in $FINCH_PATH folders static std::string findModule(const std::string &dir, const std::string &name) { - std::string here = dir + "/" + name + ".fn"; + std::string here = dir + "/" + name + ".fch"; if (sys::fs::exists(here)) return here; if (const char *fp = std::getenv("FINCH_PATH")) { std::stringstream ss(fp); for (std::string d; std::getline(ss, d, ':');) - if (!d.empty() && sys::fs::exists(d + "/" + name + ".fn")) return d + "/" + name + ".fn"; + if (!d.empty() && sys::fs::exists(d + "/" + name + ".fch")) return d + "/" + name + ".fch"; } return here; } diff --git a/src/parser.cpp b/src/parser.cpp index be451f7..14889fa 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -137,7 +137,7 @@ private: expect(Tok::Link); l.lib = expect(Tok::String, "a library name in quotes, like link \"glfw\"").text; auto ends = [&](const char *x) { size_t n = std::strlen(x); return l.lib.size() > n && l.lib.compare(l.lib.size() - n, n, x) == 0; }; - if (ends(".c") || ends(".o") || ends(".a")) return l; // your own C code, next to the .fn file + if (ends(".c") || ends(".o") || ends(".a")) return l; // your own C code, next to the .fch file if (l.lib.rfind("lib", 0) == 0 || l.lib.find(".so") != std::string::npos || l.lib.find('/') != std::string::npos) fail(l.pos.line, l.pos.col, "write just the library's name: for libglfw.so that's link \"glfw\""); return l; diff --git a/tests/boot.sh b/tests/boot.sh index 1d1305e..ef4748e 100755 --- a/tests/boot.sh +++ b/tests/boot.sh @@ -7,10 +7,10 @@ cd "$(dirname "$0")/.." tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT -build/finch build boot/main.fn -o "$tmp/boot1" || exit 1 -"$tmp/boot1" build boot/main.fn -o "$tmp/boot2" || exit 1 -"$tmp/boot1" ir boot/main.fn > "$tmp/stage2.ll" -"$tmp/boot2" ir boot/main.fn > "$tmp/stage3.ll" +build/finch build boot/main.fch -o "$tmp/boot1" || exit 1 +"$tmp/boot1" build boot/main.fch -o "$tmp/boot2" || exit 1 +"$tmp/boot1" ir boot/main.fch > "$tmp/stage2.ll" +"$tmp/boot2" ir boot/main.fch > "$tmp/stage3.ll" if cmp -s "$tmp/stage2.ll" "$tmp/stage3.ll"; then echo "bootstrap: stage 2 and stage 3 are identical ($(wc -l < "$tmp/stage3.ll") lines of IR)" else @@ -19,17 +19,17 @@ else fi pass=0; failed=0; skipped=0 -for f in tests/run/*.fn; do +for f in tests/run/*.fch; do grep -q "^fn main" "$f" || continue # the bootstrap compiler doesn't do C imports, sized numbers or defer # (checked in the test and in the modules it imports) files="$f" - for m in $(sed -n 's/^import \([a-z_]*\)$/\1/p' "$f"); do files="$files tests/run/$m.fn"; done + for m in $(sed -n 's/^import \([a-z_]*\)$/\1/p' "$f"); do files="$files tests/run/$m.fch"; done if grep -qE '^import "|^link |\b(u8|u16|u32|u64|i8|i16|i32|f32|f64)\b|defer |0x' $files; then skipped=$((skipped + 1)) continue fi - input="${f%.fn}.in" + input="${f%.fch}.in" [ -f "$input" ] || input=/dev/null if ! "$tmp/boot2" build "$f" -o "$tmp/prog" > "$tmp/err" 2>&1; then failed=$((failed + 1)) @@ -38,12 +38,12 @@ for f in tests/run/*.fn; do continue fi got=$("$tmp/prog" < "$input" 2>&1) - if [ "$got" == "$(cat "${f%.fn}.out")" ]; then + if [ "$got" == "$(cat "${f%.fch}.out")" ]; then pass=$((pass + 1)) else failed=$((failed + 1)) echo "FAIL (output) $f" - diff <(echo "$got") "${f%.fn}.out" | head -10 + diff <(echo "$got") "${f%.fch}.out" | head -10 fi done echo "self-hosted compiler: $pass passed, $failed failed, $skipped skipped (features it doesn't have)" diff --git a/tests/fail/array_compare.fn b/tests/fail/array_compare.fch similarity index 100% rename from tests/fail/array_compare.fn rename to tests/fail/array_compare.fch diff --git a/tests/fail/bad_int.fn b/tests/fail/bad_int.fch similarity index 100% rename from tests/fail/bad_int.fn rename to tests/fail/bad_int.fch diff --git a/tests/fail/bad_link_name.fn b/tests/fail/bad_link_name.fch similarity index 100% rename from tests/fail/bad_link_name.fn rename to tests/fail/bad_link_name.fch diff --git a/tests/fail/bool_bitand.fn b/tests/fail/bool_bitand.fch similarity index 100% rename from tests/fail/bool_bitand.fn rename to tests/fail/bool_bitand.fch diff --git a/tests/fail/condition_not_bool.fn b/tests/fail/condition_not_bool.fch similarity index 100% rename from tests/fail/condition_not_bool.fn rename to tests/fail/condition_not_bool.fch diff --git a/tests/fail/defer_return.fn b/tests/fail/defer_return.fch similarity index 100% rename from tests/fail/defer_return.fn rename to tests/fail/defer_return.fch diff --git a/tests/fail/div_zero_const.fn b/tests/fail/div_zero_const.fch similarity index 100% rename from tests/fail/div_zero_const.fn rename to tests/fail/div_zero_const.fch diff --git a/tests/fail/div_zero_runtime.fn b/tests/fail/div_zero_runtime.fch similarity index 100% rename from tests/fail/div_zero_runtime.fn rename to tests/fail/div_zero_runtime.fch diff --git a/tests/fail/each_readonly.fn b/tests/fail/each_readonly.fch similarity index 100% rename from tests/fail/each_readonly.fn rename to tests/fail/each_readonly.fch diff --git a/tests/fail/empty_array.fn b/tests/fail/empty_array.fch similarity index 100% rename from tests/fail/empty_array.fn rename to tests/fail/empty_array.fch diff --git a/tests/fail/float_to_int.fn b/tests/fail/float_to_int.fch similarity index 100% rename from tests/fail/float_to_int.fn rename to tests/fail/float_to_int.fch diff --git a/tests/fail/forgot_import.fn b/tests/fail/forgot_import.fch similarity index 100% rename from tests/fail/forgot_import.fn rename to tests/fail/forgot_import.fch diff --git a/tests/fail/free_value.fn b/tests/fail/free_value.fch similarity index 100% rename from tests/fail/free_value.fn rename to tests/fail/free_value.fch diff --git a/tests/fail/index_range.fn b/tests/fail/index_range.fch similarity index 100% rename from tests/fail/index_range.fn rename to tests/fail/index_range.fch diff --git a/tests/fail/lib_hint.fn b/tests/fail/lib_hint.fch similarity index 100% rename from tests/fail/lib_hint.fn rename to tests/fail/lib_hint.fch diff --git a/tests/fail/literal_too_big.fn b/tests/fail/literal_too_big.fch similarity index 100% rename from tests/fail/literal_too_big.fn rename to tests/fail/literal_too_big.fch diff --git a/tests/fail/loop_var_readonly.fn b/tests/fail/loop_var_readonly.fch similarity index 100% rename from tests/fail/loop_var_readonly.fn rename to tests/fail/loop_var_readonly.fch diff --git a/tests/fail/missing_header.fn b/tests/fail/missing_header.fch similarity index 100% rename from tests/fail/missing_header.fn rename to tests/fail/missing_header.fch diff --git a/tests/fail/missing_lib.fn b/tests/fail/missing_lib.fch similarity index 100% rename from tests/fail/missing_lib.fn rename to tests/fail/missing_lib.fch diff --git a/tests/fail/missing_return.fn b/tests/fail/missing_return.fch similarity index 100% rename from tests/fail/missing_return.fn rename to tests/fail/missing_return.fch diff --git a/tests/fail/mixed_signs.fn b/tests/fail/mixed_signs.fch similarity index 100% rename from tests/fail/mixed_signs.fn rename to tests/fail/mixed_signs.fch diff --git a/tests/fail/module_missing.fn b/tests/fail/module_missing.fch similarity index 100% rename from tests/fail/module_missing.fn rename to tests/fail/module_missing.fch diff --git a/tests/fail/module_not_imported.fn b/tests/fail/module_not_imported.fch similarity index 100% rename from tests/fail/module_not_imported.fn rename to tests/fail/module_not_imported.fch diff --git a/tests/fail/no_main.fn b/tests/fail/no_main.fch similarity index 100% rename from tests/fail/no_main.fn rename to tests/fail/no_main.fch diff --git a/tests/fail/non_ascii_name.fn b/tests/fail/non_ascii_name.fch similarity index 100% rename from tests/fail/non_ascii_name.fn rename to tests/fail/non_ascii_name.fch diff --git a/tests/fail/null_value.fn b/tests/fail/null_value.fch similarity index 100% rename from tests/fail/null_value.fn rename to tests/fail/null_value.fch diff --git a/tests/fail/old_extension.fch b/tests/fail/old_extension.fch new file mode 100644 index 0000000..2764d5c --- /dev/null +++ b/tests/fail/old_extension.fch @@ -0,0 +1,3 @@ +// expect: but Finch files now end in .fch +import oldmodule +fn main() {} diff --git a/tests/fail/old_function_syntax.fn b/tests/fail/old_function_syntax.fch similarity index 100% rename from tests/fail/old_function_syntax.fn rename to tests/fail/old_function_syntax.fch diff --git a/tests/fail/oldmodule.fn b/tests/fail/oldmodule.fn new file mode 100644 index 0000000..768ca7c --- /dev/null +++ b/tests/fail/oldmodule.fn @@ -0,0 +1,2 @@ +fn hi() { +} diff --git a/tests/fail/pop_empty.fn b/tests/fail/pop_empty.fch similarity index 100% rename from tests/fail/pop_empty.fn rename to tests/fail/pop_empty.fch diff --git a/tests/fail/push_type.fn b/tests/fail/push_type.fch similarity index 100% rename from tests/fail/push_type.fn rename to tests/fail/push_type.fch diff --git a/tests/fail/redeclare.fn b/tests/fail/redeclare.fch similarity index 100% rename from tests/fail/redeclare.fn rename to tests/fail/redeclare.fch diff --git a/tests/fail/str_null.fn b/tests/fail/str_null.fch similarity index 100% rename from tests/fail/str_null.fn rename to tests/fail/str_null.fch diff --git a/tests/fail/str_plus_int.fn b/tests/fail/str_plus_int.fch similarity index 100% rename from tests/fail/str_plus_int.fn rename to tests/fail/str_plus_int.fch diff --git a/tests/fail/struct_count.fn b/tests/fail/struct_count.fch similarity index 100% rename from tests/fail/struct_count.fn rename to tests/fail/struct_count.fch diff --git a/tests/fail/struct_no_field.fn b/tests/fail/struct_no_field.fch similarity index 100% rename from tests/fail/struct_no_field.fn rename to tests/fail/struct_no_field.fch diff --git a/tests/fail/struct_self.fn b/tests/fail/struct_self.fch similarity index 100% rename from tests/fail/struct_self.fn rename to tests/fail/struct_self.fch diff --git a/tests/fail/two_statements.fn b/tests/fail/two_statements.fch similarity index 100% rename from tests/fail/two_statements.fn rename to tests/fail/two_statements.fch diff --git a/tests/fail/type_mismatch.fn b/tests/fail/type_mismatch.fch similarity index 100% rename from tests/fail/type_mismatch.fn rename to tests/fail/type_mismatch.fch diff --git a/tests/fail/unclosed_brace.fn b/tests/fail/unclosed_brace.fch similarity index 100% rename from tests/fail/unclosed_brace.fn rename to tests/fail/unclosed_brace.fch diff --git a/tests/fail/undefined_var.fn b/tests/fail/undefined_var.fch similarity index 100% rename from tests/fail/undefined_var.fn rename to tests/fail/undefined_var.fch diff --git a/tests/fail/unreachable.fn b/tests/fail/unreachable.fch similarity index 100% rename from tests/fail/unreachable.fn rename to tests/fail/unreachable.fch diff --git a/tests/fail/untyped_null.fn b/tests/fail/untyped_null.fch similarity index 100% rename from tests/fail/untyped_null.fn rename to tests/fail/untyped_null.fch diff --git a/tests/fail/untyped_ptr.fn b/tests/fail/untyped_ptr.fch similarity index 100% rename from tests/fail/untyped_ptr.fn rename to tests/fail/untyped_ptr.fch diff --git a/tests/run.sh b/tests/run.sh index 28f0c88..c85f2b8 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash # Finch test suite. -# tests/run/*.fn must compile and print exactly what is in the matching .out file +# tests/run/*.fch must compile and print exactly what is in the matching .out file # (files without `fn main` are modules or helpers and are skipped; # a matching .in file is fed to the program as its input) -# tests/fail/*.fn must fail; the first line is "// expect: " +# tests/fail/*.fch must fail; the first line is "// expect: " # MEMCHECK=1 tests/run.sh also runs every program under valgrind: no leaks, no bad memory access set -u cd "$(dirname "$0")" @@ -12,10 +12,10 @@ pass=0; failed=0 tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT -for f in run/*.fn; do +for f in run/*.fch; do grep -q "^fn main" "$f" || continue - want="${f%.fn}.out" - input="${f%.fn}.in" + want="${f%.fch}.out" + input="${f%.fch}.in" [ -f "$input" ] || input=/dev/null got=$("$FINCH" run "$f" < "$input" 2>&1) if [ "$got" != "$(cat "$want")" ]; then @@ -25,7 +25,7 @@ for f in run/*.fn; do continue fi if [ "${MEMCHECK:-0}" = 1 ]; then - exe="$tmp/$(basename "${f%.fn}")" + exe="$tmp/$(basename "${f%.fch}")" "$FINCH" build "$f" -o "$exe" >/dev/null 2>&1 if ! valgrind -q --leak-check=full --errors-for-leak-kinds=all --error-exitcode=99 "$exe" < "$input" >/dev/null 2>"$tmp/vg"; then failed=$((failed + 1)) @@ -37,7 +37,8 @@ for f in run/*.fn; do pass=$((pass + 1)) done -for f in fail/*.fn; do +for f in fail/*.fch; do + grep -q "^// expect:" "$f" || continue expect=$(head -1 "$f" | sed -n 's|^// expect: ||p') got=$("$FINCH" run "$f" < /dev/null 2>&1) status=$? diff --git a/tests/run/basics.fn b/tests/run/basics.fch similarity index 100% rename from tests/run/basics.fn rename to tests/run/basics.fch diff --git a/tests/run/bits.fn b/tests/run/bits.fch similarity index 100% rename from tests/run/bits.fn rename to tests/run/bits.fch diff --git a/tests/run/c_structs.fn b/tests/run/c_structs.fch similarity index 100% rename from tests/run/c_structs.fn rename to tests/run/c_structs.fch diff --git a/tests/run/cimport.fn b/tests/run/cimport.fch similarity index 100% rename from tests/run/cimport.fn rename to tests/run/cimport.fch diff --git a/tests/run/control.fn b/tests/run/control.fch similarity index 100% rename from tests/run/control.fn rename to tests/run/control.fch diff --git a/tests/run/defer.fn b/tests/run/defer.fch similarity index 100% rename from tests/run/defer.fn rename to tests/run/defer.fch diff --git a/tests/run/exitcode.fn b/tests/run/exitcode.fch similarity index 100% rename from tests/run/exitcode.fn rename to tests/run/exitcode.fch diff --git a/tests/run/files.fn b/tests/run/files.fch similarity index 100% rename from tests/run/files.fn rename to tests/run/files.fch diff --git a/tests/run/functions.fn b/tests/run/functions.fch similarity index 100% rename from tests/run/functions.fn rename to tests/run/functions.fch diff --git a/tests/run/geometry.fn b/tests/run/geometry.fch similarity index 100% rename from tests/run/geometry.fn rename to tests/run/geometry.fch diff --git a/tests/run/input.fn b/tests/run/input.fch similarity index 100% rename from tests/run/input.fn rename to tests/run/input.fch diff --git a/tests/run/memory.fn b/tests/run/memory.fch similarity index 100% rename from tests/run/memory.fn rename to tests/run/memory.fch diff --git a/tests/run/modules.fn b/tests/run/modules.fch similarity index 100% rename from tests/run/modules.fn rename to tests/run/modules.fch diff --git a/tests/run/pointers.fn b/tests/run/pointers.fch similarity index 100% rename from tests/run/pointers.fn rename to tests/run/pointers.fch diff --git a/tests/run/ptr_value_field.fn b/tests/run/ptr_value_field.fch similarity index 100% rename from tests/run/ptr_value_field.fn rename to tests/run/ptr_value_field.fch diff --git a/tests/run/shapes.fn b/tests/run/shapes.fch similarity index 100% rename from tests/run/shapes.fn rename to tests/run/shapes.fch diff --git a/tests/run/structs_arrays_strings.fn b/tests/run/structs_arrays_strings.fch similarity index 100% rename from tests/run/structs_arrays_strings.fn rename to tests/run/structs_arrays_strings.fch diff --git a/tests/run/types.fn b/tests/run/types.fch similarity index 100% rename from tests/run/types.fn rename to tests/run/types.fch