Muck around with usability
This commit is contained in:
parent
cd62b65789
commit
02c1aa507e
2 changed files with 135 additions and 102 deletions
136
grammar.py
136
grammar.py
|
|
@ -1,8 +1,5 @@
|
||||||
# This is an example grammar.
|
# This is an example grammar.
|
||||||
import re
|
from parser import Assoc, Grammar, Nothing, rule, seq, Rule, Terminal, Re, Highlight, mark, opt
|
||||||
import typing
|
|
||||||
|
|
||||||
from parser import Assoc, Grammar, Nothing, rule, seq, Rule, Terminal, Re, TerminalKind
|
|
||||||
|
|
||||||
|
|
||||||
class FineGrammar(Grammar):
|
class FineGrammar(Grammar):
|
||||||
|
|
@ -53,7 +50,11 @@ class FineGrammar(Grammar):
|
||||||
|
|
||||||
@rule("ClassDeclaration")
|
@rule("ClassDeclaration")
|
||||||
def class_declaration(self) -> Rule:
|
def class_declaration(self) -> Rule:
|
||||||
return seq(self.CLASS, self.IDENTIFIER, self._class_body)
|
return seq(
|
||||||
|
self.CLASS,
|
||||||
|
mark(self.IDENTIFIER, highlight=Highlight.Entity.Name.Type),
|
||||||
|
self._class_body,
|
||||||
|
)
|
||||||
|
|
||||||
@rule
|
@rule
|
||||||
def _class_body(self) -> Rule:
|
def _class_body(self) -> Rule:
|
||||||
|
|
@ -100,21 +101,23 @@ class FineGrammar(Grammar):
|
||||||
# Functions
|
# Functions
|
||||||
@rule("FunctionDecl")
|
@rule("FunctionDecl")
|
||||||
def function_declaration(self) -> Rule:
|
def function_declaration(self) -> Rule:
|
||||||
return seq(self.FUN, self.IDENTIFIER, self.function_parameters, self.block) | seq(
|
return seq(
|
||||||
self.FUN,
|
self.FUN,
|
||||||
self.IDENTIFIER,
|
mark(self.IDENTIFIER, highlight=Highlight.Entity.Name.Function),
|
||||||
self.function_parameters,
|
self.function_parameters,
|
||||||
self.ARROW,
|
opt(self.ARROW, self.type_expression),
|
||||||
self.type_expression,
|
|
||||||
self.block,
|
self.block,
|
||||||
)
|
)
|
||||||
|
|
||||||
@rule("ParamList")
|
@rule("ParamList")
|
||||||
def function_parameters(self) -> Rule:
|
def function_parameters(self) -> Rule:
|
||||||
return (
|
return seq(
|
||||||
seq(self.LPAREN, self.RPAREN)
|
self.LPAREN,
|
||||||
| seq(self.LPAREN, self._first_parameter, self.RPAREN)
|
opt(
|
||||||
| seq(self.LPAREN, self._first_parameter, self.COMMA, self._parameter_list, self.RPAREN)
|
self._first_parameter,
|
||||||
|
opt(self.COMMA, self._parameter_list),
|
||||||
|
),
|
||||||
|
self.RPAREN,
|
||||||
)
|
)
|
||||||
|
|
||||||
@rule
|
@rule
|
||||||
|
|
@ -132,11 +135,10 @@ class FineGrammar(Grammar):
|
||||||
# Block
|
# Block
|
||||||
@rule("Block")
|
@rule("Block")
|
||||||
def block(self) -> Rule:
|
def block(self) -> Rule:
|
||||||
return (
|
return seq(
|
||||||
seq(self.LCURLY, self.RCURLY)
|
self.LCURLY,
|
||||||
| seq(self.LCURLY, self.expression, self.RCURLY)
|
opt(opt(self._statement_list), self.expression)
|
||||||
| seq(self.LCURLY, self._statement_list, self.RCURLY)
|
self.RCURLY,
|
||||||
| seq(self.LCURLY, self._statement_list, self.expression, self.RCURLY)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@rule
|
@rule
|
||||||
|
|
@ -326,32 +328,32 @@ class FineGrammar(Grammar):
|
||||||
BLANKS = Terminal(Re.set(" ", "\t", "\r", "\n").plus())
|
BLANKS = Terminal(Re.set(" ", "\t", "\r", "\n").plus())
|
||||||
COMMENT = Terminal(
|
COMMENT = Terminal(
|
||||||
Re.seq(Re.literal("//"), Re.set("\n").invert().star()),
|
Re.seq(Re.literal("//"), Re.set("\n").invert().star()),
|
||||||
kind=TerminalKind.Comment.Line,
|
highlight=Highlight.Comment.Line,
|
||||||
)
|
)
|
||||||
|
|
||||||
ARROW = Terminal("->", kind=TerminalKind.Keyword.Operator)
|
ARROW = Terminal("->", highlight=Highlight.Keyword.Operator)
|
||||||
AS = Terminal("as", kind=TerminalKind.Keyword.Operator.Expression)
|
AS = Terminal("as", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
BAR = Terminal("|", kind=TerminalKind.Keyword.Operator.Expression)
|
BAR = Terminal("|", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
CLASS = Terminal("class", kind=TerminalKind.Storage.Type.Class)
|
CLASS = Terminal("class", highlight=Highlight.Storage.Type.Class)
|
||||||
COLON = Terminal(":", kind=TerminalKind.Punctuation.Separator)
|
COLON = Terminal(":", highlight=Highlight.Punctuation.Separator)
|
||||||
ELSE = Terminal("else", kind=TerminalKind.Keyword.Control.Conditional)
|
ELSE = Terminal("else", highlight=Highlight.Keyword.Control.Conditional)
|
||||||
FOR = Terminal("for", kind=TerminalKind.Keyword.Control)
|
FOR = Terminal("for", highlight=Highlight.Keyword.Control)
|
||||||
FUN = Terminal("fun", kind=TerminalKind.Storage.Type.Function)
|
FUN = Terminal("fun", highlight=Highlight.Storage.Type.Function)
|
||||||
IDENTIFIER = Terminal(
|
IDENTIFIER = Terminal(
|
||||||
Re.seq(
|
Re.seq(
|
||||||
Re.set(("a", "z"), ("A", "Z"), "_"),
|
Re.set(("a", "z"), ("A", "Z"), "_"),
|
||||||
Re.set(("a", "z"), ("A", "Z"), ("0", "9"), "_").star(),
|
Re.set(("a", "z"), ("A", "Z"), ("0", "9"), "_").star(),
|
||||||
),
|
),
|
||||||
# kind=TerminalKind.Variable, #?
|
# highlight=Highlight.Variable, #?
|
||||||
)
|
)
|
||||||
IF = Terminal("if", kind=TerminalKind.Keyword.Control.Conditional)
|
IF = Terminal("if", highlight=Highlight.Keyword.Control.Conditional)
|
||||||
IMPORT = Terminal("import", kind=TerminalKind.Keyword.Other)
|
IMPORT = Terminal("import", highlight=Highlight.Keyword.Other)
|
||||||
IN = Terminal("in", kind=TerminalKind.Keyword.Operator)
|
IN = Terminal("in", highlight=Highlight.Keyword.Operator)
|
||||||
LCURLY = Terminal("{", kind=TerminalKind.Punctuation.CurlyBrace.Open)
|
LCURLY = Terminal("{", highlight=Highlight.Punctuation.CurlyBrace.Open)
|
||||||
RCURLY = Terminal("}", kind=TerminalKind.Punctuation.CurlyBrace.Close)
|
RCURLY = Terminal("}", highlight=Highlight.Punctuation.CurlyBrace.Close)
|
||||||
LET = Terminal("let", kind=TerminalKind.Keyword.Other)
|
LET = Terminal("let", highlight=Highlight.Keyword.Other)
|
||||||
RETURN = Terminal("return", kind=TerminalKind.Keyword.Control)
|
RETURN = Terminal("return", highlight=Highlight.Keyword.Control)
|
||||||
SEMICOLON = Terminal(";", kind=TerminalKind.Punctuation.Separator)
|
SEMICOLON = Terminal(";", highlight=Highlight.Punctuation.Separator)
|
||||||
STRING = Terminal(
|
STRING = Terminal(
|
||||||
# Double-quoted string.
|
# Double-quoted string.
|
||||||
Re.seq(
|
Re.seq(
|
||||||
|
|
@ -365,27 +367,27 @@ class FineGrammar(Grammar):
|
||||||
(~Re.set("'", "\\") | (Re.set("\\") + Re.any())).star(),
|
(~Re.set("'", "\\") | (Re.set("\\") + Re.any())).star(),
|
||||||
Re.literal("'"),
|
Re.literal("'"),
|
||||||
),
|
),
|
||||||
kind=TerminalKind.String.Quoted,
|
highlight=Highlight.String.Quoted,
|
||||||
)
|
)
|
||||||
WHILE = Terminal("while", kind=TerminalKind.Keyword.Control)
|
WHILE = Terminal("while", highlight=Highlight.Keyword.Control)
|
||||||
EQUAL = Terminal("=", kind=TerminalKind.Keyword.Operator.Expression)
|
EQUAL = Terminal("=", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
LPAREN = Terminal("(", kind=TerminalKind.Punctuation.Parenthesis.Open)
|
LPAREN = Terminal("(", highlight=Highlight.Punctuation.Parenthesis.Open)
|
||||||
RPAREN = Terminal(")", kind=TerminalKind.Punctuation.Parenthesis.Close)
|
RPAREN = Terminal(")", highlight=Highlight.Punctuation.Parenthesis.Close)
|
||||||
COMMA = Terminal(",", kind=TerminalKind.Punctuation.Separator)
|
COMMA = Terminal(",", highlight=Highlight.Punctuation.Separator)
|
||||||
SELF = Terminal("self", name="SELFF", kind=TerminalKind.Variable.Language)
|
SELF = Terminal("self", name="SELFF", highlight=Highlight.Variable.Language)
|
||||||
OR = Terminal("or", kind=TerminalKind.Keyword.Operator.Expression)
|
OR = Terminal("or", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
IS = Terminal("is", kind=TerminalKind.Keyword.Operator.Expression)
|
IS = Terminal("is", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
AND = Terminal("and", kind=TerminalKind.Keyword.Operator.Expression)
|
AND = Terminal("and", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
EQUALEQUAL = Terminal("==", kind=TerminalKind.Keyword.Operator.Expression)
|
EQUALEQUAL = Terminal("==", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
BANGEQUAL = Terminal("!=", kind=TerminalKind.Keyword.Operator.Expression)
|
BANGEQUAL = Terminal("!=", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
LESS = Terminal("<", kind=TerminalKind.Keyword.Operator.Expression)
|
LESS = Terminal("<", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
GREATER = Terminal(">", kind=TerminalKind.Keyword.Operator.Expression)
|
GREATER = Terminal(">", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
LESSEQUAL = Terminal("<=", kind=TerminalKind.Keyword.Operator.Expression)
|
LESSEQUAL = Terminal("<=", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
GREATEREQUAL = Terminal(">=", kind=TerminalKind.Keyword.Operator.Expression)
|
GREATEREQUAL = Terminal(">=", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
PLUS = Terminal("+", kind=TerminalKind.Keyword.Operator.Expression)
|
PLUS = Terminal("+", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
MINUS = Terminal("-", kind=TerminalKind.Keyword.Operator.Expression)
|
MINUS = Terminal("-", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
STAR = Terminal("*", kind=TerminalKind.Keyword.Operator.Expression)
|
STAR = Terminal("*", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
SLASH = Terminal("/", kind=TerminalKind.Keyword.Operator.Expression)
|
SLASH = Terminal("/", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
NUMBER = Terminal(
|
NUMBER = Terminal(
|
||||||
Re.seq(
|
Re.seq(
|
||||||
Re.set(("0", "9")).plus(),
|
Re.set(("0", "9")).plus(),
|
||||||
|
|
@ -399,18 +401,18 @@ class FineGrammar(Grammar):
|
||||||
Re.set(("0", "9")).plus(),
|
Re.set(("0", "9")).plus(),
|
||||||
).question(),
|
).question(),
|
||||||
),
|
),
|
||||||
kind=TerminalKind.Constant.Numeric,
|
highlight=Highlight.Constant.Numeric,
|
||||||
)
|
)
|
||||||
TRUE = Terminal("true", kind=TerminalKind.Constant.Language)
|
TRUE = Terminal("true", highlight=Highlight.Constant.Language)
|
||||||
FALSE = Terminal("false", kind=TerminalKind.Constant.Language)
|
FALSE = Terminal("false", highlight=Highlight.Constant.Language)
|
||||||
BANG = Terminal("!", kind=TerminalKind.Keyword.Operator.Expression)
|
BANG = Terminal("!", highlight=Highlight.Keyword.Operator.Expression)
|
||||||
DOT = Terminal(".", kind=TerminalKind.Punctuation.Separator)
|
DOT = Terminal(".", highlight=Highlight.Punctuation.Separator)
|
||||||
MATCH = Terminal("match", kind=TerminalKind.Keyword.Other)
|
MATCH = Terminal("match", highlight=Highlight.Keyword.Other)
|
||||||
EXPORT = Terminal("export", kind=TerminalKind.Keyword.Other)
|
EXPORT = Terminal("export", highlight=Highlight.Keyword.Other)
|
||||||
UNDERSCORE = Terminal("_", kind=TerminalKind.Variable.Language)
|
UNDERSCORE = Terminal("_", highlight=Highlight.Variable.Language)
|
||||||
NEW = Terminal("new", kind=TerminalKind.Keyword.Operator)
|
NEW = Terminal("new", highlight=Highlight.Keyword.Operator)
|
||||||
LSQUARE = Terminal("[", kind=TerminalKind.Punctuation.SquareBracket.Open)
|
LSQUARE = Terminal("[", highlight=Highlight.Punctuation.SquareBracket.Open)
|
||||||
RSQUARE = Terminal("]", kind=TerminalKind.Punctuation.SquareBracket.Close)
|
RSQUARE = Terminal("]", highlight=Highlight.Punctuation.SquareBracket.Close)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
101
parser/parser.py
101
parser/parser.py
|
|
@ -1715,6 +1715,19 @@ class NothingRule(Rule):
|
||||||
Nothing = NothingRule()
|
Nothing = NothingRule()
|
||||||
|
|
||||||
|
|
||||||
|
class OptionalRule(Rule):
|
||||||
|
"""A rule that matches if one or another rule matches."""
|
||||||
|
|
||||||
|
def __init__(self, rule: Rule):
|
||||||
|
self.rule = rule
|
||||||
|
|
||||||
|
def flatten(self) -> typing.Generator[list[str | Terminal], None, None]:
|
||||||
|
# All the things from the left of the alternative, then all the things
|
||||||
|
# from the right, never intermingled.
|
||||||
|
yield from self.rule.flatten()
|
||||||
|
yield from Nothing.flatten()
|
||||||
|
|
||||||
|
|
||||||
def seq(*args: Rule) -> Rule:
|
def seq(*args: Rule) -> Rule:
|
||||||
"""A rule that matches a sequence of rules.
|
"""A rule that matches a sequence of rules.
|
||||||
|
|
||||||
|
|
@ -1726,6 +1739,16 @@ def seq(*args: Rule) -> Rule:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def opt(*args: Rule) -> Rule:
|
||||||
|
return OptionalRule(seq(*args))
|
||||||
|
|
||||||
|
|
||||||
|
def mark(rule: Rule, **kwargs) -> Rule:
|
||||||
|
# TODO: Figure out how to incorporate this into the world.
|
||||||
|
del kwargs
|
||||||
|
return rule
|
||||||
|
|
||||||
|
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def rule(f: typing.Callable, /) -> Rule: ...
|
def rule(f: typing.Callable, /) -> Rule: ...
|
||||||
|
|
||||||
|
|
@ -2554,78 +2577,86 @@ def dump_lexer_table(table: LexerTable, name: str = "lexer.dot"):
|
||||||
# This here might be enough to produce extremely basic TextMate
|
# This here might be enough to produce extremely basic TextMate
|
||||||
# grammars but anything more complicated will want tree patterns
|
# grammars but anything more complicated will want tree patterns
|
||||||
# anyway, and we can only do tree patterns by influencing the grammar.
|
# anyway, and we can only do tree patterns by influencing the grammar.
|
||||||
class TerminalMeta:
|
class SyntaxMeta:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TerminalKind(TerminalMeta):
|
class Highlight(SyntaxMeta):
|
||||||
class Comment(TerminalMeta):
|
class Comment(SyntaxMeta):
|
||||||
class Block(TerminalMeta):
|
class Block(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Line(TerminalMeta):
|
class Line(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Constant(TerminalMeta):
|
class Constant(SyntaxMeta):
|
||||||
class Language(TerminalMeta):
|
class Language(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Numeric(TerminalMeta):
|
class Numeric(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Keyword(TerminalMeta):
|
class Entity(SyntaxMeta):
|
||||||
class Control(TerminalMeta):
|
class Name(SyntaxMeta):
|
||||||
class Conditional(TerminalMeta):
|
class Function(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Operator(TerminalMeta):
|
class Type(SyntaxMeta):
|
||||||
class Expression(TerminalMeta):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Other(TerminalMeta):
|
class Keyword(SyntaxMeta):
|
||||||
|
class Control(SyntaxMeta):
|
||||||
|
class Conditional(SyntaxMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Operator(SyntaxMeta):
|
||||||
|
class Expression(SyntaxMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Other(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Punctuation(TerminalMeta):
|
class Punctuation(SyntaxMeta):
|
||||||
class Separator(TerminalMeta):
|
class Separator(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Parenthesis(TerminalMeta):
|
class Parenthesis(SyntaxMeta):
|
||||||
class Open(TerminalMeta):
|
class Open(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Close(TerminalMeta):
|
class Close(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class CurlyBrace(TerminalMeta):
|
class CurlyBrace(SyntaxMeta):
|
||||||
class Open(TerminalMeta):
|
class Open(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Close(TerminalMeta):
|
class Close(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class SquareBracket(TerminalMeta):
|
class SquareBracket(SyntaxMeta):
|
||||||
class Open(TerminalMeta):
|
class Open(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Close(TerminalMeta):
|
class Close(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Storage(TerminalMeta):
|
class Storage(SyntaxMeta):
|
||||||
class Type(TerminalMeta):
|
class Type(SyntaxMeta):
|
||||||
class Class(TerminalMeta):
|
class Class(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Function(TerminalMeta):
|
class Function(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class String(TerminalMeta):
|
class String(SyntaxMeta):
|
||||||
class Quoted(TerminalMeta):
|
class Quoted(SyntaxMeta):
|
||||||
class Single(TerminalMeta):
|
class Single(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Double(TerminalMeta):
|
class Double(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Variable(TerminalMeta):
|
class Variable(SyntaxMeta):
|
||||||
class Language(TerminalMeta):
|
class Language(SyntaxMeta):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue