Goose  Check-in [397f594186]

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

Overview
Comment:
  • Clean up the "default return value from top level file functions" stuff.
  • Standardize to a default return value of 0 for the top level file both in execution mode and in compilation mode.
  • Implemented a combined execution/compilation test for tuples in preparation for implementing tuple compilation. (not enabled yet)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 397f594186b2149627a0458f876107eb46f0fcc80ddfc1f021d4ca568fc4a393
User & Date: achavasse 2020-05-17 17:30:43.734
Context
2020-05-18
12:39
  • Renamed the LowerType extension point to LowerTypeForRuntime as we'll need a similar "LowerTypeForVerification" later on.
  • The function type case of LowerTypeForRuntime is no longer hardcoded in the c++ utility function of the same name but implemented as an overload of the extension point.
check-in: 8818ea1872 user: achavasse tags: trunk
2020-05-17
17:30
  • Clean up the "default return value from top level file functions" stuff.
  • Standardize to a default return value of 0 for the top level file both in execution mode and in compilation mode.
  • Implemented a combined execution/compilation test for tuples in preparation for implementing tuple compilation. (not enabled yet)
check-in: 397f594186 user: achavasse tags: trunk
2020-05-16
19:32
Repo: fix syntax highlighting with the latest trunk verison of fossil. check-in: 807a4f208b user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/api/compiler.cpp.
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

        RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "#Include"_sid,
            [pEnv]( auto&& c, const Value& fnameval ) -> Value
            {
                auto filename = *FromValue< string >( fnameval );
                auto identity = InjectDomainIntoIdentity( RootIdentity(), DomainCompileTime() );

                auto result = Compiler::LoadAndExecuteFile( pEnv.lock(), filename, identity, GetValueType< uint32_t >() );


                if( !result )
                    return ToValue< uint32_t >( 1 );

                return *result;
            } );

        RegisterBuiltinFunc< uint32_t ( string ) >( e, "ExecuteFile"_sid,
            [pEnv]( const string& filename ) -> Value
            {
                auto identity = InjectDomainIntoIdentity( RootIdentity(), DomainCompileTime() );

                auto result = Compiler::LoadAndExecuteFile( pEnv.lock(), filename, identity, GetValueType< uint32_t >() );


                if( !result )
                    return ToValue< uint32_t >( 1 );

                return *result;
            } );

        RegisterBuiltinFunc< Intrinsic< Value ( string, Value, Value ) > >( e, "#CompileFileToFunction"_sid,
            [pEnv]( auto&& c, const Value& filenameVal, const Value& rt, const Value& params ) -> Value
            {
                if( !filenameVal.isConstant() )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( filenameVal.locationId(),
                        "#CompileFileToFunction: the expression doesn't evaluate to a constant." );
                    return PoisonValue();
                }







|
>


|









|
>


|




|
|







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

        RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "#Include"_sid,
            [pEnv]( auto&& c, const Value& fnameval ) -> Value
            {
                auto filename = *FromValue< string >( fnameval );
                auto identity = InjectDomainIntoIdentity( RootIdentity(), DomainCompileTime() );

                auto result = Compiler::LoadAndExecuteFile( pEnv.lock(), filename, identity,
                    GetValueType< uint32_t >(), ToValue< uint32_t >( 0 ) );

                if( !result )
                    return ToValue< uint32_t >( 0 );

                return *result;
            } );

        RegisterBuiltinFunc< uint32_t ( string ) >( e, "ExecuteFile"_sid,
            [pEnv]( const string& filename ) -> Value
            {
                auto identity = InjectDomainIntoIdentity( RootIdentity(), DomainCompileTime() );

                auto result = Compiler::LoadAndExecuteFile( pEnv.lock(), filename, identity,
                    GetValueType< uint32_t >(), ToValue< uint32_t >( 0 ) );

                if( !result )
                    return ToValue< uint32_t >( 0 );

                return *result;
            } );

        RegisterBuiltinFunc< Intrinsic< Value ( string, Value, Value, Value ) > >( e, "#CompileFileToFunction"_sid,
            [pEnv]( auto&& c, const Value& filenameVal, const Value& rt, const Value& defReturnValue, const Value& params ) -> Value
            {
                if( !filenameVal.isConstant() )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( filenameVal.locationId(),
                        "#CompileFileToFunction: the expression doesn't evaluate to a constant." );
                    return PoisonValue();
                }
185
186
187
188
189
190
191
192

193
194
195
196
197
198
199
200
201
202
203
204
                c.env()->addVisibilityRule(
                    InjectDomainIntoIdentity( identity, ANYTERM( _ ) ),
                    InjectDomainIntoIdentity( funcIdentity, ANYTERM( _ ) ) );

                auto func = BuildFunc( localC, ftype, identity, params, nullptr, c );
                const auto& pFuncLLR = func.llr();

                auto cfg = Compiler::LoadAndParseFile( pEnv.lock(), filename,  funcIdentity, ftype.returnType() );


                if( !cfg )
                    return PoisonValue();

                if( cfg->isPoisoned() )
                    return PoisonValue();

                pFuncLLR->body() = cfg;
                return ToValue( func );
            } );
    }
}







|
>












187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
                c.env()->addVisibilityRule(
                    InjectDomainIntoIdentity( identity, ANYTERM( _ ) ),
                    InjectDomainIntoIdentity( funcIdentity, ANYTERM( _ ) ) );

                auto func = BuildFunc( localC, ftype, identity, params, nullptr, c );
                const auto& pFuncLLR = func.llr();

                auto cfg = Compiler::LoadAndParseFile( pEnv.lock(), filename, funcIdentity,
                    ftype.returnType(), defReturnValue );

                if( !cfg )
                    return PoisonValue();

                if( cfg->isPoisoned() )
                    return PoisonValue();

                pFuncLLR->body() = cfg;
                return ToValue( func );
            } );
    }
}
Changes to bs/builtins/statements/return.cpp.
74
75
76
77
78
79
80

81
82
83
84
85
86
87

                // Emit a terminator with a poison value to avoid the function compilation
                // code to complain about a missing return.
                cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( PoisonValue() ) );
                cb->poison();
                return true;
            }

            cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( get< Value >( converted ) ) );
            return true;
        };

        Rule r( handleReturn );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );







>







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

                // Emit a terminator with a poison value to avoid the function compilation
                // code to complain about a missing return.
                cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( PoisonValue() ) );
                cb->poison();
                return true;
            }

            cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( get< Value >( converted ) ) );
            return true;
        };

        Rule r( handleReturn );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
Changes to bs/builtins/types/func/compile.cpp.
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
                DiagnosticsManager::GetInstance().emitErrorMessage( r->currentLocation(),
                    "missing return statement in a function with non-void return type." );
                return false;
            }

            // Implicit return at the end of a void function:
            // Emit the cleanups, and the terminator.
            // TODO: at some point we'll want to check for reachability in the static verifyr,
            // and either emit the implicit return or declare the code unreachable depending on the result.
            // The reachability analysis will have to be done before contract validation, as the
            // calls to DestroyValue() may also have requirements to enforce, so we'll need to emit
            // the eventual implicit return first.
            p.flushValue();
            cb->destroyAllLiveValues( localContext );
            cb->emitTerminator( r->currentLocation(), llr::Ret() );







|







255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
                DiagnosticsManager::GetInstance().emitErrorMessage( r->currentLocation(),
                    "missing return statement in a function with non-void return type." );
                return false;
            }

            // Implicit return at the end of a void function:
            // Emit the cleanups, and the terminator.
            // TODO: at some point we'll want to check for reachability in the static verifier,
            // and either emit the implicit return or declare the code unreachable depending on the result.
            // The reachability analysis will have to be done before contract validation, as the
            // calls to DestroyValue() may also have requirements to enforce, so we'll need to emit
            // the eventual implicit return first.
            p.flushValue();
            cb->destroyAllLiveValues( localContext );
            cb->emitTerminator( r->currentLocation(), llr::Ret() );
Changes to bs/compile/compiler.cpp.
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
#include "llvm/Support/TargetSelect.h"

using namespace goose;
using namespace goose::util;
using namespace goose::ir;
using namespace goose::sema;
using namespace goose::diagnostics;


namespace goose::compile
{
    Compiler::Compiler( int argc, char** argv ) :
        m_pEnv( make_shared< sema::Env >() )
    {
        llvm::InitLLVM( argc, argv );

        string cmdArgs;
        for( size_t i = 1; i < static_cast< size_t >( argc ); ++i )
        {
            if( i > 1 )
                cmdArgs = cmdArgs + ' ';
            cmdArgs = cmdArgs + argv[i];
        }

        builtins::SetupBuiltins( *m_pEnv );

        builtins::RegisterBuiltinFunc< string() >( *m_pEnv, "Args"_sid,
            [cmdArgs]()
            {
                return cmdArgs;
            } );

        builtins::RegisterBuiltinFunc< void ( string ) >( *m_pEnv, "Print"_sid,
            []( const string& str )
            {
                cout << str;
            } );

        llvm::InitializeAllTargetInfos();
        llvm::InitializeAllTargets();
        llvm::InitializeAllTargetMCs();
        llvm::InitializeAllAsmParsers();
        llvm::InitializeAllAsmPrinters();
    }

    uint32_t Compiler::execute( const string& filename )
    {
        auto identity = sema::InjectDomainIntoIdentity( builtins::RootIdentity(), sema::DomainCompileTime() );

        auto result = LoadAndExecuteFile( m_pEnv, filename, identity, GetValueType< uint32_t >() );

        if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
            return 0;

        if( !result )
            return 1;

        if( result->isPoison() )
            return 0;

        return *FromValue< uint32_t >( *result );
    }

    optional< Value > Compiler::LoadAndExecuteFile( const ptr< Env >& e, const string& filename, const Term& identity, optional< Term > returnType )

    {
        auto cfg = LoadAndParseFile( e, filename, identity, returnType );
        if( !cfg )
            return PoisonValue();

        if( !cfg->entryBB()->canBeExecuted() )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( 0,
                format( "{}: can not be executed.", filename ) );
            return PoisonValue();
        }

        execute::VM vm;
        return vm.execute( cfg->entryBB() );
    }

    ptr< llr::CFG > Compiler::LoadAndParseFile( const ptr< Env >& e, const string& filename, const Term& identity, optional< Term > returnType )

    {




        ifstream sourcefile( filename.c_str() );
        if( !sourcefile.good() )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( 0,
                format( "can't open '{}'.", filename ) );
            return nullptr;
        }

        sema::Context c( e, identity, returnType );
        DiagnosticsContext dc( 0, true );
        VerbosityContext vc( Verbosity::Normal, true );







>
















|

|





|
















|


|


|


|




|
>

|














|
>

>
>
>
>



|







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
#include "llvm/Support/TargetSelect.h"

using namespace goose;
using namespace goose::util;
using namespace goose::ir;
using namespace goose::sema;
using namespace goose::diagnostics;
using namespace goose::builtins;

namespace goose::compile
{
    Compiler::Compiler( int argc, char** argv ) :
        m_pEnv( make_shared< sema::Env >() )
    {
        llvm::InitLLVM( argc, argv );

        string cmdArgs;
        for( size_t i = 1; i < static_cast< size_t >( argc ); ++i )
        {
            if( i > 1 )
                cmdArgs = cmdArgs + ' ';
            cmdArgs = cmdArgs + argv[i];
        }

        SetupBuiltins( *m_pEnv );

        RegisterBuiltinFunc< string() >( *m_pEnv, "Args"_sid,
            [cmdArgs]()
            {
                return cmdArgs;
            } );

        RegisterBuiltinFunc< void ( string ) >( *m_pEnv, "Print"_sid,
            []( const string& str )
            {
                cout << str;
            } );

        llvm::InitializeAllTargetInfos();
        llvm::InitializeAllTargets();
        llvm::InitializeAllTargetMCs();
        llvm::InitializeAllAsmParsers();
        llvm::InitializeAllAsmPrinters();
    }

    uint32_t Compiler::execute( const string& filename )
    {
        auto identity = sema::InjectDomainIntoIdentity( builtins::RootIdentity(), sema::DomainCompileTime() );

        auto result = LoadAndExecuteFile( m_pEnv, filename, identity, GetValueType< uint32_t >(), ToValue< uint32_t >( 1 ) );

        if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
            return 1;

        if( !result )
            return 0;

        if( result->isPoison() )
            return 1;

        return *FromValue< uint32_t >( *result );
    }

    optional< Value > Compiler::LoadAndExecuteFile( const ptr< Env >& e, const string& filename, const Term& identity,
        const Term& returnType, optional< Value > defRetVal )
    {
        auto cfg = LoadAndParseFile( e, filename, identity, returnType, defRetVal );
        if( !cfg )
            return PoisonValue();

        if( !cfg->entryBB()->canBeExecuted() )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( 0,
                format( "{}: can not be executed.", filename ) );
            return PoisonValue();
        }

        execute::VM vm;
        return vm.execute( cfg->entryBB() );
    }

    ptr< llr::CFG > Compiler::LoadAndParseFile( const ptr< Env >& e, const string& filename, const Term& identity,
        const Term& returnType, optional< Value > defRetVal )
    {
        auto& dm = DiagnosticsManager::GetInstance();

        assert( returnType == GetValueType< void >() || defRetVal );

        ifstream sourcefile( filename.c_str() );
        if( !sourcefile.good() )
        {
            dm.emitErrorMessage( 0,
                format( "can't open '{}'.", filename ) );
            return nullptr;
        }

        sema::Context c( e, identity, returnType );
        DiagnosticsContext dc( 0, true );
        VerbosityContext vc( Verbosity::Normal, true );
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
        p.parseSequence();

        if( cfg->isPoisoned() )
            return cfg;

        if( !r->eos() )
        {
            DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                r->currentLocation(), "syntax error." );

        }

        if( cfg->currentBB() && !cfg->currentBB()->terminator() )
        {
            // TODO implement a "default return value"
            // system so that omitting the return statement
            // at the top level does the right thing.
            p.flushValue();
            cb->destroyAllLiveValues( c );


            cb->emitTerminator( r->currentLocation(), llr::Ret() );


























        }

        verify::Func fv( cfg );
        if( !fv.verify() )
            return nullptr;

        return cfg;
    }
}







<
|
>




<
<
<


>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









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
        p.parseSequence();

        if( cfg->isPoisoned() )
            return cfg;

        if( !r->eos() )
        {

            dm.emitSyntaxErrorMessage( r->currentLocation(), "syntax error." );
            return nullptr;
        }

        if( cfg->currentBB() && !cfg->currentBB()->terminator() )
        {



            p.flushValue();
            cb->destroyAllLiveValues( c );

            if( returnType == GetValueType< void >() )
               cb->emitTerminator( r->currentLocation(), llr::Ret() );
            else if( !defRetVal )
            {
                dm.emitSyntaxErrorMessage( r->currentLocation(), "missing return statement." );
                return nullptr;
            }
            else
            {
                auto converted = ConvertValueToType( c, *defRetVal, returnType );
                if( holds_alternative< ValUnifyError >( converted ) )
                {
                    switch( get< ValUnifyError >( converted ) )
                    {
                        case ValUnifyError::NoSolution:
                            dm.emitErrorMessage( defRetVal->locationId(), "default return value type mismatch." );
                            break;

                        case ValUnifyError::Ambiguous:
                            dm.emitErrorMessage( defRetVal->locationId(), "ambiguous default return value conversion." );
                            break;
                    }

                    return nullptr;
                }

                cb->emitTerminator( r->currentLocation(), llr::Ret( get< Value >( converted ) ) );
            }
        }

        verify::Func fv( cfg );
        if( !fv.verify() )
            return nullptr;

        return cfg;
    }
}
Changes to bs/compile/compiler.h.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    class Compiler
    {
        public:
            Compiler( int argc, char** argv );
            uint32_t execute( const string& filename );

            static optional< ir::Value > LoadAndExecuteFile( const util::ptr< sema::Env >& e, const string& filename,
                const ir::Term& identity, optional< ir::Term > returnType = nullopt );

            static util::ptr< llr::CFG > LoadAndParseFile( const util::ptr< sema::Env >& e, const string& filename,
                const ir::Term& identity, optional< ir::Term > returnType = nullopt );

        private:
            util::ptr< sema::Env > m_pEnv;
    };
}

#endif







|


|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    class Compiler
    {
        public:
            Compiler( int argc, char** argv );
            uint32_t execute( const string& filename );

            static optional< ir::Value > LoadAndExecuteFile( const util::ptr< sema::Env >& e, const string& filename,
                const ir::Term& identity, const ir::Term& returnType, optional< ir::Value > defRetVal );

            static util::ptr< llr::CFG > LoadAndParseFile( const util::ptr< sema::Env >& e, const string& filename,
                const ir::Term& identity, const ir::Term& returnType, optional< ir::Value > defRetVal );

        private:
            util::ptr< sema::Env > m_pEnv;
    };
}

#endif
Changes to bs/goose.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "compile/compiler.h"

using namespace std;
using namespace goose;
using namespace goose::util;

int main( int argc, char** argv )
{
    compile::Compiler ec( argc, argv );

    if( ec.execute( "lib/goose.g" ) )
        return EXIT_SUCCESS;

    return EXIT_FAILURE;
}









<
|
<
<
<

1
2
3
4
5
6
7
8
9

10



11
#include "compile/compiler.h"

using namespace std;
using namespace goose;
using namespace goose::util;

int main( int argc, char** argv )
{
    compile::Compiler ec( argc, argv );

    return ec.execute( "lib/goose.g" );



}
Changes to lib/frontend.g.
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

// Create the module
var module = CGModuleCreate( SourceToCompile )

// Setup the target.
if !CGModuleSetupTarget( module )
{
    Print( "Failed to setup llvm target.\n" )
    return 0
}

// Define the exit external function.
using exit = ExternalFunction( void( uint( 32 ) returnCode ), "_exit" )

using main = #CompileFileToFunction( SourceToCompile, void, () )

// The entry point of the binary.
// We have to use "using" and an anonymous function, because otherwise
// it would create an overloadset and CGGenerateFunction wouldn't know
// how to deal with that.
// This is basically the "crt0". Dunno yet if it's a good idea to build it myself
// or just to link to an existing crt0.o. This has the advantage of flexibility
// to add features later on, but may require more compile time conditional magic
// to handle various platforms.
// Right now it has the advantage of avoiding yet another external dependency.
using entryPoint = void() {
    main()
    exit( 0 )
}

if !CGGenerateFunction( module, entryPoint, "_start" )
{
    Print( "Frontend: codegen failed.\n" )
    return 0
}

// Run the llvm optimization passes
CGModuleOptimize( module )

// Output the llvm ir and the asm for inspection.
CGModuleEmitLLVMIr( module, strcat( SourceToCompile, ".ll" ) )

if !CGModuleEmitAsm( module, strcat( SourceToCompile, ".s" ) )
{
    Print( strcat( "Failed to write ", strcat( SourceToCompile, ".s\n" ) ) )
    return 0
}

// Output the object file.
if !CGModuleEmitObj( module, strcat( SourceToCompile, ".o" ) )
{
    Print( strcat( "Failed to write ", strcat( SourceToCompile, ".o\n" ) ) )
    return 0
}

// Link it and produce an executable file.
var linkerArgs = (
    strcat( SourceToCompile, ".o" ),
    "-o", strcat( SourceToCompile, ".out" ),
    "-L/lib/x86_64-linux-gnu", "-lc",
    "--dynamic-linker=/lib64/ld-linux-x86-64.so.2"
)

if !CGLinkerELF( linkerArgs )
    return 0

Print( strcat( "Built executable ", strcat( SourceToCompile, ".out\n" ) ) )








|





|











<
|





|











|






|











|


>
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
// Create the module
var module = CGModuleCreate( SourceToCompile )

// Setup the target.
if !CGModuleSetupTarget( module )
{
    Print( "Failed to setup llvm target.\n" )
    return 1
}

// Define the exit external function.
using exit = ExternalFunction( void( uint( 32 ) returnCode ), "_exit" )

using main = #CompileFileToFunction( SourceToCompile, uint( 32 ), 0, () )

// The entry point of the binary.
// We have to use "using" and an anonymous function, because otherwise
// it would create an overloadset and CGGenerateFunction wouldn't know
// how to deal with that.
// This is basically the "crt0". Dunno yet if it's a good idea to build it myself
// or just to link to an existing crt0.o. This has the advantage of flexibility
// to add features later on, but may require more compile time conditional magic
// to handle various platforms.
// Right now it has the advantage of avoiding yet another external dependency.
using entryPoint = void() {

    exit( main() )
}

if !CGGenerateFunction( module, entryPoint, "_start" )
{
    Print( "Frontend: codegen failed.\n" )
    return 1
}

// Run the llvm optimization passes
CGModuleOptimize( module )

// Output the llvm ir and the asm for inspection.
CGModuleEmitLLVMIr( module, strcat( SourceToCompile, ".ll" ) )

if !CGModuleEmitAsm( module, strcat( SourceToCompile, ".s" ) )
{
    Print( strcat( "Failed to write ", strcat( SourceToCompile, ".s\n" ) ) )
    return 1
}

// Output the object file.
if !CGModuleEmitObj( module, strcat( SourceToCompile, ".o" ) )
{
    Print( strcat( "Failed to write ", strcat( SourceToCompile, ".o\n" ) ) )
    return 1
}

// Link it and produce an executable file.
var linkerArgs = (
    strcat( SourceToCompile, ".o" ),
    "-o", strcat( SourceToCompile, ".out" ),
    "-L/lib/x86_64-linux-gnu", "-lc",
    "--dynamic-linker=/lib64/ld-linux-x86-64.so.2"
)

if !CGLinkerELF( linkerArgs )
    return 1

Print( strcat( "Built executable ", strcat( SourceToCompile, ".out\n" ) ) )
return 0
Name change from tests/noprelude/complex/mandelbrot.g to tests/noprelude/combined/mandelbrot.g.
Name change from tests/noprelude/complex/mandelbrot.txt to tests/noprelude/combined/mandelbrot.txt.
Name change from tests/noprelude/complex/meson.build to tests/noprelude/combined/meson.build.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
tests = [

    'mandelbrot'
]

testrunner_interp = find_program( 'test_runner_interp.sh' )
testrunner_compile = find_program( 'test_runner_compile.sh' )

foreach t : tests
    file = configure_file( copy: true,
        input: t + '.g', output: t + '.g'
    )

    test( 'g-np-complex-interp-' + t, testrunner_interp,
        args: [ goose, 'tests/noprelude/complex/' + t,
            files( t + '.txt' ) ] )

    test( 'g-np-complex-compile-' + t, testrunner_compile,
        args: [ goose, 'tests/noprelude/complex/' + t,
            files( t + '.txt' ) ] )
endforeach

>











|
|


|
|


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
tests = [
    #'tuple', # Not enabled yet since it requires implementing LowerType for tuples to be able to compile
    'mandelbrot'
]

testrunner_interp = find_program( 'test_runner_interp.sh' )
testrunner_compile = find_program( 'test_runner_compile.sh' )

foreach t : tests
    file = configure_file( copy: true,
        input: t + '.g', output: t + '.g'
    )

    test( 'g-np-combined-interp-' + t, testrunner_interp,
        args: [ goose, 'tests/noprelude/combined/' + t,
            files( t + '.txt' ) ] )

    test( 'g-np-combined-compile-' + t, testrunner_compile,
        args: [ goose, 'tests/noprelude/combined/' + t,
            files( t + '.txt' ) ] )
endforeach
Name change from tests/noprelude/complex/test_runner_compile.sh to tests/noprelude/combined/test_runner_compile.sh.
Name change from tests/noprelude/complex/test_runner_interp.sh to tests/noprelude/combined/test_runner_interp.sh.
Added tests/noprelude/combined/tuple.g.


































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
using puts = ExternalFunction( uint(32) ( pointer( uint(8) ) str ), "puts" )

void print( ct_string str )
{
    #if IsCompiling
    {
        puts( str )
    }
    #else
    {
        Print( str )
    }
}

bool check( bool cond, ct_string message )
{
    print( message )
    print( ": " )
    if cond print( "OK\n" ) else print( "Failed\n" )
    return cond
}

// Multiple return values
bool, ct_string foo()
{
    return true, "lomarf"
}

var tup1 = foo()

if !check( tup1.0 & tup1.1 == "lomarf", "tuple test 1"  )
    return 1

// Splicing
ct_int, bool, ct_string, ct_string bar()
{
    return 219, foo(), "laffo"
}

var tup2 = bar()

if !check( tup2.0 == 219 & tup2.1 & tup2.2 == "lomarf" & tup2.3 == "laffo", "tuple test 2"  )
    return 1

// Modifying individual tuple members
tup2.2 = "blah"

if !check( tup2.0 == 219 & tup2.1 & tup2.2 == "blah" & tup2.3 == "laffo", "tuple test 3"  )
    return 1
Added tests/noprelude/combined/tuple.txt.






>
>
>
1
2
3
tuple test 1: OK
tuple test 2: OK
tuple test 3: OK
Changes to tests/noprelude/execute/arithops.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#Include( "tests/noprelude/helpers.g" )

if !check( 219 + 1337 == 1556, "add test" )
    return 0

if !check( 219 - 1337 == -1118, "sub test" )
    return 0

if !check( 219 * 1337 == 292803, "mul test" )
    return 0

if !check( 1337 / 219 == 6, "div test" )
    return 0

if !check( 1337 % 219 == 23, "modulo test" )
    return 0

return 1



|


|


|


|


<
<
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


16
#Include( "tests/noprelude/helpers.g" )

if !check( 219 + 1337 == 1556, "add test" )
    return 1

if !check( 219 - 1337 == -1118, "sub test" )
    return 1

if !check( 219 * 1337 == 292803, "mul test" )
    return 1

if !check( 1337 / 219 == 6, "div test" )
    return 1

if !check( 1337 % 219 == 23, "modulo test" )


    return 1
Changes to tests/noprelude/execute/bitwiseops.g.
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
#Include( "tests/noprelude/helpers.g" )

uint( 32 ) lomarf( uint( 32 ) a, uint( 32 ) b )
{
    return a ^ b;
}

if !check( lomarf( 0xdeadbeef, 0xabadfeed ) == 0x75004002, "integer bitwise xor test" )
    return 0

if !check( ( 0xdeadbeef & 0xabadfeed ) == 0x8aadbeed, "bitwise and test" )
    return 0

if !check( ( 0xdeadbeef | 0xabadfeed ) == 0xffadfeef, "bitwise or test" )
    return 0

if !check( ( 0b110011 ^ 0x2a ) == 0b011001, "bitwise xor test" )
    return 0

if !check( 0xdeadbeef << 4 == 0xdeadbeef0, "left shift test" )
    return 0

if !check( 0xdeadbeef >> 4 == 0xdeadbee, "right shift 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
22
23


24
#Include( "tests/noprelude/helpers.g" )

uint( 32 ) lomarf( uint( 32 ) a, uint( 32 ) b )
{
    return a ^ b;
}

if !check( lomarf( 0xdeadbeef, 0xabadfeed ) == 0x75004002, "integer bitwise xor test" )
    return 1

if !check( ( 0xdeadbeef & 0xabadfeed ) == 0x8aadbeed, "bitwise and test" )
    return 1

if !check( ( 0xdeadbeef | 0xabadfeed ) == 0xffadfeef, "bitwise or test" )
    return 1

if !check( ( 0b110011 ^ 0x2a ) == 0b011001, "bitwise xor test" )
    return 1

if !check( 0xdeadbeef << 4 == 0xdeadbeef0, "left shift test" )
    return 1

if !check( 0xdeadbeef >> 4 == 0xdeadbee, "right shift test" )


    return 1
Changes to tests/noprelude/execute/comparisonops.g.
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
#Include( "tests/noprelude/helpers.g" )

if !check( true == true, "eq test 1" )
    return 0

if !check( 219 == 219, "eq test 2" )
    return 0

if !check( "lomarf" == "lomarf", "eq test 3" )
    return 0

if !check( !( true == false ), "eq test 4" )
    return 0

if !check( !( 219 == 1337 ), "eq test 5" )
    return 0

if !check( !( "lomarf" == "lmao" ), "eq test 6" )
    return 0


if !check( true != false, "neq test 1" )
    return 0

if !check( 219 != 1337, "neq test 2" )
    return 0

if !check( "lomarf" != "lmao", "neq test 3" )
    return 0

if !check( !( true != true ), "neq test 4" )
    return 0

if !check( !( 219 != 219 ), "neq test 5" )
    return 0

if !check( !( "lomarf" != "lomarf" ), "neq test 6" )
    return 0


if !check( 1337 > 219, "gt test 1" )
    return 0

if !check( !( 219 > 1337 ), "gt test 2" )
    return 0

if !check( 1337 >= 219, "ge test 1" )
    return 0

if !check( !( 219 >= 1337 ), "ge test 2" )
    return 0

if !check( 1337 >= 1337, "ge test 3" )
    return 0


if !check( 219 < 1337, "lt test 1" )
    return 0

if !check( !( 1337 < 219 ), "lt test 2" )
    return 0

if !check( 219 <= 1337, "le test 1" )
    return 0

if !check( !( 1337 <= 219 ), "le test 2" )
    return 0

if !check( 1337 <= 1337, "le test 3" )
    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
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
#Include( "tests/noprelude/helpers.g" )

if !check( true == true, "eq test 1" )
    return 1

if !check( 219 == 219, "eq test 2" )
    return 1

if !check( "lomarf" == "lomarf", "eq test 3" )
    return 1

if !check( !( true == false ), "eq test 4" )
    return 1

if !check( !( 219 == 1337 ), "eq test 5" )
    return 1

if !check( !( "lomarf" == "lmao" ), "eq test 6" )
    return 1


if !check( true != false, "neq test 1" )
    return 1

if !check( 219 != 1337, "neq test 2" )
    return 1

if !check( "lomarf" != "lmao", "neq test 3" )
    return 1

if !check( !( true != true ), "neq test 4" )
    return 1

if !check( !( 219 != 219 ), "neq test 5" )
    return 1

if !check( !( "lomarf" != "lomarf" ), "neq test 6" )
    return 1


if !check( 1337 > 219, "gt test 1" )
    return 1

if !check( !( 219 > 1337 ), "gt test 2" )
    return 1

if !check( 1337 >= 219, "ge test 1" )
    return 1

if !check( !( 219 >= 1337 ), "ge test 2" )
    return 1

if !check( 1337 >= 1337, "ge test 3" )
    return 1


if !check( 219 < 1337, "lt test 1" )
    return 1

if !check( !( 1337 < 219 ), "lt test 2" )
    return 1

if !check( 219 <= 1337, "le test 1" )
    return 1

if !check( !( 1337 <= 219 ), "le test 2" )
    return 1

if !check( 1337 <= 1337, "le test 3" )


    return 1
Changes to tests/noprelude/execute/compoundass.g.
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
#Include( "tests/noprelude/helpers.g" )

var lomarf = 219

if !check( lomarf == 219, "compound assignment operator test 1" )
    return 0


lomarf += 1337

if !check( lomarf == 1556, "compound assignment operator test 2" )
    return 0


lomarf -= 1337 * 2

if !check( lomarf == -1118, "compound assignment operator test 3" )
    return 0


lomarf *= 1337

if !check( lomarf == -1494766, "compound assignment operator test 3" )
    return 0


lomarf /= 219

if !check( lomarf == -6825, "compound assignment operator test 4" )
    return 0


lomarf = 1337
lomarf %= 219

if !check( lomarf == 23, "compound assignment operator test 5" )
    return 0


lomarf = 0xdeadbeef
lomarf ^= 0xabadfeed

if !check( lomarf == 0x75004002, "compound assignment operator test 6" )
    return 0


lomarf = 0xdeadbeef
lomarf &= 0xabadfeed

if !check( lomarf == 0x8aadbeed, "compound assignment operator test 7" )
    return 0


lomarf = 0xdeadbeef
lomarf |= 0xabadfeed

if !check( lomarf == 0xffadfeef, "compound assignment operator test 8" )
    return 0


lomarf = 0xdeadbeef
lomarf <<= 4

if !check( lomarf == 0xdeadbeef0, "compound assignment operator test 9" )
    return 0

lomarf >>= 8

if !check( lomarf == 0xdeadbee, "compound assignment operator test 10" )
    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
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
#Include( "tests/noprelude/helpers.g" )

var lomarf = 219

if !check( lomarf == 219, "compound assignment operator test 1" )
    return 1


lomarf += 1337

if !check( lomarf == 1556, "compound assignment operator test 2" )
    return 1


lomarf -= 1337 * 2

if !check( lomarf == -1118, "compound assignment operator test 3" )
    return 1


lomarf *= 1337

if !check( lomarf == -1494766, "compound assignment operator test 3" )
    return 1


lomarf /= 219

if !check( lomarf == -6825, "compound assignment operator test 4" )
    return 1


lomarf = 1337
lomarf %= 219

if !check( lomarf == 23, "compound assignment operator test 5" )
    return 1


lomarf = 0xdeadbeef
lomarf ^= 0xabadfeed

if !check( lomarf == 0x75004002, "compound assignment operator test 6" )
    return 1


lomarf = 0xdeadbeef
lomarf &= 0xabadfeed

if !check( lomarf == 0x8aadbeed, "compound assignment operator test 7" )
    return 1


lomarf = 0xdeadbeef
lomarf |= 0xabadfeed

if !check( lomarf == 0xffadfeef, "compound assignment operator test 8" )
    return 1


lomarf = 0xdeadbeef
lomarf <<= 4

if !check( lomarf == 0xdeadbeef0, "compound assignment operator test 9" )
    return 1

lomarf >>= 8

if !check( lomarf == 0xdeadbee, "compound assignment operator test 10" )


    return 1
Changes to tests/noprelude/execute/higher-func.g.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

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

if !check( higher( ct_string( ct_string a ){ return strcat( "test1: ", a ) } ) == "test1: higher", "higher order function test 1" )
    return 0

if !check( higher( ct_string( $t a ){ return strcat( "test2: ", a ) } ) == "test2: higher", "higher order function test 2" )
    return 0

if !check( higher( someFunc ) == "someFunc 1: higher", "higher order function test 3" )
    return 0

return 1







|


|


<
<
|
12
13
14
15
16
17
18
19
20
21
22
23
24


25

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

if !check( higher( ct_string( ct_string a ){ return strcat( "test1: ", a ) } ) == "test1: higher", "higher order function test 1" )
    return 1

if !check( higher( ct_string( $t a ){ return strcat( "test2: ", a ) } ) == "test2: higher", "higher order function test 2" )
    return 1

if !check( higher( someFunc ) == "someFunc 1: higher", "higher order function test 3" )


    return 1
Changes to tests/noprelude/execute/higher-poly.g.
12
13
14
15
16
17
18
19
20
21

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

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

return 1







<
<
|
12
13
14
15
16
17
18


19

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

if !check( higherPoly( someFunc ) == "someFunc1: ct_int, someFunc2: blah", "higher order polymorphism test" )


    return 1
Changes to tests/noprelude/execute/higher-template.g.
12
13
14
15
16
17
18
19
20
21
22
23
24

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

if !check( higherTpl( ct_string( ct_int a ){ return "test1" }, 123 ) == "higher: test1", "higher order template test 1" )
    return 0

if !check( higherTpl( someFunc, "meh" ) == "higher: someFunc2: meh", "higher order template test 2" )
    return 0

return 1







|


<
<
|
12
13
14
15
16
17
18
19
20
21


22

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

if !check( higherTpl( ct_string( ct_int a ){ return "test1" }, 123 ) == "higher: test1", "higher order template test 1" )
    return 1

if !check( higherTpl( someFunc, "meh" ) == "higher: someFunc2: meh", "higher order template test 2" )


    return 1
Changes to tests/noprelude/execute/if.g.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ct_string func2( bool b )
{
    if b return "lomarf"
    else return "meh"
}

if !check( func1( true ) == "lomarf", "if test 1" )
    return 0

if !check( func1( false ) == "meh", "if test 2" )
    return 0

if !check( func2( true ) == "lomarf", "if test 3" )
    return 0

if !check( func2( false ) == "meh", "if test 4" )
    return 0

return 1







|


|


|


<
<
|
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


25
ct_string func2( bool b )
{
    if b return "lomarf"
    else return "meh"
}

if !check( func1( true ) == "lomarf", "if test 1" )
    return 1

if !check( func1( false ) == "meh", "if test 2" )
    return 1

if !check( func2( true ) == "lomarf", "if test 3" )
    return 1

if !check( func2( false ) == "meh", "if test 4" )


    return 1
Changes to tests/noprelude/execute/locvar.g.
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
#Include( "tests/noprelude/helpers.g" )

uint(32) lomarf = 219

if !check( lomarf == 219, "local variable test 1" )
    return 0

if !check( lomarf != 1337, "local variable test 2" )
    return 0

lomarf = 1337

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


uint(32) laffo

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

laffo = 219

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


// Type inference with a template expression, captures the type in $T as well
$T meh = 12354

if !check( typeName( $T ) == "ct_int", "local variable test 6" )
    return 0

if !check( meh == 12354, "local variable test 7" )
    return 0

meh = 1337

if !check( meh == 1337, "local variable test 8" )
    return 0


// Simple type inference. (really the same as above except we use "var", which is
// an alias for $_, so we use an anonymous tvar and don't capture the type.)
var blah = 8787

if !check( blah == 8787, "local variable test 9" )
    return 0

blah = 98997

if !check( blah == 98997, "local variable test 10" )
    return 0

// Chained assignment
meh = blah = 1234

if !check( meh == 1234 & blah == 1234, "local variable test 11" )
    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
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( "tests/noprelude/helpers.g" )

uint(32) lomarf = 219

if !check( lomarf == 219, "local variable test 1" )
    return 1

if !check( lomarf != 1337, "local variable test 2" )
    return 1

lomarf = 1337

if !check( lomarf == 1337, "local variable test 3" )
    return 1


uint(32) laffo

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

laffo = 219

if !check( laffo == 219, "local variable test 5" )
    return 1


// Type inference with a template expression, captures the type in $T as well
$T meh = 12354

if !check( typeName( $T ) == "ct_int", "local variable test 6" )
    return 1

if !check( meh == 12354, "local variable test 7" )
    return 1

meh = 1337

if !check( meh == 1337, "local variable test 8" )
    return 1


// Simple type inference. (really the same as above except we use "var", which is
// an alias for $_, so we use an anonymous tvar and don't capture the type.)
var blah = 8787

if !check( blah == 8787, "local variable test 9" )
    return 1

blah = 98997

if !check( blah == 98997, "local variable test 10" )
    return 1

// Chained assignment
meh = blah = 1234

if !check( meh == 1234 & blah == 1234, "local variable test 11" )


    return 1
Changes to tests/noprelude/execute/logicops.g.
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

bool xor( bool a, bool b )
{
    return a ^ b;
}

if !check( lomarf( false, false ) == false, "logic or test 1" )
    return 0

if !check( lomarf( false, true ) == true, "logic or test 2" )
    return 0

if !check( lomarf( true, false ) == true, "logic or test 3" )
    return 0

if !check( lomarf( true, true ) == true, "logic or test 4" )
    return 0


if !check( blah( false, false ) == false, "logic and test 1" )
    return 0

if !check( blah( false, true ) == false, "logic and test 2" )
    return 0

if !check( blah( true, false ) == false, "logic and test 3" )
    return 0

if !check( blah( true, true ) == true, "logic and test 4" )
    return 0


if !check( xor( false, false ) == false, "logic xor test 1" )
    return 0

if !check( xor( false, true ) == true, "logic xor test 2" )
    return 0

if !check( xor( true, false ) == true, "logic xor test 3" )
    return 0

if !check( xor( true, true ) == false, "logic xor test 4" )
    return 0

return 1







|


|


|


|



|


|


|


|



|


|


|


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

bool xor( bool a, bool b )
{
    return a ^ b;
}

if !check( lomarf( false, false ) == false, "logic or test 1" )
    return 1

if !check( lomarf( false, true ) == true, "logic or test 2" )
    return 1

if !check( lomarf( true, false ) == true, "logic or test 3" )
    return 1

if !check( lomarf( true, true ) == true, "logic or test 4" )
    return 1


if !check( blah( false, false ) == false, "logic and test 1" )
    return 1

if !check( blah( false, true ) == false, "logic and test 2" )
    return 1

if !check( blah( true, false ) == false, "logic and test 3" )
    return 1

if !check( blah( true, true ) == true, "logic and test 4" )
    return 1


if !check( xor( false, false ) == false, "logic xor test 1" )
    return 1

if !check( xor( false, true ) == true, "logic xor test 2" )
    return 1

if !check( xor( true, false ) == true, "logic xor test 3" )
    return 1

if !check( xor( true, true ) == false, "logic xor test 4" )


    return 1
Changes to tests/noprelude/execute/overloading.g.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

ct_string overloadedFunc( ct_string foo, ct_int bar )
{
    return "overload 5"
}

if !check( overloadedFunc() == "overload 1", "overload test 1" )
    return 0

if !check( overloadedFunc( "gg" ) == "overload 2", "overload test 2" )
    return 0

if !check( overloadedFunc( 123 ) == "overload 3", "overload test 3" )
    return 0

if !check( overloadedFunc( 456, "meh" ) == "overload 4", "overload test 4" )
    return 0

if !check( overloadedFunc( "aha", 777 ) == "overload 5", "overload test 5" )
    return 0

return 1







|


|


|


|


<
<
|
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40


41

ct_string overloadedFunc( ct_string foo, ct_int bar )
{
    return "overload 5"
}

if !check( overloadedFunc() == "overload 1", "overload test 1" )
    return 1

if !check( overloadedFunc( "gg" ) == "overload 2", "overload test 2" )
    return 1

if !check( overloadedFunc( 123 ) == "overload 3", "overload test 3" )
    return 1

if !check( overloadedFunc( 456, "meh" ) == "overload 4", "overload test 4" )
    return 1

if !check( overloadedFunc( "aha", 777 ) == "overload 5", "overload test 5" )


    return 1
Changes to tests/noprelude/execute/templates.g.
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

ct_string tplTest2( ct_int foo )
{
    return "integer"
}

if !check( tplTest1( 1, 2 ) == "same types", "template test 1" )
    return 0

if !check( tplTest1( "a", "b" ) == "same types", "template test 2" )
    return 0

if !check( tplTest1( 1, "a" ) == "different types", "template test 3" )
    return 0

if !check( tplTest1( "b", 45 ) == "different types", "template test 4" )
    return 0

if !check( tplTest2( 123 ) == "integer", "template test 5" )
    return 0

if !check( tplTest2( "blah" ) == "blah", "template test 6" )
    return 0

if !check( tplTest2( Print ) == "whatever", "template test 7" )
    return 0

return 1







|


|


|


|


|


|


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

ct_string tplTest2( ct_int foo )
{
    return "integer"
}

if !check( tplTest1( 1, 2 ) == "same types", "template test 1" )
    return 1

if !check( tplTest1( "a", "b" ) == "same types", "template test 2" )
    return 1

if !check( tplTest1( 1, "a" ) == "different types", "template test 3" )
    return 1

if !check( tplTest1( "b", 45 ) == "different types", "template test 4" )
    return 1

if !check( tplTest2( 123 ) == "integer", "template test 5" )
    return 1

if !check( tplTest2( "blah" ) == "blah", "template test 6" )
    return 1

if !check( tplTest2( Print ) == "whatever", "template test 7" )


    return 1
Changes to tests/noprelude/execute/tuple.g.
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
#Include( "tests/noprelude/helpers.g" )

// Multiple return values
bool, ct_string foo()
{
    return true, "lomarf"
}

// Tuple decomposition using type inferred variable declarations
var a, var b = foo()

if !check( a & b == "lomarf", "tuple test 1"  )
    return 0

// Splicing
ct_int, bool, ct_string, ct_string bar()
{
    return 219, foo(), "laffo"
}

var c, var d, var e, var f = bar()

if !check( c == 219 & d & e == "lomarf" & f == "laffo", "tuple test 2"  )
    return 0

// Swapping variables
e,f = f,e

if !check( e == "laffo" & f == "lomarf", "tuple test 3"  )
    return 0

// Reading individual tuple members
if !check( bar().0 == 219 & bar().1 & bar().2 == "lomarf" & bar().3 == "laffo", "tuple test 4"  )
    return 0

var tup = bar()

if !check( tup.0 == 219 & tup.1 & tup.2 == "lomarf" & tup.3 == "laffo", "tuple test 5"  )
    return 0

// Modifying individual tuple members
tup.2 = "blah"

if !check( tup.0 == 219 & tup.1 & tup.2 == "blah" & tup.3 == "laffo", "tuple test 6"  )
    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
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


45
#Include( "tests/noprelude/helpers.g" )

// Multiple return values
bool, ct_string foo()
{
    return true, "lomarf"
}

// Tuple decomposition using type inferred variable declarations
var a, var b = foo()

if !check( a & b == "lomarf", "tuple test 1"  )
    return 1

// Splicing
ct_int, bool, ct_string, ct_string bar()
{
    return 219, foo(), "laffo"
}

var c, var d, var e, var f = bar()

if !check( c == 219 & d & e == "lomarf" & f == "laffo", "tuple test 2"  )
    return 1

// Swapping variables
e,f = f,e

if !check( e == "laffo" & f == "lomarf", "tuple test 3"  )
    return 1

// Reading individual tuple members
if !check( bar().0 == 219 & bar().1 & bar().2 == "lomarf" & bar().3 == "laffo", "tuple test 4"  )
    return 1

var tup = bar()

if !check( tup.0 == 219 & tup.1 & tup.2 == "lomarf" & tup.3 == "laffo", "tuple test 5"  )
    return 1

// Modifying individual tuple members
tup.2 = "blah"

if !check( tup.0 == 219 & tup.1 & tup.2 == "blah" & tup.3 == "laffo", "tuple test 6"  )


    return 1
Changes to tests/noprelude/execute/using.g.
1
2
3
4
5
6
7
8
9
#Include( "tests/noprelude/helpers.g" )

using u1 = u2
using u2 = "test"

if !check( u1 == "test", "using test" )
    return 0

return 1






<
<
|
1
2
3
4
5
6


7
#Include( "tests/noprelude/helpers.g" )

using u1 = u2
using u2 = "test"

if !check( u1 == "test", "using test" )


    return 1
Changes to tests/noprelude/execute/while.g.
1
2
3
4
5
6
7
8
9
10
11
12
#Include( "tests/noprelude/helpers.g" )

var i = 0
while( i < 10 )
{
    i += 1
}

if !check( i == 10, "while test" )
    return 0

return 1









<
<
|
1
2
3
4
5
6
7
8
9


10
#Include( "tests/noprelude/helpers.g" )

var i = 0
while( i < 10 )
{
    i += 1
}

if !check( i == 10, "while test" )


    return 1
Changes to tests/noprelude/helpers.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
// Helpers for core language tests, for which we don't want to use
// the prelude and the standard library.

bool check( bool cond, ct_string message )
{
    if !cond Print( strcat( strcat( "checkion failed: ", message ), "\n" ) )
    return cond
}

// An using statement to check diagnostics context that span multiple files.
using Laffo = SomeOtherThing

// Simple function to retrieve a builtin type name





|







1
2
3
4
5
6
7
8
9
10
11
12
13
// Helpers for core language tests, for which we don't want to use
// the prelude and the standard library.

bool check( bool cond, ct_string message )
{
    if !cond Print( strcat( strcat( "check failed: ", message ), "\n" ) )
    return cond
}

// An using statement to check diagnostics context that span multiple files.
using Laffo = SomeOtherThing

// Simple function to retrieve a builtin type name
Changes to tests/noprelude/meson.build.
1
2
3
4
5
6
7
8
9
file = configure_file( copy: true,
    input: 'helpers.g', output: 'helpers.g'
)

subdir( 'diagnostics' )
subdir( 'execute' )
subdir( 'codegen' )
subdir( 'complex' )
subdir( 'verify' )







|

1
2
3
4
5
6
7
8
9
file = configure_file( copy: true,
    input: 'helpers.g', output: 'helpers.g'
)

subdir( 'diagnostics' )
subdir( 'execute' )
subdir( 'codegen' )
subdir( 'combined' )
subdir( 'verify' )