diff --git a/compiler/src/main/pascal/blaise.codegen.native.backend.pas b/compiler/src/main/pascal/blaise.codegen.native.backend.pas index b34c5a5..e579c2f 100644 --- a/compiler/src/main/pascal/blaise.codegen.native.backend.pas +++ b/compiler/src/main/pascal/blaise.codegen.native.backend.pas @@ -160,7 +160,7 @@ end; procedure TNativeBackend.EmitBlank; begin - FAsm.AppendLine; + FAsm.AppendLine(); end; { The record-return ABI classifier and its leaf predicates now live as shared diff --git a/compiler/src/main/pascal/runtime.arc.pas b/compiler/src/main/pascal/runtime.arc.pas index ec07ae9..5f418fa 100644 --- a/compiler/src/main/pascal/runtime.arc.pas +++ b/compiler/src/main/pascal/runtime.arc.pas @@ -119,7 +119,7 @@ begin _libc_write(STDERR_FD, Msg, Int64(Len)); NL := 10; _libc_write(STDERR_FD, @NL, 1); - _libc_abort; + _libc_abort(); end; procedure _AbstractMethodError; diff --git a/compiler/src/main/pascal/runtime.exc.pas b/compiler/src/main/pascal/runtime.exc.pas index 6eff692..d5dfa2e 100644 --- a/compiler/src/main/pascal/runtime.exc.pas +++ b/compiler/src/main/pascal/runtime.exc.pas @@ -112,7 +112,7 @@ var ExcSlot: PPointer; begin if g_exc_top = nil then - _libc_abort; + _libc_abort(); g_current_exception := Obj; ExcSlot := g_exc_top + OFS_EXCEPTION; ExcSlot^ := Obj; @@ -245,7 +245,7 @@ begin _libc_write(2, Msg, Int64(Len)); NL := 10; _libc_write(2, @NL, 1); - _libc_abort; + _libc_abort(); end; procedure _Raise_InvalidCast; diff --git a/compiler/src/main/pascal/uParser.pas b/compiler/src/main/pascal/uParser.pas index e291a7d..dd9ea8f 100644 --- a/compiler/src/main/pascal/uParser.pas +++ b/compiler/src/main/pascal/uParser.pas @@ -3421,6 +3421,20 @@ begin if not Check(tkRParen) then ParseMethodCallArgList(MCall); Expect(tkRParen); + end + else if not Check(tkDot) then + begin + { Bare 'Obj.Method' with no '(' and no further '.' chain — a + parameterless method call written without its mandatory parentheses. + (A following '.' is a post-call/field chain handled just below; a + terminating bare reference is the error case.) Every call carries () + even with no arguments — see language-rationale.adoc, "Mandatory + parentheses on zero-argument calls". } + MCall.Free(); + MCall := nil; + raise EParseError.Create(Format( + 'Bare reference to ''%s.%s'' requires () for a call at line %d col %d in %s', + [Name, SecondIdent, Line, Col, FLexer.Filename])); end; { Post-method chain: Name.Method(args).Field := value or .Method2(args) } if Check(tkDot) then @@ -3595,11 +3609,13 @@ begin FCallNode.Free(); Exit(Call); end; - Call := TProcCall.Create(); - Call.Line := Line; - Call.Col := Col; - Call.Name := Name; - Result := Call; + { Bare identifier in statement position with no '(' — a parameterless + procedure/function call written without its mandatory parentheses. + Every call carries () even with no arguments (see language-rationale.adoc, + "Mandatory parentheses on zero-argument calls"). } + raise EParseError.Create(Format( + 'Bare reference to ''%s'' requires () for a call at line %d col %d in %s', + [Name, Line, Col, FLexer.Filename])); end; end; diff --git a/compiler/src/main/pascal/uSemantic.pas b/compiler/src/main/pascal/uSemantic.pas index 991f94a..b788536 100644 --- a/compiler/src/main/pascal/uSemantic.pas +++ b/compiler/src/main/pascal/uSemantic.pas @@ -1168,7 +1168,7 @@ var I: Integer; begin FProg := AProg; - FlushPendingGenericInstances; + FlushPendingGenericInstances(); FCurrentUnitName := AProg.Name; BuildUsesChain(AProg.UsedUnits); FTable.UsesChainProvider := Self; @@ -1202,7 +1202,7 @@ var begin FCurrentUnitName := AUnit.Name; FCurrentUnit := AUnit; - FlushPendingGenericInstances; + FlushPendingGenericInstances(); FTable.PushScope(); try { The unit's own name and the names of directly used units are @@ -1223,7 +1223,7 @@ begin *before* any FindTypeOrInstantiate call can clone an instance, or the instance is born with nil bodies and codegen emits no function for it. } LinkGenericClassMethodImpls(AUnit.ImplBlock); - RepairEarlyGenericInstances; + RepairEarlyGenericInstances(); { Register interface-section global variables — visible to impl bodies. } for I := 0 to AUnit.IntfBlock.Decls.Count - 1 do @@ -1534,7 +1534,7 @@ var begin FCurrentUnitName := AUnit.Name; FCurrentUnit := AUnit; - FlushPendingGenericInstances; + FlushPendingGenericInstances(); BuildUsesChain(AUnit.UsedUnits); FTable.UsesChainProvider := Self; { Auto-tag every global Define within this unit's analysis with the @@ -1557,7 +1557,7 @@ begin the cloned instance method is born without a body and codegen emits no function — leaving call sites referencing an undefined symbol. } LinkGenericClassMethodImpls(AUnit.ImplBlock); - RepairEarlyGenericInstances; + RepairEarlyGenericInstances(); { Register interface-section global variables. Marked IsGlobal so codegen emits them as data-segment slots rather than stack allocs; @@ -3971,7 +3971,7 @@ begin declarations, transferring the body so AnalyseMethodBodies can process it. } LinkClassMethodImpls(ABlock); LinkGenericClassMethodImpls(ABlock); - RepairEarlyGenericInstances; + RepairEarlyGenericInstances(); { Register standalone proc/func signatures before class method bodies so that methods can call free functions declared in the same block. } AnalyseStandaloneDecls(ABlock); diff --git a/compiler/src/test/pascal/cp.test.arc.pas b/compiler/src/test/pascal/cp.test.arc.pas index 0d4e175..7d862eb 100644 --- a/compiler/src/test/pascal/cp.test.arc.pas +++ b/compiler/src/test/pascal/cp.test.arc.pas @@ -687,7 +687,7 @@ begin f := TFoo.Create() end; begin - DoIt + DoIt() end. '''); FnPos := Pos('function $DoIt', IR); @@ -725,7 +725,7 @@ begin f := TFoo.Create() end; begin - DoIt + DoIt() end. '''); FnPos := Pos('function $DoIt', IR); @@ -759,7 +759,7 @@ begin f := TFoo.Create() end; begin - DoIt + DoIt() end. '''); FnPos := Pos('function $DoIt', IR); @@ -800,7 +800,7 @@ begin F := TFoo(P) end; begin - DoIt + DoIt() end. '''); FnPos := Pos('function $DoIt', IR); @@ -832,7 +832,7 @@ const r := Make() end; begin - Run + Run() end. '''; @@ -848,7 +848,7 @@ const b := a end; begin - Run + Run() end. '''; @@ -868,7 +868,7 @@ const r := Make() end; begin - Run + Run() end. '''; @@ -883,7 +883,7 @@ const b := a end; begin - Run + Run() end. '''; diff --git a/compiler/src/test/pascal/cp.test.assembler.pas b/compiler/src/test/pascal/cp.test.assembler.pas index e6b21fd..7fa616f 100644 --- a/compiler/src/test/pascal/cp.test.assembler.pas +++ b/compiler/src/test/pascal/cp.test.assembler.pas @@ -964,7 +964,7 @@ begin 'begin' + LineEnding + ' for I := 1 to 5 do' + LineEnding + ' Write(I);' + LineEnding + - ' WriteLn' + LineEnding + + ' WriteLn()' + LineEnding + 'end.', Out_, EC) then begin @@ -1037,7 +1037,7 @@ begin ' Write(N);' + LineEnding + ' N := N + 1' + LineEnding + ' end;' + LineEnding + - ' WriteLn' + LineEnding + + ' WriteLn()' + LineEnding + 'end.', Out_, EC) then begin @@ -1163,7 +1163,7 @@ begin 'begin' + LineEnding + ' G := TGreeter.Create;' + LineEnding + ' WriteLn(G.Greet());' + LineEnding + - ' G.Free' + LineEnding + + ' G.Free()' + LineEnding + 'end.', Out_, EC) then begin diff --git a/compiler/src/test/pascal/cp.test.bif_coverage.pas b/compiler/src/test/pascal/cp.test.bif_coverage.pas index 5cbc5d0..6d8333e 100644 --- a/compiler/src/test/pascal/cp.test.bif_coverage.pas +++ b/compiler/src/test/pascal/cp.test.bif_coverage.pas @@ -102,7 +102,7 @@ begin Proc.WaitOnExit(); Code := Proc.ExitCode finally - Proc.Free + Proc.Free() end; if Code <> 0 then diff --git a/compiler/src/test/pascal/cp.test.constants.pas b/compiler/src/test/pascal/cp.test.constants.pas index 04d9c91..6f152b2 100644 --- a/compiler/src/test/pascal/cp.test.constants.pas +++ b/compiler/src/test/pascal/cp.test.constants.pas @@ -480,7 +480,7 @@ begin x := Threshold end; begin - DoWork + DoWork() end. ''' ); diff --git a/compiler/src/test/pascal/cp.test.e2e.arc.pas b/compiler/src/test/pascal/cp.test.e2e.arc.pas index 9c3d7a3..f474ff3 100644 --- a/compiler/src/test/pascal/cp.test.e2e.arc.pas +++ b/compiler/src/test/pascal/cp.test.e2e.arc.pas @@ -517,7 +517,7 @@ const Freed := 0; L := TObjectList.Create(True); L.Add(TThing.Create()); - Borrow; + Borrow(); WriteLn(Freed); L.Free(); WriteLn(Freed) diff --git a/compiler/src/test/pascal/cp.test.e2e.collections2.pas b/compiler/src/test/pascal/cp.test.e2e.collections2.pas index 077162c..0938b3f 100644 --- a/compiler/src/test/pascal/cp.test.e2e.collections2.pas +++ b/compiler/src/test/pascal/cp.test.e2e.collections2.pas @@ -389,8 +389,8 @@ const OL := TObjectList.Create(False); OL.Add(SL); WriteLn(TStringList(OL[0])[1]); // chained: cast(OL default) then default - SL.Free; - OL.Free + SL.Free(); + OL.Free() end. '''; var Output: string; RCode: Integer; diff --git a/compiler/src/test/pascal/cp.test.e2e.controlflow.pas b/compiler/src/test/pascal/cp.test.e2e.controlflow.pas index ec057d0..a265f72 100644 --- a/compiler/src/test/pascal/cp.test.e2e.controlflow.pas +++ b/compiler/src/test/pascal/cp.test.e2e.controlflow.pas @@ -192,11 +192,11 @@ const end; begin Counter := 0; - Inner; + Inner(); WriteLn(Counter); end; begin - Outer; + Outer(); end. '''; @@ -311,7 +311,7 @@ const end; Write(r); Write(' '); end; - WriteLn + WriteLn() end. '''; @@ -326,7 +326,7 @@ const 5, 7..9: Write('b'); else Write('.'); end; - WriteLn + WriteLn() end. '''; diff --git a/compiler/src/test/pascal/cp.test.e2e.dynarray.pas b/compiler/src/test/pascal/cp.test.e2e.dynarray.pas index 533654c..0c150d2 100644 --- a/compiler/src/test/pascal/cp.test.e2e.dynarray.pas +++ b/compiler/src/test/pascal/cp.test.e2e.dynarray.pas @@ -85,7 +85,7 @@ const program Prg; var a: array of string; i: Integer; begin SetLength(a, 3); a[0] := 'x'; a[1] := 'y'; a[2] := 'z'; - for i := 0 to 2 do Write(a[i]); WriteLn end. + for i := 0 to 2 do Write(a[i]); WriteLn() end. '''; SrcRefSem = ''' @@ -125,7 +125,7 @@ const SetLength(m, 2); SetLength(m[0], 2); SetLength(m[1], 2); m[0][0] := 1; m[0][1] := 2; m[1][0] := 3; m[1][1] := 4; for i := 0 to 1 do for j := 0 to 1 do Write(m[i][j]); - WriteLn + WriteLn() end. '''; @@ -137,7 +137,7 @@ const m[0][0] := 'a'; m[0][1] := 'b'; m[1][0] := 'c'; m[1][1] := 'd'; m[0][1] := 'B'; for i := 0 to 1 do for j := 0 to 1 do Write(m[i][j]); - WriteLn + WriteLn() end. '''; @@ -154,7 +154,7 @@ const c[i][j][k] := i*4 + j*2 + k; for i := 0 to 1 do for j := 0 to 1 do for k := 0 to 1 do Write(c[i][j][k]); - WriteLn + WriteLn() end. '''; @@ -212,7 +212,7 @@ const SetLength(G, Length(H)); for I := 0 to High(G) do G[I] := 9; for I := 0 to High(G) do Write(G[I]); - WriteLn + WriteLn() end. '''; @@ -226,7 +226,7 @@ const SetLength(A, Length(B)); for I := 0 to High(A) do A[I] := 8; for I := 0 to High(A) do Write(A[I]); - WriteLn + WriteLn() end. '''; @@ -241,7 +241,7 @@ const SetLength(A, Pick()); for I := 0 to High(A) do A[I] := 6; for I := 0 to High(A) do Write(A[I]); - WriteLn + WriteLn() end. '''; diff --git a/compiler/src/test/pascal/cp.test.e2e.interfaces.pas b/compiler/src/test/pascal/cp.test.e2e.interfaces.pas index b090e28..1709aaa 100644 --- a/compiler/src/test/pascal/cp.test.e2e.interfaces.pas +++ b/compiler/src/test/pascal/cp.test.e2e.interfaces.pas @@ -372,9 +372,9 @@ const begin WriteLn(g.Greet(), ' / ', g.Who()) end; var per: TPerson; lou: TLoud; vl: TVeryLoud; begin - per := TPerson.Create; Use(per); per.Free; - lou := TLoud.Create; Use(lou); lou.Free; - vl := TVeryLoud.Create; Use(vl); vl.Free + per := TPerson.Create; Use(per); per.Free(); + lou := TLoud.Create; Use(lou); lou.Free(); + vl := TVeryLoud.Create; Use(vl); vl.Free() end. '''; begin @@ -406,7 +406,7 @@ const i := d; // assignment to interface i.Hello(); Use(d); // parameter passing - d.Free + d.Free() end. '''; begin diff --git a/compiler/src/test/pascal/cp.test.e2e.jumboset.pas b/compiler/src/test/pascal/cp.test.e2e.jumboset.pas index 4864054..685070e 100644 --- a/compiler/src/test/pascal/cp.test.e2e.jumboset.pas +++ b/compiler/src/test/pascal/cp.test.e2e.jumboset.pas @@ -123,7 +123,7 @@ begin ' for e in s do n := n + 1;' + LE + ' WriteLn(n);' + LE + { 4 } ' for e in s do Write(Ord(e), '' '');' + LE + - ' WriteLn' + LE + + ' WriteLn()' + LE + 'end.'; AssertRunsOnAll(Src, '4' + LE + '5 40 70 79 ' + LE, 0); end; diff --git a/compiler/src/test/pascal/cp.test.e2e.leakcheck.pas b/compiler/src/test/pascal/cp.test.e2e.leakcheck.pas index be8582d..84a92eb 100644 --- a/compiler/src/test/pascal/cp.test.e2e.leakcheck.pas +++ b/compiler/src/test/pascal/cp.test.e2e.leakcheck.pas @@ -126,7 +126,7 @@ const end end; begin - DoIt; + DoIt(); WriteLn('done') end. '''; diff --git a/compiler/src/test/pascal/cp.test.e2e.misc.pas b/compiler/src/test/pascal/cp.test.e2e.misc.pas index 7de8907..7098a11 100644 --- a/compiler/src/test/pascal/cp.test.e2e.misc.pas +++ b/compiler/src/test/pascal/cp.test.e2e.misc.pas @@ -347,7 +347,7 @@ const Obj := TFoo.Create(); Obj.FVal := 55; M := @Obj.Print; - M; + M(); Obj.Free() end. '''; @@ -991,11 +991,11 @@ const begin x := 5; WriteLn(IntToStr(x)); - Inner; + Inner(); WriteLn(IntToStr(x)) end; begin - Outer + Outer() end. '''; var Output: string; RCode: Integer; @@ -1022,7 +1022,7 @@ const R.B := Sum * 2 end; begin - Inner + Inner() end; var Rec: TRec; begin @@ -1050,11 +1050,11 @@ const end; begin R.A := 1; R.B := 2; - Inner; + Inner(); WriteLn(IntToStr(R.A), ' ', IntToStr(R.B)) end; begin - Outer + Outer() end. '''; begin @@ -1073,7 +1073,7 @@ const A[0] := 10; A[1] := 20; A[2] := A[0] + A[1] end; begin - Inner + Inner() end; var Ar: TArr; begin diff --git a/compiler/src/test/pascal/cp.test.e2e.native.pas b/compiler/src/test/pascal/cp.test.e2e.native.pas index 699aaff..c67728b 100644 --- a/compiler/src/test/pascal/cp.test.e2e.native.pas +++ b/compiler/src/test/pascal/cp.test.e2e.native.pas @@ -1226,7 +1226,7 @@ const WriteLn(D) end; begin - ShowDouble + ShowDouble() end. '''; @@ -1487,7 +1487,7 @@ const WriteLn(B.Data[4]); WriteLn(B.Data[I + 2]); WriteLn(B.At(1)); - B.Free; + B.Free(); end. '''; @@ -2843,13 +2843,13 @@ const end; procedure Tmi.use; begin - im.print; + im.print(); end; var im: Tmi; begin im := Tmi.Create(Toutput.Create()); - im.use; + im.use(); end. '''; @@ -4966,7 +4966,7 @@ begin begin B := TBox.Create(99); WriteLn(B.Val); - B.Free + B.Free() end. ''', '99' + LE, 0); @@ -4992,7 +4992,7 @@ begin A := TArr.Create; WriteLn(A.Items[0]); WriteLn(A.Items[1]); - A.Free + A.Free() end. ''', '10' + LE + '30' + LE, 0); @@ -5018,7 +5018,7 @@ begin B := TBox.Create; B.Val := 42; WriteLn(B.Val); - B.Free + B.Free() end. ''', '42' + LE, 0); @@ -5046,7 +5046,7 @@ begin A.Items[1] := 30; WriteLn(A.Items[0]); WriteLn(A.Items[1]); - A.Free + A.Free() end. ''', '10' + LE + '30' + LE, 0); @@ -5062,7 +5062,7 @@ begin begin F := TFoo.Create; WriteLn(F.ClassName); - F.Free + F.Free() end. ''', 'TFoo' + LE, 0); @@ -5084,7 +5084,7 @@ begin begin Obj := TCalc.Create; WriteLn(Obj.Sum6(1, 2, 3, 4, 5, 6)); - Obj.Free + Obj.Free() end. ''', '21' + LE, 0); @@ -5109,8 +5109,8 @@ begin O := TOuter.Create; O.FInner := I; WriteLn(O.GetVal()); - O.Free; - I.Free + O.Free(); + I.Free() end. ''', '42' + LE, 0); @@ -5137,8 +5137,8 @@ begin begin O := TMyObj.Create; O.FVal := 99; - O.Show; - O.Free + O.Show(); + O.Free() end. ''', '99' + LE, 0); @@ -5176,7 +5176,7 @@ begin begin B := TChild.Create; WriteLn(B.GetVal()); - B.Free + B.Free() end. ''', '42' + LE, 0); @@ -5322,7 +5322,7 @@ begin procedure TCalc.Run; begin FVal := 5; - Step; + Step(); WriteLn(FVal); WriteLn(Double()) end; @@ -5360,8 +5360,8 @@ begin var P: TParser; begin P := TParser.Create(); - P.Setup; - P.Advance; + P.Setup(); + P.Advance(); WriteLn(P.FA.Kind, ':', P.FA.Value, ':', P.FA.Line, ':', P.FA.Col); WriteLn(P.FB.Kind, ':', P.FB.Value, ':', P.FB.Line, ':', P.FB.Col); P.Free() diff --git a/compiler/src/test/pascal/cp.test.e2e.recordret.pas b/compiler/src/test/pascal/cp.test.e2e.recordret.pas index a1fb218..cec4b12 100644 --- a/compiler/src/test/pascal/cp.test.e2e.recordret.pas +++ b/compiler/src/test/pascal/cp.test.e2e.recordret.pas @@ -671,7 +671,7 @@ const K := TMaker.Create; R := K.Make(0.25); WriteLn(R.X); - K.Free + K.Free() end. '''; begin diff --git a/compiler/src/test/pascal/cp.test.e2e.records.pas b/compiler/src/test/pascal/cp.test.e2e.records.pas index 7b3213e..2946982 100644 --- a/compiler/src/test/pascal/cp.test.e2e.records.pas +++ b/compiler/src/test/pascal/cp.test.e2e.records.pas @@ -967,7 +967,7 @@ const var c: TC; begin c := TC.Create(); - c.Fill; + c.Fill(); writeln(c.A[0]); writeln(c.A[1]); writeln(c.A[2]); diff --git a/compiler/src/test/pascal/cp.test.e2e.staticarray.pas b/compiler/src/test/pascal/cp.test.e2e.staticarray.pas index 97fc049..2a6f206 100644 --- a/compiler/src/test/pascal/cp.test.e2e.staticarray.pas +++ b/compiler/src/test/pascal/cp.test.e2e.staticarray.pas @@ -198,7 +198,7 @@ const G[2] := L[2] end; begin - Fill; + Fill(); WriteLn(G[0]); WriteLn(G[2]) end. diff --git a/compiler/src/test/pascal/cp.test.exceptions.pas b/compiler/src/test/pascal/cp.test.exceptions.pas index 113cc16..aaf8ab4 100644 --- a/compiler/src/test/pascal/cp.test.exceptions.pas +++ b/compiler/src/test/pascal/cp.test.exceptions.pas @@ -254,7 +254,7 @@ const end end; begin - Run + Run() end. '''; diff --git a/compiler/src/test/pascal/cp.test.flowjumps.pas b/compiler/src/test/pascal/cp.test.flowjumps.pas index 7181f11..ed24b7b 100644 --- a/compiler/src/test/pascal/cp.test.flowjumps.pas +++ b/compiler/src/test/pascal/cp.test.flowjumps.pas @@ -171,7 +171,7 @@ const Exit(5) end; begin - DoIt + DoIt() end. '''; diff --git a/compiler/src/test/pascal/cp.test.generics.pas b/compiler/src/test/pascal/cp.test.generics.pas index b379e76..ac36fe3 100644 --- a/compiler/src/test/pascal/cp.test.generics.pas +++ b/compiler/src/test/pascal/cp.test.generics.pas @@ -793,7 +793,7 @@ const program Prg; uses UPair; begin - InitPair; + InitPair(); end. '''; diff --git a/compiler/src/test/pascal/cp.test.inherit.pas b/compiler/src/test/pascal/cp.test.inherit.pas index ba3fa74..d5c28be 100644 --- a/compiler/src/test/pascal/cp.test.inherit.pas +++ b/compiler/src/test/pascal/cp.test.inherit.pas @@ -477,7 +477,7 @@ begin var C: TChild; begin C := TChild.Create(); - C.NoSuchMethod + C.NoSuchMethod() end. '''); end; diff --git a/compiler/src/test/pascal/cp.test.interfaces.pas b/compiler/src/test/pascal/cp.test.interfaces.pas index d482992..62dadc7 100644 --- a/compiler/src/test/pascal/cp.test.interfaces.pas +++ b/compiler/src/test/pascal/cp.test.interfaces.pas @@ -525,7 +525,7 @@ const end; procedure Tmi.use; begin - im.print; + im.print(); end; var im: Tmi; diff --git a/compiler/src/test/pascal/cp.test.methods.pas b/compiler/src/test/pascal/cp.test.methods.pas index e2ba165..f35ce73 100644 --- a/compiler/src/test/pascal/cp.test.methods.pas +++ b/compiler/src/test/pascal/cp.test.methods.pas @@ -376,7 +376,7 @@ begin var F: TFoo; begin F := TFoo.Create(); - F.NoSuchMethod + F.NoSuchMethod() end. '''); end; diff --git a/compiler/src/test/pascal/cp.test.multifile.pas b/compiler/src/test/pascal/cp.test.multifile.pas index 05c37f4..4540bfc 100644 --- a/compiler/src/test/pascal/cp.test.multifile.pas +++ b/compiler/src/test/pascal/cp.test.multifile.pas @@ -452,7 +452,7 @@ const procedure ext_abort; external name 'abort'; procedure DoA; begin - ext_abort + ext_abort() end; end. '''; @@ -465,7 +465,7 @@ const procedure ext_abort; external name 'abort'; procedure DoB; begin - ext_abort + ext_abort() end; end. '''; @@ -474,7 +474,7 @@ const program TestP; uses AltA, AltB; begin - DoA; DoB + DoA(); DoB() end. '''; var diff --git a/compiler/src/test/pascal/cp.test.multiwrite.pas b/compiler/src/test/pascal/cp.test.multiwrite.pas index ca08343..513cd55 100644 --- a/compiler/src/test/pascal/cp.test.multiwrite.pas +++ b/compiler/src/test/pascal/cp.test.multiwrite.pas @@ -155,7 +155,7 @@ begin ''' program P; begin - WriteLn + WriteLn() end. '''); AssertTrue('empty WriteLn still emits newline', diff --git a/compiler/src/test/pascal/cp.test.overload.pas b/compiler/src/test/pascal/cp.test.overload.pas index 12b1aa9..a74fed9 100644 --- a/compiler/src/test/pascal/cp.test.overload.pas +++ b/compiler/src/test/pascal/cp.test.overload.pas @@ -175,7 +175,7 @@ const WriteLn(N) end; begin - Greet; + Greet(); Greet(42) end. '''; diff --git a/compiler/src/test/pascal/cp.test.parser.pas b/compiler/src/test/pascal/cp.test.parser.pas index 4783d76..91aa52b 100644 --- a/compiler/src/test/pascal/cp.test.parser.pas +++ b/compiler/src/test/pascal/cp.test.parser.pas @@ -47,7 +47,8 @@ type procedure TestAssignment_IntLit; procedure TestAssignment_StringLit; procedure TestProcCall_NoArgs; - procedure TestProcCall_NoParens; + procedure TestProcCall_BareNoParens_RequiresParens; + procedure TestMethodCall_BareNoParens_RequiresParens; procedure TestProcCall_OneStringArg; procedure TestProcCall_OneIntArg; @@ -406,18 +407,37 @@ begin end; end; -procedure TParserTests.TestProcCall_NoParens; -var - Prog: TProgram; - Call: TProcCall; +procedure TParserTests.TestProcCall_BareNoParens_RequiresParens; begin - Prog := ParseSource('program P; begin WriteLn end.'); + { Issue #148: a parameterless call in statement position requires its + mandatory () (see language-rationale.adoc, "Mandatory parentheses on + zero-argument calls"). `WriteLn` without () is a parse error. } try - Call := TProcCall(Prog.Block.Stmts.Items[0]); - AssertEquals('Name', 'WriteLn', Call.Name); - AssertEquals('0 args', 0, Call.Args.Count); - finally - Prog.Free(); + ParseSource('program P; begin WriteLn end.').Free(); + Fail('Expected EParseError for bare parameterless call'); + except + on E: EParseError do + AssertTrue('mentions mandatory parens', + Pos('requires () for a call', E.Message) >= 0); + end; +end; + +procedure TParserTests.TestMethodCall_BareNoParens_RequiresParens; +begin + { Issue #148: a parameterless METHOD call in statement position likewise + requires (). `tester.print` (no parens) is a parse error. } + try + ParseSource( + 'program P;' + + ' type TC = class procedure P; end;' + + ' procedure TC.P; begin end;' + + ' var c: TC;' + + ' begin c := TC.Create(); c.P end.').Free(); + Fail('Expected EParseError for bare parameterless method call'); + except + on E: EParseError do + AssertTrue('mentions mandatory parens', + Pos('requires () for a call', E.Message) >= 0); end; end; diff --git a/compiler/src/test/pascal/cp.test.procs.pas b/compiler/src/test/pascal/cp.test.procs.pas index 64f9d5c..770a14d 100644 --- a/compiler/src/test/pascal/cp.test.procs.pas +++ b/compiler/src/test/pascal/cp.test.procs.pas @@ -588,10 +588,10 @@ const begin end; begin - Inner; + Inner(); end; begin - Outer; + Outer(); end. '''; var IR: string; @@ -619,10 +619,10 @@ const end; begin x := 0; - Inner; + Inner(); end; begin - Outer; + Outer(); end. '''; var IR: string; @@ -650,7 +650,7 @@ const WriteLn(1); end; begin - Inner; + Inner(); end; procedure OuterB; procedure Inner; @@ -658,11 +658,11 @@ const WriteLn(2); end; begin - Inner; + Inner(); end; begin - OuterA; - OuterB; + OuterA(); + OuterB(); end. '''; var diff --git a/compiler/src/test/pascal/cp.test.proctypes.pas b/compiler/src/test/pascal/cp.test.proctypes.pas index 5333acc..0d1449b 100644 --- a/compiler/src/test/pascal/cp.test.proctypes.pas +++ b/compiler/src/test/pascal/cp.test.proctypes.pas @@ -494,7 +494,7 @@ begin begin end; begin - UseFn; + UseFn(); end. ''' ); diff --git a/compiler/src/test/pascal/cp.test.proctypes_ofobject.pas b/compiler/src/test/pascal/cp.test.proctypes_ofobject.pas index 9e0f395..1de1edc 100644 --- a/compiler/src/test/pascal/cp.test.proctypes_ofobject.pas +++ b/compiler/src/test/pascal/cp.test.proctypes_ofobject.pas @@ -413,7 +413,7 @@ const program P; type TM = procedure of object; var G: TM; - begin G end. + begin G() end. '''; var IR: string; begin @@ -448,7 +448,7 @@ const M.Code := MethodAddress(F, 'SayHi'); M.Data := F; G := TGreet(M); - G; + G(); F.Free() end. '''; @@ -509,7 +509,7 @@ const M.Code := MethodAddress(C, 'Print'); M.Data := C; G := TPrintMethod(M); - G; + G(); C.Free() end. '''; diff --git a/compiler/src/test/pascal/cp.test.semantic.pas b/compiler/src/test/pascal/cp.test.semantic.pas index 5ed7692..818c963 100644 --- a/compiler/src/test/pascal/cp.test.semantic.pas +++ b/compiler/src/test/pascal/cp.test.semantic.pas @@ -473,7 +473,7 @@ end; procedure TSemanticTests.TestProcCall_WriteLn_NoArgs_OK; begin - Analyse('program P; begin WriteLn end.').Free(); + Analyse('program P; begin WriteLn() end.').Free(); end; procedure TSemanticTests.TestProcCall_WriteLn_StringArg_OK; @@ -520,7 +520,7 @@ end; procedure TSemanticTests.TestProcCall_UndeclaredProc_RaisesError; begin - AnalyseExpectError('program P; begin NoSuchProc end.'); + AnalyseExpectError('program P; begin NoSuchProc() end.'); end; { ------------------------------------------------------------------ } diff --git a/docs/grammar.ebnf b/docs/grammar.ebnf index 9db6fe5..aa702f5 100644 --- a/docs/grammar.ebnf +++ b/docs/grammar.ebnf @@ -854,7 +854,7 @@ StaticSubscriptAssign * assignment (SubscriptFieldAssign) or a method call on the element * (SubscriptMethodCall). Examples: * a[0].Name := 'x'; a[i].Inner.N := 5; - * a[0].Bump; a[i].Items.Add(x); + * a[0].Bump(); a[i].Items.Add(x); * a[i].Arr[j] := v; — element write into an array-typed field * A terminating subscript directly over another subscript (a[i][j] := v, or * the comma form a[i, j] := v) is a multi-dimensional element write — see @@ -866,7 +866,7 @@ SubscriptFieldAssign SubscriptMethodCall = IDENT LBRACKET Expr RBRACKET { SubscriptSuffix } - DOT IDENT [ LPAREN [ ArgList ] RPAREN ] + DOT IDENT LPAREN [ ArgList ] RPAREN ; (* A subscript suffix indexes one or more dimensions. The comma form diff --git a/docs/language-rationale.adoc b/docs/language-rationale.adoc index ec3ded1..9faa983 100644 --- a/docs/language-rationale.adoc +++ b/docs/language-rationale.adoc @@ -3954,6 +3954,14 @@ the lexical level: `Foo()` is always a call, `Foo` is always a read. The compiler AST becomes simpler — `TMethodCallExpr` for calls with explicit parentheses, `TFieldAccessExpr` only for field/property reads. +The rule applies in *statement* position as well as expression position: a +bare `Foo;`, `Obj.Method;`, or `Obj.Free;` used as a statement is a parse +error (issue #148). Earlier the statement parser silently accepted the +bare form — expression position was already enforced, but statement-position +parameterless calls slipped through and built a paren-less `TProcCall` / +`TMethodCallStmt`. Both now raise the same "requires () for a call" +diagnostic the `inherited` and expression-position paths use. + === Alternatives considered * *Deprecation warning period* — rejected. Blaise is in alpha; there is no diff --git a/stdlib/src/main/pascal/json.writer.pas b/stdlib/src/main/pascal/json.writer.pas index b4c03e6..4ecad32 100644 --- a/stdlib/src/main/pascal/json.writer.pas +++ b/stdlib/src/main/pascal/json.writer.pas @@ -20,10 +20,10 @@ W.WriteBool('stable', True); 2. Array elements - value only, no name (the '...Value' forms): - W.BeginArray; + W.BeginArray(); W.WriteStringValue('a'); W.WriteIntValue(1); - W.EndArray; + W.EndArray(); 3. Structure / escape hatch - when an object member's value is itself a nested object or array, write the key, then open the container: diff --git a/tests/phase2_milestone.pas b/tests/phase2_milestone.pas index 82db173..8905731 100644 --- a/tests/phase2_milestone.pas +++ b/tests/phase2_milestone.pas @@ -92,7 +92,7 @@ begin Result := N.FValue; Self.FHead := N.FNext; Self.FCount := Self.FCount - 1; - N.Free + N.Free() end; procedure TLinkedList.Walk; @@ -120,7 +120,7 @@ begin while N <> nil do begin Next := N.FNext; - N.Free; + N.Free(); N := Next end; Self.FHead := nil; @@ -145,7 +145,7 @@ begin WriteLn('count=', List.Count); { 4 } WriteLn('--- walk ---'); - List.Walk; { 40/tag0, 30/tag1/marked, 20/tag0, 10/tag0 } + List.Walk(); { 40/tag0, 30/tag1/marked, 20/tag0, 10/tag0 } { Pop two values off the front } V := List.Pop(); @@ -155,7 +155,7 @@ begin WriteLn('count_after_pops=', List.Count); { 2 } finally - List.Clear; - List.Free + List.Clear(); + List.Free() end end. diff --git a/tests/phase3_milestone.pas b/tests/phase3_milestone.pas index 84c4bef..beab9dc 100644 --- a/tests/phase3_milestone.pas +++ b/tests/phase3_milestone.pas @@ -56,7 +56,7 @@ var Dest: ^Integer; begin if Self.FCount = Self.FCapacity then - Self.Grow; + Self.Grow(); Dest := Self.FData + Self.FCount * SizeOf(Integer); Dest^ := Value; Self.FCount := Self.FCount + 1 @@ -147,7 +147,7 @@ begin else begin if Self.FCount = Self.FCapacity then - Self.Grow; + Self.Grow(); KPtr := Self.FKeys + Self.FCount * SizeOf(string); VPtr := Self.FValues + Self.FCount * SizeOf(Integer); KPtr^ := Key; @@ -251,7 +251,7 @@ begin WriteLn('count_after_delete=', List.Count); { 4 } WriteLn('list[1]_after_delete=', List.Get(1)); { 30 } - List.Free; + List.Free(); { --- TDictionary --- } Dict := TStrIntDict.Create; @@ -277,5 +277,5 @@ begin Found := Dict.ContainsKey('alpha'); WriteLn('has_alpha_after_remove=', Found); { 0 } - Dict.Free + Dict.Free() end.