Skip to content

Commit

Permalink
Refactor and simplification of expression AST builder
Browse files Browse the repository at this point in the history
 * Removed most recursive collections of functions
 * Removed 2 modes of parsing (recursive descent, LL2)
 * Replaced with LL2, but with similar performance to recursive descent (tests run 5ish% faster)
    * only tail recursion (except for parentheses)
    * max recursion depth = 2 with parentheses
    * better precedence processing means that inner items tend to be processed first
	* LL2 where: if a node is unable to be processed, the system can continue to process later nodes
	    * unprocessed node can lock nodes around it to prevent incorrect precedence
 * Removed 20% of code
  • Loading branch information
ShaneGH committed Feb 25, 2025
1 parent 549ca4d commit adb64c1
Show file tree
Hide file tree
Showing 14 changed files with 595 additions and 552 deletions.
11 changes: 6 additions & 5 deletions TestDynamo.GeneratedCode/Dtos.fs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
module rec TestDynamo.GeneratedCode.Dtos

// ############################################################################
// #################### Auto generated code, do not modify ####################
// ############################################################################
// ##################################################################################
// ####################### Auto generated code, do not modify #######################
// #### Build by running `dotnet run --project .\tools\Features\Features.csproj` ####
// ##################################################################################

open System
open System.Diagnostics.CodeAnalysis
Expand Down Expand Up @@ -257,7 +258,7 @@ type Capacity =
ReadCapacityUnits: Double voption
WriteCapacityUnits: Double voption }

[<ExcludeFromCodeCoverage; DynamodbType("Amazon.Runtime.ChecksumValidationStatus", false, false)>]
[<DynamodbType("Amazon.Runtime.ChecksumValidationStatus", false, false)>]
type ChecksumValidationStatus =
| NOT_VALIDATED = 0
| PENDING_RESPONSE_READ = 1
Expand Down Expand Up @@ -352,7 +353,7 @@ type ContributorInsightsSummary =
IndexName: String voption
TableName: String voption }

[<ExcludeFromCodeCoverage; DynamodbType("Amazon.Runtime.CoreChecksumAlgorithm", false, false)>]
[<DynamodbType("Amazon.Runtime.CoreChecksumAlgorithm", false, false)>]
type CoreChecksumAlgorithm =
| NONE = 0
| CRC32C = 1
Expand Down
28 changes: 16 additions & 12 deletions TestDynamo/Model/Compiler.AstNode.fs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type SyntheticAst =
and AstNode =
| Accessor of AccessorType
| ExpressionAttrValue of string
| Call of struct (string * AstNode voption)
| Call of struct (string * AstNode)
| Between of struct (AstNode * struct (AstNode * AstNode))
| BinaryOperator of struct (BinaryOpToken * struct(AstNode * AstNode))
| UnaryOperator of struct (UnaryOpToken * AstNode)
Expand All @@ -65,8 +65,7 @@ and AstNode =
| Accessor x -> x.ToString()
| Synthetic x -> x.ToString()
| ExpressionAttrValue x -> x
| Call (name, ValueNone) -> $"{name}()"
| Call (name, ValueSome node) -> $"{name}({node})"
| Call (name, node) -> $"{name}({node})"
| Between (x, (low, high)) -> $"{x} BETWEEN {low} AND {high}"
| BinaryOperator (Multi Comma, (l, r)) -> $"{l}, {r}"
| BinaryOperator (token, (l, r)) -> $"{l} {token} {r}"
Expand Down Expand Up @@ -124,8 +123,8 @@ type ParserSettings =
module AstNode =

[<ExcludeFromCodeCoverage>]
let inline private addAcc struct (f, ast) acc = struct (f, acc, ast)

let inline private addAcc struct (f, ast) acc = struct (f, acc, ast)
/// <summary>
/// Apply function with an accumulator to each node in the tree
/// If the function returns None, do not process any more children
Expand All @@ -138,7 +137,6 @@ module AstNode =

// no children
| f, (AstNode.EmptyParenthesis & head, depth)::tail, acc
| f, (AstNode.Call (_, ValueNone) & head, depth)::tail, acc
| f, (AstNode.ExpressionAttrValue _ & head, depth)::tail, acc
| f, (AstNode.Synthetic (AccessorPath _) & head, depth)::tail, acc
| f, (AstNode.Accessor (AccessorType.ExpressionAttrName _) & head, depth)::tail, acc
Expand All @@ -150,7 +148,7 @@ module AstNode =
| ValueSome acc' -> find struct (f, tail, acc')

// 1 child
| f, (AstNode.Call (_, ValueSome next) & head, depth)::tail, acc
| f, (AstNode.Call (_, next) & head, depth)::tail, acc
| f, (AstNode.Update (_, next) & head, depth)::tail, acc
| f, (AstNode.Synthetic (IndividualRemoveUpdate next) & head, depth)::tail, acc
| f, (AstNode.Synthetic (Projections next) & head, depth)::tail, acc
Expand Down Expand Up @@ -206,12 +204,18 @@ module AstNode =
| [] -> ValueNone
| head::tail -> struct (head, tail) |> toCsv' |> ValueSome

let rec private expand' xs =
Collection.foldBackL (fun s -> function
| BinaryOperator (Multi Comma, (l, r)) -> expand' [l] @ expand' [r] @ s
| x -> x::s) [] xs
let rec private expandIntoMutableList (list: MList<_>) xs =
for x in xs do
match x with
| BinaryOperator (Multi Comma, (l, r)) ->
expandIntoMutableList list [l]
expandIntoMutableList list [r]
| x -> list.Add(x)

/// <summary>
/// Recursively expand a csv node
/// </summary>
let expand x = expand' [x]
let expand x =
let l = MList()
expandIntoMutableList l [x]
List.ofSeq l
4 changes: 2 additions & 2 deletions TestDynamo/Model/Compiler.AstOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ module Updates =

let private asSynthetic = function
| AstNode.BinaryOperator (Single WhiteSpace, (l, r) & lr) -> IndividualAddUpdate lr |> Ok
| _ -> invalid1
| x -> invalid1

let compiler =
AggregatedUpdate.compiler (ValueSome Add) asSynthetic
Expand All @@ -631,7 +631,7 @@ module Updates =
function
| ResolvedPath path & x when ValidatedPath.length path = 1 -> Resolved x |> Ok
| ResolvedPath _ & x -> notARootAttribute
| _ -> invalid2
| x -> invalid2

let private validateRhs = function
| ResolvedPath _
Expand Down
19 changes: 9 additions & 10 deletions TestDynamo/Model/Compiler.ExpressionCompiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,18 @@ module ExpressionCompiler =
static member reader x = x.asReader

module private Build =
let private expandOpt = ValueOption.map AstNode.expand >> ValueOption.defaultValue []


let private compilePart = ExpressionPartCompiler.compile
let rec private generateCode' (compiler: MutableContainer<ExpressionCompilers>): AstCompiler =
function
| AstNode.Call ("size", args) -> compilePart (expandOpt args) compiler.value.size
| AstNode.Call ("contains", args) -> compilePart (expandOpt args) compiler.value.contains
| AstNode.Call ("begins_with", args) -> compilePart (expandOpt args) compiler.value.begins_with
| AstNode.Call ("list_append", args) -> compilePart (expandOpt args) compiler.value.list_append
| AstNode.Call ("if_not_exists", args) -> compilePart (expandOpt args) compiler.value.if_not_exists
| AstNode.Call ("attribute_type", args) -> compilePart (expandOpt args) compiler.value.attribute_type
| AstNode.Call ("attribute_exists", args) -> compilePart (expandOpt args) compiler.value.attribute_exists
| AstNode.Call ("attribute_not_exists", args) -> compilePart (expandOpt args) compiler.value.attribute_not_exists
| AstNode.Call ("size", args) -> compilePart (AstNode.expand args) compiler.value.size
| AstNode.Call ("contains", args) -> compilePart (AstNode.expand args) compiler.value.contains
| AstNode.Call ("begins_with", args) -> compilePart (AstNode.expand args) compiler.value.begins_with
| AstNode.Call ("list_append", args) -> compilePart (AstNode.expand args) compiler.value.list_append
| AstNode.Call ("if_not_exists", args) -> compilePart (AstNode.expand args) compiler.value.if_not_exists
| AstNode.Call ("attribute_type", args) -> compilePart (AstNode.expand args) compiler.value.attribute_type
| AstNode.Call ("attribute_exists", args) -> compilePart (AstNode.expand args) compiler.value.attribute_exists
| AstNode.Call ("attribute_not_exists", args) -> compilePart (AstNode.expand args) compiler.value.attribute_not_exists
| AstNode.Call (name, _) -> compiler.value.invalidFunction name
| AstNode.Update (Add, updates) -> compilePart (AstNode.expand updates) compiler.value.add
| AstNode.Update (Delete, updates) -> compilePart (AstNode.expand updates) compiler.value.delete
Expand Down
Loading

0 comments on commit adb64c1

Please sign in to comment.