Compare commits

..

No commits in common. "1ecbe672bcf2751849155976a607100c6a8b8240" and "3bffe98df03e3cfabc3f30e45d99e631ea35bfca" have entirely different histories.

4 changed files with 441 additions and 1248 deletions

View file

@ -129,17 +129,14 @@ function render_state(state, input_editor) {
* otherwise just queue it for submission. * otherwise just queue it for submission.
*/ */
function post_document(worker, kind, state, document) { function post_document(worker, kind, state, document) {
console.log("Received document", kind)
if (window.localStorage) { if (window.localStorage) {
window.localStorage.setItem(kind, document); window.localStorage.setItem(kind, document);
} }
let new_state = {...state}; let new_state = {...state};
if (new_state.pending) { if (new_state.pending) {
console.log("Document parked", kind)
new_state.next = document; new_state.next = document;
} else { } else {
console.log("Document submitted", kind)
new_state.pending = document; new_state.pending = document;
new_state.next = null; new_state.next = null;
worker.postMessage({kind, data: document}); worker.postMessage({kind, data: document});
@ -154,7 +151,6 @@ function post_document(worker, kind, state, document) {
function rotate_document(worker, kind, state) { function rotate_document(worker, kind, state) {
let new_state = {...state, last: state.pending, pending: null}; let new_state = {...state, last: state.pending, pending: null};
if (new_state.next) { if (new_state.next) {
console.log("Rotating document", kind)
new_state.pending = new_state.next; new_state.pending = new_state.next;
new_state.next = null; new_state.next = null;
worker.postMessage({kind, data: new_state.pending}); worker.postMessage({kind, data: new_state.pending});

View file

@ -176,21 +176,19 @@ const pyodide_promise = setup_python();
async function load_grammar_module(code) { async function load_grammar_module(code) {
const pyodide = self.pyodide; const pyodide = self.pyodide;
console.log("eval_grammar: Running"); // console.log("Running...");
const my_fn = pyodide.globals.get("eval_grammar"); const my_fn = pyodide.globals.get("eval_grammar");
my_fn(code); my_fn(code);
my_fn.destroy(); my_fn.destroy();
console.log("eval_grammar: Done");
} }
async function parse_document(code) { async function parse_document(code) {
const pyodide = self.pyodide; const pyodide = self.pyodide;
console.log("eval_document: Running"); // console.log("Running...");
const my_fn = pyodide.globals.get("eval_document"); const my_fn = pyodide.globals.get("eval_document");
my_fn(code); my_fn(code);
my_fn.destroy(); my_fn.destroy();
console.log("eval_document: Done");
} }
self.onmessage = async function(event) { self.onmessage = async function(event) {
@ -199,10 +197,8 @@ self.onmessage = async function(event) {
try { try {
const { kind, data } = event.data; const { kind, data } = event.data;
if (kind === "grammar") { if (kind === "grammar") {
console.log("Worker received grammar")
await load_grammar_module(data); await load_grammar_module(data);
} else if (kind === "input") { } else if (kind === "input") {
console.log("Worker received input")
await parse_document(data); await parse_document(data);
} }
} catch (e) { } catch (e) {

File diff suppressed because it is too large Load diff

View file

@ -1116,9 +1116,7 @@ class ParserGenerator:
# Check to make sure they didn't use anything that will give us # Check to make sure they didn't use anything that will give us
# heartburn later. # heartburn later.
reserved = [ reserved = [a for a in alphabet if (a.startswith("__") and not a.startswith("__gen_")) or a == "$"]
a for a in alphabet if (a.startswith("__") and not a.startswith("__gen_")) or a == "$"
]
if reserved: if reserved:
raise ValueError( raise ValueError(
"Can't use {symbols} in grammars, {what} reserved.".format( "Can't use {symbols} in grammars, {what} reserved.".format(
@ -1457,18 +1455,7 @@ class ParserGenerator:
lookahead.update(context) lookahead.update(context)
for rule in rules: for rule in rules:
if len(rule) == 0: new_core = Configuration.from_rule(config_next, rule)
next = None
else:
next = rule[0]
new_core = Configuration(
name=config_next,
symbols=rule,
position=0,
next=next,
)
todo.append((new_core, lookahead)) todo.append((new_core, lookahead))
return ItemSet(closure) return ItemSet(closure)
@ -1632,7 +1619,6 @@ class Terminal(Rule):
_CURRENT_DEFINITION: str = "__global" _CURRENT_DEFINITION: str = "__global"
_CURRENT_GEN_INDEX: int = 0 _CURRENT_GEN_INDEX: int = 0
class NonTerminal(Rule): class NonTerminal(Rule):
"""A non-terminal, or a production, in the grammar. """A non-terminal, or a production, in the grammar.
@ -1713,6 +1699,7 @@ class NonTerminal(Rule):
_CURRENT_DEFINITION = prev_defn _CURRENT_DEFINITION = prev_defn
_CURRENT_GEN_INDEX = prev_idx _CURRENT_GEN_INDEX = prev_idx
return self._body return self._body
def flatten( def flatten(
@ -1820,32 +1807,22 @@ def seq(*args: Rule) -> Rule:
def opt(*args: Rule) -> Rule: def opt(*args: Rule) -> Rule:
"""Mark a sequence as optional."""
return AlternativeRule(seq(*args), Nothing) return AlternativeRule(seq(*args), Nothing)
def mark(rule: Rule, **kwargs) -> Rule: def mark(rule: Rule, **kwargs) -> Rule:
"""Mark the specified rules with metadata."""
return MetadataRule(rule, kwargs) return MetadataRule(rule, kwargs)
def one_or_more(*args: Rule) -> Rule: def one_or_more(r: Rule) -> Rule:
"""Generate a rule that matches a repetition of one or more of the specified
rule.
The resulting list is transparent, i.e., in the parse tree all of the members
of the list will be in-line with the parent. If you want to name the list
create a named nonterminal to contain it.
"""
global _CURRENT_DEFINITION global _CURRENT_DEFINITION
global _CURRENT_GEN_INDEX global _CURRENT_GEN_INDEX
tail : NonTerminal | None = None tail : NonTerminal | None = None
def impl() -> Rule: def impl() -> Rule:
nonlocal tail nonlocal tail
assert tail is not None assert(tail is not None)
return opt(tail) + seq(*args) return opt(tail) + r
tail = NonTerminal( tail = NonTerminal(
fn=impl, fn=impl,
@ -1856,17 +1833,8 @@ def one_or_more(*args: Rule) -> Rule:
return tail return tail
def zero_or_more(r:Rule) -> Rule:
def zero_or_more(*args: Rule) -> Rule: return opt(one_or_more(r))
"""Generate a rule that matches a repetition of zero or more of the specified
rule.
The resulting list is transparent, i.e., in the parse tree all of the members
of the list will be in-line with the parent. If you want to name the list
create a named nonterminal to contain it.
"""
return opt(one_or_more(*args))
@typing.overload @typing.overload
def rule(f: typing.Callable, /) -> NonTerminal: ... def rule(f: typing.Callable, /) -> NonTerminal: ...
@ -2187,25 +2155,11 @@ class Re:
def question(self) -> "Re": def question(self) -> "Re":
return ReQuestion(self) return ReQuestion(self)
def __or__(self, value: "Re | Terminal", /) -> "Re": def __or__(self, value: "Re", /) -> "Re":
if isinstance(value, Re): return ReAlt(self, value)
other = value
elif isinstance(value.pattern, Re):
other = value.pattern
else:
other = Re.literal(value.pattern)
return ReAlt(self, other) def __add__(self, value: "Re") -> "Re":
return ReSeq(self, value)
def __add__(self, value: "Re | Terminal") -> "Re":
if isinstance(value, Re):
other = value
elif isinstance(value.pattern, Re):
other = value.pattern
else:
other = Re.literal(value.pattern)
return ReSeq(self, other)
UNICODE_MAX_CP = 1114112 UNICODE_MAX_CP = 1114112
@ -2866,10 +2820,7 @@ class TriviaMode(enum.Enum):
PrecedenceList = list[typing.Tuple[Assoc, list[Terminal|NonTerminal]]] PrecedenceList = list[typing.Tuple[Assoc, list[Terminal|NonTerminal]]]
def gather_grammar(start: NonTerminal, trivia: list[Terminal]) -> tuple[dict[str,NonTerminal], dict[str,Terminal]]:
def gather_grammar(
start: NonTerminal, trivia: list[Terminal]
) -> tuple[dict[str, NonTerminal], dict[str, Terminal]]:
"""Starting from the given NonTerminal, gather all of the symbols """Starting from the given NonTerminal, gather all of the symbols
(NonTerminals and Terminals) that make up the grammar. (NonTerminals and Terminals) that make up the grammar.
""" """
@ -2913,11 +2864,9 @@ def gather_grammar(
existing = named_rules.get(rule.name) existing = named_rules.get(rule.name)
if existing is not None: if existing is not None:
# TODO TEST # TODO TEST
raise ValueError( raise ValueError(f"""Found more than one rule named {rule.name}:
f"""Found more than one rule named {rule.name}:
- {existing.definition_location} - {existing.definition_location}
- {rule.definition_location}""" - {rule.definition_location}""")
)
named_rules[rule.name] = rule named_rules[rule.name] = rule
named_terminals: dict[str, Terminal] = {} named_terminals: dict[str, Terminal] = {}
@ -2925,20 +2874,16 @@ def gather_grammar(
existing = named_terminals.get(terminal.name) existing = named_terminals.get(terminal.name)
if existing is not None: if existing is not None:
# TODO TEST # TODO TEST
raise ValueError( raise ValueError(f"""Found more than one terminal named {terminal.name}:
f"""Found more than one terminal named {terminal.name}:
- {existing.definition_location} - {existing.definition_location}
- {terminal.definition_location}""" - {terminal.definition_location}""")
)
existing_rule = named_rules.get(terminal.name) existing_rule = named_rules.get(terminal.name)
if existing_rule is not None: if existing_rule is not None:
# TODO TEST # TODO TEST
raise ValueError( raise ValueError(f"""Found a terminal and a rule both named {terminal.name}:
f"""Found a terminal and a rule both named {terminal.name}:
- The rule was defined at {existing_rule.definition_location} - The rule was defined at {existing_rule.definition_location}
- The terminal was defined at {terminal.definition_location}""" - The terminal was defined at {terminal.definition_location}""")
)
named_terminals[terminal.name] = terminal named_terminals[terminal.name] = terminal