Menu

SVN-Code Commit Log


Commit Date  
[r13055] by mikeaubury

Generator: unblock report modules and fix generated label names

Measured against fgldemo - 41 modules, 5900 lines - rather than guessed
at. Two fixes, both found by trying to compile it:

binding.o was never in the plug-in's link line, and binding.c is in any
case wrapped entirely in #ifdef CRAP, so A4GL_dtype_sz was never
compiled even though compile_cs_sql.c calls it. Every REPORT module
failed at dlopen with an undefined symbol. The guard now closes before
the dtparts table, leaving decode_datetime and A4GL_dtype_sz live - the
only two the caller needs - and the two SPRINTF macros in them, whose
header is also inside the disabled part, are plain snprintf now.

Generated labels used %d on a value that can be negative, producing
continue_input_-908174256, which is not a C# identifier. Now %u.

fgldemo now generates 39 of 41 modules, up from 36. The two that do not
are LOAD/UNLOAD, which are assertion stubs in the generator, and
DROP DATABASE, which Aubit refuses everywhere and is not a C# issue.

2026-09-02 11:58:39 Tree
[r13054] by mikeaubury

.NET: 4GL's implicit conversions, display widths, and a README

4GL allows LET lv_char = lv_int and converts on the way; C# does not. The
generator already resolves this at compile time, emitting an explicit
conversion only where the declared types differ - LET b = a between two
INTEGERs still emits a plain assignment. This adds the conversions it
emits: AsChar, AsString, AsInt, AsSmallInt, AsBigInt, AsDecimal, AsFloat,
AsSmallFloat, AsBool, AsDate, AsDateTime, AsMonthSpan and AsTimeSpan.

They are hand-written rather than System.Convert, which is wrong in the
three places that matter and has a test spelling it out: Convert rounds
7.9 to 8 where 4GL truncates to 7, turns NULL into 0 where 4GL keeps
NULL, and throws on "abc" where 4GL yields NULL.

DISPLAY now passes each value's width, not just a DECIMAL's precision.
4GL prints an INTEGER in 11 columns, a SMALLINT in 6, a FLOAT in 14 - and
a NULL still occupies its field, which a boxed null cannot know on its
own. CHAR is deliberately excluded: it is already padded at assignment,
and widening it again would defeat CLIPPED.

A fifth end-to-end program, convert.4gl, covers thirteen cross-type
assignments including truncation of negatives and NULL propagation. All
four end-to-end programs and the other four probes pass.

Adds dotnet/README.md.

2026-09-02 11:36:42 Tree
[r13053] by mikeaubury

Generator: carry DECIMAL precision and scale; control flow probe

Same problem as CHAR, same shape of fix. A DECIMAL(10,2) maps to C#'s
decimal, which carries neither the declared precision nor the scale, so
2.5 printed where 4GL prints 2.50, and it printed bare where 4GL right
aligns it in 12 columns.

Both are supplied where the declaration is still known. The assignment
wrapper - already used for CHAR - now also emits

L_d = Fgl.Scale(expr, 10, 2);

which rounds to the declared scale and forces the trailing zeros, since
Math.Round reduces a scale but never extends one. The width is the
declared PRECISION plus two and is passed at the DISPLAY site, where
expr_datatype still knows it:

Display("div =", Fgl.Disp(L_d, 10));

Adds IsNull, AsDecimal and CompareString to the runtime, which generated
code calls unqualified.

A third end-to-end probe covers FOR, WHILE, IF, CASE, arithmetic, string
concatenation, a function with a return value, a compound condition and
IS NULL. All three end-to-end probes pass, as do the other four and the
188 unit tests.

2026-09-02 07:59:22 Tree
[r13052] by mikeaubury

Generator: carry CHAR widths through to the generated code

A 4GL CHAR is fixed width and blank padded, but it maps to a C# string,
which has no width - so LET c = "hello" on a CHAR(10) was losing the
padding and DISPLAY printed five columns instead of ten.

The width is known at the assignment even though it is not recoverable
from the C# type, so every assignment to a CHAR is now wrapped:

L_s = Fgl.Pad("hello", 10);

This uses the generator's existing write-prefix / suffix mechanism in
decode_varbind, so it costs one helper and two small branches rather
than switching the emitted type to FglChar - which would have touched
the declaration, LET and parameter paths.

VARCHAR is deliberately excluded: it has no fixed width to pad to.

Also adds Fgl.CompareString, which generated code calls wherever either
side of a comparison is a string. Trailing blanks are not significant,
and a comparison involving NULL is false - including NULL against NULL.

A second end-to-end probe covers nine assignment forms: CHAR padding and
truncation, CHAR from CHAR, VARCHAR, an array element, a record field,
NULL, and an INTEGER's display width. Both probes pass.

2026-09-02 07:53:54 Tree
[r13051] by mikeaubury

Add the C# generator plug-in source (lex_cs)

lex_cs was copied into the tree but never added to SVN, so it - and the
retargeting in r13050 - existed only in a working copy. This adds the 16
source files the plug-in builds from, 432K in total.

Deliberately NOT added: the directory also holds about 35M of backup
copies (latest/, 250210/, CM/, old1/, backup_221009/), seven copies of
the same 1.7M tarball, and .exe/.dll/.mdb binaries including an Informix
DLL. Those are ignored rather than versioned; they are still on disk if
any of them turn out to matter.

The plug-in is still not built by the top-level make - it has to be
built by hand in lib/liblex/lex_cs. Wiring it in is a separate decision,
since it would make every build depend on it.

2026-09-02 07:45:49 Tree
[r13050] by mikeaubury

Retarget the C# generator onto the .NET runtime

The CSNEW generator already built and worked - it was simply never wired
into the top-level build. Retargeting it turned out to be a handful of
edits rather than a rewrite:

namespace and using -> Aubit4GL / Aubit4GL.Generated
base class -> FglModule, which carries the session
DATE -> DateOnly, an exact match
DECIMAL and MONEY -> decimal (this is where unknown_8 dies)
DATETIME, INTERVAL -> FglDateTime, FglInterval
BYTE and TEXT -> byte[]
SMALLINT -> short, not int
CLIPPED, LENGTH,
UPSHIFT and friends -> Fgl.*

DISPLAY now emits its expressions as separate arguments rather than
concatenating them, because 4GL renders each value at its type's own
width - an INTEGER in 11 columns, a SMALLINT in 6 - and joining them
into one string first threw that away. SMALLINT mapping to int? had the
same effect and is fixed.

A new end-to-end probe compiles ONE 4GL program through BOTH toolchains
and diffs what they print. It is the only check that exercises the
generator and the runtime together; every other probe tests a
hand-written .NET side. It passes.

Known gap, recorded at the head of the probe: CHAR(n) maps to a bare
string, so its declared width is lost and an unclipped CHAR prints
without its padding. Fixing that means carrying the width into the
declaration and routing assignment through Assign(), which touches the
declaration, LET and parameter paths.

2026-09-02 07:44:09 Tree
[r13049] by mikeaubury

.NET: REPORT engine

Page and line tracking, the four margins, COLUMN positioning, SKIP, NEED,
page breaks, and the aggregates. A probe compares a report's output
against the C runtime line for line - nothing normalised, since a report
is entirely about column and page layout - and all 66 lines match.

The state follows BaseFGLReport from the original C# library, which had
the data model right even though the behaviour was never written. The
layout defaults were read out of the generated C rather than guessed:
page length 66, margins top 3, bottom 3, left 5, right 132.

COUNT(*) and SUM/AVG keep separate counters: COUNT counts rows while the
others only see non-null values, so a row with a NULL still counts but
does not drag the average down.

2026-09-02 07:33:32 Tree
[r13048] by mikeaubury

.NET: USING format engine

Thirty formats now render identically to the C runtime, checked by a new
probe. Padding is significant here, so values are bracketed and compared
exactly rather than trimmed.

Four rules the probe corrected me on, all of which look wrong coming
from another language:

0 is a LITERAL, not a digit placeholder - the zero-fill character is &.
"###,##0.00" is valid in Oracle and means something else entirely in
4GL, and the C is right to render 1234.5 as 12,340.00 for it.

A zero integer part is blank under #: 0 with "###" is three spaces.

Fill is per position, not per field - one & in "##&" does not zero-fill
the other two.

Sign and currency characters occupy digit positions, so "-----" is five
of them; treating them as decoration overflows the field to asterisks.
Parentheses are the exception and never hold a digit. A single sign sits
where the mask puts it, a run of them floats to the first digit.

2026-09-02 07:29:25 Tree
[r13047] by mikeaubury

.NET: 4GL builtin functions

LENGTH, CLIPPED, UPSHIFT, DOWNSHIFT, ORD, ASCII, the substring operator,
MDY, DAY, MONTH, YEAR, WEEKDAY and DBDATE-aware date formatting - all
checked against the C runtime through the probe, which now compares 27
values rather than 13.

Two details worth having pinned down: the substring operator is 1-based
and inclusive at both ends, so s[1,5] is five characters and not four;
and WEEKDAY counts Sunday as 0, which the C confirms by giving 4 for
29 February 2024. The probe also agrees on day number 45350 for that
date, which independently checks the epoch.

Substrings step in characters, so a subscript cannot cut a surrogate
pair in half.

The divergence note in the probe was stale and has been corrected: the C
no longer leaves a partial character behind when a CHAR is truncated,
but the width is still counted in bytes there and in characters here.

2026-09-02 07:06:32 Tree
[r13046] by mikeaubury

.NET: protocol probe covers MENU; two mismatches it found

The probe now compares canonical JSON rather than text. The C wraps its
output in an envelope and spreads nested objects over many lines, so a
textual diff was only testing formatting; both streams are now parsed
and re-emitted sorted, with the C's array terminators dropped.

Two real differences surfaced once MENU was covered:

Dialog contexts were numbered from 1 here and from 0 in the C. Clients
key on the value, so they now start at 0.

EXIT MENU compiles to a menu action entry the C sends alongside the
commands - {"ACTION":"fgl_exit_menu","CMD_NO_TIMEOUT":n} - which was
never emitted. AddAction() sends it, so a menu built here is the same
menu on the wire.

Eight messages now identical, including the whole nested MENU.

2026-09-02 07:02:03 Tree
Older >