Comments (7)
I simplified the module even further, removing the TYPE
declaration, some local variables, and the VAR
parameters of the three Run
procedures.
MODULE Issue37;
IMPORT Out;
PROCEDURE Length(str: ARRAY OF CHAR) : INTEGER;
VAR i: INTEGER;
BEGIN
i := 0;
WHILE (i < LEN(str)) & (str[i] # 00X) DO INC(i) END;
RETURN i
END Length;
PROCEDURE FillString(VAR s : ARRAY OF CHAR);
VAR
i : INTEGER;
BEGIN
i := 0;
WHILE i < LEN(s) DO
s[i] := CHR(SHORT(i MOD 20) + 65);
INC(i)
END
END FillString;
PROCEDURE Run1();
VAR
str : ARRAY 257 OF CHAR;
BEGIN
str := "test";
Out.String("1.1 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
FillString(str);
Out.String("1.2 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
END Run1;
PROCEDURE Run2();
VAR
str : ARRAY 257 OF CHAR;
PROCEDURE Assert(b: BOOLEAN);
BEGIN
ASSERT(b)
END Assert;
BEGIN
str := "test";
Out.String("2.1 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
FillString(str);
Out.String("2.2 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
END Run2;
PROCEDURE Run3();
VAR
str : ARRAY 257 OF CHAR;
BEGIN
str := "test";
Out.String("3.1 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
FillString(str);
Out.String("3.2 : Length(str) = "); Out.Int(Length(str), 0); Out.Ln;
END Run3;
BEGIN
Run1();
Run2();
Run2()
END Issue37.
The erroneous behavior is still present, but actually not linked to VAR
parameters. Instead the culprit seems to be (again) the unnesting of procedure Assert
. From the debug output of the unnested module, I cannot immediately see what's going wrong. I will have to look into this in more detail on the weekend. This week the teaching resumed at my university and, therefore, I have even less time for the side project that is oberon-lang
. Nevertheless, I am grateful for bugs being hunted down!
from oberon-lang.
Excellent. The work around is simple, so not a pressing issue.
I have a large (500+ tests) testsuite from my Oberon-2 library I try to port over and discover this by
running against known good output. I will report any issues I find.
from oberon-lang.
Closed by #39
from oberon-lang.
The following code gives different result depending on if the functions is nested or not:
MODULE Test;
IMPORT Out;
PROCEDURE IsLower (ch: CHAR) : BOOLEAN;
BEGIN RETURN (ch >= "a") & (ch <= "z")
END IsLower;
PROCEDURE Upper(ch: CHAR) : CHAR;
BEGIN
IF IsLower(ch) THEN RETURN CHR(ORD(ch) + (ORD("A") - ORD("a"))) END;
RETURN ch
END Upper;
PROCEDURE Length(str: ARRAY OF CHAR) : INTEGER;
VAR i: INTEGER;
BEGIN
i := 0;
WHILE (i < LEN(str)) & (str[i] # 00X) DO INC(i) END;
RETURN i
END Length;
PROCEDURE IMatch1(str, pattern : ARRAY OF CHAR; IgnoreCase : BOOLEAN; is, ip: LONGINT): BOOLEAN;
VAR
lens, lenp : LONGINT;
BEGIN
lens := Length(str);
lenp := Length(pattern);
WHILE ip < lenp DO
IF pattern[ip] = "*" THEN
WHILE is <= lens DO (* check to end of string *)
IF IMatch1(str, pattern, IgnoreCase, is, ip + 1) THEN RETURN TRUE END;
INC(is)
END;
RETURN FALSE
ELSIF is = lens THEN (* pattern not exhausted *)
RETURN FALSE
ELSIF pattern[ip] = "?" THEN
ELSIF ~IgnoreCase & (str[is] # pattern[ip]) THEN
RETURN FALSE
ELSIF IgnoreCase & (Upper(str[is]) # Upper(pattern[ip])) THEN
RETURN FALSE
END;
INC(is); INC(ip)
END;
RETURN is = lens
END IMatch1;
PROCEDURE Match1 (str, pattern : ARRAY OF CHAR; IgnoreCase : BOOLEAN): BOOLEAN;
BEGIN
IF Length(pattern) = 0 THEN RETURN Length(str) = 0 END;
RETURN IMatch1(str, pattern, IgnoreCase, 0, 0)
END Match1;
PROCEDURE Match2 (str, pattern : ARRAY OF CHAR; IgnoreCase : BOOLEAN): BOOLEAN;
PROCEDURE IMatch(str, pattern : ARRAY OF CHAR; IgnoreCase : BOOLEAN; is, ip: LONGINT): BOOLEAN;
VAR
lens, lenp : LONGINT;
BEGIN
lens := Length(str);
lenp := Length(pattern);
WHILE ip < lenp DO
IF pattern[ip] = "*" THEN
WHILE is <= lens DO (* check to end of string *)
IF IMatch(str, pattern, IgnoreCase, is, ip + 1) THEN RETURN TRUE END;
INC(is)
END;
RETURN FALSE
ELSIF is = lens THEN (* pattern not exhausted *)
RETURN FALSE
ELSIF pattern[ip] = "?" THEN
ELSIF ~IgnoreCase & (str[is] # pattern[ip]) THEN
RETURN FALSE
ELSIF IgnoreCase & (Upper(str[is]) # Upper(pattern[ip])) THEN
RETURN FALSE
END;
INC(is); INC(ip)
END;
RETURN is = lens
END IMatch;
BEGIN
IF Length(pattern) = 0 THEN RETURN Length(str) = 0 END;
RETURN IMatch(str, pattern, IgnoreCase, 0, 0)
END Match2;
BEGIN
Out.String("Match1('Filename.exe', 'f?l*.exe', FALSE) = "); Out.Int(ORD(Match1("Filename.exe", "f?l*.exe", FALSE)), 0); Out.Ln;
Out.String("Match2('Filename.exe', 'f?l*.exe', FALSE) = "); Out.Int(ORD(Match2("Filename.exe", "f?l*.exe", FALSE)), 0); Out.Ln
END Test.
This outputs:
Match1('Filename.exe', 'f?l*.exe', FALSE) = 0
Match2('Filename.exe', 'f?l*.exe', FALSE) = 1
from oberon-lang.
Those nested procedures should be outlawed! 😎 But fine, I'll reopen the issue and have a look in what corner of LambdaLifter
the bugs are hiding!
from oberon-lang.
I take it back! LambdaLifter
is not to blame! The problem is in the code generator that does not support what LambdaLifter
is asking it to do.
tl;dr
When unnesting procedures, LambdaLifter
creates a record with all parameters and local variables of the super-procedure in order to pass its environment as an extra parameter to the sub-procedure. For the procedure Match2
, the following environment type is created by LambdaLifter
.
TYPE _TMatch2(*Scope:1*) = RECORD str: ARRAY OF CHAR; pattern: ARRAY OF CHAR; IgnoreCase: BOOLEAN END(*Size:1*);
While this type is correct, it relies on functionality that I have not yet introduced in the backend. Since open array types cannot be used for variables and record fields, a programmer could not explicitly create this type. Already the parser would not accept it. Obviously (and thanks for finding that loophole), I overlooked that open arrays will be used in this way internally by LambdaLifter
.
To fix the problem, I will add support for variables and record fields with an open array type by allocating them as pointers and checking that they are stored and loaded correctly in the LLVM-IR. However, I think it makes sense to defer upgrading the Parser and Sema to support this functionality as I consider it to be extended functionality that goes beyond the standard Oberon. At the moment my priorities are fixing bugs and closing the remaining gaps to support all of standard Oberon (e.g., record extensions, function pointers, CASE
statement, etc.).
from oberon-lang.
I agree.
Here we have a known reproducible "weird" case which can be deferred until later when more important issues are solved.
The workaround is very simple in this case.
I found this when porting code from my XDS library and have now about 170 tests passed.
I will port over more code with unittests and report back any findings.
from oberon-lang.
Related Issues (20)
- endian.h not found on Windows platform HOT 2
- Enforce position of module level VAR section? HOT 5
- Output file argument not working HOT 2
- Avoid writing .smb file for JITed main module HOT 2
- Array passed as argument is shorten HOT 2
- Export of CHAR constants not supported HOT 1
- Making Unit Tests Work! HOT 13
- Add MSYS2 page to Wiki HOT 1
- Add Embedded example to wiki HOT 1
- Cross platform support HOT 2
- Compilation error due to extra semicolon
- CHAR variable not treated equal to CHAR literal HOT 5
- Bug in name mangling of (un)nested procedures HOT 2
- Crash with assignment of string literal reference returned from procedure HOT 4
- DIV and MOD not in line with Oberon-07 report HOT 3
- Build report ArchLinux HOT 4
- Crash triggered by accessing exported variable HOT 4
- Proposal to make runtime functionality configurable.
- Access to argc & argv
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from oberon-lang.