~eda-qa/leaflang/misc

« back to all changes in this revision

Viewing changes to src/runner/runner.cpp

  • Committer: edA-qa mort-ora-y
  • Date: 2017-07-22 19:48:13 UTC
  • mfrom: (99.1.41 error)
  • Revision ID: eda-qa@disemia.com-20170722194813-h3yqkhe1j2ouwga4
merging error handling

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "runner/runner.hpp"
 
2
#include "runner/expecter.hpp"
 
3
 
 
4
#include <boost/algorithm/string/predicate.hpp>
 
5
#include <boost/filesystem.hpp>
 
6
namespace fs = boost::filesystem;
 
7
 
 
8
#include <iostream>
 
9
#include <fstream>
 
10
 
 
11
#include <dlfcn.h>
 
12
#include <unistd.h>
 
13
 
 
14
// Root Leaf data files (these are generated files, in the build directory)
 
15
#include "runner/base.leaf.hpp"
 
16
 
 
17
#define SHOW_DEBUG 0
 
18
#include "util/debug.hpp"
 
19
 
 
20
shared_ptr<ir::module> runner::build_module() 
 
21
{
 
22
        shared_ptr<ir::module> m;
 
23
        try {
 
24
                STATE_CHECK( input_files.size() );
 
25
                auto & first_file = input_files[0];
 
26
                
 
27
                if( boost::ends_with( first_file, ".lfx" ) ) {
 
28
                        STATE_CHECK( input_files.size() == 1, "only one lfx file supported as input" );
 
29
                        m = get_expr();
 
30
                } else if( boost::ends_with( first_file, ".lfb" ) ) {
 
31
                        STATE_CHECK( input_files.size() == 1, "only one lfb file supported as input" );
 
32
                        m = get_block();
 
33
                } else if( boost::ends_with( first_file, ".leaf" ) ) {
 
34
                        m = get_full();
 
35
                } else {
 
36
                        STATE_FAIL( "unknown input-file type" );
 
37
                }
 
38
        } catch( recoverable_error & re ) {
 
39
                if( expect ) {
 
40
                        expect->catch_compile_exception(re);
 
41
                        return shared_ptr<ir::module>();
 
42
                }
 
43
                throw;
 
44
        }
 
45
        
 
46
        if( dump_ir ) {
 
47
                ir::dump d( std::cout );
 
48
                d.set_show_all_types( dump_ir_types );
 
49
                d.write( m.get() );
 
50
        }
 
51
        return m;
 
52
}
 
53
 
 
54
void runner::x_dump_parse( leaf::node const & n )
 
55
{
 
56
        if( dump_parse_flat )
 
57
                std::cout << leaf::node_dump::dump_flat(n) << std::endl;
 
58
                
 
59
        if( !dump_parse )
 
60
                return;
 
61
        
 
62
        leaf::node_dump nd( std::cout );
 
63
        nd.header( "// -- Parse Tree --" );
 
64
        nd.dump( n );
 
65
        std::cout << std::endl;
 
66
}
 
67
 
 
68
void runner::x_dump_post_type( leaf::module const & mod ) {
 
69
        if( !dump_post_type )
 
70
                return;
 
71
                
 
72
        std::cout << "// -- Post-Typing Leaf Tree --" << std::endl;
 
73
        leaf::dump d( std::cout );
 
74
        d.set_show_all_types( dump_all_types );
 
75
        d.write_module( mod );
 
76
}
 
77
 
 
78
void runner::x_dump_pre_type( std::vector<shared_ptr<leaf::statement>> const & sb )
 
79
{
 
80
        if( !dump_pre_type )
 
81
                return;
 
82
                
 
83
        std::cout << "// -- Pre-Typing Leaf Tree --" << std::endl;
 
84
        leaf::dump d( std::cout );
 
85
        d.set_show_spec_type( true );
 
86
        d.set_validate( false );
 
87
        for( auto & s : sb ) {
 
88
                d.write_statement( *s );
 
89
                d.line_break();
 
90
        }
 
91
        std::cout << std::endl;
 
92
}
 
93
 
 
94
shared_ptr<leaf::expression> runner::parse_expr( std::string const & expr )
 
95
{
 
96
        auto src = leaf::source::create( expr );
 
97
 
 
98
        shared_ptr<leaf::node> n = leaf::node_parser::parse_single( *src );
 
99
        x_dump_parse( *n );
 
100
        
 
101
        auto ex = leaf::node_converter::expression_convert( *n );
 
102
        if( dump_pre_type )
 
103
        {
 
104
                leaf::dump d( std::cout );
 
105
                d.set_show_spec_type( true );
 
106
                d.set_validate( false );
 
107
                d.write( ex );
 
108
                std::cout << std::endl;
 
109
        }
 
110
        
 
111
        //the expression must be converted to its inferred type to ensure it is representable as
 
112
        //an actual compiled type (such as removing rationals)
 
113
        ex = module_typer->full_type( ex, leaf::typer::tef_convert_inferred );
 
114
        
 
115
        if( dump_post_type ) {
 
116
                leaf::dump d( std::cout );
 
117
                d.set_show_all_types( dump_all_types );
 
118
                d.write( ex );
 
119
                std::cout << std::endl;
 
120
        }
 
121
 
 
122
        return ex;
 
123
}
 
124
 
 
125
runner::statement_vector_t runner::load_parse_block( std::string const & filename, 
 
126
        leaf::scope_style_t scope_style, bool dump ) {
 
127
        DEBUG( "Block-Load", filename );
 
128
        auto s = leaf::source::create( util::load_file( filename ) );
 
129
        s->set_name( filename );
 
130
        
 
131
        return load_parse_block( s, scope_style, dump);
 
132
}
 
133
 
 
134
runner::statement_vector_t runner::load_parse_block( shared_ptr<leaf::source> src,
 
135
        leaf::scope_style_t scope_style, bool dump ) {
 
136
        
 
137
        DEBUG( "Block-Parse" );
 
138
        auto n = leaf::node_parser::parse_as_block( *src );
 
139
        DEBUG( "Block-Parse-Dump" );
 
140
        if( dump ) {
 
141
                x_dump_parse( *n );
 
142
        }
 
143
        DEBUG( "Block-Post-Parse" );
 
144
        
 
145
        auto block = leaf::node_converter::convert_block( *n, scope_style );
 
146
        if( dump ) {
 
147
                x_dump_pre_type( block );
 
148
        }
 
149
        DEBUG( "Block-Post-Convert" );
 
150
        
 
151
        return block;
 
152
}
 
153
 
 
154
void runner::do_typing( bool base )
 
155
{
 
156
        module_typer->full_complete_type();
 
157
        
 
158
        if( !base || dump_base ) {
 
159
                x_dump_post_type( *module );
 
160
        }
 
161
        
 
162
        if( !base && list_functions ) {
 
163
                std::cout <<  "Function List" << std::endl;
 
164
                for( auto & fd : module->funcdefns ) {
 
165
                        std::string name = fd->bound_decl ? fd->bound_decl->symbol : "anonymous";
 
166
                        std::cout << name << " : " << leaf::dump::get( fd->type ) << std::endl;
 
167
                }
 
168
        }
 
169
}
 
170
 
 
171
void runner::init_module() {
 
172
        module_typer = make_shared<leaf::typer>( module_name, mloader );
 
173
        module = module_typer->get_module();
 
174
 
 
175
        add_base_block( create_string_source("base.leaf",dataBaseLeaf) );
 
176
}
 
177
 
 
178
void runner::add_base_block( shared_ptr<leaf::source> src ) {
 
179
        auto list = load_parse_block( src, leaf::scope_style_t::declarative, false );
 
180
        auto block = module_typer->add_root_block( list );
 
181
        block->reference_text = src->get_name();
 
182
        do_typing(true);
 
183
}
 
184
 
 
185
shared_ptr<ir::module> runner::get_expr() {
 
186
        shared_ptr<leaf::expression> ex = parse_expr( util::load_file( input_files.at(0) ) );
 
187
        ir::compiler_leaf c( module->global );
 
188
        
 
189
        shared_ptr<ir::module> m = c.compile_expr( *ex );
 
190
        auto f = m->if_get_function( "eval_expr" );
 
191
        PRE_CHECK(f);
 
192
        main_trace_function( c, f );
 
193
 
 
194
        return m;
 
195
}
 
196
 
 
197
shared_ptr<ir::module> runner::get_block()
 
198
{
 
199
        auto list = load_parse_block( input_files.at(0),        leaf::scope_style_t::dynamic );
 
200
        auto block = module_typer->add_dynamic_block( list );
 
201
        do_typing();
 
202
        
 
203
        ir::compiler_leaf c( module->global );
 
204
        return c.compile_block( *block, *module->static_init_block );
 
205
}
 
206
 
 
207
shared_ptr<ir::module> runner::get_full() {
 
208
 
 
209
        for( auto & file : input_files ) {
 
210
                auto list = load_parse_block( file, leaf::scope_style_t::declarative );
 
211
                auto block = module_typer->add_global_block( list );
 
212
                block->reference_text = file;
 
213
        }
 
214
        do_typing();
 
215
 
 
216
        ir::compiler_leaf c( module->global );
 
217
        return c.compile_module( *module );
 
218
}
 
219
 
 
220
int runner::execute( shared_ptr<ir::module> m ) {
 
221
        //load explicit libraries (mainly for testing)
 
222
        std::vector<void*> lib_handles;
 
223
        auto load_lib = [&]( std::string const & path ) {
 
224
                auto handle = dlopen( path.c_str(), RTLD_NOW | RTLD_GLOBAL );
 
225
                STATE_CHECK( handle, std::string( "failed loading library: " )
 
226
                        + path + ": " + dlerror() );
 
227
                lib_handles.push_back( handle );
 
228
        };
 
229
        
 
230
        for( auto & lib : libraries ) {
 
231
                load_lib( lib );
 
232
        }
 
233
        //load imported libraries
 
234
        for( auto & lib : module->libraries ) {
 
235
                load_lib( mloader->resolve_dynload(lib) );
 
236
        }
 
237
 
 
238
        //setup capturing of stdout
 
239
        volatile int old_stdout = 0; //GCC: complains it will get clobbered by longjmp without volatile
 
240
        char out_filename[128] = "/tmp/output_XXXXXX";
 
241
        if( capture_stdout ) {
 
242
                old_stdout = dup(STDOUT_FILENO);
 
243
                int out_file = mkstemp(out_filename);
 
244
                fflush( stdout );
 
245
                
 
246
                dup2( out_file, STDOUT_FILENO );
 
247
        }
 
248
        
 
249
        auto end_redirect = [&]() {
 
250
                if( !old_stdout ) {
 
251
                        return;
 
252
                }
 
253
                
 
254
                fflush( stdout );
 
255
                dup2(old_stdout, STDOUT_FILENO);
 
256
        };
 
257
        auto clean_redirect = [&]() {
 
258
                unlink(out_filename);
 
259
        };
 
260
        
 
261
        //volatile to not be clobberd by setjmp/longjmp
 
262
        volatile int return_value = 0;
 
263
        
 
264
        try {
 
265
                jmp_buf abort_point;
 
266
                int i = setjmp(abort_point);
 
267
                if( i ) {
 
268
                        end_redirect();
 
269
                        if( !expect || !expect->catch_runtime_abort( runtime_test::get_error() ) ) {
 
270
                                throw recoverable_error( std::string( "abort: " ) + runtime_test::get_error() );
 
271
                        }
 
272
                } else {
 
273
                        runtime_test::prepare( &abort_point );
 
274
                        ir_llvm::gen lg( gen_opts );
 
275
                        int rv = lg.execute( *m, dump_llvm );
 
276
                        end_redirect();
 
277
                        
 
278
                        runtime_test::check_state();
 
279
                        if( expect ) {
 
280
                                std::string output = runtime_test::get_trace();
 
281
                                if( old_stdout ) {
 
282
                                        output = util::load_file( out_filename );
 
283
                                }
 
284
                                //DEBUG( "OUTPUT:", output );
 
285
                                expect->check_result( output, rv );
 
286
                        } else {
 
287
                                return_value = rv;
 
288
                        }
 
289
                }
 
290
                
 
291
                clean_redirect();
 
292
        } catch( ... ) {
 
293
                end_redirect();
 
294
                clean_redirect();
 
295
                throw;
 
296
        }
 
297
        
 
298
        return return_value;
 
299
}
 
300
 
 
301
void runner::emit_object( shared_ptr<ir::module> m, std::string const & path_base, gen_what_t gw )
 
302
{
 
303
        ir_llvm::gen lg( gen_opts );
 
304
        lg.emit_object( *m, path_base, dump_llvm );
 
305
        
 
306
        if( gw == gw_shared ) {
 
307
        #if defined(IS_DARWIN)
 
308
                std::string cmd( "gcc -dynamiclib -Wl,-undefined,dynamic_lookup,-o," );
 
309
                cmd += mloader->dyn_name(path_base) + ",-init,"
 
310
                        + "_" + *module_name + platform::export_sep + "_init_module"
 
311
                        //there just is no "fini" on OSX!
 
312
                        //+ " " + mloader->resolve_dyn_core( "runtime" )
 
313
                        + " " + mloader->obj_name(path_base);
 
314
        #else
 
315
                std::string cmd( "gcc -shared -Wl,--eh-frame-hdr,--build-id,--export-dynamic,-o," );
 
316
                cmd += path_base + ".so,-init,"
 
317
                        + *module_name + platform::export_sep + "_init_module,-fini,"
 
318
                        + *module_name + platform::export_sep + "_final_module"
 
319
                        //+ " " + mloader->resolve_dyn_core( "runtime" )
 
320
                        + "," + path_base + ".o";
 
321
        #endif
 
322
        
 
323
        #if 0
 
324
                //These work, but don't produce proper shared libraries (ldd says statically linked) (they also don't
 
325
                //contain the shared library dependencies)
 
326
                std::string cmd( "ld --eh-frame-hdr --build-id --export-dynamic -shared -o " );
 
327
                cmd += path_base + ".so -init "
 
328
                        + *module_name + platform::export_sep + "_init_module -fini "
 
329
                        + *module_name + platform::export_sep + "_final_module"
 
330
                        //+ " " + mloader->resolve_dyn_core( "runtime" )
 
331
                        + " " + path_base + ".o";
 
332
        #endif
 
333
        
 
334
                for( auto & lib : module->libraries ) {
 
335
                        cmd = cmd + " " + mloader->resolve_dynlink( lib );
 
336
                }
 
337
                int ret = std::system( cmd.c_str() );
 
338
                STATE_CHECK( ret == 0, cmd );
 
339
        } else if( gw == gw_exe ) {
 
340
        #if defined(IS_DARWIN)
 
341
                std::string cmd( "gcc -Wl -o " );
 
342
                cmd += path_base + " " + mloader->obj_name(path_base)
 
343
                        //+ " " + mloader->resolve_static_core( "runtime_support" )
 
344
                        + " " + mloader->resolve_dyn_core( "runtime" )
 
345
                        ;
 
346
        #else
 
347
                //NOTE: switch to g++ for rare debugging needs with iostream
 
348
                std::string cmd( "gcc -Wl,--eh-frame-hdr,--build-id,--export-dynamic -o " );
 
349
                cmd += path_base + " " + path_base + ".o"
 
350
                        + " " + mloader->resolve_static_core( "runtime_support" )
 
351
                        //+ " " + mloader->resolve_dyn_core( "runtime" )
 
352
                        ;
 
353
        #endif
 
354
                        
 
355
                for( auto & lib : module->libraries ) {
 
356
                        cmd = cmd + " " + mloader->resolve_dynlink( lib );
 
357
                }
 
358
                
 
359
                int ret = std::system( cmd.c_str() );
 
360
                STATE_CHECK( ret == 0, cmd );
 
361
        }
 
362
 
 
363
        if( gw == gw_shared ) {
 
364
                //detach scope and create leaf object file (this breaks the module!)
 
365
                module->global->detach_base();
 
366
                std::ofstream lo( mloader->leaflib_name(path_base), std::ios::binary );
 
367
                leaf::serial_out sout( lo, module_typer->get_serial_resolver() );
 
368
                sout.set_is_exporting();
 
369
                sout.write_key_ref( leaf::serial_item::t_root, module->global );
 
370
                for( auto & ex : module->var_exports ) {
 
371
                        sout.add_declaration( ex );
 
372
                }
 
373
                for( auto & ex : module->type_exports ) {
 
374
                        sout.add_intr_type( ex );
 
375
                }
 
376
                sout.done();
 
377
        }
 
378
}
 
379
 
 
380
//TODO: more of a util function
 
381
shared_ptr<leaf::source> runner::create_string_source( std::string const & name, std::string const & content ) {
 
382
        auto s = leaf::source::create( content );
 
383
        s->set_name( name );
 
384
        return s;
 
385
}