2016-08-20 23:09:19 +03:00
|
|
|
Import-Module $PSScriptRoot/types.psm1
|
|
|
|
|
|
|
|
Class Reader {
|
|
|
|
[String[]] $tokens
|
|
|
|
[int] $pos
|
|
|
|
|
|
|
|
Reader([String[]] $toks) {
|
|
|
|
$this.tokens = $toks
|
|
|
|
$this.pos = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
[String] peek() {
|
|
|
|
return $this.tokens[$this.pos]
|
|
|
|
}
|
|
|
|
|
|
|
|
[String] next() {
|
|
|
|
return $this.tokens[$this.pos++]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function tokenize {
|
|
|
|
$r = [regex]"[\s,]*(~@|[\[\]{}()'``~^@]|`"(?:\\.|[^\\`"])*`"|;.*|[^\s\[\]{}('`"``,;)]*)"
|
|
|
|
$r.Matches($args) |
|
2016-08-22 01:14:01 +03:00
|
|
|
Where-Object { $_.Groups.Item(1).Value.Length -gt 0 -and
|
|
|
|
$_.Groups.Item(1).Value[0] -ne ";" } |
|
2016-08-20 23:09:19 +03:00
|
|
|
Foreach-Object { $_.Groups.Item(1).Value }
|
|
|
|
}
|
|
|
|
|
|
|
|
function read_atom([Reader] $rdr) {
|
|
|
|
$token = $rdr.next()
|
|
|
|
if ($token -match "^-?[0-9]+$") {
|
|
|
|
return [convert]::ToInt32($token, 10)
|
|
|
|
} elseif ($token -match "^`".*`"") {
|
2016-08-22 01:14:01 +03:00
|
|
|
$s = $token.Substring(1,$token.Length-2)
|
2017-09-26 23:31:50 +03:00
|
|
|
$s = $s -replace "\\\\", "$([char]0x29e)"
|
2016-08-22 01:14:01 +03:00
|
|
|
$s = $s -replace "\\`"", "`""
|
|
|
|
$s = $s -replace "\\n", "`n"
|
2017-09-26 23:31:50 +03:00
|
|
|
$s = $s -replace "$([char]0x29e)", "\"
|
2016-08-22 01:14:01 +03:00
|
|
|
return $s
|
|
|
|
} elseif ($token -match ":.*") {
|
|
|
|
return "$([char]0x29e)$($token.substring(1))"
|
|
|
|
} elseif ($token -eq "true") {
|
|
|
|
return $true
|
|
|
|
} elseif ($token -eq "false") {
|
|
|
|
return $false
|
|
|
|
} elseif ($token -eq "nil") {
|
|
|
|
return $null
|
2016-08-20 23:09:19 +03:00
|
|
|
} else {
|
|
|
|
return new-symbol($token)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-22 01:14:01 +03:00
|
|
|
function read_seq([Reader] $rdr, $start, $end) {
|
|
|
|
$seq = @()
|
2016-08-20 23:09:19 +03:00
|
|
|
$token = $rdr.next()
|
2016-08-22 01:14:01 +03:00
|
|
|
if ($token -ne $start) {
|
|
|
|
throw "expected '$start'"
|
2016-08-20 23:09:19 +03:00
|
|
|
}
|
2016-08-22 01:14:01 +03:00
|
|
|
while (($token = $rdr.peek()) -ne $end) {
|
2016-08-20 23:09:19 +03:00
|
|
|
if ($token -eq "") {
|
2016-08-22 01:14:01 +03:00
|
|
|
throw "expected '$end', got EOF"
|
2016-08-20 23:09:19 +03:00
|
|
|
}
|
|
|
|
$form = read_form $rdr
|
2016-08-22 01:14:01 +03:00
|
|
|
$seq += $form
|
2016-08-20 23:09:19 +03:00
|
|
|
}
|
|
|
|
$token = $rdr.next()
|
2016-08-22 01:14:01 +03:00
|
|
|
return ,$seq
|
|
|
|
}
|
|
|
|
|
|
|
|
function read_list([Reader] $rdr) {
|
|
|
|
return new-list (read_seq $rdr "(" ")")
|
|
|
|
}
|
|
|
|
|
|
|
|
function read_vector([Reader] $rdr) {
|
|
|
|
return new-vector (read_seq $rdr "[" "]")
|
|
|
|
}
|
|
|
|
|
|
|
|
function read_hash_map([Reader] $rdr) {
|
|
|
|
return new-hashmap (read_seq $rdr "{" "}")
|
2016-08-20 23:09:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function read_form([Reader] $rdr) {
|
|
|
|
$token = $rdr.peek()
|
|
|
|
switch ($token) {
|
2016-08-22 01:14:01 +03:00
|
|
|
# reader macros/transforms
|
|
|
|
"'" { $_ = $rdr.next();
|
|
|
|
return new-list @((new-symbol "quote"),
|
|
|
|
(read_form $rdr)) }
|
|
|
|
"``" { $_ = $rdr.next();
|
|
|
|
return new-list @((new-symbol "quasiquote"),
|
|
|
|
(read_form $rdr)) }
|
|
|
|
"~" { $_ = $rdr.next();
|
|
|
|
return (new-list @((new-symbol "unquote"),
|
|
|
|
(read_form $rdr))) }
|
|
|
|
"~@" { $_ = $rdr.next();
|
|
|
|
return (new-list @((new-symbol "splice-unquote"),
|
|
|
|
(read_form $rdr))) }
|
|
|
|
"^" { $_ = $rdr.next();
|
|
|
|
$meta = read_form $rdr
|
|
|
|
return (new-list @((new-symbol "with-meta"),
|
|
|
|
(read_form $rdr),
|
|
|
|
$meta)) }
|
|
|
|
"@" { $_ = $rdr.next();
|
|
|
|
return (new-list @((new-symbol "deref"),
|
|
|
|
(read_form $rdr))) }
|
|
|
|
|
|
|
|
# list
|
2016-08-20 23:09:19 +03:00
|
|
|
")" { throw "unexpected ')'" }
|
2016-08-22 01:14:01 +03:00
|
|
|
"(" { return read_list $rdr }
|
|
|
|
|
|
|
|
# vector
|
|
|
|
"]" { throw "unexpected ']'" }
|
|
|
|
"[" { return read_vector $rdr }
|
|
|
|
|
|
|
|
# hashmap
|
|
|
|
"}" { throw "unexpected '}'" }
|
|
|
|
"{" { return read_hash_map $rdr }
|
|
|
|
|
|
|
|
default { return read_atom $rdr }
|
2016-08-20 23:09:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function read_str {
|
|
|
|
$toks = tokenize($args[0])
|
2016-08-22 01:14:01 +03:00
|
|
|
if ($toks.Length -eq 0) { return $null }
|
2016-08-20 23:09:19 +03:00
|
|
|
read_form([Reader]::new($toks))
|
|
|
|
}
|