Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
38
Task/S-expressions/JavaScript/s-expressions-1.js
Normal file
38
Task/S-expressions/JavaScript/s-expressions-1.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
String.prototype.parseSexpr = function() {
|
||||
var t = this.match(/\s*("[^"]*"|\(|\)|"|[^\s()"]+)/g)
|
||||
for (var o, c=0, i=t.length-1; i>=0; i--) {
|
||||
var n, ti = t[i].trim()
|
||||
if (ti == '"') return
|
||||
else if (ti == '(') t[i]='[', c+=1
|
||||
else if (ti == ')') t[i]=']', c-=1
|
||||
else if ((n=+ti) == ti) t[i]=n
|
||||
else t[i] = '\'' + ti.replace('\'', '\\\'') + '\''
|
||||
if (i>0 && ti!=']' && t[i-1].trim()!='(' ) t.splice(i,0, ',')
|
||||
if (!c) if (!o) o=true; else return
|
||||
}
|
||||
return c ? undefined : eval(t.join(''))
|
||||
}
|
||||
|
||||
Array.prototype.toString = function() {
|
||||
var s=''; for (var i=0, e=this.length; i<e; i++) s+=(s?' ':'')+this[i]
|
||||
return '('+s+')'
|
||||
}
|
||||
|
||||
Array.prototype.toPretty = function(s) {
|
||||
if (!s) s = ''
|
||||
var r = s + '(<br>'
|
||||
var s2 = s + Array(6).join(' ')
|
||||
for (var i=0, e=this.length; i<e; i+=1) {
|
||||
var ai = this[i]
|
||||
r += ai.constructor != Array ? s2+ai+'<br>' : ai.toPretty(s2)
|
||||
}
|
||||
return r + s + ')<br>'
|
||||
}
|
||||
|
||||
var str = '((data "quoted data" 123 4.5)\n (data (!@# (4.5) "(more" "data)")))'
|
||||
document.write('text:<br>', str.replace(/\n/g,'<br>').replace(/ /g,' '), '<br><br>')
|
||||
var sexpr = str.parseSexpr()
|
||||
if (sexpr === undefined)
|
||||
document.write('Invalid s-expr!', '<br>')
|
||||
else
|
||||
document.write('s-expr:<br>', sexpr, '<br><br>', sexpr.constructor != Array ? '' : 'pretty print:<br>' + sexpr.toPretty())
|
||||
138
Task/S-expressions/JavaScript/s-expressions-2.js
Normal file
138
Task/S-expressions/JavaScript/s-expressions-2.js
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
(() => {
|
||||
"use strict";
|
||||
|
||||
// ------------------ S-EXPRESSIONS ------------------
|
||||
const main = () => {
|
||||
const expr = [
|
||||
"((data \"quoted data\" 123 4.5)",
|
||||
" (data (!@# (4.5) \"(more\" \"data)\")))"
|
||||
].join("\n");
|
||||
|
||||
const [parse, residue] = parseExpr(
|
||||
tokenized(expr)
|
||||
);
|
||||
|
||||
return 0 < residue.length ? (
|
||||
`Unparsed tokens: ${JSON.stringify(residue)}`
|
||||
) : 0 < parse.length ? ([
|
||||
JSON.stringify(parse, null, 2),
|
||||
"Reserialized from parse:",
|
||||
parse.map(serialized).join(" ")
|
||||
].join("\n\n")) : "Could not be parsed";
|
||||
};
|
||||
|
||||
// ---------------- EXPRESSION PARSER ----------------
|
||||
|
||||
// parseExpr [String] -> ([Expr], [String])
|
||||
const parseExpr = tokens =>
|
||||
// A tuple of (parsed trees, residual tokens)
|
||||
// derived from a list of tokens.
|
||||
until(finished)(readToken)([
|
||||
[], tokens
|
||||
]);
|
||||
|
||||
|
||||
// finished :: ([Expr], [String]) -> Bool
|
||||
const finished = ([, tokens]) =>
|
||||
// True if no tokens remain, or the next
|
||||
// closes a sub-expression.
|
||||
0 === tokens.length || ")" === tokens[0];
|
||||
|
||||
|
||||
// readToken :: ([Expr], [String]) -> ([Expr], [String])
|
||||
const readToken = ([xs, tokens]) => {
|
||||
// A tuple of enriched expressions and
|
||||
// depleted tokens.
|
||||
const [token, ...ts] = tokens;
|
||||
|
||||
// An open bracket introduces recursion over
|
||||
// a sub-expression to define a sub-list.
|
||||
return "(" === token ? (() => {
|
||||
const [expr, rest] = parseExpr(ts);
|
||||
|
||||
return [xs.concat([expr]), rest.slice(1)];
|
||||
})() : ")" === token ? (
|
||||
[xs, token]
|
||||
) : [xs.concat(atom(token)), ts];
|
||||
};
|
||||
|
||||
// ------------------- ATOM PARSER -------------------
|
||||
|
||||
// atom :: String -> Expr
|
||||
const atom = s =>
|
||||
0 < s.length ? (
|
||||
isNaN(s) ? (
|
||||
"\"'".includes(s[0]) ? (
|
||||
s.slice(1, -1)
|
||||
) : {
|
||||
name: s
|
||||
}
|
||||
) : parseFloat(s, 10)
|
||||
) : "";
|
||||
|
||||
|
||||
// ------------------ TOKENIZATION -------------------
|
||||
|
||||
// tokenized :: String -> [String]
|
||||
const tokenized = s =>
|
||||
// Brackets and quoted or unquoted atomic strings.
|
||||
quoteTokens("\"")(s).flatMap(
|
||||
segment => "\"" !== segment[0] ? (
|
||||
segment.replace(/([()])/gu, " $1 ")
|
||||
.split(/\s+/u)
|
||||
.filter(Boolean)
|
||||
) : [segment]
|
||||
);
|
||||
|
||||
|
||||
// quoteTokens :: Char -> String -> [String]
|
||||
const quoteTokens = q =>
|
||||
// Alternating unquoted and quoted segments.
|
||||
s => s.split(q).flatMap(
|
||||
(k, i) => even(i) ? (
|
||||
Boolean(k) ? (
|
||||
[k]
|
||||
) : []
|
||||
) : [`${q}${k}${q}`]
|
||||
);
|
||||
|
||||
// ------------------ SERIALIZATION ------------------
|
||||
|
||||
// serialized :: Expr -> String
|
||||
const serialized = e => {
|
||||
const t = typeof e;
|
||||
|
||||
return "number" === t ? (
|
||||
`${e}`
|
||||
) : "string" === t ? (
|
||||
`"${e}"`
|
||||
) : "object" === t ? (
|
||||
Array.isArray(e) ? (
|
||||
`(${e.map(serialized).join(" ")})`
|
||||
) : e.name
|
||||
) : "?";
|
||||
};
|
||||
|
||||
|
||||
// --------------------- GENERIC ---------------------
|
||||
|
||||
// even :: Int -> Bool
|
||||
const even = n =>
|
||||
// True if 2 is a factor of n.
|
||||
0 === n % 2;
|
||||
|
||||
|
||||
// until :: (a -> Bool) -> (a -> a) -> a -> a
|
||||
const until = p =>
|
||||
// The value resulting from repeated applications
|
||||
// of f to the seed value x, terminating when
|
||||
// that result returns true for the predicate p.
|
||||
f => {
|
||||
const go = x =>
|
||||
p(x) ? x : go(f(x));
|
||||
|
||||
return go;
|
||||
};
|
||||
|
||||
return main();
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue