diff --git a/src/Fable.Transforms/Dart/Dart.fs b/src/Fable.Transforms/Dart/Dart.fs index b384127d13..21d0fe5731 100644 --- a/src/Fable.Transforms/Dart/Dart.fs +++ b/src/Fable.Transforms/Dart/Dart.fs @@ -36,6 +36,7 @@ type Type = | Generic of name: string | TypeReference of Ident * generics: Type list + | EmitType of value: string * generics: Type list | Function of argTypes: Type list * returnType: Type type Ident = diff --git a/src/Fable.Transforms/Dart/DartPrinter.fs b/src/Fable.Transforms/Dart/DartPrinter.fs index 24f785a5ac..a7f6f214a4 100644 --- a/src/Fable.Transforms/Dart/DartPrinter.fs +++ b/src/Fable.Transforms/Dart/DartPrinter.fs @@ -59,6 +59,33 @@ module PrinterExtensions = printer.Print(s) printSeparator |> Option.iter (fun f -> f printer) + member printer.PrintEmitType(value: string, genArgs: Type list) = + let printSegment (printer: Printer) (value: string) segmentStart segmentEnd = + let segmentLength = segmentEnd - segmentStart + if segmentLength > 0 then + let segment = value.Substring(segmentStart, segmentLength) + printer.Print(segment) + + let matches = Regex.Matches(value, @"\$\d+") + if matches.Count > 0 then + for i = 0 to matches.Count - 1 do + let m = matches[i] + let segmentStart = + if i > 0 then matches[i-1].Index + matches[i-1].Length + else 0 + + printSegment printer value segmentStart m.Index + + let argIndex = int m.Value[1..] + match List.tryItem argIndex genArgs with + | Some t -> printer.PrintType(t) + | None -> () + + let lastMatch = matches[matches.Count - 1] + printSegment printer value (lastMatch.Index + lastMatch.Length) value.Length + else + printSegment printer value 0 value.Length + // TODO: Most of this code matches BabelPrinter.PrintEmitExpression, can we refactor it? member printer.PrintEmitExpression(value: string, args: Expression list) = let inline replace pattern (f: Match -> string) input = @@ -233,6 +260,8 @@ module PrinterExtensions = | TypeReference(ref, gen) -> printer.PrintIdent(ref) printer.PrintList("<", ", ", ">", gen, printer.PrintType, skipIfEmpty=true) + | EmitType(macro, gen) -> + printer.PrintEmitType(macro, gen) | Function(argTypes, returnType) -> printer.PrintType(returnType) printer.Print(" ") diff --git a/src/Fable.Transforms/Dart/Fable2Dart.fs b/src/Fable.Transforms/Dart/Fable2Dart.fs index b375e01fdc..eb474120ba 100644 --- a/src/Fable.Transforms/Dart/Fable2Dart.fs +++ b/src/Fable.Transforms/Dart/Fable2Dart.fs @@ -162,6 +162,14 @@ module Util = let tup = List.length genArgs |> getTupleTypeIdent com ctx TypeReference(tup, transformGenArgs com ctx genArgs) + let (|EmitAttribute|_|) (ent: Fable.Entity) = + ent.Attributes |> Seq.tryPick (fun att -> + if att.Entity.FullName.StartsWith(Atts.emit) then + match att.ConstructorArgs with + | [:? string as macro] -> Some macro + | _ -> None + else None) + let transformDeclaredTypeIgnoreMeasure ignoreMeasure (com: IDartCompiler) ctx (entRef: Fable.EntityRef) genArgs = match entRef.FullName with | "System.Enum" -> Integer |> Some @@ -175,10 +183,11 @@ module Util = // We use `dynamic` for now because there doesn't seem to be a type that catches all errors in Dart | Naming.EndsWith "Exception" _ -> Dynamic |> Some | _ -> - let ent = com.GetEntity(entRef) - if ignoreMeasure && ent.IsMeasure then - None - else + match com.GetEntity(entRef) with + | ent when ignoreMeasure && ent.IsMeasure -> None + | EmitAttribute(macro) -> + EmitType(macro, transformGenArgs com ctx genArgs) |> Some + | ent -> let genArgs = transformGenArgs com ctx genArgs TypeReference(getEntityIdent com ctx ent, genArgs) |> Some @@ -2121,10 +2130,12 @@ module Util = | Fable.ClassDeclaration decl -> let entRef = decl.Entity - let ent = com.GetEntity(entRef) - if ent.IsInterface then + match com.GetEntity(entRef) with + // Ignore declaration for classes with Emit attribute + | EmitAttribute _ -> [] + | ent when ent.IsInterface -> transformInterfaceDeclaration com ctx decl ent - else + | ent -> let instanceMethods = decl.AttachedMembers |> List.choose (fun memb -> match memb.Name with