Repository navigation
Releases: hiroshiyui/afterschool_pascal
Release list
v4.0.0
The library reads as methods of its types, and every program that calls it
must change. Sixteen modules export 203 names where they exported 354; the
151 that went are gone rather than deprecated, because §6.11.2 puts every
imported name in one scope and keeping both spellings would keep the collision
the change exists to remove. There is no migration period. What a caller does:
| was | is |
|---|---|
JsonIntegerOr(JsonMember(p, 'line'), -1) |
p.Member('line').IntegerOr(-1) |
TomlPath(doc, 'server.port') |
doc.Path('server.port') |
ErrorText(e) |
e.Text |
IVecPush(v, 10) / SVecGet(v, 1) |
v.Push(10) / v.At(1) |
NetWriteLine(s, t) / TlsWriteLine(c, t) |
s.WriteLine(t) / c.WriteLine(t) |
StreamReadLine(f, l) / NextEntry(d, n) |
f.ReadLine(l) / d.NextEntry(n) |
A name that is still exported is one with no receiver to select from: a
type, a bound, a constructor (JsonNewObject, TomlNewTable, IVecNew), or
an entry point that answers a value rather than acting on one (JsonParse,
RegexCompile, NetConnect). pascalc --dump-uses and the language server
answer where a method is defined; grep for a bare Put no longer does, which
is the one cost no gate sees.
This is the major number because of that table, not because of the language:
every construct that compiled before this release still compiles, with two
exceptions listed under Removed.
Added
-
A module's implementations reach the components that import it
(ADR-0411, AP 6.7.10.5).impl Circle;andimpl Renders for Circle;
written in a module-block are selected in every program-component that can
nameCircle— so a library's types carry their own routines, and
c.Area,Area(c)and adyn Rendersbuilt by the client all reach them.
Nothing about the spelling changed; what changed is which translations may
read it.Until now this did not work and was not refused: the call compiled and the
program failed at the assembler or the linker, naming a symbol no source
spells. AP 6.7.10.1 NOTE 9 had recorded it as not provided (ADR-0341).A method's heading is now part of what a component is translated against,
so changing one without rebuilding the client is refused at the link, the
way a changed module-heading already was (AP 6.13.2). Changing a method's
body still costs no relink.A method may be
external, which had been admitted since methods landed and
is now pinned by a case; it is the one method shape whose linkage name is
C's rather than this compiler's. -
A type may have routines of its own:
impl T;andx.M(a)(ADR-0410,
AP 6.7.10, AP 6.7.10.4).impl Point;declares routines belonging to
Point, with the receiver written as an ordinary first parameter, and
p.Shift(1, 1)calls one. It is not a second mechanism:x.M(a)and
M(x, a)denote the same call, the routine having been selected from its
first argument's type since traits landed, so a method may be written either
way and any variable may be the receiver —p.Len,q^.Len,a[1].Len,
b.inner.Len.What it buys is that a method is not an exported name: a module exports
the type, and its routines travel with it, so two modules may each have a
Putwhere §6.11.2 refuses that to two exported names. 139 of this
library's 486 exported names repeat their own module's noun to work around
exactly that.A type may not have a field and a routine of one name, and is told so where
the implementation is written. A method called on what a method returned
needs that second method to take its receiver by value, §6.6.3.3 wanting a
variable for avarparameter.implreserves nothing.This completes ADR-0315's three increments, all of them now built.
-
A collection may hold values of different types:
dyn T, the trait
object (ADR-0408, ADR-0409, AP 6.7.11).type Shape = dyn Renders;denotes
something that implementsRenders, andowned ^Shapeowns one;take
moves a concrete value in and attaches its implementation, and a call
through the result selects the implementation where the value is used
rather than where the call is translated. This is what a bound
(AP 6.7.3.10.5) cannot do — a bound chooses where the type is written, so
one collection is one type — and it is the first place this compiler emits a
dispatch table.A trait object stands in two positions: the domain of an
ownedpointer and
avarorprotected varparameter. Everything else is refused with a
message saying where one can stand, because every other position would hold
a value whose lifetime nothing states. The implementation travels with the
value and so does the release, so disposing anowned ^Shapereleases
the concrete value and whatever that owns.Not every trait has a trait object: each routine must take its receiver as a
varorprotected varfirst parameter and nameSelfnowhere else, and a
trait that does not is told so where thedyntype is declared, with the
heading named.dynreserves nothing — a program may still declare a type,
a field and a parameter of that name.AP 6.7.11 was published one release early, marked
[not yet implemented]
under AP 5.6 — the first and only clause ever to carry that marker — and the
marker is now gone. Building it corrected two things the clause had said
(AP Annex E.13, E.14).
Changed
-
PasJson's routines are methods of its types (ADR-0412, AP 6.7.10).
The module exports 25 names where it exported 50, and a document is read
bydoc.Member('id').IntegerOr(-1)rather than
JsonIntegerOr(JsonMember(doc, 'id'), -1).JsonKindOfisKind,
JsonCharsAddLineisAddText,JsonTextIntoisTextInto, and so on
for 24 routines; what stays exported is what has no receiver to select
from — the types, the three bounds, the sevenJsonNew*constructors and
JsonParse/JsonParseChars.This renames a library's interface and every caller must change. The
old spellings are gone rather than deprecated:§6.11.2puts every
imported name in one scope, and keeping both would keep the collision the
change exists to remove.JsonCharsandJsonPtrnow each have aFree,
aLenand anAt, which two exported names could not have been. -
PasToml's routines are methods of its types too (AP 6.7.10). The same
change one format over, and the module it was modelled on: 31 names are
exported where 59 were, and a configuration is read by
doc.Path('server.port').IntegerOr(80)rather than
TomlIntegerOr(TomlPath(doc, 'server.port'), 80).TomlKindOfisKind,
TomlCharsAddLineisAddText,TomlPositionOfisTomlChars.PositionOf
-- a buffer asked about itself -- andTomlCharsandTomlPtrnow each
have aFree, aLenand anAt.TomlParse,TomlParseCharsand the
eightTomlNew*constructors keep their names, a parse answering a document
rather than being an operation of a buffer. Every caller must change,
for the reason above; the three TOML cases answer their goldens unchanged,
which is what says the rewrite moved no behaviour. -
Eight more library modules read as methods of their types (AP 6.7.10).
PasVectorexports 4 names where it exported 15,PasMap6 of 16,
PasStrVec6 of 19,PasRegex20 of 31,PasProcess12 of 22,PasNet10
of 14,PasTls16 of 20 andPasHttp27 of 38 — withPasJsonand
PasToml, 157 exported names where there were 284. A vector is
v.Push(x),v.At(i)andv.Len; a socket and a TLS connection both have
Close,WriteText,WriteLineandReadLine; a match is
m.GroupInto(1, s). Every caller must change, and the old spellings are
gone rather than deprecated, for the reason given above.Five spellings could not simply lose a prefix and the compiler said so:
IVecSet/SVecSetarePut(§6.1.2 reservesset) andBeginRequest/
BeginResponseareBeginWrite/BeginRead(it reservesbegin);
RegexFaultOf,RegexGroupsandRegexStepsareFaultOf,GroupCount
andStepCount, each beside a field of that spelling; andRegexFaultText
isRegexFault's ownText, an enumerated type being able to carry an
implementation. Nine receivers gainedprotected var: §6.7.3.1's advice is
deferred for an exported routine and fires on a method.PasFileis deliberately unconverted, and so arePasProcess'sRun,
CaptureandCaptureLinesandPasNet'sNetWait: their first parameter
is a type produced from a schema, or a schema, and neither may carry an
inherent implementation. -
PasErrorandPasLspDiagtoo, which finishes the conversion at
sixteen modules and 203 exported names where there were 354.ErrorText(e)
ise.TextandFailed(e)ise.Failed— an enumerated receiver, so
errNone.Textworks on a constant — andDiagJson(d, line, enc)is
d.Json(line, enc). 234 call sites across 48 files. What could not convert in
either module says what a receiver may be:ValueOrtakes a type-parameter
first, andHoldsNul,DiagParseandUtf16Columntakestringor a
production of it, which no module owns. -
Four more library modules read as methods of their types (AP 6.7.10).
PasListexports 3 names where it exported 13,PasStream6 of 11,PasLsp
7 of 10 andPasDir5 of 7 — with the ten before them, 177 exported names
where there were 325. A list isl.Push(x),l.Len,l.Reverse; a stream
and a socket and a TLS connection now shareWriteText,WriteLine,
ReadLineandClose.PasListkeeps no constructor, a fresh variable of
anowned ^being an empty list already. Every caller must change, for
the reason given above. -
PasNet.NetServiceisSocket.Service(AP 6.7.10), the one judgement
call the previous batch left open. It takes a socket tha...
v3.11.0
The editor replaces, and two things it shipped broken a day ago do not do
that any more. v3.10.0 put eight documents behind one screen in a day, and
two questions that had been complete became incomplete without changing: the
quit guard asked about the document on screen, so Ctrl-Q over a clean one
discarded another's work in silence; and the menu's key dispatch did not name
the two kinds that feature had added, so F3 or F6 with the menu open stopped
the program. Both are fixed, and the gate that could have caught the second is
now pointed at every program here instead of only at the compiler.
Added
- The editor replaces.
Ctrl-Rasks for a pattern and a replacement and
changes every occurrence in the document, matching case-insensitively as the
search does, with an empty replacement meaning deletion — and oneCtrl-Z
takes the whole of it back (ADR-0403).Search ▸ Replaceis the same thing
from the menu. That last part is why it is not a small feature: the undo
journal knew about operations and not about actions, so an entry may
now say the undo continues through it — a property of an entry, deliberately
not a fifth operation, so the four routines are still the only code that
touches the buffer. Confirm-each was rejected rather than deferred: what a
person wants after a replace that went wrong is to undo it. - Every program here is checked for a
casethat has stopped covering its
enumeration, not only the compiler (ADR-0404). The editor and the language
server join the sweep — five corpora, and adding one is a line — because
--dump-dispatchanswers that question about any Pascal program and had
been asked about one. 63 case-statements over 13 enumerations became 79 over
35. The crash below is what the widening found. - The editor's shell is checked.
tui-terminaldrives the real editor
under a pseudo-terminal and requires every coloured run it writes to be one
the model decided, at the same columns, in the colour that role's table
gives, over both the twenty-four-bit and the eight-colour table (ADR-0402).
Nothing had ever read a byte the editor wrote to a terminal: a shell
painting every row in one flat colour passed every oracle here. The
expectation is derived from the session golden's own run decomposition
rather than recorded.
Changed
- The runtime's POSIX half is two translation units. What the operating
system is asked about — a file's size and kind, a directory's entries,
whether a descriptor has anything to read — is nowruntime/pasrt_file.c,
and what it is asked to do — a process, a socket, a terminal, a private
directory — stays inruntime/pasrt_posix.c(ADR-0405). Nothing a program
can call changed; what changed is that a target with a file system and no
processes gets the first half, which is whatwasm32-wasiis. 560 of the
598 corpus programs ran there and 563 do.
Fixed
- The editor no longer discards another document's changes on one Ctrl-Q.
Since eight documents landed in v3.10.0, the quit guard asked whether the
document on screen was modified, so typing into one file, opening a clean
second over it and pressing Ctrl-Q once exited with no prompt and no
message. It now asks about every open document and the message says how many
hold changes (ADR-0401). Two presses still discard, as they always have. - F3 and F6 no longer stop the editor when the menu is open.
MenuKey
dispatches over the key kinds with acaseand nootherwise— the right
shape, since an unmatched selector is a reported trap rather than a
swallowed key — and the two kinds the second document added in v3.10.0 were
not listed, so opening a file or cycling documents from under an open menu
exited withcase: no label matches the selector. - A test case is run in a directory of its own, not the one the harness
was invoked from (ADR-0406). Every case shared the invoker's, so the one
case that names a file relatively raced its own concurrent copy — eight
failures in twenty concurrent pairs, and none after. Only the two harnesses
that start the program under test changed; a toolchain still runs where it
was invoked.
v3.10.0
A text value knows how wide it is, and the editor is one you can work in.
AP 6.4.15.13 defines display width and PasUnicode.Columns answers it, so a
column in the editor is a cell rather than a byte; and the editor opens eight
documents, scrolls sideways, lands on a diagnostic in whichever of them it
names, and draws in twenty-four-bit colour where the terminal has it.
Added
- A question is a box (ADR-0392).
Find,Go to lineandSave asare
centred framed dialogs instead of a line at the bottom, so the editor draws
one kind of thing for one kind of thing. It is the second user of the panel
primitives, which is what tests whether they are an abstraction. - The editor has a menu bar (ADR-0391):
File Edit Search Runalong
the top, F10 (or Ctrl-O) to open, arrows to move, Enter to choose, Ctrl-C to
close — drawn as a framed drop-down in real box characters. A screen
became one array element per display column to make that possible:┌is
three bytes and one column, so a row indexed by byte could not hold a frame
and keep the colour plane naming what a person sees. A menu item names a
key, so choosing one is the same path as pressing it — no second dispatch. - The editor decodes the function keys and binds two of them in Turbo
Pascal's positions: F2 is Save and F9 is Build. Both spellings a
terminal uses are understood —ESC O Q(SS3) andESC [ 1 2 ~(CSI) are
the same key — and the decoder maps a bound one to the key it is bound to,
so nothing above it learns that Save has two spellings. The other ten are
decoded and reported by number (F5 is not bound) rather than ignored. The
hint bar now readsF2 Save F9 Build ….
Added
- A second reading of the width properties (ADR-0400).
East_Asian_Width is the one Unicode property here with no conformance
file, so the newicu-widthcase compares AP 6.4.15.13's table against
ICU's reading of the same two files — applying the clause's own rules
toUCHAR_EAST_ASIAN_WIDTHandu_charType, so what is compared is two
transcriptions and not two opinions about rendering. 1 112 064 code
points, exact agreement. It abstains when ICU's Unicode version is not
the pinned one, which is what makes exactness a claim worth making. - The editor scrolls sideways (ADR-0397). A line wider than the window
was cut; the window follows the cursor now, by column rather than by
byte, so a line of Japanese scrolls by what a person sees and a wide
character straddling the edge is dropped rather than half-drawn. - The editor opens more than one file at once (ADR-0396). F3 opens, F6
goes to the next, up to eight — each with its own cursor, scroll, dirty mark
and undo journal, and the status line says which of how many. This is what
makes it usable on this compiler:pascalctranslates every
program-component and this compiler is three of them, so a diagnostic
naming an open document is now landed on, switching to that file. PasUnicode.Columns, and AP 6.4.15.13 to define it (ADR-0395). How many
cells a text value occupies when a fixed-pitch terminal draws it: Wide and
Fullwidth take two, a mark or a format character takes none, and the unit is
the element, soewith a combining acute is one cell and a family
emoji is two rather than six. AP 6.4.15 NOTE 14 had put this outside the
language and is amended to point at the clause — it was right that no
property of a character answers for a proportional font, and wrong that
nothing was left to answer.- The editor edits East Asian text correctly (ADR-0395). A column is a
cell rather than a byte, the arrows and Backspace and Delete move by
element, and a wide character occupies two cells with the second holding
nothing.ed.colis still a byte and the status line still shows one,
becausepascalcreports a diagnostic's column in bytes and Ctrl-B has to
land on it. PasTerm.SetRgb, twenty-four-bit colour (ADR-0394). SGR's direct
38;2;r;g;bform over anOctetsubrange, beside the eight ANSI colours
the module has had. It has noclDefaultand cannot — the terminal's own
colour has no numeric value to name — so a program drawing a document still
writesSetColour(clDefault, clDefault)and leaves the person's own colours
alone. Whether a terminal understands the form is the caller's policy: there
is no query one lacking it answers safely, andCOLORTERMis what emulators
set.- The editor draws a published palette where the terminal can show it
(ADR-0394).apidereadsCOLORTERMonce and keeps two tables: the eight
ANSI colours for every terminal, and five colours of the LUXE scheme for
one that says it understands twenty-four bits. Five of ten is the finding
rather than a compromise — the scheme's rose, khaki, slate, blue and
vermilion reach at best 6.7:1 against anything else in it, and every cell of
a text editor is text. Both tables are held to the same floor.
Fixed
- Ctrl-B no longer lands on the wrong line of the wrong file.
EditFault
parsedfile:line:col:and threw the filename away, so a diagnostic naming
one of the other program-components jumped to that line number in whatever
document was open and displayed the message as though it had arrived there.
pascalctranslates every component and this compiler is three of them, so
that was the ordinary case rather than a corner. A diagnostic about another
file is now reported as the compiler wrote it, position and all, and the
cursor stays where it was. - The editor's colour is legible, and a role that nothing draws now fails a gate (ADR-0393). A drop-down's body was cyan on blue, which is 4.8:1 on xterm's own palette and worse on a muted theme, and the message line was yellow on the terminal's own background, which on a light terminal is yellow on white. Every role but the document's text now pairs black or white with a colour, at 7.5:1 or better. And a dialog's answer is drawn as a field again:
crPrompt— the editor is waiting for you — had been declared, coloured and drawn on no screen since the prompts became boxes, with all fifteen session goldens agreeing. The newtui-palettecase holds both claims in both directions. - A menu that was legible and indistinguishable (ADR-0394). The fix above
put the selected menu title at black on white against a black-on-cyan bar:
16.7:1 to read and 1.6:1 away from the four titles beside it, so nothing
said which menu was open. A contrast floor cannot see that — both pairs pass
it — sotui-palettenow also requires two regions a person sees at once to
differ in their backgrounds by 3:1, and the three bars along the bottom
were rechosen together.
Changed
- The editor is
apide, and that is now its only name. v3.9.0 installed
it asafterschool, on the conventionpascalcsets over
selfhost/compiler.pas— buttui/build.pynames its default output after
the program it was given, so the script wrotebuild/bin/apideand the
CMake target wrotebuild/bin/afterschool, leaving one program under two
names with nothing to say which one a document meant. The script's default
is what keepsbuild.py '' session.pasfrom overwriting the editor and so
could not move; the binary did.cmake --buildnow produces
build/bin/apideandcmake --installputs it in<prefix>/bin/apide.
v3.9.0
Two more targets and a program that runs on one of them, and an editor
you can install and use. The compiler's --target= now admits seven
triples, two of which are not machines: wasm32-wasi, where 560 of the 598
programs in this corpus compile, link and print what they print everywhere
else under a WASI engine, and wasm64-wasi, admitted on the layout claim
alone because no sysroot for memory64 exists yet. And tui/ — withdrawn by
decision nine days ago and un-withdrawn for reasons that decision could not
weigh — is now afterschool, a CMake target installed beside pascalc, with
undo, search, go-to-line, save-as, colour and a hint bar.
Nothing an already-valid program does has changed. The runtime stopped
calling tmpfile and builds §6.7.5.5's auxiliary file out of two other ISO C
functions instead, which is a portability improvement on every target and no
change to behaviour; the runtime still holds zero preprocessor
conditionals.
Added
-
The editor has colour and a hint bar (ADR-0389). A cell carries a
role — document text, status, hint, message, prompt — and the shell maps a
role to a colour, soApEditstill names no terminal capability and a
palette change touches no recorded screen. The bottom row now lists the
bindings, which were discoverable only by reading the README.PasTermhad
gained colour for the editor with ADR-0381 and the editor had no way to
express it; this is what connects them. -
A document with no name asks for one (ADR-0388). Ctrl-S on a new
document opens aSave as:prompt instead of advising a restart, which is
what the fileless start needed to be usable: runafterschool, type, save.
The decision is the model's and the write is the shell's, so a session
drives the prompt and a golden holds it — ADR-0387's division of labour, and
the third prompt cost almost nothing because the first was built there. It
also removed a second copy of the document's name that the shell had been
keeping since milestone one. -
The editor is
afterschool, and it starts with no argument. It is a
CMake target and an installed program now —cmake --buildproduces
build/bin/afterschoolandcmake --installputs it in<prefix>/bin
besidepascalc— where launching it used to meantui/build.pywith three
arguments and an output path a person had to invent and then remember. With
no file it opens a new unnamed document rather than printing what looked
like a usage line, and a document with no name says so instead of failing at
the first Ctrl-S.tui/build.pyis still what builds it, and every one of
its arguments now has a default. -
The editor gains undo, find and go-to-line (ADR-0387), milestone two of
tui/. Ctrl-Z and Ctrl-Y over a journal in which every edit is one of four
named operations — insert, remove, split, join — so one entry both reverses
an edit and performs it again; a typed run is one undo and not one per
character. Ctrl-F and Ctrl-L search, case-insensitively because this is an
editor for a language whose identifiers are, wrapping round the end and
saying so. Ctrl-G goes to a line. A prompt is a mode of the model rather
than a loop in the shell, which is what lets a session drive one and a
golden hold it; Ctrl-C closes it, because a decoder handed one byte at a
time cannot tell a bare Escape from the start of an arrow. -
Programs run as WebAssembly (ADR-0385, ADR-0390). 560 of the 598 programs in this
repository's corpus compile forwasm32-wasi, link, and print what they
print everywhere else under a WASI runtime.tools/pascalccknows what the
target needs — the SjLj lowering the non-local goto compiles through,
libsetjmp, no-pthread, and a stack of a megabyte rather than wasm's
64 KB default. It was 519 until the runtime stopped callingtmpfile, which
is ISO C and which wasi declares and does not define: an exclusivefopen
and aremoveare both ISO C and do the same job, so 39 more programs run
with no preprocessor conditional added anywhere (ADR-0390). What is not
there yet is still the runtime -- channels, tasks, processes and sockets are
30 of the 38 that do not run. -
A seventh target:
--target=wasm64-wasi(ADR-0386), WebAssembly's
memory64. It is admitted on the layout claim alone — the emitted module
states the target's layout and clang assembles it — because no sysroot for
it exists to link against. It cost nothing in the compiler's layout rules:
every one already had the arm an LP64 target needs. -
A sixth target:
--target=wasm32-wasi(ADR-0383), also spelled
wasm32-unknown-wasiandwasm32-wasip1. The emitted module states
WebAssembly's layout and triple, andclangassembles it into a.wasm
object. What this does not yet do is link a program: the runtime does
not build for the target, andruntime-nonposixsays how far away that is —
two of its four translation units compile, one wants five headers wasi has
not got, and one wants threads the target does not have. -
A text-mode editor,
tui/apide.pas, in Turbo Pascal's mould and written
in this language: open, edit, save, and Ctrl-B to compile with the cursor
landing on the first diagnostic. Build it with
tui/build.py tools/pascalcc apide.pas ~/bin/apide. A first milestone, and
it says what it is not — no horizontal scrolling, no mouse, no undo, and a
column is a byte. -
PasTermgained the alternate screen, colour and a reset:
EnterScreen,LeaveScreen,SetColourandResetColour, each a string
the caller writes where it likes, as the five sequences before them are.
Removed
--target=x86_64-w64-windows-gnu, and every other spelling of it. The
compiler emits for five machines and every one of them is POSIX. Windows was
measured rather than assumed — a program was built and run under wine — and
then dropped: what remained was a frame-layout change compared across every
target and seven headers of winsock, for a platform this project does not
run. The measurements are kept indoc/history.mdfor anyone who wants to
take it up, and practical compatibility work is still welcome.
v3.8.0
The platforms were measured instead of assumed, and one of them was told
no. --target= admits six machines where it admitted three: a Windows
triple, and both Darwin ones, so a module built on macOS names the machine it
is for rather than relying on clang to override an x86-64 Linux header. A
release now ships a macOS archive beside the two Linux ones. Windows got as
far as a program that runs and was then deferred, on a run rather than a
reading — a trivial program prints its golden under wine and the non-local
goto faults on an alignment this compiler gets wrong for Win64 alone. Minor,
because the command line accepts input it used to refuse and nothing already
accepted changed meaning.
Added
- Three more targets (ADR-0371, ADR-0372).
--target=accepts
x86_64-w64-mingw32,arm64-apple-macosxandx86_64-apple-macosx, with
the spellings people write for each, and the emitted module states that
target's own datalayout and triple — each taken from clang and verified
byte-identical. Win64 is the first LLP64 target here, a pointer of eight
bytes with a four-byte Clong, which cost one line because AP 6.4.2.7's
clongandcsizealready existed for saying "whatever this target's is". - A macOS release archive (ADR-0375). A
v*tag now produces
afterschool-pascal-<tag>-arm64-darwin.tar.gzbeside the two Linux ones.
Apple ships no static libc, so that archive cannot be statically linked and
is not required to be; what is checked instead is a claim that platform can
answer — that the binary depends on nothing outside/usr/liband
/System, whichotool -Lreports and every hosted runner's Homebrew
makes worth asking. - Platform tiers, written down (README). GNU/Linux is the first tier —
the seed is generated for x86-64, every gate has a job that installs its
tools, and i386 is built and run at two optimisation levels. macOS (arm64)
is the second: the whole suite runs there natively on every push and the job
can fail. Everything else is unsupported, and README says what a
contributor starts from. - Four gates.
runtime-nonposixcompiles the runtime for a target that is
not POSIX and holds the result in a catalogue that fails both ways
(ADR-0369);setjmp-aritycompares the_setjmpthis compiler emits
against what each target's C library declares (ADR-0371);
helper-portabilitymakes ADR-0366's rule mechanical (ADR-0367); and
foreign-widthgained a second claim — a C function declared in more than
one module must have one representation (ADR-0376).
Changed
readstrandwritestrare backed by memory, not by aFILE *
(ADR-0370). §6.7.5.5 asks for an auxiliarytextvariable backed by memory
and never for a stream;fmemopenandopen_memstreamare POSIX and were
two of the three names that stoppedruntime/pasrt.ccompiling for a target
that is not POSIX. The formatting is untouched — the same bytes, handed
somewhere else — andruntime/pasrt.c's departure from ISO C went from five
names to three.tmpfile()would have been ISO C and is 88 times slower,
measured.- macOS is a job that can fail (ADR-0368). It was advisory from the first
run of the port; the whole suite runs there natively on every push now, and
a macOS failure stops the build. Nine gates still skip, each naming a tool
the runner has not got, and the job lists them with the reason for each. - Every helper is Python 3, and a gate keeps it that way (ADR-0366,
ADR-0367). The thirty-one shell scripts under test were converted one at a
time, each proved by byte-identical output from both versions on this tree
and by its own historical mutation re-run;tools/pascalccis the one that
remains, by decision.helper-portabilityrefuses a new shell script, the
constructs bash 3.2 lacks in the one that is catalogued, and a Python helper
starting a general-purpose utility to do what the standard library does. - The runtime holds one preprocessor conditional (ADR-0373), where it held
none._longjmpis what pairs with the_setjmpthe emitter writes and
mingw-w64 declares no such name; no portable spelling exists,longjmp
after_setjmpworking on glibc and restoring on Darwin a mask that was
never saved.runtime-isocnow catalogues the set of conditionals in both
directions, so a second one is a decision with a record.
Fixed
- A task may have helper routines. AP 6.7.8.2 admits a variable declared
"in that task-declaration or in a block within it", and a procedure or
function declared inside a task was refused its own parameters and its own
locals — so recursion inside a task, and any helper at all, could not be
written (ADR-0365). - A task declared inside a task no longer lifts the rule from the one that
contains it. Every statement of the outer body after the inner
declaration could name a global. writeln(output, x)is accepted inside a task, aswriteln(x)always
was; both write the same required variable.task A; forward;is refused. AP 6.7.8 admits no directive.- A task-declaration may stand in a module-block, so a library module can
export a routine that spawns its own workers. A module-heading is refused
one, with a diagnostic that says why. - A deferred statement of a block no longer runs before the block's tasks
are joined.defer c := nilbeside aspawnclosed the channel the task
was still sending on, which AP 6.9.3.12.1 forbids. - An integer expression may be sent on a channel of real, and passed to a
real formal of a task. Both were accepted by the front end and then
refused by the assembler, 6.4.6 c)'s conversion never having been emitted. - A failed write to a text file is reported.
pas_write_paddedcalled
fwriteand ignored the result where the primitive beside it checked;
both go through one emitter now (ADR-0370). - Two goldens pinned a platform rather than a program.
lib_net_wait's
fixed which of a buffered line and a socket's reply a round saw first, and
lib_net's fixed how many writes a closed connection takes to be refused —
two on Linux, more than a hundred on macOS, where they fit in a send buffer.
Both were found by macOS after passing on Linux for their whole lives. - Four gates were asking about something other than what they said.
runtime-isoc's fifth strict compile spelledclangliterally where the
other four honouredAPASCAL_CLANG;irtestread neithername.optnor
AFTERSCHOOL_PASCAL_OPT, so the fixed-point harness compiled at a level no
case had asked for;runtime-coverage's two totals were written and never
compared, and had drifted; andtlsreported its findings to nowhere.
v3.7.0
A command is words, not a line — and the boundary answers instead of
stopping. A path an editor handed the language server could run a shell
command; closing that gave the library PasProcess.Execute, an audit of the
fix the same afternoon closed six more findings, and a project-wide audit
after it found nine foreign scalars bound at the wrong width and nineteen
routines that stopped a program on a name holding chr(0). Beside that, a
TOML library and the project reader rewritten over it. Minor, because the
library and the command line grew and nothing already accepted changed
meaning; a program that met one of the fixed defects met a trap or a wrong
width, and neither is a behaviour to preserve.
Added
-
PasProcess.Deadline— how long any run of anArgVmay take; on expiry
the child is killed, the pipe is closed so a grandchild cannot hold the
caller either, and the run iserrIO.PasFS.TemporaryDirectory— a
directory of the program's own, overmkdtemp, for a caller that wants
several files by names of its choosing (ADR-0363). -
A command as words, not as a line —
PasProcess.Executeand the four
routines beside it (ExecuteInto,ExecuteBoth,ExecuteLines,
ExecuteToFile), over anArgVbuilt withNewArgs,AddArg,ArgsLen
andDropArgs. The words are carried as words and no shell reads them, so
an argument holding a space, an apostrophe, a semicolon or a backquote is an
argument.Run,CaptureandCaptureLinesare unchanged and remain the
right answer for a pipeline or a redirection; preferExecutewherever any
part of the command came from outside the program (ADR-0362). -
A TOML library —
lib/dialect/pastoml.pas, TOML v1.0.0 whole rather
than a subset: bare, quoted and dotted keys; basic, literal and both
multi-line string forms; decimal, hexadecimal, octal and binary integers with
underscores; floats withinfandnan; all four date-time forms; arrays
over several lines and with a trailing comma; inline tables; tables; and
arrays of tables.TomlParseandTomlParseCharsanswer aTomlResult, and
TomlPositionOfturns the byte a refusal stopped at into a line and a
column.TomlPath(doc, 'server.port')is the dotted lookup a configuration
reader wants;TomlRenderwrites a document back, and parsing that and
rendering again reproduces it byte for byte. A date-time is §6.4.3.4's
ownTimeStampwith a nanosecond and a UTC offset beside it, so a program
hands the result straight toPasTime. An integer isinteger, so a
value outside -maxint..maxint iserrRangeand never a wrapped number.
ADR-0360. -
PasText.RealToStr— the shortest decimal that reads back as a given real,
which wasPasJson's and is now where two formats can reach it. ADR-0359. -
bin/apconfig— the project-file readerpascalcc build,runand
testcall, written in this language overPasTomland installed beside
pascalc.APCONFIGoverrides where the driver looks for it, asPASCALC
does for the compiler. ADR-0361.
Fixed
-
Nineteen library routines stopped the program on a name holding
chr(0)-- every path, name, host or service taken byPasFS,PasDir,
PasEnv,PasIO,PasStreamandPasNetreached ADR-0122's trap. Each
now answers a code (errSyntax,falseornil) through the shared
PasError.HoldsNul, which is ADR-0363's rule applied to the whole library
rather than to the two routines it was written for. -
Nine more foreign scalars bound at the wrong width, and the emitter's own
slice count (ADR-0364):read/write(ssize_t),fflush(a pointer)
and six OpenSSL bindings (longs and pointers) wereint64; nowcsize
orclong. A slice's count crossed every foreign call asi64, on i386
too, wheresize_tis 32 bits -- it is the target's width now. The new
foreign-widthgate holds both, because no behavioural case can: on a
host whose spare register is clean the wrong width gives the right answer. -
PasProcess.SecondsandCpuSecondsanswered garbage on i386:time
andclockwere bound as returningint64, and both arelong, 32 bits
there -- the high word was whatever the register held. Bound asclong
now (AP 6.4.2.7); found by ADR-0363's deadline case, the first to compute
withSeconds, under thetarget32gate on CI. -
Six findings of the security audit over
PasProcess.Execute(ADR-0363),
four of them older than it: a path holdingchr(0)stopped the language
server on one request, and is now refused as a code;ExecuteToFile
followed a symbolic link, and the server's scratch files were composed at
the top ofTMPDIRunder a guessable name —O_NOFOLLOWnow, and a private
mkdtempdirectory removed atexit; noExecutehad a deadline; a child
inherited every open descriptor (FD_CLOEXECon pipes and sockets, mode
eon everyfopen); threeposix_spawnfile-action returns went
unchecked; and a failedfdopendropped the output silently. -
A path the language server was given could run a command (ADR-0362).
lsp/pasls.pasassembled a shell command and wrapped the source path in
apostrophes; a path holding an apostrophe closed the quoting, so a file named
a'; touch PWNED; echo '.pasrantouch PWNEDwhen an editor asked for its
outline — and under MCP the path comes from whatever is driving the model.
The server now spawns the compiler with an argument vector and quotes
nothing.tools/pascalccwas never affected: it is bash and uses arrays.
The newcommand-injectiongate holds both halves — that nothing ran, and
that such a file still compiles. -
afterschool-pascal.tomlis read as TOML. The driver read it with a
declared subset written inawk, which got two kinds of legal document
wrong: a#inside a quoted string ended the value, sooutput = "build/demo#1"silently builtbuild/demo; and an array was split on every
comma, soldflags = ["-Wl,-rpath,/opt/lib"]— one flag — was rejected as
three malformed strings. Both now read as TOML says, a syntax error names a
line and a column, and an unknown key or a value of the wrong shape is
still refused by name. ADR-0361. -
Writing a NaN through
PasJsonstopped the program. The guard against a
value with no decimal spelling askedx <> x, which is false for a NaN on
this processor —<>on reals is ordered not-equal — so the guard never
fired and the scan below it read past the end of whatwritestrhad
written, reportingarray index out of boundsagainst a line of the
library. It asksnot (x = x)now. A program could only reach it by
computing a NaN, this language having no literal for one. ADR-0359.
v3.6.0
The library asked the language for something, and got it. Traits landed in
3.5.0 with one client; this release is the one where PasContainer's map keys
itself with a trait and every map call loses two arguments — the payoff the
feature was measured against, and a break for every existing map client, said
below in as many words. Around it: the sanitizers see compiled Pascal for the
first time, an outline calls a task a task, a refused generic instantiation is
reported once instead of a hundred times, and pascalcc new-project writes a
project a program can be started in. The number is minor because the accepted
language and the command line grew and nothing they accept changed meaning; a
library interface changed, and the entry says which.
Changed
- Every emitted function carries
sanitize_addressandsanitize_thread
(ADR-0358).AFTERSCHOOL_PASCAL_CFLAGS=-fsanitize=addressnow instruments
the program and not only the runtime — a use-after-free written in Pascal
is reported with a stack trace where it printed a value — and
-fsanitize=threadsees a race between two tasks. The attributes are inert
without the flag. Thesanitizersandthread-sanitizergates refuse to
sweep until a probe the sanitizer must report is reported, and the corpus
was clean under both with compiled Pascal instrumented on the day. --dump-symbolsreports a task astask(ADR-0357), where it reported
procedure— a task is started byspawnand cannot be called, so an outline
naming it a procedure sent a reader to the wrong construct. The language
server maps the new word besidefunction, the protocol having no nearer
kind, and the MCPoutlinetool writes the word itself. A client written
against the previous list reports a task as a variable until it learns the
word.PasContainer's map key implements a trait, and every map call loses two
arguments (ADR-0355).Map(K: Key; V: type; cap: integer)binds the key
discriminant withtrait Key—Hash(k: Self): integerandSame(a: Self; b: Self): boolean— declared in the module's interface.MapPut,MapGet,
MapHasandMapDeleteno longer take a hash and an equality; the client
writes oneimpl Key forits key type, before the map type is produced, and
StrHash/StrEqstay exported as what a string key's implementation calls.
This breaks every existing map client: the four in this tree lost 34
argument pairs and gained one implementation block each (three for
lib_container_key, one per key capacity), with every golden unchanged. The
module cannot supply an implementation for its ownMapKey(ADR-0341), so
even the ready-made key type takes two lines in each client.
Fixed
- A refused generic instantiation is reported once (ADR-0356). A schema
whose type-valued discriminant failed its bound used to produce^integer,
and every generic body instantiated against it then reported faults located
in the library — seven lines for oneMapInit, a hundred for a client that
also put and got — after the one line that was the diagnostic; and a call
whose instantiation was refused for a category, a bound or an undetermined
type was followed byunknown functionnaming the function just refused.
The type now carries the refusal, no body is checked against it, and the
second message is gone. Five goldens lost fifteen lines and gained none.
Added
-
A project:
pascalcc new-project <name>(ADR-0348), aliasnew, with
build,runandtestreading what it wrote. The skeleton issrc/,
test/,build/, a.gitignore, a README andafterschool-pascal.toml;
pascalcc runin the new directory printsHello, world!without anything
else being done first.afterschool-pascal.tomlcarries what the compiler cannot infer — which
source is the program, where the executable goes, the optimisation level, the
target, extra import paths and the link flags, the last being what a
program bindingPasTlsotherwise has to know to pass by hand. It is looked
for in the current directory and each enclosing one. It lists no modules and
never will:import greet;findssrc/greet.pasby name, so adding a
module is adding a file and there is no build order anywhere. The reader is a
strict TOML subset —[section],key = "string",key = ["a", "b"],
comments — and refuses an unknown key or section by line number rather than
ignoring it.A subcommand is recognised as the first argument and nowhere else, so
pascalcc build.passtill compiles a file of that name.
v3.5.1
Nothing about the language changed. The version number here tracks the
accepted language, the diagnostics and the command line, and this release
touches none of them: it is the documentation pass after 3.5.0 plus four dead
symbols removed from the runtime. It is recorded because a release with nothing
in it for a user is worth saying so plainly rather than dressing up.
What the documentation pass found is the part worth reading, and it is in
doc/history.md under The release that checked itself:
three defects that cutting 3.5.0 surfaced and no gate could see, a seed that
named the machine that made it, and two documents claiming an oracle —
AddressSanitizer over compiled Pascal — that has never existed.
Removed
-
Four runtime symbols that nothing called:
pas_index_error,
pas_range_error,pas_disc_errorandpas_length_error, the two-word
forms kept as wrappers when ADR-0293 gave every trap its own position. The
3.5.0 reseed made them dead — the seed calls only the_atforms — and
doc/sop.md§7 had said since ADR-0293 that they could go at the next
reseed.The one compatibility note in this release: IR emitted by v3.4.0 or
earlier calls the two-word forms, so such a module will not link against
this runtime. Anything emitted by 3.5.0 or later is unaffected, and the
release archive ships the compiler and the runtime together. Recompile the
source rather than relinking old.ll.
Fixed
- A trap in a seed-built compiler names its position. The wrappers passed
none, so a crash inbuild/bin/pascalc— whichprocedure-coverageand
fuzzwatch for — reported where nothing. This is a fact about building the
compiler rather than about using it.
v3.5.0
The release that finished the memory model and then found out what it had left
open. owned ^T went into the library, which is what ADR-0181 was built for,
and adopting it turned up four ways a borrow could outlive what it borrows that
the rule as written did not see — three of them found by a langspec audit whose
whole purpose is that no oracle here can contradict a reading, and every gate
was green over all three.
Two threads of control became something a program can steer. A task is a
value now, with a name and a type; wait joins one; and the select-statement
waits on several channels at once, takes the first arm that can proceed, and
gives up after a timeout. ThreadSanitizer is the oracle underneath that, and it
is a gate rather than a thing run by hand.
A pointer is not always eight bytes. i386 is admitted, which took seven
layout rules rather than the 3858 offsets that looked like the work, and it
brought clong and csize — the first required identifiers whose type
depends on the target. It also decided something this release states outright:
an i386 this compiler emits for has SSE2, because on an x87 an error condition
this language says it detects goes undetected.
And traits. A trait bounds a schema's type-valued discriminant and a
routine's type parameter, an implementation is written by whoever names the
type, and lib/dialect/passortx.pas is the first client that is not a test —
impl Sortable for Point; once, and Sort(ps) thereafter. Four records
preceded one working feature and each says why the previous was wrong; the
first client found the fifth thing in under an hour, which is now a rule in
doc/sop.md.
Added
-
Waiting for a task, and for whichever of several things comes first
(ADR-0312, ADR-0313, AP 6.4.17, AP 6.9.3.15).taskis a required
type-identifier — shadowable, likeint64, and not a word-symbol — and its
values are handles, so a task is released by the block that declared it,
moved bytake, and refused as an assignment source like every other handle.
wait(t)blocks until that one task has finished. The select-statement
waits on several channels at once and takes the first arm whose operation can
proceed, with the case-statement's own punctuation:select receive(x, got): send(out, got); receive(y, got): send(out, got); after 2000: writeln('gave up waiting') end
A
sendarm waits for room as areceivearm waits for a value, anafter
arm gives up after that many milliseconds, and anotherwisedeclines to wait
at all. -
A third target:
--target=i386-pc-linux-gnu(ADR-0325). Every layout rule
that wrote 8 now asksPtrSizeorWordAlign, so a pointer is four bytes
where the target says so. The corpus runs against a 32-bit runtime under the
target32gate; the one program that cannot is a deliberate 2 GB allocation. -
clongandcsize(ADR-0328), two required identifiers denoting whichever
integer type a Clongand a Csize_tfit on the target —int64on x86-64
and aarch64,integeron i386. Anexternaldeclaration naming a C routine
that takes alongis now writable once rather than per target. -
A protected parameter may be of an owned-pointer-type (ADR-0318,
AP 6.4.14.8), which is the read-only borrow: a name for what a variable owns,
read through, and through which nothing may be released. §6.4.1's exclusion of
a pointer-type does not reach an owned pointer. -
A discriminated schema may be written wherever a type-name is required
(ADR-0324, AP 6.7.3.1.1, AP 6.7.2.1) — a parameter-form and a result-type both
takeVec(integer)where they took only a name. -
An array determines a slice parameter's component type (ADR-0316), as a
slice-type already did, soarray of Taccepts an actual of an array-type
without the caller writing the slice. -
PasSortX, a sort over the element type itself (ADR-0344): the trait
SortablewithSort,SortWith,IsSortedandLowerBoundOfover an
array of T. The trait is declared in the module and every implementation
is written by the client —impl Sortable for Point;once, andSort(ps)
thereafter — which is the only shape separate translation admits and is
what makes a trait usable from a library at all.SortWithtakes the order
as a procedural parameter instead, for a caller whose order is not the
type's or whose element type implements nothing.PasSortis unchanged and
stays: it is conforming Extended Pascal, and itsSortIndexedstill answers
for parallel arrays. -
A type may implement a trait, and a trait may bound a type (ADR-0338 to
ADR-0341, AP 6.4.7.2, AP 6.7.9, AP 6.7.10).trait Sortable; function Rank(u: Self; v: Self): integer; end;names routines a program supplies, and
impl Sortable for Point;supplies them — each routine written as a name
alone, the trait having given the heading. A call selects by the type of its
first argument, after the ordinary lookup, so two implementations of one
trait live in one block and a program declaring its own routine of the name
keeps it. A subrange takes its host's implementation. The bound is written
where the client writes the type — on a schema's type-valued discriminant,
Map(K: Sortable; V: type; cap: integer), checked once at the type-denoter —
and also on a routine's type parameter,T: Sortable type, where a category
would stand. One bound, not two. Neithertraitnorimplis reserved. A
trait may be declared in a module's interface and exported; an
implementation belongs to one translation, so it may not stand in a
procedure or in a module heading. -
A task may be handed a handle (ADR-0303, AP 6.7.8.1): a formal parameter
of a task-declaration may be of a handle-type, and the actual is written
takeof a variable of that type — the one position outside an assignment
where AP 6.4.14.6 admits a move. The variable is emptied before the
activation commences and the task's block releases what it was given, so a
socket, a stream or a directory can now be given to a task. A channel is
still lent and a handle is moved; a handle still cannot be sent through
a channel. -
A channel is closed by the release the program wrote (ADR-0302,
AP 6.4.16.4):release(c),c := nilandc := take(d)each close the
channel wherever they stand, including inside a task. Before this a task's
release dropped that task's reference and left the channel open, so a
pipeline of stages each closing the one downstream of it deadlocked with no
diagnostic. The release performed by the end of a task's block is unchanged
and still only drops the reference, which is what a pool of workers needs. -
A release archive on every tag (ADR-0296). Pushing a
v*tag now
attachesafterschool-pascal-<tag>-x86_64-linux.tar.gzand an
aarch64-linuxone, each with a.sha256, to the GitHub release: the
cmake --installlayout,LICENSE,COPYING.RUNTIMEand a shortREADME,
withpascalclinked statically.clangis still needed at use time.
tools/release.shbuilds and checks the archive,release-archiveruns
both halves underctest, andtests/checks/install_layout.sh --prefix
checks an unpacked prefix.APASCAL_STATIC_PASCALCis the CMake option. -
examples/(ADR-0295): twelve complete programs of a page each,
written to be read by someone who knows Turbo Pascal, every one actest
case (example-<name>) with a golden, and swept by the same gates as the
rest of the corpus. Writing them found seven things — a task cannot close
the channel downstream of it and a program that tries deadlocks silently,
a map lookup writes two types the call already knows, four of twelve
programs collided with a library noun — recorded in the ADR and in
doc/roadmap.mdrather than fixed here. -
tests/checks/heap_balance.pymeasures a case that resolves its imports
by.importpath, and--writerefuses to write a catalogue when a case
did not run instead of striking it in silence. -
diagnostic-coverageandforeign-layoutread nothing when the checkout
is itself a.claude/worktreestree, their worktree filter having tested
the absolute path; both now test the path below the root.
Fixed
-
The committed seed no longer names the machine that generated it
(ADR-0347). Since ADR-0293 a trap carries its own position, so the source's
path is a string constant in the emitted module — andseed/refresh.sh
handed the compiler an absolute one, soseed/*.llheld the reseeding
machine's home directory andtests/checks/seed_current.shcould pass only
in the directory that had produced it. Both now translate from the repository
root with a relative path, and a newseed-portablegate asks the cheap half
of the question on every push rather than at a tag. -
Disposing a long owned chain or a deep owned tree costs one frame
(ADR-0322, ADR-0333, AP 6.4.14.3). The release routine walked the structure
recursively, so a list or a tree deeper than the stack ended the program in a
segmentation fault rather than freeing it. Every self-owned field is emptied
onto a work list threaded through the nodes themselves, so the depth costs no
stack and no allocation. -
A block could reach an owner through a procedural parameter (ADR-0326),
and through a formal bound before its own activation existed (ADR-0332). Both
were ways for a borrow to outlive what it borrowed that the rule as written
did not see; both are refused, and the second is one conjunct rather than a
second rule. -
disposeof a variable whose domain is a schema found no tuple
(ADR-0329) where the walk reached one below the outermost, so a discriminated
component was released against the wrong bounds. -
PasJsonreads a number by rounding once (ADR-0314). The reader
normalised and t...
v3.4.0
The release that emptied doc/roadmap.md's What would make this easier to
work on. Three rows closed since 3.3.0 and all three by the same method the
chapter kept recommending to itself -- attempt the row rather than believe it.
Two were built and the third talked the page out of itself.
The fourth warning (ADR-0283) is the first whose answer is a property of
the whole compilation rather than of one routine, and it is a fixed point
rather than a list: protecting one parameter stops its callers' arguments from
being threatened and exposes the next layer. One pass over this tree reports
130 sites and seven passes report zero, having added protected 54 times.
--format --range=L:H (ADR-0284) was recorded as needing a parse to know
where a range's indent begins. It needs no parse: the printer accumulates that
depth as it walks, so the lines before the range are walked without being
written. textDocument/rangeFormatting follows from it.
And the style: gate was tried and declined (ADR-0285). A reformat of this
tree rewrites 42 601 lines and grows the implementation 6.8%, almost all of it
style rather than defect. What the attempt was worth is five layout defects it
found -- every one token-preserving, so every oracle here was green on all
five.
Added
-
pascalc --format --range=L:H(ADR-0284) writes those lines alone, with
the layout they have in the whole file.doc/roadmap.mdhad this down as
needing the printer told where its indent begins, "a question about the
enclosing structure that only a parse can answer"; the printer accumulates
that depth itself, so the lines before the range are walked without being
written and the depth on arrival is the one the whole file would have. A
boundary inside a construct gets a line break there that the whole file would
not have, which is what asking for part of a file means. A span it cannot use
is refused rather than widened to the document. -
The language server formats a selection.
textDocument/rangeFormatting,
beside the whole-document request. A client's range is a position pair and
the formatter's unit is a line, so the selection is widened to every line it
touches and the reply replaces whole lines; a range ending at character 0
does not reach into that line, so three selected lines come back as three. -
A
varparameter nothing writes through is reported (ADR-0283). The
fourth warning, and the first whose answer is a property of the whole
compilation rather than of one routine. 6.7.3.1 spells such a parameter
protected var, and the advice is exact rather than a guess: 6.5.1 forbids a
statement to threaten a protected variable-identifier, 6.9.4 lists the six
ways to threaten one, and the compiler already recorded every one of them --
so "never threatened" is precisely the condition under which adding the word
still compiles. A file or a pointer is never advised, 6.4.1 making it
unprotectable.It is not advised where the word would be illegal, which is why it is
written at the end of the compilation: a routine passed as a procedural
actual cannot take it, since 6.6.3.6 compares the parameter lists with
protectedin them and the call may be written after the routine; and
whether an exported routine is passed that way is a question no single
component can answer.
Changed
-
A program that compiled with three warnings may now print a fourth. As
in 3.3.0, nothing about what it does changes -- the emitted IR, the exit
status and the program's own output are untouched -- but avarparameter
the body never writes through is now remarked on. A build script that treats
any compiler output as failure is what notices. Every--dumpflag still
suppresses warnings, and the new one is never written for an imported
component, nor once an error has been reported. -
54 parameters of the compiler, the library and the language server are now
protected var. They are the warning's own first finding, and three were
groups likevar l, r, v: strsplit intoprotected var l, r: str; var v: str, which had been claiming all three were writable when one was. Nothing
about what any of them does changes --protectedis a Sema-only property
and the code generator never reads it -- but a future change that writes
through one of them is now a compilation error naming the clause.
Fixed
-
Five layout defects in the formatter (ADR-0285), found by pointing it at
36 real sources rather than at a case someone wrote. Every one preserves the
token stream, so every oracle here was green on all five. A blank line
inside a parenthesised list dropped the rest of the list to column zero. A
comment introducing anelsetook the indent of the arm above it.^was
glued to whatever preceded it, which is right for a dereference and wrong
for a pointer-type, printing= ^Tas=^T. AP 6.4.13's!is binary and
took a space on one side only. And 6.9.2.1's empty statement after a
case-label lost its space, printingred:;. -
and thenandor elsewere written straight to standard output by the
formatter, which adjusted its column counter by hand rather than going
through its one character sink. The bytes were identical either way, so
nothing could see it until--rangegave the sink something to suppress --
and then those two word-symbols printed outside the range asked for.