Skip to content

Commit

Permalink
Add class properties for unions and records in declaration
Browse files Browse the repository at this point in the history
  • Loading branch information
alfonsogarciacaro committed Aug 1, 2016
1 parent dc23fd6 commit ddc7762
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 29 deletions.
9 changes: 7 additions & 2 deletions src/fable/Fable.Compiler/FSharp2Fable.Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,16 @@ module Types =
None

and makeEntity (com: IFableCompiler) (tdef: FSharpEntity) =
let makeFields (tdef: FSharpEntity) =
tdef.FSharpFields
// It's ok to use an empty context here, because we don't need to resolve generic params
|> Seq.map (fun x -> x.Name, makeType com Context.Empty x.FieldType)
|> Seq.toList
let kind =
if tdef.IsInterface then Fable.Interface
elif tdef.IsFSharpRecord then Fable.Record
elif tdef.IsFSharpUnion then Fable.Union
elif tdef.IsFSharpExceptionDeclaration then Fable.Exception
elif tdef.IsFSharpRecord then makeFields tdef |> Fable.Record
elif tdef.IsFSharpExceptionDeclaration then makeFields tdef |> Fable.Exception
elif tdef.IsFSharpModule || tdef.IsNamespace then Fable.Module
else Fable.Class (getBaseClass com tdef)
let genParams =
Expand Down
15 changes: 6 additions & 9 deletions src/fable/Fable.Compiler/FSharp2Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -739,22 +739,19 @@ let rec private transformEntityDecl
declInfo.AddIgnoredChild ent
declInfo, ctx
else
let fableEnt = com.GetEntity ent
// Unions, records and F# exceptions don't have a constructor
let cons =
if ent.IsFSharpUnion
then [makeUnionCons()]
elif ent.IsFSharpRecord || ent.IsFSharpExceptionDeclaration
then ent.FSharpFields
|> Seq.map (fun x -> (x.Name, makeType com ctx x.FieldType)) |> Seq.toList
|> makeRecordCons
|> List.singleton
else []
match fableEnt.Kind with
| Fable.Union -> [makeUnionCons()]
| Fable.Record fields
| Fable.Exception fields -> [makeRecordCons fields]
| _ -> []
let compareMeths =
// If F# union or records implement System.IComparable (in that case they
// allways implement System.Equatable too) generate Equals and CompareTo methods
// Note: F# compiler generates these methods too but see `IsIgnoredMethod`
// Note: If `ReferenceEqualityAttribute` is used, the type doesn't implement IComparable
let fableEnt = com.GetEntity ent
let fableType = Fable.DeclaredType(fableEnt, fableEnt.GenericParameters |> List.map Fable.GenericParam)
if ent.IsFSharpUnion && fableEnt.HasInterface "System.IComparable"
then makeUnionCompareMethods com fableType
Expand Down
40 changes: 27 additions & 13 deletions src/fable/Fable.Compiler/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -635,12 +635,17 @@ module Util =
args, body

let transformClass com ctx range (ent: Fable.Entity option) baseClass decls =
let declareMember range kind name args (body: Fable.Expr) typeParams hasRestParams isStatic =
let declareProperty com ctx name typ =
let typ = Babel.TypeAnnotation(typeAnnotation com ctx typ)
Babel.ClassProperty(Babel.Identifier(name), typeAnnotation=typ)
|> U2<Babel.ClassMethod,_>.Case2
let declareMethod range kind name args (body: Fable.Expr) typeParams hasRestParams isStatic =
let name, computed = sanitizeName name
let args, body, returnType, typeParams =
getMemberArgs com ctx args body typeParams hasRestParams
Babel.ClassMethod(kind, name, args, body, computed, isStatic,
?returnType=returnType, ?typeParams=typeParams, loc=range)
|> U2<_,Babel.ClassProperty>.Case1
let baseClass = baseClass |> Option.map (transformExpr com ctx)
decls
|> List.map (function
Expand All @@ -651,21 +656,30 @@ module Util =
| Fable.Method -> Babel.ClassFunction, m.Name, m.IsStatic
| Fable.Getter | Fable.Field -> Babel.ClassGetter, m.Name, m.IsStatic
| Fable.Setter -> Babel.ClassSetter, m.Name, m.IsStatic
declareMember m.Range kind name m.Arguments m.Body m.GenericParameters m.HasRestParams isStatic
declareMethod m.Range kind name m.Arguments m.Body m.GenericParameters m.HasRestParams isStatic
| Fable.ActionDeclaration _
| Fable.EntityDeclaration _ as decl ->
failwithf "Unexpected declaration in class: %A" decl)
|> List.map U2<_,Babel.ClassProperty>.Case1
|> fun meths ->
|> fun members ->
let id = ent |> Option.map (fun x -> identFromName x.Name)
let typeParams =
let typeParams, members =
match com.Options.declaration, ent with
| true, Some ent ->
ent.GenericParameters
|> List.map Babel.TypeParameter
|> Babel.TypeParameterDeclaration |> Some
| _ -> None
Babel.ClassExpression(Babel.ClassBody(meths, ?loc=range),
let typeParams =
ent.GenericParameters
|> List.map Babel.TypeParameter
|> Babel.TypeParameterDeclaration |> Some
let props =
match ent.Kind with
| Fable.Union ->
["Case", Fable.String; "Fields", Fable.Array Fable.Any]
|> List.map (fun (name, typ) -> declareProperty com ctx name typ)
| Fable.Record fields | Fable.Exception fields ->
fields |> List.map (fun (name, typ) -> declareProperty com ctx name typ)
| _ -> []
typeParams, props@members
| _ -> None, members
Babel.ClassExpression(Babel.ClassBody(members, ?loc=range),
?id=id, ?typeParams=typeParams, ?super=baseClass, ?loc=range)

let declareInterfaces (com: IBabelCompiler) ctx (ent: Fable.Entity) isClass =
Expand All @@ -676,8 +690,8 @@ module Util =
let interfaces =
match ent.Kind with
| Fable.Union -> "FSharpUnion"::ent.Interfaces
| Fable.Record -> "FSharpRecord"::ent.Interfaces
| Fable.Exception -> "FSharpException"::ent.Interfaces
| Fable.Record _ -> "FSharpRecord"::ent.Interfaces
| Fable.Exception _ -> "FSharpException"::ent.Interfaces
| _ -> ent.Interfaces
[ getCoreLibImport com ctx "Util"
typeRef com ctx ent None
Expand Down Expand Up @@ -836,7 +850,7 @@ module Util =
declareClass com ctx declareMember modIdent
ent privateName entDecls entRange baseClass true
|> List.append <| acc
| Fable.Union | Fable.Record | Fable.Exception ->
| Fable.Union | Fable.Record _ | Fable.Exception _ ->
declareClass com ctx declareMember modIdent
ent privateName entDecls entRange None false
|> List.append <| acc
Expand Down
5 changes: 3 additions & 2 deletions src/fable/Fable.Core/AST/AST.Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -526,10 +526,11 @@ type ClassMethod(kind, key, args, body, computed, ``static``,
/// ES Class Fields & Static Properties
/// https://github.com/jeffmo/es-class-fields-and-static-properties
/// e.g, class MyClass { static myStaticProp = 5; myProp /* = 10 */; }
type ClassProperty(key, value, ?loc) =
type ClassProperty(key, ?value, ?typeAnnotation, ?loc) =
inherit Node("ClassProperty", ?loc = loc)
member x.key: Identifier = key
member x.value: Expression = value
member x.value: Expression option = value
member x.typeAnnotation: TypeAnnotation option = typeAnnotation

type ClassBody(body, ?loc) =
inherit Node("ClassBody", ?loc = loc)
Expand Down
6 changes: 3 additions & 3 deletions src/fable/Fable.Core/AST/AST.Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ type Type =
(** ##Entities *)
and EntityKind =
| Module
| Class of baseClass: (string*Expr) option
| Union
| Record
| Exception
| Record of fields: (string*Type) list
| Exception of fields: (string*Type) list
| Class of baseClass: (string*Expr) option
| Interface

and Entity(kind, file, fullName, genParams, interfaces, decorators, isPublic) =
Expand Down

0 comments on commit ddc7762

Please sign in to comment.