S-expressions: Difference between revisions

Content added Content deleted
m (→‎{{header|Wren}}: Minor tidy)
m (→‎JS Functional: Tidied.)
Line 3,919: Line 3,919:
"((data \"quoted data\" 123 4.5)",
"((data \"quoted data\" 123 4.5)",
" (data (!@# (4.5) \"(more\" \"data)\")))"
" (data (!@# (4.5) \"(more\" \"data)\")))"
].join("\n");
]
.join("\n");


const [parse, residue] = parseExpr(
const [parse, residue] = parseExpr(
Line 3,925: Line 3,926:
);
);


return 0 < residue.length ? (
return 0 < residue.length
`Unparsed tokens: ${JSON.stringify(residue)}`
? `Unparsed tokens: ${JSON.stringify(residue)}`
) : 0 < parse.length ? ([
: 0 < parse.length
JSON.stringify(parse, null, 2),
? ([
"Reserialized from parse:",
JSON.stringify(parse, null, 2),
parse.map(serialized).join(" ")
"Reserialized from parse:",
parse.map(serialized).join(" ")
].join("\n\n")) : "Could not be parsed";
]
.join("\n\n"))
: "Could not be parsed";
};
};


Line 3,960: Line 3,964:
// An open bracket introduces recursion over
// An open bracket introduces recursion over
// a sub-expression to define a sub-list.
// a sub-expression to define a sub-list.
return "(" === token ? (() => {
return "(" === token
const [expr, rest] = parseExpr(ts);
? (() => {
const [expr, rest] = parseExpr(ts);


return [xs.concat([expr]), rest.slice(1)];
return [xs.concat([expr]), rest.slice(1)];
})() : ")" === token ? (
})()
[xs, token]
: ")" === token
) : [xs.concat(atom(token)), ts];
? [xs, token]
: [xs.concat(atom(token)), ts];
};
};


Line 3,973: Line 3,979:
// atom :: String -> Expr
// atom :: String -> Expr
const atom = s =>
const atom = s =>
0 < s.length ? (
0 < s.length
isNaN(s) ? (
? isNaN(s)
"\"'".includes(s[0]) ? (
? (
s.slice(1, -1)
"\"'".includes(s[0])
) : {
? s.slice(1, -1)
name: s
: {name: s}
}
)
) : parseFloat(s, 10)
: parseFloat(s, 10)
) : "";
: "";




Line 3,990: Line 3,996:
// Brackets and quoted or unquoted atomic strings.
// Brackets and quoted or unquoted atomic strings.
quoteTokens("\"")(s).flatMap(
quoteTokens("\"")(s).flatMap(
segment => "\"" !== segment[0] ? (
segment => "\"" !== segment[0]
segment.replace(/([()])/gu, " $1 ")
? segment.replace(/([()])/gu, " $1 ")
.split(/\s+/u)
.split(/\s+/u)
.filter(Boolean)
.filter(Boolean)
) : [segment]
: [segment]
);
);


Line 4,002: Line 4,008:
// Alternating unquoted and quoted segments.
// Alternating unquoted and quoted segments.
s => s.split(q).flatMap(
s => s.split(q).flatMap(
(k, i) => even(i) ? (
(k, i) => even(i)
Boolean(k) ? (
? 0 < k.length
[k]
? [k]
) : []
: []
) : [`${q}${k}${q}`]
: [`${q}${k}${q}`]
);
);


Line 4,015: Line 4,021:
const t = typeof e;
const t = typeof e;


return "number" === t ? (
return "number" === t
`${e}`
? `${e}`
) : "string" === t ? (
: "string" === t
`"${e}"`
? `"${e}"`
) : "object" === t ? (
: "object" === t
Array.isArray(e) ? (
? Array.isArray(e)
`(${e.map(serialized).join(" ")})`
? `(${e.map(serialized).join(" ")})`
) : e.name
: e.name
) : "?";
: "?";
};
};


Line 4,042: Line 4,048:
f => {
f => {
const go = x =>
const go = x =>
p(x) ? x : go(f(x));
p(x)
? x
: go(f(x));


return go;
return go;