Skip to content

Commit

Permalink
Add bare methods and bare lambdas (RFC 34)
Browse files Browse the repository at this point in the history
These new language constructs can be used in FFI interoperation with C
libraries that use function pointers as callbacks.

Closes #1690.
  • Loading branch information
Benoit Vey committed Apr 21, 2017
1 parent 6f0bac8 commit ebd5201
Show file tree
Hide file tree
Showing 41 changed files with 1,457 additions and 209 deletions.
9 changes: 8 additions & 1 deletion pony.g
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ field
;

method
: ('fun' | 'be' | 'new') ('\\' ID (',' ID)* '\\')? cap? ID typeparams? ('(' | LPAREN_NEW) params? ')' (':' type)? '?'? STRING? ('if' rawseq)? ('=>' rawseq)?
: ('fun' | 'be' | 'new') ('\\' ID (',' ID)* '\\')? (cap | '@')? ID typeparams? ('(' | LPAREN_NEW) params? ')' (':' type)? '?'? STRING? ('if' rawseq)? ('=>' rawseq)?
;

annotatedrawseq
Expand Down Expand Up @@ -202,6 +202,7 @@ nextatom
| 'object' ('\\' ID (',' ID)* '\\')? cap? ('is' type)? members 'end'
| '{' ('\\' ID (',' ID)* '\\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq '}' cap?
| 'lambda' ('\\' ID (',' ID)* '\\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq 'end'
| '@{' ('\\' ID (',' ID)* '\\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq '}' cap?
| '@' (ID | STRING) typeargs? ('(' | LPAREN_NEW) positional? named? ')' '?'?
| '__loc'
;
Expand All @@ -215,6 +216,7 @@ atom
| 'object' ('\\' ID (',' ID)* '\\')? cap? ('is' type)? members 'end'
| '{' ('\\' ID (',' ID)* '\\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq '}' cap?
| 'lambda' ('\\' ID (',' ID)* '\\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq 'end'
| '@{' ('\\' ID (',' ID)* '\\')? cap? ID? typeparams? ('(' | LPAREN_NEW) params? ')' lambdacaptures? (':' type)? '?'? '=>' rawseq '}' cap?
| '@' (ID | STRING) typeargs? ('(' | LPAREN_NEW) positional? named? ')' '?'?
| '__loc'
;
Expand Down Expand Up @@ -253,6 +255,11 @@ atomtype
| ('(' | LPAREN_NEW) infixtype tupletype? ')'
| nominal
| lambdatype
| barelambdatype
;

barelambdatype
: '@{' cap? ID? typeparams? ('(' | LPAREN_NEW) (type (',' type)*)? ')' (':' type)? '?'? '}' (cap | gencap)? ('^' | '!')?
;

lambdatype
Expand Down
26 changes: 13 additions & 13 deletions src/libponyc/ast/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* no annotation, the type will be stored in the annotation_type field.
*
* These situations can be distinguished because an annotation must always be a
* TK_BACKSLASH, and the type may never be a TK_BACKSLASH.
* TK_ANNOTATION, and the type may never be a TK_ANNOTATION.
*
* It is STRONGLY recommended to only access them through provided functions:
* ast_type()
Expand Down Expand Up @@ -653,13 +653,13 @@ ast_t* ast_type(ast_t* ast)
pony_assert(ast != NULL);

// An annotation may never have a type.
if(ast_id(ast) == TK_BACKSLASH)
if(ast_id(ast) == TK_ANNOTATION)
return NULL;

// If the annotation_type is an annotation, the type node (if any) is in the
// annotation_type field of the annotation node.
ast_t* type = ast->annotation_type;
if((type != NULL) && (ast_id(type) == TK_BACKSLASH))
if((type != NULL) && (ast_id(type) == TK_ANNOTATION))
type = type->annotation_type;

return type;
Expand All @@ -670,12 +670,12 @@ static void settype(ast_t* ast, ast_t* type, bool allow_free)
pony_assert(ast != NULL);

// An annotation may never have a type.
if(ast_id(ast) == TK_BACKSLASH)
if(ast_id(ast) == TK_ANNOTATION)
pony_assert(type == NULL);

// A type can never be a TK_BACKSLASH (the annotation token).
// A type can never be a TK_ANNOTATION.
if(type != NULL)
pony_assert(ast_id(type) != TK_BACKSLASH);
pony_assert(ast_id(type) != TK_ANNOTATION);

ast_t* prev_type = ast_type(ast);
if(prev_type == type)
Expand All @@ -690,7 +690,7 @@ static void settype(ast_t* ast, ast_t* type, bool allow_free)
}

if((ast->annotation_type != NULL) &&
(ast_id(ast->annotation_type) == TK_BACKSLASH))
(ast_id(ast->annotation_type) == TK_ANNOTATION))
ast->annotation_type->annotation_type = type;
else
ast->annotation_type = type;
Expand All @@ -709,12 +709,12 @@ ast_t* ast_annotation(ast_t* ast)
pony_assert(ast != NULL);

// An annotation may never be annotated.
if(ast_id(ast) == TK_BACKSLASH)
if(ast_id(ast) == TK_ANNOTATION)
return NULL;

// If annotation_type is an annotation, we return it.
ast_t* annotation = ast->annotation_type;
if((annotation != NULL) && (ast_id(annotation) == TK_BACKSLASH))
if((annotation != NULL) && (ast_id(annotation) == TK_ANNOTATION))
return annotation;

return NULL;
Expand All @@ -725,12 +725,12 @@ void setannotation(ast_t* ast, ast_t* annotation, bool allow_free)
pony_assert(ast != NULL);

// An annotation may never be annotated.
if(ast_id(ast) == TK_BACKSLASH)
if(ast_id(ast) == TK_ANNOTATION)
pony_assert(annotation == NULL);

// An annotation must always be a TK_BACKSLASH (or NULL).
// An annotation must always be a TK_ANNOTATION (or NULL).
if(annotation != NULL)
pony_assert(ast_id(annotation) == TK_BACKSLASH);
pony_assert(ast_id(annotation) == TK_ANNOTATION);

ast_t* prev_annotation = ast_annotation(ast);
if(prev_annotation == annotation)
Expand Down Expand Up @@ -781,7 +781,7 @@ bool ast_has_annotation(ast_t* ast, const char* name)

ast_t* annotation = ast_annotation(ast);

if((annotation != NULL) && (ast_id(annotation) == TK_BACKSLASH))
if((annotation != NULL) && (ast_id(annotation) == TK_ANNOTATION))
{
const char* strtab_name = stringtab(name);
ast_t* elem = ast_child(annotation);
Expand Down
4 changes: 4 additions & 0 deletions src/libponyc/ast/astbuild.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
*/
#define BUILD(var, existing, ...) \
ast_t* var; \
BUILD_NO_DECL(var, existing, __VA_ARGS__)

/// Builds an AST but without declaring a new variable.
#define BUILD_NO_DECL(var, existing, ...) \
{ \
ast_t* basis_ast = existing; \
ast_t* parent = NULL; \
Expand Down
7 changes: 7 additions & 0 deletions src/libponyc/ast/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ static const lextoken_t symbols[] =

{ "\\", TK_BACKSLASH },

{ "@{", TK_AT_LBRACE },

{ "{", TK_LBRACE },
{ "}", TK_RBRACE },
{ "(", TK_LPAREN },
Expand Down Expand Up @@ -244,6 +246,7 @@ static const lextoken_t abstract[] =
{ "thistype", TK_THISTYPE },
{ "funtype", TK_FUNTYPE },
{ "lambdatype", TK_LAMBDATYPE },
{ "barelambdatype", TK_BARELAMBDATYPE },
{ "dontcaretype", TK_DONTCARETYPE },
{ "infer", TK_INFERTYPE },
{ "errortype", TK_ERRORTYPE },
Expand All @@ -266,6 +269,8 @@ static const lextoken_t abstract[] =
{ "lambdacaptures", TK_LAMBDACAPTURES },
{ "lambdacapture", TK_LAMBDACAPTURE },

{ "barelambda", TK_BARELAMBDA },

{ "seq", TK_SEQ },
{ "qualify", TK_QUALIFY },
{ "call", TK_CALL },
Expand Down Expand Up @@ -297,6 +302,8 @@ static const lextoken_t abstract[] =
{ "bechain", TK_BECHAIN },
{ "funchain", TK_FUNCHAIN },

{ "annotation", TK_ANNOTATION },

{ "\\n", TK_NEWLINE },
{NULL, (token_id)0}
};
Expand Down
73 changes: 63 additions & 10 deletions src/libponyc/ast/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,17 @@ DEF(cap);
TOKEN("capability", TK_ISO, TK_TRN, TK_REF, TK_VAL, TK_BOX, TK_TAG);
DONE();

// GENCAP
// GENCAP
DEF(gencap);
TOKEN("generic capability", TK_CAP_READ, TK_CAP_SEND, TK_CAP_SHARE,
TK_CAP_ALIAS, TK_CAP_ANY);
DONE();

// AT
DEF(bare);
TOKEN("@", TK_AT);
DONE();

// ID [DOT ID] [typeargs] [CAP] [EPHEMERAL | ALIASED]
DEF(nominal);
AST_NODE(TK_NOMINAL);
Expand Down Expand Up @@ -242,9 +247,27 @@ DEF(lambdatype);
OPT TOKEN(NULL, TK_EPHEMERAL, TK_ALIASED);
DONE();

// (thistype | cap | typeexpr | nominal | lambdatype)
// AT_LBRACE [CAP] [ID] [typeparams] (LPAREN | LPAREN_NEW) [typelist] RPAREN
// [COLON type] [QUESTION] RBRACE [CAP] [EPHEMERAL | ALIASED]
DEF(barelambdatype);
AST_NODE(TK_BARELAMBDATYPE);
SKIP(NULL, TK_AT_LBRACE);
OPT RULE("capability", cap);
OPT TOKEN("function name", TK_ID);
OPT RULE("type parameters", typeparams);
SKIP(NULL, TK_LPAREN, TK_LPAREN_NEW);
OPT RULE("parameters", typelist);
SKIP(NULL, TK_RPAREN);
IF(TK_COLON, RULE("return type", type));
OPT TOKEN(NULL, TK_QUESTION);
SKIP(NULL, TK_RBRACE);
OPT RULE("capability", cap, gencap);
OPT TOKEN(NULL, TK_EPHEMERAL, TK_ALIASED);
DONE();

// (thistype | cap | typeexpr | nominal | lambdatype | barelambdatype)
DEF(atomtype);
RULE("type", thistype, cap, groupedtype, nominal, lambdatype);
RULE("type", thistype, cap, groupedtype, nominal, lambdatype, barelambdatype);
DONE();

// ARROW type
Expand Down Expand Up @@ -292,6 +315,7 @@ DEF(positional);
DEF(annotations);
PRINT_INLINE();
TOKEN(NULL, TK_BACKSLASH);
MAP_ID(TK_BACKSLASH, TK_ANNOTATION);
TOKEN("annotation", TK_ID);
WHILE(TK_COMMA, TOKEN("annotation", TK_ID));
TERMINATE("annotations", TK_BACKSLASH);
Expand Down Expand Up @@ -380,6 +404,33 @@ DEF(lambda);
SET_CHILD_FLAG(7, AST_FLAG_PRESERVE); // Body
DONE();

// AT_LBRACE [annotations] [CAP] [ID] [typeparams] (LPAREN | LPAREN_NEW)
// [params] RPAREN [lambdacaptures] [COLON type] [QUESTION] ARROW rawseq RBRACE
// [CAP]
DEF(barelambda);
PRINT_INLINE();
AST_NODE(TK_BARELAMBDA);
SKIP(NULL, TK_AT_LBRACE);
ANNOTATE(annotations);
OPT RULE("receiver capability", cap);
OPT TOKEN("function name", TK_ID);
OPT RULE("type parameters", typeparams);
SKIP(NULL, TK_LPAREN, TK_LPAREN_NEW);
OPT RULE("parameters", params);
SKIP(NULL, TK_RPAREN);
OPT RULE("captures", lambdacaptures);
IF(TK_COLON, RULE("return type", type));
OPT TOKEN(NULL, TK_QUESTION);
SKIP(NULL, TK_DBLARROW);
RULE("lambda body", rawseq);
TERMINATE("lambda expression", TK_RBRACE);
OPT RULE("reference capability", cap);
SET_CHILD_FLAG(2, AST_FLAG_PRESERVE); // Type parameters
SET_CHILD_FLAG(3, AST_FLAG_PRESERVE); // Parameters
SET_CHILD_FLAG(5, AST_FLAG_PRESERVE); // Return type
SET_CHILD_FLAG(7, AST_FLAG_PRESERVE); // Body
DONE();

// AS type ':'
DEF(arraytype);
PRINT_INLINE();
Expand Down Expand Up @@ -470,16 +521,18 @@ DEF(ffi);
OPT TOKEN(NULL, TK_QUESTION);
DONE();

// ref | this | literal | tuple | array | object | lambda | ffi | location
// ref | this | literal | tuple | array | object | lambda | barelambda | ffi |
// location
DEF(atom);
RULE("value", ref, thisliteral, literal, groupedexpr, array, object, lambda,
oldlambda, ffi, location);
oldlambda, barelambda, ffi, location);
DONE();

// ref | this | literal | tuple | array | object | lambda | ffi | location
// ref | this | literal | tuple | array | object | lambda | barelambda| ffi |
// location
DEF(nextatom);
RULE("value", ref, thisliteral, literal, nextgroupedexpr, nextarray, object,
lambda, oldlambda, ffi, location);
lambda, oldlambda, barelambda, ffi, location);
DONE();

// DOT ID
Expand Down Expand Up @@ -1061,13 +1114,13 @@ DEF(annotatedseq);
SCOPE();
DONE();

// (FUN | BE | NEW) [annotations] [CAP] ID [typeparams] (LPAREN | LPAREN_NEW)
// [params] RPAREN [COLON type] [QUESTION] [ARROW rawseq]
// (FUN | BE | NEW) [annotations] [CAP | AT] ID [typeparams]
// (LPAREN | LPAREN_NEW) [params] RPAREN [COLON type] [QUESTION] [ARROW rawseq]
DEF(method);
TOKEN(NULL, TK_FUN, TK_BE, TK_NEW);
ANNOTATE(annotations);
SCOPE();
OPT RULE("capability", cap);
OPT RULE("capability", cap, bare);
TOKEN("method name", TK_ID);
OPT RULE("type parameters", typeparams);
SKIP(NULL, TK_LPAREN, TK_LPAREN_NEW);
Expand Down
5 changes: 5 additions & 0 deletions src/libponyc/ast/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ typedef enum token_id
TK_MOD,
TK_MOD_TILDE,
TK_AT,
TK_AT_LBRACE,

TK_LSHIFT,
TK_LSHIFT_TILDE,
Expand Down Expand Up @@ -109,6 +110,7 @@ typedef enum token_id
TK_ACTOR,
TK_OBJECT,
TK_LAMBDA,
TK_BARELAMBDA,

TK_AS,
TK_IS,
Expand Down Expand Up @@ -196,6 +198,7 @@ typedef enum token_id
TK_THISTYPE,
TK_FUNTYPE,
TK_LAMBDATYPE,
TK_BARELAMBDATYPE,
TK_DONTCARETYPE,
TK_INFERTYPE,
TK_ERRORTYPE,
Expand Down Expand Up @@ -250,6 +253,8 @@ typedef enum token_id
TK_BECHAIN,
TK_FUNCHAIN,

TK_ANNOTATION,

// Pseudo tokens that never actually exist
TK_NEWLINE, // Used by parser macros
TK_FLATTEN, // Used by parser macros for tree building
Expand Down
13 changes: 10 additions & 3 deletions src/libponyc/codegen/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1103,12 +1103,13 @@ LLVMValueRef codegen_addfun(compile_t* c, const char* name, LLVMTypeRef type)
}

void codegen_startfun(compile_t* c, LLVMValueRef fun, LLVMMetadataRef file,
LLVMMetadataRef scope)
LLVMMetadataRef scope, bool bare)
{
compile_frame_t* frame = push_frame(c);

frame->fun = fun;
frame->is_function = true;
frame->bare_function = bare;
frame->di_file = file;
frame->di_scope = scope;

Expand All @@ -1131,6 +1132,7 @@ void codegen_pushscope(compile_t* c, ast_t* ast)
compile_frame_t* frame = push_frame(c);

frame->fun = frame->prev->fun;
frame->bare_function = frame->prev->bare_function;
frame->break_target = frame->prev->break_target;
frame->break_novalue_target = frame->prev->break_novalue_target;
frame->continue_target = frame->prev->continue_target;
Expand Down Expand Up @@ -1235,6 +1237,7 @@ void codegen_pushloop(compile_t* c, LLVMBasicBlockRef continue_target,
compile_frame_t* frame = push_frame(c);

frame->fun = frame->prev->fun;
frame->bare_function = frame->prev->bare_function;
frame->break_target = break_target;
frame->break_novalue_target = break_novalue_target;
frame->continue_target = continue_target;
Expand All @@ -1253,6 +1256,7 @@ void codegen_pushtry(compile_t* c, LLVMBasicBlockRef invoke_target)
compile_frame_t* frame = push_frame(c);

frame->fun = frame->prev->fun;
frame->bare_function = frame->prev->bare_function;
frame->break_target = frame->prev->break_target;
frame->break_novalue_target = frame->prev->break_novalue_target;
frame->continue_target = frame->prev->continue_target;
Expand Down Expand Up @@ -1357,10 +1361,13 @@ LLVMBasicBlockRef codegen_block(compile_t* c, const char* name)
}

LLVMValueRef codegen_call(compile_t* c, LLVMValueRef fun, LLVMValueRef* args,
size_t count)
size_t count, bool setcc)
{
LLVMValueRef result = LLVMBuildCall(c->builder, fun, args, (int)count, "");
LLVMSetInstructionCallConv(result, c->callconv);

if(setcc)
LLVMSetInstructionCallConv(result, c->callconv);

return result;
}

Expand Down
Loading

0 comments on commit ebd5201

Please sign in to comment.