-
-
Save bathos/9b632d6ccfd02211420d37d4f93a21e5 to your computer and use it in GitHub Desktop.
unwāpurify.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { Transform } = require('stream'); | |
// Although superficially there are "rules" we could implement programmatically, | |
// this is a grammar; its only real rules from a computer’s perspective are the | |
// fact that certain inputs map to certain terminal symbols (or don’t). In other | |
// words, the grammar itself is just data. | |
const TABLE = new Map([ | |
[ ' ', '' ], | |
[ '\n', '\n' ], | |
[ '\r', '\n' ], | |
[ 'a', 'あ' ], | |
[ 'b', new Map([ | |
[ 'a', 'ば' ], | |
[ 'e', 'べ' ], | |
[ 'i', 'び' ], | |
[ 'o', 'ぼ' ], | |
[ 'u', 'ぶ' ], | |
[ 'y', new Map([ | |
[ 'a', 'びゃ' ], | |
[ 'o', 'びょ' ], | |
[ 'u', 'びゅ' ] | |
]) ] | |
]) ], | |
[ 'c', new Map([ | |
[ 'c', new Map([ | |
[ 'h', new Map([ | |
[ 'a', 'っちゃ' ], | |
[ 'i', 'っち' ], | |
[ 'o', 'っちょ' ], | |
[ 'u', 'っちゅ' ] | |
]) ] | |
]) ], | |
[ 'h', new Map([ | |
[ 'a', 'ちゃ' ], | |
[ 'i', 'ち' ], | |
[ 'o', 'ちょ' ], | |
[ 'u', 'ちゅ' ] | |
]) ] | |
]) ], | |
[ 'd', new Map([ | |
[ 'a', 'だ' ], | |
[ 'e', 'で' ], | |
[ 'i', 'ぢ' ], | |
[ 'o', 'ど' ], | |
[ 'u', 'づ' ], | |
[ 'y', new Map([ | |
[ 'a', 'ぢゃ' ], | |
[ 'o', 'ぢょ' ], | |
[ 'u', 'ぢゅ' ] | |
]) ] | |
]) ], | |
[ 'e', 'え' ], | |
[ 'f', new Map([ | |
[ 'u', 'ふ' ] | |
]) ], | |
[ 'g', new Map([ | |
[ 'a', 'が' ], | |
[ 'e', 'げ' ], | |
[ 'i', 'ぎ' ], | |
[ 'o', 'ご' ], | |
[ 'u', 'ぐ' ], | |
[ 'y', new Map([ | |
[ 'a', 'ぎゃ' ], | |
[ 'o', 'ぎょ' ], | |
[ 'u', 'ぎゅ' ] | |
]) ] | |
]) ], | |
[ 'h', new Map([ | |
[ 'a', 'は' ], | |
[ 'e', 'へ' ], | |
[ 'i', 'ひ' ], | |
[ 'o', 'ほ' ], | |
[ 'y', new Map([ | |
[ 'a', 'ひゃ' ], | |
[ 'o', 'ひょ' ], | |
[ 'u', 'ひゅ' ] | |
]) ] | |
]) ], | |
[ 'i', 'い' ], | |
[ 'j', new Map([ | |
[ 'a', 'じゃ' ], | |
[ 'i', 'じ' ], | |
[ 'o', 'じょ' ], | |
[ 'u', 'じゅ' ] | |
]) ], | |
[ 'k', new Map([ | |
[ 'a', 'か' ], | |
[ 'e', 'け' ], | |
[ 'i', 'き' ], | |
[ 'k', new Map([ | |
[ 'a', 'っか' ], | |
[ 'e', 'っけ' ], | |
[ 'i', 'っき' ], | |
[ 'o', 'っこ' ], | |
[ 'u', 'っく' ], | |
[ 'y', new Map([ | |
[ 'a', 'っきゃ' ], | |
[ 'o', 'っきょ' ], | |
[ 'u', 'っきゅ' ] | |
]) ] | |
]) ], | |
[ 'o', 'こ' ], | |
[ 'u', 'く' ], | |
[ 'y', new Map([ | |
[ 'a', 'きゃ' ], | |
[ 'o', 'きょ' ], | |
[ 'u', 'きゅ' ] | |
]) ] | |
]) ], | |
[ 'm', new Map([ | |
[ 'a', 'ま' ], | |
[ 'e', 'め' ], | |
[ 'i', 'み' ], | |
[ 'o', 'も' ], | |
[ 'u', 'む' ], | |
[ 'y', new Map([ | |
[ 'a', 'みゃ' ], | |
[ 'o', 'みょ' ], | |
[ 'u', 'みゅ' ] | |
]) ] | |
]) ], | |
[ 'n', new Map([ | |
[ ' ', 'ん' ], | |
[ '\n', 'ん\n' ], | |
[ '\r', 'ん\n' ], | |
[ 'a', 'な' ], | |
[ 'e', 'ね' ], | |
[ 'i', 'に' ], | |
[ 'o', 'の' ], | |
[ 'u', 'ぬ' ], | |
[ 'y', new Map([ | |
[ 'a', 'にゃ' ], | |
[ 'o', 'にょ' ], | |
[ 'u', 'にゅ' ] | |
]) ] | |
]) ], | |
[ 'o', 'お' ], | |
[ 'p', new Map([ | |
[ 'a', 'ぱ' ], | |
[ 'e', 'ぺ' ], | |
[ 'i', 'ぴ' ], | |
[ 'o', 'ぽ' ], | |
[ 'p', new Map([ | |
[ 'a', 'っぱ' ], | |
[ 'e', 'っぺ' ], | |
[ 'i', 'っぴ' ], | |
[ 'o', 'っぽ' ], | |
[ 'u', 'っぷ' ], | |
[ 'y', new Map([ | |
[ 'a', 'っぴゃ' ], | |
[ 'o', 'っぴょ' ], | |
[ 'u', 'っぴゅ' ] | |
]) ] | |
]) ], | |
[ 'u', 'ぷ' ], | |
[ 'y', new Map([ | |
[ 'a', 'ぴゃ' ], | |
[ 'o', 'ぴょ' ], | |
[ 'u', 'ぴゅ' ] | |
]) ] | |
]) ], | |
[ 'r', new Map([ | |
[ 'a', 'ら' ], | |
[ 'e', 'れ' ], | |
[ 'i', 'り' ], | |
[ 'o', 'ろ' ], | |
[ 'u', 'る' ], | |
[ 'y', new Map([ | |
[ 'a', 'りゃ' ], | |
[ 'o', 'りょ' ], | |
[ 'u', 'りゅ' ] | |
]) ] | |
]) ], | |
[ 's', new Map([ | |
[ 'a', 'さ' ], | |
[ 'e', 'せ' ], | |
[ 'h', new Map([ | |
[ 'a', 'しゃ' ], | |
[ 'i', 'し' ], | |
[ 'o', 'しょ' ], | |
[ 'u', 'しゅ' ] | |
]) ], | |
[ 'o', 'そ' ], | |
[ 's', new Map([ | |
[ 'a', 'っさ' ], | |
[ 'e', 'っせ' ], | |
[ 'h', new Map([ | |
[ 'a', 'っしゃ' ], | |
[ 'i', 'っし' ], | |
[ 'o', 'っしょ' ], | |
[ 'u', 'っしゅ' ] | |
]) ], | |
[ 'o', 'っそ' ], | |
[ 'u', 'っす' ] | |
]) ], | |
[ 'u', 'す' ] | |
]) ], | |
[ 't', new Map([ | |
[ 'a', 'た' ], | |
[ 'e', 'て' ], | |
[ 'o', 'と' ], | |
[ 's', new Map([ | |
[ 'u', 'つ' ] | |
]) ], | |
[ 't', new Map([ | |
[ 'a', 'った' ], | |
[ 'e', 'って' ], | |
[ 'o', 'っと' ] | |
]) ] | |
]) ], | |
[ 'u', 'う' ], | |
[ 'w', new Map([ | |
[ 'a', 'わ' ], | |
[ 'o', 'を' ] | |
]) ], | |
[ 'y', new Map([ | |
[ 'a', 'や' ], | |
[ 'o', 'よ' ], | |
[ 'u', 'ゆ' ] | |
]) ], | |
[ 'z', new Map([ | |
[ 'a', 'ざ' ], | |
[ 'e', 'ぜ' ], | |
[ 'o', 'ぞ' ], | |
[ 'u', 'ず' ] | |
]) ] | |
]); | |
const OBSOLETE_TABLE = new Map(TABLE); | |
OBSOLETE_TABLE.set('w', new Map(OBSOLETE_TABLE.get('w'))); | |
OBSOLETE_TABLE.get('w').set('e', 'ゑ'); | |
OBSOLETE_TABLE.get('w').set('i', 'ゐ'); | |
function * unwāpurify(baseTable, table=baseTable, input) { | |
while (table.has(input = (yield))) { | |
const res = table.get(input); | |
if (typeof res === 'string') table = baseTable, yield res; | |
else table = res; | |
} | |
throw new Error(`Unexpected input ${ input }`); | |
} | |
if (!module.parent) { | |
process.stdin.setRawMode(true); | |
const table = process.env.INCLUDE_OBSOLETE ? OBSOLETE_TABLE : TABLE; | |
const iter = unwāpurify(table); | |
iter.next(); | |
const transform = new Transform({ | |
flush(done) { | |
const { value } = iter.next(' '); | |
if (value) this.push(value); | |
}, | |
transform(chunk, _, done) { | |
try { | |
for (const char of String(chunk)) { | |
if (char === '\x03') return process.exit(); | |
if (char === '\x7F') { | |
throw new Error(`Backspace? Backspace???`); | |
} | |
if (char < ' ' && char !== '\n' && char !== '\r') continue; | |
const { value } = iter.next(char); | |
if (value !== undefined) iter.next(), this.push(value); | |
} | |
done(); | |
} catch (err) { | |
this.push('\n'); | |
done(err); | |
} | |
} | |
}); | |
process.stdin.pipe(transform).pipe(process.stdout); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment