summaryrefslogtreecommitdiff
path: root/std/xeval/mod.ts
diff options
context:
space:
mode:
authorRy Dahl <ry@tinyclouds.org>2020-01-08 17:40:59 -0500
committerGitHub <noreply@github.com>2020-01-08 17:40:59 -0500
commitc50cab90a05d271013f741768d70c1eda6ef9a10 (patch)
tree08c8f59ed2ef449abd56455c9494a43a73058e67 /std/xeval/mod.ts
parentb71d5708c603b09714a1f539f92f82392b6ee33d (diff)
Remove xeval subcommand (#3630)
Diffstat (limited to 'std/xeval/mod.ts')
-rw-r--r--std/xeval/mod.ts170
1 files changed, 0 insertions, 170 deletions
diff --git a/std/xeval/mod.ts b/std/xeval/mod.ts
deleted file mode 100644
index 5843c8650..000000000
--- a/std/xeval/mod.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-import { parse } from "../flags/mod.ts";
-const { Buffer, EOF, args, exit, stdin, writeAll } = Deno;
-type Reader = Deno.Reader;
-
-/* eslint-disable-next-line max-len */
-// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction.
-const AsyncFunction = Object.getPrototypeOf(async function(): Promise<void> {})
- .constructor;
-
-const HELP_MSG = `Deno xeval
-
-USAGE:
- deno -A https://deno.land/std/xeval/mod.ts [OPTIONS] <code>
-
-OPTIONS:
- -d, --delim <delim> Set delimiter, defaults to newline
- -I, --replvar <replvar> Set variable name to be used in eval, defaults to $
-
-ARGS:
- <code>`;
-
-export type XevalFunc = (v: string) => void;
-
-export interface XevalOptions {
- delimiter?: string;
-}
-
-const DEFAULT_DELIMITER = "\n";
-
-// Generate longest proper prefix which is also suffix array.
-function createLPS(pat: Uint8Array): Uint8Array {
- const lps = new Uint8Array(pat.length);
- lps[0] = 0;
- let prefixEnd = 0;
- let i = 1;
- while (i < lps.length) {
- if (pat[i] == pat[prefixEnd]) {
- prefixEnd++;
- lps[i] = prefixEnd;
- i++;
- } else if (prefixEnd === 0) {
- lps[i] = 0;
- i++;
- } else {
- prefixEnd = pat[prefixEnd - 1];
- }
- }
- return lps;
-}
-
-// TODO(kevinkassimo): Move this utility somewhere public in deno_std.
-// Import from there once doable.
-// Read from reader until EOF and emit string chunks separated
-// by the given delimiter.
-async function* chunks(
- reader: Reader,
- delim: string
-): AsyncIterableIterator<string> {
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
- // Avoid unicode problems
- const delimArr = encoder.encode(delim);
- const delimLen = delimArr.length;
- const delimLPS = createLPS(delimArr);
-
- let inputBuffer = new Buffer();
- const inspectArr = new Uint8Array(Math.max(1024, delimLen + 1));
-
- // Modified KMP
- let inspectIndex = 0;
- let matchIndex = 0;
- while (true) {
- const result = await reader.read(inspectArr);
- if (result === EOF) {
- // Yield last chunk.
- const lastChunk = inputBuffer.toString();
- yield lastChunk;
- return;
- }
- if ((result as number) < 0) {
- // Discard all remaining and silently fail.
- return;
- }
- const sliceRead = inspectArr.subarray(0, result as number);
- await writeAll(inputBuffer, sliceRead);
-
- let sliceToProcess = inputBuffer.bytes();
- while (inspectIndex < sliceToProcess.length) {
- if (sliceToProcess[inspectIndex] === delimArr[matchIndex]) {
- inspectIndex++;
- matchIndex++;
- if (matchIndex === delimLen) {
- // Full match
- const matchEnd = inspectIndex - delimLen;
- const readyBytes = sliceToProcess.subarray(0, matchEnd);
- // Copy
- const pendingBytes = sliceToProcess.slice(inspectIndex);
- const readyChunk = decoder.decode(readyBytes);
- yield readyChunk;
- // Reset match, different from KMP.
- sliceToProcess = pendingBytes;
- inspectIndex = 0;
- matchIndex = 0;
- }
- } else {
- if (matchIndex === 0) {
- inspectIndex++;
- } else {
- matchIndex = delimLPS[matchIndex - 1];
- }
- }
- }
- // Keep inspectIndex and matchIndex.
- inputBuffer = new Buffer(sliceToProcess);
- }
-}
-
-export async function xeval(
- reader: Reader,
- xevalFunc: XevalFunc,
- { delimiter = DEFAULT_DELIMITER }: XevalOptions = {}
-): Promise<void> {
- for await (const chunk of chunks(reader, delimiter)) {
- // Ignore empty chunks.
- if (chunk.length > 0) {
- await xevalFunc(chunk);
- }
- }
-}
-
-async function main(): Promise<void> {
- const parsedArgs = parse(args.slice(1), {
- boolean: ["help"],
- string: ["delim", "replvar"],
- alias: {
- delim: ["d"],
- replvar: ["I"],
- help: ["h"]
- },
- default: {
- delim: DEFAULT_DELIMITER,
- replvar: "$"
- }
- });
- if (parsedArgs._.length != 1) {
- console.error(HELP_MSG);
- exit(1);
- }
- if (parsedArgs.help) {
- return console.log(HELP_MSG);
- }
-
- const delimiter = parsedArgs.delim;
- const replVar = parsedArgs.replvar;
- const code = parsedArgs._[0];
-
- // new AsyncFunction()'s error message for this particular case isn't great.
- if (!replVar.match(/^[_$A-z][_$A-z0-9]*$/)) {
- console.error(`Bad replvar identifier: "${replVar}"`);
- exit(1);
- }
-
- const xEvalFunc = new AsyncFunction(replVar, code);
-
- await xeval(stdin, xEvalFunc, { delimiter });
-}
-
-if (import.meta.main) {
- main();
-}