Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a5ebe8b
[Python/Beam] Add F# quotation support with construction, pattern mat…
dbrattli Mar 14, 2026
755b9c8
Fix Beam quotation tests: dereference array Refs in evaluate and patt…
dbrattli Mar 14, 2026
1302734
Fix is_new_tuple to return FSharpList matching .NET quotation API
dbrattli Mar 14, 2026
0a8f667
Fix interpolated string warnings in QuotationEmitter.fs
dbrattli Mar 14, 2026
d93a06e
Fix standalone build and Python type annotations
dbrattli Mar 14, 2026
264be9f
Add FSharpExpr instance methods: GetFreeVars, Substitute, expr_to_string
dbrattli Mar 14, 2026
19f1b14
Fix get_free_vars return type to Array[Var] for IEnumerable compatibi…
dbrattli Mar 14, 2026
cf93b98
Add list.pyi stub and remove pyright ignore comment
dbrattli Mar 14, 2026
b75b7b4
Merge branch 'main' into dbrattli/quoted
dbrattli Apr 2, 2026
25d80ce
Extract shared quotation replacements to Replacements.Util.fs
dbrattli Apr 2, 2026
a67e1ea
Merge branch 'main' into dbrattli/quoted
dbrattli Apr 4, 2026
371052e
Align quotation function names with JS PR #4474
dbrattli Apr 4, 2026
90545bf
Use camelCase for all quotation library names in compiler
dbrattli Apr 4, 2026
0293324
Rename quotation module to "quotation" across all targets
dbrattli Apr 4, 2026
0cb164c
Revert CLAUDE.md change (--skip-fable-library no longer exists)
dbrattli Apr 4, 2026
66dce9c
Add source location to Quote AST node
dbrattli Apr 4, 2026
595a642
Merge branch 'main' into dbrattli/quoted
dbrattli Apr 6, 2026
234c682
chore: Fixup changelog merge
dbrattli Apr 6, 2026
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
3 changes: 3 additions & 0 deletions src/Fable.AST/Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -836,11 +836,13 @@ type Expr =

| Unresolved of expr: UnresolvedExpr * typ: Type * range: SourceLocation option
| Extended of expr: ExtendedSet * range: SourceLocation option
| Quote of quotedExpr: Expr * isTyped: bool * range: SourceLocation option

member this.Type =
match this with
| Unresolved(_, t, _) -> t
| Extended(kind, _) -> kind.Type
| Quote _ -> Any
| Test _ -> Boolean
| Value(kind, _) -> kind.Type
| IdentExpr id -> id.Type
Expand Down Expand Up @@ -892,6 +894,7 @@ type Expr =
| Set(_, _, _, _, r)
| ForLoop(_, _, _, _, _, r)
| WhileLoop(_, _, r) -> r
| Quote(_, _, r) -> r

// module PrettyPrint =
// let rec printType (t: Type) = "T" // TODO
Expand Down
1 change: 1 addition & 0 deletions src/Fable.Cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* [Python/Beam] Add F# quotation support — construction, pattern matching, and evaluation via `LeafExpressionConverter.EvaluateQuotation` (by @dbrattli)
* [All] Add support for `Guid.CreateVersion7()` and `Guid.CreateVersion7(DateTimeOffset)` (by @OnurGumus)
* [All] Add missing `Array`, `List`, and `Seq` random choice/shuffle/sample members and tests (by @ncave)
* [Dart/Rust] Add missing `System.Random` implementations and tests (by @ncave)
Expand Down
1 change: 1 addition & 0 deletions src/Fable.Compiler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* [Python/Beam] Add F# quotation support — construction, pattern matching, and evaluation via `LeafExpressionConverter.EvaluateQuotation` (by @dbrattli)
* [All] Add support for `Guid.CreateVersion7()` and `Guid.CreateVersion7(DateTimeOffset)` (by @OnurGumus)
* [All] Add missing `Array`, `List`, and `Seq` random choice/shuffle/sample members and tests (by @ncave)
* [Dart/Rust] Add missing `System.Random` implementations and tests (by @ncave)
Expand Down
4 changes: 4 additions & 0 deletions src/Fable.Transforms/Beam/Fable2Beam.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,10 @@ let rec transformExpr (com: IBeamCompiler) (ctx: Context) (expr: Expr) : Beam.Er
]
)

| Quote(body, _isTyped, _r) ->
let emitted = QuotationEmitter.emitQuotedExpr com body
transformExpr com ctx emitted

| Extended(kind, _range) ->
match kind with
| Throw(Some exprArg, _typ) ->
Expand Down
3 changes: 2 additions & 1 deletion src/Fable.Transforms/Beam/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5679,7 +5679,8 @@ let tryCall
| _ -> emitExpr r t [ c ] "maps:get(name, $0)" |> Some
| _ -> None
| "System.Text.StringBuilder" -> bclType com ctx r t info thisArg args
| _ -> None
// F# Quotations
| typeName -> Quotations.tryQuotationCall "quotation" com ctx r t info thisArg args typeName

let tryBaseConstructor
(_com: ICompiler)
Expand Down
4 changes: 4 additions & 0 deletions src/Fable.Transforms/Dart/Fable2Dart.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2191,6 +2191,10 @@ module Util =
],
None

| Fable.Quote _ ->
addError com [] None "Quotations are not yet supported for Dart target"
[], None

let getLocalFunctionGenericParams
(_com: IDartCompiler)
(ctx: Context)
Expand Down
11 changes: 7 additions & 4 deletions src/Fable.Transforms/FSharp2Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1456,10 +1456,11 @@ let private transformExpr (com: IFableCompiler) (ctx: Context) appliedGenArgs fs
$"Cannot compile ILFieldGet(%A{ownerTyp}, %s{fieldName})"
|> addErrorAndReturnNull com ctx.InlinePath (makeRangeFrom fsExpr)

| FSharpExprPatterns.Quote _ ->
return
"Quotes are not currently supported by Fable"
|> addErrorAndReturnNull com ctx.InlinePath (makeRangeFrom fsExpr)
| FSharpExprPatterns.Quote quotedExpr ->
let! body = transformExpr com ctx [] quotedExpr
let exprType = fsExpr.Type
let isTyped = exprType.GenericArguments.Count > 0
return Fable.Quote(body, isTyped, makeRangeFrom fsExpr)

| FSharpExprPatterns.AddressOf expr ->
let r = makeRangeFrom fsExpr
Expand Down Expand Up @@ -2475,6 +2476,8 @@ let resolveInlineExpr (com: IFableCompiler) ctx info expr =
|> makeValue r
| Fable.TypeInfo(t, d) -> Fable.TypeInfo(resolveInlineType ctx.GenericArgs t, d) |> makeValue r

| Fable.Quote(e, isTyped, r) -> Fable.Quote(resolveInlineExpr com ctx info e, isTyped, r)

| Fable.Extended(kind, r) as e ->
match kind with
| Fable.Curry(e, arity) -> Fable.Extended(Fable.Curry(resolveInlineExpr com ctx info e, arity), r)
Expand Down
1 change: 1 addition & 0 deletions src/Fable.Transforms/Fable.Transforms.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<Compile Include="Beam/Replacements.fs" />
<Compile Include="Replacements.fs" />
<Compile Include="Replacements.Api.fs" />
<Compile Include="QuotationEmitter.fs" />
<Compile Include="FSharp2Fable.fsi" />
<Compile Include="FSharp2Fable.fs" />
<Compile Include="FableTransforms.fsi" />
Expand Down
7 changes: 7 additions & 0 deletions src/Fable.Transforms/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,7 @@ module Util =
| Fable.CurriedApply _
| Fable.Operation _
| Fable.Get _
| Fable.Quote _
| Fable.Test _ -> false

| Fable.TypeCast(e, _) -> isJsStatement ctx preferStatement e
Expand Down Expand Up @@ -3141,6 +3142,8 @@ but thanks to the optimisation done below we get
| Fable.Throw _
| Fable.Debugger -> iife com ctx expr

| Fable.Quote _ -> addErrorAndReturnNull com None "Quotations are not yet supported for JS/TS target"

let rec transformAsStatements (com: IBabelCompiler) ctx returnStrategy (expr: Fable.Expr) : Statement array =
match expr with
| Fable.Unresolved(_, _, r) ->
Expand Down Expand Up @@ -3308,6 +3311,10 @@ but thanks to the optimisation done below we get
)
|]

| Fable.Quote _ ->
addError com [] None "Quotations are not yet supported for JS/TS target"
[||]

let transformFunction com ctx name (args: Fable.Ident list) (body: Fable.Expr) : Parameter array * BlockStatement =
let tailcallChance =
Option.map (fun name -> NamedTailCallOpportunity(com, ctx, name, args) :> ITailCallOpportunity) name
Expand Down
3 changes: 2 additions & 1 deletion src/Fable.Transforms/FableTransforms.fs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ let noSideEffectBeforeIdent identName expr =
findIdentOrSideEffect e
| Import _
| Lambda _
| Delegate _ -> false
| Delegate _
| Quote _ -> false
| Extended((Throw _ | Debugger), _) -> true
| Extended(Curry(e, _), _) -> findIdentOrSideEffect e
| CurriedApply(callee, args, _, _) -> callee :: args |> findIdentOrSideEffectInList |> orSideEffect
Expand Down
1 change: 1 addition & 0 deletions src/Fable.Transforms/Php/Fable2Php.fs
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,7 @@ let rec tryFindMethod methodName (phpType: PhpType) =
let rec convertExpr (com: IPhpCompiler) (expr: Fable.Expr) =
match expr with
| Fable.Extended _ -> failwith "TODO: Extended instructions"
| Fable.Quote _ -> failwith "Quotations are not yet supported for PHP target"

| Fable.Unresolved _ -> failwith "Unexpected unresolved expression"

Expand Down
7 changes: 7 additions & 0 deletions src/Fable.Transforms/Python/Fable2Python.Transforms.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2659,6 +2659,9 @@ let rec transformAsExpr (com: IPythonCompiler) ctx (expr: Fable.Expr) : Expressi
| Fable.Curry(e, arity) -> transformCurry com ctx e arity
| Fable.Throw _
| Fable.Debugger -> iife com ctx expr
| Fable.Quote(body, _isTyped, _r) ->
let emitted = QuotationEmitter.emitQuotedExpr com body
transformAsExpr com ctx emitted

let transformAsSlice (com: IPythonCompiler) ctx expr (info: Fable.CallInfo) : Expression * Statement list =
Expression.withStmts {
Expand Down Expand Up @@ -2981,6 +2984,10 @@ let rec transformAsStatements (com: IPythonCompiler) ctx returnStrategy (expr: F

[ Statement.for' (target = target, iter = iter, body = body) ]

| Fable.Quote(body, _isTyped, _r) ->
let emitted = QuotationEmitter.emitQuotedExpr com body
transformAsStatements com ctx returnStrategy emitted

let transformFunction
com
ctx
Expand Down
1 change: 1 addition & 0 deletions src/Fable.Transforms/Python/Fable2Python.Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ module Util =
| Fable.Operation _
| Fable.Get _
| Fable.Test _
| Fable.Quote _
| Fable.TypeCast _ -> false

| Fable.TryCatch _
Expand Down
3 changes: 2 additions & 1 deletion src/Fable.Transforms/Python/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4157,7 +4157,8 @@ let tryCall (com: ICompiler) (ctx: Context) r t (info: CallInfo) (thisArg: Expr
getTypeName com ctx loc exprType |> StringConstant |> makeValue r |> Some
| c -> Helper.LibCall(com, "Reflection", "name", t, [ c ], ?loc = r) |> Some
| _ -> None
| _ -> None
// F# Quotations
| typeName -> Quotations.tryQuotationCall "quotation" com ctx r t info thisArg args typeName

let tryBaseConstructor com ctx (ent: EntityRef) (argTypes: Lazy<Type list>) genArgs args =
match ent.FullName with
Expand Down
Loading
Loading