Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: |
|
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
f1cab5f761a024358c1e7fab475d3881 |
| 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 |
| |
| 13:42 | Factored out the common code of Compiler::execute(), ExecuteFile() and #CompileFileToFunction(). check-in: 0c5641877d user: achavasse tags: trunk | |
Changes
Changes to bs/builtins/api/compiler.cpp.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 |
[pEnv]( uint32_t budget )
{
static bool used = false;
if( used )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
| | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | | | 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 |
#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( _ ) ) ),
| > > < < < < < < < < < < | | | | 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 |
format( "{}: can not be executed.", filename ) );
return PoisonValue();
}
execute::VM vm;
return vm.execute( cfg->entryBB() );
}
| < | 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 | // This is the interpreted code entry point of the empathy // command line tool. // | < < < < < < < < < | < | | < < < < < < | > | | | | > | | | | | | < < < < < < < < < < < < < < < < < < < < | | | < < < | < < < | < | < < < < < | < < < < < | < | < < < < | < < | | < < < | < | 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 | // 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. | < < | | | 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 |
return 0
}
// Run the llvm optimization passes
CGModuleOptimize( module )
// Output the llvm ir and the asm for inspection.
| | | | | | | | | | 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 |
#Include( "tests/noprelude/helpers.em"
bool lomarf()
{
return true
}
|
Changes to tests/noprelude/diagnostics/recursive-using.em.
|
| | | 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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#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 |
#Include( "tests/noprelude/helpers.em" )
var i = 0
while( i < 10 )
{
i += 1
}
|
| ︙ | ︙ |