Menu

SVN-Code Commit Log


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

Bound the prototype parameter and return lists

add_bolton splits a prototype's parameter and return lists into

char *p_params[200];
char *p_rets[200];

with no bounds check, so a prototypes file listing more than 200 of either
walked off the end of the arrays and the compiler died with

*** stack smashing detected *** : terminated

A prototypes file is input data. No input should be able to smash the
compiler's stack, whatever is wrong with it. Both loops now stop at the limit
and say so:

Prototype for <name> has more than 199 return values - ignoring the rest

2026-09-05 12:31:40 Tree
[r13082] by mikeaubury

Coerce SMALLINT properly, and let make_cast be forced

ensure_smint tested for DTYPE_SMINT and then cast to DTYPE_INT. It was the only
one of the twelve ensure_* functions that casts to a different type from the one
it just tested for, so a value coerced for a SMALLINT parameter arrived as an
INTEGER. C did not care - the two interconvert silently - but a back end with a
distinct 16-bit type cannot pass the result to the parameter it was coerced for.

Also: 4GL says SMALLINT minus a literal is still SMALLINT, so no conversion was
requested. That holds for the 4GL type but not for the expression a back end
writes to evaluate it - C and C# both promote short arithmetic to int, and the
result has to be narrowed again before it can be passed to a SMALLINT
parameter. ensure_smint now asks for the cast on arithmetic, looking through
brackets so "(a - 1)" is treated like "a - 1".

make_cast took a "force" flag and never consulted it, so a cast that is a no-op
by 4GL type rules could not be requested even where a back end needs it written
out. It is now honoured, and ensure_smint uses it for the case above.

No change to the C back end's output on the example suite.

2026-09-05 12:31:28 Tree
[r13081] by mikeaubury

Fix INTERVAL YEAR TO MONTH arithmetic

Two bugs in the same function, both of which threw away the month part of a
year-month interval:

v1 = data_a[0] + data_a[1] / 12;

data_a is an int array, so dividing by an int truncated - every YEAR TO MONTH
value was treated as a whole number of years before the arithmetic ran. Fixed
by dividing by 12.0.

double yd, md;
int y = 0;
...
yd = floor (r1);
md = (r1 - y) * 12.0;

y is declared, initialised to zero and never assigned; the months are what is
left after the whole years, so it should have been yd. As written the month
field became the whole value times twelve.

Together these make subtraction correct where the result is positive and
smaller than the left operand. Addition, and a negative result, are still wrong
- the fault there is in how the result qualifier is encoded, which these two do
not reach. The interval fidelity probe records all three cases.

2026-09-05 12:30:53 Tree
[r13080] by mikeaubury

Fix variable substitution inside SQL subqueries

A 4GL variable used inside a subquery was never replaced by a placeholder and
never bound, so both the C and the C# back ends stopped with

Assertion failed: These should all have been removed by now... (sqlexpr.c)

and the statement could not be compiled at all.

make_list_item_list_from_select collects a statement's expressions so the back
ends can substitute variables for placeholders. Its E_SLI_IN_SELECT case walked
only complex_expr.left - the column being tested - and never the right, which is
the subquery. The E_SLI_SUBQUERY case below it does the right thing, but nothing
ever reached it, so nothing inside the subquery was collected.

The text writer already read both sides, so the collector was simply out of step
with it.

SELECT COUNT(*) INTO n FROM t WHERE k IN (SELECT a.k FROM u a WHERE a.c = v)

A constant in place of v compiled; a variable did not.

2026-09-05 12:30:37 Tree
[r13079] by mikeaubury

dotnet: qualify the builtins, so a program may reuse their names

Every builtin that can be static now lives on the static Fgl class and
is emitted as Fgl.X. Only the few that need the running session -
errorlog, err_get, lastkeypress and the SQLCA/flag members - stay
unqualified on FglModule.

The point is namespace: a builtin on the module base class reserves that
name across every 4GL program, so a program with its own function called
Current, or readln, or getuser, silently hides one. Adding Current in
r13077 collided with a member of that name in our own test example,
which was the warning. Since the generator decides how these are
written, the fix is to write them qualified rather than to hope the
names never clash - and Fgl.Pad, Fgl.Clipped and Fgl.Length were
already emitted that way, so this makes the surface consistent rather
than introducing a new convention.

Most of it went into map_fname's table, which is where a 4GL name is
turned into a .NET one; three sites emit their names directly and were
changed there. CURRENT is now one method taking an optional qualifier,
rather than a property and a separate CurrentQual.

The reservation that remains is deliberate and small. It is worth
knowing it exists: those few names are still spent.

On the large application this is 99 errors down to 94 - the qualifying
is not about the count, it is about what the generated code is allowed
to be. 203 runtime tests pass and the six end-to-end programs still
agree with the C runtime.

2026-09-04 20:16:33 Tree
Older >