Skip to content

Commit

Permalink
Add &&& and ||| operators
Browse files Browse the repository at this point in the history
These are the short-circuit implementations of the `&&` and `||` operators.
  • Loading branch information
positively-charged committed Jan 31, 2017
1 parent f5e2426 commit 80787d1
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 11 deletions.
12 changes: 10 additions & 2 deletions doc/grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,17 @@ assignment:
<conditional> |= <assignment>

conditional:
<short-circuit-or>
<short-circuit-or> ? <expression> : <conditional>
<short-circuit-orshort-or> ? : <conditional>

short-circuit-or:
<short-circuit-and>
<short-circuit-or> ||| <short-circuit-and>

short-circuit-and:
<logical-or>
<logical-or> ? <expression> : <conditional>
<logical-or> ? : <conditional>
<short-circuit-and> &&& <logical-or>

logical-or:
<logical-and>
Expand Down
5 changes: 3 additions & 2 deletions src/codegen/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,10 +613,11 @@ void write_logical( struct codegen* codegen, struct result* result,
struct logical* logical ) {
push_logical_operand( codegen, logical->lside, logical->lside_spec );
struct c_jump* rside_jump = c_create_jump( codegen,
( logical->op == LOP_OR ? PCD_IFNOTGOTO : PCD_IFGOTO ) );
( logical->op == LOP_OR || logical->op == LOP_SHORTCIRCUITOR ?
PCD_IFNOTGOTO : PCD_IFGOTO ) );
c_append_node( codegen, &rside_jump->node );
c_pcd( codegen, PCD_PUSHNUMBER,
( logical->op == LOP_OR ? 1 : 0 ) );
( logical->op == LOP_OR || logical->op == LOP_SHORTCIRCUITOR ? 1 : 0 ) );
struct c_jump* exit_jump = c_create_jump( codegen, PCD_GOTO );
c_append_node( codegen, &exit_jump->node );
struct c_point* rside_point = c_create_point( codegen );
Expand Down
30 changes: 30 additions & 0 deletions src/parse/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ void read_op( struct parse* parse, struct expr_reading* reading ) {
struct binary* bit_or = NULL;
struct logical* log_and = NULL;
struct logical* log_or = NULL;
struct logical* sc_and = NULL;
struct logical* sc_or = NULL;
struct assign* assign = NULL;

top:
Expand Down Expand Up @@ -300,6 +302,34 @@ void read_op( struct parse* parse, struct expr_reading* reading ) {
goto top;
}

// Short-circuit AND.
// -----------------------------------------------------------------------
if ( sc_and ) {
sc_and->rside = reading->node;
reading->node = &sc_and->node;
sc_and = NULL;
}
if ( parse->tk == TK_SHORTCIRCUITAND ) {
sc_and = alloc_logical( LOP_SHORTCIRCUITAND, &parse->tk_pos );
sc_and->lside = reading->node;
p_read_tk( parse );
goto top;
}

// Short-circuit OR.
// -----------------------------------------------------------------------
if ( sc_or ) {
sc_or->rside = reading->node;
reading->node = &sc_or->node;
sc_or = NULL;
}
if ( parse->tk == TK_SHORTCIRCUITOR ) {
sc_or = alloc_logical( LOP_SHORTCIRCUITOR, &parse->tk_pos );
sc_or->lside = reading->node;
p_read_tk( parse );
goto top;
}

// Conditional
// -----------------------------------------------------------------------
if ( parse->lang == LANG_BCS && parse->tk == TK_QUESTION_MARK ) {
Expand Down
3 changes: 3 additions & 0 deletions src/parse/phase.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ enum tk {
TK_REOPEN,
TK_LET,
TK_STRICT,
// 150
TK_SHORTCIRCUITOR,
TK_SHORTCIRCUITAND,

TK_TOTAL,

Expand Down
7 changes: 5 additions & 2 deletions src/parse/token/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,19 @@ static struct token_info g_table[] = {
ENTRY( "reopen", TKF_KEYWORD ),
ENTRY( "let", TKF_KEYWORD ),
ENTRY( "strict", TKF_KEYWORD ),
// 150
ENTRY( "|||", TKF_NONE ),
ENTRY( "&&&", TKF_NONE ),
};
#undef ENTRY

const struct token_info* p_get_token_info( enum tk tk ) {
STATIC_ASSERT( TK_TOTAL == 150 );
STATIC_ASSERT( TK_TOTAL == 152 );
return &g_table[ tk ];
}

void p_present_token( struct str* str, enum tk tk ) {
STATIC_ASSERT( TK_TOTAL == 150 );
STATIC_ASSERT( TK_TOTAL == 152 );
switch ( tk ) {
case TK_ID:
str_append( str,
Expand Down
16 changes: 14 additions & 2 deletions src/parse/token/source.c
Original file line number Diff line number Diff line change
Expand Up @@ -1968,8 +1968,14 @@ void read_token( struct parse* parse, struct token* token ) {
else if ( ch == '&' ) {
ch = read_ch( parse );
if ( ch == '&' ) {
tk = TK_LOG_AND;
ch = read_ch( parse );
if ( ch == '&' ) {
tk = TK_SHORTCIRCUITAND;
ch = read_ch( parse );
}
else {
tk = TK_LOG_AND;
}
}
else if ( ch == '=' ) {
tk = TK_ASSIGN_BIT_AND;
Expand All @@ -1983,8 +1989,14 @@ void read_token( struct parse* parse, struct token* token ) {
else if ( ch == '|' ) {
ch = read_ch( parse );
if ( ch == '|' ) {
tk = TK_LOG_OR;
ch = read_ch( parse );
if ( ch == '|' ) {
tk = TK_SHORTCIRCUITOR;
ch = read_ch( parse );
}
else {
tk = TK_LOG_OR;
}
}
else if ( ch == '=' ) {
tk = TK_ASSIGN_BIT_OR;
Expand Down
10 changes: 8 additions & 2 deletions src/semantic/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -742,8 +742,14 @@ void fold_logical( struct semantic* semantic, struct logical* logical,
UNREACHABLE();
}
switch ( logical->op ) {
case LOP_OR: l = ( l || r ); break;
case LOP_AND: l = ( l && r ); break;
case LOP_OR:
case LOP_SHORTCIRCUITOR:
l = ( l || r );
break;
case LOP_AND:
case LOP_SHORTCIRCUITAND:
l = ( l && r );
break;
default:
UNREACHABLE();
}
Expand Down
4 changes: 3 additions & 1 deletion src/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,10 @@ struct binary {
struct logical {
struct node node;
enum {
LOP_SHORTCIRCUITOR,
LOP_SHORTCIRCUITAND,
LOP_OR,
LOP_AND
LOP_AND,
} op;
struct node* lside;
struct node* rside;
Expand Down

0 comments on commit 80787d1

Please sign in to comment.