Skip to content

Commit

Permalink
Always allow writing to _ (dontcare)
Browse files Browse the repository at this point in the history
`_` is now an identifier that is always valid to write to, but never to
read from. It can also be shadowed freely.

Closes #876.
  • Loading branch information
Benoit Vey authored and SeanTAllen committed Jan 7, 2017
1 parent 9543a15 commit d0bfc48
Show file tree
Hide file tree
Showing 38 changed files with 598 additions and 250 deletions.
19 changes: 9 additions & 10 deletions pony.g
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,12 @@ elseif
idseq
: ID
| '_'
| ('(' | LPAREN_NEW) (idseq_in_seq | '_') (',' (idseq_in_seq | '_'))* ')'
| ('(' | LPAREN_NEW) idseq_in_seq (',' idseq_in_seq)* ')'
;
idseq_in_seq
: ID
| ('(' | LPAREN_NEW) (idseq_in_seq | '_') (',' (idseq_in_seq | '_'))* ')'
| ('(' | LPAREN_NEW) idseq_in_seq (',' idseq_in_seq)* ')'
;
nextpattern
Expand Down Expand Up @@ -192,7 +191,7 @@ nextatom
: ID
| 'this'
| literal
| LPAREN_NEW (rawseq | '_') tuple? ')'
| LPAREN_NEW rawseq tuple? ')'
| LSQUARE_NEW ('as' type ':')? rawseq (',' rawseq)* ']'
| 'object' ('\' ID (',' ID)* '\')? cap? ('is' type)? members 'end'
| '{' ('\' ID (',' ID)* '\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq '}' cap?
Expand All @@ -205,7 +204,7 @@ atom
: ID
| 'this'
| literal
| ('(' | LPAREN_NEW) (rawseq | '_') tuple? ')'
| ('(' | LPAREN_NEW) rawseq tuple? ')'
| ('[' | LSQUARE_NEW) ('as' type ':')? rawseq (',' rawseq)* ']'
| 'object' ('\' ID (',' ID)* '\')? cap? ('is' type)? members 'end'
| '{' ('\' ID (',' ID)* '\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq '}' cap?
Expand All @@ -215,7 +214,7 @@ atom
;
tuple
: ',' (rawseq | '_') (',' (rawseq | '_'))*
: ',' rawseq (',' rawseq)*
;
lambdacaptures
Expand Down Expand Up @@ -245,7 +244,7 @@ type
atomtype
: 'this'
| cap
| ('(' | LPAREN_NEW) (infixtype | '_') tupletype? ')'
| ('(' | LPAREN_NEW) infixtype tupletype? ')'
| nominal
| lambdatype
;
Expand All @@ -255,7 +254,7 @@ lambdatype
;
tupletype
: ',' (infixtype | '_') (',' (infixtype | '_'))*
: ',' infixtype (',' infixtype)*
;
infixtype
Expand Down Expand Up @@ -322,7 +321,7 @@ literal
;

param
: (parampattern | '_') (':' type)? ('=' infix)?
: parampattern (':' type)? ('=' infix)?
;

antlr_0
Expand Down Expand Up @@ -379,7 +378,7 @@ Type:

ID
: LETTER (LETTER | DIGIT | '_' | '\'')*
| '_' (LETTER | DIGIT | '_' | '\'')+
| '_' (LETTER | DIGIT | '_' | '\'')*
;

INT
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/ast/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1438,7 +1438,7 @@ static void print_type(printbuf_t* buffer, ast_t* type)
printbuf(buffer, "this");
break;

case TK_DONTCARE:
case TK_DONTCARETYPE:
printbuf(buffer, "_");
break;

Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/ast/bnfprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static const char* antlr_post =
"// Lexer\n\n"
"ID\n"
" : LETTER (LETTER | DIGIT | '_' | '\\'')*\n"
" | '_' (LETTER | DIGIT | '_' | '\\'')+\n"
" | '_' (LETTER | DIGIT | '_' | '\\'')*\n"
" ;\n\n"
"INT\n"
" : DIGIT (DIGIT | '_')*\n"
Expand Down
23 changes: 20 additions & 3 deletions src/libponyc/ast/id.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ bool check_id(pass_opt_t* opt, ast_t* id_node, const char* desc, int spec)
name++;
prev = '_';

if(*name == '\0')
{
if((spec & ALLOW_DONTCARE) == 0)
{
ast_error(opt->check.errors, id_node,
"%s name cannot be \"%s\"", desc, ast_name(id_node));
return false;
}
return true;
}

if((spec & ALLOW_LEADING_UNDERSCORE) == 0)
{
ast_error(opt->check.errors, id_node,
Expand Down Expand Up @@ -168,9 +179,9 @@ bool check_id_param(pass_opt_t* opt, ast_t* id_node)

bool check_id_local(pass_opt_t* opt, ast_t* id_node)
{
// [a-z][A-Za-z0-9_]*'* (and no double or trailing underscores)
// (_|[a-z][A-Za-z0-9_]*'*) (and no double or trailing underscores)
return check_id(opt, id_node, "local variable",
START_LOWER | ALLOW_UNDERSCORE | ALLOW_TICK);
START_LOWER | ALLOW_UNDERSCORE | ALLOW_TICK | ALLOW_DONTCARE);
}

bool is_name_type(const char* name)
Expand All @@ -186,7 +197,8 @@ bool is_name_type(const char* name)

bool is_name_private(const char* name)
{
return name[0] == '_' || (is_name_internal_test(name) && name[1] == '_');
return ((name[0] == '_') && (name[1] != '\0')) ||
(is_name_internal_test(name) && (name[1] == '_'));
}

bool is_name_ffi(const char* name)
Expand All @@ -198,3 +210,8 @@ bool is_name_internal_test(const char* name)
{
return name[0] == '$';
}

bool is_name_dontcare(const char* name)
{
return (name[0] == '_') && (name[1] == '\0');
}
3 changes: 3 additions & 0 deletions src/libponyc/ast/id.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ bool is_name_ffi(const char* name);
// Report whether the given id name is for an internal test
bool is_name_internal_test(const char* name);

// Report whether the given id name is '_'
bool is_name_dontcare(const char* name);

PONY_EXTERN_C_END

#endif
1 change: 1 addition & 0 deletions src/libponyc/ast/id_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ PONY_EXTERN_C_BEGIN
#define ALLOW_LEADING_UNDERSCORE 0x04
#define ALLOW_UNDERSCORE 0x08
#define ALLOW_TICK 0x10
#define ALLOW_DONTCARE 0x20


/* Check that the name in the given ID node meets the given spec.
Expand Down
4 changes: 3 additions & 1 deletion src/libponyc/ast/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ static const lextoken_t symbols[] =

static const lextoken_t keywords[] =
{
{ "_", TK_DONTCARE },
{ "compile_intrinsic", TK_COMPILE_INTRINSIC },

{ "use", TK_USE },
Expand Down Expand Up @@ -211,6 +210,7 @@ static const lextoken_t abstract[] =
{ "members", TK_MEMBERS },
{ "fvar", TK_FVAR },
{ "flet", TK_FLET },
{ "dontcare", TK_DONTCARE },
{ "ffidecl", TK_FFIDECL },
{ "fficall", TK_FFICALL },

Expand All @@ -222,6 +222,7 @@ static const lextoken_t abstract[] =
{ "thistype", TK_THISTYPE },
{ "funtype", TK_FUNTYPE },
{ "lambdatype", TK_LAMBDATYPE },
{ "dontcaretype", TK_DONTCARETYPE },
{ "infer", TK_INFERTYPE },
{ "errortype", TK_ERRORTYPE },

Expand Down Expand Up @@ -279,6 +280,7 @@ static const lextoken_t abstract[] =
{ "varref", TK_VARREF },
{ "letref", TK_LETREF },
{ "paramref", TK_PARAMREF },
{ "dontcareref", TK_DONTCAREREF },
{ "newapp", TK_NEWAPP },
{ "beapp", TK_BEAPP },
{ "funapp", TK_FUNAPP },
Expand Down
42 changes: 18 additions & 24 deletions src/libponyc/ast/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,17 @@ DECL(thisliteral);

// Parse rules

// DONTCARE
DEF(dontcare);
PRINT_INLINE();
TOKEN(NULL, TK_DONTCARE);
DONE();

// type
DEF(provides);
PRINT_INLINE();
AST_NODE(TK_PROVIDES);
RULE("provided type", type);
DONE();

// (postfix | dontcare) [COLON type] [ASSIGN infix]
// postfix [COLON type] [ASSIGN infix]
DEF(param);
AST_NODE(TK_PARAM);
RULE("name", parampattern, dontcare);
RULE("name", parampattern);
IF(TK_COLON,
RULE("parameter type", type);
UNWRAP(0, TK_REFERENCE);
Expand Down Expand Up @@ -196,20 +190,20 @@ DEF(infixtype);
SEQ("type", uniontype, isecttype);
DONE();

// COMMA (infixtype | dontcare) {COMMA (infixtype | dontcare)}
// COMMA infixtype {COMMA infixtype}
DEF(tupletype);
INFIX_BUILD();
TOKEN(NULL, TK_COMMA);
MAP_ID(TK_COMMA, TK_TUPLETYPE);
RULE("type", infixtype, dontcare);
WHILE(TK_COMMA, RULE("type", infixtype, dontcare));
RULE("type", infixtype);
WHILE(TK_COMMA, RULE("type", infixtype));
DONE();

// (LPAREN | LPAREN_NEW) (infixtype | dontcare) [tupletype] RPAREN
// (LPAREN | LPAREN_NEW) infixtype [tupletype] RPAREN
DEF(groupedtype);
PRINT_INLINE();
SKIP(NULL, TK_LPAREN, TK_LPAREN_NEW);
RULE("type", infixtype, dontcare);
RULE("type", infixtype);
OPT_NO_DFLT RULE("type", tupletype);
SKIP(NULL, TK_RPAREN);
SET_FLAG(AST_FLAG_IN_PARENS);
Expand Down Expand Up @@ -413,30 +407,30 @@ DEF(nextarray);
TERMINATE("array literal", TK_RSQUARE);
DONE();

// COMMA (rawseq | dontcare) {COMMA (rawseq | dontcare)}
// COMMA rawseq {COMMA rawseq}
DEF(tuple);
INFIX_BUILD();
TOKEN(NULL, TK_COMMA);
MAP_ID(TK_COMMA, TK_TUPLE);
RULE("value", rawseq, dontcare);
WHILE(TK_COMMA, RULE("value", rawseq, dontcare));
RULE("value", rawseq);
WHILE(TK_COMMA, RULE("value", rawseq));
DONE();

// (LPAREN | LPAREN_NEW) (rawseq | dontcare) [tuple] RPAREN
// (LPAREN | LPAREN_NEW) rawseq [tuple] RPAREN
DEF(groupedexpr);
PRINT_INLINE();
SKIP(NULL, TK_LPAREN, TK_LPAREN_NEW);
RULE("value", rawseq, dontcare);
RULE("value", rawseq);
OPT_NO_DFLT RULE("value", tuple);
SKIP(NULL, TK_RPAREN);
SET_FLAG(AST_FLAG_IN_PARENS);
DONE();

// LPAREN_NEW (rawseq | dontcare) [tuple] RPAREN
// LPAREN_NEW rawseq [tuple] RPAREN
DEF(nextgroupedexpr);
PRINT_INLINE();
SKIP(NULL, TK_LPAREN_NEW);
RULE("value", rawseq, dontcare);
RULE("value", rawseq);
OPT_NO_DFLT RULE("value", tuple);
SKIP(NULL, TK_RPAREN);
SET_FLAG(AST_FLAG_IN_PARENS);
Expand Down Expand Up @@ -587,8 +581,8 @@ DEF(idseqmulti);
PRINT_INLINE();
AST_NODE(TK_TUPLE);
SKIP(NULL, TK_LPAREN, TK_LPAREN_NEW);
RULE("variable name", idseq_in_seq, dontcare);
WHILE(TK_COMMA, RULE("variable name", idseq_in_seq, dontcare));
RULE("variable name", idseq_in_seq);
WHILE(TK_COMMA, RULE("variable name", idseq_in_seq));
SKIP(NULL, TK_RPAREN);
DONE();

Expand All @@ -606,9 +600,9 @@ DEF(idseq_in_seq);
RULE("variable name", idseqsingle, idseqmulti);
DONE();

// ID | '_' | (LPAREN | LPAREN_NEW) idseq {COMMA idseq} RPAREN
// ID | (LPAREN | LPAREN_NEW) idseq {COMMA idseq} RPAREN
DEF(idseq);
RULE("variable name", idseqsingle, dontcare, idseqmulti);
RULE("variable name", idseqsingle, idseqmulti);
DONE();

// ELSE annotatedseq
Expand Down
5 changes: 4 additions & 1 deletion src/libponyc/ast/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ typedef enum token_id
TK_QUESTION,
TK_UNARY_MINUS,
TK_ELLIPSIS,
TK_DONTCARE,
TK_CONSTANT,

// Newline symbols, only used by lexer and parser
Expand Down Expand Up @@ -103,6 +102,7 @@ typedef enum token_id
TK_VAR,
TK_LET,
TK_EMBED,
TK_DONTCARE,
TK_NEW,
TK_FUN,
TK_BE,
Expand Down Expand Up @@ -192,6 +192,7 @@ typedef enum token_id
TK_THISTYPE,
TK_FUNTYPE,
TK_LAMBDATYPE,
TK_DONTCARETYPE,
TK_INFERTYPE,
TK_ERRORTYPE,

Expand Down Expand Up @@ -221,6 +222,7 @@ typedef enum token_id
TK_CASES,
TK_CASE,
TK_MATCH_CAPTURE,
TK_MATCH_DONTCARE,

TK_REFERENCE,
TK_PACKAGEREF,
Expand All @@ -236,6 +238,7 @@ typedef enum token_id
TK_VARREF,
TK_LETREF,
TK_PARAMREF,
TK_DONTCAREREF,
TK_NEWAPP,
TK_BEAPP,
TK_FUNAPP,
Expand Down
10 changes: 5 additions & 5 deletions src/libponyc/ast/treecheckdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ RULE(asop,

RULE(tuple,
HAS_TYPE(type)
ONE_OR_MORE(rawseq, dont_care),
ONE_OR_MORE(rawseq),
TK_TUPLE);

RULE(consume,
Expand Down Expand Up @@ -319,7 +319,7 @@ RULE(match_case,
CHILD(rawseq, none), // Body
TK_CASE);

RULE(no_case_expr, HAS_TYPE(dont_care), TK_NONE);
RULE(no_case_expr, HAS_TYPE(dontcare_type), TK_NONE);

RULE(try_expr,
HAS_TYPE(type)
Expand Down Expand Up @@ -403,8 +403,8 @@ RULE(local_ref,

GROUP(type,
type_infix, type_tuple, type_arrow, type_this, cap, nominal,
type_param_ref, dont_care, fun_type, error_type, lambda_type,
literal_type, opliteral_type, control_type, dont_care);
type_param_ref, dontcare_type, fun_type, error_type, lambda_type,
literal_type, opliteral_type, control_type);

RULE(type_infix, ONE_OR_MORE(type), TK_UNIONTYPE, TK_ISECTTYPE);

Expand Down Expand Up @@ -458,7 +458,7 @@ RULE(borrowed, LEAF, TK_BORROWED);
RULE(cap, LEAF, TK_ISO, TK_TRN, TK_REF, TK_VAL, TK_BOX, TK_TAG);
RULE(control_type, LEAF, TK_IF, TK_CASES, TK_COMPILE_INTRINSIC,
TK_COMPILE_ERROR, TK_RETURN, TK_BREAK, TK_CONTINUE, TK_ERROR);
RULE(dont_care, HAS_TYPE(type), TK_DONTCARE);
RULE(dontcare_type, LEAF, TK_DONTCARETYPE);
RULE(ellipsis, LEAF, TK_ELLIPSIS);
RULE(ephemeral, LEAF, TK_EPHEMERAL);
RULE(error_type, LEAF, TK_ERRORTYPE);
Expand Down
Loading

0 comments on commit d0bfc48

Please sign in to comment.