Jump to content

S-expressions: Difference between revisions

Added Wren
(Added Wren)
Line 5,947:
First, we match an open parenthesis that can be embedded in whitespace. Then we have a <code>@(coll)</code> construct which terminates with <code>@(end)</code>. This is a repetition construct for collecting zero or more items. The <code>:vars (e)</code> argument makes the collect strict: each repetition must bind the variable <code>e</code>. More importantly, in this case, if nothing is
collected, then <code>e</code> gets bound to <code>nil</code> (the empty list). The collect construct does not look at context beyond itself. To terminate the collect at the closing parenthesis we use <code>@(last))</code>. The second closing parenthesis here is literal text to be matched, not TXR syntax. This special clause establishes the terminating context without which the collect will munge all input. When the last clause matches, whatever it matches is consumed and the collect ends. (There is a related <code>@(until)</code> clause which terminates the collect, but leaves its own match unconsumed.)
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
<lang ecmascript>import "/pattern" for Pattern
import "/fmt" for Fmt
 
var INDENT = 2
 
var parseSExpr = Fn.new { |str|
var ipat = " \t\n\f\v\r()\""
var p = Pattern.new("""+0/s["+0^""|(|)|"|+1/I]""", Pattern.within, ipat)
var t = p.findAll(str).map { |m| m.text }.toList
if (t.count == 0) return null
var o = false
var c = 0
for (i in t.count-1..0) {
var ti = t[i].trim()
var nd = Num.fromString(ti)
if (ti == "\"") return null
if (ti == "(") {
t[i] = "["
c = c + 1
} else if (ti == ")") {
t[i] = "]"
c = c - 1
} else if (nd) {
var ni = Num.fromString(ti)
t[i] = ni ? ni.toString : nd.toString
} else if (ti.startsWith("\"")) { // escape embedded double quotes
var temp = ti[1...-1]
t[i] = "\"" + temp.replace("\"", "\\\"") + "\""
}
if (i > 0 && t[i] != "]" && t[i - 1].trim() != "(") t.insert(i, ", ")
if (c == 0) {
if (!o) o = true else return null
}
}
return (c != 0) ? null : t
}
 
var toSExpr = Fn.new { |tokens|
for (i in 0...tokens.count) {
if (tokens[i] == "[") {
tokens[i] = "("
} else if (tokens[i] == "]") {
tokens[i] = ")"
} else if (tokens[i] == ", ") {
tokens[i] = " "
} else if (tokens[i].startsWith("\"")) { // unescape embedded quotes
var temp = tokens[i][1...-1]
tokens[i] = "\"" + temp.replace("\\\"", "\"") + "\""
}
}
return tokens.join()
}
 
var prettyPrint = Fn.new { |tokens|
var level = 0
for (t in tokens) {
var n
if (t == ", " || t == " ") {
continue
} else if (t == "[" || t == "(") {
n = level * INDENT + 1
level = level + 1
} else if (t == "]" || t == ")") {
level = level - 1
n = level * INDENT + 1
} else {
n = level * INDENT + t.count
}
Fmt.print("$*s", n, t)
}
}
 
var str = """((data "quoted data" 123 4.5)""" + "\n" +
""" (data (!@# (4.5) "(more" "data)")))"""
var tokens = parseSExpr.call(str)
if (!tokens) {
System.print("Invalid s-expr!")
} else {
System.print("Native data structure:")
System.print(tokens.join())
System.print("\nNative data structure (pretty print):")
prettyPrint.call(tokens)
 
System.print("\nRecovered S-Expression:")
System.print(toSExpr.call(tokens))
System.print("\nRecovered S-Expression (pretty print):")
prettyPrint.call(tokens)
}</lang>
 
{{out}}
<pre>
Native data structure:
[[data, "quoted data", 123, 4.5], [data, [!@#, [4.5], "(more", "data)"]]]
 
Native data structure (pretty print):
[
[
data
"quoted data"
123
4.5
]
[
data
[
!@#
[
4.5
]
"(more"
"data)"
]
]
]
 
Recovered S-Expression:
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))
 
Recovered S-Expression (pretty print):
(
(
data
"quoted data"
123
4.5
)
(
data
(
!@#
(
4.5
)
"(more"
"data)"
)
)
)
</pre>
 
{{omit from|Brlcad}}
9,482

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.