summaryrefslogtreecommitdiff
path: root/std/examples/xeval.ts
diff options
context:
space:
mode:
Diffstat (limited to 'std/examples/xeval.ts')
-rw-r--r--std/examples/xeval.ts104
1 files changed, 9 insertions, 95 deletions
diff --git a/std/examples/xeval.ts b/std/examples/xeval.ts
index 75c864745..16ce37fb4 100644
--- a/std/examples/xeval.ts
+++ b/std/examples/xeval.ts
@@ -1,5 +1,6 @@
import { parse } from "../flags/mod.ts";
-const { Buffer, EOF, args, exit, stdin, writeAll } = Deno;
+import { readStringDelim } from "../io/bufio.ts";
+const { args, exit, stdin } = Deno;
type Reader = Deno.Reader;
/* eslint-disable-next-line max-len */
@@ -10,18 +11,16 @@ const AsyncFunction = Object.getPrototypeOf(async function(): Promise<void> {})
/* eslint-disable max-len */
const HELP_MSG = `xeval
-Eval a script on lines from stdin.
-Read from standard input and eval code on each whitespace-delimited
-string chunks.
+Run a script for each new-line or otherwise delimited chunk of standard input.
Print all the usernames in /etc/passwd:
- cat /etc/passwd | deno -A https://deno.land/std/examples/xeval.ts -- "a = $.split(':'); if (a) console.log(a[0])"
+ cat /etc/passwd | deno -A https://deno.land/std/examples/xeval.ts "a = $.split(':'); if (a) console.log(a[0])"
A complicated way to print the current git branch:
- git branch | deno -A https://deno.land/std/examples/xeval.ts -- -I 'line' "if (line.startsWith('*')) console.log(line.slice(2))"
+ git branch | deno -A https://deno.land/std/examples/xeval.ts -I 'line' "if (line.startsWith('*')) console.log(line.slice(2))"
Demonstrates breaking the input up by space delimiter instead of by lines:
- cat LICENSE | deno -A https://deno.land/std/examples/xeval.ts -- -d " " "if ($ === 'MIT') console.log('MIT licensed')",
+ cat LICENSE | deno -A https://deno.land/std/examples/xeval.ts -d " " "if ($ === 'MIT') console.log('MIT licensed')",
USAGE:
deno -A https://deno.land/std/examples/xeval.ts [OPTIONS] <code>
@@ -40,98 +39,12 @@ export interface XevalOptions {
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;
-}
-
-// 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)) {
+ for await (const chunk of readStringDelim(reader, delimiter)) {
// Ignore empty chunks.
if (chunk.length > 0) {
await xevalFunc(chunk);
@@ -140,7 +53,7 @@ export async function xeval(
}
async function main(): Promise<void> {
- const parsedArgs = parse(args.slice(1), {
+ const parsedArgs = parse(args, {
boolean: ["help"],
string: ["delim", "replvar"],
alias: {
@@ -155,6 +68,7 @@ async function main(): Promise<void> {
});
if (parsedArgs._.length != 1) {
console.error(HELP_MSG);
+ console.log(parsedArgs._);
exit(1);
}
if (parsedArgs.help) {