dope2/tests/fixpoint.js

74 lines
No EOL
1.6 KiB
JavaScript

import { fixer } from "../lib/util/fixpoint.js";
const booleanLattice = {
isMaximal: (value) => value,
equality: (l, r) => l === r,
bottom: () => false,
};
const nullable = grammar => nonterminal => request => {
console.log(nonterminal);
const f = nt => {
return {
Epsilon: () => true,
T: () => false,
NT: () => request(nt.nt),
Seq: () => f(nt.l) && f(nt.r),
Alt: () => f(nt.l) || f(nt.r),
}[nt.kind]();
}
return f(grammar[nonterminal]);
}
// S → A B C
// A → a A | ε
// B → b B | A C
// C → c C | ε
const exampleGrammar = {
S: {kind: "Seq",
l: {kind: "NT", nt: "A"},
r: {kind: "Seq",
l: {kind: "NT", nt: "B"},
r: {kind: "NT", nt: "C"},
},
},
A: {kind: "Alt",
l: {kind: "Seq",
l: {kind: "T", token: "a"},
r: {kind: "NT", nt: "A"}
},
r: {kind: "Epsilon"},
},
B: {kind: "Alt",
l: {kind: "Seq",
l: {kind: "T", token: "b"},
r: {kind: "NT", nt: "B"}
},
r: {kind: "Seq",
l: {kind: "NT", nt: "A"},
r: {kind: "NT", nt: "C"}
},
},
C: {kind: "Alt",
l: {kind: "Seq",
l: {kind: "T", token: "c"},
r: {kind: "NT", nt: "C"}
},
r: {kind: "Epsilon"},
},
};
// A is nullable because it has a production A → ε.
// C is nullable because it has a production C → ε.
// B is nullable because B → A C, and both A and C are nullable.
// S is nullable because S → A B C, and A, B, and C are all nullable.
const isNullable = fixer(nullable(exampleGrammar), booleanLattice);
console.log(isNullable("S"));
console.log(isNullable("A"));
console.log(isNullable("B"));
console.log(isNullable("C"));