An example based on a language I once knew
This commit is contained in:
parent
0af5cfe2ee
commit
0ddf166e4e
1 changed files with 233 additions and 0 deletions
233
examples/lens.py
Normal file
233
examples/lens.py
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
from parser import *
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def expression():
|
||||||
|
return alt(
|
||||||
|
TRUE | FALSE | NUMBER | NAME,
|
||||||
|
LPAREN + expression + RPAREN,
|
||||||
|
binary_expression,
|
||||||
|
object_expression,
|
||||||
|
with_expression,
|
||||||
|
function_expression,
|
||||||
|
invoke_expression,
|
||||||
|
member_expression,
|
||||||
|
statement_block_expression,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def binary_expression():
|
||||||
|
return alt(
|
||||||
|
expression + PLUS + expression,
|
||||||
|
expression + STAR + expression,
|
||||||
|
expression + MINUS + expression,
|
||||||
|
expression + SLASH + expression,
|
||||||
|
expression + LESSER + expression,
|
||||||
|
expression + GREATER + expression,
|
||||||
|
expression + LESSER_EQUAL + expression,
|
||||||
|
expression + GREATER_EQUAL + expression,
|
||||||
|
expression + EQUAL_EQUAL + expression,
|
||||||
|
expression + AND + expression,
|
||||||
|
expression + OR + expression,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def object_expression():
|
||||||
|
return LCURLY + zero_or_more(value_pair + opt(COMMA)) + RCURLY
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def value_pair():
|
||||||
|
return value_name + opt(EQUAL, expression)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def value_name():
|
||||||
|
return NAME | LSQUARE + expression + RSQUARE
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def with_expression():
|
||||||
|
return WITH + object_expression + YIELD + expression
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def function_expression():
|
||||||
|
return FN + opt(param_list) + FAT_ARROW + expression
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def param_list():
|
||||||
|
return zero_or_more(NAME + COMMA) + NAME + opt(COMMA)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def invoke_expression():
|
||||||
|
return seq(
|
||||||
|
expression,
|
||||||
|
LPAREN,
|
||||||
|
opt(
|
||||||
|
zero_or_more(expression + COMMA),
|
||||||
|
expression + opt(COMMA),
|
||||||
|
),
|
||||||
|
RPAREN,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def member_expression():
|
||||||
|
return expression + DOT + NAME
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def statement_block_expression():
|
||||||
|
return DO + statement_list + YIELD + expression
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def statement_list():
|
||||||
|
return zero_or_more(_statement)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def _statement():
|
||||||
|
return alt(
|
||||||
|
assignment_statement,
|
||||||
|
if_statement,
|
||||||
|
declaration_statement,
|
||||||
|
while_loop,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def assignment_statement():
|
||||||
|
return (
|
||||||
|
NAME
|
||||||
|
+ alt(COLON_EQUAL, PLUS_EQUAL, MINUS_EQUAL, STAR_EQUAL, SLASH_EQUAL)
|
||||||
|
+ expression
|
||||||
|
+ SEMICOLON
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def if_statement():
|
||||||
|
return IF + expression + THEN + statement_list + END
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def declaration_statement():
|
||||||
|
return VAR + NAME + COLON_EQUAL + expression + SEMICOLON
|
||||||
|
|
||||||
|
|
||||||
|
@rule
|
||||||
|
def while_loop():
|
||||||
|
return WHILE + expression + DO + statement_list + END
|
||||||
|
|
||||||
|
|
||||||
|
BLANKS = Terminal("BLANKS", Re.set(" ", "\t", "\r", "\n").plus())
|
||||||
|
COMMENT = Terminal("COMMENT", Re.seq(Re.literal("//"), Re.set("\n").invert().star()))
|
||||||
|
|
||||||
|
TRUE = Terminal("TRUE", "true")
|
||||||
|
FALSE = Terminal("FALSE", "false")
|
||||||
|
|
||||||
|
NUMBER = Terminal(
|
||||||
|
"NUMBER",
|
||||||
|
Re.seq(
|
||||||
|
Re.set(("0", "9")).plus(),
|
||||||
|
Re.seq(
|
||||||
|
Re.literal("."),
|
||||||
|
Re.set(("0", "9")).plus(),
|
||||||
|
).question(),
|
||||||
|
Re.seq(
|
||||||
|
Re.set("e", "E"),
|
||||||
|
Re.set("+", "-").question(),
|
||||||
|
Re.set(("0", "9")).plus(),
|
||||||
|
).question(),
|
||||||
|
),
|
||||||
|
highlight=highlight.constant.numeric,
|
||||||
|
)
|
||||||
|
|
||||||
|
FN = Terminal("FN", "fn")
|
||||||
|
ARROW = Terminal("ARROW", "->")
|
||||||
|
FAT_ARROW = Terminal("FAT_ARROW", "=>")
|
||||||
|
|
||||||
|
COMMA = Terminal("COMMA", ",")
|
||||||
|
LPAREN = Terminal("LPAREN", "(")
|
||||||
|
RPAREN = Terminal("RPAREN", ")")
|
||||||
|
LCURLY = Terminal("LCURLY", "{")
|
||||||
|
RCURLY = Terminal("RCURLY", "}")
|
||||||
|
LSQUARE = Terminal("LSQUARE", "[")
|
||||||
|
RSQUARE = Terminal("RSQUARE", "]")
|
||||||
|
COLON = Terminal("COLON", ":")
|
||||||
|
SEMICOLON = Terminal("SEMICOLON", ";")
|
||||||
|
LET = Terminal("LET", "let")
|
||||||
|
EQUAL = Terminal("EQUAL", "=")
|
||||||
|
RETURN = Terminal("RETURN", "return")
|
||||||
|
PLUS = Terminal("PLUS", "+")
|
||||||
|
PLUS_EQUAL = Terminal("PLUS_EQUAL", "+=")
|
||||||
|
MINUS = Terminal("MINUS", "-")
|
||||||
|
MINUS_EQUAL = Terminal("MINUS_EQUAL", "-=")
|
||||||
|
STAR = Terminal("STAR", "*")
|
||||||
|
STAR_EQUAL = Terminal("STAR_EQUAL", "*=")
|
||||||
|
SLASH = Terminal("SLASH", "/")
|
||||||
|
SLASH_EQUAL = Terminal("SLASH_EQUAL", "/=")
|
||||||
|
DOT = Terminal("DOT", ".")
|
||||||
|
|
||||||
|
# Design: A different assignment operator to make sure we
|
||||||
|
# don't get confused.
|
||||||
|
COLON_EQUAL = Terminal("COLON_EQUAL", ":=")
|
||||||
|
|
||||||
|
GREATER = Terminal("GREATER", ">")
|
||||||
|
GREATER_EQUAL = Terminal("GREATER_EQUAL", ">=")
|
||||||
|
LESSER = Terminal("LESSER", "<")
|
||||||
|
LESSER_EQUAL = Terminal("LESSER_EQUAL", "<=")
|
||||||
|
EQUAL_EQUAL = Terminal("EQUAL_EQUAL", "==")
|
||||||
|
AND = Terminal("AND", "and")
|
||||||
|
OR = Terminal("OR", "or")
|
||||||
|
NOT = Terminal("NOT", "not")
|
||||||
|
|
||||||
|
# I like `DO -> YIELD` instead of `BEGIN -> YIELD`
|
||||||
|
# A `YIELD` at the end instead of a generic "last expression"
|
||||||
|
# setup because I want to be explicit that blocks yield values
|
||||||
|
# and you don't get the wrong one by accident!
|
||||||
|
DO = Terminal("DO", "do")
|
||||||
|
IF = Terminal("IF", "if")
|
||||||
|
THEN = Terminal("THEN", "then")
|
||||||
|
END = Terminal("END", "end")
|
||||||
|
WHILE = Terminal("WHILE", "while")
|
||||||
|
|
||||||
|
# I just like explicit variable declaration, otherwise
|
||||||
|
# sometimes you don't mean to make a new variable but
|
||||||
|
# make a typeo and do. :(
|
||||||
|
#
|
||||||
|
# This also allows you to control shadowing.
|
||||||
|
VAR = Terminal("VAR", "var")
|
||||||
|
|
||||||
|
|
||||||
|
WITH = Terminal("WITH", "with")
|
||||||
|
YIELD = Terminal("YIELD", "yield")
|
||||||
|
|
||||||
|
NAME = Terminal(
|
||||||
|
"NAME",
|
||||||
|
Re.seq(
|
||||||
|
Re.set(("a", "z"), ("A", "Z"), "_"),
|
||||||
|
Re.set(("a", "z"), ("A", "Z"), ("0", "9"), "_").star(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
LensGrammar = Grammar(
|
||||||
|
name="Lens",
|
||||||
|
start=expression,
|
||||||
|
trivia=[BLANKS, COMMENT],
|
||||||
|
precedence=[
|
||||||
|
(Assoc.LEFT, [OR]),
|
||||||
|
(Assoc.LEFT, [AND]),
|
||||||
|
(Assoc.LEFT, [EQUAL_EQUAL, LESSER_EQUAL, LESSER, GREATER_EQUAL, GREATER]),
|
||||||
|
(Assoc.LEFT, [PLUS, MINUS]),
|
||||||
|
(Assoc.LEFT, [STAR, SLASH]),
|
||||||
|
(Assoc.LEFT, [LPAREN]),
|
||||||
|
(Assoc.LEFT, [DOT]),
|
||||||
|
],
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue