import yaml from 'yaml'; import {DATA_DIR, RUST_OUT_DIR} from './_common'; import {readFileSync, writeFileSync} from 'fs'; import {join} from 'path'; import {EOL} from 'os'; import {parsePattern, TrieBuilder} from './trie'; const dfa: { [node: string]: { [transition: string]: string } } = yaml.parse(readFileSync(join(DATA_DIR, 'dfa.yaml'), 'utf8')); // These states must always exist; see lex/mod.rs for more details. dfa['TextEntity'] = {}; dfa['AttrValueEntity'] = {}; dfa['Unknown'] = {}; dfa['EOF'] = {}; const nodes = Object.keys(dfa).sort(); const rsTransition = (val: string) => { const [_, flag, next] = /^([_<+?]?)(.*)$/.exec(val)!; const consumeMode = { '_': 'AccumulateLowerCase', '': 'Accumulate', '<': 'Current', '+': 'Next', '?': 'Reconsume', }[flag]; return `Transition { to: State::${next}, consume: ConsumeMode::${consumeMode}, }`; }; const output = ` #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum State { ${nodes.map((n, i) => `${n} = ${i}`).join(`,${EOL} `)} } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ConsumeMode { Current, Next, Reconsume, Accumulate, AccumulateLowerCase, } #[derive(Clone, Copy)] pub struct Transition { // Make pub to allow destructuring. pub to: State, pub consume: ConsumeMode, } ${nodes.map(n => { const trieBuilder = new TrieBuilder(n.toUpperCase(), 'Transition'); for (const [pat, val] of Object.entries(dfa[n])) { if (pat == '') { continue; } trieBuilder.addPattern(parsePattern(pat), rsTransition(val)); } if (dfa[n][''] !== undefined) { trieBuilder.fillRemaining(rsTransition(dfa[n][''])); } return trieBuilder.generate(); }).join(EOL + EOL)} pub static TRANSITIONS: [&'static crate::pattern::TrieNode; ${nodes.length}] = [${nodes.map(n => n.toUpperCase()).join(', ')}]; `; writeFileSync(join(RUST_OUT_DIR, 'dfa.rs'), output);