Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
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
7 changes: 6 additions & 1 deletion src/QsFmt/Formatter.Tests/Examples.fs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ return x + 1;

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

"""namespace Foo {
newtype InternalType = Unit;
function Bar() : Int {
let x = 5;
return x;
Expand All @@ -60,6 +61,8 @@ let ``Adds newlines and indents`` =
[<Example(ExampleKind.Format)>]
let ``Removes extraneous spaces`` =
"""namespace Foo {
open qualified.name as qn;
internal newtype Complex = (Real: Double, Imaginary : Double);
function Bar() : Int [ ] {
let x= // Newlines are preserved.
(7 * 1) // Comments too.
Expand All @@ -70,6 +73,8 @@ let ``Removes extraneous spaces`` =
}""",

"""namespace Foo {
open qualified.name as qn;
internal newtype Complex = (Real: Double, Imaginary : Double);
function Bar() : Int [ ] {
let x = // Newlines are preserved.
(7 * 1) // Comments too.
Expand Down
102 changes: 86 additions & 16 deletions src/QsFmt/Formatter/ParseTree/Namespace.fs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,50 @@ type CallableBodyVisitor(tokens) =
}
|> Specializations

type UnderlyingTypeVistor(tokens) =
inherit QSharpParserBaseVisitor<UnderlyingType>()

let typeVisitor = TypeVisitor tokens

override _.DefaultResult = failwith "Unknown underlying type."

override visitor.VisitTupleUnderlyingType context =
context.typeDeclarationTuple () |> visitor.Visit

override _.VisitUnnamedTypeItem context =
context.``type`` () |> typeVisitor.Visit |> Type

override _.VisitTypeDeclarationTuple context =
let parameters = context._items |> Seq.map (TypeTupleItemVistor tokens).Visit
let commas = context._commas |> Seq.map (Node.toTerminal tokens)

{
OpenParen = context.openParen |> Node.toTerminal tokens
Items = Node.tupleItems parameters commas
CloseParen = context.closeParen |> Node.toTerminal tokens
}
|> TypeDeclarationTuple

and TypeTupleItemVistor(tokens) =
inherit QSharpParserBaseVisitor<TypeTupleItem>()

let typeVisitor = TypeVisitor tokens
let underlyingTypeVistor = UnderlyingTypeVistor tokens

override _.DefaultResult = failwith "Unknown type tuple item."

override visitor.VisitNamedTypeItem context = context.namedItem () |> visitor.Visit

override _.VisitUnderlyingTypeItem context =
context.underlyingType () |> underlyingTypeVistor.Visit |> UnderlyingType

override _.VisitNamedItem context =
{
Name = context.name |> Node.toTerminal tokens
Type = { Colon = context.colon |> Node.toTerminal tokens; Type = context.itemType |> typeVisitor.Visit }
}
|> TypeBinding

/// <summary>
/// Creates syntax tree <see cref="NamespaceItem"/> nodes from a parse tree and the list of tokens.
/// </summary>
Expand All @@ -141,30 +185,56 @@ type NamespaceItemVisitor(tokens) =
let parameterVisitor = ParameterVisitor tokens
let typeVisitor = TypeVisitor tokens
let callableBodyVisitor = CallableBodyVisitor tokens
let underlyingTypeVistor = UnderlyingTypeVistor tokens

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

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

override _.VisitCallableElement context =
override visitor.VisitOpenElement context =
context.openDirective () |> visitor.Visit

override visitor.VisitTypeElement context =
context.typeDeclaration () |> visitor.Visit

override visitor.VisitCallableElement context =
context.callableDeclaration () |> visitor.Visit

override _.VisitOpenDirective context =
{
Attributes =
context.callable.prefix._attributes |> Seq.map (NamespaceContext.toAttribute tokens) |> Seq.toList
Access = context.callable.prefix.access () |> Option.ofObj |> Option.map (Node.toUnknown tokens)
CallableKeyword = context.callable.keyword |> Node.toTerminal tokens
Name = context.callable.name |> Node.toTerminal tokens
OpenKeyword = context.``open`` |> Node.toTerminal tokens
OpenName = context.openName |> Node.toUnknown tokens
AsKeyword = context.``as`` |> Option.ofObj |> Option.map (Node.toTerminal tokens)
AsName = context.asName |> Option.ofObj |> Option.map (Node.toUnknown tokens)
Semicolon = context.semicolon |> Node.toTerminal tokens
}
|> OpenDirective

override _.VisitTypeDeclaration context =
{
Attributes = context.prefix._attributes |> Seq.map (NamespaceContext.toAttribute tokens) |> Seq.toList
Access = context.prefix.access () |> Option.ofObj |> Option.map (Node.toUnknown tokens)
NewtypeKeyword = context.keyword |> Node.toTerminal tokens
DeclaredType = context.declared |> Node.toTerminal tokens
Equals = context.equals |> Node.toTerminal tokens
UnderlyingType = context.underlying |> underlyingTypeVistor.Visit
Semicolon = context.semicolon |> Node.toTerminal tokens
}
|> TypeDeclaration

override _.VisitCallableDeclaration context =
{
Attributes = context.prefix._attributes |> Seq.map (NamespaceContext.toAttribute tokens) |> Seq.toList
Access = context.prefix.access () |> Option.ofObj |> Option.map (Node.toUnknown tokens)
CallableKeyword = context.keyword |> Node.toTerminal tokens
Name = context.name |> Node.toTerminal tokens
TypeParameters =
Option.ofObj context.callable.typeParameters
|> Option.map (NamespaceContext.toTypeParameterBinding tokens)
Parameters = parameterVisitor.Visit context.callable.tuple
Option.ofObj context.typeParameters |> Option.map (NamespaceContext.toTypeParameterBinding tokens)
Parameters = parameterVisitor.Visit context.tuple
ReturnType =
{
Colon = context.callable.colon |> Node.toTerminal tokens
Type = typeVisitor.Visit context.callable.returnType
}
CharacteristicSection =
Option.ofObj context.callable.returnChar |> Option.map (toCharacteristicSection tokens)
Body = callableBodyVisitor.Visit context.callable.body
{ Colon = context.colon |> Node.toTerminal tokens; Type = typeVisitor.Visit context.returnType }
CharacteristicSection = Option.ofObj context.returnChar |> Option.map (toCharacteristicSection tokens)
Body = callableBodyVisitor.Visit context.body
}
|> CallableDeclaration

Expand Down
39 changes: 39 additions & 0 deletions src/QsFmt/Formatter/SyntaxTree/Namespace.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@ type SpecializationGenerator =

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

type OpenDirective =
{
OpenKeyword: Terminal
OpenName: Terminal
AsKeyword: Terminal option
AsName: Terminal option
Semicolon: Terminal
}

type internal UnderlyingType =
| TypeDeclarationTuple of TypeTupleItem Tuple
| Type of Type

and internal TypeTupleItem =
| TypeBinding of ParameterDeclaration
| UnderlyingType of UnderlyingType

type TypeDeclaration =
{
Attributes: Attribute list
Access: Terminal option
NewtypeKeyword: Terminal
DeclaredType: Terminal
Equals: Terminal
UnderlyingType: UnderlyingType
Semicolon: Terminal
}

type CallableBody =
| Statements of Statement Block
| Specializations of Specialization Block
Expand All @@ -40,12 +68,23 @@ type CallableDeclaration =
}

type NamespaceItem =
| OpenDirective of OpenDirective
| TypeDeclaration of TypeDeclaration
| CallableDeclaration of CallableDeclaration
| Unknown of Terminal

module NamespaceItem =
let mapPrefix mapper =
function
| OpenDirective openDirective ->
{ openDirective with OpenKeyword = Terminal.mapPrefix mapper openDirective.OpenKeyword }
|> OpenDirective
| TypeDeclaration declaration ->
match declaration.Attributes, declaration.Access with
| head :: tail, _ -> { declaration with Attributes = Attribute.mapPrefix mapper head :: tail }
| [], Some access -> { declaration with Access = Terminal.mapPrefix mapper access |> Some }
| [], None -> { declaration with NewtypeKeyword = Terminal.mapPrefix mapper declaration.NewtypeKeyword }
|> TypeDeclaration
| CallableDeclaration callable ->
{ callable with
CallableKeyword = Terminal.mapPrefix mapper callable.CallableKeyword
Expand Down
74 changes: 74 additions & 0 deletions src/QsFmt/Formatter/SyntaxTree/Namespace.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,74 @@ type internal Specialization =
Generator: SpecializationGenerator
}

/// An open directive
type internal OpenDirective =
{
/// <summary>
/// The <c>open</c> keyword.
/// </summary>
OpenKeyword: Terminal

/// The name of the opened namespace.
OpenName: Terminal

/// <summary>
/// The optional <c>as</c> keyword.
/// </summary>
AsKeyword: Terminal option

/// The alias name of the opened namespace.
AsName: Terminal option

/// The semicolon.
Semicolon: Terminal
}

/// The underlying type of a newly defined type.
type internal UnderlyingType =
/// A tuple of type items.
| TypeDeclarationTuple of TypeTupleItem Tuple

/// A simple type.
| Type of Type

/// An item used in type declaration.
and internal TypeTupleItem =
/// A named type item.
| TypeBinding of ParameterDeclaration

/// An anonymous type item.
| UnderlyingType of UnderlyingType

/// A type declaration
type internal TypeDeclaration =
{
/// The attributes attached to the type declaration.
Attributes: Attribute list

/// The access modifier for the callable.
Access: Terminal option

/// <summary>
/// The <c>newtype</c> keyword.
/// </summary>
NewtypeKeyword: Terminal

/// The name of the declared type.
DeclaredType: Terminal

/// <summary>
/// The <c>=</c> symbol.
/// </summary>
Equals: Terminal

/// The underlying type.
UnderlyingType: UnderlyingType

/// The semicolon.
Semicolon: Terminal
}

/// The body of a callable declaration.
type internal CallableBody =
/// An implicit body specialization with statements.
Expand Down Expand Up @@ -88,6 +156,12 @@ type internal CallableDeclaration =

/// An item in a namespace.
type internal NamespaceItem =
/// An open directive
| OpenDirective of OpenDirective

/// A type declaration
| TypeDeclaration of TypeDeclaration

/// A callable declaration
| CallableDeclaration of CallableDeclaration

Expand Down
39 changes: 39 additions & 0 deletions src/QsFmt/Formatter/SyntaxTree/Reducer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,53 @@ type internal 'result Reducer() as reducer =

default _.NamespaceItem item =
match item with
| OpenDirective directive -> reducer.OpenDirective directive
| TypeDeclaration delcaration -> reducer.TypeDeclaration delcaration
| CallableDeclaration callable -> reducer.CallableDeclaration callable
| Unknown terminal -> reducer.Terminal terminal

abstract OpenDirective : directive: OpenDirective -> 'result

default _.OpenDirective directive =
[ reducer.Terminal directive.OpenKeyword; reducer.Terminal directive.OpenName ]
@ (directive.AsKeyword |> Option.map reducer.Terminal |> Option.toList)
@ (directive.AsName |> Option.map reducer.Terminal |> Option.toList)
@ [ reducer.Terminal directive.Semicolon ]
|> reduce

abstract TypeDeclaration : declaration: TypeDeclaration -> 'result

default _.TypeDeclaration declaration =
(declaration.Attributes |> List.map reducer.Attribute)
@ (declaration.Access |> Option.map reducer.Terminal |> Option.toList)
@ [
reducer.Terminal declaration.NewtypeKeyword
reducer.Terminal declaration.DeclaredType
reducer.Terminal declaration.Equals
reducer.UnderlyingType declaration.UnderlyingType
reducer.Terminal declaration.Semicolon
]
|> reduce

abstract Attribute : attribute: Attribute -> 'result

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

abstract UnderlyingType : underlying: UnderlyingType -> 'result

default _.UnderlyingType underlying =
match underlying with
| TypeDeclarationTuple tuple -> reducer.Tuple(reducer.TypeTupleItem, tuple)
| Type _type -> reducer.Type _type

abstract TypeTupleItem : item: TypeTupleItem -> 'result

default _.TypeTupleItem item =
match item with
| TypeBinding binding -> reducer.ParameterDeclaration binding
| UnderlyingType underlying -> reducer.UnderlyingType underlying

abstract CallableDeclaration : callable: CallableDeclaration -> 'result

default _.CallableDeclaration callable =
Expand Down
24 changes: 24 additions & 0 deletions src/QsFmt/Formatter/SyntaxTree/Reducer.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,36 @@ type internal 'result Reducer =
abstract NamespaceItem: item:NamespaceItem -> 'result
default NamespaceItem: item:NamespaceItem -> 'result

/// <summary>
/// Reduces an <see cref="OpenDirective"/> node.
/// </summary>
abstract OpenDirective: directive:OpenDirective -> 'result
default OpenDirective: directive:OpenDirective -> 'result

/// <summary>
/// Reduces a <see cref="TypeDeclaration"/> node.
/// </summary>
abstract TypeDeclaration: declaration:TypeDeclaration -> 'result
default TypeDeclaration: declaration:TypeDeclaration -> 'result

/// <summary>
/// Reduces an <see cref="Attribute"/> node.
/// </summary>
abstract Attribute: attribute:Attribute -> 'result
default Attribute: attribute:Attribute -> 'result

/// <summary>
/// Reduces an <see cref="UnderlyingType"/> node.
/// </summary>
abstract UnderlyingType: underlying:UnderlyingType -> 'result
default UnderlyingType: underlying:UnderlyingType -> 'result

/// <summary>
/// Reduces a <see cref="TypeTupleItem"/> node.
/// </summary>
abstract TypeTupleItem: item:TypeTupleItem -> 'result
default TypeTupleItem: item:TypeTupleItem -> 'result

/// <summary>
/// Reduces a <see cref="CallableDeclaration"/> node.
/// </summary>
Expand Down
Loading