Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Some more renaming. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
0345b9f80713cb5eef151494f9f3b03f |
| User & Date: | achavasse 2021-01-02 18:00:11.039 |
Context
|
2021-01-02
| ||
| 18:24 | Yet one more reference/address refactor: each calculation step (getting temp addr, getting var addr, selecting a member) is now a separate cir instruction. We need this level of generalization to be able to obtain addresses from anywhere, including variables and function parameters. check-in: 26c691ecb9 user: achavasse tags: trunk | |
| 18:00 | Some more renaming. check-in: 0345b9f807 user: achavasse tags: trunk | |
|
2020-12-27
| ||
| 14:40 | Renamed "ir" to "eir" (expression intermediate representation) and "llr" to "cir" (code intermediate representation) for clarity. check-in: 7d2def7b75 user: achavasse tags: trunk | |
Changes
Changes to bs/builtins/api/codegen/func.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
void SetupApiCGFunc( Env& e )
{
weak_ptr< Env > pEnv = e.shared_from_this();
RegisterBuiltinFunc< bool ( ptr< codegen::Module >, CustomPattern< Value, FuncPattern > ) >( e, "CGGenerateFunction"_sid,
[pEnv]( const ptr< codegen::Module >& module, const Value& f )
{
| | | | 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 |
void SetupApiCGFunc( Env& e )
{
weak_ptr< Env > pEnv = e.shared_from_this();
RegisterBuiltinFunc< bool ( ptr< codegen::Module >, CustomPattern< Value, FuncPattern > ) >( e, "CGGenerateFunction"_sid,
[pEnv]( const ptr< codegen::Module >& module, const Value& f )
{
if( !IsFuncType( *ValueFromEIR( f.type() ) ) )
return false;
sema::Context c( pEnv.lock(), RootIdentity() );
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( c, f );
if( func.isPoison() || DiagnosticsManager::GetInstance().errorsWereEmitted() )
return false;
auto llvmFunc = module->getOrCreateFunc( c, *FromValue< Func >( func ) );
return !!llvmFunc;
} );
RegisterBuiltinFunc< bool ( ptr< codegen::Module >, CustomPattern< Value, FuncPattern >, string ) >( e, "CGGenerateFunction"_sid,
[pEnv]( const ptr< codegen::Module >& module, const Value& f, const string& name )
{
if( !IsFuncType( *ValueFromEIR( f.type() ) ) )
return false;
sema::Context c( pEnv.lock(), RootIdentity() );
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
|
| ︙ | ︙ |
Changes to bs/builtins/api/codegen/module.cpp.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 |
}
}
namespace goose::eir
{
const Term& Bridge< ptr< codegen::Module > >::Type()
{
| | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
}
}
namespace goose::eir
{
const Term& Bridge< ptr< codegen::Module > >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( cg_module ) ) ) );
return type;
}
Value Bridge< ptr< codegen::Module > >::ToValue( const ptr< codegen::Module >& os )
{
return Value( Type(), TERM( static_pointer_cast< void >( os ) ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/api/compiler.cpp.
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
"CreateConstant: the expression doesn't evaluate to a constant." );
return;
}
pEnv.lock()->storeValue(
AppendToVectorTerm( RootIdentity(), StringId( name.c_str() ) ),
| | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
"CreateConstant: the expression doesn't evaluate to a constant." );
return;
}
pEnv.lock()->storeValue(
AppendToVectorTerm( RootIdentity(), StringId( name.c_str() ) ),
ANYTERM( _ ), ValueToEIR( v ) );
} );
RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "#Include"_sid,
[pEnv]( auto&& c, const Value& fnameval ) -> Value
{
auto filename = *FromValue< string >( fnameval );
|
| ︙ | ︙ | |||
186 187 188 189 190 191 192 |
DiagnosticsManager::GetInstance().emitErrorMessage( params.locationId(),
"#CompileFileToFunction: template parameter lists are not supported.", 0 );
return PoisonValue();
}
// TODO at some point we'll want to pass the base identity to use as a param but
// let's wait and see how the module and namespace stuff pans out first
| | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
DiagnosticsManager::GetInstance().emitErrorMessage( params.locationId(),
"#CompileFileToFunction: template parameter lists are not supported.", 0 );
return PoisonValue();
}
// TODO at some point we'll want to pass the base identity to use as a param but
// let's wait and see how the module and namespace stuff pans out first
sema::Context localC( pEnv.lock(), builtins::RootIdentity(), ValueToEIR( rt ) );
auto ftype = BuildFuncType( localC, rt, params );
auto funcIdentity = AppendToVectorTerm( builtins::RootIdentity(),
TERM( StringId( Env::NewUniqueId() ) ) );
c.env()->addVisibilityRule( builtins::RootIdentity(), funcIdentity );
|
| ︙ | ︙ |
Changes to bs/builtins/api/extensibility/codebuilder.cpp.
1 2 3 4 5 6 7 |
#include "builtins/builtins.h"
#include "eir/eir.h"
namespace goose::eir
{
const Term& Bridge< ptr< sema::CodeBuilder > >::Type()
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include "builtins/builtins.h"
#include "eir/eir.h"
namespace goose::eir
{
const Term& Bridge< ptr< sema::CodeBuilder > >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_codebuilder ) ) ) );
return type;
}
Value Bridge< ptr< sema::CodeBuilder > >::ToValue( const ptr< sema::CodeBuilder >& cb )
{
return Value( Type(), TERM( static_pointer_cast< void >( cb ) ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/api/extensibility/termwrapper.cpp.
1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
#include "eir/eir.h"
using namespace goose::builtins;
namespace goose::eir
{
const Term& Bridge< TermWrapper >::Type()
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include "builtins/builtins.h"
#include "eir/eir.h"
using namespace goose::builtins;
namespace goose::eir
{
const Term& Bridge< TermWrapper >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_termwrapper ) ) ) );
return type;
}
Value Bridge< TermWrapper >::ToValue( const TermWrapper& tw )
{
return Value( Type(), Quote( tw.get() ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/api/extensibility/valuewrapper.cpp.
1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
#include "eir/eir.h"
using namespace goose::builtins;
namespace goose::eir
{
const Term& Bridge< ValueWrapper >::Type()
{
| | | | | 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 |
#include "builtins/builtins.h"
#include "eir/eir.h"
using namespace goose::builtins;
namespace goose::eir
{
const Term& Bridge< ValueWrapper >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_valuewrapper ) ) ) );
return type;
}
Value Bridge< ValueWrapper >::ToValue( const ValueWrapper& vw )
{
return Value( Type(), Quote( ValueToEIR( vw.get() ) ) );
}
optional< Value > Bridge< ValueWrapper >::FromValue( const Value& v )
{
if( v.type() != Type() )
return nullopt;
auto uq = Unquote( v.val() );
if( !uq )
return nullopt;
return ValueFromEIR( *uq );
}
}
|
Changes to bs/builtins/helpers.cpp.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 |
np.flushValue();
return bb;
}
variant< Value, ValUnifyError > ConvertValueToType( const Context& c, const Value& val, const Term& type )
{
| | | | | 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 |
np.flushValue();
return bb;
}
variant< Value, ValUnifyError > ConvertValueToType( const Context& c, const Value& val, const Term& type )
{
auto valTerm = ValueToEIR( val );
auto paramPat = ParamPat( type );
auto us = FindBestTyping( paramPat, valTerm, c );
if( holds_alternative< NoUnification >( us ) )
return ValUnifyError::NoSolution;
if( holds_alternative< AmbiguousTypeCheck >( us ) )
return ValUnifyError::Ambiguous;
auto&& [s,tcc] = get< TCSol >( us );
auto finalVal = ValueFromEIR( s );
assert( finalVal );
return *finalVal;
}
pvec ParseExpressionList( Parser& p, uint32_t precedence, const pvec& pVec )
{
while( p.parseExpression( precedence ) )
{
auto val = p.popValue();
if( !val || val->isPoison() )
return nullptr;
pVec->append( ValueToEIR( *val ) );
}
return pVec;
}
}
|
Changes to bs/builtins/operators/arith.cpp.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 |
{
return BuildComputedValue( GetValueType< BigInt >(),
Sub( ToValue( BigInt() ), operand ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& operand ) -> Value
{
| | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
{
return BuildComputedValue( GetValueType< BigInt >(),
Sub( ToValue( BigInt() ), operand ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& operand ) -> Value
{
auto opTypeVal = *ValueFromEIR( operand.type() );
auto opType = *FromValue< IntegerType >( opTypeVal );
return BuildComputedValue( operand.type(),
Sub( Value( operand.type(), APSInt( opType.m_numBits, false ) ),
operand ) );
} )
),
LeftAssInfixOp( "operator_sub"_sid, precedence::AddSubOp,
|
| ︙ | ︙ |
Changes to bs/builtins/operators/assignment.cpp.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
// Generic function to perform the assignation of a builtin runtime type
// to a mutable reference of that same type.
auto BuiltinTypeAssignment = []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
auto ref = *FromValue< Reference >( lhs );
| | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// Generic function to perform the assignation of a builtin runtime type
// to a mutable reference of that same type.
auto BuiltinTypeAssignment = []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
auto ref = *FromValue< Reference >( lhs );
if( !ParseTypePredicates( c, c.identity(), *ValueFromEIR( ref.type().type() ) ) )
return PoisonValue();
const auto& cb = c.codeBuilder();
if( !cb )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
return PoisonValue();
|
| ︙ | ︙ | |||
109 110 111 112 113 114 115 |
// We go at very high level to construct the temporary variables by resolving an invocation
// of the assignment of the rhs value to a TNamedDecl with an empty name.
// The reason we need to work at such high level is so that the initializer value gets
// resolved exactly like if it was a regular assignment. In particular, if the value in question
// is a locvar, we want it to go through the type checking process to be replaced with its content.
// This is the simplest and most robust way to achieve this, which should honor every relevant
// extension point.
| | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
// We go at very high level to construct the temporary variables by resolving an invocation
// of the assignment of the rhs value to a TNamedDecl with an empty name.
// The reason we need to work at such high level is so that the initializer value gets
// resolved exactly like if it was a regular assignment. In particular, if the value in question
// is a locvar, we want it to go through the type checking process to be replaced with its content.
// This is the simplest and most robust way to achieve this, which should honor every relevant
// extension point.
auto anonVarDecl = ToValue( TNamedDecl( ValueToEIR( ToValue( TVar( "_"_sid ) ) ), ""_sid ) );
auto tmpVar = InvokeOverloadSet( c,
assOp, MakeTuple( anonVarDecl, srcVal ) );
if( tmpVar.isPoison() )
{
success = false;
|
| ︙ | ︙ |
Changes to bs/builtins/operators/dollar.cpp.
| ︙ | ︙ | |||
31 32 33 34 35 36 37 |
// body, refering to a bound TVar, so we just return the stored value.
// Otherwise, we're in a template declaration and have to construct a new TVar.
Term result;
switch( c.env()->retrieveValue( captureIdentity, c.identity(), result ) )
{
case sema::Env::Status::Success:
| | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// body, refering to a bound TVar, so we just return the stored value.
// Otherwise, we're in a template declaration and have to construct a new TVar.
Term result;
switch( c.env()->retrieveValue( captureIdentity, c.identity(), result ) )
{
case sema::Env::Status::Success:
return *ValueFromEIR( result );
case sema::Env::Status::AmbiguousMatch:
DiagnosticsManager::GetInstance().emitErrorMessage( locationId,
format( "unexpected ambiguous match when resolving '${}'.", name ) );
return PoisonValue();
default:
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 |
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( nameTerm->second,
"expected an unbound identifier after '$'." );
return false;
}
auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );
| | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( nameTerm->second,
"expected an unbound identifier after '$'." );
return false;
}
auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );
auto typeOrTExpr = ValueToEIR( *p.popValue() );
auto tdecl = builtins::BuildTDecl( c, move( typeOrTExpr ), *name );
assert( tdecl );
p.pushValue( ToValue( move( *tdecl ) ).setLocationId( loc ) );
return true;
}
}
|
| ︙ | ︙ |
Changes to bs/builtins/operators/dot.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
if( !rhs.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the right operand for the dot operator needs to be a constant." );
return PoisonValue();
}
| | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
if( !rhs.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the right operand for the dot operator needs to be a constant." );
return PoisonValue();
}
auto tupType = *ValueFromEIR( lhs.type() );
uint32_t index = *FromValue< uint32_t >( rhs );
if( index >= TupleTypeSize( tupType ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the index is out of range." );
return PoisonValue();
|
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the right operand for the dot operator needs to be a constant." );
return PoisonValue();
}
auto lv = *FromValue< LocalVar >( lhs );
| | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the right operand for the dot operator needs to be a constant." );
return PoisonValue();
}
auto lv = *FromValue< LocalVar >( lhs );
auto tupType = *ValueFromEIR( lv.type() );
uint32_t index = *FromValue< uint32_t >( rhs );
if( index >= TupleTypeSize( tupType ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the index is out of range." );
return PoisonValue();
|
| ︙ | ︙ |
Changes to bs/builtins/operators/logic.cpp.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 |
BuildParseRule( e, "~"_sid,
PrefixOp( "operator_bitwise_not"_sid, precedence::UnaryOps,
BuildGenericTupleOperator(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >( []( auto&& c, auto&& operand ) -> Value
{
| | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
BuildParseRule( e, "~"_sid,
PrefixOp( "operator_bitwise_not"_sid, precedence::UnaryOps,
BuildGenericTupleOperator(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >( []( auto&& c, auto&& operand ) -> Value
{
auto opTypeVal = *ValueFromEIR( operand.type() );
auto opType = *FromValue< IntegerType >( opTypeVal );
return BuildComputedValue( operand.type(),
Xor( operand,
Value( operand.type(), APSInt::getMaxValue( opType.m_numBits, true ) )
) );
} )
)
|
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
| | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *ValueFromEIR( GetValueType< bool >() ), 2,
resultIndex );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( predBB, ToValue( true ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
|
| ︙ | ︙ | |||
187 188 189 190 191 192 193 |
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
| | | 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *ValueFromEIR( GetValueType< bool >() ), 2,
resultIndex );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( predBB, ToValue( false ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
|
| ︙ | ︙ | |||
234 235 236 237 238 239 240 |
auto cfg = cb->cfg();
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
| | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
auto cfg = cb->cfg();
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
auto lhsType = *FromValue< IntegerType >( *ValueFromEIR( lhs.type() ) );
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );
auto cond = ULT( rhs, bitSizeValue );
DiagnosticsManager::GetInstance().defineCustomDiagnostic(
cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 |
auto cfg = cb->cfg();
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
| | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
auto cfg = cb->cfg();
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
auto lhsType = *FromValue< IntegerType >( *ValueFromEIR( lhs.type() ) );
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );
auto cond = ULT( rhs, bitSizeValue );
DiagnosticsManager::GetInstance().defineCustomDiagnostic(
cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );
|
| ︙ | ︙ | |||
311 312 313 314 315 316 317 |
auto cfg = cb->cfg();
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
| | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
auto cfg = cb->cfg();
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
auto lhsType = *FromValue< IntegerType >( *ValueFromEIR( lhs.type() ) );
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );
auto cond = ULT( rhs, bitSizeValue );
DiagnosticsManager::GetInstance().defineCustomDiagnostic(
cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );
|
| ︙ | ︙ |
Changes to bs/builtins/statements/break.cpp.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 |
cfg->currentBB()->setTerminator( cir::Break( cb->breakableScopeLevels() ) );
return true;
};
Rule r( handleBreak );
auto ruleVal = ToValue( move( r ) );
| | | 37 38 39 40 41 42 43 44 45 46 47 |
cfg->currentBB()->setTerminator( cir::Break( cb->breakableScopeLevels() ) );
return true;
};
Rule r( handleBreak );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( break ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/statements/continue.cpp.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 |
cfg->currentBB()->setTerminator( cir::Continue( cb->continuableScopeLevels() ) );
return true;
};
Rule r( handleContinue );
auto ruleVal = ToValue( move( r ) );
| | | 37 38 39 40 41 42 43 44 45 46 47 |
cfg->currentBB()->setTerminator( cir::Continue( cb->continuableScopeLevels() ) );
return true;
};
Rule r( handleContinue );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( continue ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/statements/hif.cpp.
| ︙ | ︙ | |||
127 128 129 130 131 132 133 |
}
return true;
};
Rule r( handleHIf );
auto ruleVal = ToValue( move( r ) );
| | | 127 128 129 130 131 132 133 134 135 136 137 |
}
return true;
};
Rule r( handleHIf );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( #if ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/statements/if.cpp.
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
// instructions.
cfg->setCurrentBB( pSuccBB );
return true;
};
Rule r( handleIf );
auto ruleVal = ToValue( move( r ) );
| | | 135 136 137 138 139 140 141 142 143 144 145 |
// instructions.
cfg->setCurrentBB( pSuccBB );
return true;
};
Rule r( handleIf );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( if ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/statements/return.cpp.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( get< Value >( converted ) ) );
return true;
};
Rule r( handleReturn );
auto ruleVal = ToValue( move( r ) );
| | | 81 82 83 84 85 86 87 88 89 90 91 |
cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( get< Value >( converted ) ) );
return true;
};
Rule r( handleReturn );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( return ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/statements/using.cpp.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 |
get< pvec >( localIdentity )->terms().back() = nameTerm->first;
context.env()->addVisibilityRule( context.identity(), localIdentity );
auto eqTerm = p.resolver()->consumeUnresolved();
if( !eqTerm )
{
dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected '='.", 0 );
| | | | | | | | 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 |
get< pvec >( localIdentity )->terms().back() = nameTerm->first;
context.env()->addVisibilityRule( context.identity(), localIdentity );
auto eqTerm = p.resolver()->consumeUnresolved();
if( !eqTerm )
{
dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected '='.", 0 );
context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
return true;
}
const auto* eq = get_if< StringId >( &eqTerm->first );
if( !eq || *eq != "="_sid )
{
dm.emitSyntaxErrorMessage( eqTerm->second, "expected '='.", 0 );
context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
return true;
}
auto np = p.makeNestedParser();
if( !np.parseExpression( precedence::UsingStmt ) )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
return true;
}
if( !np.peekLastValue() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
"expected an expression.", 0 );
context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
return true;
}
context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( *np.popValue() ) );
return true;
};
Rule r( handleUsing );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( using ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/statements/while.cpp.
| ︙ | ︙ | |||
140 141 142 143 144 145 146 |
cfg->setCurrentBB( pSuccBB );
return true;
};
Rule r( handleWhile );
auto ruleVal = ToValue( move( r ) );
| | | 140 141 142 143 144 145 146 147 148 149 150 |
cfg->setCurrentBB( pSuccBB );
return true;
};
Rule r( handleWhile );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( while ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/types/basic.cpp.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( void ) ), ANYTERM( _ ), GetValueType< void >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( bool ) ), ANYTERM( _ ), GetValueType< bool >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_int ) ), ANYTERM( _ ), GetValueType< BigInt >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_char ) ), ANYTERM( _ ), GetValueType< char32_t >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_string ) ), ANYTERM( _ ), GetValueType< string >() );
// bool literals
| | | | | | | | 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 |
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( void ) ), ANYTERM( _ ), GetValueType< void >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( bool ) ), ANYTERM( _ ), GetValueType< bool >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_int ) ), ANYTERM( _ ), GetValueType< BigInt >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_char ) ), ANYTERM( _ ), GetValueType< char32_t >() );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_string ) ), ANYTERM( _ ), GetValueType< string >() );
// bool literals
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( true ) ), ANYTERM( _ ), ValueToEIR( ToValue( true ) ) );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( false ) ), ANYTERM( _ ), ValueToEIR( ToValue( false ) ) );
// _ and var are both aliases for an anonymous tvar ($_)
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( _ ) ), ANYTERM( _ ), ValueToEIR( ToValue( TVar( "_"_sid ) ) ) );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( var ) ), ANYTERM( _ ), ValueToEIR( ToValue( TVar( "_"_sid ) ) ) );
}
const Term& ValuePatternT::GetPattern()
{
static auto pattern = HOLE( "T"_sid );
return pattern;
}
}
namespace goose::eir
{
// void
const Term& Bridge< void >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), TSID( void ) ) );
return type;
}
// bool
const Term& Bridge< bool >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( bool ) ) ) );
return type;
}
Value Bridge< bool >::ToValue( bool x )
{
return Value( Type(), TERM( x ? 1U : 0U ) );
}
|
| ︙ | ︙ | |||
64 65 66 67 68 69 70 |
return *pint;
}
// Integers
const Term& Bridge< BigInt >::Type()
{
| | | | | 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 111 112 113 |
return *pint;
}
// Integers
const Term& Bridge< BigInt >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_integer ) ) ) );
return type;
}
const BigInt* Bridge< BigInt >::FromValue( const Value& v )
{
if( v.type() != Type() )
return nullptr;
return get_if< BigInt >( &v.val() );
}
// char
const Term& Bridge< char32_t >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_char ) ) ) );
return type;
}
Value Bridge< char32_t >::ToValue( char32_t x )
{
return Value( Type(), TERM( x ) );
}
optional< char32_t > Bridge< char32_t >::FromValue( const Value& v )
{
if( v.type() != Type() )
return nullopt;
return get< uint32_t >( v.val() );
}
// strings
const Term& Bridge< string >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_string ) ) ) );
return type;
}
Value Bridge< string >::ToValue( const string& x )
{
return Value( Type(), TERM( x ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/constrainedfunc/constrainedfunc.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "builtins/builtins.h"
using namespace goose::builtins;
bool goose::builtins::IsConstrainedFunc( const Value& tcc )
{
return tcc.type() == GetValueType< ConstrainedFunc >();
}
namespace goose::eir
{
const Term& Bridge< builtins::ConstrainedFunc >::Type()
{
| | | | 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 |
#include "builtins/builtins.h"
using namespace goose::builtins;
bool goose::builtins::IsConstrainedFunc( const Value& tcc )
{
return tcc.type() == GetValueType< ConstrainedFunc >();
}
namespace goose::eir
{
const Term& Bridge< builtins::ConstrainedFunc >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( constrainedfunc ) ) ) );
return type;
}
Value Bridge< builtins::ConstrainedFunc >::ToValue( const builtins::ConstrainedFunc& cf )
{
return Value( Type(), VEC(
Quote( cf.constraintPat() ),
TERM( static_pointer_cast< void >( cf.invRule() ) ),
ValueToEIR( cf.func() ) ) );
}
optional< builtins::ConstrainedFunc > Bridge< builtins::ConstrainedFunc >::FromValue( const Value& v )
{
if( !IsConstrainedFunc( v ) )
return nullopt;
|
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
if( !result )
return nullopt;
auto&& [constraintPat, pInvRule, func] = *result;
return builtins::ConstrainedFunc(
*Unquote( constraintPat ),
static_pointer_cast< InvocationRule >( pInvRule ),
| | | 38 39 40 41 42 43 44 45 46 47 |
if( !result )
return nullopt;
auto&& [constraintPat, pInvRule, func] = *result;
return builtins::ConstrainedFunc(
*Unquote( constraintPat ),
static_pointer_cast< InvocationRule >( pInvRule ),
*ValueFromEIR( func ) );
}
}
|
Changes to bs/builtins/types/constrainedfunc/invoke.cpp.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
return PoisonValue();
}
};
void SetupConstrainedFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
| | | 32 33 34 35 36 37 38 39 40 41 42 43 44 |
return PoisonValue();
}
};
void SetupConstrainedFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( Value(
GetValueType< ConstrainedFunc >(),
ANYTERM( _ ) ) ),
make_shared< ConstrainedFuncInvocationRule >() );
}
}
|
Changes to bs/builtins/types/constrainedfunc/typecheck.cpp.
1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupConstrainedFuncTypeChecking( Env& e )
{
| | | | | | | | | | | | | | | 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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupConstrainedFuncTypeChecking( Env& e )
{
auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ) ) ) );
auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
// func type param / constrainedfunc arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( move( funcTypePat ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
GetValueType< builtins::ConstrainedFunc >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildCallPatternFromFuncType( *ValueFromEIR( type ) );
auto rhsVal = *ValueFromEIR( rhs );
auto cfunc = FromValue< ConstrainedFunc >( rhsVal );
assert( cfunc );
auto localC = tcc;
for( auto&& [s, tcc] : TypeCheck( callPat, cfunc->constraintPat(), localC ) )
{
if( Postprocess( s, tcc ) )
{
auto func = ValueToEIR( cfunc->func() );
co_yield TypeCheck( lhs, func, tcc );
co_return;
}
}
} );
// tfunc type param / constrainedfunc arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern( HOLE( "_"_sid ), move( tFuncTypePat ), HOLE( "_"_sid ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
GetValueType< builtins::ConstrainedFunc >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *ValueFromEIR( type ) );
assert( callPat );
auto rhsVal = *ValueFromEIR( rhs );
auto cfunc = FromValue< ConstrainedFunc >( rhsVal );
assert( cfunc );
auto localC = tcc;
for( auto&& [s, tcc] : TypeCheck( *callPat, cfunc->constraintPat(), localC ) )
{
if( Postprocess( s, tcc ) )
{
auto func = ValueToEIR( cfunc->func() );
co_yield TypeCheck( lhs, func, tcc );
co_return;
}
}
} );
// constrainedfunc param / any arg:
// Just yield the constrained func.
//
// This is because when we monomorphize a function that takes
// a polymorphic function type, we turn the later into a
// compile time constant. So it isn't really a parameter
// in the resulting monomorphic function, and we just want
// to ignore whatever parameter is being passed there
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
TSID( constant ),
GetValueType< builtins::ConstrainedFunc >(),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
co_yield { lhs, tcc };
} );
}
}
|
Changes to bs/builtins/types/decl.cpp.
1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose::builtins;
namespace goose::builtins
{
bool IsDecl( const Value& d )
{
| | | | | | 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 |
#include "builtins/builtins.h"
using namespace goose::builtins;
namespace goose::builtins
{
bool IsDecl( const Value& d )
{
auto typeVal = ValueFromEIR( d.type() );
auto result = Decompose( typeVal->val(),
Vec(
Lit( "decl"_sid ),
SubTerm()
)
);
return !!result;
}
const Term& Decl::Pattern::GetPattern()
{
static auto pattern = ValueToEIR(
Value( TypeType(), VEC( TSID( decl ), HOLE( "_"_sid ) ) ) );
return pattern;
}
}
namespace goose::eir
{
Term Bridge< Decl >::Type( const Term& declType )
{
return ValueToEIR( Value( TypeType(), VEC( TSID( decl ), declType ) ) );
}
Value Bridge< Decl >::ToValue( const Decl& d )
{
return Value( Type( d.type() ), TERM( d.name() ) );
}
optional< Decl > Bridge< Decl >::FromValue( const Value& v )
{
auto typeVal = ValueFromEIR( v.type() );
auto result = Decompose( typeVal->val(),
Vec(
Lit( "decl"_sid ),
SubTerm()
)
);
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/bfunc.cpp.
1 2 3 4 5 6 |
#include "builtins/builtins.h"
namespace goose::builtins
{
bool IsBuiltinFunc( const Value& func )
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "builtins/builtins.h"
namespace goose::builtins
{
bool IsBuiltinFunc( const Value& func )
{
auto funcType = ValueFromEIR( func.type() );
assert( funcType );
auto decomp = Decompose( funcType->val(),
Vec(
Lit( "func"_sid ),
Lit( "builtin"_sid ),
SubTerm(), // return type
|
| ︙ | ︙ | |||
33 34 35 36 37 38 39 |
);
return !!decomp;
}
bool IsNonEagerBuiltinFunc( const Value& func )
{
| | | | 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 |
);
return !!decomp;
}
bool IsNonEagerBuiltinFunc( const Value& func )
{
auto funcType = ValueFromEIR( func.type() );
assert( funcType );
auto decomp = Decompose( funcType->val(),
Vec(
Lit( "func"_sid ),
Lit( "builtin"_sid ),
SubTerm(), // return type
SubTerm(), // param types
SubTerm(), // verif info
SubTerm() // varArg
)
);
return !!decomp;
}
bool IsEagerBuiltinFunc( const Value& func )
{
auto funcType = ValueFromEIR( func.type() );
assert( funcType );
auto decomp = Decompose( funcType->val(),
Vec(
Lit( "func"_sid ),
Lit( "builtin_eager"_sid ),
SubTerm(), // return type
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/bfunc.inl.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );
Term result;
switch( env.retrieveValue( identity, RootIdentity(), result ) )
{
case sema::Env::Status::Success:
| | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );
Term result;
switch( env.retrieveValue( identity, RootIdentity(), result ) )
{
case sema::Env::Status::Success:
pOvlSet = *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );
break;
case sema::Env::Status::NoMatch:
pOvlSet = make_shared< OverloadSet >( identity );
env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
break;
case sema::Env::Status::AmbiguousMatch:
throw logic_error( "panic: ambiguous match while registering builtin func "s + name.str() );
}
return RegisterBuiltinFunc< FT >( env, pOvlSet, forward< F >( func ) );
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
{
return VEC( BuildBuiltinFuncParamPat< T >::GetParamPattern()... );
}
template< typename R, typename... T >
const Term& Bridge< R ( T... ) >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
{
| | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
{
return VEC( BuildBuiltinFuncParamPat< T >::GetParamPattern()... );
}
template< typename R, typename... T >
const Term& Bridge< R ( T... ) >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
builtins::is_eager_v< R > ? TSID( builtin_eager ) : TSID( builtin ),
GetValueType< builtins::remove_eager_t< R > >(),
sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
static_pointer_cast< void >( fvi ), TERM( 0U )
) ) );
return type;
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/build.cpp.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
// Bind a stand-in value with the parameters name to be used inside of verification expressions.
auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
TERM( decl.name() ) );
Reference argRef( ReferenceType{ decl.type(), TSID( const ) }, cir::VarBaseAddr( varId++ ) );
c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
| | | | | | | 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 |
// Bind a stand-in value with the parameters name to be used inside of verification expressions.
auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
TERM( decl.name() ) );
Reference argRef( ReferenceType{ decl.type(), TSID( const ) }, cir::VarBaseAddr( varId++ ) );
c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
ValueToEIR( BuildComputedValue( decl.type(),
cir::Load( ToValue( argRef ), decl.type() ) ) ) );
}
else if( param.isConstant() )
tv->append( ValueToEIR( param ) );
return true;
} );
// If the return type is non-void, expose @result under the verification identity as a computed value whose type
// is the function's return type, and the value is a placeholder cir instruction. This will allow verification
// expressions to refer to the current function's return value as a value of the correct type.
auto rtTerm = ValueToEIR( returnType );
if( rtTerm != GetValueType< void >() )
{
auto name = "@result"_sid;
auto retValVerificationIdentity = AppendToVectorTerm( verificationIdentity, TERM( name ) );
c.env()->storeValue( retValVerificationIdentity, ANYTERM( _ ),
ValueToEIR( BuildComputedValue( rtTerm, cir::Placeholder( rtTerm, name ) ) ) );
}
auto pVerifInfos = make_shared< FuncVerificationInfos >( move( verificationIdentity ) );
return FuncType( ValueToEIR( returnType ), tv, move( pVerifInfos ) );
}
Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg )
{
funcType.setVarArg( varArg );
return Func( funcType, symbol );
}
|
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
// 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
// a default implementation that denies access to outside variables with an error)
| | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
// 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
// a default implementation that denies access to outside variables with an error)
auto funcTypeTerm = ValueToEIR( ToValue( funcType ) );
auto identity = VEC( funcIdentity, funcTypeTerm );
assert( c.identity() != identity );
c.env()->addVisibilityRule( c.identity(), identity );
out_bodyContext = Context( c.env(), identity, funcType.returnType() );
auto pFuncCIR = c.env()->createCIRFunc( identity );
|
| ︙ | ︙ | |||
105 106 107 108 109 110 111 |
assert( result );
auto&& [sort, type, val, locId] = *result;
if( sort == TSID( constant ) )
apv->append( param );
else
| | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
assert( result );
auto&& [sort, type, val, locId] = *result;
if( sort == TSID( constant ) )
apv->append( param );
else
apv->append( ValueToEIR( ValuePattern( TSID( computed ), type, TERM( ptr< void >() ) ) ) );
return true;
} );
return VEC( apv, ftype.returnType() );
}
}
|
Changes to bs/builtins/types/func/compile.cpp.
| ︙ | ︙ | |||
113 114 115 116 117 118 119 |
Val< LocationId >()
)
);
assert( result );
auto&& [sort, type, val, locId] = *result;
| | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
Val< LocationId >()
)
);
assert( result );
auto&& [sort, type, val, locId] = *result;
if( !ParseTypePredicates( c, pFuncCIR->identity(), *ValueFromEIR( type ) ) )
predsOk = false;
return true;
} );
if( !predsOk )
return false;
// Perform lazy parsing on return type predicates
if( !ParseTypePredicates( c, pFuncCIR->identity(), *ValueFromEIR( f.type().returnType() ) ) )
return false;
// If the function already have a cir body, nothing to do.
if( pFuncCIR->body() )
return true;
if( !f.tokens() )
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 |
localContext.setBuilder( cb );
// Create the local variable bindings to access the function params
// from inside the body, as well as the signature.
uint32_t varId = 0;
for( auto&& t : f.paramsDecl()->terms() )
{
| | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
localContext.setBuilder( cb );
// Create the local variable bindings to access the function params
// from inside the body, as well as the signature.
uint32_t varId = 0;
for( auto&& t : f.paramsDecl()->terms() )
{
auto param = *ValueFromEIR( t );
if( !IsDecl( param ) )
continue;
auto decl = *FromValue< Decl >( param );
auto paramIdentity = AppendToVectorTerm(
pFuncCIR->identity(),// ANYTERM( _ ),
TERM( decl.name() ) );
// Create a locvar to hold the param.
LocalVar lv( decl.name(), decl.type(), varId++ );
auto locVar = ToValue( lv ).setLocationId( param.locationId() );
c.env()->storeValue( paramIdentity, ANYTERM( _ ),
ValueToEIR( locVar ) );
cb->pushLiveValue( locVar, lv.index() );
}
auto tokProvider = lex::MakeVectorAdapter( *static_pointer_cast< vector< TermLoc > >( f.tokens() ) );
auto r = make_shared< parse::Resolver >( tokProvider, localContext );
Parser p( r );
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/func.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
#include "verify/verify.h"
#include "builtins/helpers.h"
using namespace goose::builtins;
using namespace goose::parse;
namespace goose::builtins
{
const Term& FuncPattern::GetPattern()
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
#include "verify/verify.h"
#include "builtins/helpers.h"
using namespace goose::builtins;
using namespace goose::parse;
namespace goose::builtins
{
const Term& FuncPattern::GetPattern()
{
static auto pattern = ValueToEIR(
Value( TypeType(), VEC( TSID( func ), HOLE( "llvmType"_sid ),
HOLE( "_"_sid ), HOLE( "_"_sid ),
HOLE( "_"_sid ), HOLE( "_"_sid ) ) ) );
return pattern;
}
|
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
);
return !!result;
}
Term GetFuncSig( const Value& func )
{
| | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
);
return !!result;
}
Term GetFuncSig( const Value& func )
{
auto funcType = ValueFromEIR( func.type() );
assert( funcType );
return GetFuncSigFromType( *funcType );
}
Term GetFuncSigFromType( const Value& funcType )
{
auto typeDecomp = Decompose( funcType.val(),
|
| ︙ | ︙ | |||
71 72 73 74 75 76 77 |
auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;
return VEC( *Unquote( ptypes ), rtype );
}
Term GetFuncRType( const Value& func )
{
| | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;
return VEC( *Unquote( ptypes ), rtype );
}
Term GetFuncRType( const Value& func )
{
auto funcType = ValueFromEIR( func.type() );
assert( funcType );
auto typeDecomp = Decompose( funcType->val(),
Vec(
Lit( "func"_sid ),
SubTerm(), // kind
SubTerm(), // return type
|
| ︙ | ︙ | |||
110 111 112 113 114 115 116 |
return ParamListKind::Invalid;
auto result = ParamListKind::Regular;
const auto& vec = *get< pvec >( tup.val() );
for( auto&& x : vec.terms() )
{
| | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
return ParamListKind::Invalid;
auto result = ParamListKind::Regular;
const auto& vec = *get< pvec >( tup.val() );
for( auto&& x : vec.terms() )
{
auto v = ValueFromEIR( x );
if( !v )
return ParamListKind::Invalid;
if( IsTDecl( *v ) || IsTNamedDecl( *v ) || IsTExpr( *v ) )
result = ParamListKind::Template;
else if( !IsDecl( *v ) && !v->isConstant() )
return ParamListKind::Invalid;
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 |
return FuncType( rtype, *Unquote( params ),
static_pointer_cast< FuncVerificationInfos >( vinf ),
static_cast< llvm::FunctionType* >( llvmtype ), varArg );
}
Term Bridge< Func >::Type( const builtins::Func& func )
{
| | | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
return FuncType( rtype, *Unquote( params ),
static_pointer_cast< FuncVerificationInfos >( vinf ),
static_cast< llvm::FunctionType* >( llvmtype ), varArg );
}
Term Bridge< Func >::Type( const builtins::Func& func )
{
return ValueToEIR( ::ToValue( func.type() ) );
}
Value Bridge< Func >::ToValue( const builtins::Func& func )
{
if( func.isExternal() )
return Value( Type( func ), TERM( *func.symbol() ) );
return Value( Type( func ), VEC(
TERM( func.tokens() ), TERM( func.paramsDecl() ), TERM( func.cir() ) ) );
}
optional< Func > Bridge< Func >::FromValue( const Value& v )
{
if( !v.isConstant() || v.isPoison() )
return nullopt;
auto funcTypeVal = ValueFromEIR( v.type() );
if( !funcTypeVal )
return nullopt;
auto funcType = ::FromValue< FuncType >( *funcTypeVal );
if( !funcType )
return nullopt;
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/invoke.cpp.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
if( IsBuiltinFunc( newCallee ) )
return BuildComputedValue( unifiedRType, cir::Call( newCallee, unifiedArgs ) );
if( IsIntrinsicFunc( newCallee ) )
return GetBuiltinIntrinsicFuncWrapper( newCallee )( c, unifiedArgs );
| | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
if( IsBuiltinFunc( newCallee ) )
return BuildComputedValue( unifiedRType, cir::Call( newCallee, unifiedArgs ) );
if( IsIntrinsicFunc( newCallee ) )
return GetBuiltinIntrinsicFuncWrapper( newCallee )( c, unifiedArgs );
auto ft = *FromValue< FuncType >( *ValueFromEIR( newCallee.type() ) );
auto argList = BuildArgListForCall( ft, unifiedArgs );
return BuildComputedValue( unifiedRType, cir::Call( newCallee, argList ) );
}
optional< Term > getSignature( const Value& callee ) const final
{
|
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
static ptr< InvocationRule > pRule = make_shared< FunctionInvocationRule >();
return pRule;
}
void SetupFunctionInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
| | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
static ptr< InvocationRule > pRule = make_shared< FunctionInvocationRule >();
return pRule;
}
void SetupFunctionInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
GetFuncInvocationRule() );
}
}
|
Changes to bs/builtins/types/func/lower.cpp.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 |
optional< FuncType > LowerFunctionTypeForRuntime( const Context& c, const FuncType& ft )
{
// If the passed function already have an associated llvm type,
// we have nothing to do.
if( ft.llvmType() )
return ft;
| | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
optional< FuncType > LowerFunctionTypeForRuntime( const Context& c, const FuncType& ft )
{
// If the passed function already have an associated llvm type,
// we have nothing to do.
if( ft.llvmType() )
return ft;
auto rt = LowerTypeForRuntime( c, *ValueFromEIR( ft.returnType() ) );
if( !rt )
return nullopt;
vector< llvm::Type* > paramTypes;
const auto& paramVec = *get< pvec >( ft.params() );
paramTypes.reserve( paramVec.terms().size() );
|
| ︙ | ︙ | |||
37 38 39 40 41 42 43 |
{
success = false;
return false;
}
if( vp->val() == HOLE( "_"_sid ) )
{
| | | | | | 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 |
{
success = false;
return false;
}
if( vp->val() == HOLE( "_"_sid ) )
{
auto type = LowerTypeForRuntime( c, *ValueFromEIR( vp->type() ) );
if( !type )
{
success = false;
return false;
}
paramTypes.emplace_back( GetLLVMType( *type ) );
vp->type() = ValueToEIR( *type );
pv->append( ValueToEIR( *vp ) );
}
else
pv->append( p );
return true;
} );
if( !success )
return nullopt;
auto* pLLVMType = llvm::FunctionType::get( GetLLVMType( *rt ), paramTypes, ft.varArg() );
if( !pLLVMType )
return nullopt;
return FuncType( ValueToEIR( *rt ), pv, nullptr, pLLVMType );
}
void SetupFunctionLowering( Env& e )
{
RegisterBuiltinFunc< Intrinsic< Value ( TypePatternParam< FuncPattern > ) > >( e, e.extLowerTypeForRuntime(),
[]( const Context& c, const Value& ft )
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/typecheck.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
void SetupFunctionTypeChecking( Env& e )
{
// Default param rule: we basically treat it like a regular value.
// Things that need a more specific rule for params can override this with
// more specific pattern.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
| | | | | | | | | | | | | | | | | | 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 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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
void SetupFunctionTypeChecking( Env& e )
{
// Default param rule: we basically treat it like a regular value.
// Things that need a more specific rule for params can override this with
// more specific pattern.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
TSID( param ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *ValuePatternFromIRExpr( lhs );
lhsVal.sort() = HOLE( "_"_sid );
co_yield Unify( ValueToEIR( lhsVal ), rhs, tcc );
} );
// Constant param rule
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *ValuePatternFromIRExpr( lhs );
auto rhsVal = *ValuePatternFromIRExpr( rhs );
// Unify the types
for( auto&& [ut,tcc] : Unify( lhsVal.type(), rhsVal.type(), tcc ) )
{
// Unify the contents
for( auto&& [uv,tcc] : Unify( lhsVal.val(), rhsVal.val(), tcc ) )
{
ValuePattern result( move( ut ), move( uv ), rhsVal.locationId() );
co_yield { ValueToEIR( move( result ) ), tcc };
}
}
} );
auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( RT ), ANYTERM( P ), ANYTERM( _ ), ANYTERM( VA ) ) ) );
auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
// func type param / func arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( funcTypePat ),
ValueToEIR( ValuePattern(
TSID( constant ),
funcTypePat,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto rhsVal = *ValueFromEIR( rhs );
if( IsBuiltinFunc( rhsVal ) )
{
co_yield { rhs, tcc };
co_return;
}
auto wrapped = WrapWithPostprocFunc( rhs, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( tcc.context(), rhsVal );
if( func.isPoison() )
return nullopt;
return ValueToEIR( func );
} );
co_yield { move( wrapped ), tcc };
} );
// tfunc type param / func arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( move( tFuncTypePat ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
move( funcTypePat ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *ValueFromEIR( type ) );
assert( callPat );
auto rhsVal = *ValueFromEIR( rhs );
auto sig = GetFuncSig( rhsVal );
for( auto&& [s, tcc] : TypeCheck( sig, *callPat, tcc ) )
{
if( IsBuiltinFunc( rhsVal ) )
{
co_yield { ValueToEIR( rhsVal ), tcc };
continue;
}
auto wrapped = WrapWithPostprocFunc( s, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( tcc.context(), rhsVal );
if( func.isPoison() )
return nullopt;
return ValueToEIR( func );
} );
co_yield { move( wrapped ), tcc };
}
} );
}
}
|
Changes to bs/builtins/types/init.cpp.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
// or partial specialization of this, since it will have to emit specialized
// binary runtime code.
RegisterBuiltinFunc< Intrinsic< Value ( MutRefOfTypeT, ValueOfTypeT ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r, const Value& initVal )
{
auto ref = *FromValue< Reference >( r );
| | | | | 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 |
// or partial specialization of this, since it will have to emit specialized
// binary runtime code.
RegisterBuiltinFunc< Intrinsic< Value ( MutRefOfTypeT, ValueOfTypeT ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r, const Value& initVal )
{
auto ref = *FromValue< Reference >( r );
if( !ParseTypePredicates( c, c.identity(), *ValueFromEIR( ref.type().type() ) ) )
return PoisonValue();
return BuildComputedValue( GetValueType< void >(),
Store( r, initVal ) );
} );
// Default initialization for ct_int vars
RegisterBuiltinFunc< Intrinsic< Value ( CTIntMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
auto ref = *FromValue< Reference >( r );
if( !ParseTypePredicates( c, c.identity(), *ValueFromEIR( ref.type().type() ) ) )
return PoisonValue();
return BuildComputedValue( GetValueType< void >(),
Store( r, ToValue( BigInt() ) ) );
} );
// Default initialization for ct_string vars
RegisterBuiltinFunc< Intrinsic< Value ( CTStringMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
auto ref = *FromValue< Reference >( r );
if( !ParseTypePredicates( c, c.identity(), *ValueFromEIR( ref.type().type() ) ) )
return PoisonValue();
return BuildComputedValue( GetValueType< void >(),
Store( r, ToValue( ""s ) ) );
} );
}
}
|
Changes to bs/builtins/types/intrinsic/intrinsic.cpp.
1 2 3 4 5 6 |
#include "builtins/builtins.h"
namespace goose::builtins
{
bool IsIntrinsicFunc( const Value& func )
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "builtins/builtins.h"
namespace goose::builtins
{
bool IsIntrinsicFunc( const Value& func )
{
auto funcType = ValueFromEIR( func.type() );
assert( funcType );
auto decomp = Decompose( funcType->val(),
Vec(
Lit( "func"_sid ),
Lit( "intrinsic"_sid ),
SubTerm(), // return type
|
| ︙ | ︙ |
Changes to bs/builtins/types/intrinsic/intrinsic.inl.
1 2 3 4 5 6 7 8 |
#ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL
#define GOOSE_BUILTINS_TYPES_INTRINSIC_INL
namespace goose::eir
{
template< typename R, typename... T >
const Term& Bridge< builtins::Intrinsic< R ( T... ) > >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL
#define GOOSE_BUILTINS_TYPES_INTRINSIC_INL
namespace goose::eir
{
template< typename R, typename... T >
const Term& Bridge< builtins::Intrinsic< R ( T... ) > >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( func ), TSID( intrinsic ),
GetValueType< Value >(),
sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
static_pointer_cast< void >( fvi ), TERM( 0U )
) ) );
return type;
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/drop.cpp.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
if( lv.name() == ""_sid )
return;
// Make the variable visible from the current scope (the parent scope of the statement)
auto identity = AppendToVectorTerm( c.identity(), lv.name() );
c.env()->storeValue( identity, ANYTERM( _ ),
| | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
if( lv.name() == ""_sid )
return;
// Make the variable visible from the current scope (the parent scope of the statement)
auto identity = AppendToVectorTerm( c.identity(), lv.name() );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( v ) );
// Extend the variable's lifetime, so that it won't be destroyed as the statement's lifetime scope ends,
// but instead when its parent lifetime scope ends.
if( c.codeBuilder() )
c.codeBuilder()->extendValueLifetime( lv.index() );
} );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/invoke.cpp.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 |
return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
}
};
void SetupLocalVarInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
| | | 27 28 29 30 31 32 33 34 35 36 37 38 39 |
return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
}
};
void SetupLocalVarInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( Value(
GetValueType< LocalVar >( ANYTERM( _ ) ),
ANYTERM( _ ) ) ),
make_shared< LocVarInvocationRule >() );
}
}
|
Changes to bs/builtins/types/localvar/localvar.cpp.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
auto bb = cfg->currentBB();
if( !bb )
return PoisonValue();
// If the type is a tuple of type, transform it into the type of a tuple.
// I'm hoping that I'm just a huge idiot and not seeing a more obvious and
// simpler way that would avoid this confusing distinction...
| | | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
auto bb = cfg->currentBB();
if( !bb )
return PoisonValue();
// If the type is a tuple of type, transform it into the type of a tuple.
// I'm hoping that I'm just a huge idiot and not seeing a more obvious and
// simpler way that would avoid this confusing distinction...
Value typeVal = *ValueFromEIR( type );
if( IsTuple( typeVal ) )
typeVal = TupleOfTypesToTupleType( *ValueFromEIR( type ) );
LocalVar lv( name, ValueToEIR( typeVal ), index );
bb->emplace_back( AllocVar( typeVal, index ) );
Value initResult;
{
DiagnosticsContext dc( 0, "When invoking Initialize." );
|
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
MakeTuple( move( initResult ) ) );
}
auto locVar = ToValue( lv );
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
| | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
MakeTuple( move( initResult ) ) );
}
auto locVar = ToValue( lv );
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( locVar ) );
cb->pushLiveValue( locVar, lv.index() );
return locVar;
}
Value DeclareLocalVarWithTypeInference( Context& c, const Term& typeTExpr, StringId name, const Value& initVal )
{
|
| ︙ | ︙ | |||
96 97 98 99 100 101 102 |
// Where pat is the TNamedDecl's type pattern and initValType is the initialization
// expression's type.
// We construct the above expressions and unify them. The best solution (if any)
// will give us the wanted type and the function to invoke to initialize it.
// Create the _ texpr.
| | | | | | | | | 96 97 98 99 100 101 102 103 104 105 106 107 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 |
// Where pat is the TNamedDecl's type pattern and initValType is the initialization
// expression's type.
// We construct the above expressions and unify them. The best solution (if any)
// will give us the wanted type and the function to invoke to initialize it.
// Create the _ texpr.
static auto anyTVar = ValueToEIR( ToValue( TVar( "_"_sid ) ) );
// The $T texpr.
static auto TTVar = ValueToEIR( ToValue( TVar( "T"_sid ) ) );
// Create the MutRef[$T] param.
static auto mutRefParamPattern = ValueToEIR( ToValue( TNamedDecl( GetValueType< Reference >( TTVar, TSID( mut ) ), "ref"_sid ) ) );
auto initValParamPattern = ValueToEIR( ToValue( Decl( initVal.type(), "initVal"_sid ) ) );
// Create the _ ( MutRef[pat], initType ) initFunc param.
auto initFuncTFTParam = ValueToEIR( ToValue(
TNamedDecl( ValueToEIR( ToValue( TFuncType( anyTVar, VEC( move( mutRefParamPattern ), move( initValParamPattern ) ),
make_shared< vector< TermLoc > >(), make_shared< vector< TermLoc > >() ) ) ), "initFunc"_sid ) ) );
// Create our parameter list pattern.
auto paramPat = VEC(
*BuildTemplateSignature( c, TTVar ),
*BuildTemplateSignature( c, initFuncTFTParam )
);
// Create our arg list pattern.
auto args = VEC(
*BuildTemplateArgPattern( c, typeTExpr ),
ValueToEIR( ToValue( c.env()->extInitialize() ) )
);
auto us = FindBestTyping( paramPat, args, c );
if( holds_alternative< NoUnification >( us ) )
{
// TODO display details
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
Vec(
SubTerm(), // locvar
SubTerm() // initializer
)
);
auto&& [type, initializer] = *callDecomp;
| | | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
Vec(
SubTerm(), // locvar
SubTerm() // initializer
)
);
auto&& [type, initializer] = *callDecomp;
auto initializerVal = *ValueFromEIR( initializer );
auto index = cfg->getNewTemporaryIndex();
// Retrieve the texpr's location and set it on the inferred type. This way if an
// error occurs later with it, for instance when calling LowerTypeForRuntime on it during codegen,
// it will have a meaningful location for the error message to attach itself on.
uint32_t typeLoc = ValueFromEIR( typeTExpr )->locationId();
LocalVar lv( name, type, index );
bb->emplace_back( AllocVar( ValueFromEIR( lv.type() )->setLocationId( typeLoc ), index ) );
DiagnosticsContext dc( 0, "When invoking Initialize." );
auto initResult = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
MakeTuple( ToValue( lv ), initVal ) );
if( !initResult.isConstant() && cir::CanValueBeEagerlyEvaluated( initResult ) )
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
auto locVar = ToValue( lv );
if( name != ""_sid )
{
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
| | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
auto locVar = ToValue( lv );
if( name != ""_sid )
{
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( locVar ) );
}
cb->pushLiveValue( locVar, lv.index() );
return locVar;
}
}
|
| ︙ | ︙ | |||
242 243 244 245 246 247 248 |
auto&& [type] = *result;
return LocalVarType( move( type ) );
}
Term Bridge< LocalVar >::Type( const Term& type )
{
| | | | 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 |
auto&& [type] = *result;
return LocalVarType( move( type ) );
}
Term Bridge< LocalVar >::Type( const Term& type )
{
return ValueToEIR( ToValue< LocalVarType >( type ) );
}
Value Bridge< LocalVar >::ToValue( const LocalVar& lv )
{
return Value( Type( lv.type() ), VEC( TERM( lv.name() ), TERM( lv.index() ) ) );
}
optional< LocalVar > Bridge< LocalVar >::FromValue( const Value& v )
{
if( !v.isConstant() )
return nullopt;
auto t = FromValue< LocalVarType >( *ValueFromEIR( v.type() ) );
if( !t )
return nullopt;
auto result = Decompose( v.val(),
Vec(
Val< StringId >(),
Val< uint32_t >()
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/typecheck.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupLocalVarTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
| | | | | | | 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 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupLocalVarTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
auto refTypePattern = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
// LocalVar type checking against another LocalVar: unify their types.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( localVarPattern ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lvarType = *FromValue< LocalVarType >( *ValueFromEIR( ValuePatternFromIRExpr( lhs )->type() ) );
auto rhsVal = *ValuePatternFromIRExpr( rhs );
auto rvarType = *FromValue< LocalVarType >( *ValueFromEIR( rhsVal.type() ) );
for( auto&& [s, tcc] : Unify( lvarType.type(), rvarType.type(), tcc ) )
{
co_yield { ValueToEIR( Value( ValueToEIR( ToValue( LocalVarType( s ) ) ),
rhsVal.val() ) ), tcc };
}
} );
}
}
|
Changes to bs/builtins/types/overloadset/helpers.cpp.
1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
#include "execute/execute.h"
namespace goose::builtins
{
ptr< OverloadSet > CreateOverloadSet( Env& env, const StringId& name )
{
auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );
auto pOvlSet = make_shared< OverloadSet >( identity );
| | | | | | 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 |
#include "builtins/builtins.h"
#include "execute/execute.h"
namespace goose::builtins
{
ptr< OverloadSet > CreateOverloadSet( Env& env, const StringId& name )
{
auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );
auto pOvlSet = make_shared< OverloadSet >( identity );
env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
return pOvlSet;
}
ptr< OverloadSet > GetOverloadSet( Env& env, const StringId& name )
{
auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );
Term result;
switch( env.retrieveValue( identity, RootIdentity(), result ) )
{
case sema::Env::Status::Success:
return *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );
case sema::Env::Status::NoMatch:
throw logic_error( format( "fatal: overload set {} not found", name ) );
case sema::Env::Status::AmbiguousMatch:
throw logic_error( format( "fatal: ambiguous match for overload set {}", name ) );
}
return nullptr;
}
ptr< OverloadSet > GetOrCreateOverloadSet( Env& env, const StringId& name )
{
auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );
Term result;
switch( env.retrieveValue( identity, RootIdentity(), result ) )
{
case sema::Env::Status::Success:
return *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );
case sema::Env::Status::NoMatch:
{
auto pOvlSet = make_shared< OverloadSet >( identity );
env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
return pOvlSet;
}
case sema::Env::Status::AmbiguousMatch:
throw logic_error( format( "fatal: ambiguous match for overload set {}", name ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/overloadset/invoke.cpp.
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
static ptr< InvocationRule > pRule = make_shared< OverloadSetInvocationRule >();
return pRule;
}
void SetupOverloadSetInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
| | | 67 68 69 70 71 72 73 74 75 76 77 78 79 |
static ptr< InvocationRule > pRule = make_shared< OverloadSetInvocationRule >();
return pRule;
}
void SetupOverloadSetInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( Value(
GetValueType< ptr< OverloadSet > >(),
ANYTERM( _ ) ) ),
GetOverloadSetInvocationRule() );
}
}
|
Changes to bs/builtins/types/overloadset/overloadset.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "builtins/builtins.h"
using namespace goose::builtins;
bool goose::builtins::IsOverloadSet( const Value& os )
{
return os.type() == GetValueType< ptr< OverloadSet > >();
}
namespace goose::eir
{
const Term& Bridge< ptr< builtins::OverloadSet > >::Type()
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "builtins/builtins.h"
using namespace goose::builtins;
bool goose::builtins::IsOverloadSet( const Value& os )
{
return os.type() == GetValueType< ptr< OverloadSet > >();
}
namespace goose::eir
{
const Term& Bridge< ptr< builtins::OverloadSet > >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( overloadset ) ) ) );
return type;
}
Value Bridge< ptr< builtins::OverloadSet > >::ToValue( const ptr< builtins::OverloadSet >& os )
{
return Value( Type(), TERM( static_pointer_cast< void >( os ) ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/overloadset/typecheck.cpp.
1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupOverloadSetTypeChecking( Env& e )
{
| | | | | | | 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 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupOverloadSetTypeChecking( Env& e )
{
auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );
auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
// func type param / overloadset arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( move( funcTypePat ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
GetValueType< ptr< builtins::OverloadSet > >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildCallPatternFromFuncType( *ValueFromEIR( type ) );
auto cpdecomp = Decompose( callPat,
Vec(
SubTerm(),
SubTerm()
)
);
assert( cpdecomp );
auto&& [argPat, rtPat] = *cpdecomp;
auto rhsVal = *ValueFromEIR( rhs );
auto os = *FromValue< ptr< OverloadSet > >( rhsVal );
auto rhsLocId = rhsVal.locationId();
// Create a new named hole namespace to isolate holes from the passed function from those in
// the called function.
auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
{
tcc.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );
if( func.isPoison() )
return nullopt;
| | | | | | | 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 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 136 |
{
tcc.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );
if( func.isPoison() )
return nullopt;
return ValueToEIR( move( func ) );
} );
co_yield { move( wrapped ), tcc };
}
} );
// tfunc type param / overloadset arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
move( tFuncTypePat ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
GetValueType< ptr< builtins::OverloadSet > >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *ValueFromEIR( type ) );
assert( callPat );
auto cpdecomp = Decompose( *callPat,
Vec(
SubTerm(),
SubTerm()
)
);
assert( cpdecomp );
auto&& [argPat, rtPat] = *cpdecomp;
auto rhsVal = *ValueFromEIR( rhs );
auto os = *FromValue< ptr< OverloadSet > >( rhsVal );
auto rhsLocId = rhsVal.locationId();
// Create a new named hole namespace to isolate holes from the called functions from those
// in the call expression.
auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
|
| ︙ | ︙ | |||
151 152 153 154 155 156 157 |
{
tcc.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );
if( func.isPoison() )
return nullopt;
| | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
{
tcc.setRHSNamespaceIndex( localNSId );
auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );
if( func.isPoison() )
return nullopt;
return ValueToEIR( move( func ) );
} );
co_yield { move( wrapped ), tcc };
}
} );
}
}
|
Changes to bs/builtins/types/param.h.
1 2 3 4 5 6 7 8 9 10 |
#ifndef GOOSE_BUILTINS_TYPES_PARAM_H
#define GOOSE_BUILTINS_TYPES_PARAM_H
namespace goose::builtins
{
template< typename T, typename V >
auto ParamPat( T&& type, V&& val )
{
// If the type is a tuple of type, convert it to the type of a tuple.
// (the type of a tuple is just a list of values, so just extract the value part of the tuple)
| | | | | | | | 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 |
#ifndef GOOSE_BUILTINS_TYPES_PARAM_H
#define GOOSE_BUILTINS_TYPES_PARAM_H
namespace goose::builtins
{
template< typename T, typename V >
auto ParamPat( T&& type, V&& val )
{
// If the type is a tuple of type, convert it to the type of a tuple.
// (the type of a tuple is just a list of values, so just extract the value part of the tuple)
if( auto typeVal = ValueFromEIR( type ); typeVal && IsTuple( *typeVal ) )
return ValueToEIR( Value( ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );
return ValueToEIR( Value( forward< T >( type ), forward< V >( val ) ) );
}
template< typename T >
auto ParamPat( T&& type )
{
// If the type is a tuple of type, convert it to the type of a tuple.
// (the type of a tuple is just a list of values, so just extract the value part of the tuple)
if( auto typeVal = ValueFromEIR( type ); typeVal && IsTuple( *typeVal ) )
return ValueToEIR( ValuePattern( HOLE( "_"_sid ), ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );
return ValueToEIR( ValuePattern( TSID( param ), forward< T >( type ), HOLE( "_"_sid ) ) );
}
}
#endif
|
Changes to bs/builtins/types/reference/parse.cpp.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 |
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( p.resolver()->currentLocation(),
"expected a type.", 0 );
p.pushValue( PoisonValue() );
return true;
}
| | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( p.resolver()->currentLocation(),
"expected a type.", 0 );
p.pushValue( PoisonValue() );
return true;
}
ReferenceType rt( ValueToEIR( *type ), move( bhv ) );
p.pushValue( ToValue( rt ) );
return true;
};
Rule r( parseRefType );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToEIR( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ref ) ), ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/builtins/types/reference/reference.cpp.
1 2 3 4 5 6 7 8 9 10 11 |
#include "builtins/builtins.h"
#include "parse/parse.h"
using namespace goose::builtins;
using namespace goose::cir;
using namespace goose::parse;
namespace goose::builtins
{
bool IsReferenceType( const Term& t )
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include "builtins/builtins.h"
#include "parse/parse.h"
using namespace goose::builtins;
using namespace goose::cir;
using namespace goose::parse;
namespace goose::builtins
{
bool IsReferenceType( const Term& t )
{
auto result = Decompose( ValueFromEIR( t )->val(),
Vec(
Lit( "reference"_sid ),
SubTerm(),
SubTerm()
)
);
|
| ︙ | ︙ | |||
76 77 78 79 80 81 82 |
auto&& [bhv, type] = *result;
return ReferenceType( move( type ), move( bhv ) );
}
Term Bridge< builtins::Reference >::Type( const Term& type, const Term& bhv )
{
| | | | | 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 |
auto&& [bhv, type] = *result;
return ReferenceType( move( type ), move( bhv ) );
}
Term Bridge< builtins::Reference >::Type( const Term& type, const Term& bhv )
{
return ValueToEIR( ::ToValue( ReferenceType( type, bhv ) ) );
}
Value Bridge< builtins::Reference >::ToValue( const builtins::Reference& ref )
{
return BuildComputedValue( ValueToEIR( ::ToValue( ref.type() ) ), cir::CalcAddress{ ref.address() } );
}
optional< builtins::Reference > Bridge< builtins::Reference >::FromValue( const Value& v )
{
if( v.isConstant() )
return nullopt;
auto cirRef = get_if< cir::CalcAddress >( &v.cir()->content() );
if( !cirRef )
return nullopt;
auto t = FromValue< ReferenceType >( *ValueFromEIR( v.type() ) );
if( !t )
return nullopt;
return builtins::Reference( move( *t ), get< cir::CalcAddress >( v.cir()->content() ) );
}
}
|
Changes to bs/builtins/types/reference/typecheck.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupReferenceTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
| | | | | | | | | | 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 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupReferenceTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
auto refTypePattern = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
auto refTypePatternConstant = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( const ), ANYTERM( _ ) ) ) );
auto refTypePatternMutable = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( mut ), ANYTERM( _ ) ) ) );
auto refTypePatternTemporary = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( temp ), ANYTERM( _ ) ) ) );
// Reference type checking rule.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( refTypePattern ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lRefType = *FromValue< ReferenceType >( *ValueFromEIR( ValuePatternFromIRExpr( lhs )->type() ) );
auto rhsVal = *ValuePatternFromIRExpr( rhs );
auto rRefType = *FromValue< ReferenceType >( *ValueFromEIR( rhsVal.type() ) );
// Unify the behaviors
for( auto&& [b, tcc] : Unify( lRefType.behavior(), rRefType.behavior(), tcc ) )
{
// Unify the types
for( auto&& [t, tcc] : Unify( lRefType.type(), rRefType.type(), tcc ) )
{
co_yield { ValueToEIR( ValuePattern( rhsVal.sort(), ValueToEIR( ToValue( ReferenceType( t, b ) ) ),
rhsVal.val() ) ), tcc };
}
}
}
);
// mut -> const reference unification rule.
|
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
// Reference type checking against a param (implicit dereferencing):
// Unify the referenced value with the param.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ANYTERM( _ ),
| | | | | | | | | | | | | | | | | 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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
// Reference type checking against a param (implicit dereferencing):
// Unify the referenced value with the param.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ANYTERM( _ ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto refval = *ValueFromEIR( rhs );
auto ref = FromValue< Reference >( refval );
if( !ref )
co_return;
auto content = ValueToEIR( BuildComputedValue( ref->type().type(),
cir::Load( refval, ref->type().type() ) )
.setLocationId( refval.locationId() ) );
// TypeCheck the param with the ref's content
co_yield TypeCheck( lhs, content, tcc );
} );
// LocalVar type checking against a param (implicit referencing):
// Build a mutable ref value, or just unwrap the locVar if it
// already contains a ref
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltype = ValuePatternFromIRExpr( lhs )->type();
auto lvval = *ValueFromEIR( rhs );
auto locvar = FromValue< LocalVar >( lvval );
if( !locvar )
co_return;
auto ref = ValueToEIR( ToValue( BuildLocalVarMutRef( *locvar ) )
.setLocationId( lvval.locationId() ) );
co_yield TypeCheck( lhs, ref, tcc );
} );
// Implicit referencing of non-variables: build a tempref
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[refTypePattern]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
if( !tcc.context().codeBuilder() )
co_return;
if( !tcc.context().codeBuilder()->cfg() )
co_return;
auto lRefType = *FromValue< ReferenceType >( *ValueFromEIR( ValuePatternFromIRExpr( lhs )->type() ) );
auto lhsPat = ValueToEIR( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );
auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )
{
auto valPat = *ValuePatternFromIRExpr( s );
ReferenceType rt( valPat.type(), TSID( temp ) );
auto refPat = ValueToEIR( ValuePattern( HOLE( "_"_sid ), ValueToEIR( ToValue( rt ) ), HOLE( "_"_sid ) ) );
// TypeCheck the param with the ref
for( auto&& [s,tcc] : TypeCheck( lhs, refPat, tcc ) )
{
assert( tcc.complexity() >= GetComplexity( ParamPat( refTypePattern ) ) );
tcc.subComplexity( GetComplexity( ParamPat( refTypePattern ) ) );
auto wrapped = WrapWithPostprocFunc( VEC( s, rhs ),
[tempIndex]( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
{
auto result = Decompose( t,
Vec(
SubTerm(),
SubTerm()
)
);
assert( result );
auto&& [ref, rhs] = *result;
auto rhsVal = *ValueFromEIR( rhs );
auto refPat = *ValuePatternFromIRExpr( ref );
auto rt = *FromValue< ReferenceType >( *ValueFromEIR( refPat.type() ) );
return ValueToEIR( ToValue( Reference{ move( rt ), TemporaryBaseAddr( tempIndex, rhsVal ) } ) );
} );
co_yield { move( wrapped ), tcc };
}
}
} );
}
}
|
Changes to bs/builtins/types/runtime/array.cpp.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
{
if( !GetLLVMType( containedType ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( containedType.locationId(), "runtime arrays can only contain runtime types." );
return PoisonValue();
}
| | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
{
if( !GetLLVMType( containedType ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( containedType.locationId(), "runtime arrays can only contain runtime types." );
return PoisonValue();
}
return ToValue( ArrayType( ValueToEIR( containedType ), count ) );
} );
}
llvm::Type* GetLLVMType( const ArrayType& a )
{
return llvm::ArrayType::get( GetLLVMType( *ValueFromEIR( a.m_containedType ) ), a.m_count );
}
}
namespace goose::eir
{
Value Bridge< ArrayType >::ToValue( const ArrayType& a )
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/basic.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "builtins/builtins.h"
#include "codegen/codegen.h"
#include "builtins/helpers.h"
using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;
namespace goose::builtins
{
void SetupRuntimeBasicTypes( Env& e )
{
| | | | | | | | | 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 |
#include "builtins/builtins.h"
#include "codegen/codegen.h"
#include "builtins/helpers.h"
using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;
namespace goose::builtins
{
void SetupRuntimeBasicTypes( Env& e )
{
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( half ) ), ANYTERM( _ ), ValueToEIR( ToValue( HalfFloatType() ) ) );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( float ) ), ANYTERM( _ ), ValueToEIR( ToValue( FloatType() ) ) );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( double ) ), ANYTERM( _ ), ValueToEIR( ToValue( DoubleFloatType() ) ) );
RegisterBuiltinFunc< Eager< Value > ( uint32_t ) >( e, "uint"_sid,
[]( uint32_t numBits )
{
return ToValue( IntegerType( numBits ) );
} );
RegisterBuiltinFunc< Eager< Value > ( uint32_t ) >( e, "sint"_sid,
[]( uint32_t numBits )
{
return ToValue( IntegerType( numBits, true ) );
} );
}
const Term& IntegerType::Pattern::GetPattern()
{
static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
nullptr,
VEC( HOLE( "size"_sid ), HOLE( "signedness"_sid ) ) ) ) );
return pattern;
}
const Term& IntegerType::PatternSigned::GetPattern()
{
static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
nullptr,
VEC( HOLE( "size"_sid ), TERM( 1U ) ) ) ) );
return pattern;
}
const Term& IntegerType::PatternUnsigned::GetPattern()
{
static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
nullptr,
VEC( HOLE( "size"_sid ), TERM( 0U ) ) ) ) );
return pattern;
}
const Term& IntegerType::PatternUnsigned32::GetPattern()
{
static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
nullptr,
VEC( TERM( 32U ), TERM( 0U ) ) ) ) );
return pattern;
}
llvm::Type* GetLLVMType( const HalfFloatType& t )
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 |
auto&& [predicates, llvmType, params] = *result;
auto&& [numBits, signd] = params;
return IntegerType( numBits, !!signd );
}
Term Bridge< APSInt >::Type( const APSInt& i )
{
| | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
auto&& [predicates, llvmType, params] = *result;
auto&& [numBits, signd] = params;
return IntegerType( numBits, !!signd );
}
Term Bridge< APSInt >::Type( const APSInt& i )
{
return ValueToEIR( eir::ToValue(
IntegerType( i.getBitWidth(), i.isSigned() ) ) );
}
Value Bridge< APSInt >::ToValue( const APSInt& i )
{
return Value( Type( i ), TERM( i ) );
}
|
| ︙ | ︙ | |||
179 180 181 182 183 184 185 |
return *result;
}
const Term& Bridge< uint8_t >::Type()
{
| | | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
return *result;
}
const Term& Bridge< uint8_t >::Type()
{
static auto type = ValueToEIR( eir::ToValue(
IntegerType( 8, false ) ) );
return type;
}
Value Bridge< uint8_t >::ToValue( uint8_t x )
{
return eir::ToValue( APSInt::getUnsigned( x ).trunc( 8 ) );
}
optional< uint8_t > Bridge< uint8_t >::FromValue( const Value& v )
{
return FromValue< APSInt >( v )->getLimitedValue();
}
const Term& Bridge< uint32_t >::Type()
{
static auto type = ValueToEIR( eir::ToValue(
IntegerType( 32, false ) ) );
return type;
}
Value Bridge< uint32_t >::ToValue( uint32_t x )
{
return eir::ToValue( APSInt::getUnsigned( x ).trunc( 32 ) );
}
optional< uint32_t > Bridge< uint32_t >::FromValue( const Value& v )
{
return FromValue< APSInt >( v )->getLimitedValue();
}
const Term& Bridge< uint64_t >::Type()
{
static auto type = ValueToEIR( eir::ToValue(
IntegerType( 64, false ) ) );
return type;
}
Value Bridge< uint64_t >::ToValue( uint64_t x )
{
return eir::ToValue( APSInt::getUnsigned( x ) );
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/init.cpp.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 |
// Default initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
auto ref = *FromValue< Reference >( r );
| | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// Default initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
auto ref = *FromValue< Reference >( r );
auto opTypeVal = *ValueFromEIR( ref.type().type() );
auto opType = *FromValue< IntegerType >( opTypeVal );
auto initVal = Value( ref.type().type(),
APSInt( opType.m_numBits, !opType.m_signed ) );
return BuildComputedValue( GetValueType< void >(),
Store( r, initVal ) );
} );
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/pointer.cpp.
1 2 3 4 5 6 7 8 9 10 11 |
#include "builtins/builtins.h"
#include "builtins/helpers.h"
using namespace goose;
using namespace goose::builtins;
namespace goose::builtins
{
void SetupRuntimePointerType( Env& e )
{
// null pointer literal
| | | | | 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 |
#include "builtins/builtins.h"
#include "builtins/helpers.h"
using namespace goose;
using namespace goose::builtins;
namespace goose::builtins
{
void SetupRuntimePointerType( Env& e )
{
// null pointer literal
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( nullptr ) ), ANYTERM( _ ), ValueToEIR( ToValue( NullPointer() ) ) );
RegisterBuiltinFunc< Eager< Value > ( Value ) >( e, "pointer"_sid,
[]( const Value& pointedType )
{
if( !GetLLVMType( pointedType ) )
{
// TODO come up with some lightweight builtin option type
// for the builtin apis, because this is a very bullshit
// way to handle errors
return ToValue( "error"s );
}
return ToValue( PointerType( ValueToEIR( pointedType ) ) );
} );
}
llvm::Type* GetLLVMType( const PointerType& p )
{
return llvm::PointerType::getUnqual( GetLLVMType( *ValueFromEIR( p.m_pointedType ) ) );
}
}
namespace goose::eir
{
Value Bridge< PointerType >::ToValue( const PointerType& p )
{
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
return nullopt;
return NullPointerType();
}
const Term& Bridge< NullPointer >::Type()
{
| | | | 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 |
return nullopt;
return NullPointerType();
}
const Term& Bridge< NullPointer >::Type()
{
static auto type = ValueToEIR( eir::ToValue( NullPointerType() ) );
return type;
}
const Value& Bridge< NullPointer >::ToValue( const NullPointer& np )
{
static auto val = Value( Type(), TSID( nullptr ) );
return val;
}
optional< NullPointer > Bridge< NullPointer >::FromValue( const Value& v )
{
if( !FromValue< NullPointerType >( *ValueFromEIR( v.type() ) ) )
return nullopt;
auto result = Decompose( v.val(),
Lit( "nullptr"_sid )
);
if( !result )
return nullopt;
return NullPointer();
}
}
|
Changes to bs/builtins/types/runtime/record.cpp.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 |
llvm::Type* GetLLVMType( const RecordType& rt )
{
vector< llvm::Type* > elements;
elements.reserve( rt.m_memberTypes->terms().size() );
for( auto&& mt : rt.m_memberTypes->terms() )
{
| | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
llvm::Type* GetLLVMType( const RecordType& rt )
{
vector< llvm::Type* > elements;
elements.reserve( rt.m_memberTypes->terms().size() );
for( auto&& mt : rt.m_memberTypes->terms() )
{
auto llvmType = GetLLVMType( *ValueFromEIR( mt ) );
assert( llvmType );
elements.emplace_back( llvmType );
}
return llvm::StructType::get( GetLLVMContext(), elements, rt.m_packed );
}
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/record.h.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
pvec m_memberTypes;
bool m_packed = false;
};
template< typename T, typename V >
Value CreateRecord( T&& types, V&& vals, bool packed )
{
| | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
pvec m_memberTypes;
bool m_packed = false;
};
template< typename T, typename V >
Value CreateRecord( T&& types, V&& vals, bool packed )
{
auto rt = ValueToEIR( ToValue( RecordType( forward< T >( types ), packed ) ) );
return Value( move( rt ), forward< V >( vals ) );
}
extern llvm::Type* GetLLVMType( const RecordType& rt );
}
namespace goose::eir
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/typecheck.cpp.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 |
VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );
// ct_int type against a IntegerType type:
// return the IntegerType type. We don't care if the
// ct_int fits at this point, this will be dealt with by
// the ct_int value type checking rule below.
e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
| | | | | | | | | 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 |
VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );
// ct_int type against a IntegerType type:
// return the IntegerType type. We don't care if the
// ct_int fits at this point, this will be dealt with by
// the ct_int value type checking rule below.
e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
ValueToEIR( rtIntTypePattern ),
GetValueType< BigInt >(),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
return HalfUnify( lhs, c );
} );
// Reject the ct_int param and IntegerType arg pattern,
// so that it doesn't fall into the rule above which would be incorrect
// in that case.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( GetValueType< BigInt >() ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( rtIntTypePattern ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
co_return;
} );
// ct_integer constant type checking against a IntegerType:
// Check if the IntegerType is big enough for the constant,
// and emit a LoadConstantInt cir instruction if so.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( rtIntTypePattern ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
GetValueType< BigInt >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
// The rhs might not be constant. It can happen even with ct_int if the rhs is a
// fake argument pattern generated to unify a higher-order function param.
// It means that we are unifying a function parameter against any ct_int value,
// which we can't (because we have to know the value to safely convert it),
// so we reject it.
auto rhsVal = *ValueFromEIR( rhs );
if( !rhsVal.isConstant() )
co_return;
auto lhsVal = ValuePatternFromIRExpr( lhs );
if( !lhsVal )
co_return;
|
| ︙ | ︙ | |||
86 87 88 89 90 91 92 |
SubTerm()
)
);
assert( result );
auto&& [type, rhs] = *result;
| | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
SubTerm()
)
);
assert( result );
auto&& [type, rhs] = *result;
auto ct = *FromValue< BigInt >( *ValueFromEIR( rhs ) );
auto rttypeVal = ValueFromEIR( type );
assert( rttypeVal );
auto rttype = FromValue< IntegerType >( *rttypeVal );
assert( rttype );
APSInt valToLoad;
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
valToLoad = ct.zext( rttype->m_numBits );
valToLoad.setIsSigned( false );
}
return TERM( valToLoad );
} );
| | | | | | | | | | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
valToLoad = ct.zext( rttype->m_numBits );
valToLoad.setIsSigned( false );
}
return TERM( valToLoad );
} );
co_yield { ValueToEIR( Value( s, move( wrapped ) ) ), tcc };
}
} );
auto rtInt8TypePattern = Value( TypeType(), MkStdType( TSID( integer ),
VEC( TERM( 8U ), ANYTERM( _ ) ) ) );
auto rtInt8PtrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
ValueToEIR( rtInt8TypePattern ) ) );
// ct_string type against a char*:
// return the char* type.
e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
ValueToEIR( rtInt8PtrTypePattern ),
GetValueType< string >(),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
co_yield HalfUnify( lhs, c );
} );
// ct_string constant type checking against a pointer to a integer( 8 ):
// Emit a LoadConstantStr cir instruction.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( rtInt8PtrTypePattern ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
GetValueType< string >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
auto str = *FromValue< string >( *ValueFromEIR( rhs ) );
auto lhsVal = *ValuePatternFromIRExpr( lhs );
co_yield { ValueToEIR(
BuildComputedValue( lhsVal.type(), cir::LoadConstStr( str ) ) ), c };
} );
auto ptrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
ANYTERM( _ ) ) );
// nullptr constant type checking against a pointer of any type;
// Yield a value of the given pointer type, with a 0 integer as its content.
// This'll be recognized by codegen to emit a null pointer value of the right type.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( ValueToEIR( ptrTypePattern ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
GetValueType< NullPointer >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
auto lVal = *ValuePatternFromIRExpr( lhs );
co_yield { ValueToEIR( Value( lVal.type(), 0U ) ), c };
} );
}
}
|
Changes to bs/builtins/types/template/build.cpp.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
TFuncType BuildTFuncType( const Value& returnType, const Value& params )
{
auto v = make_shared< Vector >();
v->reserve( TupleSize( params ) );
ForEachInTuple( params, [&]( auto&& param )
{
| | | | | | 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 |
TFuncType BuildTFuncType( const Value& returnType, const Value& params )
{
auto v = make_shared< Vector >();
v->reserve( TupleSize( params ) );
ForEachInTuple( params, [&]( auto&& param )
{
v->append( ValueToEIR( param ) );
return true;
} );
return TFuncType( ValueToEIR( returnType ), v,
make_shared< vector< TermLoc > >(), make_shared< vector< TermLoc > >() );
}
optional< Term > BuildTFuncSignature( const Context& c, const TFuncType& tft )
{
auto v = make_shared< Vector >();
v->reserve( VecSize( tft.params() ) );
bool success = true;
ForEachInVectorTerm( tft.params(), [&]( auto&& param )
{
auto teSig = BuildTemplateSignature( c, param );
if( !teSig )
{
DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( param )->locationId(),
"Invalid template parameter." );
success = false;
return false;
}
v->append( move( *teSig ) );
return true;
} );
if( !success )
return nullopt;
auto rtSig = BuildTemplateSignature( c, tft.returnType() );
if( !rtSig )
{
DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( tft.returnType() )->locationId(),
"Invalid template return type or texpr." );
return nullopt;
}
return VEC( v, *rtSig );
}
|
| ︙ | ︙ | |||
80 81 82 83 84 85 86 |
bool success = true;
ForEachInVectorTerm( ftype->params(), [&]( auto&& param )
{
auto teArgPat = BuildTemplateArgPattern( c, param );
if( !teArgPat )
{
| | | | 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 |
bool success = true;
ForEachInVectorTerm( ftype->params(), [&]( auto&& param )
{
auto teArgPat = BuildTemplateArgPattern( c, param );
if( !teArgPat )
{
DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( param )->locationId(),
"Invalid template parameter." );
success = false;
return false;
}
apv->append( move( *teArgPat ) );
return true;
} );
if( !success )
return nullopt;
auto rtArgPat = BuildTemplateArgPattern( c, ftype->returnType() );
if( !rtArgPat )
{
DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( ftype->returnType() )->locationId(),
"Invalid template return type or texpr." );
return nullopt;
}
return VEC( apv,*rtArgPat );
}
}
|
Changes to bs/builtins/types/template/instantiate.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
{
auto p = BuildTemplateParam( c, param, arg );
instanceParams = AppendToTuple( instanceParams, p );
return true;
} );
// Build the instance function type and identity
| | | | 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 |
{
auto p = BuildTemplateParam( c, param, arg );
instanceParams = AppendToTuple( instanceParams, p );
return true;
} );
// Build the instance function type and identity
auto returnType = *ValueFromEIR( unifiedRType );
auto instanceType = BuildFuncType( c, returnType, instanceParams );
auto instanceSig = GetFuncSigFromType( ToValue( instanceType ) );
auto instanceIdentity = AppendToVectorTerm( tf->identity(), instanceSig );
// Look for an already existing instanced function
Value instanceFunc = PoisonValue();
Term result;
switch( c.env()->retrieveValue( instanceIdentity, c.identity(), result ) )
{
case Env::Status::Success:
instanceFunc = *ValueFromEIR( result );
break;
case Env::Status::NoMatch:
{
// Prepare the verification statements
instanceType.verifInfos()->setPreCondToks( tf->type().preCondToks() );
instanceType.verifInfos()->setPostCondToks( tf->type().postCondToks() );
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
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 );
| | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
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( _ ), ValueToEIR( instanceFunc ) );
break;
}
case Env::Status::AmbiguousMatch:
DiagnosticsManager::GetInstance().emitErrorMessage( callee.locationId(),
"unexpected ambiguous match when looking up a template function instance." );
return PoisonValue();
}
return instanceFunc;
}
}
|
Changes to bs/builtins/types/template/invoke.cpp.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
static ptr< InvocationRule > pRule = make_shared< TemplateFunctionInvocationRule >();
return pRule;
}
void SetupTemplateFunctionInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
| | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
static ptr< InvocationRule > pRule = make_shared< TemplateFunctionInvocationRule >();
return pRule;
}
void SetupTemplateFunctionInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( TSID( constant ),
ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
GetTFuncInvocationRule() );
}
}
|
Changes to bs/builtins/types/template/rules.cpp.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 |
return param;
}
optional< Term > buildArgPattern( const Context& c, const Value& val ) const final
{
auto decl = FromValue< Decl >( val );
assert( decl );
| | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
return param;
}
optional< Term > buildArgPattern( const Context& c, const Value& val ) const final
{
auto decl = FromValue< Decl >( val );
assert( decl );
return ValueToEIR( ValuePattern( TSID( computed ), decl->type(), TERM( ptr< void >() ) ) );
}
};
class TNamedDeclTemplateRule : public TemplateRule
{
optional< Term > buildSignature( const Context& c, const Value& val ) const final
{
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
auto tnd = FromValue< TNamedDecl >( val );
assert( tnd );
auto typeSig = BuildTemplateArgPattern( c, tnd->type() );
if( !typeSig )
return nullopt;
| | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
auto tnd = FromValue< TNamedDecl >( val );
assert( tnd );
auto typeSig = BuildTemplateArgPattern( c, tnd->type() );
if( !typeSig )
return nullopt;
return ValueToEIR( ValuePattern( TSID( computed ), *typeSig, TERM( ptr< void >() ) ) );
}
};
class TDeclTemplateRule : public TemplateRule
{
optional< Term > buildSignature( const Context& c, const Value& val ) const final
{
return ValueToEIR( val );
}
Value buildParamDecl( const Context& c, const Value& param, const Value& arg ) const final
{
return arg;
}
|
| ︙ | ︙ | |||
238 239 240 241 242 243 244 |
}
};
class TFuncTypeTemplateRule : public TemplateRule
{
optional< Term > buildSignature( const Context& c, const Value& val ) const final
{
| | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
}
};
class TFuncTypeTemplateRule : public TemplateRule
{
optional< Term > buildSignature( const Context& c, const Value& val ) const final
{
return ValueToEIR( val );
}
Value buildParamDecl( const Context& c, const Value& param, const Value& arg ) const final
{
return arg;
}
|
| ︙ | ︙ | |||
269 270 271 272 273 274 275 |
return buildSignature( c, val );
}
};
void SetupTemplateRules( Env& e )
{
// Decl
| | | | | | | | | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
return buildSignature( c, val );
}
};
void SetupTemplateRules( Env& e )
{
// Decl
auto declTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( decl ), ANYTERM( _ ) ) ) );
e.templateRuleSet()->addRule(
ValueToEIR( ValuePattern( TSID( constant ), declTypePat, ANYTERM( _ ) ) ),
make_shared< DeclTemplateRule >() );
// TNamedDecl
e.templateRuleSet()->addRule(
ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TNamedDecl >(), ANYTERM( _ ) ) ),
make_shared< TNamedDeclTemplateRule >() );
// TDecl
e.templateRuleSet()->addRule(
ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TDecl >(), ANYTERM( _ ) ) ),
make_shared< TDeclTemplateRule >() );
// TVar
e.templateRuleSet()->addRule(
ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TVar >(), ANYTERM( _ ) ) ),
make_shared< TVarTemplateRule >() );
// TVec
e.templateRuleSet()->addRule(
ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TVec >(), ANYTERM( _ ) ) ),
make_shared< TVecTemplateRule >() );
// Value
e.templateRuleSet()->addRule(
ValueToEIR( ValuePattern( TSID( constant ), ANYTERM( _ ), ANYTERM( _ ) ) ),
make_shared< ValueTemplateRule >() );
// TFuncType
auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
e.templateRuleSet()->addRule( tFuncTypePat,
make_shared< TFuncTypeTemplateRule >() );
}
}
|
Changes to bs/builtins/types/template/tc-tdecl.cpp.
1 2 3 4 5 6 |
#include "builtins/builtins.h"
namespace goose::builtins
{
Term BuildArgPatternFromTDecl( const TDecl& td )
{
| | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include "builtins/builtins.h"
namespace goose::builtins
{
Term BuildArgPatternFromTDecl( const TDecl& td )
{
return ValueToEIR( ValuePattern( HOLE( "_"_sid ), td.type(), HOLE( "_"_sid ) ) );
}
TCGen UnifyTDecl( const Term& lhs, const Term& rhs, TypeCheckingContext tcc )
{
auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
assert( tdecl );
auto tdeclHole = HOLE( tdecl->name() );
auto pat = ValueToEIR( Value( tdecl->type(), HOLE( "_"_sid ) ) );
// We are replacing lhs with a different terms and re-unifying,
// so update the complexity accordingly. The structure of the tdecl
// shouldn't count, only its pattern.
tcc.subComplexity( GetComplexity( lhs ) );
tcc.addComplexity( GetComplexity( pat ) );
|
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
co_yield { s, tcc };
}
}
}
void SetupTDeclTypeChecking( Env& e )
{
| | | | | | | | | | 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 |
co_yield { s, tcc };
}
}
}
void SetupTDeclTypeChecking( Env& e )
{
auto tDeclPat = ValueToEIR( Value( GetValueType< TDecl >(), VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );
e.typeCheckingRuleSet()->addHalfUnificationRule( TCRINFOS, tDeclPat,
[]( const Term& lhs, const TypeCheckingContext& c ) -> TCGen
{
auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
assert( tdecl );
return HalfUnify( tdecl->type(), c );
} );
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, ANYTERM( _ ), UnifyTDecl );
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, tDeclPat, UnifyTDecl );
// tfunc tdecl param / tfunc arg
auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
auto tDeclTFuncPat = ParamPat( GetValueType< TDecl >(), VEC( tFuncTypePat, ANYTERM( _ ) ) );
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
tDeclTFuncPat,
ValueToEIR( ValuePattern(
TSID( constant ),
move( tFuncTypePat ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
assert( tdecl );
auto tfuncType = FromValue< TFuncType >( *ValueFromEIR( tdecl->type() ) );
assert( tfuncType );
auto callPat = BuildArgPatternFromTDecl( *tdecl );
auto tdeclHole = HOLE( tdecl->name() );
auto rhsVal = *ValueFromEIR( rhs );
auto constraintPat = BuildTFuncSignature( tcc.context(), *tfuncType );
assert( constraintPat );
ConstrainedFunc cfunc( *constraintPat, GetTFuncInvocationRule(), rhsVal );
auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );
// Create a new named hole namespace to isolate holes from the passed function from those in
// the called function.
auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
tcc.setRHSNamespaceIndex( tcc.newNamespaceIndex() );
auto oldValueRequired = tcc.isValueResolutionRequired();
|
| ︙ | ︙ | |||
122 123 124 125 126 127 128 |
} );
// tfunc tdecl param / overloadset arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
move( tDeclTFuncPat ),
| | | | | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
} );
// tfunc tdecl param / overloadset arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
move( tDeclTFuncPat ),
ValueToEIR( ValuePattern(
TSID( constant ),
GetValueType< ptr< builtins::OverloadSet > >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
assert( tdecl );
auto tfuncType = FromValue< TFuncType >( *ValueFromEIR( tdecl->type() ) );
assert( tfuncType );
auto callPat = BuildArgPatternFromTDecl( *tdecl );
auto tdeclHole = HOLE( tdecl->name() );
auto rhsVal = *ValueFromEIR( rhs );
auto constraintPat = BuildTFuncSignature( tcc.context(), *tfuncType );
assert( constraintPat );
ConstrainedFunc cfunc( *constraintPat, GetOverloadSetInvocationRule(), rhsVal );
auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );
// Create a new named hole namespace to isolate holes from the passed function from those in
// the called function.
auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
tcc.setRHSNamespaceIndex( tcc.newNamespaceIndex() );
auto oldValueRequired = tcc.isValueResolutionRequired();
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tdecl.cpp.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
}
}
namespace goose::eir
{
const Term& Bridge< TDecl >::Type()
{
| | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
}
}
namespace goose::eir
{
const Term& Bridge< TDecl >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), TSID( tdecl ) ) );
return type;
}
Value Bridge< TDecl >::ToValue( const TDecl& td )
{
return Value( Type(), VEC( td.type(), TERM( td.name() ) ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tfunc.cpp.
1 2 3 4 5 6 7 8 9 10 11 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
using namespace goose::builtins;
using namespace goose::parse;
namespace goose::eir
{
Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
{
| | | | 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 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
using namespace goose::builtins;
using namespace goose::parse;
namespace goose::eir
{
Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
{
return ValueToEIR( ::ToValue( tf.type() ) );
}
Value Bridge< TFunc >::ToValue( const TFunc& tf )
{
return Value( Type( tf ), VEC( Quote( tf.signature() ), tf.identity(),
TERM( tf.toks() ) ) );
}
optional< TFunc > Bridge< TFunc >::FromValue( const Value& v )
{
auto typeVal = ValueFromEIR( v.type() );
auto type = ::FromValue< TFuncType >( *typeVal );
if( !type )
return nullopt;
auto result = Decompose( v.val(),
Vec(
SubTerm(), // signature
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tfunctype.cpp.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
);
return !!result;
}
bool IsTFunc( const Value& t )
{
| | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
);
return !!result;
}
bool IsTFunc( const Value& t )
{
return IsTFuncType( *ValueFromEIR( t.type() ) );
}
}
namespace goose::eir
{
const Term& Bridge< TFuncType >::Type()
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tnameddecl.cpp.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
}
}
namespace goose::eir
{
const Term& Bridge< TNamedDecl >::Type()
{
| | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
}
}
namespace goose::eir
{
const Term& Bridge< TNamedDecl >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), TSID( tnameddecl ) ) );
return type;
}
Value Bridge< TNamedDecl >::ToValue( const TNamedDecl& td )
{
return Value( Type(), VEC( td.type(), TERM( td.name() ) ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tvar.cpp.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
if( ppVec && !( *ppVec )->empty()
&&( **ppVec )[0] == TSID( texpr ) )
{
return true;
}
}
| | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
if( ppVec && !( *ppVec )->empty()
&&( **ppVec )[0] == TSID( texpr ) )
{
return true;
}
}
auto typeVal = ValueFromEIR( te.type() );
if( !typeVal )
return false;
const auto* ppVec = get_if< pvec >( &typeVal->val() );
if( !ppVec )
return false;
|
| ︙ | ︙ | |||
41 42 43 44 45 46 47 |
}
}
namespace goose::eir
{
const Term& Bridge< TVar >::Type()
{
| | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
}
}
namespace goose::eir
{
const Term& Bridge< TVar >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tvar ) ) ) );
return type;
}
Value Bridge< TVar >::ToValue( TVar&& td )
{
return Value( Type(), TERM( td.name() ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tvec.cpp.
1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose::builtins;
namespace goose::eir
{
const Term& Bridge< TVec >::Type()
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include "builtins/builtins.h"
using namespace goose::builtins;
namespace goose::eir
{
const Term& Bridge< TVec >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tvec ) ) ) );
return type;
}
Value Bridge< TVec >::ToValue( const TVec& tv )
{
return Value( Type(), tv.content() );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/tvec.h.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
// so that they are automatically turned into a suitable TExpr if
// TExprs are passed as parameters.
template< typename... T >
extern Term BuildVecOrTVec( T&&... terms )
{
auto vec = Vector::Make( terms... );
| | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// so that they are automatically turned into a suitable TExpr if
// TExprs are passed as parameters.
template< typename... T >
extern Term BuildVecOrTVec( T&&... terms )
{
auto vec = Vector::Make( terms... );
if( ( IsTExpr( ValueFromEIR( terms ) ) || ... ) )
return ValueToEIR( ToValue( TVec( move( vec ) ) ) );
return vec;
}
#define TVEC( ... ) BuildVecOrTVec( __VA_ARGS__ )
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/typecheck.cpp.
1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupTemplateFunctionTypeChecking( Env& e )
{
| | | | | | | 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 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupTemplateFunctionTypeChecking( Env& e )
{
auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );
auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
// func type param / tfunc arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( move( funcTypePat ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
tFuncTypePat,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildCallPatternFromFuncType( *ValueFromEIR( type ) );
auto rhsVal = *ValueFromEIR( rhs );
auto tf = *FromValue< TFunc >( rhsVal );
// Create a new named hole namespace to isolate holes from the passed function from those in
// the called function.
auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
auto localNSId = tcc.newNamespaceIndex();
tcc.setRHSNamespaceIndex( localNSId );
|
| ︙ | ︙ | |||
60 61 62 63 64 65 66 |
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );
if( ifunc.isPoison() )
return nullopt;
| | | | | | 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 |
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );
if( ifunc.isPoison() )
return nullopt;
return ValueToEIR( ifunc );
} );
co_yield { move( wrapped ), tcc };
}
} );
// tfunc type param / tfunc arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( tFuncTypePat ),
ValueToEIR( ValuePattern(
TSID( constant ),
move( tFuncTypePat ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *ValueFromEIR( type ) );
assert( callPat );
auto rhsVal = *ValueFromEIR( rhs );
auto tf = *FromValue< TFunc >( rhsVal );
// Create a new named hole namespace to isolate holes from the passed function from those in
// the called function.
auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
auto localNSId = tcc.newNamespaceIndex();
tcc.setRHSNamespaceIndex( localNSId );
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );
if( ifunc.isPoison() )
return nullopt;
| | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ? "Instantiated here." : "", false );
auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );
if( ifunc.isPoison() )
return nullopt;
return ValueToEIR( ifunc );
} );
co_yield { move( wrapped ), tcc };
}
} );
}
}
|
Changes to bs/builtins/types/tuple/init.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "builtins/builtins.h"
#include "parse/parse.h"
using namespace goose::parse;
using namespace goose::cir;
namespace goose::builtins
{
void InitTuple( const Context& c, const Value& tupRef, const Value& initTup )
{
auto lref = *FromValue< Reference >( tupRef );
uint32_t index = 0;
| | | | | | 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 |
#include "builtins/builtins.h"
#include "parse/parse.h"
using namespace goose::parse;
using namespace goose::cir;
namespace goose::builtins
{
void InitTuple( const Context& c, const Value& tupRef, const Value& initTup )
{
auto lref = *FromValue< Reference >( tupRef );
uint32_t index = 0;
auto tupType = *ValueFromEIR( lref.type().type() );
if( TupleTypeSize( tupType ) != TupleSize( initTup ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0, "Incompatible tuple sizes." );
return;
}
ForEachInTupleType( tupType, [&]( auto&& t )
{
auto elemType = *ValueFromEIR( t );
// Create a mutable reference to the element to initialize
ReferenceType rt( t, TSID( mut ) );
auto addr = lref.address();
addr.appendToPath( index );
auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
move( addr ) ).setLocationId( elemType.locationId() );
auto elemInit = *ValueFromEIR( GetTupleElement( initTup, index++ ) );
DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
MakeTuple( elemRef, move( elemInit ) ) );
DiagnosticsContext dc2( elemType.locationId(), "When invoking DropValue." );
InvokeOverloadSet( c, c.env()->extDropValue(),
|
| ︙ | ︙ | |||
52 53 54 55 56 57 58 |
CustomPattern< Reference, Reference::PatternMutable< TuplePattern > >
) > >( e, e.extInitialize(),
[]( const Context& c, const Value& tupRef )
{
auto ref = *FromValue< Reference >( tupRef );
uint32_t index = 0;
| | | | | 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 |
CustomPattern< Reference, Reference::PatternMutable< TuplePattern > >
) > >( e, e.extInitialize(),
[]( const Context& c, const Value& tupRef )
{
auto ref = *FromValue< Reference >( tupRef );
uint32_t index = 0;
auto tupType = *ValueFromEIR( ref.type().type() );
ForEachInTupleType( tupType, [&]( auto&& t )
{
auto elemType = *ValueFromEIR( t );
// Create a mutable reference to the element to initialize
ReferenceType rt( t, TSID( mut ) );
auto addr = ref.address();
addr.path().back() = index++;
auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
Load( ToValue( ref ), rt.type() ) )
.setLocationId( elemType.locationId() );
DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
MakeTuple( elemRef ) );
|
| ︙ | ︙ |
Changes to bs/builtins/types/tuple/lower.cpp.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 |
[]( const Context& c, const Value& tupType )
{
RecordType rt;
bool success = true;
ForEachInTupleType( tupType, [&]( auto&& t )
{
| | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
[]( const Context& c, const Value& tupType )
{
RecordType rt;
bool success = true;
ForEachInTupleType( tupType, [&]( auto&& t )
{
auto loweredType = LowerTypeForRuntime( c, *ValueFromEIR( t ) );
if( !loweredType || loweredType->isPoison() )
{
success = false;
return false;
}
rt.m_memberTypes->append( ValueToEIR( *loweredType ) );
return true;
} );
if( !success )
return PoisonValue();
return ToValue( rt );
|
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
if( !member || member->isPoison() )
{
success = false;
return false;
}
types->append( member->type() );
| | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
if( !member || member->isPoison() )
{
success = false;
return false;
}
types->append( member->type() );
vals->append( ValueToEIR( *member ) );
return true;
} );
if( !success )
return PoisonValue();
return CreateRecord( move( types ), move( vals ), false );
} );
}
}
|
Changes to bs/builtins/types/tuple/tuple.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
Value MkTupleType( const Term& state, const Term& types )
{
return Value( TypeType(), VEC( TSID( tuple ), state, types ) );
}
extern Value TupleOfTypesToTupleType( const Value& tup )
{
| | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Value MkTupleType( const Term& state, const Term& types )
{
return Value( TypeType(), VEC( TSID( tuple ), state, types ) );
}
extern Value TupleOfTypesToTupleType( const Value& tup )
{
auto typeVal = ValueFromEIR( tup.type() );
auto result = Decompose( typeVal->val(),
Vec(
Lit( "tuple"_sid ),
SubTerm(),
SubTerm()
)
);
|
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
{
static auto type = MkTupleType( TSID( close ), VEC() );
return type;
}
const Value& EmptyTuple()
{
| | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
{
static auto type = MkTupleType( TSID( close ), VEC() );
return type;
}
const Value& EmptyTuple()
{
static auto val = Value( ValueToEIR( EmptyTupleType() ), VEC() );
return val;
}
const Value& EmptyClosedTuple()
{
static auto val = Value( ValueToEIR( EmptyClosedTupleType() ), VEC() );
return val;
}
Value ToClosedTupleType( const Value& tuptype )
{
auto decomp = Decompose( tuptype.val(),
Vec(
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
SubTerm(),
SubTerm()
)
);
auto&& [tupState, tupTypesVec] = *decomp;
| | | | | | | | | | | | | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
SubTerm(),
SubTerm()
)
);
auto&& [tupState, tupTypesVec] = *decomp;
auto newTypeVec = AppendToVectorTerm( tupTypesVec, ValueToEIR( type ) );
auto result = MkTupleType( tupState, newTypeVec );
if( tuptype.isPoison() || type.isPoison() )
result.setPoison();
return result;
}
Value AppendToTuple( const Value& tup, const ValuePattern& valPat )
{
auto tupType = ValueFromEIR( tup.type() );
assert( tupType );
auto result = Value(
ValueToEIR( AppendToTupleType( *tupType, valPat.type() ) ),
AppendToVectorTerm( tup.val(), ValueToEIR( valPat ) ) );
if( tup.isPoison() || valPat.isPoison() )
result.setPoison();
return result;
}
Value AppendToTuple( const Value& tup, const Value& val )
{
auto tupType = ValueFromEIR( tup.type() );
auto valType = ValueFromEIR( val.type() );
assert( tupType );
assert( valType );
auto result = Value(
ValueToEIR( AppendToTupleType( *tupType, *valType ) ),
AppendToVectorTerm( tup.val(), ValueToEIR( val ) ) );
if( tup.isPoison() || val.isPoison() )
result.setPoison();
return result;
}
Value PrependToTupleType( const Value& type, const Value& tuptype )
{
auto decomp = Decompose( tuptype.val(),
Vec(
Lit( "tuple"_sid ),
SubTerm(),
SubTerm()
)
);
auto&& [tupState, tupTypesVec] = *decomp;
auto newTypeVec = PrependToVectorTerm( tupTypesVec, ValueToEIR( type ) );
auto result = MkTupleType( tupState, newTypeVec );
if( tuptype.isPoison() || type.isPoison() )
result.setPoison();
return result;
}
Value PrependToTuple( const Value& val, const Value& tup )
{
auto tupType = ValueFromEIR( tup.type() );
auto valType = ValueFromEIR( val.type() );
assert( tupType );
assert( valType );
auto result = Value(
ValueToEIR( PrependToTupleType( *valType, *tupType ) ),
PrependToVectorTerm( tup.val(), ValueToEIR( val ) ) );
if( tup.isPoison() || val.isPoison() )
result.setPoison();
return result;
}
|
| ︙ | ︙ | |||
206 207 208 209 210 211 212 |
result.setPoison();
return result;
}
Value ConcatenateTuples( const Value& ltup, const Value& rtup )
{
| | | | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
result.setPoison();
return result;
}
Value ConcatenateTuples( const Value& ltup, const Value& rtup )
{
auto ltupType = ValueFromEIR( ltup.type() );
auto rtupType = ValueFromEIR( rtup.type() );
assert( ltupType );
assert( rtupType );
auto result = Value(
ValueToEIR( ConcatenateTupleTypes( *ltupType, *rtupType ) ),
ConcatenateVectorTerms( ltup.val(), rtup.val() ) );
if( ltup.isPoison() || rtup.isPoison() )
result.setPoison();
return result;
}
|
| ︙ | ︙ | |||
240 241 242 243 244 245 246 |
);
return !!result;
}
bool IsTuple( const Value& t )
{
| | | | | | 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 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
);
return !!result;
}
bool IsTuple( const Value& t )
{
auto typeVal = ValueFromEIR( t.type() );
if( !typeVal || !typeVal->isConstant() )
return false;
auto result = Decompose( typeVal->val(),
Vec(
Lit( "tuple"_sid ),
SubTerm(),
SubTerm()
)
);
return !!result;
}
bool IsOpenTuple( const Value& t )
{
if( !t.isConstant() )
return false;
auto typeVal = ValueFromEIR( t.type() );
auto result = Decompose( typeVal->val(),
Vec(
Lit( "tuple"_sid ),
Lit( "open"_sid ),
SubTerm()
)
);
return !!result;
}
Value CloseTuple( const Value& tup )
{
auto tupType = ValueFromEIR( tup.type() );
return Value( ValueToEIR( ToClosedTupleType( *tupType ) ),
tup.val() ).setLocationId( tup.locationId() );
}
size_t TupleTypeSize( const Value& tupType )
{
auto decomp = Decompose( tupType.val(),
Vec(
|
| ︙ | ︙ | |||
316 317 318 319 320 321 322 |
auto&& [tupState, tupTypesVec] = *decomp;
return tupTypesVec->terms()[index];
}
const Term& GetTupleElementType( const Value& tup, uint32_t index )
{
| | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
auto&& [tupState, tupTypesVec] = *decomp;
return tupTypesVec->terms()[index];
}
const Term& GetTupleElementType( const Value& tup, uint32_t index )
{
return GetTupleTypeElement( *ValueFromEIR( tup.type() ), index );
}
const Term& GetTupleElement( const Value& tup, uint32_t index )
{
const auto& vec = *get< pvec >( tup.val() );
return vec.terms()[index];
}
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 |
} );
return result;
}
const Term& TuplePattern::GetPattern()
{
| | | | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
} );
return result;
}
const Term& TuplePattern::GetPattern()
{
static auto pattern = ValueToEIR( MkTupleType( HOLE( "_"_sid ), HOLE( "_"_sid ) ) );
return pattern;
}
const Term& TupleOpenPattern::GetPattern()
{
static auto pattern = ValueToEIR( MkTupleType( TSID( open ), HOLE( "_"_sid ) ) );
return pattern;
}
const Term& TuplePatternOfTypeT::GetPattern()
{
static auto pattern = ValueToEIR( MkTupleType( HOLE( "_"_sid ), HOLE( "T"_sid ) ) );
return pattern;
}
}
|
Changes to bs/builtins/types/tuple/tuple.inl.
1 2 3 4 5 6 7 8 9 |
#ifndef GOOSE_BUILTINS_TYPES_TUPLE_INL
#define GOOSE_BUILTINS_TYPES_TUPLE_INL
namespace goose::builtins
{
template< typename... V >
Value MakeTuple( V&&... values )
{
return Value(
| | | | | 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 |
#ifndef GOOSE_BUILTINS_TYPES_TUPLE_INL
#define GOOSE_BUILTINS_TYPES_TUPLE_INL
namespace goose::builtins
{
template< typename... V >
Value MakeTuple( V&&... values )
{
return Value(
ValueToEIR( MkTupleType( TSID( close ), TERM( Vector::Make( values.type()... ) ) ) ),
TERM( Vector::Make( ValueToEIR( values )... ) ) );
}
template< typename F >
void ForEachInTuple( const Value& tup, F&& func )
{
// Check that the tuple's payload is a vector. It might be a hole.
if( !holds_alternative< pvec >( tup.val() ) )
return;
ForEachInVectorTerm( tup.val(), [&]( auto&& t )
{
return func( *ValueFromEIR( t ) );
} );
}
template< typename F >
void ForEachInTupleType( const Value& tupType, F&& func )
{
auto decomp = Decompose( tupType.val(),
|
| ︙ | ︙ | |||
83 84 85 86 87 88 89 |
return false;
if( !holds_alternative< pvec >( tup2.val() ) )
return false;
return ForEachInVectorTerms( tup1.val(), tup2.val(), [&]( auto&& t1, auto&& t2 )
{
| | | | | | | | | 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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
return false;
if( !holds_alternative< pvec >( tup2.val() ) )
return false;
return ForEachInVectorTerms( tup1.val(), tup2.val(), [&]( auto&& t1, auto&& t2 )
{
return func( *ValueFromEIR( t1 ), *ValueFromEIR( t2 ) );
} );
}
}
namespace goose::eir
{
// Type
static inline const Value& BuildTupleType( const Value& typeSoFar )
{
return typeSoFar;
}
template< typename H, typename... T >
static Value BuildTupleType( const Value& typeSoFar )
{
if constexpr( sizeof...( T ) > 1 )
{
return BuildTupleType< T... >( builtins::AppendToTupleType( typeSoFar,
*ValueFromEIR( GetValueType< H >() ) ) );
}
else
return builtins::AppendToTupleType( typeSoFar, *ValueFromEIR( GetValueType< H >() ) );
}
template< typename... T >
const Term& Bridge< tuple< T... > >::Type()
{
if constexpr( sizeof... ( T ) == 0 )
{
static auto type = ValueToEIR( builtins::EmptyClosedTupleType() );
return type;
}
else
{
static auto type = ValueToEIR( BuildTupleType< T... >( builtins::EmptyClosedTupleType() ) );
return type;
}
}
// Val
template< typename T, size_t... I >
auto BuildTupleValue( const T& tup, index_sequence< I... > )
{
return VEC( ValueToEIR( ToValue( get< I >( tup ) ) )... );
}
template< typename... T >
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( ValueFromEIR( 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;
|
| ︙ | ︙ |
Changes to bs/builtins/types/tuple/typecheck.cpp.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
for( auto&& [s,tcc] : TypeCheck( param, arg, tcc ) )
{
auto val = ValuePatternFromIRExpr( s );
assert( val );
auto newOut = AppendToTuple( out, *val );
if( index == ( tupSize - 1 ) )
| | | | | | | | | | | | | | | | | | | | | | | | | | 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 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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
for( auto&& [s,tcc] : TypeCheck( param, arg, tcc ) )
{
auto val = ValuePatternFromIRExpr( s );
assert( val );
auto newOut = AppendToTuple( out, *val );
if( index == ( tupSize - 1 ) )
co_yield { ValueToEIR( newOut ), tcc };
else
co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
}
}
TCGen TypeCheckComputedTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const cir::CalcAddress& tupAddr, uint32_t index, const Value& out )
{
auto param = ParamPat( GetTupleTypeElement( tupType, index ) );
auto argType = GetTupleElementType( tupArg, index );
ReferenceType rt( argType, TSID( const ) );
auto argAddr = tupAddr;
argAddr.appendToPath( index );
auto argRef = ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ),
move( argAddr ) ) );
auto tupSize = TupleTypeSize( tupType );
for( auto&& [s,tcc] : TypeCheck( param, argRef, tcc ) )
{
auto val = ValuePatternFromIRExpr( s );
assert( val );
auto newOut = AppendToTuple( out, *val );
if( index == ( tupSize - 1 ) )
co_yield { ValueToEIR( newOut ), tcc };
else
co_yield TypeCheckComputedTuple( tcc, tupType, tupArg, tupAddr, index + 1, newOut );
}
}
void SetupTupleTypeChecking( Env& e )
{
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
VECOFLENGTH( L ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = ValuePatternFromIRExpr( lhs );
auto rtup = ValueFromEIR( rhs );
if( !ltup || !rtup )
co_return;
auto tupType = *ValueFromEIR( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleSize( *rtup ) );
co_yield TypeCheckConstantTuple( tcc, tupType, *rtup, 0, EmptyTuple() );
} );
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( computed ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = ValuePatternFromIRExpr( lhs );
auto rtup = ValueFromEIR( rhs );
if( !ltup || !rtup || !tcc.context().codeBuilder() )
co_return;
auto tupType = *ValueFromEIR( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromEIR( rtup->type() ) ) );
auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
cir::CalcAddress addr( cir::TemporaryBaseAddr( tempIndex, *rtup ) );
co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, addr, 0, EmptyTuple() );
} );
// Single element tuple unwrapping rules: if we encounter such a tuple, attempt to typecheck
// its contained value with whatever's on the other side.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto tup = ValueFromEIR( rhs );
if( !tup )
co_return;
const auto& vec1 = *get< pvec >( tup->val() );
co_yield TypeCheck( lhs, vec1[0], tcc );
} );
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto tup = ValueFromEIR( lhs );
if( !tup )
co_return;
const auto& vec1 = *get< pvec >( tup->val() );
// In some cases, the tuple may not be an actual tuple value but merely
// a pattern for a tuple value, with a hole instead of its content vector.
|
| ︙ | ︙ | |||
172 173 174 175 176 177 178 |
// When unifying a tuple against a value whose type is a hole, we don't want
// the above rule to apply (ie we don't want 1 element tuples bound to generic
// template parameters to be peeled off). So here's a rule for this case which
// leaves the tuple unchanged. It will take priority over the above rule in
// those cases because it matches a more specific pattern.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
| | | | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
// When unifying a tuple against a value whose type is a hole, we don't want
// the above rule to apply (ie we don't want 1 element tuples bound to generic
// template parameters to be peeled off). So here's a rule for this case which
// leaves the tuple unchanged. It will take priority over the above rule in
// those cases because it matches a more specific pattern.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern( ANYTERM( _ ), HolePattern(), ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
co_yield { lhs, tcc };
} );
}
}
|
Changes to bs/builtins/types/typepredicates.cpp.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 |
return true;
// Create a new identity for the predicate, which imports everything from the parent identity
// and also makes @val visible as a placeholder for the type's value.
auto predicatesIdentity = VEC( Env::NewUniqueId() );
c.env()->addVisibilityRule( parentIdentity, predicatesIdentity );
| | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
return true;
// Create a new identity for the predicate, which imports everything from the parent identity
// and also makes @val visible as a placeholder for the type's value.
auto predicatesIdentity = VEC( Env::NewUniqueId() );
c.env()->addVisibilityRule( parentIdentity, predicatesIdentity );
auto typeTerm = ValueToEIR( type );
auto name = "@val"_sid;
auto valuePlaceholderIdentity = AppendToVectorTerm( predicatesIdentity, TERM( name ) );
c.env()->storeValue( valuePlaceholderIdentity, ANYTERM( _ ),
ValueToEIR( BuildComputedValue( typeTerm, cir::Placeholder( typeTerm, name ) ) ) );
Context localContext( c.env(), predicatesIdentity );
for( auto&& toks : tp.m_unparsedPredicates )
{
auto tokProvider = lex::MakeVectorAdapter( toks );
auto r = make_shared< parse::Resolver >( tokProvider, localContext );
|
| ︙ | ︙ |
Changes to bs/builtins/types/types.cpp.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
}
bool IsCompileTimeOnlyValue( const Value& v )
{
if( IsBuiltinFunc( v ) || IsIntrinsicFunc( v ) || IsType( v ) )
return true;
| | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
}
bool IsCompileTimeOnlyValue( const Value& v )
{
if( IsBuiltinFunc( v ) || IsIntrinsicFunc( v ) || IsType( v ) )
return true;
auto typeVal = *ValueFromEIR( v.type() );
assert( typeVal.isConstant() );
auto vec = get_if< pvec >( &typeVal.val() );
if( vec && !( *vec )->terms().empty() && ( *vec )->terms().front() == TSID( ct_type ) )
return true;
return false;
}
|
| ︙ | ︙ |
Changes to bs/cir/call.cpp.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 |
if( IsExternalFunc( m_func ) )
return false;
bool argsCanBeExecuted = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
| | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
if( IsExternalFunc( m_func ) )
return false;
bool argsCanBeExecuted = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
if( !IsValueConstantOrExecutable( *ValueFromEIR( arg ) ) )
{
argsCanBeExecuted = false;
return false;
}
return true;
} );
|
| ︙ | ︙ | |||
53 54 55 56 57 58 59 |
if( IsExternalFunc( m_func ) )
return false;
bool argsAreConstant = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
| | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
if( IsExternalFunc( m_func ) )
return false;
bool argsAreConstant = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
if( !CanValueBeEagerlyEvaluated( *ValueFromEIR( arg ) ) )
{
argsAreConstant = false;
return false;
}
return true;
} );
|
| ︙ | ︙ |
Changes to bs/codegen/instructions.cpp.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 |
const auto& vec = *get< pvec >( call.args() );
vector< llvm::Value* > args;
args.reserve( vec.terms().size() );
for( auto&& a : vec.terms() )
{
| | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
const auto& vec = *get< pvec >( call.args() );
vector< llvm::Value* > args;
args.reserve( vec.terms().size() );
for( auto&& a : vec.terms() )
{
auto* parg = buildValue( inf, *ValueFromEIR( a ) );
if( !parg )
return nullptr;
args.emplace_back( parg );
}
return m_llvmBuilder.CreateCall( llvm::FunctionCallee( llvmCallee ), args );
|
| ︙ | ︙ | |||
105 106 107 108 109 110 111 |
auto* pAlloca = buildAlloca( inf, GetLLVMType( *type ) );
createTemporary( inf, av.index(), pAlloca );
return pAlloca;
}
llvm::Value* Module::buildInstruction( Infos& inf, const cir::Load& load )
{
| | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
auto* pAlloca = buildAlloca( inf, GetLLVMType( *type ) );
createTemporary( inf, av.index(), pAlloca );
return pAlloca;
}
llvm::Value* Module::buildInstruction( Infos& inf, const cir::Load& load )
{
auto type = LowerTypeForRuntime( inf.context, *ValueFromEIR( load.type() ) );
if( !type )
return nullptr;
auto* llvmType = GetLLVMType( *type );
assert( llvmType );
auto* ptrVal = buildValue(inf, load.addr() );// buildAddress( inf, load.addr() );
|
| ︙ | ︙ |
Changes to bs/codegen/value.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
{
return *b ?
llvm::ConstantInt::getTrue( GetLLVMContext() ) :
llvm::ConstantInt::getFalse( GetLLVMContext() );
}
else if( auto intVal = FromValue< APSInt >( *val ) )
{
| | | | | | | | 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 |
{
return *b ?
llvm::ConstantInt::getTrue( GetLLVMContext() ) :
llvm::ConstantInt::getFalse( GetLLVMContext() );
}
else if( auto intVal = FromValue< APSInt >( *val ) )
{
return llvm::ConstantInt::get( GetLLVMType( *ValueFromEIR( val->type() ) ),
*FromValue< APSInt >( *val ) );
}
else if( auto ptType = FromValue< PointerType >( *ValueFromEIR( val->type() ) ) )
{
// The only kind of pointer constant we can have at the moment are nullptr.
return llvm::ConstantPointerNull::get( static_cast< llvm::PointerType* >
( GetLLVMType( *ValueFromEIR( val->type() ) ) ) );
}
else if( auto recType = FromValue< RecordType >( *ValueFromEIR( val->type() ) ) )
{
llvm::SmallVector< llvm::Constant*, 8 > members;
assert( holds_alternative< pvec >( val->val() ) );
bool success = true;
ForEachInVectorTerm( val->val(), [&]( auto&& t )
{
auto* pMemberVal = buildConstant( inf, *ValueFromEIR( t ) );
if( !pMemberVal )
{
success = false;
return false;
}
members.push_back( pMemberVal );
return true;
} );
if( !success )
return nullptr;
return llvm::ConstantStruct::get( static_cast< llvm::StructType* >
( GetLLVMType( *ValueFromEIR( val->type() ) ) ), members );
}
DiagnosticsManager::GetInstance().emitErrorMessage(
v.locationId(), "constants with compile time types are not supported.", 0 );
return nullptr;
}
|
Changes to bs/eir/value.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
static auto poisonType = Value( TypeType(), 0U ).setPoison();
return poisonType;
}
// A generic poisoned value of "poisontype" type.
const Value& PoisonValue()
{
| | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
static auto poisonType = Value( TypeType(), 0U ).setPoison();
return poisonType;
}
// A generic poisoned value of "poisontype" type.
const Value& PoisonValue()
{
static auto poisonVal = Value( ValueToEIR( PoisonType() ), 0U ).setPoison();
return poisonVal;
}
Term ValueToEIR( const Value& v )
{
if( v.isConstant() )
{
// Special case for type's type
if( v.isType() )
{
auto result = Decompose( v.val(),
|
| ︙ | ︙ | |||
56 57 58 59 60 61 62 |
}
return VEC( TSID( value ), TSID( computed ), v.type(),
TERM( static_pointer_cast< void >( v.cir() ) ),
static_cast< LocationId >( v.locationId() ) );
}
| | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
}
return VEC( TSID( value ), TSID( computed ), v.type(),
TERM( static_pointer_cast< void >( v.cir() ) ),
static_cast< LocationId >( v.locationId() ) );
}
optional< Value > ValueFromEIR( const Term& t )
{
// Special case for type's type
auto typedecomp = Decompose( t,
Vec(
Lit( "type"_sid ),
Val< uint32_t >(),
Val< LocationId >()
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
auto cir = Decompose( val, Val< ptr< void > >() );
if( !cir )
return nullopt;
return Value( type, static_pointer_cast< cir::Instruction >( ptr< void >( *cir ) ), static_cast< uint32_t >( locationId ) );
}
| | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
auto cir = Decompose( val, Val< ptr< void > >() );
if( !cir )
return nullopt;
return Value( type, static_pointer_cast< cir::Instruction >( ptr< void >( *cir ) ), static_cast< uint32_t >( locationId ) );
}
Term ValueToEIR( const ValuePattern& v )
{
return VEC( TSID( value ), v.sort(), v.type(), v.val(), static_cast< LocationId >( v.locationId() ) );
}
optional< ValuePattern > ValuePatternFromIRExpr( const Term& t )
{
auto result = Decompose( t,
|
| ︙ | ︙ |
Changes to bs/eir/value.h.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 |
namespace goose::eir
{
class Value;
class ValuePattern;
extern const Term& TypeType();
| | | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
namespace goose::eir
{
class Value;
class ValuePattern;
extern const Term& TypeType();
extern Term ValueToEIR( const Value& v );
extern optional< Value > ValueFromEIR( const Term& t );
extern Term ValueToEIR( const ValuePattern& v );
extern optional< ValuePattern > ValuePatternFromIRExpr( const Term& t );
class Value
{
public:
Value() : m_locationId( ~0 ) {}
|
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
auto&& setPoison() { m_locationId = ~0; return *this; }
bool isConstant() const { return holds_alternative< Term >( m_valOrCIR ); }
bool isType() const;
friend ostream& operator<<( ostream& out, const Value& val )
{
| | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
auto&& setPoison() { m_locationId = ~0; return *this; }
bool isConstant() const { return holds_alternative< Term >( m_valOrCIR ); }
bool isType() const;
friend ostream& operator<<( ostream& out, const Value& val )
{
return out << ValueToEIR( val );
}
bool operator==( const Value& rhs ) const
{
return m_type == rhs.m_type && m_valOrCIR == rhs.m_valOrCIR;
}
|
| ︙ | ︙ |
Changes to bs/execute/eval.cpp.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
ForEachInTuple( v, [&]( auto&& v )
{
auto newV = Evaluate( v, vm );
if( newV.isPoison() )
poison = true;
| | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
ForEachInTuple( v, [&]( auto&& v )
{
auto newV = Evaluate( v, vm );
if( newV.isPoison() )
poison = true;
vals.append( ValueToEIR( move( newV ) ) );
return true;
} );
Value newTup( v.type(), make_shared< Vector >( move( vals ) ) );
if( poison )
newTup.setPoison();
|
| ︙ | ︙ |
Changes to bs/execute/vm.cpp.
| ︙ | ︙ | |||
76 77 78 79 80 81 82 |
bool poisoned = false;
const auto& vec = *get< pvec >( call.args() );
if( IsBuiltinFunc( func ) )
{
auto newVec = vec.transform( [&]( auto&& x ) -> optional< Term >
{
| | | | | | | 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 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 136 137 138 139 140 |
bool poisoned = false;
const auto& vec = *get< pvec >( call.args() );
if( IsBuiltinFunc( func ) )
{
auto newVec = vec.transform( [&]( auto&& x ) -> optional< Term >
{
auto val = ValueFromEIR( x );
assert( val );
auto newVal = Evaluate( *val, *this );
if( newVal.isPoison() )
poisoned = true;
if( !newVal.isConstant() )
{
poisoned = true;
return ValueToEIR( PoisonValue() );
}
return ValueToEIR( newVal );
} );
if( poisoned )
return PoisonValue();
if( !newVec )
return nullopt;
return ExecuteBuiltinFuncCall( func, TERM( newVec ) );
}
const auto* pFunc = GetFuncCIR( func );
if( !pFunc || !pFunc->isValid() )
return PoisonValue();
auto savedStackSize = m_stack.size();
for( auto&& a : vec.terms() )
{
auto val = ValueFromEIR( a );
assert( val );
auto newVal = Evaluate( *val, *this );
if( newVal.isPoison() )
{
m_stack.resize( savedStackSize );
return PoisonValue();
}
if( !newVal.isConstant() )
{
m_stack.resize( savedStackSize );
return nullopt;
}
m_stack.emplace_back( ValueToEIR( newVal ) );
}
swap( m_currentFrameStart, savedStackSize );
auto result = execute( *pFunc->body() );
swap( m_currentFrameStart, savedStackSize );
m_stack.resize( savedStackSize );
|
| ︙ | ︙ | |||
158 159 160 161 162 163 164 |
optional< Value > VM::execute( const cir::CreateTemporary& ct )
{
auto stackIndex = m_currentFrameStart + ct.index();
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
| | | | | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
optional< Value > VM::execute( const cir::CreateTemporary& ct )
{
auto stackIndex = m_currentFrameStart + ct.index();
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
m_stack[stackIndex] = ValueToEIR( Evaluate( ct.value(), *this ) );
return nullopt;
}
optional< Value > VM::execute( const cir::GetTemporary& gt )
{
auto stackIndex = gt.index() + m_currentFrameStart;
if( stackIndex >= m_stack.size() )
return PoisonValue();
return ValueFromEIR( m_stack[stackIndex] );
}
optional< Value > VM::execute( const cir::AllocVar& av )
{
auto stackIndex = m_currentFrameStart + av.index();
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
m_stack[stackIndex] = BuildUninitializedValue( av.type() );
return nullopt;
}
optional< Value > VM::execute( const cir::Load& l )
{
auto addrInt = FromValue< uintptr_t >( Evaluate( l.addr(), *this ) );
if( !addrInt )
return nullopt;
auto addr = reinterpret_cast< const Term* >( *addrInt );
return ValueFromEIR( *addr );
}
optional< Value > VM::execute( const cir::Store& s )
{
auto addrInt = FromValue< uintptr_t >( Evaluate( s.addr(), *this ) );
if( !addrInt )
return nullopt;
auto addr = reinterpret_cast< Term* >( *addrInt );
auto result = Evaluate( s.val(), *this );
if( !result.isConstant() )
return PoisonValue();
*addr = ValueToEIR( result );
return nullopt;
}
optional< Value > VM::execute( const cir::Phi& p )
{
auto stackIndex = m_currentFrameStart + p.destIndex();
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
p.forAllIncomings( [&]( auto&& bb, auto&& val )
{
if( bb == m_pPreviousBB )
{
m_stack[stackIndex] = ValueToEIR( Evaluate( val, *this ) );
return false;
}
return true;
} );
return PoisonValue();
|
| ︙ | ︙ | |||
314 315 316 317 318 319 320 |
{
auto* pTerm = calcAddress( addr.baseAddr() );
if( !pTerm )
return nullptr;
for( auto&& index : addr.path() )
{
| | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
{
auto* pTerm = calcAddress( addr.baseAddr() );
if( !pTerm )
return nullptr;
for( auto&& index : addr.path() )
{
auto val = *ValueFromEIR( *pTerm );
// We only support tuples now, we'll also support arrays in the future.
// Everything else (structs, classes, containers, etc.) should build on top
// of those two fundamental types.
if( !IsTuple( val ) )
return nullptr;
|
| ︙ | ︙ | |||
348 349 350 351 352 353 354 |
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
if( stackIndex >= m_stack.size() )
return nullptr;
if( m_stack[stackIndex] == TSID( UNINITIALIZED ) )
| | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
if( stackIndex >= m_stack.size() )
return nullptr;
if( m_stack[stackIndex] == TSID( UNINITIALIZED ) )
m_stack[stackIndex] = ValueToEIR( Evaluate( ta.m_initValue, *this ) );
return &m_stack[stackIndex];
}
Term* VM::calcAddress( const cir::VarBaseAddr& va )
{
auto stackIndex = m_currentFrameStart + va.index;
|
| ︙ | ︙ | |||
372 373 374 375 376 377 378 |
return TSID( UNINITIALIZED );
auto tupContent = make_shared< Vector >();
tupContent->reserve( TupleTypeSize( type ) );
ForEachInTupleType( type, [&]( auto&& t )
{
| | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 |
return TSID( UNINITIALIZED );
auto tupContent = make_shared< Vector >();
tupContent->reserve( TupleTypeSize( type ) );
ForEachInTupleType( type, [&]( auto&& t )
{
tupContent->append( BuildUninitializedValue( *ValueFromEIR( t ) ) );
return true;
} );
return ValueToEIR( Value( ValueToEIR( type ), TERM( move( tupContent ) ) ) );
}
|
Changes to bs/parse/func.cpp.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
return true;
}
bool Parser::parseFunctionDeclaration( const Value& decl, const Value& paramsDecl )
{
auto d = FromValue< Decl >( decl );
| | | | 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 |
return true;
}
bool Parser::parseFunctionDeclaration( const Value& decl, const Value& paramsDecl )
{
auto d = FromValue< Decl >( decl );
if( !parseFuncType( *ValueFromEIR( d->type() ), paramsDecl ) )
return false;
const auto& c = context();
auto funcIdentity = DuplicateVectorTerm( c.identity() );
get< pvec >( funcIdentity )->terms().back() = TERM( d->name() );
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.env(), *func );
c.env()->storeValue( funcIdentity, ANYTERM( _ ),
ValueToEIR( ToValue( pOvlSet ) ) );
return true;
}
optional< Value > Parser::parseFunctionDeclaration( const Term& identity, const Value& paramsDecl )
{
if( !peekLastValue() )
|
| ︙ | ︙ |
Changes to bs/parse/parser.cpp.
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
// If the identifier is preceded by a TExpr or a Type,
// then this becomes a TDecl or a Decl, respectively.
if( IsTExpr( *leftVal ) )
{
auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );
| | | | | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
// If the identifier is preceded by a TExpr or a Type,
// then this becomes a TDecl or a Decl, respectively.
if( IsTExpr( *leftVal ) )
{
auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );
auto texpr = ValueToEIR( *popType() );
pushValue( ToValue( TNamedDecl( move( texpr ), *name ) ).setLocationId( loc ) );
return true;
}
else if( IsType( *leftVal ) )
{
auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );
auto type = ValueToEIR( *popType() );
pushValue( ToValue( Decl( move( type ), *name ) ).setLocationId( loc ) );
return true;
}
return parsePrefix( strid, prec );
}
bool Parser::parsePrefix( const pvec& vec, uint32_t prec )
{
auto t = *m_resolver->lookAhead();
auto val = ValueFromEIR( t.first );
if( !val )
return false;
if( val->isPoison() )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
// If the term is a prefix rule value, invoke its parsePrefix() function.
|
| ︙ | ︙ | |||
254 255 256 257 258 259 260 |
m_resolver->consume();
return ( *rule )->parsePrefix( *this, t.second, prec );
}
optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
| | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
m_resolver->consume();
return ( *rule )->parsePrefix( *this, t.second, prec );
}
optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
auto val = ValueFromEIR( t );
if( !val )
return nullopt;
if( val->type() == GetValueType< ptr< OverloadSet > >() )
{
if( !peekLastValue() )
return nullopt;
|
| ︙ | ︙ | |||
284 285 286 287 288 289 290 |
return ( *rule )->getPrecedence( *this );
}
bool Parser::parseInfix( const pvec& vec, uint32_t prec )
{
auto t = *m_resolver->lookAhead();
| | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
return ( *rule )->getPrecedence( *this );
}
bool Parser::parseInfix( const pvec& vec, uint32_t prec )
{
auto t = *m_resolver->lookAhead();
auto val = ValueFromEIR( t.first );
if( !val )
return false;
if( val->isPoison() )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
if( val->type() == GetValueType< ptr< OverloadSet > >() )
|
| ︙ | ︙ |
Changes to bs/parse/rule-helpers.cpp.
1 2 3 4 5 6 7 8 9 |
#include "parse.h"
using namespace goose;
using namespace goose::parse;
namespace goose::eir
{
const Term& Bridge< parse::Rule >::Type()
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include "parse.h"
using namespace goose;
using namespace goose::parse;
namespace goose::eir
{
const Term& Bridge< parse::Rule >::Type()
{
static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( rule ) ) ) );
return type;
}
Value Bridge< parse::Rule >::ToValue( parse::Rule&& r )
{
ptr< void > prule = make_shared< parse::Rule >( move( r ) );
return Value( Type(), TERM( move( prule ) ) );
|
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
}
namespace goose::parse
{
void RegisterRule( sema::Env& env, const Term& identity, Rule&& rule )
{
auto ruleVal = ToValue( move( rule ) );
| | | 28 29 30 31 32 33 34 35 36 37 38 |
}
namespace goose::parse
{
void RegisterRule( sema::Env& env, const Term& identity, Rule&& rule )
{
auto ruleVal = ToValue( move( rule ) );
auto ruleTerm = ValueToEIR( ruleVal );
env.storeValue( identity, ANYTERM( _ ), ruleTerm );
}
}
|
Changes to bs/parse/tfunc.cpp.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
return true;
}
bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl )
{
auto d = FromValue< TNamedDecl >( tnamedDecl );
| | | | 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 |
return true;
}
bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl )
{
auto d = FromValue< TNamedDecl >( tnamedDecl );
if( !parseTFuncType( *ValueFromEIR( d->type() ), paramsDecl ) )
return false;
const auto& c = context();
auto tfuncIdentity = DuplicateVectorTerm( c.identity() );
get< pvec >( tfuncIdentity )->terms().back() = TERM( d->name() );
auto tfunc = parseTemplateFunction( tfuncIdentity, paramsDecl );
if( tfunc.isPoison() )
return true;
// 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.env(), tfunc );
c.env()->storeValue( tfuncIdentity, ANYTERM( _ ),
ValueToEIR( ToValue( pOvlSet ) ) );
return true;
}
Value Parser::parseTemplateFunction( const Term& identity, const Value& paramsDecl )
{
auto pBody = getFuncBody();
|
| ︙ | ︙ |
Changes to bs/sema/invocation.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
{
const auto& rules = e.invocationRuleSet()->rules();
MatchSolution bestSol;
ptr< InvocationRule > pBestRule;
bool ambiguous = false;
| | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{
const auto& rules = e.invocationRuleSet()->rules();
MatchSolution bestSol;
ptr< InvocationRule > pBestRule;
bool ambiguous = false;
auto calleeTerm = ValueToEIR( callee );
for( auto&& [s, rule] : Match( calleeTerm, rules ) )
{
if( !pBestRule || s > bestSol )
{
bestSol = s;
pBestRule = rule;
|
| ︙ | ︙ |
Changes to bs/sema/lower.cpp.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
return nullopt;
return result;
}
optional< Value > LowerConstantForRuntime( const Context& c, const Value& val )
{
| | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
return nullopt;
return result;
}
optional< Value > LowerConstantForRuntime( const Context& c, const Value& val )
{
if( val.type() == GetValueType< bool >() || IsRuntimeType( *ValueFromEIR( val.type() ) ) )
return val;
DiagnosticsContext dc( val.locationId(), "When invoking LowerConstantForRuntime." );
auto result = InvokeOverloadSet( c, c.env()->extLowerConstantForRuntime(), AppendToTuple( EmptyTuple(), val ) );
if( result.isPoison() || !IsRuntimeType( *ValueFromEIR( result.type() ) ) )
return nullopt;
return result;
}
optional< Value > LowerTypeForVerification( const Context& c, const Value& type )
{
|
| ︙ | ︙ |
Changes to bs/sema/template.cpp.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
optional< Term > BuildTemplateSignature( const Context& c, const Term& tpl )
{
const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
if( !pTemplateRuleSet )
return nullopt;
| | | | | | 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 |
optional< Term > BuildTemplateSignature( const Context& c, const Term& tpl )
{
const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
if( !pTemplateRuleSet )
return nullopt;
return pTemplateRuleSet->buildSignature( c, *ValueFromEIR( tpl ) );
}
Value BuildTemplateParam( const Context& c, const Term& tpl, const Term& arg )
{
const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
if( !pTemplateRuleSet )
return PoisonValue();
return pTemplateRuleSet->buildParamDecl( c, *ValueFromEIR( tpl ), *ValueFromEIR( arg ) );
}
void TemplateSetup( const Context& c, TypeCheckingContext tcc, const Term& tpl )
{
const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
if( !pTemplateRuleSet )
return;
pTemplateRuleSet->setup( c, tcc, *ValueFromEIR( tpl ) );
}
extern optional< Term > BuildTemplateArgPattern( const Context& c, const Term& tpl )
{
const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
if( !pTemplateRuleSet )
return nullopt;
return pTemplateRuleSet->buildArgPattern( c, *ValueFromEIR( tpl ) );
}
}
|
Changes to bs/verify/call.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
// Inject the arguments in the context.
// They will be picked up by getVars instructions when refered to
// by the verification conditions.
uint32_t index = 0;
ForEachInVectorTerm( instr.args(), [&]( auto&& t )
{
| | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// Inject the arguments in the context.
// They will be picked up by getVars instructions when refered to
// by the verification conditions.
uint32_t index = 0;
ForEachInVectorTerm( instr.args(), [&]( auto&& t )
{
auto arg = *ValueFromEIR( t );
if( auto zv = BuildZ3ExprFromValue( b, arg ) )
cb.setVar( index++, move( *zv ) );
return true;
} );
|
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
if( retExpr )
cb.setPlaceholder( "@result"_sid, retExpr->expr );
// Check preconditions.
const auto& preConds = fvi->preConditions();
ForEachInVectorTerm( preConds, [&]( auto&& t )
{
| | | | 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 111 112 |
if( retExpr )
cb.setPlaceholder( "@result"_sid, retExpr->expr );
// Check preconditions.
const auto& preConds = fvi->preConditions();
ForEachInVectorTerm( preConds, [&]( auto&& t )
{
auto val = *ValueFromEIR( t );
if( auto zv = BuildZ3ExprFromValue( cb, val ) )
{
DiagnosticsContext dc( instr.func().locationId(), "At this call." );
b.checkAssertion( zv->expr, val.locationId() );
}
return true;
} );
// Add the return type's predicates as assumptions.
ForEachPredicate( cb, ft.returnType(), retExpr->expr, [&]( auto&& z3expr, auto locId )
{
b.assume( z3expr );
} );
// Add postconditions as assumptions.
const auto& postConds = fvi->postConditions();
ForEachInVectorTerm( postConds, [&]( auto&& t )
{
if( auto zv = BuildZ3ExprFromValue( cb, *ValueFromEIR( t ) ) )
b.assume( zv->expr );
return true;
} );
return retExpr;
}
}
|
Changes to bs/verify/comptime.cpp.
| ︙ | ︙ | |||
94 95 96 97 98 99 100 |
// by the verification conditions.
uint32_t index = 0;
bool eagerEvalFailed = false;
ForEachInVectorTerm( instr.args(), [&]( auto&& t )
{
| | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
// by the verification conditions.
uint32_t index = 0;
bool eagerEvalFailed = false;
ForEachInVectorTerm( instr.args(), [&]( auto&& t )
{
auto arg = ValueFromEIR( t );
if( !arg->isConstant() )
{
execute::VM vm;
arg = execute::Evaluate( *arg, vm );
if( !arg->isConstant() )
|
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
return true;
} );
// Check preconditions.
const auto& preConds = fvi->preConditions();
ForEachInVectorTerm( preConds, [&]( auto&& t )
{
| | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
return true;
} );
// Check preconditions.
const auto& preConds = fvi->preConditions();
ForEachInVectorTerm( preConds, [&]( auto&& t )
{
auto val = *ValueFromEIR( t );
if( auto zv = BuildZ3ExprFromValue( b, val ) )
{
DiagnosticsContext dc( instr.func().locationId(), "At this compilation-time call." );
b.checkAssertion( zv->expr, val.locationId() );
}
return true;
} );
return !b.hasCheckFailed();
}
}
|
Changes to bs/verify/condition.cpp.
| ︙ | ︙ | |||
47 48 49 50 51 52 53 |
bool Condition::addConditionsList( const pvec& assList )
{
bool success = true;
ForEachInVectorTerm( assList, [&]( auto&& t )
{
| | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
bool Condition::addConditionsList( const pvec& assList )
{
bool success = true;
ForEachInVectorTerm( assList, [&]( auto&& t )
{
auto val = *ValueFromEIR( t );
if( val.isPoison() )
{
success = false;
return false;
}
if( val.type() != GetValueType< bool >() )
|
| ︙ | ︙ |
Changes to bs/verify/func.cpp.
| ︙ | ︙ | |||
93 94 95 96 97 98 99 |
// Add assumptions of the function's requirements
const auto& reqs = m_func->type().verifInfos()->preConditions();
ForEachInVectorTerm( reqs, [&]( auto&& t )
{
// Don't do any error handling here, it should already have been taken care of
// by the condition verifier.
| | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
// Add assumptions of the function's requirements
const auto& reqs = m_func->type().verifInfos()->preConditions();
ForEachInVectorTerm( reqs, [&]( auto&& t )
{
// Don't do any error handling here, it should already have been taken care of
// by the condition verifier.
if( auto zv = BuildZ3ExprFromValue( m_builder, *ValueFromEIR( t ) ) )
m_builder.assume( zv->expr );
return true;
} );
}
bool result = buildZ3Expressions( *m_cfg->entryBB(), nullptr );
|
| ︙ | ︙ |
Changes to bs/verify/helpers.inl.
1 2 3 4 5 6 7 8 9 10 |
#ifndef GOOSE_HELPERS_INL
#define GOOSE_HELPERS_INL
#include "builtins/helpers.h"
namespace goose::verify
{
template< typename F >
void ForEachPredicate( Builder& b, const Term& t, const z3::expr& valExpr, F&& func )
{
| | | | 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 |
#ifndef GOOSE_HELPERS_INL
#define GOOSE_HELPERS_INL
#include "builtins/helpers.h"
namespace goose::verify
{
template< typename F >
void ForEachPredicate( Builder& b, const Term& t, const z3::expr& valExpr, F&& func )
{
auto type = *ValueFromEIR( t );
auto optTypePreds = builtins::GetTypePredicates( type );
if( !optTypePreds || !*optTypePreds )
return;
auto& tp = **optTypePreds;
const auto* prevValPH = b.retrievePlaceholder( "@val"_sid );
b.setPlaceholder( "@val"_sid, valExpr );
ForEachInVectorTerm( tp.m_predicates, [&]( auto&& p )
{
auto predVal = *ValueFromEIR( p );
if( auto zv = BuildZ3ExprFromValue( b, predVal ) )
func( zv->expr, predVal.locationId() );
return true;
} );
if( prevValPH )
|
| ︙ | ︙ |
Changes to bs/verify/storage.cpp.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
{
auto val = LoadFromAddress( b, addr.baseAddr() );
if( !val )
return nullopt;
for( auto&& index : addr.path() )
{
| | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
{
auto val = LoadFromAddress( b, addr.baseAddr() );
if( !val )
return nullopt;
for( auto&& index : addr.path() )
{
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( val->type ) );
if( !tinfo )
return nullopt;
// The only aggregate type that we handle for now are tuples.
// TODO: arrays
auto elemType = GetTupleTypeElement( val->type, index );
auto elemExpr = tinfo->proj( val->expr, index );
val = Z3Val{ move( elemExpr ), *ValueFromEIR( elemType ) };
}
return val;
}
optional< Z3Val > LoadFromAddress( Builder& b, const BaseAddress& baseAddr )
{
|
| ︙ | ︙ | |||
48 49 50 51 52 53 54 |
optional< Z3Val > LoadFromAddress( Builder& b, const cir::VarBaseAddr& va )
{
return b.retrieveVar( va.index );
}
optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const AddressPath& path, uint32_t index, Z3Val&& valToStore )
{
| | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
optional< Z3Val > LoadFromAddress( Builder& b, const cir::VarBaseAddr& va )
{
return b.retrieveVar( va.index );
}
optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const AddressPath& path, uint32_t index, Z3Val&& valToStore )
{
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( aggregate.type ) );
if( !tinfo )
return nullopt;
// The only aggregate type that we handle for now are tuples.
// TODO: arrays
auto elemCount = TupleTypeSize( aggregate.type );
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
if( i == elemIndex )
{
// If we didn't reach the end of the path yet, recurse.
// Otherwise, it means we finally reached the nested member that we wanted to modify,
// so push the new value.
if( index < ( path.size() - 1 ) )
{
| | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
if( i == elemIndex )
{
// If we didn't reach the end of the path yet, recurse.
// Otherwise, it means we finally reached the nested member that we wanted to modify,
// so push the new value.
if( index < ( path.size() - 1 ) )
{
auto newElem = ModifyAggregate( b, Z3Val{ move( elemExpr ), *ValueFromEIR( elemType ) }, path, ++index, move( valToStore ) );
if( !newElem )
return nullopt;
args.push_back( move( *newElem ) );
}
else
args.push_back( valToStore.expr );
|
| ︙ | ︙ |
Changes to bs/verify/terminator.cpp.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 |
const auto& postConds = m_func->type().verifInfos()->postConditions();
bool success = true;
ForEachInVectorTerm( postConds, [&]( auto&& t )
{
// Don't do any error handling here, it should already have been taken care of
// by the condition verifier.
| | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
const auto& postConds = m_func->type().verifInfos()->postConditions();
bool success = true;
ForEachInVectorTerm( postConds, [&]( auto&& t )
{
// Don't do any error handling here, it should already have been taken care of
// by the condition verifier.
auto cond = *ValueFromEIR( t );
if( auto zv = BuildZ3ExprFromValue( cb, cond ) )
{
bool succ = false;
// TODO: we don't have a useful location here in the case of a return from a void func.
// we'll have to add it to the ret statement. The case can only happen when checking post conditions
|
| ︙ | ︙ |
Changes to bs/verify/type.cpp.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
return tinfo;
}
optional< TypeInfo > TypeCache::CreateTypeInfoForBasicType( const sema::Context& c, const Value& typeVal )
{
// Handle all non-aggregate types (bool, signed int, unsigned int, floats) directly.
// TODO: some are missing and will be dealt with later on.
| | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
return tinfo;
}
optional< TypeInfo > TypeCache::CreateTypeInfoForBasicType( const sema::Context& c, const Value& typeVal )
{
// Handle all non-aggregate types (bool, signed int, unsigned int, floats) directly.
// TODO: some are missing and will be dealt with later on.
if( ValueToEIR( typeVal ) == GetValueType< bool >() )
{
return TypeInfo { GetZ3Context().bool_sort(),
[]( auto&& b )
{
return GetZ3Context().bool_const( format( "u{}", b.newUniqueId() ).c_str() );
},
[]( auto&& b, auto&& val )
|
| ︙ | ︙ | |||
95 96 97 98 99 100 101 |
}
return nullopt;
}
optional< TypeInfo > TypeCache::CreateTypeInfo( const sema::Context& c, const Term& type )
{
| | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
}
return nullopt;
}
optional< TypeInfo > TypeCache::CreateTypeInfo( const sema::Context& c, const Term& type )
{
auto typeVal = *ValueFromEIR( type );
auto tinfo = CreateTypeInfoForBasicType( c, typeVal );
if( tinfo )
return tinfo;
// The only non aggregate type that we handle at the moment are tuples.
// Other higher level types such as structs and classes need to be lowered
|
| ︙ | ︙ |
Changes to bs/verify/value.cpp.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
return nullopt;
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), loweredVal->type() );
if( !tinfo )
return nullopt;
auto zexpr = tinfo->build( b, *loweredVal );
| | | | | 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 |
return nullopt;
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), loweredVal->type() );
if( !tinfo )
return nullopt;
auto zexpr = tinfo->build( b, *loweredVal );
return Z3Val { move( zexpr ), *ValueFromEIR( val.type() ) };
}
optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Value& type, const string& name )
{
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( type ) );
if( !tinfo )
return nullopt;
assert( tinfo->sort );
return Z3Val { GetZ3Context().constant( name.c_str(), *tinfo->sort ), type };
}
optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Term& type, const string& name )
{
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), type );
if( !tinfo )
return nullopt;
assert( tinfo->sort );
return Z3Val { GetZ3Context().constant( name.c_str(), *tinfo->sort ), *ValueFromEIR( type ) };
}
z3::expr GetAsBitVec( const z3::expr& expr, const Value& type )
{
if( expr.is_bv() )
return expr;
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
return nullopt;
auto rhs = BuildZ3ExprFromValue( b, instr.rhs() );
if( !rhs )
return nullopt;
if( lhs->expr.get_sort().sort_kind() == rhs->expr.get_sort().sort_kind() )
| | | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
return nullopt;
auto rhs = BuildZ3ExprFromValue( b, instr.rhs() );
if( !rhs )
return nullopt;
if( lhs->expr.get_sort().sort_kind() == rhs->expr.get_sort().sort_kind() )
return Z3Val{ func( lhs->expr, rhs->expr, lhs->type ), *ValueFromEIR( GetValueType< bool >() ) };
// If we are trying to do an operation on a mix of bitvec and int,
// convert the int to a bitvec first.
if( lhs->expr.is_bv() )
{
assert( rhs->expr.is_int() );
return Z3Val{ func( lhs->expr, GetAsBitVec( *rhs ), lhs->type ), *ValueFromEIR( GetValueType< bool >() ) };
}
else
{
assert( lhs->expr.is_int() );
return Z3Val{ func( GetAsBitVec( *lhs ), rhs->expr, lhs->type ), *ValueFromEIR( GetValueType< bool >() ) };
}
return nullopt;
}
template< typename T >
optional< Z3Val > BuildZ3Op( Builder& b, const T& instr )
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 |
return zv;
return BuildZ3ConstantFromType( b, instr.type(), format( "v{}", instr.index() ) );
}
optional< Z3Val > BuildZ3Op( Builder& b, const AllocVar& instr )
{
| | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
return zv;
return BuildZ3ConstantFromType( b, instr.type(), format( "v{}", instr.index() ) );
}
optional< Z3Val > BuildZ3Op( Builder& b, const AllocVar& instr )
{
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( instr.type() ) );
if( !tinfo )
return nullopt;
b.setVar( instr.index(), Z3Val{ tinfo->undefined( b ), instr.type() } );
return nullopt;
}
|
| ︙ | ︙ | |||
378 379 380 381 382 383 384 |
return nullopt;
}
optional< Z3Val > BuildZ3Op( Builder& b, const Placeholder& instr )
{
const auto* expr = b.retrievePlaceholder( instr.name() );
if( expr )
| | | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
return nullopt;
}
optional< Z3Val > BuildZ3Op( Builder& b, const Placeholder& instr )
{
const auto* expr = b.retrievePlaceholder( instr.name() );
if( expr )
return Z3Val{ *expr, *ValueFromEIR( instr.type() ) };
return BuildZ3ConstantFromType( b, instr.type(), format( "p{}", instr.name() ) );
}
optional< Z3Val > BuildZ3Op( Builder& b, const cir::Instruction& instr )
{
return visit( [&]( auto&& e )
|
| ︙ | ︙ |