Skip to content

Commit

Permalink
Support TypeLiteral inside of method argument
Browse files Browse the repository at this point in the history
Fix #50
  • Loading branch information
MangelMaxime committed Mar 22, 2024
1 parent 3c6b535 commit eea2980
Show file tree
Hide file tree
Showing 18 changed files with 599 additions and 123 deletions.
58 changes: 55 additions & 3 deletions src/Glutinum.Converter/FsharpAST.fs
Original file line number Diff line number Diff line change
Expand Up @@ -139,23 +139,41 @@ type FSharpAccessibility =
| Private
| Protected

member this.Text =
match this with
| Public -> "public"
| Private -> "private"
| Protected -> "protected"

[<RequireQualifiedAccess>]
type FSharpAttribute =
| Text of string
/// <summary>
/// Generates <c>[&lt;Emit("$0($1...)")&gt;]</c> attribute.
/// </summary>
| EmitSelfInvoke
| Import of string * string
| ImportAll of string
/// <summary>
/// Generates <c>[&lt;Emit("$0")&gt;]</c> attribute.
/// </summary>
| EmitSelf
/// <summary>
/// Generates <c>[&lt;Import(selector, from)&gt;]</c> attribute.
/// </summary>
| Import of selector: string * from: string
/// <summary>
/// Generates <c>[&lt;ImportAll(moduleName)&gt;]</c> attribute.
/// </summary>
| ImportAll of moduleName: string
| Erase
| AllowNullLiteral
| StringEnum of Fable.Core.CaseRules
| CompiledName of string
| RequireQualifiedAccess
| EmitConstructor
| EmitMacroConstructor of text: string
| EmitMacroConstructor of className: string
| EmitIndexer
| Global
| ParamObject

type FSharpParameter =
{
Expand Down Expand Up @@ -190,6 +208,39 @@ type FSharpInterface =
Members: FSharpMember list
}

type FSharpExplicitField = { Name: string; Type: FSharpType }

type FSharpConstructor =
{
Parameters: FSharpParameter list
Attributes: FSharpAttribute list
Accessibility: FSharpAccessibility
}

static member EmptyPublic =
{
Parameters = []
Attributes = []
Accessibility = FSharpAccessibility.Public
}

static member EmptyPrivate =
{
Parameters = []
Attributes = []
Accessibility = FSharpAccessibility.Private
}

type FSharpClass =
{
Attributes: FSharpAttribute list
Name: string
TypeParameters: FSharpTypeParameter list
PrimaryConstructor: FSharpConstructor
SecondaryConstructors: FSharpConstructor list
ExplicitFields: FSharpExplicitField list
}

type FSharpMapped =
{
Name: string
Expand Down Expand Up @@ -281,5 +332,6 @@ type FSharpType =
| ResizeArray of FSharpType
| ThisType of typeName: string
| Function of FSharpFunctionType
| Class of FSharpClass

type FSharpOutFile = { Name: string; Opens: string list }
109 changes: 109 additions & 0 deletions src/Glutinum.Converter/Printer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ let private attributeToText (fsharpAttribute: FSharpAttribute) =
$"[<Emit(\"new $0.{className}($1...)\")>]"
| FSharpAttribute.ImportAll module_ -> $"[<ImportAll(\"{module_}\")>]"
| FSharpAttribute.EmitIndexer -> "[<EmitIndexer>]"
| FSharpAttribute.Global -> "[<Global>]"
| FSharpAttribute.ParamObject -> "[<ParamObject>]"
| FSharpAttribute.EmitSelf -> "[<Emit(\"$0\")>]"

let private printInlineAttribute
(printer: Printer)
Expand Down Expand Up @@ -217,6 +220,7 @@ let rec private printType (fsharpType: FSharpType) =
| FSharpType.ResizeArray arrayType -> $"ResizeArray<{printType arrayType}>"
| FSharpType.Module _
| FSharpType.Interface _
| FSharpType.Class _
| FSharpType.Unsupported _
| FSharpType.TypeAlias _
| FSharpType.Discard -> "obj"
Expand All @@ -239,6 +243,24 @@ let private printTypeParameters

printer.WriteInline(">")

module FSharpAccessibility =

let print (printer: Printer) (accessibility: FSharpAccessibility) =
match accessibility with
// We print an empty string for public like that the indentation
// matches the other accessibilities
| FSharpAccessibility.Public -> printer.Write("")
| FSharpAccessibility.Private -> printer.Write("private ")
| FSharpAccessibility.Protected -> printer.Write("protected ")

let printInline (printer: Printer) (accessibility: FSharpAccessibility) =
match accessibility with
// We print an empty string for public like that the indentation
// matches the other accessibilities
| FSharpAccessibility.Public -> printer.WriteInline("")
| FSharpAccessibility.Private -> printer.WriteInline("private ")
| FSharpAccessibility.Protected -> printer.WriteInline("protected ")

let private printInterface (printer: Printer) (interfaceInfo: FSharpInterface) =
printAttributes printer interfaceInfo.Attributes

Expand Down Expand Up @@ -390,6 +412,92 @@ let private printInterface (printer: Printer) (interfaceInfo: FSharpInterface) =

printer.Unindent

let private printPrimaryConstructor
(printer: Printer)
(constructor: FSharpConstructor)
=
printCompactAttributesAndNewLine printer constructor.Attributes

FSharpAccessibility.print printer constructor.Accessibility

printer.WriteInline($"(")
printer.Indent

constructor.Parameters
|> List.iteri (fun index p ->
if index <> 0 then
printer.WriteInline(",")

printer.NewLine

if p.IsOptional then
printer.Write("?")
else
printer.Write("") // Empty string to have the correct indentation

printer.WriteInline($"{p.Name}: {printType p.Type}")
)

printer.Unindent
printer.NewLine
printer.Write(") =")
printer.NewLine

let private printClass (printer: Printer) (classInfo: FSharpClass) =
printAttributes printer classInfo.Attributes

printer.Write($"type {classInfo.Name}")
printTypeParameters printer classInfo.TypeParameters
printer.NewLine
printer.Indent
printPrimaryConstructor printer classInfo.PrimaryConstructor
printer.NewLine

if not classInfo.SecondaryConstructors.IsEmpty then
classInfo.SecondaryConstructors
|> List.iter (fun constructor ->
printCompactAttributesAndNewLine printer constructor.Attributes
FSharpAccessibility.print printer constructor.Accessibility
printer.WriteInline($"new (")

constructor.Parameters
|> List.iteri (fun index p ->
if index <> 0 then
printer.WriteInline(", ")

if p.IsOptional then
printer.WriteInline("?")

printer.WriteInline($"{p.Name}: {printType p.Type}")
)

printer.WriteInline(") =")
printer.NewLine
printer.Indent
printer.Write($"%s{classInfo.Name}()")
printer.NewLine
printer.Unindent
printer.NewLine
)

if
classInfo.ExplicitFields.IsEmpty
&& classInfo.SecondaryConstructors.IsEmpty
then
printer.Write("class end")
printer.NewLine

if not classInfo.ExplicitFields.IsEmpty then
classInfo.ExplicitFields
|> List.iter (fun explicitField ->
printer.Write($"member val {explicitField.Name} : ")
printer.WriteInline(printType explicitField.Type)
printer.WriteInline(" = nativeOnly with get, set")
printer.NewLine
)

printer.Unindent

let private printEnum (printer: Printer) (enumInfo: FSharpEnum) =
printer.Write("[<RequireQualifiedAccess>]")
printer.NewLine
Expand Down Expand Up @@ -480,6 +588,7 @@ let rec print (printer: Printer) (fsharpTypes: FSharpType list) =
// printer.Unindent

| FSharpType.TypeAlias aliasInfo -> printTypeAlias printer aliasInfo
| FSharpType.Class classInfo -> printClass printer classInfo

| FSharpType.Mapped _
| FSharpType.Primitive _
Expand Down
Loading

0 comments on commit eea2980

Please sign in to comment.