Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Parser: refactored function and template function parsing to go through a common code path to build function types. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
5fd301c5f90f3d50a354c8a396c09fb7 |
| User & Date: | achavasse 2019-07-07 10:33:19.908 |
Context
|
2019-07-07
| ||
| 16:22 | Parser: parse function type modifiers. check-in: 105ba83ebf user: achavasse tags: trunk | |
| 10:33 | Parser: refactored function and template function parsing to go through a common code path to build function types. check-in: 5fd301c5f9 user: achavasse tags: trunk | |
|
2019-07-06
| ||
| 13:27 | Cleanup: remove a superfluous argument from BuildFunc(). check-in: f0724b61e5 user: achavasse tags: trunk | |
Changes
Changes to bs/builtins/types/func/build.cpp.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
return true;
} );
return FuncType( domain, ValueToIRExpr( returnType ),
TERM( make_shared< Vector >( tvt.persistent(), false ) ) );
}
| | | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
return true;
} );
return FuncType( domain, ValueToIRExpr( returnType ),
TERM( make_shared< Vector >( tvt.persistent(), false ) ) );
}
Value BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const pvec& unparsedBody, Context& out_bodyContext )
{
auto funcType = BuildFuncType( domain, returnType, paramsDecl );
return BuildFunc( c, funcType, funcIdentity, paramsDecl, unparsedBody, out_bodyContext );
}
Value BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& paramsDecl, const pvec& unparsedBody, Context& out_bodyContext )
{
// TODO: instead of a normal import rule, we should use a custom visibility
// rule that deals with variables from the parent context in a special way:
// If the function body tries to access variables from the parent function,
// we should invoke an overridable global function that can transform both the
// variable object and the function type. This way, we can implement/customize
// smart lexical captures from inside the language itself (and at a minimum, have
|
| ︙ | ︙ | |||
52 53 54 55 56 57 58 |
c.env()->addTransitiveImport(
InjectDomainIntoIdentity( c.identity(), DomainCompileTime() ),
InjectDomainIntoIdentity( identity, ANYTERM( domain2 ) ) );
// Create the local variable bindings to access the function params
// from inside the body, as well as the signature.
vector< uint32_t > paramVarIds;
| | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
c.env()->addTransitiveImport(
InjectDomainIntoIdentity( c.identity(), DomainCompileTime() ),
InjectDomainIntoIdentity( identity, ANYTERM( domain2 ) ) );
// Create the local variable bindings to access the function params
// from inside the body, as well as the signature.
vector< uint32_t > paramVarIds;
paramVarIds.reserve( TupleSize( paramsDecl ) );
ForEachInTuple( paramsDecl, [&]( auto&& param )
{
if( !IsDecl( param ) )
{
paramVarIds.emplace_back( llr::InvalidVarId );
return true;
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/build.h.
1 2 3 4 5 6 7 |
#ifndef EMPATHY_BUILTINS_FUNC_BUILD_H
#define EMPATHY_BUILTINS_FUNC_BUILD_H
namespace empathy::builtins
{
extern FuncType BuildFuncType( const Term& domain, const Value& returnType, const Value& params );
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#ifndef EMPATHY_BUILTINS_FUNC_BUILD_H
#define EMPATHY_BUILTINS_FUNC_BUILD_H
namespace empathy::builtins
{
extern FuncType BuildFuncType( const Term& domain, const Value& returnType, const Value& params );
extern Value BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const pvec& unparsedBody, Context& out_bodyContext );
extern Value BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& paramsDecl, const pvec& unparsedBody,
Context& out_bodyContext );
extern Term BuildCallPatternFromFuncType( const Value& funcType );
}
#endif
|
Changes to bs/builtins/types/template/build.cpp.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 |
return TVEC(
tft.domain(),
TERM( make_shared< Vector >( vt.persistent(), false ) ),
*rtSig );
}
| | < < | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
return TVEC(
tft.domain(),
TERM( make_shared< Vector >( vt.persistent(), false ) ),
*rtSig );
}
optional< Value > BuildTFunc( const Context& c, const TFuncType& tft, const Term& identity, const Value& params, pvec&& body )
{
auto sig = BuildTFuncSignature( c, tft );
if( !sig )
return nullopt;
return ToValue( TFunc( tft, *sig, identity, move( body ) ) );
}
optional< Term > BuildArgPatternFromTFuncType( const Context& c, const Value& tfuncType )
{
const auto& ftype = FromValue< TFuncType >( tfuncType );
assert( ftype );
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/build.h.
1 2 3 4 5 6 7 8 |
#ifndef EMPATHY_BUILTINS_TEMPLATE_BUILD_H
#define EMPATHY_BUILTINS_TEMPLATE_BUILD_H
namespace empathy::builtins
{
extern optional< TDecl > BuildTDecl( const Context& c, const Term& typeTExpr, const StringId& name );
extern TFuncType BuildTFuncType( const Term& domain, const Value& returnType, const Value& params );
extern optional< Term > BuildTFuncSignature( const Context& c, const TFuncType& tft );
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#ifndef EMPATHY_BUILTINS_TEMPLATE_BUILD_H
#define EMPATHY_BUILTINS_TEMPLATE_BUILD_H
namespace empathy::builtins
{
extern optional< TDecl > BuildTDecl( const Context& c, const Term& typeTExpr, const StringId& name );
extern TFuncType BuildTFuncType( const Term& domain, const Value& returnType, const Value& params );
extern optional< Term > BuildTFuncSignature( const Context& c, const TFuncType& tft );
extern optional< Value > BuildTFunc( const Context& c, const TFuncType& tft, const Term& identity, const Value& params, pvec&& body );
extern optional< Term > BuildArgPatternFromTFuncType( const Context& c, const Value& tfuncType );
}
#endif
|
Changes to bs/parse/CMakeLists.txt.
1 2 3 4 5 6 7 8 9 10 11 12 |
add_library( empathy-parse
resolver.cpp
parser.cpp
rule-helpers.cpp
blocks.cpp
func.cpp
tfunc.cpp
overload.cpp
)
target_link_libraries( empathy-parse
empathy-lex
| > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
add_library( empathy-parse
resolver.cpp
parser.cpp
rule-helpers.cpp
blocks.cpp
functype.cpp
func.cpp
tfunc.cpp
overload.cpp
)
target_link_libraries( empathy-parse
empathy-lex
|
| ︙ | ︙ |
Changes to bs/parse/func.cpp.
1 2 3 4 5 6 7 8 | #include "parse.h" #include "builtins/builtins.h" #include "precedence.h" using namespace empathy; using namespace empathy::parse; using namespace empathy::builtins; | | < < < | < | < > | < < < < | < | < | | > > | | | | > > > | | < < < < < < | < | < < < < < > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"
using namespace empathy;
using namespace empathy::parse;
using namespace empathy::builtins;
bool Parser::parseFunctionExpression( const Value& returnType, const Value& paramsDecl )
{
if( !parseFuncType( returnType, paramsDecl ) )
return false;
if( IsTExpr( *peekLastValue() ) )
return parseTemplateFunctionExpression( paramsDecl );
// Check if a brace block follows, in which case this is a function declaration. Otherwise, it's just a function type.
auto next = m_resolver->lookAheadUnresolved();
if( !next )
{
// Just leave the type as is, nothing to do.
return true;
}
auto decomp = Decompose( *next, Val< Delimiter >() );
if( !decomp || *decomp != Delimiter::OpenBrace )
{
// Just leave the type as is, nothing to do.
return true;
}
return parseFunctionDeclExpr( paramsDecl );
}
bool Parser::parseFunctionDeclExpr( const Value& paramsDecl )
{
auto funcType = *FromValue< FuncType >( *popValue() );
auto pBody = getFuncBody();
if( !pBody )
return false;
const auto& c = m_resolver->context();
auto identity = AppendToVectorTerm( c.identity(), TERM( StringId( m_resolver->context().env()->GetUniqueId() ) ) );
auto bodyContext = m_resolver->context();
auto func = BuildFunc( m_resolver->context(), funcType,
identity, paramsDecl, move( pBody ), bodyContext );
if( !CompileFunc( c, func ) )
return false;
pushValue( move( func ) );
return true;
}
bool Parser::parseFunctionDeclaration( const Value& decl, const Value& paramsDecl )
{
auto d = FromValue< Decl >( decl );
if( !parseFuncType( *ValueFromIRExpr( d->type() ), paramsDecl ) )
return false;
const auto& c = m_resolver->context();
auto funcIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );
// We want all functions to always be visible in the compile time domain, so we can retrieve
// them when they are not present in other domains. OverloadSets themselves should only
// live in the CompileTime domain as well. This is why we set the function identity's domain to CompileTime.
funcIdentity = InjectDomainIntoIdentity( funcIdentity, DomainCompileTime() );
auto func = parseFunctionDeclaration( funcIdentity, paramsDecl );
if( !func )
return false;
// If we're here, this is not an overload, but the first time we come accross this function.
// So create a new overload set. The case of actually overloading an existing function is parsed
// elsewhere.
auto pOvlSet = make_shared< OverloadSet >( funcIdentity );
pOvlSet->add( c, *func );
c.env()->storeValue( funcIdentity, ANYTERM( _ ),
ValueToIRExpr( ToValue( pOvlSet ) ) );
return true;
}
optional< Value > Parser::parseFunctionDeclaration( const Term& identity, const Value& paramsDecl )
{
if( IsTExpr( *peekLastValue() ) )
return parseTemplateFunction( identity, paramsDecl );
auto pBody = getFuncBody();
if( !pBody )
return nullopt;
auto& c = m_resolver->context();
auto bodyContext = c;
auto funcType = *FromValue< FuncType >( *popValue() );
return BuildFunc( c, funcType, identity, paramsDecl, move( pBody ), bodyContext );
}
pvec Parser::getFuncBody()
{
auto next = m_resolver->lookAheadUnresolved();
if( !next )
{
|
| ︙ | ︙ |
Added bs/parse/functype.cpp.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"
using namespace empathy;
using namespace empathy::parse;
using namespace empathy::builtins;
bool Parser::parseFuncType( const Value& returnType, const Value& paramsDecl )
{
// Check if the params are valid, and whether they might actually be template params.
switch( CheckParamListKind( paramsDecl ) )
{
case ParamListKind::Invalid:
cout << "function expression: invalid param list.\n";
return false;
case ParamListKind::Template:
pushValue( ToValue( BuildTFuncType( DomainCompileTime(), returnType, paramsDecl ) ) );
break;
case ParamListKind::Regular:
pushValue( ToValue( BuildFuncType( DomainCompileTime(), returnType, paramsDecl ) ) );
break;
}
// TODO recursive parsing call to handle modifiers such as domain specifiers
return true;
}
bool Parser::parseTFuncType( const Value& returnType, const Value& paramsDecl )
{
pushValue( ToValue( BuildTFuncType( DomainCompileTime(), returnType, paramsDecl ) ) );
// TODO recursive parsing call to handle modifiers such as domain specifiers
return true;
}
|
Changes to bs/parse/overload.cpp.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 |
}
bool Parser::parseInfixOverloadSet( const ptr< builtins::OverloadSet >& pOvlSet, uint32_t prec )
{
auto rt = *popValue();
m_resolver->consume();
| | | > > > < < | | > > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
}
bool Parser::parseInfixOverloadSet( const ptr< builtins::OverloadSet >& pOvlSet, uint32_t prec )
{
auto rt = *popValue();
m_resolver->consume();
auto paramsDecl = parseParenBlock();
if( !paramsDecl )
return false;
if( !parseFuncType( rt, *paramsDecl ) )
return false;
optional< Value > func;
if( IsTExpr( *peekLastValue() ) )
func = parseTemplateFunction( pOvlSet->identity(), *paramsDecl );
else
func = parseFunctionDeclaration( pOvlSet->identity(), *paramsDecl );
if( !func )
return false;
const auto& c = m_resolver->context();
if( !pOvlSet->add( c, *func ) )
{
|
| ︙ | ︙ |
Changes to bs/parse/parser.h.
| ︙ | ︙ | |||
108 109 110 111 112 113 114 115 |
optional< Value > parseParenBlock();
optional< uint32_t > getPostfixParenBlockPrecedence();
bool parsePostfixParenBlock( uint32_t prec );
bool parseBraceBlock();
// Functions
| > > > | | | | | > | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
optional< Value > parseParenBlock();
optional< uint32_t > getPostfixParenBlockPrecedence();
bool parsePostfixParenBlock( uint32_t prec );
bool parseBraceBlock();
bool parseFuncType( const Value& returnType, const Value& paramsDecl );
bool parseTFuncType( const Value& returnType, const Value& paramsDecl );
// Functions
bool parseFunctionExpression( const Value& returnType, const Value& paramsDecl );
bool parseFunctionDeclExpr( const Value& paramsDecl );
bool parseFunctionDeclaration( const Value& decl, const Value& paramsDecl );
optional< Value > parseFunctionDeclaration( const Term& identity, const Value& paramsDecl );
// Template functions
bool parseTemplateFunctionExpression( const Value& returnType, const Value& paramsDecl );
bool parseTemplateFunctionExpression( const Value& paramsDecl );
bool parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl );
optional< Value > parseTemplateFunction( const Term& identity, const Value& paramsDecl );
// Overloading
optional< uint32_t > getInfixOverloadSetPrecedence();
bool parseInfixOverloadSet( const ptr< builtins::OverloadSet >& pOvlSet, uint32_t prec );
// Resolver to fetch input terms from.
ptr< Resolver > m_resolver;
|
| ︙ | ︙ |
Changes to bs/parse/tfunc.cpp.
1 2 3 4 5 6 7 8 | #include "parse.h" #include "builtins/builtins.h" #include "precedence.h" using namespace empathy; using namespace empathy::parse; using namespace empathy::builtins; | | | | | < | | > > | < | < | < | > > > | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"
using namespace empathy;
using namespace empathy::parse;
using namespace empathy::builtins;
bool Parser::parseTemplateFunctionExpression( const Value& returnType, const Value& paramsDecl )
{
if( !parseTFuncType( returnType, paramsDecl ) )
return false;
return parseTemplateFunctionExpression( paramsDecl );
}
bool Parser::parseTemplateFunctionExpression( const Value& paramsDecl )
{
// Check if a brace block follows, in which case this is a function declaration. Otherwise, it's just a function type.
auto next = m_resolver->lookAheadUnresolved();
if( !next )
{
// Just leave the type as is, nothing to do.
return true;
}
auto decomp = Decompose( *next, Val< Delimiter >() );
if( !decomp || *decomp != Delimiter::OpenBrace )
{
// Just leave the type as is, nothing to do.
return true;
}
const auto& c = m_resolver->context();
auto tfuncIdentity = AppendToVectorTerm( c.identity(),
TERM( StringId( m_resolver->context().env()->GetUniqueId() ) ) );
auto tfunc = parseTemplateFunction( tfuncIdentity, paramsDecl );
if( !tfunc )
return false;
pushValue( *tfunc );
return true;
}
bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl )
{
auto d = FromValue< TNamedDecl >( tnamedDecl );
if( !parseTFuncType( *ValueFromIRExpr( d->type() ), paramsDecl ) )
return false;
const auto& c = m_resolver->context();
auto tfuncIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );
// We want all functions to always be visible in the compile time domain, so we can retrieve
// them when they are not present in other domains. OverloadSets themselves should only
// live in the CompileTime domain as well. This is why we set the function identity's domain to CompileTime.
tfuncIdentity = InjectDomainIntoIdentity( tfuncIdentity, DomainCompileTime() );
auto tfunc = parseTemplateFunction( tfuncIdentity, paramsDecl );
if( !tfunc )
return false;
// If we're here, this is not an overload, but the first time we come accross this function.
// So create a new overload set. The case of actually overloading an existing function is parsed
// elsewhere.
auto pOvlSet = make_shared< OverloadSet >( tfuncIdentity );
pOvlSet->add( c, *tfunc );
c.env()->storeValue( tfuncIdentity, ANYTERM( _ ),
ValueToIRExpr( ToValue( pOvlSet ) ) );
return true;
}
optional< Value > Parser::parseTemplateFunction( const Term& identity, const Value& paramsDecl )
{
auto pBody = getFuncBody();
if( !pBody )
return nullopt;
auto& c = m_resolver->context();
auto tFuncType = *FromValue< TFuncType >( *popValue() );
// TODO syntax for domain specifier
return BuildTFunc( c, tFuncType, identity, paramsDecl, move( pBody ) );
}
|