Skip to content

Commit

Permalink
finishing initial port of gaze, closes #9
Browse files Browse the repository at this point in the history
  • Loading branch information
almibe committed Jan 13, 2023
1 parent a5b1678 commit b082eae
Show file tree
Hide file tree
Showing 7 changed files with 446 additions and 8 deletions.
25 changes: 25 additions & 0 deletions src/Gaze.Test/Gaze.Test.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<GenerateProgramFile>false</GenerateProgramFile>
</PropertyGroup>

<ItemGroup>
<Compile Include="GazeSuite.fs" />
<Compile Include="NibblersSuite.fs" />
<Compile Include="Main.fs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Expecto" Version="9.*" />
<PackageReference Include="YoloDev.Expecto.TestSdk" Version="0.*" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Gaze\Gaze.fsproj" />
</ItemGroup>

</Project>
49 changes: 49 additions & 0 deletions src/Gaze.Test/GazeSuite.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

module GazeSuite

open Expecto

[<Tests>]
let tests =
testList "Gaze Suite" [
testCase "empty String input" <| fun _ ->
let gaze = Gaze.fromString("")
Expect.isTrue (Gaze.isComplete gaze) ""
Expect.equal (Gaze.peek gaze) None ""
Expect.equal (Gaze.peek gaze) None ""
Expect.isTrue (Gaze.isComplete gaze) ""

testCase "empty array input" <| fun _ ->
let gaze = Gaze.fromArray([||])
Expect.isTrue (Gaze.isComplete gaze) ""
Expect.equal (Gaze.peek gaze) None ""
Expect.equal (Gaze.peek gaze) None ""
Expect.isTrue (Gaze.isComplete gaze) ""

testCase "init Gaze with one value" <| fun _ ->
let gaze = Gaze.fromArray([|'a'|])
Expect.isFalse (Gaze.isComplete gaze) ""
Expect.equal (Gaze.peek gaze) (Some('a')) ""
Expect.equal (Gaze.peek gaze) (Some('a')) ""
Expect.equal (Gaze.next gaze) (Some('a')) ""
Expect.equal (Gaze.next gaze) None ""
Expect.isTrue (Gaze.isComplete gaze) ""

testCase "init Gaze with single char String" <| fun _ ->
let gaze = Gaze.fromString("a")
Expect.isFalse (Gaze.isComplete gaze) ""
Expect.equal (Gaze.peek gaze) (Some('a')) ""
Expect.equal (Gaze.peek gaze) (Some('a')) ""
Expect.equal (Gaze.next gaze) (Some('a')) ""
Expect.equal (Gaze.next gaze) None ""
Expect.isTrue (Gaze.isComplete gaze) ""

testCase "map digit" <| fun _ ->
let gaze = Gaze.fromString("1")
let result = Some(1)
let nibbler = Gaze.map Gaze.next (fun char -> int (string char))
Expect.equal(Gaze.attempt nibbler gaze) result ""
]
9 changes: 9 additions & 0 deletions src/Gaze.Test/Main.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

open Expecto

[<EntryPoint>]
let main argv =
Tests.runTestsInAssembly defaultConfig argv
156 changes: 156 additions & 0 deletions src/Gaze.Test/NibblersSuite.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

module NibblersSuite

open Expecto

[<Tests>]
let tests = testList "Nibbler Tests" [
testList "Take Suite" [
testCase "take with single value" <| fun _ ->
let gaze = Gaze.fromString("a")
Expect.equal (Gaze.attempt (Nibblers.take 'a') gaze) (Some('a')) ""
Expect.isTrue (Gaze.isComplete gaze) ""
]

testList "Take List Suite" [
testCase "takeList simple" <| fun _ ->
let gaze = Gaze.fromString("hello, world")
let list = ['h'; 'e'; 'l'; 'l'; 'o']
Expect.equal (Gaze.attempt (Nibblers.takeList list) gaze) (Some(list)) ""
Expect.equal(Gaze.peek gaze) (Some(',')) ""
]

testList "Take String Suite" [
testCase "takeString simple" <| fun _ ->
let gaze = Gaze.fromString("hello, world")
Expect.equal (Gaze.attempt(Nibblers.takeString "hello") gaze) (Some(['h'; 'e'; 'l'; 'l'; 'o'])) ""
Expect.equal (Gaze.peek gaze) (Some(',')) ""
]

testList "Take Cond Suite" [
testCase "takeCond with a single value" <| fun _ ->
let gaze = Gaze.fromString("a")
Expect.equal
(Gaze.attempt(Nibblers.takeCond (fun c -> c = 'a')) gaze)
(Some('a')) ""
assert(Gaze.isComplete(gaze))
testCase "takeCond with multiple values" <| fun _ ->
let gaze = Gaze.fromString("cab")
Expect.equal
(Gaze.attempt(Nibblers.takeCond(fun c -> List.contains c ['a'; 'b'; 'c'; 'd'])) gaze)
(Some('c')) ""
Expect.isFalse (Gaze.isComplete gaze) ""
testCase "takeCond match beginning" <| fun _ ->
let gaze = Gaze.fromString("abc123")
Expect.equal
(Gaze.attempt(Nibblers.takeCond(fun c -> List.contains c ['a'; 'b'; 'c'; 'd'])) gaze)
(Some('a')) ""
Expect.isFalse (Gaze.isComplete gaze) ""
testCase "takeCond no match beginning" <| fun _ ->
let gaze = Gaze.fromString("123abc")
Expect.equal
(Gaze.attempt(Nibblers.takeCond(fun c -> List.contains c ['a'; 'b'; 'c'; 'd'])) gaze)
None ""
Expect.isFalse (Gaze.isComplete gaze) ""
]

testList "Take While Suite" [
testCase "takeWhile with a single value" <| fun _ ->
let gaze = Gaze.fromString("a")
Expect.equal (Gaze.attempt(Nibblers.takeWhile(fun c -> c = 'a')) gaze) (Some(['a'])) ""
Expect.isTrue (Gaze.isComplete gaze) ""
testCase "takeWhile with multiple values" <| fun _ ->
let gaze = Gaze.fromString("cab")
Expect.equal
(Gaze.attempt (Nibblers.takeWhile(fun c -> List.contains c ['a'; 'b'; 'c'; 'd'])) gaze)
(Some(['c'; 'a'; 'b'])) ""
Expect.isTrue (Gaze.isComplete gaze) ""
testCase "takeWhile match beginning" <| fun _ ->
let gaze = Gaze.fromString("abc123")
Expect.equal
(Gaze.attempt(Nibblers.takeWhile(fun c -> List.contains c ['a'; 'b'; 'c'; 'd'])) gaze)
(Some(['a'; 'b'; 'c'])) ""
Expect.isFalse (Gaze.isComplete gaze) ""
testCase "takeWhile no match beginning" <| fun _ ->
let gaze = Gaze.fromString("123abc")
Expect.equal
(Gaze.attempt(Nibblers.takeWhile(fun c -> List.contains c ['a'; 'b'; 'c'; 'd'])) gaze) None ""
Expect.isFalse (Gaze.isComplete gaze) ""
]

testList "Take While Index Suite" [
testCase "takeWhileIndex simple" <| fun _ ->
let gaze = Gaze.fromString("abc")
Expect.equal
(Gaze.attempt(Nibblers.takeWhileIndex(fun (c, i) -> (c = 'a' && i = 0) || (c = 'b' && i = 1))) gaze)
(Some(['a'; 'b'])) ""
Expect.isFalse(Gaze.isComplete gaze) ""
]

testList "Take Until Suite" [
testCase "takeUntil simple" <| fun _ ->
let gaze = Gaze.fromString("hello, world")
Expect.equal
(Gaze.attempt (Nibblers.takeUntil (Nibblers.take ',')) gaze)
(Some(['h'; 'e'; 'l'; 'l'; 'o'])) ""
Expect.equal (Gaze.peek gaze) (Some(',')) ""
]

testList "Between Suite" [
testCase "between simple" <| fun _ ->
let gaze = Gaze.fromString("abbbbbc")
Expect.equal
(Gaze.attempt(Nibblers.between 'a' (Nibblers.takeWhile(fun c -> c = 'b')) 'c') gaze)
(Some(['b'; 'b'; 'b'; 'b'; 'b'])) ""
Expect.isTrue (Gaze.isComplete gaze) ""
]

testList "Optional Suite" [
testCase "optional simple" <| fun _ ->
let gaze = Gaze.fromString("a")
Expect.equal
(Gaze.attempt(Nibblers.optional(Gaze.map (Nibblers.take 'b') (fun r -> [r]))) gaze)
(Some([])) ""
Expect.equal (Gaze.peek gaze) (Some('a')) ""
]

testList "Repeat Suite" [
testCase "repeat simple" <| fun _ ->
let gaze = Gaze.fromString("aaaabbbbbc")
Expect.equal(Gaze.attempt(Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'a'))) gaze) (Some(['a'; 'a'; 'a'; 'a'])) ""
Expect.isFalse(Gaze.isComplete gaze) ""
Expect.equal(Gaze.attempt(Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'b'))) gaze) (Some(['b'; 'b'; 'b'; 'b'; 'b'])) ""
Expect.isFalse(Gaze.isComplete gaze) ""
Expect.equal(Gaze.attempt(Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'c'))) gaze) (Some(['c'])) ""
Expect.isTrue(Gaze.isComplete gaze) ""
]

testList "Take All Suite" [
testCase "take all simple" <| fun _ ->
let gaze = Gaze.fromString("aaaabbbbbc")
let takeAs = Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'a'))
let takeBs = Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'b'))
let takeCs = Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'c'))
let takeAll = Nibblers.takeAll [takeAs; takeBs; takeCs]
Expect.equal
(Gaze.attempt takeAll gaze)
(Some([['a'; 'a'; 'a'; 'a']; ['b'; 'b'; 'b'; 'b'; 'b']; ['c']])) ""
Expect.isTrue(Gaze.isComplete gaze) ""
]

testList "Take First Suite" [
testCase "take first simple" <| fun _ ->
let gaze = Gaze.fromString("aaaabbbbbc")
let takeAs = Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'a'))
let takeBs = Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'b'))
let takeCs = Nibblers.repeat(Nibblers.takeCond(fun c -> c = 'c'))
let takeFirst = Nibblers.takeFirst [takeCs; takeBs; takeAs]
Expect.equal
(Gaze.attempt takeFirst gaze)
(Some(['a'; 'a'; 'a'; 'a'])) ""
Expect.isFalse(Gaze.isComplete gaze) ""
]
]
15 changes: 7 additions & 8 deletions src/Gaze/Gaze.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Gaze<'input> = {

type Nibbler<'input, 'output> = Gaze<'input> -> 'output option

let private explode (s:string) =
let explode (s:string) =
[| for c in s -> c |]

/// Create an instance of Gaze that works with a String as input.
Expand Down Expand Up @@ -50,15 +50,14 @@ let check nibbler gaze =
let attempt nibbler gaze =
let startOffset = gaze.offset
match nibbler gaze with
| Some(res) -> Some(res)
| None ->
gaze.offset <- startOffset
None
| Some(res) -> Some(res)
| None ->
gaze.offset <- startOffset
None

let offset gaze = gaze.offset

let map nibbler mapper gaze =
match attempt nibbler gaze with
| Some(result) ->
Some(mapper(result))
| None -> None
| Some(result) -> Some(mapper(result))
| None -> None
13 changes: 13 additions & 0 deletions src/Gaze/Gaze.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="Gaze.fs" />
<Compile Include="Nibblers.fs" />
</ItemGroup>

</Project>

0 comments on commit b082eae

Please sign in to comment.