prodigy.pgcl.ppy_parser¶
Parser for .ppy¶
A Lark-based parser for the Python-like surface syntax .ppy (see the design
in docs/source/language-design.md). It produces the same AST as
prodigy.pgcl.parser for everything the old syntax can express, so the type
checker, the compiler and the analysis do not change.
Sugar is translated into the existing AST:
a missing
elsegives an emptyelsebranch,else ifa nestedIfInstr;switch (c) { case 1: {…} case 2, 3: {…} default: {…} }gives nestedif (c == 1) … else if (c == 2 or c == 3) … else …;categorical({v: p, …})andcategorical(p0, …, pn)give aCategoricalExpr;declarations at the top level of the program or of a function are collected into the declarations, an initial value becomes an assignment at the place of the declaration;
loop(N)with a constantNuses the constant’s literal value.
Two constructs have no counterpart in the old AST. They are parsed into
LocalDeclInstr (a declaration inside a block) and
Binop.FLOOR_DIVIDE (//), and the type checker rejects both as not
implemented yet.
Errors are raised as PpySyntaxError with line and column.
>>> parse_ppy("x: nat; x = unif(1, 6);").instructions
[AsgnInstr(lhs='x', rhs=FunctionCallExpr(function='unif', params=([NatLitExpr(1), NatLitExpr(6)], {})))]
- PPY_GRAMMAR = '\n start: item*\n\n ?item: statement\n | "const" NAME (":" type)? "=" expression ";" -> const_decl\n | "param" NAME ":" type ";" -> param_decl\n | "def" NAME "(" [def_params] ")" ("->" type)? "{" statement* "return" expression ";" "}" -> def_decl\n | "query" NAME "[" expression "]" ";" -> query\n | "print" ";" -> print_query\n | "plot" "(" NAME ("," NAME)? ("," plot_literal)? ")" ";" -> plot\n | "optimize" "(" expression "," NAME "," NAME ")" ";" -> optimize\n\n def_params: def_param ("," def_param)*\n def_param: NAME ":" type\n\n ?statement: "skip" ";" -> skip\n | "abort" ";" -> abort\n | NAME "=" expression ";" -> assign\n | names ":" type ("=" expression)? ";" -> var_decl\n | "tick" "(" expression ")" ";" -> tick\n | "observe" "(" expression ")" ";" -> observe\n | "while" "(" expression ")" block -> while_\n | if_statement\n | block "[" expression "]" block -> choice\n | "loop" "(" (INT | NAME) ")" block -> loop\n | "switch" "(" NAME ")" "{" case+ default? "}" -> switch\n | "query" block -> query_block\n | ";" -> empty\n\n if_statement: "if" "(" expression ")" block ("else" (block | if_statement))?\n\n case: "case" expression ("," expression)* ":" block\n default: "default" ":" block\n\n block: "{" statement* "}"\n\n names: NAME ("," NAME)*\n\n type: "nat" bounds? -> nat_type\n | "real" -> real_type\n | "bool" -> bool_type\n | "dist" -> dist_type\n\n bounds: "[" expression "," expression "]"\n\n plot_literal: INT -> nat_lit\n | FLOAT -> real_lit\n | INFINITY -> infinity\n\n ?expression: or_expr\n\n ?or_expr: and_expr\n | or_expr "or" and_expr -> or_\n | or_expr "||" and_expr -> or_\n\n ?and_expr: not_expr\n | and_expr "and" not_expr -> and_\n | and_expr "&&" not_expr -> and_\n\n ?not_expr: comparison\n | "not" not_expr -> not_\n | "!" not_expr -> not_\n\n ?comparison: sum\n | sum "<=" sum -> leq\n | sum "<" sum -> lt\n | sum ">" sum -> gt\n | sum ">=" sum -> geq\n | sum "==" sum -> eq\n\n ?sum: term\n | sum "+" term -> plus\n | sum "-" term -> minus\n\n ?term: factor\n | term "*" factor -> times\n | term "/" factor -> divide\n | term "//" factor -> floor_divide\n | term "%" factor -> mod\n\n ?factor: power\n | "-" factor -> uminus\n\n ?power: atom\n | atom "**" factor -> power\n\n ?atom: INT -> nat_lit\n | FLOAT -> real_lit\n | INFINITY -> infinity\n | "true" -> true\n | "false" -> false\n | NAME -> var\n | NAME "(" [arguments] ")" -> call\n | "categorical" "(" categories ")" -> categorical\n | "infer" "(" NAME ("," arguments)? ")" -> infer\n | "sample" "(" NAME ")" -> sample\n | "(" expression ")"\n | "[" expression "]" -> iverson\n\n arguments: argument ("," argument)*\n ?argument: expression\n | NAME "=" expression -> named_argument\n\n ?categories: "{" category ("," category)* "}" -> category_dict\n | expression ("," expression)* -> category_list\n category: expression ":" expression\n\n INFINITY: "∞" | "\\\\infty"\n\n %import common.CNAME -> NAME\n %import common.INT\n %import common.FLOAT\n %import common.WS\n\n COMMENT: /#[^\\n]*/\n %ignore COMMENT\n %ignore WS\n'¶
or<and<not< comparisons <+ -<* / // %< unary-<**.- Type:
The Lark grammar of
.ppy. Precedences follow Python
- PPY_KEYWORDS = frozenset({'abort', 'and', 'bool', 'case', 'categorical', 'const', 'def', 'default', 'dist', 'else', 'false', 'if', 'infer', 'loop', 'nat', 'not', 'observe', 'optimize', 'or', 'param', 'plot', 'print', 'query', 'real', 'return', 'sample', 'skip', 'switch', 'tick', 'true', 'while'})¶
Words that cannot be used as names in
.ppy.
- exception PpySyntaxError(message, line, column)[source]¶
Bases:
SyntaxErrorA syntax error in a
.ppyprogram, with line and column (1-based).
- parse_ppy(code)[source]¶
Parse a program in the
.ppysyntax.>>> parse_ppy("x: nat = 3; if (x == 3) { skip; }").instructions[1] IfInstr(cond=BinopExpr(operator=Binop.EQ, lhs=VarExpr('x'), rhs=NatLitExpr(3)), true=[SkipInstr()], false=[]) >>> parse_ppy("x: nat; x = 1 +;") Traceback (most recent call last): ... prodigy.pgcl.ppy_parser.PpySyntaxError: line 1, column 16: Unexpected ';', expected ... or a number.
- Parameters:
code (
str)- Return type:
Program
- parse_ppy_expr(code)[source]¶
Parse an expression in the
.ppysyntax.>>> parse_ppy_expr("not z or x") BinopExpr(operator=Binop.OR, lhs=UnopExpr(operator=Unop.NEG, expr=VarExpr('z')), rhs=VarExpr('x'))
- Parameters:
code (
str)- Return type:
VarExpr|BoolLitExpr|NatLitExpr|RealLitExpr|UnopExpr|BinopExpr|CategoricalExpr|SubstExpr|TickExpr|FunctionCallExpr|InferExpr|SampleExpr