Skip to content

Instantly share code, notes, and snippets.

@jca02266
Last active September 14, 2019 22:24
Show Gist options
  • Save jca02266/5d0363d752a5282f459a to your computer and use it in GitHub Desktop.
Save jca02266/5d0363d752a5282f459a to your computer and use it in GitHub Desktop.
powershellでパーサコンビネータ ref: https://qiita.com/jca02266/items/b7e1dc21d8d537827290
$x = $target[0..(0+4-1)]
$y = $target[4..(4+3-1)]
& seq (setvar x (tokenN 4)) `
(setvar y (tokenN 3)) `
$target 0
$target |
setvar x (tokenN 4) |
setvar y (tokenN 3)
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)
& {
$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