(define (top) (let ((__start *i*)) (r+ (stmt))))

(define (if_)
  (let ((__start *i*))
    (and (literal "if") (expr) (literal ":") (suite) (or (else_) #t))))

(define (else_)
  (let ((__start *i*)) (and (literal "else") (literal ":") (suite))))

(define (while_)
  (let ((__start *i*))
    (and (literal "while") (expr) (literal ":") (suite) (or (else_) #t))))

(define (for_)
  (let ((__start *i*))
    (and (literal "for") (expr) (literal ":") (suite) (or (else_) #t))))

(define (with_)
  (let ((__start *i*)) (and (literal "with") (expr) (literal ":") (suite))))

(define (def_)
  (let ((__start *i*) (n #f) (a #f) (s #f))
    (and (literal "def")
         (or (setf n (name)) #t)
         (literal "(")
         (setf a (r+ (argument)))
         (literal ")")
         (literal ":")
         (setf s (suite))
         (if n `(define (,n ,@a) ,s) `(lambda ,a ,s)))))

(define (class_)
  (let ((__start *i*))
    (and (literal "class")
         (name)
         (or (and (literal "(") (name) (literal ")")) #t)
         (literal ":")
         (suite))))

(define (try_)
  (let ((__start *i*))
    (and (literal "try")
         (literal ":")
         (suite)
         (r+ (or (and (literal "except") (literal ":") (suite)) #t))
         (or (else_) #t)
         (or (and (literal "finally") (literal ":") (suite)) #t))))

(define (suite)
  (let ((__start *i*) (s #f))
    (or (and (nl) (indent) (setf s (r+ (stmt))) (dedent))
        (and (setf s (stmtlist)) (nl))
        s)))

(define (stmt)
  (let ((__start *i*) (s #f))
    (or (setf s (compound)) (and (setf s (simple)) (nl)) s)))

(define (stmtlist)
  (let ((__start *i*) (s #f) (ss #f))
    (and (setf s (simple))
         (setf ss (r* (or (and (literal ";") (simple)) #t)))
         (or (literal ";") #t)
         (if (empty? ss) s (cons s ss)))))

(define (simple)
  (let ((__start *i*)) (or (pass) (return) (scope) (break) (continue) (expr))))

(define (compound)
  (let ((__start *i*))
    (or (def_) (class_) (if_) (while_) (for_) (try_) (with_))))

(define (scope)
  (let ((__start *i*) (kw #f) (ns #f))
    (and (setf kw (and (or (literal "global") (literal "nonlocal"))))
         (setf ns (r+ (name)))
         `(kw ,ns))))

(define (return) (let ((__start *i*)) (literal "return")))

(define (pass) (let ((__start *i*)) (literal "pass")))

(define (break) (let ((__start *i*)) (literal "break")))

(define (continue) (let ((__start *i*)) (literal "continue")))

(define (parens)
  (let ((__start *i*) (es #f))
    (and (literal "(")
         (setf es (r+ (and (and (expr) (literal ",")))))
         (literal ")")
         `(begin ,es))))

(define (value) (let ((__start *i*)) (or (scalar) (varref))))

(define (varref)
  (let ((__start *i*) (n #f) (a #f))
    (and (setf n (name))
         (or (and (literal "(") (setf a (r+ (parameter))) (literal ")")) #t)
         (if a `(n ,a) n))))

(define (parameter)
  (let ((__start *i*) (r #f) (k #f) (n #f) (d #f))
    (and (or (setf r (literal "*")) #t)
         (or (setf k (literal "*")) #t)
         (setf n (name))
         (or (setf d (default)) #t)
         (cond (k (kwarg n)) (r (restarg n)) (d (optarg n)) (else n)))))

(define (argument)
  (let ((__start *i*) (r #f) (k #f) (n #f) (t #f) (d #f))
    (and (or (setf r (literal "*")) #t)
         (or (setf k (literal "*")) #t)
         (setf n (name))
         (or (setf t (typetag)) #t)
         (or (setf d (default)) #t)
         (cond (k (kwarg n)) (r (restarg n)) (d (optarg n)) (else n)))))

(define (typetag) (let ((__start *i*)) (and (literal ":") (name))))

(define (default) (let ((__start *i*)) (and (literal "=") (expr))))

(define (scalar) (let ((__start *i*)) (or (number) (string) (bool) (List))))

(define (bool) (let ((__start *i*)) (or (True) (False) (None))))

(define (True) (let ((__start *i*)) (and (literal "True") #t)))

(define (False) (let ((__start *i*)) (and (literal "False") '#f)))

(define (None) (let ((__start *i*)) (and (literal "None") null)))

(define (List)
  (let ((__start *i*) (es #f))
    (and (literal "[")
         (setf es (or (and (expr) (r* (or (and (literal ",") (expr)) #t))) #t))
         (or (literal ",") #t)
         (literal "]"))))

