Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: |
|
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
9d81e31cfebf9f9d6690200bb746d5f4 |
| User & Date: | achavasse 2019-08-18 14:51:10.311 |
Context
|
2019-08-18
| ||
| 15:35 | llr: added the break and continue terminators. check-in: b16e7c5933 user: achavasse tags: trunk | |
| 14:51 |
| |
| 00:54 |
| |
Changes
Changes to bs/builtins/api/compiler.cpp.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
parse::Parser p( r );
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
p.parseSequence();
if( !r->eos() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
r->getCurrentLocation(), "syntax error." );
return 0;
}
| > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
parse::Parser p( r );
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
p.parseSequence();
if( cfg->isPoisoned() )
return 0;
if( !r->eos() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
r->getCurrentLocation(), "syntax error." );
return 0;
}
|
| ︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
p.parseSequence();
if( !r->eos() )
{
pFuncLLR->setInvalid();
DiagnosticsManager::GetInstance().emitErrorMessage(
r->getCurrentLocation(), "syntax error." );
return ToValue( func ).setPoison();
}
| > > > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
p.parseSequence();
if( cfg->isPoisoned() )
return PoisonValue();
if( !r->eos() )
{
pFuncLLR->setInvalid();
DiagnosticsManager::GetInstance().emitErrorMessage(
r->getCurrentLocation(), "syntax error." );
return ToValue( func ).setPoison();
}
|
| ︙ | ︙ |
Changes to bs/builtins/statements/if.cpp.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 |
{
void SetupIfStmt( Env& e )
{
auto handleIf = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
| | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{
void SetupIfStmt( Env& e )
{
auto handleIf = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
if( p.isInParenExpr() || !p.cfg() )
{
dm.emitSyntaxErrorMessage( locationId, "the if statement is not allowed here.", 0 );
return false;
}
auto pPrecBB = p.currentBB();
|
| ︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
case ValUnifyError::Ambiguous:
dm.emitSyntaxErrorMessage( condVal->locationId(), "ambiguous if condition bool conversion." );
break;
}
return false;
}
auto pThenBB = ParseSubStatement( p, precedence::IfStmt );
if( !pThenBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->getCurrentLocation(), "expected a statement after the if condition.", 0 );
return false;
}
| > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
case ValUnifyError::Ambiguous:
dm.emitSyntaxErrorMessage( condVal->locationId(), "ambiguous if condition bool conversion." );
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
p.cfg()->poison();
auto pThenBB = ParseSubStatement( p, precedence::IfStmt );
if( !pThenBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->getCurrentLocation(), "expected a statement after the if condition.", 0 );
return false;
}
|
| ︙ | ︙ |
Changes to bs/builtins/statements/return.cpp.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 |
{
void SetupReturnStmt( Env& e )
{
auto handleReturn = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
| | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{
void SetupReturnStmt( Env& e )
{
auto handleReturn = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
if( p.isInParenExpr() || !p.cfg() )
{
dm.emitSyntaxErrorMessage( locationId, "the return statement is not allowed here.", 0 );
return false;
}
const auto& context = p.resolver()->context();
|
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
dm.emitErrorMessage( retVal->locationId(), "ambiguous return value conversion." );
break;
}
// Emit a terminator with a poison value to avoid the function compilation
// code to complain about a missing return.
p.emitTerminator( llr::Ret( PoisonValue() ) );
| > | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
dm.emitErrorMessage( retVal->locationId(), "ambiguous return value conversion." );
break;
}
// Emit a terminator with a poison value to avoid the function compilation
// code to complain about a missing return.
p.emitTerminator( llr::Ret( PoisonValue() ) );
p.cfg()->poison();
return true;
}
p.emitTerminator( llr::Ret( get< Value >( converted ) ) );
return true;
};
Rule r( handleReturn );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToIRExpr( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( return ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/statements/while.cpp.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 |
{
void SetupWhileStmt( Env& e )
{
auto handleWhile = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
| | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{
void SetupWhileStmt( Env& e )
{
auto handleWhile = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
if( p.isInParenExpr() || !p.cfg() )
{
dm.emitSyntaxErrorMessage( locationId, "the while statement is not allowed here.", 0 );
return false;
}
auto pPrecBB = p.currentBB();
|
| ︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
case ValUnifyError::Ambiguous:
dm.emitSyntaxErrorMessage( condVal->locationId(), "ambiguous while condition bool conversion." );
break;
}
return false;
}
auto pHeaderBB = p.cfg()->createBB();
auto pBodyBB = ParseSubStatement( p, precedence::IfStmt );
if( !pBodyBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->getCurrentLocation(), "expected a statement after the while condition.", 0 );
| > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
case ValUnifyError::Ambiguous:
dm.emitSyntaxErrorMessage( condVal->locationId(), "ambiguous while condition bool conversion." );
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
p.cfg()->poison();
auto pHeaderBB = p.cfg()->createBB();
auto pBodyBB = ParseSubStatement( p, precedence::IfStmt );
if( !pBodyBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->getCurrentLocation(), "expected a statement after the while condition.", 0 );
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/bfunc.inl.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 |
template< typename R, typename... T >
template< typename F >
auto Bridge< R ( T... ) >::WrapFunc( F&& func )
{
return [func]( const Term& argVec ) -> Value
{
auto params = Bridge< tuple< typename StripCustomPattern< T >::type... > >::FromVectorTerm( argVec );
| | > | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
template< typename R, typename... T >
template< typename F >
auto Bridge< R ( T... ) >::WrapFunc( F&& func )
{
return [func]( const Term& argVec ) -> Value
{
auto params = Bridge< tuple< typename StripCustomPattern< T >::type... > >::FromVectorTerm( argVec );
if( !params )
return PoisonValue();
if constexpr( is_void_v< builtins::remove_eager_t< R > > )
{
apply( func, *params );
return Value( GetValueType< void >(), 0U );
}
else
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/func.cpp.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
{
static auto pattern = ValueToIRExpr(
Value( TypeType(), VEC( TSID( func ), MkHole( "llvmType"_sid ),
MkHole( "_"_sid ), MkHole( "_"_sid ), MkHole( "_"_sid ) ) ) );
return pattern;
}
bool IsFuncType( const Value& t )
{
auto result = Decompose( t.val(),
Vec(
Lit( "func"_sid ),
Val< void* >(),
| > > > > > > > > > > > > > | 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 |
{
static auto pattern = ValueToIRExpr(
Value( TypeType(), VEC( TSID( func ), MkHole( "llvmType"_sid ),
MkHole( "_"_sid ), MkHole( "_"_sid ), MkHole( "_"_sid ) ) ) );
return pattern;
}
bool IsExternalFunc( const Value& f )
{
if( !f.isConstant() )
return false;
// Try to decode it as an external func
auto result = Decompose( f.val(),
Val< string >()
);
return !!result;
}
bool IsFuncType( const Value& t )
{
auto result = Decompose( t.val(),
Vec(
Lit( "func"_sid ),
Val< void* >(),
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 |
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
bool success = p.parseBraceBlock();
p.flushValue();
| | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
bool success = p.parseBraceBlock();
p.flushValue();
if( !success || cfg->isPoisoned() )
{
// Fail silently here, because it may be a case of trying
// to execute an invocation at compile time before falling
// back to code generation.
// It's up to our caller to catch the error here, if any.
pFuncLLR->setInvalid();
return false;
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/func.h.
| ︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
private:
Term m_domain;
Term m_returnType;
Term m_params;
llvm::FunctionType* m_pllvmType = nullptr;
};
extern bool IsFuncType( const Value& t );
class Func
{
public:
template< typename T, typename B >
Func( T&& funcType, B&& toks, llr::Func* llr ) :
| > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
private:
Term m_domain;
Term m_returnType;
Term m_params;
llvm::FunctionType* m_pllvmType = nullptr;
};
extern bool IsExternalFunc( const Value& f );
extern bool IsFuncType( const Value& t );
class Func
{
public:
template< typename T, typename B >
Func( T&& funcType, B&& toks, llr::Func* llr ) :
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/unify.cpp.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
auto wrapped = WrapWithPostprocFunc( rhs, [rhsVal]( const Term& t, const UnificationContext& uc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( uc.context(), rhsVal );
return ValueToIRExpr( func );
} );
co_yield { move( wrapped ), uc };
} );
// tfunc type param / func arg
| > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
auto wrapped = WrapWithPostprocFunc( rhs, [rhsVal]( const Term& t, const UnificationContext& uc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( uc.context(), rhsVal );
if( func.isPoison() )
return nullopt;
return ValueToIRExpr( func );
} );
co_yield { move( wrapped ), uc };
} );
// tfunc type param / func arg
|
| ︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
auto wrapped = WrapWithPostprocFunc( s, [rhsVal]( const Term& t, const UnificationContext& uc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( uc.context(), rhsVal );
return ValueToIRExpr( func );
} );
co_yield { move( wrapped ), uc };
}
} );
}
}
| > > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
auto wrapped = WrapWithPostprocFunc( s, [rhsVal]( const Term& t, const UnificationContext& uc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( uc.context(), rhsVal );
if( func.isPoison() )
return nullopt;
return ValueToIRExpr( func );
} );
co_yield { move( wrapped ), uc };
}
} );
}
}
|
Changes to bs/builtins/types/overloadset/unify.cpp.
| ︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
auto overload = ovl;
auto wrapped = WrapWithPostprocFunc( s,
[overload,localNSId,rhsLocId]( const Term& t, UnificationContext& uc ) -> optional< Term >
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( uc.context(), rhsLocId, *overload.callee, t, localC.flip() );
return ValueToIRExpr( move( func ) );
} );
co_yield { move( wrapped ), uc };
}
uc.flip();
| > > > > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
auto overload = ovl;
auto wrapped = WrapWithPostprocFunc( s,
[overload,localNSId,rhsLocId]( const Term& t, UnificationContext& uc ) -> optional< Term >
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( uc.context(), rhsLocId, *overload.callee, t, localC.flip() );
if( func.isPoison() )
return nullopt;
return ValueToIRExpr( move( func ) );
} );
co_yield { move( wrapped ), uc };
}
uc.flip();
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
auto overload = ovl;
auto wrapped = WrapWithPostprocFunc( s,
[overload,localNSId,rhsLocId]( const Term& t, UnificationContext& uc ) -> optional< Term >
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( uc.context(), rhsLocId, *overload.callee, t, localC.flip() );
return ValueToIRExpr( move( func ) );
} );
co_yield { move( wrapped ), uc };
}
uc.flip();
uc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
} );
}
}
| > > > > | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
auto overload = ovl;
auto wrapped = WrapWithPostprocFunc( s,
[overload,localNSId,rhsLocId]( const Term& t, UnificationContext& uc ) -> optional< Term >
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( uc.context(), rhsLocId, *overload.callee, t, localC.flip() );
if( func.isPoison() )
return nullopt;
return ValueToIRExpr( move( func ) );
} );
co_yield { move( wrapped ), uc };
}
uc.flip();
uc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
} );
}
}
|
Changes to bs/builtins/types/template/instantiate.cpp.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
} );
instanceFunc = ToValue( func );
// TODO: better description including the function's name
DiagnosticsContext dc( callee.locationId(), "In the template function declared here.", false );
| | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
} );
instanceFunc = ToValue( func );
// TODO: better description including the function's name
DiagnosticsContext dc( callee.locationId(), "In the template function declared here.", false );
instanceFunc = CompileFunc( c, instanceFunc );
c.env()->storeValue( instanceIdentity, ANYTERM( _ ), ValueToIRExpr( instanceFunc ) );
break;
}
case Env::Status::AmbiguousMatch:
DiagnosticsManager::GetInstance().emitErrorMessage( callee.locationId(),
"unexpected ambiguous match when looking up a template function instance." );
return PoisonValue();
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/unify.cpp.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( uc.context(), rhsVal, t, localC.flip() );
return ValueToIRExpr( ifunc );
} );
co_yield { move( wrapped ), uc };
}
uc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
| > > > > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( uc.context(), rhsVal, t, localC.flip() );
if( ifunc.isPoison() )
return nullopt;
return ValueToIRExpr( ifunc );
} );
co_yield { move( wrapped ), uc };
}
uc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
|
| ︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( uc.context(), rhsVal, t, localC.flip() );
return ValueToIRExpr( ifunc );
} );
co_yield { move( wrapped ), uc };
}
uc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
} );
}
}
| > > > > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
{
auto localC = uc;
localC.setRHSNamespaceIndex( localNSId );
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( uc.context(), rhsVal, t, localC.flip() );
if( ifunc.isPoison() )
return nullopt;
return ValueToIRExpr( ifunc );
} );
co_yield { move( wrapped ), uc };
}
uc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
} );
}
}
|
Changes to bs/builtins/types/tuple/tuple.inl.
| ︙ | ︙ | |||
76 77 78 79 80 81 82 |
Value Bridge< tuple< T... > >::ToValue( const tuple< T... >& x )
{
auto val = BuildTupleValue( x, index_sequence_for< T... >() );
return Value( Type(), move( val ) );
}
template< typename TT, size_t... I >
| | > > > > > | > > > > > | 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 |
Value Bridge< tuple< T... > >::ToValue( const tuple< T... >& x )
{
auto val = BuildTupleValue( x, index_sequence_for< T... >() );
return Value( Type(), move( val ) );
}
template< typename TT, size_t... I >
optional< TT > BuildTupleFromValueVec( const Vector& vec, index_sequence< I... > )
{
if constexpr( sizeof... ( I ) == 0 )
return TT();
else
{
auto values = make_tuple( ValueFromIRExpr( vec[I] )... );
if( ( !get< I >( values ) || ... ) )
return nullopt;
auto items = make_tuple( FromValue< tuple_element_t< I, TT > >( *get< I >( values ) )... );
if( ( !get< I >( items ) || ... ) )
return nullopt;
return TT( move( *get< I >( items ) )... );
}
}
template< typename... T >
optional< tuple< T... > > Bridge< tuple< T... > >::FromVectorTerm( const Term& v )
{
const auto& vec = *get< pvec >( v );
return BuildTupleFromValueVec< tuple< T... > >( vec, index_sequence_for< T... >() );
|
| ︙ | ︙ |
Changes to bs/compiler.cpp.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
VerbosityContext vc( Verbosity::Normal, true );
p.parseSequence();
if( !r->eos() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
r->getCurrentLocation(), "syntax error." );
return 0;
}
| > > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
auto cfg = make_shared< llr::CFG >();
p.setCFG( cfg );
p.setCurrentBB( cfg->entryBB() );
VerbosityContext vc( Verbosity::Normal, true );
p.parseSequence();
if( cfg->isPoisoned() )
return 0;
if( !r->eos() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
r->getCurrentLocation(), "syntax error." );
return 0;
}
|
| ︙ | ︙ |
Changes to bs/diagnostics/renderer.cpp.
| ︙ | ︙ | |||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
// If we flush a context that had no location,
// just print it as is.
if( m_pendingContextFilename.empty() )
{
applyColor( m_pendingContextMessageColor );
m_output << m_pendingContextMessage << '\n';
m_pendingContextFilename.clear();
m_pendingContextMessage.clear();
m_pendingContextMessageColor = nullptr;
m_pendingCaret = false;
m_pendingHighlightSpans.clear();
return;
| > | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
// If we flush a context that had no location,
// just print it as is.
if( m_pendingContextFilename.empty() )
{
applyColor( m_pendingContextMessageColor );
m_output << m_pendingContextMessage << '\n';
applyColor( Colors::Reset );
m_pendingContextFilename.clear();
m_pendingContextMessage.clear();
m_pendingContextMessageColor = nullptr;
m_pendingCaret = false;
m_pendingHighlightSpans.clear();
return;
|
| ︙ | ︙ |
Changes to bs/execute/eval.cpp.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 |
if( !v.isConstant() )
{
const auto& llr = val.llr();
if( !llr )
return v.setPoison();
auto result = vm.execute( *llr );
// Execution may fail: there are some cases when we can't really
// be sure that eager evaluation is possible until we actually try.
// In this case we forget about the eager evaluation and return the
| > > > | | > > | 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 |
if( !v.isConstant() )
{
const auto& llr = val.llr();
if( !llr )
return v.setPoison();
VerbosityContext vc( Verbosity::Silent );
execute::ExecutionBudgetGuard ebg;
auto result = vm.execute( *llr );
// Execution may fail: there are some cases when we can't really
// be sure that eager evaluation is possible until we actually try.
// In this case we forget about the eager evaluation and return the
// value as is.
if( !result || result->isPoison() )
return v;
ebg.commit();
v = move( *result );
v.setLocationId( val.locationId() );
}
return v;
}
|
| ︙ | ︙ |
Changes to bs/execute/vm.cpp.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 |
optional< Value > VM::execute( const ptr< CFG >& ic )
{
return execute( *ic );
}
optional< Value > VM::execute( const llr::Call& call )
{
| | > > | > > > > > > > > > > | 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 |
optional< Value > VM::execute( const ptr< CFG >& ic )
{
return execute( *ic );
}
optional< Value > VM::execute( const llr::Call& call )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: compilation time execution budget exceeded." );
return PoisonValue();
}
--ms_remainingBranchInstExecutions;
if( call.func().isPoison() )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::SilentLocally );
auto func = Evaluate( call.func(), *this );
if( func.isPoison() )
return PoisonValue();
if( !func.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: function evaluation failed." );
return PoisonValue();
}
if( IsExternalFunc( func ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: can't call external functions." );
return PoisonValue();
}
bool poisoned = false;
const auto& vec = *get< pvec >( call.args() );
if( IsBuiltinFunc( func ) )
{
auto newVec = vec.transform( [&]( auto&& x ) -> optional< Term >
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
if( !newVal.isConstant() )
return ValueToIRExpr( PoisonValue() );
return ValueToIRExpr( newVal );
} );
| > > > | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
if( !newVal.isConstant() )
return ValueToIRExpr( PoisonValue() );
return ValueToIRExpr( newVal );
} );
if( poisoned )
return PoisonValue();
if( !newVec )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: args evaluation failed." );
return PoisonValue();
}
return ExecuteBuiltinFuncCall( func, TERM( newVec ) );
|
| ︙ | ︙ | |||
114 115 116 117 118 119 120 |
for( auto&& a : vec.terms() )
{
auto val = ValueFromIRExpr( a );
assert( val );
auto newVal = Evaluate( *val, *this );
| | > > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
for( auto&& a : vec.terms() )
{
auto val = ValueFromIRExpr( a );
assert( val );
auto newVal = Evaluate( *val, *this );
if( newVal.isPoison() )
return PoisonValue();
if( !newVal.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: args evaluation failed." );
return PoisonValue();
}
args.emplace_back( move( newVal ) );
|
| ︙ | ︙ | |||
204 205 206 207 208 209 210 |
optional< Value > VM::execute( const llr::LoadConstInt& lci )
{
return ToValue( lci.value() );
}
ptr< BasicBlock > VM::execute( const llr::Branch& b )
{
| | > | > > | > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
optional< Value > VM::execute( const llr::LoadConstInt& lci )
{
return ToValue( lci.value() );
}
ptr< BasicBlock > VM::execute( const llr::Branch& b )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: compilation time execution budget exceeded." );
m_frame.setRetVal( PoisonValue() );
return nullptr;
}
--ms_remainingBranchInstExecutions;
return b.dest().lock();
}
ptr< BasicBlock > VM::execute( const llr::CondBranch& cb )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: compilation time execution budget exceeded." );
m_frame.setRetVal( PoisonValue() );
return nullptr;
}
--ms_remainingBranchInstExecutions;
auto cond = Evaluate( cb.cond(), *this );
if( cond.isPoison() )
return nullptr;
if( !cond.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: branch condition evaluation failed." );
m_frame.setRetVal( PoisonValue() );
return nullptr;
}
if( *FromValue< bool >( cond ) )
return cb.trueDest().lock();
return cb.falseDest().lock();
}
|
Changes to bs/execute/vm.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#ifndef EMPATHY_EXECUTE_VM_H
#define EMPATHY_EXECUTE_VM_H
namespace empathy::execute
{
class VM
{
public:
optional< Value > execute( CFG& cfg );
optional< Value > execute( ptr< BasicBlock > bb );
optional< Value > execute( const llr::Instruction& instr );
optional< Value > execute( const ptr< CFG >& ic );
optional< Value > execute( const llr::Call& call );
| > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#ifndef EMPATHY_EXECUTE_VM_H
#define EMPATHY_EXECUTE_VM_H
namespace empathy::execute
{
class VM
{
friend class ExecutionBudgetGuard;
public:
optional< Value > execute( CFG& cfg );
optional< Value > execute( ptr< BasicBlock > bb );
optional< Value > execute( const llr::Instruction& instr );
optional< Value > execute( const ptr< CFG >& ic );
optional< Value > execute( const llr::Call& call );
|
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
optional< Value > execute( const llr::SGE& bo );
optional< Value > execute( const llr::SLT& bo );
optional< Value > execute( const llr::SLE& bo );
template< typename T >
optional< Value > execute( const T& )
{
| | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
optional< Value > execute( const llr::SGE& bo );
optional< Value > execute( const llr::SLT& bo );
optional< Value > execute( const llr::SLE& bo );
template< typename T >
optional< Value > execute( const T& )
{
return PoisonValue();
}
ptr< BasicBlock > execute( const llr::Terminator& terminator );
ptr< BasicBlock > execute( const llr::Ret& r );
ptr< BasicBlock > execute( const llr::Branch& b );
ptr< BasicBlock > execute( const llr::CondBranch& cb );
|
| ︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 |
ptr< BasicBlock > m_pPreviousBB;
// To avoid compile time code to get stuck, we have a limitation on the
// total number of call and loop instructions that we are willing to execute
// before giving up.
static uint32_t ms_remainingBranchInstExecutions;
};
}
#endif
| > > > > > > > > > > > > > > > > > > > > > > > | 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 111 112 113 |
ptr< BasicBlock > m_pPreviousBB;
// To avoid compile time code to get stuck, we have a limitation on the
// total number of call and loop instructions that we are willing to execute
// before giving up.
static uint32_t ms_remainingBranchInstExecutions;
};
// To avoid using up the execution budget on failed non mandatory compile time execution attempts
class ExecutionBudgetGuard
{
public:
ExecutionBudgetGuard() :
m_savedBudget( VM::ms_remainingBranchInstExecutions )
{}
~ExecutionBudgetGuard()
{
VM::ms_remainingBranchInstExecutions = m_savedBudget;
}
// If the budget use should be kept, call this before destruction.
void commit()
{
m_savedBudget = VM::ms_remainingBranchInstExecutions;
}
private:
uint32_t m_savedBudget = 0;
};
}
#endif
|
Changes to bs/llr/call.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include "llr/llr.h"
#include "builtins/builtins.h"
using namespace empathy::builtins;
namespace empathy::llr
{
bool Call::canBeExecuted() const
{
if( !IsValueConstantOrExecutable( m_func ) )
return false;
bool argsCanBeExecuted = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
if( !IsValueConstantOrExecutable( *ValueFromIRExpr( arg ) ) )
{
argsCanBeExecuted = false;
| > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "llr/llr.h"
#include "builtins/builtins.h"
using namespace empathy::builtins;
namespace empathy::llr
{
bool Call::canBeExecuted() const
{
if( !IsValueConstantOrExecutable( m_func ) )
return false;
if( IsExternalFunc( m_func ) )
return false;
bool argsCanBeExecuted = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
if( !IsValueConstantOrExecutable( *ValueFromIRExpr( arg ) ) )
{
argsCanBeExecuted = false;
|
| ︙ | ︙ |
Changes to bs/llr/cfg.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#ifndef EMPATHY_LLR_CFG_H
#define EMPATHY_LLR_CFG_H
namespace empathy::llr
{
class BasicBlock;
class CFG
{
public:
CFG();
const auto& entryBB() const { return m_basicBlocks.front(); }
const auto& lastBB() const { return m_basicBlocks.back(); }
auto count() const { return m_basicBlocks.size(); }
auto uniqueId() const { return m_uniqueId; }
| > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#ifndef EMPATHY_LLR_CFG_H
#define EMPATHY_LLR_CFG_H
namespace empathy::llr
{
class BasicBlock;
class CFG
{
public:
CFG();
bool isPoisoned() const { return m_poisoned; }
void poison() { m_poisoned = true; }
const auto& entryBB() const { return m_basicBlocks.front(); }
const auto& lastBB() const { return m_basicBlocks.back(); }
auto count() const { return m_basicBlocks.size(); }
auto uniqueId() const { return m_uniqueId; }
|
| ︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 |
vector< ptr< llr::BasicBlock > > m_basicBlocks;
// The unique identifier of this CFG.
uint32_t m_uniqueId = ms_nextUniqueId++;
// The number of temporary indices used by this CFG.
uint32_t m_temporariesCount = 0;
static uint32_t ms_nextUniqueId;
};
}
#endif
| > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
vector< ptr< llr::BasicBlock > > m_basicBlocks;
// The unique identifier of this CFG.
uint32_t m_uniqueId = ms_nextUniqueId++;
// The number of temporary indices used by this CFG.
uint32_t m_temporariesCount = 0;
bool m_poisoned = false;
static uint32_t ms_nextUniqueId;
};
}
#endif
|
Changes to bs/parse/parser.inl.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
m_currentBB->setTerminator( forward< T >( terminator ) );
}
template< typename V >
void Parser::pushValue( V&& val )
{
if( val.isPoison() )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::SilentLocally );
flushValue();
if( val.isConstant() || !llr::CanValueBeEagerlyEvaluated( val ) )
{
m_lastValue = forward< V >( val );
return;
| > > > > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
m_currentBB->setTerminator( forward< T >( terminator ) );
}
template< typename V >
void Parser::pushValue( V&& val )
{
if( val.isPoison() )
{
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::SilentLocally );
if( cfg() )
cfg()->poison();
}
flushValue();
if( val.isConstant() || !llr::CanValueBeEagerlyEvaluated( val ) )
{
m_lastValue = forward< V >( val );
return;
|
| ︙ | ︙ |
Changes to bs/parse/rule-helpers.inl.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
if( !rightVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
return false;
}
}
DiagnosticsContext dc( locationId, false );
auto result = func( p, *rightVal );
p.pushValue( move( result ) );
return true;
} );
| > > > > > > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
if( !rightVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
return false;
}
}
if( rightVal->isPoison() )
{
p.pushValue( PoisonValue() );
return true;
}
DiagnosticsContext dc( locationId, false );
auto result = func( p, *rightVal );
p.pushValue( move( result ) );
return true;
} );
|
| ︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
auto leftVal = p.popValue();
if( !leftVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected a value operand.", 0 );
return false;
}
DiagnosticsContext dc( locationId, false );
auto result = func( p, *leftVal );
p.pushValue( move( result ) );
return true;
} );
| > > > > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
auto leftVal = p.popValue();
if( !leftVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected a value operand.", 0 );
return false;
}
if( leftVal->isPoison() )
{
p.pushValue( PoisonValue() );
return true;
}
DiagnosticsContext dc( locationId, false );
auto result = func( p, *leftVal );
p.pushValue( move( result ) );
return true;
} );
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
if( !rightVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
return false;
}
}
DiagnosticsContext dcl( leftVal->locationId(), false );
DiagnosticsContext dcr( rightVal->locationId(), false );
DiagnosticsContext dc( locationId, false );
auto result = func( p, *leftVal, *rightVal );
| > > > > > > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
if( !rightVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
return false;
}
}
if( leftVal->isPoison() || rightVal->isPoison() )
{
p.pushValue( PoisonValue() );
return true;
}
DiagnosticsContext dcl( leftVal->locationId(), false );
DiagnosticsContext dcr( rightVal->locationId(), false );
DiagnosticsContext dc( locationId, false );
auto result = func( p, *leftVal, *rightVal );
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
if( !rightVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
return false;
}
}
DiagnosticsContext dcl( leftVal->locationId(), false );
DiagnosticsContext dcr( rightVal->locationId(), false );
DiagnosticsContext dc( locationId, false );
auto result = func( p, *leftVal, *rightVal );
| > > > > > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
if( !rightVal )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
return false;
}
}
if( leftVal->isPoison() || rightVal->isPoison() )
{
p.pushValue( PoisonValue() );
return true;
}
DiagnosticsContext dcl( leftVal->locationId(), false );
DiagnosticsContext dcr( rightVal->locationId(), false );
DiagnosticsContext dc( locationId, false );
auto result = func( p, *leftVal, *rightVal );
|
| ︙ | ︙ |
Changes to bs/sema/invocation.cpp.
1 2 3 4 5 6 7 8 9 |
#include "sema.h"
#include "builtins/builtins.h"
namespace empathy::sema
{
ptr< InvocationRule > GetInvocationRule( const Env& e, const Value& callee )
{
const auto& rules = e.invocationRuleSet()->rules();
| > | 1 2 3 4 5 6 7 8 9 10 |
#include "sema.h"
#include "builtins/builtins.h"
#include "execute/execute.h"
namespace empathy::sema
{
ptr< InvocationRule > GetInvocationRule( const Env& e, const Value& callee )
{
const auto& rules = e.invocationRuleSet()->rules();
|
| ︙ | ︙ | |||
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 |
bool CanBeInvoked( const Context& c, const Value& callee )
{
return !!GetInvocationRule( *c.env(), callee );
}
Value ResolveInvocation( const Context& c, const ptr< InvocationRule >& pInvRule, const Value& callee, const Value& args )
{
auto loc = Location::CreateSpanningLocation( callee.locationId(), args.locationId() );
// If the current domain isn't compile time and the args are constant, attempt to resolve it as a compile time invocation
// first.
if( args.isConstant() && c.domain() != DomainCompileTime() && builtins::IsTupleConstant( args ) )
{
// This is a speculative attempt at compile time execution. It it doesn't work, we'll
// just try to resolve the invocation in its originally intended domain.
// So don't display any error message during the attempt.
VerbosityContext vc( Verbosity::Silent );
Context localC( c.env(), InjectDomainIntoIdentity( c.identity(), DomainCompileTime() ) );
auto result = pInvRule->resolveInvocation( localC, loc, callee, args ).setLocationId( loc );
if( !result.isPoison() )
return result;
}
if( loc == ~0 )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::SilentLocally );
return pInvRule->resolveInvocation( c, loc, callee, args ).setLocationId( loc );
}
}
| > > > > > > > > > > | 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 |
bool CanBeInvoked( const Context& c, const Value& callee )
{
return !!GetInvocationRule( *c.env(), callee );
}
Value ResolveInvocation( const Context& c, const ptr< InvocationRule >& pInvRule, const Value& callee, const Value& args )
{
if( callee.isPoison() || args.isPoison() )
return PoisonValue();
auto loc = Location::CreateSpanningLocation( callee.locationId(), args.locationId() );
// If the current domain isn't compile time and the args are constant, attempt to resolve it as a compile time invocation
// first.
if( args.isConstant() && c.domain() != DomainCompileTime() && builtins::IsTupleConstant( args ) )
{
// This is a speculative attempt at compile time execution. It it doesn't work, we'll
// just try to resolve the invocation in its originally intended domain.
// So don't display any error message during the attempt.
VerbosityContext vc( Verbosity::Silent );
execute::ExecutionBudgetGuard ebg;
Context localC( c.env(), InjectDomainIntoIdentity( c.identity(), DomainCompileTime() ) );
auto result = pInvRule->resolveInvocation( localC, loc, callee, args ).setLocationId( loc );
if( !result.isPoison() )
{
execute::VM vm;
result = execute::Evaluate( result, vm );
ebg.commit();
return result;
}
}
if( loc == ~0 )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::SilentLocally );
return pInvRule->resolveInvocation( c, loc, callee, args ).setLocationId( loc );
}
}
|