Menu

SVN-Code Commit Log


Commit Date  
[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
[r13088] by mikeaubury

Put the whole C# runtime in one directory

The runtime was split across two trees: four files under lib/liblex/lex_cs/
runtime and the other thirty-seven under dotnet/src/Aubit4GL.Runtime, joined by
a relative <Compile Include> reaching out of the project. One assembly, one
partial class, two places to look - and the cross-tree include was also why
building outside the fidelity harness kept failing to resolve the project
reference through a symlinked tree.

The four move to where the rest of them are: FglStrings, FglEnvironment and
FglProcess are Fgl builtins so they join the others in Types/, and
FglModuleBuiltins extends FglModule so it sits beside FglSession. The include
is gone and the emptied directory with it.

No code change - the files move as they are, with their history.

2026-09-05 12:34:24 Tree
[r13087] by mikeaubury

C# back end: type fidelity, INTERVAL qualifiers, LOAD/UNLOAD

SMALLINT was collapsed onto INTEGER in three places, each producing an int?
where a short? was needed:

- the cast fallback switch fell DTYPE_SMINT through into DTYPE_INT
- explicitCastFunction returned "AsInt" for DTYPE_SMINT
- the CALL ... RETURNING path folded SMALLINT onto INTEGER before deciding
whether a mapping variable was needed, so a SMALLINT-against-INTEGER return
was judged to match. C# passes those by out, which admits no conversion at
all, so the call would not compile without the mapping variable this
decision creates.

INTERVAL qualifiers are now built rather than spelled out. The leading field's
precision was being folded into the unit name - INTERVAL YEAR(4) TO MONTH
emitted FglTimeUnit.Year4, which no enum has - and elsewhere the qualifier was
passed as a string for the runtime to parse back, with the precision dropped on
the way. Both now emit a constructed FglIntervalQualifier carrying the two
fields and the precision, which the compiler can check and nothing has to
re-read at run time. Precision matters: it decides the width DISPLAY gives the
value. EXTEND is emitted the same way, as two units rather than a string.

LOAD and UNLOAD were A4GL_assertion(1, "Not implemented yet"), so any module
using them failed outright. Both are now emitted, UNLOAD handling a statement
held in a string and a parsed query - the latter going through the same
preprocessing and variable substitution a SELECT does so its variables become
bindings.

Also here:
- find_function fell through its cases, re-comparing a non-matching function
definition through report_definition.funcname - the wrong arm of the union
- a static Main is emitted for the module holding the 4GL MAIN, calling
FglModule.Run<T> so startup policy lives in the runtime
- Year, Month, Day, the UNITS builtins and Pow were emitted unqualified and
resolved against nothing
- a comparison with a DATE or DATETIME on one side only now goes through the
comparison helper: 4GL stores a DATE as a day count and lets it be compared
with an integer, which a raw C# == cannot do
- a call with fewer arguments than the prototype declares is padded, so the
existing FGLCHECK marker is left on a call that still compiles rather than
on one that cannot
- a bounded loop where ensure_parameters walked the declared parameter count
while indexing the arguments actually present, which ran off the end

2026-09-05 12:32:40 Tree
[r13086] by mikeaubury

C# back end: report group breaks compile without an ORDER BY

ordGroup was declared inside "if (cnt)" - only when the report has ORDER BY
variables - but the three blocks below it use the variable unconditionally. A
report without an ORDER BY emitted the uses and not the declaration, and the
generated method would not compile. The declaration is hoisted out of the
guard; the comparison loop that needs the ORDER BY list stays inside it.

2026-09-05 12:32:36 Tree
[r13085] by mikeaubury

C# back end: escape identifiers that are C# keywords

A 4GL variable is emitted with an L_/M_/G_ prefix and cannot collide with a C#
keyword. A record field keeps the name its schema gave it, and "ref", "out",
"in", "object", "lock" and "event" are ordinary column names - those came out
as

public int? ref;
... x.ref ...

which will not compile.

bad_idents.c already had the mechanism for this and its word list was empty, so
it always answered "fine". That list feeds the parser's reject path, though, and
filling it would make the compiler refuse such programs the way the C back end
does for its own reserved words. C# has a proper escape, so this adds
LEXLIB_A4GL_cs_identifier alongside it: the name survives intact as @ref and
reads back as the same identifier.

Applied at the use site and at all four declaration sites - flat members,
nested records and arrays of records. A second helper handles the declaration
sites, which build the type and the name into one string, so the identifier to
escape is the last token rather than the whole thing.

2026-09-05 12:32:11 Tree
[r13084] by mikeaubury

C# back end: resolve decode_cmd_type locally

libLEX_CSNEW.so shipped with an unresolved symbol. decode_cmd_type is only
called when the generator reports an unreachable statement after a RETURN, so
the plug-in loaded normally and then died part way through a module with

libLEX_CSNEW.so: undefined symbol: decode_cmd_type

leaving a half written output file behind.

fgl_enums.c and fgl_enums.h are copied here from lex_esqlc rather than linked
from it: the lex plug-ins are built and shipped independently, so one must not
depend on another's objects. The enums come from the shared compiler headers,
so the two copies cannot drift apart silently - a new enumerator makes both
fail to build in the same way.

2026-09-05 12:31:55 Tree
Older >