*** empty log message ***
[chuck-blob.git] / v2 / chuck_compile.cpp
blob228f2fb1e0a11966ffbb52ce151c1c8f5a3f5eef
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: chuck_compile.cpp
27 // desc: chuck compile system unifying parser, type checker, and emitter
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // date: Autumn 2005 - original
32 //-----------------------------------------------------------------------------
33 #include "chuck_compile.h"
34 #include "chuck_lang.h"
35 #include "chuck_errmsg.h"
36 #include "chuck_otf.h"
38 #include "ugen_osc.h"
39 #include "ugen_xxx.h"
40 #include "ugen_filter.h"
41 #include "ugen_stk.h"
42 #include "uana_xform.h"
43 #include "uana_extract.h"
44 #include "ulib_machine.h"
45 #include "ulib_math.h"
46 #include "ulib_std.h"
47 #include "ulib_opsc.h"
49 using namespace std;
54 // function prototypes
55 t_CKBOOL load_internal_modules( Chuck_Compiler * compiler );
56 t_CKBOOL load_module( Chuck_Env * env, f_ck_query query, const char * name, const char * nspc );
61 //-----------------------------------------------------------------------------
62 // name: Chuck_Compiler()
63 // desc: constructor
64 //-----------------------------------------------------------------------------
65 Chuck_Compiler::Chuck_Compiler()
67 env = NULL;
68 emitter = NULL;
69 code = NULL;
75 //-----------------------------------------------------------------------------
76 // name: ~Chuck_Compiler()
77 // desc: destructor
78 //-----------------------------------------------------------------------------
79 Chuck_Compiler::~Chuck_Compiler()
81 // call shutdown
82 this->shutdown();
88 //-----------------------------------------------------------------------------
89 // name: initialize()
90 // desc: initialize the compiler
91 //-----------------------------------------------------------------------------
92 t_CKBOOL Chuck_Compiler::initialize( Chuck_VM * vm )
94 // log
95 EM_log( CK_LOG_SYSTEM, "initializing compiler..." );
96 // push indent level
97 EM_pushlog();
99 // allocate the type checker
100 env = type_engine_init( vm );
101 // add reference
102 env->add_ref();
104 // allocate the emitter
105 emitter = emit_engine_init( env );
106 // add reference
107 emitter->add_ref();
108 // set auto depend to 0
109 m_auto_depend = FALSE;
111 // load internal libs
112 if( !load_internal_modules( this ) )
113 goto error;
115 // pop indent
116 EM_poplog();
118 return TRUE;
120 error:
121 // clean up
122 this->shutdown();
124 // pop indent
125 EM_poplog();
127 return FALSE;
133 //-----------------------------------------------------------------------------
134 // name: shutdown()
135 // desc: shutdown the compiler
136 //-----------------------------------------------------------------------------
137 void Chuck_Compiler::shutdown()
139 // log
140 EM_log( CK_LOG_SYSTEM, "shutting down compiler..." ) ;
141 // push indent
142 EM_pushlog();
144 // TODO: free
145 type_engine_shutdown( env );
146 // emit_engine_shutdown( emitter );
147 env = NULL;
148 emitter = NULL;
149 code = NULL;
150 m_auto_depend = FALSE;
151 m_recent.clear();
153 // pop indent
154 EM_poplog();
160 //-----------------------------------------------------------------------------
161 // name: set_auto_depend()
162 // desc: auto dependency resolve for types
163 //-----------------------------------------------------------------------------
164 void Chuck_Compiler::set_auto_depend( t_CKBOOL v )
166 // log
167 EM_log( CK_LOG_SYSTEM, "type dependency resolution: %s",
168 v ? "AUTO" : "MANUAL" );
169 m_auto_depend = v;
175 //-----------------------------------------------------------------------------
176 // name: go()
177 // desc: parse, type-check, and emit a program
178 //-----------------------------------------------------------------------------
179 t_CKBOOL Chuck_Compiler::go( const string & filename, FILE * fd, const char * str_src )
181 t_CKBOOL ret = TRUE;
182 Chuck_Context * context = NULL;
184 // check to see if resolve dependencies automatically
185 if( !m_auto_depend )
187 // normal
188 ret = this->do_normal( filename, fd, str_src );
189 return ret;
191 else // auto
193 // parse the code
194 if( !chuck_parse( filename.c_str(), fd, str_src ) )
195 return FALSE;
197 // make the context
198 context = type_engine_make_context( g_program, filename );
199 if( !context ) return FALSE;
201 // reset the env
202 env->reset();
204 // load the context
205 if( !type_engine_load_context( env, context ) )
206 return FALSE;
208 // do entire file
209 if( !do_entire_file( context ) )
210 { ret = FALSE; goto cleanup; }
212 // get the code
213 if( !(code = context->code()) )
215 ret = FALSE;
216 EM_error2( 0, "internal error: context->code() NULL!" );
217 goto cleanup;
220 cleanup:
222 // commit
223 if( ret ) env->global()->commit();
224 // or rollback
225 else env->global()->rollback();
227 // unload the context from the type-checker
228 if( !type_engine_unload_context( env ) )
230 EM_error2( 0, "internal error unloading context...\n" );
231 return FALSE;
234 return ret;
241 //-----------------------------------------------------------------------------
242 // name: resolve()
243 // desc: resolve type automatically - if auto_depend is off, return FALSE
244 //-----------------------------------------------------------------------------
245 t_CKBOOL Chuck_Compiler::resolve( const string & type )
247 t_CKBOOL ret = TRUE;
249 // check auto_depend
250 if( !m_auto_depend )
251 return FALSE;
253 // look up if name is already parsed
257 return ret;
263 //-----------------------------------------------------------------------------
264 // name: do_entire_file()
265 // desc: parse, type-check, and emit a program
266 //-----------------------------------------------------------------------------
267 t_CKBOOL Chuck_Compiler::do_entire_file( Chuck_Context * context )
269 // 0th-scan (pass 0)
270 if( !type_engine_scan0_prog( env, g_program, te_do_all ) )
271 return FALSE;
273 // 1st-scan (pass 1)
274 if( !type_engine_scan1_prog( env, g_program, te_do_all ) )
275 return FALSE;
277 // 2nd-scan (pass 2)
278 if( !type_engine_scan2_prog( env, g_program, te_do_all ) )
279 return FALSE;
281 // check the program (pass 3)
282 if( !type_engine_check_context( env, context, te_do_all ) )
283 return FALSE;
285 // emit (pass 4)
286 if( !emit_engine_emit_prog( emitter, g_program ) )
287 return FALSE;
289 // set the state of the context to done
290 context->progress = Chuck_Context::P_ALL;
292 return TRUE;
298 //-----------------------------------------------------------------------------
299 // name: do_only_classes()
300 // desc: compile only classes definitions
301 //-----------------------------------------------------------------------------
302 t_CKBOOL Chuck_Compiler::do_only_classes( Chuck_Context * context )
304 // 0th-scan (pass 0)
305 if( !type_engine_scan0_prog( env, g_program, te_do_classes_only ) )
306 return FALSE;
308 // 1st-scan (pass 1)
309 if( !type_engine_scan1_prog( env, g_program, te_do_classes_only ) )
310 return FALSE;
312 // 2nd-scan (pass 2)
313 if( !type_engine_scan2_prog( env, g_program, te_do_classes_only ) )
314 return FALSE;
316 // check the program (pass 3)
317 if( !type_engine_check_context( env, context, te_do_classes_only ) )
318 return FALSE;
320 // emit (pass 4)
321 if( !(code = emit_engine_emit_prog( emitter, g_program , te_do_classes_only )) )
322 return FALSE;
324 // set the state of the context to done
325 context->progress = Chuck_Context::P_ALL;
327 return TRUE;
333 //-----------------------------------------------------------------------------
334 // name: do_all_except_classes()
335 // desc: compile everything except classes
336 //-----------------------------------------------------------------------------
337 t_CKBOOL Chuck_Compiler::do_all_except_classes( Chuck_Context * context )
339 // 0th scan only deals with classes, so is not needed
341 // 1st-scan (pass 1)
342 if( !type_engine_scan1_prog( env, g_program, te_do_no_classes ) )
343 return FALSE;
345 // 2nd-scan (pass 2)
346 if( !type_engine_scan2_prog( env, g_program, te_do_no_classes ) )
347 return FALSE;
349 // check the program (pass 3)
350 if( !type_engine_check_context( env, context, te_do_no_classes ) )
351 return FALSE;
353 // emit (pass 4)
354 if( !(code = emit_engine_emit_prog( emitter, g_program, te_do_no_classes )) )
355 return FALSE;
357 // set the state of the context to done
358 context->progress = Chuck_Context::P_ALL;
360 return TRUE;
366 //-----------------------------------------------------------------------------
367 // name: do_normal()
368 // desc: compile normally without auto-depend
369 //-----------------------------------------------------------------------------
370 t_CKBOOL Chuck_Compiler::do_normal( const string & filename, FILE * fd, const char * str_src )
372 t_CKBOOL ret = TRUE;
373 Chuck_Context * context = NULL;
375 // parse the code
376 if( !chuck_parse( filename.c_str(), fd, str_src ) )
377 return FALSE;
379 // make the context
380 context = type_engine_make_context( g_program, filename );
381 if( !context ) return FALSE;
383 // reset the env
384 env->reset();
386 // load the context
387 if( !type_engine_load_context( env, context ) )
388 return FALSE;
390 // 0th-scan (pass 0)
391 if( !type_engine_scan0_prog( env, g_program, te_do_all ) )
392 { ret = FALSE; goto cleanup; }
394 // 1st-scan (pass 1)
395 if( !type_engine_scan1_prog( env, g_program, te_do_all ) )
396 { ret = FALSE; goto cleanup; }
398 // 2nd-scan (pass 2)
399 if( !type_engine_scan2_prog( env, g_program, te_do_all ) )
400 { ret = FALSE; goto cleanup; }
402 // check the program (pass 3)
403 if( !type_engine_check_context( env, context, te_do_all ) )
404 { ret = FALSE; goto cleanup; }
406 // emit (pass 4)
407 if( !(code = emit_engine_emit_prog( emitter, g_program, te_do_all )) )
408 { ret = FALSE; goto cleanup; }
410 cleanup:
412 // commit
413 if( ret ) env->global()->commit();
414 // or rollback
415 else env->global()->rollback();
417 // unload the context from the type-checker
418 if( !type_engine_unload_context( env ) )
420 EM_error2( 0, "internal error unloading context...\n" );
421 return FALSE;
424 return ret;
430 //-----------------------------------------------------------------------------
431 // name: find_recent_path()
432 // desc: find recent context by path
433 //-----------------------------------------------------------------------------
434 Chuck_Context * Chuck_Compiler::find_recent_path( const string & path )
436 return NULL;
442 //-----------------------------------------------------------------------------
443 // name: find_recent_type()
444 // desc: find recent context by type name
445 //-----------------------------------------------------------------------------
446 Chuck_Context * Chuck_Compiler::find_recent_type( const string & type )
448 return NULL;
454 //-----------------------------------------------------------------------------
455 // name: add_recent_path()
456 // desc: add recent context by path
457 //-----------------------------------------------------------------------------
458 t_CKBOOL Chuck_Compiler::add_recent_path( const string & path,
459 Chuck_Context * context )
461 return TRUE;
467 //-----------------------------------------------------------------------------
468 // name: output()
469 // desc: get the code generated by the last do()
470 //-----------------------------------------------------------------------------
471 Chuck_VM_Code * Chuck_Compiler::output()
473 return this->code;
479 //-----------------------------------------------------------------------------
480 // name: load_module()
481 // desc: load a dll and add it
482 //-----------------------------------------------------------------------------
483 t_CKBOOL load_module( Chuck_Env * env, f_ck_query query,
484 const char * name, const char * nspc )
486 Chuck_DLL * dll = NULL;
487 t_CKBOOL query_failed = FALSE;
489 // load osc
490 dll = new Chuck_DLL( name );
491 if( !dll->load( query ) || (query_failed = !dll->query()) ||
492 !type_engine_add_dll( env, dll, nspc ) )
494 fprintf( stderr,
495 "[chuck]: internal error loading module '%s.%s'...\n",
496 nspc, name );
497 if( query_failed )
498 fprintf( stderr, " %s\n", dll->last_error() );
500 return FALSE;
503 return TRUE;
509 //-----------------------------------------------------------------------------
510 // name: load_internal_modules()
511 // desc: ...
512 //-----------------------------------------------------------------------------
513 t_CKBOOL load_internal_modules( Chuck_Compiler * compiler )
515 // log
516 EM_log( CK_LOG_SEVERE, "loading built-in modules..." );
517 // push indent level
518 EM_pushlog();
520 // get env
521 Chuck_Env * env = compiler->env;
522 // make context
523 Chuck_Context * context = type_engine_make_context( NULL, "@[internal]" );
524 // reset env - not needed since we just created the env
525 env->reset();
526 // load it
527 type_engine_load_context( env, context );
529 // load
530 EM_log( CK_LOG_SEVERE, "module osc..." );
531 load_module( env, osc_query, "osc", "global" );
532 EM_log( CK_LOG_SEVERE, "module xxx..." );
533 load_module( env, xxx_query, "xxx", "global" );
534 EM_log( CK_LOG_SEVERE, "module filter..." );
535 load_module( env, filter_query, "filter", "global" );
536 EM_log( CK_LOG_SEVERE, "module STK..." );
537 load_module( env, stk_query, "stk", "global" );
538 EM_log( CK_LOG_SEVERE, "module xform..." );
539 load_module( env, xform_query, "xform", "global" );
540 EM_log( CK_LOG_SEVERE, "module extract..." );
541 load_module( env, extract_query, "extract", "global" );
543 // load
544 EM_log( CK_LOG_SEVERE, "class 'machine'..." );
545 if( !load_module( env, machine_query, "Machine", "global" ) ) goto error;
546 machine_init( compiler, otf_process_msg );
547 EM_log( CK_LOG_SEVERE, "class 'std'..." );
548 if( !load_module( env, libstd_query, "Std", "global" ) ) goto error;
549 EM_log( CK_LOG_SEVERE, "class 'math'..." );
550 if( !load_module( env, libmath_query, "Math", "global" ) ) goto error;
551 EM_log( CK_LOG_SEVERE, "class 'opsc'..." );
552 if( !load_module( env, opensoundcontrol_query, "opsc", "global" ) ) goto error;
553 // if( !load_module( env, net_query, "net", "global" ) ) goto error;
555 #ifndef __DISABLE_MIDI__
556 if( !init_class_Midi( env ) ) goto error;
557 if( !init_class_MidiRW( env ) ) goto error;
558 #endif // __DISABLE_MIDI__
559 if( !init_class_HID( env ) ) goto error;
561 // clear context
562 type_engine_unload_context( env );
564 // commit what is in the type checker at this point
565 env->global()->commit();
567 // pop indent level
568 EM_poplog();
570 return TRUE;
572 error:
574 // probably dangerous: rollback
575 env->global()->rollback();
577 // clear context
578 type_engine_unload_context( env );
580 // pop indent level
581 EM_poplog();
583 return FALSE;