Skip to content

Commit

Permalink
Parse array types (#6)
Browse files Browse the repository at this point in the history
* Parse array types

* generate opencover XML report

* revert changes to coverage reporting setup

* output more formats when collecting coverage
  • Loading branch information
kevinbarabash authored Nov 1, 2023
1 parent 8567293 commit 17bf6ba
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Build
run: dotnet build
- name: Test
run: dotnet test --collect:"XPlat Code Coverage"
run: dotnet test --collect:"XPlat Code Coverage;Format=json,lcov,cobertura"
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ bin
obj
.fake
TestResults
coverage.opencover.xml
8 changes: 4 additions & 4 deletions src/Escalier.Parser.Tests/Escalier.Parser.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FParsec" Version="1.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="Verify.Xunit" Version="22.1.4" />
Expand All @@ -22,10 +26,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
16 changes: 16 additions & 0 deletions src/Escalier.Parser.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,19 @@ let ParseUnionAndIntersectionType () =
let result = sprintf "input: %s\noutput: %A" src expr

Verifier.Verify(result, settings).ToTask() |> Async.AwaitTask

[<Fact>]
let ParseArrayType () =
let src = "number[][]"
let expr = run ExprParser.typeAnn src
let result = sprintf "input: %s\noutput: %A" src expr

Verifier.Verify(result, settings).ToTask() |> Async.AwaitTask

[<Fact>]
let ParseParenthesizedType () =
let src = "(number | string)[]"
let expr = run ExprParser.typeAnn src
let result = sprintf "input: %s\noutput: %A" src expr

Verifier.Verify(result, settings).ToTask() |> Async.AwaitTask
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
input: number[][]
output: Success: { kind = Array { kind = Array { kind = Keyword Number
span = { start = 0
stop = 6 }
inferred_type = None }
span = { start = 0
stop = 8 }
inferred_type = None }
span = { start = 0
stop = 10 }
inferred_type = None }
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
input: (number | string)[]
output: Success: { kind =
Array { kind = Union [{ kind = Keyword Number
span = { start = 1
stop = 8 }
inferred_type = None }; { kind = Keyword String
span = { start = 10
stop = 16 }
inferred_type = None }]
span = { start = 1
stop = 16 }
inferred_type = None }
span = { start = 1
stop = 19 }
inferred_type = None }
96 changes: 57 additions & 39 deletions src/Escalier.Parser/ExprParser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ module ExprParser =
let stmt, stmtRef = createParserForwardedToRef<Stmt, unit> ()
let pattern, patternRef = createParserForwardedToRef<Pattern, unit> ()
let typeAnn, typeAnnRef = createParserForwardedToRef<TypeAnn, unit> ()
let primaryType, primaryTypeRef = createParserForwardedToRef<TypeAnn, unit> ()

let opp = new OperatorPrecedenceParser<Expr, list<Expr>, unit>()

Expand Down Expand Up @@ -484,7 +483,7 @@ module ExprParser =
{ kind = StmtKind.Decl(decl)
span = { start = start; stop = stop } }

stmtRef.Value <- varDecl <|> typeDecl <|> returnStmt <|> exprStmt
stmtRef.Value <- choice [ varDecl; typeDecl; returnStmt; exprStmt ]

let private identPattern =
pipe3 getPosition ident getPosition
Expand Down Expand Up @@ -563,24 +562,28 @@ module ExprParser =
inferred_type = None }

patternRef.Value <-
identPattern
<|> literalPattern
<|> wildcardPattern
<|> objectPattern
<|> tuplePattern
choice
[ identPattern
literalPattern
wildcardPattern
objectPattern
tuplePattern ]

let private parenthesizedTypeAnn = (between (str_ws "(") (str_ws ")") typeAnn)

let private keywordTypeAnn =

let keyword =
(str_ws "object" |>> fun _ -> KeywordType.Object)
<|> (str_ws "never" |>> fun _ -> Never)
<|> (str_ws "unknown" |>> fun _ -> Unknown)
<|> (str_ws "boolean" |>> fun _ -> Boolean)
<|> (str_ws "number" |>> fun _ -> Number)
<|> (str_ws "string" |>> fun _ -> String)
<|> (str_ws "symbol" |>> fun _ -> Symbol)
<|> (str_ws "null" |>> fun _ -> Null)
<|> (str_ws "undefined" |>> fun _ -> Undefined)
choice
[ (str_ws "object" |>> fun _ -> KeywordType.Object)
(str_ws "never" |>> fun _ -> Never)
(str_ws "unknown" |>> fun _ -> Unknown)
(str_ws "boolean" |>> fun _ -> Boolean)
(str_ws "number" |>> fun _ -> Number)
(str_ws "string" |>> fun _ -> String)
(str_ws "symbol" |>> fun _ -> Symbol)
(str_ws "null" |>> fun _ -> Null)
(str_ws "undefined" |>> fun _ -> Undefined) ]

pipe3 getPosition keyword getPosition
<| fun p1 keyword p2 ->
Expand Down Expand Up @@ -648,7 +651,43 @@ module ExprParser =
span = { start = start; stop = stop }
inferred_type = None }

let opp' = new OperatorPrecedenceParser<TypeAnn, Position, unit>()

let primaryType = opp'.ExpressionParser

// NOTE(kevinb): We use an operator precedence parser to workaround the
// fact that `[]` is left recursive.
opp'.AddOperator(
PostfixOperator(
"[]",
getPosition .>> ws,
1,
true,
(),
(fun pos target ->
{ TypeAnn.kind = Array(target)
span =
{ start = target.span.start
stop = pos.Index |> int }
inferred_type = None })
)
)

opp'.TermParser <-
choice
[ parenthesizedTypeAnn
keywordTypeAnn // aka PredefinedType
// objectTypeAnn
tupleTypeAnn
typeofTypeAnn // aka TypeQuery
keyofTypeAnn
restTypeAnn
// thisTypeAnn
// NOTE: should come last since any identifier can be a type reference
typeRef ]

// NOTE: We don't use InfixOperator here because that only supports
// binary operators and intersection types are n-ary.
let intersectionOrPrimaryType: Parser<TypeAnn, unit> =
pipe3 getPosition (sepBy1 primaryType (str_ws "&")) getPosition
<| fun p1 typeAnns p2 ->
Expand All @@ -662,6 +701,8 @@ module ExprParser =
span = { start = start; stop = stop }
inferred_type = None }

// NOTE: We don't use InfixOperator here because that only supports
// binary operators and union types are n-ary.
let unionOrIntersectionOrPrimaryType: Parser<TypeAnn, unit> =
pipe3
getPosition
Expand All @@ -678,28 +719,5 @@ module ExprParser =
span = { start = start; stop = stop }
inferred_type = None }

let arrayTypeAnn =
pipe3 getPosition (primaryType .>> (str_ws "[]")) getPosition
<| fun p1 elem p2 ->
let start = p1.Index |> int
let stop = p2.Index |> int

{ TypeAnn.kind = TypeAnnKind.Array(elem)
span = { start = start; stop = stop }
inferred_type = None }

primaryTypeRef.Value <-
// TODO: parathesized types
keywordTypeAnn // PredefinedType
// <|> objectTypeAnn
// <|> arrayTypeAnn
<|> tupleTypeAnn
<|> typeofTypeAnn // TypeQuery
<|> keyofTypeAnn
<|> restTypeAnn
// <|> thisTypeAnn
// should come last since any identifier can be a type reference
<|> typeRef

// TODO: handle function types
typeAnnRef.Value <- unionOrIntersectionOrPrimaryType

0 comments on commit 17bf6ba

Please sign in to comment.