New Syntax -- with an implementation

Donald Beaudry (don@vicorp.com)
Tue, 31 May 94 16:17:15 EDT

Well, here is that syntax patch that I promised. The goal is to
provide optionally-required-end-statements. That is, it makes it
possible (optional) to write compound statements that are terminated
by a required end statement. This is not to be confused with
optionally allowing an end statement. An optional end statement is of
no more value than a comment that says '# end'. When writing the
initial part of a compound statement (if, while, etc), the programmer
must decide then if the statement will be terminated by an end
statement. This makes it possible for the parser to check that it was
in fact terminated with an end statement.

It works like this: any place a colon is currently required, (except
in dictionary) it may be omitted. Omitting the colon is a signal to
the parser that an explicit terminator will follow. Now, what is an
explicit terminator? Take a look at the 'if' statement. An explicit
terminator is either an 'end', 'elif', or 'else' statement. An elif,
with the colon omitted, can be terminated by an 'end', 'else', or
another 'elif'. An 'else' with the colon omitted must be terminated
by an 'end'.

Thus both,

if a == b
print a
else
print b
end

and
if a == b:
print a
else:
print b

are valid. Note that as far as I can tell this change does not break
any existing code. But, a change that I would not mind seeing, which
would break existing code, would be to limit to one the number of
statements allowed after the colon. Making this additional change
would be as simple as it would be controversial, but making it would
pave the way for implementing a clean solution to the "multi-line
lambda problem" which was discussed previously.

So, rather than going though a long winded discussion of each of the
cases, I put together the following patch. Changes only need to be
made to Grammar/Grammar and Python/compile.c. After applying the
patch, you must run Parser/pgen on the new grammar and install the
resulting graminit.c into Python/graminit.c and the resulting
graminit.h into Include/graminit.h, then rebuild everything (actually
just relinking will work, but since graminit.h changed everything that
depends on should also be recompiled).

--Don

______ ______
\_\_\_\ /#/#/#/
\_\_\_\ ______
\_\_\_V#/#/#/ Donald Beaudry don@vicorp.com
\_\_/#/#/#/ V. I. Corporation uunet!vicorp!don
\_/#/#/#/ 47 Pleasant Street PHONE: (413) 586-4144
V#/#/#/ Northampton, MA 01060 FAX: (413) 586-3805

------------------------------<cut here>------------------------------

Index: Grammar/Grammar
*** /vi/python/1.0.2/Grammar/Grammar Wed May 4 03:40:09 1994
--- Grammar/Grammar Tue May 31 13:59:31 1994
***************
*** 86,91 ****
--- 86,92 ----
# added 'from' NAME option on import clause, and '*' to import all;
# added class definition.

+
# Start symbols for the grammar:
# single_input is a single interactive statement;
# file_input is a module or sequence of commands read from an input file;
***************
*** 96,103 ****
file_input: (NEWLINE | stmt)* ENDMARKER
eval_input: testlist NEWLINE* ENDMARKER

! funcdef: 'def' NAME parameters ':' suite
! parameters: '(' [varargslist] ')'
varargslist: (fpdef ['=' test] ',')* '*' NAME | fpdef ['=' test] (',' fpdef ['=' test])* [',']
fpdef: NAME | '(' fplist ')'
fplist: fpdef (',' fpdef)* [',']
--- 97,105 ----
file_input: (NEWLINE | stmt)* ENDMARKER
eval_input: testlist NEWLINE* ENDMARKER

! funcdef: 'def' NAME '(' [varargslist] ')' ':' suite \
! | 'def' NAME '(' [varargslist] ')' stmt_block end_clause
!
varargslist: (fpdef ['=' test] ',')* '*' NAME | fpdef ['=' test] (',' fpdef ['=' test])* [',']
fpdef: NAME | '(' fplist ')'
fplist: fpdef (',' fpdef)* [',']
***************
*** 124,137 ****
exec_stmt: 'exec' expr ['in' test [',' test]]

compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
! if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
! while_stmt: 'while' test ':' suite ['else' ':' suite]
! for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
! try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite
! # NB compile.c makes sure that the default except clause is last
! except_clause: 'except' [test [',' test]]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

test: and_test ('or' and_test)* | lambdef
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
--- 126,165 ----
exec_stmt: 'exec' expr ['in' test [',' test]]

compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
!
! if_stmt: 'if' test ':' suite [elif_clause] \
! | 'if' test stmt_block (elif_clause | end_clause)
!
! elif_clause: 'elif' test ':' suite [elif_clause] \
! | 'elif' test stmt_block (elif_clause | end_clause) \
! | else_clause
!
! else_clause: 'else' ':' suite \
! | 'else' stmt_block end_clause
!
! while_stmt: 'while' test ':' suite [else_clause] \
! | 'while' test stmt_block (else_clause | end_clause)
!
! for_stmt: 'for' exprlist 'in' testlist ':' suite [else_clause] \
! | 'for' exprlist 'in' testlist stmt_block (else_clause | end_clause)
!
! try_stmt: 'try' ':' suite except_clause+ [else_clause] \
! | 'try' stmt_block except_clause+ (else_clause | end_clause) \
! | 'try' ':' suite finally_clause \
! | 'try' stmt_block finally_clause
!
! finally_clause: 'finally' ':' suite \
! | 'finally' stmt_block end_clause
!
! except_clause: 'except' [test [',' test]] ':' suite \
! | 'except' [test [',' test]] stmt_block
!
! end_clause: 'end' NEWLINE
!
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

+ stmt_block: NEWLINE INDENT stmt+ DEDENT
+
test: and_test ('or' and_test)* | lambdef
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
***************
*** 152,155 ****
testlist: test (',' test)* [',']
dictmaker: test ':' test (',' test ':' test)* [',']

! classdef: 'class' NAME ['(' testlist ')'] ':' suite
--- 180,184 ----
testlist: test (',' test)* [',']
dictmaker: test ':' test (',' test ':' test)* [',']

! classdef: 'class' NAME ['(' testlist ')'] ':' suite \
! | 'class' NAME ['(' testlist ')'] stmt_block end_clause

Index: Python/compile.c
*** /vi/python/1.0.2/Python/compile.c Wed May 4 03:41:34 1994
--- Python/compile.c Fri May 27 00:53:38 1994
***************
*** 1560,1565 ****
--- 1560,1574 ----
com_addbyte(c, EXEC_STMT);
}

+
+ /*
+ | if_stmt: 'if' test ':' suite [elif_clause] \
+ | | 'if' test block (elif_clause | 'end')
+ |
+ | elif_clause: 'elif' test ':' suite [elif_clause] \
+ | | 'elif' test block (elif_clause | 'end') \
+ | | else_clause
+ */
static void
com_if_stmt(c, n)
struct compiling *c;
***************
*** 1567,1592 ****
{
int i;
int anchor = 0;
! REQ(n, if_stmt);
! /*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */
! for (i = 0; i+3 < NCH(n); i+=4) {
! int a = 0;
! node *ch = CHILD(n, i+1);
! if (i > 0)
! com_addoparg(c, SET_LINENO, ch->n_lineno);
! com_node(c, CHILD(n, i+1));
! com_addfwref(c, JUMP_IF_FALSE, &a);
! com_addbyte(c, POP_TOP);
! com_node(c, CHILD(n, i+3));
! com_addfwref(c, JUMP_FORWARD, &anchor);
! com_backpatch(c, a);
! com_addbyte(c, POP_TOP);
! }
! if (i+2 < NCH(n))
! com_node(c, CHILD(n, i+2));
! com_backpatch(c, anchor);
}

static void
com_while_stmt(c, n)
struct compiling *c;
--- 1576,1639 ----
{
int i;
int anchor = 0;
! int first = 1;
! REQ(n, if_stmt);
!
! do {
! int a = 0;
!
! if (first)
! first = 0;
! else
! com_addoparg(c, SET_LINENO, CHILD(n, 1)->n_lineno);
!
! com_node(c, CHILD(n, 1));
! com_addfwref(c, JUMP_IF_FALSE, &a);
! com_addbyte(c, POP_TOP);
! if (TYPE(CHILD(n, 2)) == COLON) {
! com_node(c, CHILD(n, 3));
! if (NCH(n) > 4)
! n = CHILD(n, 4);
! else
! n = NULL;
! }
! else {
! com_node(c, CHILD(n, 2));
! n = CHILD(n, 3);
! }
! com_addfwref(c, JUMP_FORWARD, &anchor);
! com_backpatch(c, a);
! com_addbyte(c, POP_TOP);
! } while(n && TYPE(n) == elif_clause && NCH(n) > 1);
!
! if (n && NCH(n) == 1 && TYPE(CHILD(n, 0)) == else_clause)
! com_node(c, CHILD(n, 0));
!
! com_backpatch(c, anchor);
! }
!
!
! /*
! | else_clause: 'else' ':' suite \
! | | 'else' stmt_block 'end'
! */
! static void
! com_else_clause(c, n)
! struct compiling *c;
! node *n;
! {
! REQ(n, else_clause);
! if (TYPE(CHILD(n, 1)) == COLON)
! com_node(c, CHILD(n, 2));
! else
! com_node(c, CHILD(n, 1));
}

+
+ /*
+ | while_stmt: 'while' test ':' suite [else_clause] \
+ | | 'while' test stmt_block (else_clause | 'end')
+ */
static void
com_while_stmt(c, n)
struct compiling *c;
***************
*** 1595,1601 ****
int break_anchor = 0;
int anchor = 0;
int save_begin = c->c_begin;
! REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */
com_addfwref(c, SETUP_LOOP, &break_anchor);
block_push(c, SETUP_LOOP);
c->c_begin = c->c_nexti;
--- 1642,1648 ----
int break_anchor = 0;
int anchor = 0;
int save_begin = c->c_begin;
! REQ(n, while_stmt);
com_addfwref(c, SETUP_LOOP, &break_anchor);
block_push(c, SETUP_LOOP);
c->c_begin = c->c_nexti;
***************
*** 1604,1610 ****
com_addfwref(c, JUMP_IF_FALSE, &anchor);
com_addbyte(c, POP_TOP);
c->c_loops++;
! com_node(c, CHILD(n, 3));
c->c_loops--;
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
c->c_begin = save_begin;
--- 1651,1660 ----
com_addfwref(c, JUMP_IF_FALSE, &anchor);
com_addbyte(c, POP_TOP);
c->c_loops++;
! if (TYPE(CHILD(n, 2)) == COLON)
! com_node(c, CHILD(n, 3));
! else
! com_node(c, CHILD(n, 2));
c->c_loops--;
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
c->c_begin = save_begin;
***************
*** 1612,1622 ****
com_addbyte(c, POP_TOP);
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_LOOP);
! if (NCH(n) > 4)
! com_node(c, CHILD(n, 6));
! com_backpatch(c, break_anchor);
}

static void
com_for_stmt(c, n)
struct compiling *c;
--- 1662,1681 ----
com_addbyte(c, POP_TOP);
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_LOOP);
!
! if (NCH(n) > 4)
! com_node(c, CHILD(n, 4));
! else if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == else_clause)
! com_node(c, CHILD(n, 3));
!
! com_backpatch(c, break_anchor);
}

+
+ /*
+ | for_stmt: 'for' exprlist 'in' testlist ':' suite [else_clause] \
+ | | 'for' exprlist 'in' testlist stmt_block (else_clause | 'end')
+ */
static void
com_for_stmt(c, n)
struct compiling *c;
***************
*** 1627,1634 ****
int anchor = 0;
int save_begin = c->c_begin;
REQ(n, for_stmt);
! /* 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] */
! com_addfwref(c, SETUP_LOOP, &break_anchor);
block_push(c, SETUP_LOOP);
com_node(c, CHILD(n, 3));
v = newintobject(0L);
--- 1686,1692 ----
int anchor = 0;
int save_begin = c->c_begin;
REQ(n, for_stmt);
! com_addfwref(c, SETUP_LOOP, &break_anchor);
block_push(c, SETUP_LOOP);
com_node(c, CHILD(n, 3));
v = newintobject(0L);
***************
*** 1641,1655 ****
com_addfwref(c, FOR_LOOP, &anchor);
com_assign(c, CHILD(n, 1), 1/*assigning*/);
c->c_loops++;
! com_node(c, CHILD(n, 5));
! c->c_loops--;
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
c->c_begin = save_begin;
com_backpatch(c, anchor);
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_LOOP);
! if (NCH(n) > 8)
! com_node(c, CHILD(n, 8));
com_backpatch(c, break_anchor);
}

--- 1699,1720 ----
com_addfwref(c, FOR_LOOP, &anchor);
com_assign(c, CHILD(n, 1), 1/*assigning*/);
c->c_loops++;
! if (TYPE(CHILD(n, 4)) == COLON)
! com_node(c, CHILD(n, 5));
! else
! com_node(c, CHILD(n, 4));
! c->c_loops--;
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
c->c_begin = save_begin;
com_backpatch(c, anchor);
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_LOOP);
!
! if (NCH(n) > 6)
! com_node(c, CHILD(n, 6));
! else if (NCH(n) > 5 && TYPE(CHILD(n, 5)) == else_clause)
! com_node(c, CHILD(n, 5));
!
com_backpatch(c, break_anchor);
}

***************
*** 1719,1724 ****
--- 1784,1797 ----
Of course, parts are not generated if Vi or Ei is not present.
*/

+
+ /*
+ | try_stmt: 'try' ':' suite except_clause+ [else_clause] \
+ | | 'try' stmt_block except_clause+ (else_clause | 'end')
+ |
+ | except_clause: 'except' [test [',' test]] ':' suite \
+ | | 'except' [test [',' test]] stmt_block
+ */
static void
com_try_except(c, n)
struct compiling *c;
***************
*** 1732,1755 ****

com_addfwref(c, SETUP_EXCEPT, &except_anchor);
block_push(c, SETUP_EXCEPT);
! com_node(c, CHILD(n, 2));
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_EXCEPT);
com_addfwref(c, JUMP_FORWARD, &else_anchor);
com_backpatch(c, except_anchor);
! for (i = 3;
! i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause;
! i += 3) {
! /* except_clause: 'except' [expr [',' expr]] */
! if (except_anchor == 0) {
err_setstr(SyntaxError,
! "default 'except:' must be last");
c->c_errors++;
break;
}
except_anchor = 0;
com_addoparg(c, SET_LINENO, ch->n_lineno);
! if (NCH(ch) > 1) {
com_addbyte(c, DUP_TOP);
com_node(c, CHILD(ch, 1));
com_addoparg(c, COMPARE_OP, EXC_MATCH);
--- 1805,1842 ----

com_addfwref(c, SETUP_EXCEPT, &except_anchor);
block_push(c, SETUP_EXCEPT);
! if (TYPE(CHILD(n, 1)) == COLON) {
! com_node(c, CHILD(n, 2));
! i = 3;
! }
! else {
! com_node(c, CHILD(n, 1));
! i = 2;
! }
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_EXCEPT);
com_addfwref(c, JUMP_FORWARD, &else_anchor);
com_backpatch(c, except_anchor);
! for (; i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause; i++) {
! node *cch;
! int ntests;
!
! if (except_anchor == 0) {
err_setstr(SyntaxError,
! "default 'except:' must be last");
c->c_errors++;
break;
}
+
+ cch = CHILD(ch, NCH(ch) - 1);
+ if (TYPE(CHILD(ch, NCH(ch)) - 2) == COLON)
+ ntests = NCH(ch) - 3;
+ else
+ ntests = NCH(ch) - 2;
+
except_anchor = 0;
com_addoparg(c, SET_LINENO, ch->n_lineno);
! if (ntests > 0) {
com_addbyte(c, DUP_TOP);
com_node(c, CHILD(ch, 1));
com_addoparg(c, COMPARE_OP, EXC_MATCH);
***************
*** 1757,1768 ****
com_addbyte(c, POP_TOP);
}
com_addbyte(c, POP_TOP);
! if (NCH(ch) > 3)
com_assign(c, CHILD(ch, 3), 1/*assigning*/);
else
com_addbyte(c, POP_TOP);
com_addbyte(c, POP_TOP);
! com_node(c, CHILD(n, i+2));
com_addfwref(c, JUMP_FORWARD, &end_anchor);
if (except_anchor) {
com_backpatch(c, except_anchor);
--- 1844,1855 ----
com_addbyte(c, POP_TOP);
}
com_addbyte(c, POP_TOP);
! if (ntests > 2)
com_assign(c, CHILD(ch, 3), 1/*assigning*/);
else
com_addbyte(c, POP_TOP);
com_addbyte(c, POP_TOP);
! com_node(c, cch);
com_addfwref(c, JUMP_FORWARD, &end_anchor);
if (except_anchor) {
com_backpatch(c, except_anchor);
***************
*** 1771,1781 ****
}
com_addbyte(c, END_FINALLY);
com_backpatch(c, else_anchor);
! if (i < NCH(n))
! com_node(c, CHILD(n, i+2));
com_backpatch(c, end_anchor);
}

static void
com_try_finally(c, n)
struct compiling *c;
--- 1858,1891 ----
}
com_addbyte(c, END_FINALLY);
com_backpatch(c, else_anchor);
! if (TYPE(CHILD(n, i)) == else_clause)
! com_node(c, CHILD(n, i));
com_backpatch(c, end_anchor);
}

+
+ /*
+ | finally: 'finally' ':' suite \
+ | | 'finally' stmt_block 'end'
+ */
+ static void
+ com_finally_clause(c, n)
+ struct compiling *c;
+ node *n;
+ {
+ REQ(n, finally_clause);
+ if (TYPE(CHILD(n, 1)) == COLON)
+ com_node(c, CHILD(n, 2));
+ else
+ com_node(c, CHILD(n, 1));
+ }
+
+
+ /*
+ | try_stmt: 'try' ':' suite finally_clause \
+ | | 'try' stmt_block finally_clause
+ |
+ */
static void
com_try_finally(c, n)
struct compiling *c;
***************
*** 1786,1804 ****

com_addfwref(c, SETUP_FINALLY, &finally_anchor);
block_push(c, SETUP_FINALLY);
! com_node(c, CHILD(n, 2));
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_FINALLY);
block_push(c, END_FINALLY);
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
com_backpatch(c, finally_anchor);
! ch = CHILD(n, NCH(n)-1);
! com_addoparg(c, SET_LINENO, ch->n_lineno);
com_node(c, ch);
com_addbyte(c, END_FINALLY);
block_pop(c, END_FINALLY);
}

static void
com_try_stmt(c, n)
struct compiling *c;
--- 1896,1927 ----

com_addfwref(c, SETUP_FINALLY, &finally_anchor);
block_push(c, SETUP_FINALLY);
! if (TYPE(CHILD(n, 1)) == COLON) {
! com_node(c, CHILD(n, 2));
! ch = CHILD(n, 3);
! }
! else {
! com_node(c, CHILD(n, 1));
! ch = CHILD(n, 2);
! }
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_FINALLY);
block_push(c, END_FINALLY);
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
com_backpatch(c, finally_anchor);
! com_addoparg(c, SET_LINENO, ch->n_lineno);
com_node(c, ch);
com_addbyte(c, END_FINALLY);
block_pop(c, END_FINALLY);
}

+
+ /*
+ | try_stmt: 'try' ':' suite except_clause+ [else_clause] \
+ | | 'try' stmt_block except_clause+ (else_clause | 'end') \
+ | | 'try' ':' suite finally_clause \
+ | | 'try' stmt_block finally_clause
+ */
static void
com_try_stmt(c, n)
struct compiling *c;
***************
*** 1805,1818 ****
node *n;
{
REQ(n, try_stmt);
! /* 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
! | 'try' ':' suite 'finally' ':' suite */
! if (TYPE(CHILD(n, 3)) != except_clause)
com_try_finally(c, n);
else
com_try_except(c, n);
}

static void
com_suite(c, n)
struct compiling *c;
--- 1928,1941 ----
node *n;
{
REQ(n, try_stmt);
! if (TYPE(CHILD(n, 2)) == finally_clause
! || TYPE(CHILD(n, 3)) == finally_clause)
com_try_finally(c, n);
else
com_try_except(c, n);
}

+
static void
com_suite(c, n)
struct compiling *c;
***************
*** 1833,1838 ****
--- 1956,1977 ----
}
}

+ static void
+ com_stmt_block(c, n)
+ struct compiling *c;
+ node *n;
+ {
+ int i;
+ REQ(n, stmt_block);
+ /* stmt_block: NEWLINE INDENT stmt+ DEDENT */
+ for (i = 0; i < NCH(n); i++) {
+ node *ch = CHILD(n, i);
+ if (TYPE(ch) == stmt)
+ com_node(c, ch);
+ }
+ }
+
+
/* ARGSUSED */
static void
com_continue_stmt(c, n)
***************
*** 1863,1873 ****
n = CHILD(n, 1);
}
else {
! REQ(n, funcdef); /* funcdef: 'def' NAME parameters ... */
! n = CHILD(n, 2);
! REQ(n, parameters); /* parameters: '(' [varargslist] ')' */
! n = CHILD(n, 1);
! }
if (TYPE(n) != varargslist)
return -1;
/* varargslist:
--- 2002,2011 ----
n = CHILD(n, 1);
}
else {
! REQ(n, funcdef); /* funcdef: 'def' NAME '('
! [varargslist] ')' ... */
! n = CHILD(n, 3);
! }
if (TYPE(n) != varargslist)
return -1;
/* varargslist:
***************
*** 1915,1920 ****
--- 2053,2062 ----
return ndefs;
}

+ /*
+ | funcdef: 'def' NAME '(' [varargslist] ')' ':' suite \
+ | | 'def' NAME '(' [varargslist] ')' stmt_block 'end'
+ */
static void
com_funcdef(c, n)
struct compiling *c;
***************
*** 1921,1927 ****
node *n;
{
object *v;
! REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
v = (object *)compile(n, c->c_filename);
if (v == NULL)
c->c_errors++;
--- 2063,2069 ----
node *n;
{
object *v;
! REQ(n, funcdef);
v = (object *)compile(n, c->c_filename);
if (v == NULL)
c->c_errors++;
***************
*** 1951,1956 ****
--- 2093,2104 ----
com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 2);
}

+ /*
+ | classdef: 'class' NAME ['(' testlist ')'] ':' suite \
+ | | 'class' NAME ['(' testlist ')'] stmt_block 'end'
+ */
+
+ /* classdef: class NAME ['(' testlist ')'] ':' suite */
static void
com_classdef(c, n)
struct compiling *c;
***************
*** 1959,1965 ****
int i;
object *v;
REQ(n, classdef);
! /* classdef: class NAME ['(' testlist ')'] ':' suite */
if ((v = newstringobject(STR(CHILD(n, 1)))) == NULL) {
c->c_errors++;
return;
--- 2107,2113 ----
int i;
object *v;
REQ(n, classdef);
!
if ((v = newstringobject(STR(CHILD(n, 1)))) == NULL) {
c->c_errors++;
return;
***************
*** 2070,2075 ****
--- 2218,2229 ----
case if_stmt:
com_if_stmt(c, n);
break;
+ case else_clause:
+ com_else_clause(c, n);
+ break;
+ case finally_clause:
+ com_finally_clause(c, n);
+ break;
case while_stmt:
com_while_stmt(c, n);
break;
***************
*** 2082,2087 ****
--- 2236,2244 ----
case suite:
com_suite(c, n);
break;
+ case stmt_block:
+ com_stmt_block(c, n);
+ break;

/* Expression nodes */

***************
*** 2231,2236 ****
--- 2388,2398 ----

/* Top-level compile-node interface */

+ /*
+ | funcdef: 'def' NAME '(' [varargslist] ')' ':' suite \
+ | | 'def' NAME '(' [varargslist] ')' stmt_block 'end'
+ */
+
static void
compile_funcdef(c, n)
struct compiling *c;
***************
*** 2237,2253 ****
node *n;
{
node *ch;
! REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
c->c_name = STR(CHILD(n, 1));
com_addoparg(c, RESERVE_FAST, com_addconst(c, None)); /* Patched! */
! ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
! ch = CHILD(ch, 1); /* ')' | varargslist */
! if (TYPE(ch) == RPAR)
com_addoparg(c, UNPACK_ARG, 0);
else
com_arglist(c, ch);
c->c_infunction = 1;
! com_node(c, CHILD(n, 4));
c->c_infunction = 0;
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
com_addbyte(c, RETURN_VALUE);
--- 2399,2417 ----
node *n;
{
node *ch;
! REQ(n, funcdef);
c->c_name = STR(CHILD(n, 1));
com_addoparg(c, RESERVE_FAST, com_addconst(c, None)); /* Patched! */
! ch = CHILD(n, 3);
! if (TYPE(ch) == RPAR)
com_addoparg(c, UNPACK_ARG, 0);
else
com_arglist(c, ch);
c->c_infunction = 1;
! if (TYPE(CHILD(n, NCH(n) - 1)) == suite)
! com_node(c, CHILD(n, NCH(n) - 1));
! else
! com_node(c, CHILD(n, NCH(n) - 2));
c->c_infunction = 0;
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
com_addbyte(c, RETURN_VALUE);
***************
*** 2318,2324 ****
case classdef: /* A class definition */
/* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
c->c_name = STR(CHILD(n, 1));
! com_node(c, CHILD(n, NCH(n)-1)); /* The suite */
com_addbyte(c, LOAD_LOCALS);
com_addbyte(c, RETURN_VALUE);
break;
--- 2482,2491 ----
case classdef: /* A class definition */
/* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
c->c_name = STR(CHILD(n, 1));
! if (TYPE(CHILD(n, NCH(n)-1)) == suite)
! com_node(c, CHILD(n, NCH(n)-1)); /* The suite */
! else
! com_node(c, CHILD(n, NCH(n)-2)); /* The block */
com_addbyte(c, LOAD_LOCALS);
com_addbyte(c, RETURN_VALUE);
break;