Private/ConvertFrom-SchemaText.ps1
function ConvertFrom-SchemaText { param( [Parameter(Mandatory)] [String] $Schema ) # Schema Nodes $nodes = @() <# 0 : plain 1 : substitution 2 : operation name 3 : operation parameters #> $mode = 0 # for mode 0 : plain text $plain = "" # for mode 1 : substitution variable name $variable = "" $failoverVariable = $false $operationGroups = [System.Collections.Generic.List[OperationGroup]]::new() # for mode 2 : operation group $operations = @() $operation = "" $failoverGroup = $false # 0 unspecified, 1 conjunctive, 2 disjunctive $groupType = 0 $parameters = @() # for mode 3 : parameter $parameter = "" foreach ($char in $Schema.ToCharArray()) { switch ($mode) { 0 { switch ($char) { # A) We switch from plain text matching to substitution variable matching upon encountering { '{' { if ($plain -ne "") { # Save $nodes += [Plain]::new($plain) # Reset $plain = "" } # Switch $mode = 1 } # B) We construct plain text in this mode default { $plain += $char } } } 1 { switch ($char) { # A) We discard whitespaces with a warning in substitution variable matching ' ' { Write-Warning -Message "Skipping whitespace in variable matching." continue } # B) We mark the substitution variable as failover, given that the question mark is the first character '?' { # Variable marked as failover if ($variable -eq "") { $failoverVariable = $true } else { Write-Error -Message "Unexpected question mark in schema string." } } # C) We switch to operation groups matching upon encountering ( '(' { $mode = 2 } # D) We switch back to plain text matching upon closing the substition variable with a } '}' { # Save $nodes += [Variable]::new( $failoverVariable, $variable, $operationGroups.ToArray() ) # Reset $failoverVariable = $false $variable = "" $operationGroups = [System.Collections.Generic.List[OperationGroup]]::new() # Switch $mode = 0 } # E) We construct the variable name default { $variable += $char } } } 2 { switch ($char) { # A) We mark the first operation in the group as failover or delimit multiple operations when encountering a ? '?' { # Starting operation marked as failover if ($operation -eq "") { $failoverGroup = $true } else { Write-Error -Message "Unexpected question mark in schema string." } } '|' { if ($groupType -eq 0 -or $groupType -eq 2) { # Save $groupType = 2 $operations += [OperationFactory]::GetOperation( $operation, $parameters ) # Reset $operation = "" $parameters = @() } else { Write-Error -Message "Mixed disjunctive group with conjunctive group." } } '&' { if ($groupType -eq 0 -or $groupType -eq 1) { # Save $groupType = 1 $operations += [OperationFactory]::GetOperation( $operation, $parameters ) # Reset $operation = "" $parameters = @() } else { Write-Error -Message "Mixed conjunctive group with disjunctive group." } } # B) We switch to parameter matching upon encountering a [ '[' { $mode = 3 } # C) We switch back to variable matching upon closing the operation group variable with a ) ')' { # Save if ($operation -ne "") { $operations += [OperationFactory]::GetOperation( $operation, $parameters ) } switch ($groupType) { 1 { $operationGroups.Add( [OperationGroup]::new($operations, $failoverGroup, [OperationGroupType]::Conjunctive) ) } 2 { $operationGroups.Add( [OperationGroup]::new($operations, $failoverGroup, [OperationGroupType]::Disjunctive) ) } Default { $operationGroups.Add( [OperationGroup]::new($operations, $failoverGroup) ) } } # Reset $operation = "" $failoverGroup = $false $groupType = 0 $parameters = @() $operations = @() # Switch $mode = 1 } # D) We construct the operation name default { $operation += $char } } } 3 { switch ($char) { # A) We match another parameter when encountering a , ',' { # Save $parameters += $parameter # Reset $parameter = "" } # B) We switch back to operation group matching upon closing the parameters with a ] ']' { # Save $parameters += $parameter # Reset $parameter = "" # Switch $mode = 2 } # C) We construct the parameter value default { $parameter += $char } } } default { throw [System.NotImplementedException]::new() } } } if ($mode -ne 0) { Write-Error "Unexpected EOL" } elseif ($plain -ne "") { $nodes += [Plain]::new($plain) } return [Schema]::new($nodes) } |