Goose  Check-in [f1cab5f761]

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

Overview
Comment:
  • ExecuteFile is now a regular builtin function.
  • Added #Include, which works the same as the old ExecuteFile.
  • Added a CreateConstant() builtin func.
  • Used the above to cleanup the command line parsing code in empathy.em.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f1cab5f761a024358c1e7fab475d38812ac7c124be8bcb50d96512b512c5f69f
User & Date: achavasse 2019-08-24 16:54:29.173
Context
2019-08-24
19:33
More cleanup around which builtin functions should be intrinsics/eager/non eager. check-in: fece958df9 user: achavasse tags: trunk
16:54
  • ExecuteFile is now a regular builtin function.
  • Added #Include, which works the same as the old ExecuteFile.
  • Added a CreateConstant() builtin func.
  • Used the above to cleanup the command line parsing code in empathy.em.
check-in: f1cab5f761 user: achavasse tags: trunk
13:42
Factored out the common code of Compiler::execute(), ExecuteFile() and #CompileFileToFunction(). check-in: 0c5641877d user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/api/compiler.cpp.
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
            [pEnv]( uint32_t budget )
            {
                static bool used = false;

                if( used )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( 0,
                        "SetExecutionBudget can only be used once." );
                    return;
                }

                used = true;
                execute::VM::SetExecutionBudget( budget );
            } );

        RegisterBuiltinFunc< Eager< Value > ( Value, string ) >( e, "#ExternalFunction"_sid,
            [pEnv]( const Value& f, const string& symbol )
            {
                auto ft = FromValue< FuncType >( f );
                if( !ft )
                    return ToValue( "error"s ).setPoison();

                return ToValue( BuildExternalFunc( *ft, symbol ) );
            } );
















        RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "ExecuteFile"_sid,
            [pEnv]( 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< Eager< Value > ( string, Value, Value ) >( e, "#CompileFileToFunction"_sid,
            [pEnv]( const string& filename, const Value& rt, const Value& params ) -> Value
            {
                // Validate those generic value inputs
                if( !rt.isType() )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( rt.locationId(),
                        "#CompileFileToFunction: type expected." );
                    return PoisonValue();
                }

                if( CheckParamListKind( params ) != ParamListKind::Regular )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( params.locationId(),
                        "#CompileFileToFunction: template parameter lists are not supported." );
                    return PoisonValue();
                }

                auto ftype = BuildFuncType( sema::DomainAny(), rt, params );

                // TODO at some point we'll want to pass the base identity to use as a param but
                // let's wait and see how the module and namespace stuff pans out first







|

















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




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
















|






|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
            [pEnv]( uint32_t budget )
            {
                static bool used = false;

                if( used )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( 0,
                        "#SetExecutionBudget can only be used once." );
                    return;
                }

                used = true;
                execute::VM::SetExecutionBudget( budget );
            } );

        RegisterBuiltinFunc< Eager< Value > ( Value, string ) >( e, "#ExternalFunction"_sid,
            [pEnv]( const Value& f, const string& symbol )
            {
                auto ft = FromValue< FuncType >( f );
                if( !ft )
                    return ToValue( "error"s ).setPoison();

                return ToValue( BuildExternalFunc( *ft, symbol ) );
            } );

        RegisterBuiltinFunc< void ( string, Value ) >( e, "CreateConstant"_sid,
            [pEnv]( const string& name, const Value& v )
            {
                if( !v.isConstant() )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
                        "CreateConstant: the expression doesn't evaluate to a constant." );
                    return;
                }

                pEnv.lock()->storeValue(
                    AppendToVectorTerm( RootIdentity(), StringId( name.c_str() ) ),
                    ANYTERM( _ ), ValueToIRExpr( v ) );
            } );

        RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "#Include"_sid,
            [pEnv]( 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< Eager< Value > ( string, Value, Value ) >( e, "#CompileFileToFunction"_sid,
            [pEnv]( const string& filename, const Value& rt, const Value& params ) -> Value
            {
                // Validate those generic value inputs
                if( !rt.isType() )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( rt.locationId(),
                        "#CompileFileToFunction: type expected.", 0 );
                    return PoisonValue();
                }

                if( CheckParamListKind( params ) != ParamListKind::Regular )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( params.locationId(),
                        "#CompileFileToFunction: template parameter lists are not supported.", 0 );
                    return PoisonValue();
                }

                auto ftype = BuildFuncType( sema::DomainAny(), rt, params );

                // TODO at some point we'll want to pass the base identity to use as a param but
                // let's wait and see how the module and namespace stuff pans out first
97
98
99
100
101
102
103



104
105
106
107
108
109
110
                    InjectDomainIntoIdentity( funcIdentity, ANYTERM( _ ) ) );

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

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




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

                if( c.returnType() != GetValueType< void >()
                    && !cfg->areAllBBTerminated() )
                {
                    pFuncLLR->setInvalid();







>
>
>







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
                    InjectDomainIntoIdentity( funcIdentity, ANYTERM( _ ) ) );

                auto func = BuildFunc( c, 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();

                if( c.returnType() != GetValueType< void >()
                    && !cfg->areAllBBTerminated() )
                {
                    pFuncLLR->setInvalid();
Changes to bs/builtins/types/tuple/unify.cpp.
1
2
3
4
5
6
7
8
9
10
11
12


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "builtins/builtins.h"

using namespace empathy;
using namespace empathy::ir;

namespace empathy::builtins
{
    void SetupTupleUnification( Env& e )
    {
        // Single element tuple unwrapping rule: if we encounter such a tuple, attempt to unify
        // its contained value with whatever's on the other side.
        e.unificationRuleSet()->addSymRule(



            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

            ANYTERM( _ ),

        []( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
        {
            // Only deal with during the second pass, we may have unresolved holes
            // messing things up.
            if( !c.secondPass() )
            {
                co_yield { lhs, c };
                co_return;
            }

            auto tup = ValueFromIRExpr( lhs );
            assert( tup );

            const auto& vec1 = *get< pvec >( tup->val() );

            // In some cases, the tuple may not be an actual tuple value but merely
            // a pattern for a tuple value, with a hole instead of its content vector.
            // If it happens, since that hole is represented as a vector, we'll have a longer than
            // 1 vector here. But this means we can't extract the first element anyway (since it
            // doesn't really exist yet), so just yield the tuple as is.
            if( vec1.length().minLength() != 1 )
            {
                co_yield { lhs, c };
                co_return;
            }

            co_yield Unify( vec1[0], rhs, c );
        } );

        // When unifying a tuple against a value whose type is a hole, we don't want
        // the above rule to apply (ie we don't want 1 element tuples bound to generic
        // template parameters to be peeled off). So here's a rule for this case which
        // leaves the tuple unchanged. It will take priority over the above rule in
        // those cases because it matches a more specific pattern.












>
>






<
<


<
<
<
<
<
<
<
<
|











|



|







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


21
22








23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "builtins/builtins.h"

using namespace empathy;
using namespace empathy::ir;

namespace empathy::builtins
{
    void SetupTupleUnification( Env& e )
    {
        // Single element tuple unwrapping rule: if we encounter such a tuple, attempt to unify
        // its contained value with whatever's on the other side.
        e.unificationRuleSet()->addSymRule(

            ANYTERM( _ ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),



        []( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
        {








            auto tup = ValueFromIRExpr( rhs );
            assert( tup );

            const auto& vec1 = *get< pvec >( tup->val() );

            // In some cases, the tuple may not be an actual tuple value but merely
            // a pattern for a tuple value, with a hole instead of its content vector.
            // If it happens, since that hole is represented as a vector, we'll have a longer than
            // 1 vector here. But this means we can't extract the first element anyway (since it
            // doesn't really exist yet), so just yield the tuple as is.
            if( vec1.length().minLength() != 1 )
            {
                co_yield { rhs, c };
                co_return;
            }

            co_yield Unify( lhs, vec1[0], c );
        } );

        // When unifying a tuple against a value whose type is a hole, we don't want
        // the above rule to apply (ie we don't want 1 element tuples bound to generic
        // template parameters to be peeled off). So here's a rule for this case which
        // leaves the tuple unchanged. It will take priority over the above rule in
        // those cases because it matches a more specific pattern.
Changes to bs/compiler.cpp.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
            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,







<







78
79
80
81
82
83
84

85
86
87
88
89
90
91
            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,
Changes to lib/empathy.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
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
// This is the interpreted code entry point of the empathy
// command line tool.
//
// This will setup the prelude and drive the compilation
// process (through function calls exposed by empathy).

// Direct run mode:
// We have a bunch of low level, simple tests of the basic language functionality
// and builtins provided by the compilers, which make do without the standard prelude and library.
// Since those tests are very useful, we want to be able to skip the regular front-end to
// be able to continue to run those tests.
// This is achieved by using a couple of utility builtin fonction to perform a crude parsing
// of the command line.
// If the command line starts with "--noprelude", followed by a filename, we skip the frontend
// and library setup and just run the provided file as is.

// This is a bit awkward for now: we need the parsing to be containd entirely
//  into compile time functions whose result can be eagerly evaluated, so
// that we can use it as parameters for the #if below. But we don't have any way to
// return multiple results yet, hence the awkward duplication.
void HandleForceColorOption()
{
    var args = Args()


    while true
    {
        if StrStartsWith( args, "--noprelude" )
        {

            args = StrStripFirstSubStr( args )
            continue
        }

        if StrStartsWith( args, "--forcecolors" )
        {
            DiagnosticsForceColors( true )
            return
        }

        break
    }
}

bool HandleNoPreludeOption()
{
    var args = Args()

    while true
    {
        if StrStartsWith( args, "--noprelude" )
        {
            return true
        }

        if StrStartsWith( args, "--forcecolors" )
        {
            args = StrStripFirstSubStr( args )
            continue
        }

        return false
    }
}

ct_string GetFilename()
{
    var args = Args()

    while true
    {
        if StrStartsWith( args, "--noprelude" )
        {
            args = StrStripFirstSubStr( args )
            continue
        }

        if StrStartsWith( args, "--forcecolors" )
        {
            args = StrStripFirstSubStr( args )
            continue
        }

        return args
    }
}

HandleForceColorOption()

#if HandleNoPreludeOption()
{
    using IsCompiling = false
    return ExecuteFile( GetFilename() )
}
#else
{
    using IsCompiling = true
    return ExecuteFile( "lib/frontend.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



26



27

28





29





30

31




32


33
34



35

// This is the interpreted code entry point of the empathy
// command line tool.
//









// It parses the command line options

// and either execute the provided file directly
// or compile it by launching the frontend.






var args = Args()
bool noPrelude = false

while true
{
    if StrStartsWith( args, "--noprelude" )
    {
        noPrelude = true
        args = StrStripFirstSubStr( args )
        continue
    }

    if StrStartsWith( args, "--forcecolors" )
    {
        DiagnosticsForceColors( true )




















        args = StrStripFirstSubStr( args )
        continue
    }




    break



}







CreateConstant( "SourceToCompile", args )





CreateConstant( "IsCompiling", !noPrelude )






if noPrelude


    return ExecuteFile( args )




return ExecuteFile( "lib/frontend.em" )

Changes to lib/frontend.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
26
27
28
29
30
31
32
33
// The front-end.

// Its job, as of now, is to take the source file name from the command line,
// and compile it into an executable file of the same name, with the .out suffix.
//
// There is zero goal of portability yet, all of this is linux specific.
//
// It will become more sophisticated later on as library facilities become available
// and allow to implement more intelligence here.

using filename = GetFilename()

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

// 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( filename, 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










<
<

|











|







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
// The front-end.

// Its job, as of now, is to take the source file name from the command line,
// and compile it into an executable file of the same name, with the .out suffix.
//
// There is zero goal of portability yet, all of this is linux specific.
//
// It will become more sophisticated later on as library facilities become available
// and allow to implement more intelligence here.



// 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
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
    return 0
}

// Run the llvm optimization passes
CGModuleOptimize( module )

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

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

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

// Link it and produce an executable file.
var linkerArgs = (
    strcat( filename, ".o" ),
    "-o", strcat( filename, ".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( filename, ".out\n" ) ) )







|

|

|




|

|





|
|







|
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
    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" ) ) )
Changes to tests/noprelude/diagnostics/missing-closing-paren.em.
1
2
3
4
5
6
ExecuteFile( "tests/noprelude/helpers.em"

bool lomarf()
{
    return true
}
|





1
2
3
4
5
6
#Include( "tests/noprelude/helpers.em"

bool lomarf()
{
    return true
}
Changes to tests/noprelude/diagnostics/recursive-using.em.
1
2
3
4
5
6
ExecuteFile( "tests/noprelude/helpers.em" )

// Recursive using expression accross two files.
using SomeOtherThing = Laffo

SomeOtherThing
|





1
2
3
4
5
6
#Include( "tests/noprelude/helpers.em" )

// Recursive using expression accross two files.
using SomeOtherThing = Laffo

SomeOtherThing
Changes to tests/noprelude/diagnostics/template-instantiation-context.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

// This will cause an error in a template function that wasn't directly called,
// but instantiated by being passed as a function object. This generates a
// specific context message.

ct_string higherTpl( ct_string( $T s ) func, $T x )
{
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

// This will cause an error in a template function that wasn't directly called,
// but instantiated by being passed as a function object. This generates a
// specific context message.

ct_string higherTpl( ct_string( $T s ) func, $T x )
{
Changes to tests/noprelude/diagnostics/template-type-mismatch.em.
1
2
3
4
5
6
7
8
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 )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

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

ct_string someFunc( $T x )
Changes to tests/noprelude/execute/arithops.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

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

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

|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

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

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

Changes to tests/noprelude/execute/bitwiseops.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

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

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







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

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

if !assert( lomarf( 0xdeadbeef, 0xabadfeed ) == 0x75004002, "integer bitwise xor test" )
Changes to tests/noprelude/execute/comparisonops.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

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

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

|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

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

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

Changes to tests/noprelude/execute/compoundass.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

var lomarf = 219

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


|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

var lomarf = 219

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


Changes to tests/noprelude/execute/higher-func.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

ct_string higher( ct_string( ct_string s ) func )
{
    return func( "higher" )
}

ct_string someFunc( $T a )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

ct_string higher( ct_string( ct_string s ) func )
{
    return func( "higher" )
}

ct_string someFunc( $T a )
Changes to tests/noprelude/execute/higher-poly.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

ct_string higherPoly( ct_string( $T s ) $func )
{
    return strcat( strcat( $func( 123 ), ", " ), $func( "blah" ) )
}

ct_string someFunc( $T x )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

ct_string higherPoly( ct_string( $T s ) $func )
{
    return strcat( strcat( $func( 123 ), ", " ), $func( "blah" ) )
}

ct_string someFunc( $T x )
Changes to tests/noprelude/execute/higher-template.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

ct_string higherTpl( ct_string( $T s ) func, $T x )
{
    return strcat( "higher: ", func( x ) )
}

ct_string someFunc( $T x )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

ct_string higherTpl( ct_string( $T s ) func, $T x )
{
    return strcat( "higher: ", func( x ) )
}

ct_string someFunc( $T x )
Changes to tests/noprelude/execute/if.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

ct_string func1( bool b )
{
    if b return "lomarf"
    return "meh"
}

|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

ct_string func1( bool b )
{
    if b return "lomarf"
    return "meh"
}

Changes to tests/noprelude/execute/locvar.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

uint(32) lomarf = 219

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

if !assert( lomarf != 1337, "local variable test 2" )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

uint(32) lomarf = 219

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

if !assert( lomarf != 1337, "local variable test 2" )
Changes to tests/noprelude/execute/logicops.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

bool lomarf( bool a, bool b )
{
    return a | b;
}

bool blah( bool a, bool b )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

bool lomarf( bool a, bool b )
{
    return a | b;
}

bool blah( bool a, bool b )
Changes to tests/noprelude/execute/overloading.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

ct_string overloadedFunc()
{
    return "overload 1"
}

ct_string overloadedFunc( ct_string foo )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

ct_string overloadedFunc()
{
    return "overload 1"
}

ct_string overloadedFunc( ct_string foo )
Changes to tests/noprelude/execute/templates.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

ct_string tplTest1( $T a, $U b )
{
    return "different types"
}

ct_string tplTest1( $T a, $T b )
|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

ct_string tplTest1( $T a, $U b )
{
    return "different types"
}

ct_string tplTest1( $T a, $T b )
Changes to tests/noprelude/execute/using.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

using u1 = u2
using u2 = "test"

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

|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

using u1 = u2
using u2 = "test"

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

Changes to tests/noprelude/execute/while.em.
1
2
3
4
5
6
7
8
ExecuteFile( "tests/noprelude/helpers.em" )

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

|







1
2
3
4
5
6
7
8
#Include( "tests/noprelude/helpers.em" )

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