Menu

SVN-Code Commit Log


Commit Date  
[r13098] by mikeaubury

C# back end: restore three fixes lost to a revert

These were committed in r13095 and then reverted out of the working copy while
undoing an unrelated bad edit to the same file. The commit stands; the working
copy did not, and later work was built without them. Restored and verified
against the programs that first showed each:

- a struct with a field initialiser needs an explicit parameterless
constructor, and an array member is emitted with an initialiser
- two WHEN clauses may test the same value; 4GL runs the first that matches
and a C# switch rejects duplicate labels, so those take the if/else
fallback that already existed
- the keyword escape must not survive into a flattened identifier -
"InVar_a_@..." does not parse, and the flattened name cannot be a keyword

The lesson is narrower than it looks: revert takes the whole file, so undoing
one edit to a file that carries several loses the rest.

2026-09-06 13:47:01 Tree
[r13097] by mikeaubury

C# back end: type a function from its widest RETURN

A function not covered by the prototypes has its signature worked out by
scanning its RETURN statements - and the scan stopped at the first one it
found. A 4GL function may return different numbers of values on different
paths, so where a later path returned more, the function was typed too narrow
and its calls would not compile.

It now keeps the RETURN that yields the most values, matching how the compiler
chooses between a function's prototype variants (r13096): the signature has to
suit every call site, and the widest does.

2026-09-06 13:16:19 Tree
[r13096] by mikeaubury

Choose deliberately between a function's return shapes

A 4GL function may return different things on different paths - a value on one
and nothing on another, or a SMALLINT here and a DECIMAL there. fglproto emits
one prototype per shape, and is_bolton_function answered with whichever came
first, so which shape a back end saw depended on the order they happened to be
written. Arbitrary, and for a back end with a strict type system it decides
whether the program compiles at all.

The widest now wins: a function returning SMALLINT on one path and DECIMAL on
another is a DECIMAL function, and the narrow value converts to it without
loss. Where two shapes return different numbers of values the one returning
more wins, so no call site loses a result.

Ordering is SMALLINT < INTEGER < INT8 < DECIMAL < FLOAT < CHAR, comparing at
the first position where two shapes differ.

No change to the C back end's output on the example suite - it accepts either
shape, so it never depended on the choice.

2026-09-06 13:08:55 Tree
[r13095] by mikeaubury

C# back end: make ORDER BY reports compile

The ordered report path was almost complete - it creates the temp table,
prepares the insert, re-reads with an ORDER BY and replays the rows, matching
what A4GL_make_report_table and its siblings do in the C runtime, down to the
c0, c1 column naming. Three naming faults stopped any of it compiling:

- the reread cursor was used and never declared. Ordinary cursors become
class members when their DECLARE is compiled; this one is invented for the
reread and has no DECLARE, so it needs a local.
- the prepared statement was referenced without the Statement_ prefix that
print_prepare_cmd gives it.
- both, and a statement-level CALL ... RETURNING, need the module prefix
inside a report, which is emitted as a nested class. The expression form of
a call already had it; the statement form did not.

A4GL_cs_module_prefix exports that prefix for compile_cs_sql.c, which generates
the report body and cannot see the static function in compile_cs.c.

A report with an ORDER BY now compiles. Whether its rows come back sorted has
not been shown - that needs a database behind it.

2026-09-06 13:03:59 Tree
[r13094] by mikeaubury

C# runtime: date arithmetic, blob fetch, and two missing entry points

DateAdd and DateDiff. A DATE is a day count in 4GL - day 0 is 31 December 1899
- so adding a whole number adds days. C# has no operator for DateOnly against
an int and none can be added to a type we do not own, so the generator calls
these instead of writing the arithmetic inline.

GetData(out byte[]?, int) for BYTE and TEXT columns. The generator used to pass
the target by value, which could assign nothing. A driver may hand back either
bytes or a string, so a string is encoded rather than rejected - which is what
a program reading a TEXT column into a BYTE variable expects.

UI.ClearWindow: the protocol message existed and the entry point did not.

A report's COLUMN takes whatever the 4GL gave it, commonly a SMALLINT, rather
than requiring an int.

2026-09-05 22:00:36 Tree
[r13093] by mikeaubury

C# back end: report generation fixes

A report is emitted as a nested class, so the module's own members are not in
scope by their bare names. The body refers to SQL and to the error hook exactly
as module code does, and there are sixty emission sites - too many to qualify
individually - so the report now forwards both to the module once. A nested
class may reach its enclosing type's protected members, which is what makes
that legal.

startReportOrdered and finishReportReordered were called by the ORDER BY path
and defined nowhere at all, so no report with an ORDER BY could be compiled.
They are defined here. The ordering itself is still not done - print_report_
table's "make the table" phase emits nothing, so there is no temp table to
collect rows into and re-read - and rather than quietly produce a report in the
wrong order, the start says so once and then runs unordered. The rows are
right; only their order is not.

outputMode was assigned unqualified in one place when it is a field on the
report driver.

"while (1)" is not a condition in C#.

Note: r13092 carried more than its message describes. Besides the RUN ...
RETURNING fix it also contains DATE increment and decrement (the "d++"
shortcut has no meaning for a day count), DATE arithmetic through the runtime,
BYTE and TEXT columns fetched by out rather than by value, the module prefix on
seventeen cursor and statement references inside reports, and identifier
escaping in record initialisation - a fourth site where a field named after a
C# keyword was emitted bare. The log could not be corrected after the fact:
this repository has no pre-revprop-change hook.

2026-09-05 21:59:56 Tree
[r13092] by mikeaubury

C# back end: close the wrapper on RUN ... RETURNING

decode_varbind in 'w' mode opens a conversion around an assignment target -
"x = AsSmallInt(" - and its ')' mode closes it. The LET path does both; RUN ...
RETURNING only ever opened one, so the statement was written a bracket short:

L_stat = AsSmallInt(Fgl.ExecuteCmd(L_cmd);

That is a parse error, so it took the whole module's diagnostics with it and
showed up as a scatter of unrelated-looking syntax errors rather than as one
obvious fault.

2026-09-05 21:59:13 Tree
[r13091] by mikeaubury

Fix INTERVAL addition and negative results

Two faults in the year-month branch of A4GL_in_in_ops, which is where interval
arithmetic actually happens.

Addition wrote the total as a float and handed that to the parser:

SPRINTF1 (buff_3, "%f", d_i1); /* "68.000000" */
acli_interval (buff_3, 0x822);

which cannot be read as a year-month interval, so every addition of two
intervals produced 0-00. Subtraction, a few lines below, already split the
total into years and months and wrote "Y-M". Addition now does the same.

That shared formatting was itself wrong for a negative total: it wrote each
field with its own sign, so -40 months came out as "-3--4", which does not
parse either - any subtraction giving a negative result produced -0-00. The
sign belongs to the value, not to each field, and is now written once at the
front with the fields carrying the magnitude.

The day-time class was already correct; it goes through the seconds path.

The interval fidelity probe now covers subtraction, addition and a subtraction
crossing zero, in both classes.

Note that A4GL_op_ival in lib/libaubit4gl/interval.c, corrected in r13081, has
no callers - the two bugs fixed there are real but that function is dead code,
and it is not what interval arithmetic runs through. Left as it is: it is
correct now, and worth keeping that way if anything ever calls it.

2026-09-05 12:45:20 Tree
[r13090] by mikeaubury

Add an INTERVAL fidelity probe

Checks INTERVAL qualifiers against the C runtime, and in particular what the
leading field's precision does: the value is written unpadded and then
right-aligned in a width the qualifier decides, so YEAR TO MONTH and YEAR(2) TO
MONTH print alike and YEAR(4) wider. The default leading precision is two for
every field, YEAR included, which this is what establishes.

Three INTERVAL cases are deliberately left out because the C runtime is wrong
about them, and a probe that fails for a known reason stops being useful as a
guard. The file names all three.

run.sh no longer writes its own entry point: the generator emits a static Main
in whichever module holds the 4GL MAIN, so supplying one here would be a second
entry point and the build would refuse to choose.

2026-09-05 12:35:31 Tree
[r13089] by mikeaubury

C# runtime: INTERVAL qualifiers, LOAD/UNLOAD, PUT, and missing builtins

INTERVAL now carries its qualifier as a value. FglIntervalQualifier holds the
two fields it spans and how many digits the leading one has; FglInterval keeps
it, so a value knows how wide it prints without anything being passed alongside
it. The precision is part of the type in 4GL, not decoration - YEAR(4) TO MONTH
and YEAR(2) TO MONTH display the same magnitude differently - and it was being
dropped. Rendering writes the fields the qualifier actually spans and stops at
its last one, so HOUR TO MINUTE is "12:30" and not "12:30:00", and the value is
right-aligned in the width the qualifier gives it. The new interval fidelity
probe pins all of this against the C runtime.

Also on the temporal types: arithmetic on DATETIME and INTERVAL, DATE plus or
minus an INTERVAL (month arithmetic clamping to the target month's last day),
comparison operators for DATETIME, EXTEND, and an INTERVAL literal.

LOAD and UNLOAD are implemented, following Informix's delimited format - one
line per row, a trailing delimiter before the newline, NULL written as nothing,
and delimiter, newline and backslash escaped within a value. PUT and FLUSH on
an insert cursor. Neither has been run against a live database.

Missing builtins added: writeln, FGL_LASTKEY and FGL_KEYVAL (using the
numbering from A4GL_net_keyval and the A4GLKEY_ constants, so a program
comparing them sees the same values as under the C runtime), the UNITS
builtins, Pow, and PRINT with no argument. DAY, MONTH, YEAR, WEEKDAY and MDY
take object? and give back a nullable, so a NULL date propagates instead of
throwing, and they accept a DATETIME as 4GL allows. CompareString gained an
overload that compares a DATE as a date rather than as text - as strings
"01/01/1901" sorts before "12/31/1900".

STATUS is assignable, routed through a setter that keeps the status fields
consistent rather than writing SqlCode alone. CONTINUE moved to the dialog base
class, since 4GL spells it for every kind of dialog. f_open and readln take the
shape of the C entry points they replace, with their results as out parameters.

The client/server call layer still throws, but with the signatures its
prototypes describe rather than params object?[] guesses - the generator emits
out arguments for the values a function returns, and a params array cannot take
one.

2026-09-05 12:35:17 Tree
Older >