Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Commit a317cf7

Browse files
yjt98765Ryan Moreno (HE/HIM)
authored andcommitted
Complete NamespaceItem in qsfmt (#1239)
1 parent 4ea9514 commit a317cf7

File tree

9 files changed

+342
-25
lines changed

9 files changed

+342
-25
lines changed

src/QsFmt/Formatter.Tests/Examples.fs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ return x + 1;
4848

4949
[<Example(ExampleKind.Format)>]
5050
let ``Adds newlines and indents`` =
51-
"""namespace Foo { function Bar() : Int { let x = 5; return x; } }""",
51+
"""namespace Foo { newtype InternalType = Unit; function Bar() : Int { let x = 5; return x; } }""",
5252

5353
"""namespace Foo {
54+
newtype InternalType = Unit;
5455
function Bar() : Int {
5556
let x = 5;
5657
return x;
@@ -60,6 +61,8 @@ let ``Adds newlines and indents`` =
6061
[<Example(ExampleKind.Format)>]
6162
let ``Removes extraneous spaces`` =
6263
"""namespace Foo {
64+
open qualified.name as qn;
65+
internal newtype Complex = (Real: Double, Imaginary : Double);
6366
function Bar() : Int [ ] {
6467
let x= // Newlines are preserved.
6568
(7 * 1) // Comments too.
@@ -70,6 +73,8 @@ let ``Removes extraneous spaces`` =
7073
}""",
7174

7275
"""namespace Foo {
76+
open qualified.name as qn;
77+
internal newtype Complex = (Real: Double, Imaginary : Double);
7378
function Bar() : Int [ ] {
7479
let x = // Newlines are preserved.
7580
(7 * 1) // Comments too.

src/QsFmt/Formatter/ParseTree/Namespace.fs

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,50 @@ type CallableBodyVisitor(tokens) =
132132
}
133133
|> Specializations
134134

135+
type UnderlyingTypeVistor(tokens) =
136+
inherit QSharpParserBaseVisitor<UnderlyingType>()
137+
138+
let typeVisitor = TypeVisitor tokens
139+
140+
override _.DefaultResult = failwith "Unknown underlying type."
141+
142+
override visitor.VisitTupleUnderlyingType context =
143+
context.typeDeclarationTuple () |> visitor.Visit
144+
145+
override _.VisitUnnamedTypeItem context =
146+
context.``type`` () |> typeVisitor.Visit |> Type
147+
148+
override _.VisitTypeDeclarationTuple context =
149+
let parameters = context._items |> Seq.map (TypeTupleItemVistor tokens).Visit
150+
let commas = context._commas |> Seq.map (Node.toTerminal tokens)
151+
152+
{
153+
OpenParen = context.openParen |> Node.toTerminal tokens
154+
Items = Node.tupleItems parameters commas
155+
CloseParen = context.closeParen |> Node.toTerminal tokens
156+
}
157+
|> TypeDeclarationTuple
158+
159+
and TypeTupleItemVistor(tokens) =
160+
inherit QSharpParserBaseVisitor<TypeTupleItem>()
161+
162+
let typeVisitor = TypeVisitor tokens
163+
let underlyingTypeVistor = UnderlyingTypeVistor tokens
164+
165+
override _.DefaultResult = failwith "Unknown type tuple item."
166+
167+
override visitor.VisitNamedTypeItem context = context.namedItem () |> visitor.Visit
168+
169+
override _.VisitUnderlyingTypeItem context =
170+
context.underlyingType () |> underlyingTypeVistor.Visit |> UnderlyingType
171+
172+
override _.VisitNamedItem context =
173+
{
174+
Name = context.name |> Node.toTerminal tokens
175+
Type = { Colon = context.colon |> Node.toTerminal tokens; Type = context.itemType |> typeVisitor.Visit }
176+
}
177+
|> TypeBinding
178+
135179
/// <summary>
136180
/// Creates syntax tree <see cref="NamespaceItem"/> nodes from a parse tree and the list of tokens.
137181
/// </summary>
@@ -141,30 +185,56 @@ type NamespaceItemVisitor(tokens) =
141185
let parameterVisitor = ParameterVisitor tokens
142186
let typeVisitor = TypeVisitor tokens
143187
let callableBodyVisitor = CallableBodyVisitor tokens
188+
let underlyingTypeVistor = UnderlyingTypeVistor tokens
144189

145190
override _.DefaultResult = failwith "Unknown namespace element."
146191

147192
override _.VisitChildren node = Node.toUnknown tokens node |> Unknown
148193

149-
override _.VisitCallableElement context =
194+
override visitor.VisitOpenElement context =
195+
context.openDirective () |> visitor.Visit
196+
197+
override visitor.VisitTypeElement context =
198+
context.typeDeclaration () |> visitor.Visit
199+
200+
override visitor.VisitCallableElement context =
201+
context.callableDeclaration () |> visitor.Visit
202+
203+
override _.VisitOpenDirective context =
150204
{
151-
Attributes =
152-
context.callable.prefix._attributes |> Seq.map (NamespaceContext.toAttribute tokens) |> Seq.toList
153-
Access = context.callable.prefix.access () |> Option.ofObj |> Option.map (Node.toUnknown tokens)
154-
CallableKeyword = context.callable.keyword |> Node.toTerminal tokens
155-
Name = context.callable.name |> Node.toTerminal tokens
205+
OpenKeyword = context.``open`` |> Node.toTerminal tokens
206+
OpenName = context.openName |> Node.toUnknown tokens
207+
AsKeyword = context.``as`` |> Option.ofObj |> Option.map (Node.toTerminal tokens)
208+
AsName = context.asName |> Option.ofObj |> Option.map (Node.toUnknown tokens)
209+
Semicolon = context.semicolon |> Node.toTerminal tokens
210+
}
211+
|> OpenDirective
212+
213+
override _.VisitTypeDeclaration context =
214+
{
215+
Attributes = context.prefix._attributes |> Seq.map (NamespaceContext.toAttribute tokens) |> Seq.toList
216+
Access = context.prefix.access () |> Option.ofObj |> Option.map (Node.toUnknown tokens)
217+
NewtypeKeyword = context.keyword |> Node.toTerminal tokens
218+
DeclaredType = context.declared |> Node.toTerminal tokens
219+
Equals = context.equals |> Node.toTerminal tokens
220+
UnderlyingType = context.underlying |> underlyingTypeVistor.Visit
221+
Semicolon = context.semicolon |> Node.toTerminal tokens
222+
}
223+
|> TypeDeclaration
224+
225+
override _.VisitCallableDeclaration context =
226+
{
227+
Attributes = context.prefix._attributes |> Seq.map (NamespaceContext.toAttribute tokens) |> Seq.toList
228+
Access = context.prefix.access () |> Option.ofObj |> Option.map (Node.toUnknown tokens)
229+
CallableKeyword = context.keyword |> Node.toTerminal tokens
230+
Name = context.name |> Node.toTerminal tokens
156231
TypeParameters =
157-
Option.ofObj context.callable.typeParameters
158-
|> Option.map (NamespaceContext.toTypeParameterBinding tokens)
159-
Parameters = parameterVisitor.Visit context.callable.tuple
232+
Option.ofObj context.typeParameters |> Option.map (NamespaceContext.toTypeParameterBinding tokens)
233+
Parameters = parameterVisitor.Visit context.tuple
160234
ReturnType =
161-
{
162-
Colon = context.callable.colon |> Node.toTerminal tokens
163-
Type = typeVisitor.Visit context.callable.returnType
164-
}
165-
CharacteristicSection =
166-
Option.ofObj context.callable.returnChar |> Option.map (toCharacteristicSection tokens)
167-
Body = callableBodyVisitor.Visit context.callable.body
235+
{ Colon = context.colon |> Node.toTerminal tokens; Type = typeVisitor.Visit context.returnType }
236+
CharacteristicSection = Option.ofObj context.returnChar |> Option.map (toCharacteristicSection tokens)
237+
Body = callableBodyVisitor.Visit context.body
168238
}
169239
|> CallableDeclaration
170240

src/QsFmt/Formatter/SyntaxTree/Namespace.fs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,34 @@ type SpecializationGenerator =
2222

2323
type Specialization = { Names: Terminal list; Generator: SpecializationGenerator }
2424

25+
type OpenDirective =
26+
{
27+
OpenKeyword: Terminal
28+
OpenName: Terminal
29+
AsKeyword: Terminal option
30+
AsName: Terminal option
31+
Semicolon: Terminal
32+
}
33+
34+
type internal UnderlyingType =
35+
| TypeDeclarationTuple of TypeTupleItem Tuple
36+
| Type of Type
37+
38+
and internal TypeTupleItem =
39+
| TypeBinding of ParameterDeclaration
40+
| UnderlyingType of UnderlyingType
41+
42+
type TypeDeclaration =
43+
{
44+
Attributes: Attribute list
45+
Access: Terminal option
46+
NewtypeKeyword: Terminal
47+
DeclaredType: Terminal
48+
Equals: Terminal
49+
UnderlyingType: UnderlyingType
50+
Semicolon: Terminal
51+
}
52+
2553
type CallableBody =
2654
| Statements of Statement Block
2755
| Specializations of Specialization Block
@@ -40,12 +68,23 @@ type CallableDeclaration =
4068
}
4169

4270
type NamespaceItem =
71+
| OpenDirective of OpenDirective
72+
| TypeDeclaration of TypeDeclaration
4373
| CallableDeclaration of CallableDeclaration
4474
| Unknown of Terminal
4575

4676
module NamespaceItem =
4777
let mapPrefix mapper =
4878
function
79+
| OpenDirective openDirective ->
80+
{ openDirective with OpenKeyword = Terminal.mapPrefix mapper openDirective.OpenKeyword }
81+
|> OpenDirective
82+
| TypeDeclaration declaration ->
83+
match declaration.Attributes, declaration.Access with
84+
| head :: tail, _ -> { declaration with Attributes = Attribute.mapPrefix mapper head :: tail }
85+
| [], Some access -> { declaration with Access = Terminal.mapPrefix mapper access |> Some }
86+
| [], None -> { declaration with NewtypeKeyword = Terminal.mapPrefix mapper declaration.NewtypeKeyword }
87+
|> TypeDeclaration
4988
| CallableDeclaration callable ->
5089
{ callable with
5190
CallableKeyword = Terminal.mapPrefix mapper callable.CallableKeyword

src/QsFmt/Formatter/SyntaxTree/Namespace.fsi

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,74 @@ type internal Specialization =
4444
Generator: SpecializationGenerator
4545
}
4646

47+
/// An open directive
48+
type internal OpenDirective =
49+
{
50+
/// <summary>
51+
/// The <c>open</c> keyword.
52+
/// </summary>
53+
OpenKeyword: Terminal
54+
55+
/// The name of the opened namespace.
56+
OpenName: Terminal
57+
58+
/// <summary>
59+
/// The optional <c>as</c> keyword.
60+
/// </summary>
61+
AsKeyword: Terminal option
62+
63+
/// The alias name of the opened namespace.
64+
AsName: Terminal option
65+
66+
/// The semicolon.
67+
Semicolon: Terminal
68+
}
69+
70+
/// The underlying type of a newly defined type.
71+
type internal UnderlyingType =
72+
/// A tuple of type items.
73+
| TypeDeclarationTuple of TypeTupleItem Tuple
74+
75+
/// A simple type.
76+
| Type of Type
77+
78+
/// An item used in type declaration.
79+
and internal TypeTupleItem =
80+
/// A named type item.
81+
| TypeBinding of ParameterDeclaration
82+
83+
/// An anonymous type item.
84+
| UnderlyingType of UnderlyingType
85+
86+
/// A type declaration
87+
type internal TypeDeclaration =
88+
{
89+
/// The attributes attached to the type declaration.
90+
Attributes: Attribute list
91+
92+
/// The access modifier for the callable.
93+
Access: Terminal option
94+
95+
/// <summary>
96+
/// The <c>newtype</c> keyword.
97+
/// </summary>
98+
NewtypeKeyword: Terminal
99+
100+
/// The name of the declared type.
101+
DeclaredType: Terminal
102+
103+
/// <summary>
104+
/// The <c>=</c> symbol.
105+
/// </summary>
106+
Equals: Terminal
107+
108+
/// The underlying type.
109+
UnderlyingType: UnderlyingType
110+
111+
/// The semicolon.
112+
Semicolon: Terminal
113+
}
114+
47115
/// The body of a callable declaration.
48116
type internal CallableBody =
49117
/// An implicit body specialization with statements.
@@ -88,6 +156,12 @@ type internal CallableDeclaration =
88156

89157
/// An item in a namespace.
90158
type internal NamespaceItem =
159+
/// An open directive
160+
| OpenDirective of OpenDirective
161+
162+
/// A type declaration
163+
| TypeDeclaration of TypeDeclaration
164+
91165
/// A callable declaration
92166
| CallableDeclaration of CallableDeclaration
93167

src/QsFmt/Formatter/SyntaxTree/Reducer.fs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,53 @@ type internal 'result Reducer() as reducer =
6868

6969
default _.NamespaceItem item =
7070
match item with
71+
| OpenDirective directive -> reducer.OpenDirective directive
72+
| TypeDeclaration delcaration -> reducer.TypeDeclaration delcaration
7173
| CallableDeclaration callable -> reducer.CallableDeclaration callable
7274
| Unknown terminal -> reducer.Terminal terminal
7375

76+
abstract OpenDirective : directive: OpenDirective -> 'result
77+
78+
default _.OpenDirective directive =
79+
[ reducer.Terminal directive.OpenKeyword; reducer.Terminal directive.OpenName ]
80+
@ (directive.AsKeyword |> Option.map reducer.Terminal |> Option.toList)
81+
@ (directive.AsName |> Option.map reducer.Terminal |> Option.toList)
82+
@ [ reducer.Terminal directive.Semicolon ]
83+
|> reduce
84+
85+
abstract TypeDeclaration : declaration: TypeDeclaration -> 'result
86+
87+
default _.TypeDeclaration declaration =
88+
(declaration.Attributes |> List.map reducer.Attribute)
89+
@ (declaration.Access |> Option.map reducer.Terminal |> Option.toList)
90+
@ [
91+
reducer.Terminal declaration.NewtypeKeyword
92+
reducer.Terminal declaration.DeclaredType
93+
reducer.Terminal declaration.Equals
94+
reducer.UnderlyingType declaration.UnderlyingType
95+
reducer.Terminal declaration.Semicolon
96+
]
97+
|> reduce
98+
7499
abstract Attribute : attribute: Attribute -> 'result
75100

76101
default _.Attribute attribute =
77102
[ reducer.Terminal attribute.At; reducer.Expression attribute.Expression ] |> reduce
78103

104+
abstract UnderlyingType : underlying: UnderlyingType -> 'result
105+
106+
default _.UnderlyingType underlying =
107+
match underlying with
108+
| TypeDeclarationTuple tuple -> reducer.Tuple(reducer.TypeTupleItem, tuple)
109+
| Type _type -> reducer.Type _type
110+
111+
abstract TypeTupleItem : item: TypeTupleItem -> 'result
112+
113+
default _.TypeTupleItem item =
114+
match item with
115+
| TypeBinding binding -> reducer.ParameterDeclaration binding
116+
| UnderlyingType underlying -> reducer.UnderlyingType underlying
117+
79118
abstract CallableDeclaration : callable: CallableDeclaration -> 'result
80119

81120
default _.CallableDeclaration callable =

src/QsFmt/Formatter/SyntaxTree/Reducer.fsi

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,36 @@ type internal 'result Reducer =
3535
abstract NamespaceItem: item:NamespaceItem -> 'result
3636
default NamespaceItem: item:NamespaceItem -> 'result
3737

38+
/// <summary>
39+
/// Reduces an <see cref="OpenDirective"/> node.
40+
/// </summary>
41+
abstract OpenDirective: directive:OpenDirective -> 'result
42+
default OpenDirective: directive:OpenDirective -> 'result
43+
44+
/// <summary>
45+
/// Reduces a <see cref="TypeDeclaration"/> node.
46+
/// </summary>
47+
abstract TypeDeclaration: declaration:TypeDeclaration -> 'result
48+
default TypeDeclaration: declaration:TypeDeclaration -> 'result
49+
3850
/// <summary>
3951
/// Reduces an <see cref="Attribute"/> node.
4052
/// </summary>
4153
abstract Attribute: attribute:Attribute -> 'result
4254
default Attribute: attribute:Attribute -> 'result
4355

56+
/// <summary>
57+
/// Reduces an <see cref="UnderlyingType"/> node.
58+
/// </summary>
59+
abstract UnderlyingType: underlying:UnderlyingType -> 'result
60+
default UnderlyingType: underlying:UnderlyingType -> 'result
61+
62+
/// <summary>
63+
/// Reduces a <see cref="TypeTupleItem"/> node.
64+
/// </summary>
65+
abstract TypeTupleItem: item:TypeTupleItem -> 'result
66+
default TypeTupleItem: item:TypeTupleItem -> 'result
67+
4468
/// <summary>
4569
/// Reduces a <see cref="CallableDeclaration"/> node.
4670
/// </summary>

0 commit comments

Comments
 (0)