Skip to content

Releases: ozzenerol/ktm-lang

v0.28.3

Choose a tag to compare

@ozzenerol ozzenerol released this 16 Oct 11:06

A program that clears the history before it ends leaves nothing for memsafe to report.

Fixes

  • term.historyClear() frees the history's list as well as its lines, and the path given to term.historyFile is kept without allocating, so -Memsafe no longer lists them as still in use at exit. The file keeps its lines, and lines added after the clear still go into it.

v0.28.2

Choose a tag to compare

@ozzenerol ozzenerol released this 16 Oct 10:58

A prompt of several lines for term.readLine.

Fixes

  • term.readLine with a prompt that holds a newline ("[bold]app>[/]\n") wrote the prompt again at every key, so the screen filled with prompts and the cursor drifted. The lines before the prompt's last are written once now, and only the last is redrawn with what is typed.

v0.28.1

Choose a tag to compare

@ozzenerol ozzenerol released this 16 Oct 10:36

Two fixes found by a program built on term.readLine.

Fixes

  • A parameter's default value is checked against its type, as an argument is. A literal for a String parameter (String path = ".history") compiled and handed the function a String of garbage, which crashed later in whatever used it; it is an error now that says to take a u8[]. A default that would only warn as an argument (an integer for a pointer) warns.
  • An uncaught error that passed through a defer is traced from where it was thrown. The trace began at the function whose defer ran, and the calls below it were missing: an error deep in a package showed up as a line of main. A throw(e) from a catch is shown at its own line, not at the catch's closing brace.

v0.28.0

Choose a tag to compare

@ozzenerol ozzenerol released this 16 Oct 09:46

Reading what people type, with line editing and a history, as GNU readline does.

term: reading lines

  • term.readLine(prompt, &line) shows a prompt (markup allowed) and reads a line; false when the input ends (Ctrl-D on an empty line, or the end of a pipe). On a terminal the line can be edited with the keys of bash: Left/Right, Home/End, Ctrl-A/E/B/F, a word at a time with Ctrl-Left/Right and Alt-B/F, Backspace, Delete, Ctrl-W, Ctrl-U, Ctrl-K; Ctrl-L clears the screen and Ctrl-C drops the line. A long line scrolls sideways. From a pipe or a file, lines are read as they come.
  • The history: Up/Down (Ctrl-P/N) go through the lines typed before, which readLine adds by itself (not empty lines or a repeat). term.historyFile(path) keeps them between runs; historyAdd, historyAuto, historyMax, historyLen, historyAt and historyClear manage it.
  • term.readPassword(prompt, &line) reads a line without showing it and keeps it out of the history. term.clear() clears the terminal.
  • The terminal guide builds a small interactive program with them.

v0.27.1

Choose a tag to compare

@ozzenerol ozzenerol released this 16 Oct 09:40

Range for over a map, closable sidebars and chapter descriptions on the docs site, and a steadier test.

Fixes

  • for (auto e : m) over a map.Map gives each entry, with e.key and e.value, in the order the keys were added; deleted keys are skipped. It works on a map held by value, through a pointer or as a field, with break and continue. Before, it was refused with "Range for loop must be on a struct with both a 'size' and 'entries' property". Ranging over m.entries now says to range over the map itself.
  • Docs site: the language chapters and the Quick Guides list their descriptions on the index pages, and every chapter page has a meta description.
  • Docs site: every sidebar can be closed: the chapter lists, "On this page" and both panes of the library browser. Each keeps its tab where it was, and the site remembers what you closed.
  • Test 534 (coro.waitChild) no longer fails now and then on a loaded machine: its children end in a fixed order whatever their start-up time.

v0.27.0

Choose a tag to compare

@ozzenerol ozzenerol released this 16 Oct 09:13

A new standard library module for the output of command-line programs, and two Quick Guides.

term: terminal output

  • term.print(fmt, ...) is printf with colors written as markup: "[green]passed[/] %d tests, [bold red]%d failed[/]". Colors, backgrounds ([white on blue]) and styles (bold, dim, italic, underline, reverse, strike); [/] closes the last tag. The values filled in by %s are never read as markup. term.eprint writes to stderr, term.format into a String.
  • term.success, term.info, term.warn and term.error write one line after a green ✓, a blue •, a yellow ! or a red ✗ (warnings and errors to stderr); term.title a bold line.
  • Colors are on for a terminal and off for a pipe or a file, with NO_COLOR set or TERM=dumb; FORCE_COLOR and term.setColors turn them on. Without colors the markup is removed and the text stays.
  • term.table(headers...) and t.row(cells...): cells of any type (text, numbers, bools, enums, Strings) in lined-up columns, numbers on the right, markup that doesn't count in the width. t.align, t.border (box lines or a markdown table) and t.format() for the table as a String.
  • term.progress(label, total): a progress bar on stderr, redrawn in place on a terminal, with the time taken at p.done(). Lines written with term while it runs go above it; in a pipe only the last line is written.

Documentation

v0.26.0

Choose a tag to compare

@ozzenerol ozzenerol released this 16 Oct 08:40

SQLite with arguments and structs, go-to-definition into packages, man pages, and Quick Guides.

SQLite: queries with arguments, rows into structs

  • db.exec(query, args...) runs one statement with its ?s filled from the arguments and answers how many rows it changed. An argument can be an integer, bool, enum (stored by name), float, text (u8[], String, u8 *), sql.blob(bytes), a struct or slice (as JSON), or a pointer to one of them; a null pointer is NULL.
  • sql.queryAll<T>(db, query, args...) returns every row as a vec.Vec<T>, sql.queryOne<T> the first (sql.ERR_NO_ROWS when there is none). Columns fill a struct's fields by name (@key, @skip); a pointer field is null for NULL; any other T takes the first column, so sql.queryOne<i64>(db, "INSERT ... RETURNING id", ...) gives the new id. sql.free(reflect.of(x)) frees what they allocated.
  • Failures throw sql.ERR_SQL with SQLite's message; db.errorCode() tells a broken constraint apart (sql.CONSTRAINT_UNIQUE, NOTNULL, FOREIGNKEY, CHECK, PRIMARYKEY). db.lastInsertId() is the last row's id.
  • The sql.Param, sql.select and prepared-statement calls work as before. The SQLite guide uses the new calls.

LSP

  • Go to definition and hover reach a package's names: pg.connect, pg.Conn, a sub-package (postgres.driver) and an import under another name. Before, only the standard library's and methods on a package's types did.
  • Go to definition reaches generic functions: vec.new<i64>, json.decode<T>, pg.queryAll<T>.
  • Hover shows a package's names as the code writes them (pg.Conn *pg.connect(...)), not the compiler's internal path. A package under a replace opens at its real path.

Documentation

  • man ktm: the language guide and the standard library as man pages (ktm-<module>(3), ktm-guide-<chapter>(7)), installed on Linux.
  • Quick Guides: one task each, from an empty directory to a working program: database migrations, logging, SQLite and PostgreSQL. Every code block has a Copy button.

v0.25.0

Choose a tag to compare

@ozzenerol ozzenerol released this 15 Oct 17:57

Two changes to the language that make a program that compiled before fail to: both say what to write instead.

Changes you may notice

  • ad is gone (v0.24.0 renamed it scoped). ad in front of a declaration is an error that says to write scoped; anywhere else ad is an ordinary name. The packages moved too: ktm-pg v0.2.1, ktm-jwt v0.2.1 and ktm-migrate v0.1.1 use scoped (ktm get them; older versions don't build any more).
  • A program or package can't give String or Error methods of its own (void String.shout()), as it can't for any library type: their methods are the standard library's. Write a function that takes one instead: void shout(String *s).

v0.24.0

Choose a tag to compare

@ozzenerol ozzenerol released this 15 Oct 17:35

Threads without C, a clearer name for ad, and an LSP that imports for you.

Changes you may notice

  • ad is spelled scoped: scoped String s = str.from("x"); frees s at the end of its block, as ad did. ad still works, with a warning at it that says to write scoped (none for the files of a package in the module cache); it will be removed in a later minor.
  • thread.Pool's field run is now running (the name is the new run() method). poolNew, poolEnqueue, poolWait, poolStop and poolRelease work as before, for one more minor.

The thread module

  • thread.spawn(&f, &arg) runs f(T *) on a new thread, typed, with no casts; join() waits and throws what the thread threw, with its code, message, file and line. A spawned thread has ktm's runtime: crash reports, try, threadlocal.
  • thread.Mutex (with guard() for scoped), Cond, RwLock and Once: ready as declared, no setup, nothing to free.
  • thread.go(&f, &arg, &wg) with a thread.WaitGroup, thread.each(items, &f) over a slice on every core, thread.Channel<T> (buffered or not) and a typed thread.pool(n) with run() and wait(); each wait throws the first error its threads threw.
  • The threads chapter of the docs teaches the module, with C's threads last.

LSP

  • Completion offers names from modules a file doesn't import yet (the library, the project's own modules and its ktm.mod packages) and adds the import when one is picked; quick fixes add a missing import for an unknown name.
  • A correct file no longer shows errors: files of a package repository (a ktm.mod with module pg; in a directory named otherwise) were read as stray programs, open files kept errors after the file they import was fixed, and an imported file's warnings showed up in every importer.
  • An error in a return no longer also warns that the function may not return a value.

Fixes

  • macOS: a caught throw left the thread's signal mask garbled, so a thread started or a program run afterwards blocked SIGSEGV, and a crash in it spun forever instead of being reported.

v0.23.2

Choose a tag to compare

@ozzenerol ozzenerol released this 15 Oct 16:21

Fixes, most of them to the compiler. Two make programs that were wrong fail loudly: a printf-style format whose values don't match it no longer compiles, and an integer division by zero on arm64 crashes as it does on x86_64.

  • An inlined call whose body declares a local from a parameter (i64 *p = (i64 *)w;) kept the argument's value: given an array element, a dereference or a field (f(slot[0])), the parameter read garbage. Wrong code since inlining came in; plain locals as arguments were right.
  • printf-style formats (printf, str.format, appendFormat and your own functions that take one) check each value's type against its conversion, not only their count: %s of a number, %d of text or a float and %f of an integer are compile errors that say which value is wrong.
  • An integer division or % by zero crashes on arm64 with "integer division by zero" and exit status 136, as on x86_64, compiled and in the JIT. It gave 0 and the program went on.
  • The smallest i64 divided by -1 (and % -1) crashes on every platform with "integer overflow in division"; x86_64 called it a division by zero and arm64 gave the dividend.
  • A crash inside C code (printf given a bad %s) names the ktm line that called it and every caller up to main. x86_64 could name rt.crash or a function that had already returned and lose main; Linux arm64 showed only "in C code".
  • A module's extern "c" function is called by the module's name for it (libc.strlen): a program function with the same C name no longer takes those calls.
  • A method can be defined through a type alias of its struct.
  • An error in an asm function is reported on its instruction's line, not the line after it.