Source/Classes/LogicalFormula.ps1
using module .\..\..\..\ObjectGraphTools using namespace System.Collections using namespace System.Collections.Generic enum LogicalOperatorEnum { not; and; or; xor } class LogicalTerm {} class LogicalOperator : LogicalTerm { hidden [LogicalOperatorEnum]$Value LogicalOperator ([LogicalOperatorEnum]$Operator) { $this.Value = $Operator } LogicalOperator ([String]$Operator) { $this.Value = [LogicalOperatorEnum]$Operator } [String]ToString() { return $this.Value } } class LogicalVariable : LogicalTerm { hidden [Object]$Value LogicalVariable ($Variable) { $this.Value = $Variable } [String]ToString() { if ($this.Value -is [String]) { return "'$($this.Value -Replace "'", "''")'" } else { return $this.Value } } } class LogicalFormula : LogicalTerm { hidden static $OperatorSymbols = @{ '!' = [LogicalOperatorEnum]'Not' ',' = [LogicalOperatorEnum]'And' '*' = [LogicalOperatorEnum]'And' '|' = [LogicalOperatorEnum]'Or' '+' = [LogicalOperatorEnum]'Or' } hidden static [Int[]]$OperatorNameLengths hidden [List[LogicalTerm]]$Terms = [List[LogicalTerm]]::new() hidden [Int]$Pointer GetFormula([String]$Expression, [Int]$Start) { $SubExpression = $Start -gt 0 $InString = $null # Quote type (double - or single quoted) $Escaped = $null $this.Pointer = $Start While ($this.Pointer -le $Expression.Length) { $Char = if ($this.Pointer -lt $Expression.Length) { $Expression[$this.Pointer] } if ($InString) { if ($Char -eq $InString) { if ($this.Pointer + 1 -lt $Expression.Length -and $Expression[$this.Pointer + 1] -eq $InString) { $Escaped = $true $this.Pointer++ } else { $Name = $Expression.SubString($Start + 1, ($this.Pointer - $Start - 1)) if ($Escaped) { $Name = $Name.Replace("$InString$InString", $InString) } $this.Terms.Add([LogicalVariable]::new($Name)) $InString = $Null $Start = $this.Pointer + 1 } } } elseif ('"', "'" -eq $Char) { $InString = $Char $Escaped = $false $Start = $this.Pointer } elseif ($Char -eq '(') { $Formula = [LogicalFormula]::new($Expression, ($this.Pointer + 1)) $this.Terms.Add($Formula) $this.Pointer = $Formula.Pointer $Start = $this.Pointer + 1 } elseif ($Char -in $Null, ' ', ')' + [LogicalFormula]::OperatorSymbols.Keys) { $Length = $this.Pointer - $Start if ($Length -gt 0) { $Term = $Expression.SubString($Start, $Length) if ([LogicalOperatorEnum].GetEnumNames() -eq $Term) { $this.Terms.Add([LogicalOperator]::new($Term)) } else { $Double = 0 if ([double]::TryParse($Term, [Ref]$Double)) { $this.Terms.Add([LogicalVariable]::new($Double)) } else { $this.Terms.Add([LogicalVariable]::new($Term)) } } } if ($Char -eq ')') { return } if ($Char -gt ' ') { $this.Terms.Add([LogicalOperator]::new([LogicalFormula]::OperatorSymbols($Char))) } $Start = $this.Pointer + 1 } # elseif ($Char -le ' ' -or $Null -eq $Char) { # A space or any control code # if ($Start -lt $this.Pointer) { # $this.Terms.Add($this.GetUnquotedTerm($Expression, $Start, ($this.Pointer - $Start))) # } # $Start = $this.Pointer + 1 # } $this.Pointer++ } if ($InString) { Throw "Missing the terminator: $InString in logical expression: $Expression" } if ($SubExpression) { Throw "Missing closing ')' in logical expression: $Expression" } } LogicalFormula ([String]$Expression) { $this.GetFormula($Expression, 0) if ($this.Pointer -lt $Expression.Length) { Throw "Unexpected token ')' at position $($this.Pointer) in logical expression: $Expression" } } LogicalFormula ([String]$Expression, $Start) { $this.GetFormula($Expression, $Start) } Append ([LogicalOperator]$Operator, [LogicalFormula]$Formula) { if ($Operator.Value -eq 'Not') { $this.Terms.Add([LogicalOperator]'And') } $this.Terms.Add($Operator) $this.Terms.AddRange($Formula.Terms) } [String] ToString() { $StringBuilder = [System.Text.StringBuilder]::new() $Stack = [System.Collections.Stack]::new() $Enumerator = $this.Terms.GetEnumerator() $Term = $null while ($true) { while ($Enumerator.MoveNext()) { if ($Null -ne $Term) { $null = $StringBuilder.Append([ANSI]::ResetColor) # Not really necessarily $null = $StringBuilder.Append(' ') } $Term = $Enumerator.Current if ($Term -is [LogicalVariable]) { if ($Term.Value -is [String]) { $null = $StringBuilder.Append([ANSI]::VariableColor) } else { $null = $StringBuilder.Append([ANSI]::NumberColor) } } elseif ($Term -is [LogicalOperator]) { $null = $StringBuilder.Append([ANSI]::OperatorColor) } else { # if ($Term -is [LogicalFormula]) $null = $StringBuilder.Append([ANSI]::StringColor) $null = $StringBuilder.Append('(') $Stack.Push($Enumerator) $Enumerator = $Term.Terms.GetEnumerator() $Term = $null continue } $null = $StringBuilder.Append($Term) } if (-not $Stack.Count) { $null = $StringBuilder.Append([ANSI]::ResetColor) break } $null = $StringBuilder.Append([ANSI]::StringColor) $null = $StringBuilder.Append(')') $Enumerator = $Stack.Pop() } return $StringBuilder.ToString() } } |