Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Overloading: parse function overloading, and multiple fixes. Overloading now works. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
9089b014a270859cf7ee9bc679141984 |
| User & Date: | achavasse 2019-03-16 23:19:44.246 |
Context
|
2019-03-17
| ||
| 00:13 | Functions: store the signature alongside the body rather than in the type, to be consistent with template functions. check-in: cce96c5a25 user: achavasse tags: trunk | |
|
2019-03-16
| ||
| 23:19 | Overloading: parse function overloading, and multiple fixes. Overloading now works. check-in: 9089b014a2 user: achavasse tags: trunk | |
| 21:27 | Overloading: the first time a function or function template declaration is encountered, it is stored in a new overloadset. check-in: 224370818a user: achavasse tags: trunk | |
Changes
Changes to bs/builtins/types/overloadset/overloadset.cpp.
1 2 3 4 | #include "builtins/builtins.h" 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 |
#include "builtins/builtins.h"
using namespace empathy::builtins;
bool OverloadSet::add( const sema::Context& context, const Value& callee )
{
auto pInvRule = GetInvocationRule( context, callee );
assert( pInvRule );
auto signature = pInvRule->getSignature( callee );
assert( signature );
auto result = Decompose( *signature,
Vec(
Val< pvec >(),
SubTerm()
)
);
assert( result );
auto&& [params,rt] = *result;
const auto& rtype = rt;
bool success = false;
m_trie = m_trie->merge( *params, [&]( auto&& rtTrie )
{
return Merge( rtTrie, rtype, [&]( auto&& previous ) -> Overload
{
if( previous.callee )
return move( previous );
success = true;
return { pInvRule, callee };
} );
} );
return success;
}
OverloadSet::UniGen OverloadSet::unify( const Term& argsPat, const Term& rtPat, UnificationContext& uc ) const
{
auto argDecomp = Decompose( argsPat,
Val< pvec >()
);
|
| ︙ | ︙ |
Changes to bs/builtins/types/overloadset/overloadset.h.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
public:
struct Overload
{
ptr< InvocationRule > pInvRule;
optional< Value > callee;
};
| > > > > > > | > > | 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 |
public:
struct Overload
{
ptr< InvocationRule > pInvRule;
optional< Value > callee;
};
OverloadSet( const StringId& name ) :
m_name( name )
{}
const auto& name() const { return m_name; }
bool add( const sema::Context& context, const Value& callee );
using UniGen = Generator< tuple<
Term,
const Overload&,
UnificationContext
> >;
UniGen unify( const Term& argsPat, const Term& rtPat, UnificationContext& uc ) const;
private:
StringId m_name;
using utrie_type = UTrie< Trie< Overload > >;
ptr< utrie_type > m_trie = make_shared< utrie_type >();
};
extern bool IsOverloadSet( const Value& os );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/invoke.cpp.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
UnificationContext uc( env );
optional< UnificationContext > bestUC;
optional< Term > bestSol;
bool ambiguous = false;
auto callPat = TVEC( args.val(), sema::MkHole( "_"_sid ) );
for( auto&& [s, uc] : Unify( tf->signature(), callPat, uc ) )
{
if( uc.numUnknownValues() )
continue;
if( !bestSol || uc.score() > bestUC->score() )
{
| > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
UnificationContext uc( env );
optional< UnificationContext > bestUC;
optional< Term > bestSol;
bool ambiguous = false;
auto callPat = TVEC( args.val(), sema::MkHole( "_"_sid ) );
for( auto&& [s, uc] : Unify( tf->signature(), callPat, uc ) )
{
if( uc.numUnknownValues() )
continue;
if( !bestSol || uc.score() > bestUC->score() )
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tfunc.cpp.
1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
using namespace empathy::builtins;
using namespace empathy::parse;
namespace empathy::ir
{
| | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
using namespace empathy::builtins;
using namespace empathy::parse;
namespace empathy::ir
{
Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
{
return ValueToIRExpr( ::ToValue( tf.type() ) );
}
Value Bridge< TFunc >::ToValue( const TFunc& tf )
{
return Value( Type( tf ), TVEC( tf.signature(), tf.identity(),
TERM( static_pointer_cast< void >( tf.toks() ) ) ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tfunc.h.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
}
namespace empathy::ir
{
template<>
struct Bridge< builtins::TFunc >
{
| | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
}
namespace empathy::ir
{
template<>
struct Bridge< builtins::TFunc >
{
static Term Type( const builtins::TFunc& tf );
static Value ToValue( const builtins::TFunc& tf );
static optional< builtins::TFunc > FromValue( const Value& v );
};
}
#endif
|
Changes to bs/parse/CMakeLists.txt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
add_library( empathy-parse
resolver.cpp
parser.cpp
rule-helpers.cpp
blocks.cpp
func.cpp
tfunc.cpp
)
target_link_libraries( empathy-parse
empathy-lex
empathy-sema
empathy-builtins
)
| > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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
empathy-sema
empathy-builtins
)
|
Changes to bs/parse/func.cpp.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
const auto& c = m_resolver->context();
auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );
// 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.
| | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
const auto& c = m_resolver->context();
auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );
// 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 >( d->name() );
pOvlSet->add( c, *func );
c.env()->storeValue( funcValIdentity, ANYTERM( c ),
ValueToIRExpr( ToValue( pOvlSet ) ) );
return true;
}
|
| ︙ | ︙ |
Added bs/parse/overload.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 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"
using namespace empathy;
using namespace empathy::parse;
using namespace empathy::builtins;
optional< uint32_t > Parser::getInfixOverloadSetPrecedence()
{
if( isInParenExpr() )
return nullopt;
auto next = m_resolver->lookAheadUnresolved( 1 );
if( !next )
return nullopt;
auto decomp = Decompose( *next, Val< Delimiter >() );
if( !decomp || *decomp != Delimiter::OpenParen )
return nullopt;
return precedence::Application;
}
bool Parser::parseInfixOverloadSet( const ptr< builtins::OverloadSet >& pOvlSet, uint32_t prec )
{
auto rt = *pop();
m_resolver->consume();
auto params = parseParenBlock( Delimiter::OpenParen );
if( !params )
return false;
optional< Value > func;
if( rt.type() == TSID( type ) )
func = parseFunctionDeclaration( pOvlSet->name(), rt, *params );
else if( IsTExpr( rt ) )
func = parseTemplateFunction( pOvlSet->name(), rt, *params );
if( !func )
return false;
const auto& c = m_resolver->context();
if( !pOvlSet->add( c, *func ) )
{
cout << "error: duplicate function overload\n";
return false;
}
return true;
}
|
Changes to bs/parse/parser.cpp.
| ︙ | ︙ | |||
166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
}
optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
auto val = ValueFromIRExpr( t );
if( !val )
return nullopt;
// If the term is an infix rule value, invoke its getPrecedence() function.
auto rule = FromValue< Rule >( *val );
if( !rule )
return nullopt;
if( !rule->isInfix() )
| > > > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
}
optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
auto val = ValueFromIRExpr( t );
if( !val )
return nullopt;
if( val->type() == GetValueType< ptr< OverloadSet > >() )
return getInfixOverloadSetPrecedence();
// If the term is an infix rule value, invoke its getPrecedence() function.
auto rule = FromValue< Rule >( *val );
if( !rule )
return nullopt;
if( !rule->isInfix() )
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
{
auto t = *m_resolver->lookAhead();
auto val = ValueFromIRExpr( t );
if( !val )
return false;
// If the term is an infix rule value, invoke its parseInfix() function.
auto rule = FromValue< Rule >( *val );
if( !rule )
return false;
m_resolver->consume();
if( !rule->isInfix() )
return false;
return rule->parseInfix( *this, t, prec );
}
| > > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
{
auto t = *m_resolver->lookAhead();
auto val = ValueFromIRExpr( t );
if( !val )
return false;
if( val->type() == GetValueType< ptr< OverloadSet > >() )
return parseInfixOverloadSet( FromValue< ptr< OverloadSet > >( *val ), prec );
// If the term is an infix rule value, invoke its parseInfix() function.
auto rule = FromValue< Rule >( *val );
if( !rule )
return false;
m_resolver->consume();
if( !rule->isInfix() )
return false;
return rule->parseInfix( *this, t, prec );
}
|
Changes to bs/parse/parser.h.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
{
optional< Value > result;
swap( result, m_lastValue );
return result;
}
optional< Value > result();
private:
optional< uint32_t > getPrecedence( const Term& t );
bool parsePrefix( const Term&, uint32_t precedence );
bool parseInfix( const Term&, uint32_t precedence );
// Default getPrecedence overload
| > > > > > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
{
optional< Value > result;
swap( result, m_lastValue );
return result;
}
optional< Value > result();
bool isInParenExpr() const
{
return m_introDelimiter && *m_introDelimiter == Delimiter::OpenParen;
}
private:
optional< uint32_t > getPrecedence( const Term& t );
bool parsePrefix( const Term&, uint32_t precedence );
bool parseInfix( const Term&, uint32_t precedence );
// Default getPrecedence overload
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
optional< Value > parseFunctionDeclaration( const StringId& name, const Value& returnType, const Value& params );
// Template functions
bool parseTemplateFunctionExpression( const Value& returnType, const Value& params );
bool parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& params );
optional< Value > parseTemplateFunction( const StringId& name, const Value& returnType, const Value& params );
// Resolver to fetch input terms from.
ptr< Resolver > m_resolver;
// The sequence under construction.
ptr< llr::Seq > m_seq;
// The last value that we have built,
| > > > > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
optional< Value > parseFunctionDeclaration( const StringId& name, const Value& returnType, const Value& params );
// Template functions
bool parseTemplateFunctionExpression( const Value& returnType, const Value& params );
bool parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& params );
optional< Value > parseTemplateFunction( const StringId& name, const Value& returnType, const Value& params );
// 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;
// The sequence under construction.
ptr< llr::Seq > m_seq;
// The last value that we have built,
|
| ︙ | ︙ |
Changes to bs/parse/tfunc.cpp.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 |
const auto& c = m_resolver->context();
auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );
// 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.
| | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
const auto& c = m_resolver->context();
auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );
// 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 >( d->name() );
pOvlSet->add( c, *tfunc );
c.env()->storeValue( funcValIdentity, ANYTERM( c ),
ValueToIRExpr( ToValue( pOvlSet ) ) );
return true;
}
|
| ︙ | ︙ |
Changes to lib/empathy.em.
1 2 3 4 5 6 7 8 | // Front-end. This is the interpreted code entry point, directly // executed by the empathy command. // // This will setup the prelude and drive the compilation // process (through function calls exposed by empathy). // For now it's just a playground to dump test code. | | > > | > > > > | > > > > | > | > > > > > | > | > > | > > > > > | > > > > > > | > | > > > > | | | > | > > > > > > > > > > | > > > > > | > > > > > > > | 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 |
// Front-end. This is the interpreted code entry point, directly
// executed by the empathy command.
//
// This will setup the prelude and drive the compilation
// process (through function calls exposed by empathy).
// For now it's just a playground to dump test code.
void testTmpl( ct_string foo )
{
Print( foo );
}
void testTmpl( $T foo )
{
Print( "whatever" )
}
void testTmpl( ct_int foo )
{
Print( "integer" )
}
testTmpl( 123 )
testTmpl( "Test2" )
// TODO: The following call ought to print "whatever", but
// the value of Print fails to unify because it contains the function's signature, whose holes
// are left unresolved. The signature pattern should really not be stored in the type, but along with
// the function's body, like for templates.
// testTmpl( Print )
///////////////////////////////////////////////
void test( $T a, $U b )
{
Print( "different types" )
}
void test( $T a, $T b )
{
Print( "same types" )
}
test(1,2)
test("a", "b")
test(1,"a")
test("b",45)
///////////////////////////////////////////////
using args = Args()
void testFunc()
{
Print( "testFunc: overload 1" )
}
void testFunc( ct_string foo )
{
Print( "testFunc: overload 2" )
Print( foo )
}
void testFunc( ct_int foo )
{
Print( "testFunc: overload 3" )
}
void testFunc( ct_int foo, ct_string bar )
{
Print( "testFunc: overload 4" )
Print( bar )
}
void testFunc( ct_string foo, ct_int bar )
{
Print( "testFunc: overload 5" )
Print( foo )
}
testFunc( "gg" )
testFunc()
testFunc( 1234 )
testFunc( 12347, args )
testFunc( "meh", 878787 )
|