Last active
September 14, 2019 22:24
-
-
Save jca02266/5d0363d752a5282f459a to your computer and use it in GitHub Desktop.
powershellでパーサコンビネータ ref: https://qiita.com/jca02266/items/b7e1dc21d8d537827290
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$x = $target[0..(0+4-1)] | |
$y = $target[4..(4+3-1)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
& seq (setvar x (tokenN 4)) ` | |
(setvar y (tokenN 3)) ` | |
$target 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$target | | |
setvar x (tokenN 4) | | |
setvar y (tokenN 3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function token { | |
Param($str) | |
$len = $str.Length | |
return { | |
Param($target, $position) | |
if ($target.Length -ge ($position + $len) -and $target.Substring($position, $len) -eq $str) { | |
return @($true, $str, ($position + $len)) | |
} else { | |
return @($false, "", $position) | |
} | |
}.GetNewClosure() | |
} | |
# & (token 'foobar') 'foobar' 0 # => (True, 'foobar', 6) | |
# & (token 'foobar') 'foobar' 1 # => (False, '', 1) | |
function many { | |
Param($parser) | |
return { | |
Param($target, $position) | |
$result = [Collections.ArrayList]@() | |
for (;;) { | |
$parsed = & $parser $target $position | |
if ($parsed[0]) { | |
$result.Add($parsed[1]) | Out-Null | |
$position = $parsed[2] | |
} else { | |
break | |
} | |
} | |
return ($True, (-join $result), $position) | |
}.GetNewClosure() | |
} | |
# & (many (token 'hoge')) 'hogehoge' 0 # => (True, ('hoge', 'hoge'), 8) | |
# & (many (token 'hoge')) '' 0 # => (True, '', 0) | |
function choice { | |
$parsers = $args | |
return { | |
Param($target, $position) | |
for ($i = 0; $i -lt $parsers.Length; $i++) { | |
$parsed = & $parsers[$i] $target $position | |
if ($parsed[0]) { | |
return $parsed | |
} | |
} | |
return ($false, '', $position) | |
}.GetNewClosure() | |
} | |
# $parse = many (choice (token 'hoge') (token 'fuga')) | |
# | |
# & $parse '' 0 # => (True, '', 0) | |
# & $parse 'hogehoge' 0 # => (True, ('hoge', 'hoge'), 8) | |
# & $parse 'fugahoge' 0 # => (True, ('fuga', 'hoge'), 8) | |
# & $parse 'fugafoo' 0 # => (True, 'fuga', 4) | |
function seq { | |
$parsers = $args | |
return { | |
Param($target, $position) | |
$result = [Collections.ArrayList]@() | |
for ($i = 0; $i -lt $parsers.Length; $i++) { | |
$parsed = & $parsers[$i] $target $position | |
if ($parsed[0]) { | |
$result.Add($parsed[1]) | Out-Null | |
$position = $parsed[2] | |
} else { | |
return @($false, '', $position) | |
} | |
} | |
return @($true, (-join $result), $position) | |
}.GetNewClosure() | |
} | |
# $parse = seq (token 'foo') (choice (token 'bar') (token 'baz')) | |
# | |
# & $parse 'foobar' 0 # => (True, ('foo', 'bar'), 6) | |
# & $parse 'foobaz' 0 # => (True, ('foo', 'baz'), 6) | |
# & $parse 'foo' 0 # => (False, '', 3) | |
function option { | |
Param($parser) | |
return { | |
Param($target, $position) | |
$result = & $parser $target $position | |
if ($result[0]) { | |
return $result; | |
} else { | |
return ($true, '', $position) | |
} | |
}.GetNewClosure() | |
} | |
# $parser = option (token 'hoge') | |
# | |
# & $parser 'hoge' 0 # => (True, 'hoge', 4) | |
# & $parser 'fuga' 0 # => (True, '', 0) | |
function regex { | |
Param($regexp) | |
if ($regexp -is [String]) { | |
$regexp = New-Object Regex ($regexp) | |
} | |
if (! $regexp.ToString().StartsWith("\G")) { | |
$regexp = New-Object Regex (("\G" + $regexp.ToString()), $regexp.Options) | |
} | |
return { | |
Param($target, $position) | |
$regexResult = $regexp.Match($target, $position) | |
if ($regexResult.Success) { | |
$position += $regexResult.Length; | |
return ($true, $regexResult.Value, $position) | |
} else { | |
return ($false, "", $position) | |
} | |
}.GetNewClosure() | |
} | |
# $parser = regex "hoge" | |
# | |
# & $parser 'hoge' 0 # => [true, 'hoge', 4]を返す | |
# $parser = regex ([regex]"([1-9][0-9]*)") | |
# | |
# & $parser '2014' 0 # => (True, '2014', 4) | |
# & $parser '01' 0 # => (False, '', 0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
& { | |
$foo = "FOO" | |
$bar = { | |
Write-Warning $foo | |
}.GetNewClosure() | |
$foo = "BAR" | |
& $bar | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment