Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/Common/FoxProCmd.xh
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,42 @@
#command DIR => __VfpDir( "" )
#command DIRECTORY => __VfpDir( "" )

// COUNT — the VO rule in dbcmd.xh requires the TO clause (it expands to
// "<xvar> := 0", which leaves a dangling ":=" when TO is omitted) and never
// updates _TALLY. VFP accepts the TO clause both right after COUNT and at the
// end, so both orders need their own rule: an optional clause cannot be matched
// across a mandatory one.
#command COUNT ;
[ALL] ;
[<REST:REST>] ;
[NEXT <nnext>] ;
[RECORD <rec>] ;
[FOR <lfor>] ;
[WHILE <lwhile>] ;
[<noopt: NOOPTIMIZE>] ;
=> __VfpCount( <{lfor}>, <{lwhile}>, <nnext>, <rec>, <.rest.>, <.noopt.> )

#command COUNT TO <xvar> ;
[ALL] ;
[<REST:REST>] ;
[NEXT <nnext>] ;
[RECORD <rec>] ;
[FOR <lfor>] ;
[WHILE <lwhile>] ;
[<noopt: NOOPTIMIZE>] ;
=> <xvar> := __VfpCount( <{lfor}>, <{lwhile}>, <nnext>, <rec>, <.rest.>, <.noopt.> )

#command COUNT ;
[ALL] ;
[<REST:REST>] ;
[NEXT <nnext>] ;
[RECORD <rec>] ;
[FOR <lfor>] ;
[WHILE <lwhile>] ;
TO <xvar> ;
[<noopt: NOOPTIMIZE>] ;
=> <xvar> := __VfpCount( <{lfor}>, <{lwhile}>, <nnext>, <rec>, <.rest.>, <.noopt.> )

// WAIT
#xcommand WAIT <msg> [<win:WINDOW> [AT <nRow>, <nCol>]] [<now:NOWAIT>] [<nclr:NOCLEAR>] [TIMEOUT <secs>] ;
=> __VfpWait(<msg>, <.win.>, <!nRow!>, <!nCol!>, <.now.>, <.nclr.>, <!secs!>)
Expand Down
135 changes: 135 additions & 0 deletions src/Runtime/XSharp.VFP.Tests/TallyTests.prg
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//
// Copyright (c) XSharp B.V. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System
USING XUnit

BEGIN NAMESPACE XSharp.VFP.Tests
CLASS TallyTests

STATIC CONSTRUCTOR
XSharp.RuntimeState.Dialect := XSharpDialect.FoxPro
END CONSTRUCTOR

PRIVATE METHOD CreateTestCursor() AS VOID
CREATE CURSOR curtally (f I)
INSERT INTO curtally VALUES (1)
INSERT INTO curtally VALUES (2)
INSERT INTO curtally VALUES (3)
INSERT INTO curtally VALUES (4)
INSERT INTO curtally VALUES (5)
GO TOP
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD CountWithoutToClauseSetsTally AS VOID
TRY
SELF:CreateTestCursor()
_TALLY := -1
COUNT
Assert.Equal(5, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD CountWithForSetsTally AS VOID
TRY
SELF:CreateTestCursor()
_TALLY := -1
COUNT FOR curtally->f > 2
Assert.Equal(3, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD CountToVariableSetsBothTheVariableAndTally AS VOID
LOCAL n AS USUAL
TRY
SELF:CreateTestCursor()
_TALLY := -1
COUNT TO n
Assert.Equal(5, (INT) n)
Assert.Equal(5, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD CountAcceptsToBeforeFor AS VOID
LOCAL n AS USUAL
TRY
SELF:CreateTestCursor()
_TALLY := -1
COUNT TO n FOR curtally->f > 3
Assert.Equal(2, (INT) n)
Assert.Equal(2, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD CountAcceptsToAfterFor AS VOID
LOCAL n AS USUAL
TRY
SELF:CreateTestCursor()
_TALLY := -1
COUNT FOR curtally->f > 3 TO n
Assert.Equal(2, (INT) n)
Assert.Equal(2, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD CountAcceptsScopeBeforeFor AS VOID
LOCAL n AS USUAL
TRY
SELF:CreateTestCursor()
_TALLY := -1
COUNT ALL FOR curtally->f > 2 TO n NOOPTIMIZE
Assert.Equal(3, (INT) n)
Assert.Equal(3, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD CountNextLimitsTheScope AS VOID
LOCAL n AS USUAL
TRY
SELF:CreateTestCursor()
_TALLY := -1
COUNT NEXT 3 TO n
Assert.Equal(3, (INT) n)
Assert.Equal(3, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

[Fact, Trait("Category", "Tally")];
METHOD NavigationDoesNotChangeTally AS VOID
TRY
SELF:CreateTestCursor()
COUNT
_TALLY := 99
GO TOP
Assert.Equal(99, (INT) _TALLY)
FINALLY
USE
END TRY
END METHOD

END CLASS
END NAMESPACE
1 change: 1 addition & 0 deletions src/Runtime/XSharp.VFP.Tests/XSharp.VFP.Tests.xsproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
<Compile Include="SetDateCommandTests.prg" />
<Compile Include="SQLStatementTests.prg" />
<Compile Include="StrConvTests.prg" />
<Compile Include="TallyTests.prg" />
<Compile Include="TypeTests.prg" />
<Compile Include="EmptyTests.prg" />
<Compile Include="FoxArraytests.prg" />
Expand Down
7 changes: 7 additions & 0 deletions src/Runtime/XSharp.VFP/Commands.prg
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,10 @@ FUNCTION __VfpWaitForKey(uTimeout AS USUAL) AS STRING

function __VfpWaitClear() as void
return

/// <exclude/>
FUNCTION __VfpCount(cbFor, cbWhile, nNext, nRecord, lRest, lNoOpt) AS LONG CLIPPER
LOCAL nCount := 0 AS LONG
DbEval({|| nCount += 1}, cbFor, cbWhile, nNext, nRecord, lRest, lNoOpt)
_TALLY := nCount
RETURN nCount