Skip to content

Instantly share code, notes, and snippets.

@CurtHagenlocher
Last active August 31, 2021 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CurtHagenlocher/406d084f534732bbf3cd334c972ed540 to your computer and use it in GitHub Desktop.
Save CurtHagenlocher/406d084f534732bbf3cd334c972ed540 to your computer and use it in GitHub Desktop.
Given a table type and a function, returns the AST for the foldable function as JSON
(tableType as type, fn as function) =>
let
TransformNode = (x) => Record.FromList(List.Transform(Record.FieldValues(x), TransformValue), Record.FieldNames(x)),
TransformValue = (x) => if x is record then TransformRecord(x) else if x is list then TransformList(x) else x,
TransformList = (x) => List.Transform(x, TransformValue),
TransformRecord = (x) =>
if x = RowExpression.Row then [Kind="Row"]
else if x[Kind] = "Constant" then TransformConstant(x)
else TransformNode(x),
TransformConstant = (x) => if x[Value] is function and TryFunctionName(x[Value]) <> null then [Kind="Identifier", Name=TryFunctionName(x[Value])]
else if x[Value] is function then [Kind="Constant", Value="<function>", Type=TextType(Value.Type(x[Value]))]
else x & [Type=TextType(Value.Type(x[Value]))],
TryFunctionName =
let
Shared = Table.TransformColumns(Record.ToTable(#sections), {{"Value", Record.FieldNames}})[Value]{0},
Shared2 = List.RemoveItems(Record.FieldNames(#shared), Shared),
Library = Record.SelectFields(#shared, Shared2),
Functions = Table.Buffer(Table.SelectRows(Record.ToTable(Library), each try ([Value] is function) otherwise false))
in
(fn) => Table.First(Table.SelectRows(Functions, each [Value] = fn))[Name]?,
TextType = (t as type) as text =>
let
nonNullableType = Type.NonNullable(t),
TypeDescription = if Type.Is(nonNullableType, type binary) then "binary"
else if Type.Is(nonNullableType, type date) then "date"
else if Type.Is(nonNullableType, type datetime) then "datetime"
else if Type.Is(nonNullableType, type datetimezone) then "datetimezone"
else if Type.Is(nonNullableType, type duration) then "duration"
else if Type.Is(nonNullableType, type function) then "function"
else if Type.Is(nonNullableType, type list) then "list"
else if Type.Is(nonNullableType, type logical) then "logical"
else if Type.Is(nonNullableType, type none) then "none"
else if Type.Is(nonNullableType, type null) then "null"
else if Type.Is(nonNullableType, type number) then "number"
else if Type.Is(nonNullableType, type record) then "record"
else if Type.Is(nonNullableType, type table) then "table"
else if Type.Is(nonNullableType, type text) then "text"
else if Type.Is(nonNullableType, type time) then "time"
else if Type.Is(nonNullableType, type type) then "type"
else if Type.Is(nonNullableType, type action) then "action"
else if Type.Is(type anynonnull, nonNullableType) then "any"
else error "Unknown type",
TypeString = if TypeDescription = "any" then
if Type.IsNullable(t) then
"any" else "anynonnull"
else if Type.IsNullable(t) then
"nullable " & TypeDescription
else TypeDescription
in
TypeString,
MakeAst = (fn) => Text.FromBinary(Json.FromValue(TransformRecord(RowExpression.From(fn)))),
table = #table(tableType, {}),
ConstantFolding =
Table.AddColumn(
Table.View(table, [
OnAddColumns = (c) => Table.FromRows(
{List.Repeat({null}, Table.ColumnCount(table)) & {MakeAst(c{0}[Function])}},
Table.ColumnNames(table) & {"____"})]),
"____",
fn){0}[____]
in
ConstantFolding
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment