Goose  Check-in [3d8b581261]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:
  • Fixed some bugs related to dropping values.
  • Implemented local variable declarations with default initialization.
  • codegen: Fixed allocas not properly grouped up at the start of the first basic block of functions.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 3d8b581261aa99e94896961cd2ce5458d672d271053cb0b21d4690b80085bfd5
User & Date: achavasse 2019-08-15 22:37:33.645
Context
2019-08-15
22:58
Implemented InitializeLocalVar() for the bool, ct_int and ct_string types. check-in: 6d69e387ac user: achavasse tags: trunk
22:37
  • Fixed some bugs related to dropping values.
  • Implemented local variable declarations with default initialization.
  • codegen: Fixed allocas not properly grouped up at the start of the first basic block of functions.
check-in: 3d8b581261 user: achavasse tags: trunk
01:54
Fixed a couple of typos. check-in: 1e6e7c928d user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/extpoints.cpp.
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
                    return;

                auto& p = *Parser::GetCurrentParser();
                auto bb = p.currentBB();
                bb->emplace_back( move( *v.llr() ) );
            } );

        using AnyLocVarType =
            CustomPattern< LocalVar, LocalVar::PatternTypeT >;

        RegisterBuiltinFunc< Intrinsic< void ( AnyLocVarType ) > >( e, e.extDropValue(),
            []( const Value& v )
            {
                return;
            } );






















        using IntegerLocVarType =
            CustomPattern< LocalVar, LocalVar::Pattern< IntegerType::Pattern > >;
        using IntegerType = CustomPattern< IntegerType, IntegerType::Pattern >;

        RegisterBuiltinFunc< Intrinsic< Value ( IntegerLocVarType, IntegerType ) > >( e, e.extInitializeLocalVar(),
            []( const Value& lv, const Value& initVal )
            {
                auto locVar = *FromValue< LocalVar >( lv );
                return BuildComputedValue( GetValueType< void >(),
                    SetVar( initVal, locVar.cfgId(), locVar.index() ) );
            } );
















    }
}







<
|






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


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
                    return;

                auto& p = *Parser::GetCurrentParser();
                auto bb = p.currentBB();
                bb->emplace_back( move( *v.llr() ) );
            } );


        using AnyLocVarType = CustomPattern< LocalVar, LocalVar::PatternTypeT >;

        RegisterBuiltinFunc< Intrinsic< void ( AnyLocVarType ) > >( e, e.extDropValue(),
            []( const Value& v )
            {
                return;
            } );

        using AnyDeclType = CustomPattern< Decl, Decl::PatternTypeT >;

        // DropValue for Decls: declare a local variable with default initialization.
        // TODO: if the invocation to InitializeValue fails, we should have a way to
        // replace the generic "function arguments mismatch" error message with something
        //  more specific: "can't default-initialize a variable of type XXX"
        RegisterBuiltinFunc< Intrinsic< void ( AnyDeclType ) > >( e, e.extDropValue(),
            []( const Value& v )
            {
                auto& p = *Parser::GetCurrentParser();

                if( !p.cfg() )
                {
                    DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "variable declarations are not allowed here." );
                    return PoisonValue();
                }

                auto decl = *FromValue< Decl >( v );
                return DeclareLocalVar( p, decl.type(), decl.name(), nullopt );
            } );

        using IntegerLocVarType =
            CustomPattern< LocalVar, LocalVar::Pattern< IntegerType::Pattern > >;
        using IntegerType = CustomPattern< IntegerType, IntegerType::Pattern >;

        RegisterBuiltinFunc< Intrinsic< Value ( IntegerLocVarType, IntegerType ) > >( e, e.extInitializeLocalVar(),
            []( const Value& lv, const Value& initVal )
            {
                auto locVar = *FromValue< LocalVar >( lv );
                return BuildComputedValue( GetValueType< void >(),
                    SetVar( initVal, locVar.cfgId(), locVar.index() ) );
            } );

        // Default initialization for integer vars
        RegisterBuiltinFunc< Intrinsic< Value ( IntegerLocVarType ) > >( e, e.extInitializeLocalVar(),
            []( const Value& lv )
            {
                auto locVar = *FromValue< LocalVar >( lv );

                auto opTypeVal = *ValueFromIRExpr( locVar.type() );
                auto opType = *FromValue< IntegerType >( opTypeVal );
                auto initVal = BuildComputedValue( locVar.type(),
                    LoadConstInt( static_cast< llvm::IntegerType* >( GetLLVMType( opTypeVal ) ),
                    APSInt( opType.m_numBits, !opType.m_signed ) ) );

                return BuildComputedValue( GetValueType< void >(),
                    SetVar( move( initVal ), locVar.cfgId(), locVar.index() ) );
            } );
    }
}
Changes to bs/builtins/operators/assignment.cpp.
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
            RightAssInfixOp( "operator_assign"_sid, precedence::AssignmentOp,
                // Assignment with a decl of type $T to the left and a value of type $T to the right:
                // Local variable declaration and initialization.
                ForTypes< CustomPattern< Decl, Decl::PatternTypeT >,
                    CustomPattern< Value, ValuePatternT > >(
                []( auto&& lhs, auto&& rhs ) -> Value
                {
                    auto decl = *FromValue< Decl >( lhs );

                    auto& p = *Parser::GetCurrentParser();
                    auto bb = p.currentBB();

                    auto cfgId = p.cfg()->uniqueId();
                    auto index = p.cfg()->getNewTemporaryIndex();

                    LocalVar lv( rhs.type(), cfgId, index );

                    bb->emplace_back( AllocVar( *ValueFromIRExpr( decl.type() ), cfgId, index ) );

                    p.pushValue( InvokeOverloadSet( p.resolver()->context(),
                        p.resolver()->context().env()->extInitializeLocalVar(),
                        MakeTuple( ToValue( lv ), rhs ) ) );

                    // Store the new local var in the env
                    auto locVar = ToValue( lv );
                    auto identity = AppendToVectorTerm( p.resolver()->context().identity(),
                        TERM( decl.name() ) );

                    p.resolver()->context().env()->storeValue( identity, ANYTERM( _ ),
                        ValueToIRExpr( locVar ) );

                    p.resolver()->clearLookAheadCache();
                    return locVar;
                } ),

                // Assignation of a local var.
                // We define overloads for every runtime builtin types and directly perform the assignation.
                // TODO: we also need a generic overload that invokes an assignation extension point,
                // for custom types to implement their own. But we need to implement mutable references
                // first.







<
<

<

|
<
|
<
|
<
|
<
<
<
|
<
<
<
<

<
<
|
<
|







28
29
30
31
32
33
34


35

36
37

38

39

40



41




42


43

44
45
46
47
48
49
50
51
            RightAssInfixOp( "operator_assign"_sid, precedence::AssignmentOp,
                // Assignment with a decl of type $T to the left and a value of type $T to the right:
                // Local variable declaration and initialization.
                ForTypes< CustomPattern< Decl, Decl::PatternTypeT >,
                    CustomPattern< Value, ValuePatternT > >(
                []( auto&& lhs, auto&& rhs ) -> Value
                {


                    auto& p = *Parser::GetCurrentParser();


                    if( !p.cfg() )

                    {

                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "variable declarations are not allowed here." );

                        return PoisonValue();



                    }







                    auto decl = *FromValue< Decl >( lhs );

                    return DeclareLocalVar( p, decl.type(), decl.name(), rhs );
                } ),

                // Assignation of a local var.
                // We define overloads for every runtime builtin types and directly perform the assignation.
                // TODO: we also need a generic overload that invokes an assignation extension point,
                // for custom types to implement their own. But we need to implement mutable references
                // first.
Changes to bs/builtins/statements/hif.cpp.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
    void SetupHIfStmt( Env& e )
    {
        auto handleHIf = []( Parser& p, uint32_t locationId, uint32_t prec )
        {
            auto& dm = DiagnosticsManager::GetInstance();

            auto pPrecBB = p.currentBB();

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::IfStmt ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the #if statement1.", 0 );
                return false;
            }








<
<







11
12
13
14
15
16
17


18
19
20
21
22
23
24
{
    void SetupHIfStmt( Env& e )
    {
        auto handleHIf = []( Parser& p, uint32_t locationId, uint32_t prec )
        {
            auto& dm = DiagnosticsManager::GetInstance();



            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::IfStmt ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the #if statement1.", 0 );
                return false;
            }

Changes to bs/builtins/statements/if.cpp.
10
11
12
13
14
15
16






17
18
19
20
21
22
23
namespace empathy::builtins
{
    void SetupIfStmt( Env& e )
    {
        auto handleIf = []( Parser& p, uint32_t locationId, uint32_t prec )
        {
            auto& dm = DiagnosticsManager::GetInstance();







            auto pPrecBB = p.currentBB();

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::IfStmt ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the if statement.", 0 );







>
>
>
>
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace empathy::builtins
{
    void SetupIfStmt( Env& e )
    {
        auto handleIf = []( Parser& p, uint32_t locationId, uint32_t prec )
        {
            auto& dm = DiagnosticsManager::GetInstance();

            if( p.isInParenExpr() )
            {
                dm.emitSyntaxErrorMessage( locationId, "the if statement is not allowed here.", 0 );
                return false;
            }

            auto pPrecBB = p.currentBB();

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::IfStmt ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the if statement.", 0 );
Changes to bs/builtins/statements/return.cpp.
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
{
    void SetupReturnStmt( Env& e )
    {
        auto handleReturn = []( Parser& p, uint32_t locationId, uint32_t prec )
        {
            auto& dm = DiagnosticsManager::GetInstance();

            const auto& context = p.resolver()->context();

            if( !context.returnType() )
            {
                // TODO: actually create nested contexts without return types for sub-expressions
                // in which return doesnt make sense, so that this error message is actually triggered.
                dm.emitSyntaxErrorMessage( locationId, "the return statement is not allowed here.", 0 );
                return false;
            }



            if( context.returnType() == GetValueType< void >() )
            {
                p.emitTerminator( llr::Ret() );
                return true;
            }

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::ReturnStmt + 1 ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                p.emitTerminator( llr::Ret( PoisonValue() ) );
                return false;
            }

            auto retVal = np.peekLastValue();
            if( !retVal )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                p.emitTerminator( llr::Ret( PoisonValue() ) );
                return false;
            }








<
|
<

<
<



>
>















|







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
{
    void SetupReturnStmt( Env& e )
    {
        auto handleReturn = []( Parser& p, uint32_t locationId, uint32_t prec )
        {
            auto& dm = DiagnosticsManager::GetInstance();


            if( p.isInParenExpr() )

            {


                dm.emitSyntaxErrorMessage( locationId, "the return statement is not allowed here.", 0 );
                return false;
            }

            const auto& context = p.resolver()->context();

            if( context.returnType() == GetValueType< void >() )
            {
                p.emitTerminator( llr::Ret() );
                return true;
            }

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::ReturnStmt + 1 ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                p.emitTerminator( llr::Ret( PoisonValue() ) );
                return false;
            }

            auto retVal = np.popValue();
            if( !retVal )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                p.emitTerminator( llr::Ret( PoisonValue() ) );
                return false;
            }

Changes to bs/builtins/statements/using.cpp.
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
                        dm.emitErrorMessage( loc, "invalid expression." );
                        content = ValueToIRExpr( PoisonValue() );
                        result = get< Term >( content );
                        bInUse = false;
                        return Env::Status::Success;
                    }

                    auto result = p.peekLastValue();
                    if( !result )
                    {
                        dm.emitErrorMessage( loc, "invalid expression." );
                        result = PoisonValue();
                    }

                    if( !result->isConstant() )







|







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
                        dm.emitErrorMessage( loc, "invalid expression." );
                        content = ValueToIRExpr( PoisonValue() );
                        result = get< Term >( content );
                        bInUse = false;
                        return Env::Status::Success;
                    }

                    auto result = p.popValue();
                    if( !result )
                    {
                        dm.emitErrorMessage( loc, "invalid expression." );
                        result = PoisonValue();
                    }

                    if( !result->isConstant() )
Changes to bs/builtins/types/localvar/localvar.cpp.
1

2
3


4
5
6
7
8
9
10
11

































12
13
14
15
16
17
18
#include "builtins/builtins.h"


using namespace empathy::builtins;



namespace empathy::builtins
{
    const Term& LocalVar::PatternTypeT::GetPattern()
    {
        static auto pattern = GetValueType< LocalVar >( MkHole( "T"_sid ) );
        return pattern;
    }

































}

namespace empathy::ir
{
    const Term& Bridge< LocalVarType >::Type()
    {
        return TypeType();

>


>
>








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace empathy::builtins;
using namespace empathy::llr;
using namespace empathy::parse;

namespace empathy::builtins
{
    const Term& LocalVar::PatternTypeT::GetPattern()
    {
        static auto pattern = GetValueType< LocalVar >( MkHole( "T"_sid ) );
        return pattern;
    }

    Value DeclareLocalVar( Parser& p, const Term& type, StringId name, const optional< Value >& initializer )
    {
        auto cfgId = p.cfg()->uniqueId();
        auto index = p.cfg()->getNewTemporaryIndex();

        LocalVar lv( type, cfgId, index );

        auto bb = p.currentBB();
        bb->emplace_back( AllocVar( *ValueFromIRExpr( type ), cfgId, index ) );

        if( initializer )
        {
            p.pushValue( InvokeOverloadSet( p.resolver()->context(),
                p.resolver()->context().env()->extInitializeLocalVar(),
                MakeTuple( ToValue( lv ), *initializer ) ) );
        }
        else
        {
            p.pushValue( InvokeOverloadSet( p.resolver()->context(),
                p.resolver()->context().env()->extInitializeLocalVar(),
                MakeTuple( ToValue( lv ) ) ) );
        }

        auto locVar = ToValue( lv );
        auto identity = AppendToVectorTerm( p.resolver()->context().identity(), name );

        p.resolver()->context().env()->storeValue( identity, ANYTERM( _ ),
            ValueToIRExpr( locVar ) );

        p.resolver()->clearLookAheadCache();
        return locVar;
    }
}

namespace empathy::ir
{
    const Term& Bridge< LocalVarType >::Type()
    {
        return TypeType();
Changes to bs/builtins/types/localvar/localvar.h.
1
2





3
4
5
6


7
8
9
10
11
12
13
#ifndef EMPATHY_BUILTINS_TYPES_LOCALVAR_H
#define EMPATHY_BUILTINS_TYPES_LOCALVAR_H






namespace empathy::builtins
{
    void SetupLocalVarUnification( Env& e );



    class LocalVarType
    {
        public:
            template< typename T >
            LocalVarType( T&& type ) :
                m_type( forward< T >( type ) )


>
>
>
>
>




>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef EMPATHY_BUILTINS_TYPES_LOCALVAR_H
#define EMPATHY_BUILTINS_TYPES_LOCALVAR_H

namespace empathy::parse
{
    class Parser;
}

namespace empathy::builtins
{
    void SetupLocalVarUnification( Env& e );

    Value DeclareLocalVar( parse::Parser& p, const Term& type, StringId name, const optional< Value >& initializer );

    class LocalVarType
    {
        public:
            template< typename T >
            LocalVarType( T&& type ) :
                m_type( forward< T >( type ) )
Changes to bs/codegen/func.cpp.
52
53
54
55
56
57
58

59
60
61
62
63

64

65
66
67
68
69
70
71
72
73
    Infos inf( c );

    // Generate allocas and stores for the args
    auto pEntryBB = func.llr()->body()->entryBB();
    if( !pEntryBB->llvmBB() )
        pEntryBB->setLLVMBB( llvm::BasicBlock::Create( GetLLVMContext(), "", pllvmFunc ) );


    m_llvmBuilder.SetInsertPoint( pEntryBB->llvmBB() );

    llvm::SmallVector< NullInit< llvm::Value* >, 8 > args;

    for( auto&& arg : pllvmFunc->args() )

        args.push_back( m_llvmBuilder.CreateAlloca( arg.getType() ) );


    inf.localInsertPoint = m_llvmBuilder.saveIP();

    size_t i = 0;
    for( auto&& arg : pllvmFunc->args() )
        m_llvmBuilder.CreateStore( &arg, args[i++] );

    inf.temporaries->setVec( 0, move( args ) );








>





>
|
>
|
<







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
    Infos inf( c );

    // Generate allocas and stores for the args
    auto pEntryBB = func.llr()->body()->entryBB();
    if( !pEntryBB->llvmBB() )
        pEntryBB->setLLVMBB( llvm::BasicBlock::Create( GetLLVMContext(), "", pllvmFunc ) );

    inf.allocaBasicBlock = pEntryBB->llvmBB();
    m_llvmBuilder.SetInsertPoint( pEntryBB->llvmBB() );

    llvm::SmallVector< NullInit< llvm::Value* >, 8 > args;

    for( auto&& arg : pllvmFunc->args() )
    {
        inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( arg.getType() );
        args.push_back( inf.lastEmittedAlloca );
    }


    size_t i = 0;
    for( auto&& arg : pllvmFunc->args() )
        m_llvmBuilder.CreateStore( &arg, args[i++] );

    inf.temporaries->setVec( 0, move( args ) );

Changes to bs/codegen/instructions.cpp.
103
104
105
106
107
108
109
110




111
112
113
114
115
116
117
118
119
120
121
122
123
124
llvm::Value* Module::buildInstruction( Infos& inf, const llr::AllocVar& av )
{
    auto type = LowerType( inf.context, av.type() );
    if( !type )
        return nullptr;

    llvm::IRBuilderBase::InsertPointGuard g( m_llvmBuilder );
    m_llvmBuilder.restoreIP( inf.localInsertPoint );





    auto pAlloca = m_llvmBuilder.CreateAlloca( GetLLVMType( *type ) );
    createTemporary( inf, av.cfgId(), av.index(), pAlloca );

    inf.localInsertPoint = m_llvmBuilder.saveIP();

    return pAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::GetVar& gv )
{
    return m_llvmBuilder.CreateLoad( *inf.temporaries->get( gv.cfgId(), gv.index() ) );
}








|
>
>
>
>

|
|

<
|
<







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

119

120
121
122
123
124
125
126
llvm::Value* Module::buildInstruction( Infos& inf, const llr::AllocVar& av )
{
    auto type = LowerType( inf.context, av.type() );
    if( !type )
        return nullptr;

    llvm::IRBuilderBase::InsertPointGuard g( m_llvmBuilder );

    if( inf.lastEmittedAlloca && inf.lastEmittedAlloca->getNextNode() )
        m_llvmBuilder.SetInsertPoint( inf.lastEmittedAlloca->getNextNode() );
    else
        m_llvmBuilder.SetInsertPoint( inf.allocaBasicBlock, inf.allocaBasicBlock->begin() );

    inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( GetLLVMType( *type ) );
    createTemporary( inf, av.cfgId(), av.index(), inf.lastEmittedAlloca );


    return inf.lastEmittedAlloca;

}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::GetVar& gv )
{
    return m_llvmBuilder.CreateLoad( *inf.temporaries->get( gv.cfgId(), gv.index() ) );
}

Changes to bs/codegen/module.h.
30
31
32
33
34
35
36
37


38
39
40
41
42
43
44

        private:
            struct Infos
            {
                Infos( const Context& c ) : context( c ) {}
                const Context& context;
                llvm::SmallVector< llvm::Value*, 8 > m_locals;
                llvm::IRBuilderBase::InsertPoint localInsertPoint;



                using storage_type = llr::TempStorage< NullInit< llvm::Value* > >;
                ptr< storage_type > temporaries = make_shared< storage_type >();

                bool inlining = false;
                llvm::Value* inlineResult = nullptr;
            };







|
>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

        private:
            struct Infos
            {
                Infos( const Context& c ) : context( c ) {}
                const Context& context;
                llvm::SmallVector< llvm::Value*, 8 > m_locals;

                llvm::BasicBlock* allocaBasicBlock = nullptr;
                llvm::AllocaInst* lastEmittedAlloca = nullptr;

                using storage_type = llr::TempStorage< NullInit< llvm::Value* > >;
                ptr< storage_type > temporaries = make_shared< storage_type >();

                bool inlining = false;
                llvm::Value* inlineResult = nullptr;
            };
Changes to bs/execute/vm.cpp.
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
        return PoisonValue();
    return *pVal;
}

optional< Value > VM::execute( const llr::GetVar& gv )
{
    const auto* pVal = m_frame.getTemporary( gv.cfgId(), gv.index() );
    assert( pVal );
    if( !pVal )
        return PoisonValue();

    auto result = Evaluate( **pVal, *this );
    if( !result.isConstant() )
        return PoisonValue();








<







165
166
167
168
169
170
171

172
173
174
175
176
177
178
        return PoisonValue();
    return *pVal;
}

optional< Value > VM::execute( const llr::GetVar& gv )
{
    const auto* pVal = m_frame.getTemporary( gv.cfgId(), gv.index() );

    if( !pVal )
        return PoisonValue();

    auto result = Evaluate( **pVal, *this );
    if( !result.isConstant() )
        return PoisonValue();

Changes to bs/parse/blocks.cpp.
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
{
    // Create a nested verbosity context to restrict the scope of
    // error silencing caused by syntax errors to the block.
    VerbosityContext vc( Verbosity::Normal );

    auto tok = m_resolver->consume();

    Parser p( resolver(), Delimiter::OpenParen );
    p.parseExpression();
    auto content = p.peekLastValue();

    auto next = m_resolver->consume();
    if( !next )
    {
        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
            resolver()->getCurrentLocation(), "')' expected.", 0 );
        return PoisonValue();







|

|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
{
    // Create a nested verbosity context to restrict the scope of
    // error silencing caused by syntax errors to the block.
    VerbosityContext vc( Verbosity::Normal );

    auto tok = m_resolver->consume();

    auto p = makeNestedParser( Delimiter::OpenParen );
    p.parseExpression();
    auto content = p.popValue();

    auto next = m_resolver->consume();
    if( !next )
    {
        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
            resolver()->getCurrentLocation(), "')' expected.", 0 );
        return PoisonValue();
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
{
    // Create a nested verbosity context to restrict the scope of
    // error silencing caused by syntax errors to the block.
    VerbosityContext vc( Verbosity::Normal );

    m_resolver->consume();

    Parser p( resolver(), Delimiter::OpenBrace );

    p.setCFG( cfg() );
    p.setCurrentBB( currentBB() );

    p.parseSequence();

    auto next = m_resolver->consumeUnresolved();
    if( !next )
    {
        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
            resolver()->getCurrentLocation(), "'}' expected.", 0 );







|
<
<
<
<







215
216
217
218
219
220
221
222




223
224
225
226
227
228
229
{
    // Create a nested verbosity context to restrict the scope of
    // error silencing caused by syntax errors to the block.
    VerbosityContext vc( Verbosity::Normal );

    m_resolver->consume();

    auto p = makeNestedParser( Delimiter::OpenBrace );




    p.parseSequence();

    auto next = m_resolver->consumeUnresolved();
    if( !next )
    {
        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
            resolver()->getCurrentLocation(), "'}' expected.", 0 );
Changes to bs/parse/parser.cpp.
12
13
14
15
16
17
18








19
20
21
22


23

24
25
26
27
28
29
30
{
    Parser p( m_resolver );
    p.m_introDelimiter = m_introDelimiter;
    p.setCFG( cfg() );
    p.setCurrentBB( currentBB() );
    return p;
}









void Parser::parseSequence()
{
    while( parseExpression( 0 ) )


        m_resolver->consumeNewLines();


    flushValue();
}

bool Parser::parseExpression( uint32_t precedence )
{
    auto next = m_resolver->lookAhead();







>
>
>
>
>
>
>
>




>
>

>







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
{
    Parser p( m_resolver );
    p.m_introDelimiter = m_introDelimiter;
    p.setCFG( cfg() );
    p.setCurrentBB( currentBB() );
    return p;
}

Parser Parser::makeNestedParser( Delimiter introDelimiter )
{
    Parser p( m_resolver, introDelimiter );
    p.setCFG( cfg() );
    p.setCurrentBB( currentBB() );
    return p;
}

void Parser::parseSequence()
{
    while( parseExpression( 0 ) )
    {
        flushValue();
        m_resolver->consumeNewLines();
    }

    flushValue();
}

bool Parser::parseExpression( uint32_t precedence )
{
    auto next = m_resolver->lookAhead();
53
54
55
56
57
58
59
60
61
62



63
64
65

66
67
68
69
70
71
72
73
74
75
76

void Parser::flushValue()
{
    // Flush the pending value, by invoking the DropValue
    // extension point, where an overload will decide
    // of the value's fate (or possibly emit an error
    // if that value wasn't allowed to be discarded).
    if( !m_lastValue )
        return;




    if( m_lastValue->isPoison() )
        return;


    InvokeOverloadSet( resolver()->context(), resolver()->context().env()->extDropValue(),
        MakeTuple( *m_lastValue ) );

    m_lastValue = nullopt;
}

optional< uint32_t > Parser::getPrecedence( const Term& t )
{
    return visit( [&]( auto&& content )
    {
        return getPrecedence( t, content );







|
<
|
>
>
>
|
|

>
|
|
|
<







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

void Parser::flushValue()
{
    // Flush the pending value, by invoking the DropValue
    // extension point, where an overload will decide
    // of the value's fate (or possibly emit an error
    // if that value wasn't allowed to be discarded).
    while( m_lastValue )

    {
        auto val = move( *m_lastValue );
        m_lastValue = nullopt;

        if( val.isPoison() )
            return;

        DiagnosticsContext dc( val.locationId(), false );
        InvokeOverloadSet( resolver()->context(), resolver()->context().env()->extDropValue(),
            MakeTuple( val ) );
    }

}

optional< uint32_t > Parser::getPrecedence( const Term& t )
{
    return visit( [&]( auto&& content )
    {
        return getPrecedence( t, content );
Changes to bs/parse/parser.h.
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
            {
                m_pParentParser = ms_pCurrentParser;
                ms_pCurrentParser = this;
            }

            ~Parser()
            {

                ms_pCurrentParser = m_pParentParser;
            }

            // Static method to retrieve the current parser.
            // This is needed by intrinsic functions, specifically
            // those that implements the builtin operators: they can't receive
            // the parser as a parameter since they can be overloaded by normal
            // functions which can't manipulate compile-time data.
            // So they need a static method to retrieve it.
            static Parser* GetCurrentParser() { return ms_pCurrentParser; }

            // Build a parser for a nested parsing context that needs to share everything
            // except the current sequence and value.
            Parser makeNestedParser();


            const auto& resolver() const { return m_resolver; }
            auto& resolver() { return m_resolver; }

            void parseSequence();
            bool parseExpression( uint32_t precedence = 0 );
            void parsePostfixExpression( uint32_t precedence );







>














>







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
            {
                m_pParentParser = ms_pCurrentParser;
                ms_pCurrentParser = this;
            }

            ~Parser()
            {
                flushValue();
                ms_pCurrentParser = m_pParentParser;
            }

            // Static method to retrieve the current parser.
            // This is needed by intrinsic functions, specifically
            // those that implements the builtin operators: they can't receive
            // the parser as a parameter since they can be overloaded by normal
            // functions which can't manipulate compile-time data.
            // So they need a static method to retrieve it.
            static Parser* GetCurrentParser() { return ms_pCurrentParser; }

            // Build a parser for a nested parsing context that needs to share everything
            // except the current sequence and value.
            Parser makeNestedParser();
            Parser makeNestedParser( Delimiter introDelimiter );

            const auto& resolver() const { return m_resolver; }
            auto& resolver() { return m_resolver; }

            void parseSequence();
            bool parseExpression( uint32_t precedence = 0 );
            void parsePostfixExpression( uint32_t precedence );
Changes to bs/parse/rule-helpers.inl.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
                if( !np.parseExpression( precedence + 1 ) )
                {
                    DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                        "expected an expression.", 0 );
                    return false;
                }

                rightVal = np.peekLastValue();
                if( !rightVal )
                {
                    DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                        "expected an expression.", 0 );
                    return false;
                }
            }







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
                if( !np.parseExpression( precedence + 1 ) )
                {
                    DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                        "expected an expression.", 0 );
                    return false;
                }

                rightVal = np.popValue();
                if( !rightVal )
                {
                    DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                        "expected an expression.", 0 );
                    return false;
                }
            }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
                    if( !np.parseExpression( precedence + 1 ) )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }

                    rightVal = np.peekLastValue();
                    if( !rightVal )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }
                }







|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
                    if( !np.parseExpression( precedence + 1 ) )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }

                    rightVal = np.popValue();
                    if( !rightVal )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }
                }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
                    if( !np.parseExpression( precedence ) )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }

                    rightVal = np.peekLastValue();
                    if( !rightVal )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }
                }







|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
                    if( !np.parseExpression( precedence ) )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }

                    rightVal = np.popValue();
                    if( !rightVal )
                    {
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                            "expected an expression.", 0 );
                        return false;
                    }
                }
Changes to tests/noprelude/codegen/locvar.em.
1
2
3

4
5




6
7
8
9
10
using module = CGModuleCreate( "local var test" )

using entryPoint = uint(32) () {

    uint(32) lomarf = 219
    lomarf = 1337




    return lomarf
}

CGGenerateFunction( module, entryPoint, "main" )
CGModuleEmitLLVMIr( module, "tests/noprelude/codegen/locvar.ll" )


|
>


>
>
>
>





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using module = CGModuleCreate( "local var test" )

using entryPoint = uint(32) ( bool b ) {

    uint(32) lomarf = 219
    lomarf = 1337

    uint(32) laffo
    laffo = 654654

    return lomarf
}

CGGenerateFunction( module, entryPoint, "main" )
CGModuleEmitLLVMIr( module, "tests/noprelude/codegen/locvar.ll" )
Changes to tests/noprelude/codegen/locvar.ll.
1
2
3
4

5


6
7


8
9
10
; ModuleID = 'local var test'
source_filename = "local var test"

define i32 @main() {

  %1 = alloca i32


  store i32 219, i32* %1
  store i32 1337, i32* %1


  %2 = load i32, i32* %1
  ret i32 %2
}



|
>
|
>
>
|
|
>
>
|
|

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
; ModuleID = 'local var test'
source_filename = "local var test"

define i32 @main(i1 %0) {
  %2 = alloca i1
  %3 = alloca i32
  %4 = alloca i32
  store i1 %0, i1* %2
  store i32 219, i32* %3
  store i32 1337, i32* %3
  store i32 0, i32* %4
  store i32 654654, i32* %4
  %5 = load i32, i32* %3
  ret i32 %5
}
Changes to tests/noprelude/diagnostics/template-type-mismatch.em.
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
ExecuteFile( "tests/noprelude/helpers.em" )

//Print( typeName( 465464 ) )

ct_string higherPoly( ct_string( $T s ) $f )
{
    return strcat( strcat( $f(5), ", " ), $f( "blah" ) )
}

ct_string someFunc( $T x )
{
    return strcat( 219, typeName( $T ) )
}

ct_string someFunc( ct_string s )
{
    return strcat( "someFunc2: ", s )
}

//DiagnosticsTraceMode( true )

if !assert( higherPoly( someFunc ) == "someFunc1: int, someFunc2: blah", "higher order polymorphism test" )
    return 0

return 1


<
<















<
<




1
2


3
4
5
6
7
8
9
10
11
12
13
14
15
16
17


18
19
20
21
ExecuteFile( "tests/noprelude/helpers.em" )



ct_string higherPoly( ct_string( $T s ) $f )
{
    return strcat( strcat( $f(5), ", " ), $f( "blah" ) )
}

ct_string someFunc( $T x )
{
    return strcat( 219, typeName( $T ) )
}

ct_string someFunc( ct_string s )
{
    return strcat( "someFunc2: ", s )
}



if !assert( higherPoly( someFunc ) == "someFunc1: int, someFunc2: blah", "higher order polymorphism test" )
    return 0

return 1
Changes to tests/noprelude/diagnostics/template-type-mismatch.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
tests/noprelude/diagnostics/template-type-mismatch.em:12:12: error: function arguments mismatch.
   12 |     return strcat( 219, typeName( $T ) )
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     ...
   10 | ct_string someFunc( $T x )
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~
      | In the template function declared here.
     ...
    7 |     return strcat( strcat( $f(5), ", " ), $f( "blah" ) )
      |                            ~~~~~
      |                         Called here.
     ...
    5 | ct_string higherPoly( ct_string( $T s ) $f )
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   In the template function declared here.
     ...
   22 | if !assert( higherPoly( someFunc ) == "someFunc1: int, someFunc2: blah", "higher order polymorphism test" )
      |             ~~~~~~~~~~~~~~~~~~~~~~
      |                  Called here.
|
|


|



|



|



|


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
tests/noprelude/diagnostics/template-type-mismatch.em:10:12: error: function arguments mismatch.
   10 |     return strcat( 219, typeName( $T ) )
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     ...
    8 | ct_string someFunc( $T x )
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~
      | In the template function declared here.
     ...
    5 |     return strcat( strcat( $f(5), ", " ), $f( "blah" ) )
      |                            ~~~~~
      |                         Called here.
     ...
    3 | ct_string higherPoly( ct_string( $T s ) $f )
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   In the template function declared here.
     ...
   18 | if !assert( higherPoly( someFunc ) == "someFunc1: int, someFunc2: blah", "higher order polymorphism test" )
      |             ~~~~~~~~~~~~~~~~~~~~~~
      |                  Called here.
Changes to tests/noprelude/execute/locvar.em.
8
9
10
11
12
13
14










15
16
if !assert( lomarf != 1337, "local variable test 2" )
    return 0

lomarf = 1337

if !assert( lomarf == 1337, "local variable test 3" )
    return 0











return 1







>
>
>
>
>
>
>
>
>
>


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
if !assert( lomarf != 1337, "local variable test 2" )
    return 0

lomarf = 1337

if !assert( lomarf == 1337, "local variable test 3" )
    return 0

uint(32) laffo

if !assert( laffo == 0, "local variable test 4" )
    return 0

laffo = 219

if !assert( laffo == 219, "local variable test 5" )
    return 0

return 1