Newer
Older
#include "bc_compiler.h"
#include <assert.h>
void string_init ( String * str ) {
str -> str = (u8*) malloc ( INIT_STRING_LENGTH );
}
void string_destroy ( String * str ) {
free ( str -> str );
}
void string_write_byte ( String * str, const u8 data ) {
if ( str -> capacity == str -> len ) {
u8 * tmp = (u8*) malloc ( str -> capacity * 2 );
assert ( tmp );
memcpy ( tmp, str -> str, str -> len );
free ( str -> str );
str -> str = tmp;
str -> capacity *= 2;
}
str -> str [ str -> len ++ ] = data;
}
void string_write_u16 ( String * str, const u16 data ) {
string_write_byte ( str, data & 255 );
string_write_byte ( str, data >> 8 );
}
void string_write_i32 ( String * str, const i32 data ) {
string_write_byte ( str, data & 255 );
string_write_byte ( str, (data >> 8) & 255 );
string_write_byte ( str, (data >> 16) & 255 );
string_write_byte ( str, (data >> 24) & 255 );
}
void string_write_constant ( String * str, BCConstant constant ) {
switch ( constant . kind ) {
case CONSTANT_NULL:
string_write_byte ( str, 0x01 );
break;
case CONSTANT_BOOLEAN:
string_write_byte ( str, 0x04 );
string_write_byte ( str, constant . boolean ? 0x01 : 0x00 );
break;
case CONSTANT_INTEGER:
string_write_byte ( str, 0x00 );
string_write_i32 ( str, constant . integer );
break;
case CONSTANT_STRING:
string_write_byte ( str, 0x02 );
string_write_i32 ( str, constant . string . len );
for ( size_t i = 0; i < constant . string . len; ++i )
string_write_byte ( str, constant . string . str [ i ] );
break;
case CONSTANT_FUNCTION: {
string_write_byte ( str, 0x03 );
string_write_byte ( str, constant . function . parameters );
string_write_u16 ( str, constant . function . locals );
string_write_i32 ( str, constant . function . bc . len );
for ( size_t i = 0; i < constant . function . bc . len; ++i )
string_write_byte ( str, constant . function . bc . str [ i ] );
Michal Štěpánek
committed
case CONSTANT_CLASS: {
string_write_byte ( str, 0x05 );
string_write_u16 ( str, constant . class . fields );
for ( size_t i = 0; i < constant . class . fields; ++i )
string_write_u16 ( str, constant . class . indexes [ i ] );
break;
}
default:
assert ( false );
break;
}
}
BCConstant create_function ( u8 parameters ) {
BCFunction function = (BCFunction) { .parameters = parameters, .locals = 0 };
string_init ( & function . bc );
return (BCConstant) { .kind = CONSTANT_FUNCTION, .function = function };
}
LocalScope * create_function_scope ( u8 parameters ) {
LocalScope * scope = (LocalScope*) malloc ( sizeof (LocalScope*) + 2 * sizeof (u16) + sizeof (Str) * ( parameters + MAX_SCOPE_VARIABLES ) );
scope -> locals [ 0 ] = STR ( "this" );
scope -> used_locals = 1;
return scope;
}
void add_scope ( BCCompilerState * state ) {
LocalScope * scope = (LocalScope*) malloc ( sizeof (LocalScope*) + 2 * sizeof (u16) + sizeof (Str) * MAX_SCOPE_VARIABLES );
scope -> local_count = state -> scope -> local_count;
scope -> used_locals = 0;
scope -> prev = state -> scope;
state -> scope = scope;
}
void remove_scope ( BCCompilerState * state ) {
LocalScope * scope = state -> scope;
state -> scope = scope -> prev;
free ( scope );
}
void convert_function_to_bc ( BCCompilerState * state, u16 index ) {
BCConstant * this_constant = & state -> constants . constants [ index ];
AstFunction * func = (AstFunction*) this_constant -> ast;
LocalScope * old_scope = state -> scope;
*this_constant = create_function ( func -> parameter_cnt + 1 );
u16 old_fp = state -> fp;
state -> fp = index;
state -> scope = create_function_scope ( func -> parameter_cnt + 1 );
state -> scope -> prev = state -> top;
state -> scope -> used_locals = func -> parameter_cnt + 1;
state -> scope -> local_count = func -> parameter_cnt + 1;
for ( u16 i = 1; i < func -> parameter_cnt + 1; ++i )
state -> scope -> locals [ i ] = func -> parameters [ i - 1 ];
ast_to_bc ( state, func -> body );
free ( state -> scope );
string_write_byte ( & this_constant -> function . bc, 0x0F );
state -> scope = old_scope;
state -> fp = old_fp;
}
u16 get_string_index ( BCCompilerState * state, Str str ) {
u16 i;
for ( i = 0; i < state -> constants . constant_count; ++i )
if ( state -> constants . constants [ i ] . kind == CONSTANT_STRING && str_eq ( state -> constants . constants [ i ] . string, str ) )
return 0;
}
u16 make_string_index ( BCCompilerState * state, Str str ) {
insert_constant ( state, (BCConstant) { .kind = CONSTANT_STRING, .string = str } );
return state -> constants . constant_count - 1;
u16 get_local_index ( BCCompilerState * state, Str name ) {
LocalScope * scope = state -> scope;
size_t i;
while ( scope ) {
for ( i = 0; i < scope -> used_locals; ++i )
if ( str_eq ( scope -> locals [ i ], name ) )
return scope -> local_count - scope -> used_locals + i;
// return scope -> prev ? scope -> prev -> local_count + i: i;
scope = scope -> prev;
}
}
u16 make_local_index ( BCCompilerState * state, Str name ) {
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
u16 * n = & state -> scope -> local_count;
assert ( *n != 256 * 256 );
state -> scope -> locals [ state -> scope -> used_locals ] = (Str) { .len = name . len, .str = name . str };
++(*n);
++(state -> scope -> used_locals);
if ( *n - function -> parameters > function -> locals ) {
function -> locals = *n - function -> parameters;
}
return *n - 1;
Michal Štěpánek
committed
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
u16 get_or_make_class ( BCCompilerState * state, AstObject * object ) {
size_t i;
// create class
BCClass created_class = (BCClass) { .fields = object -> member_cnt, .indexes = (u16*) malloc ( sizeof (u16) * object -> member_cnt ) };
AstDefinition * def;
u16 index;
for ( size_t field = 0; field < created_class . fields; ++field ) {
assert ( object -> members [ field ] -> kind == AST_DEFINITION );
def = (AstDefinition*) object -> members [ field ];
index = get_string_index ( state, def -> name );
if ( index == 0 )
index = make_string_index ( state, def -> name );
created_class . indexes [ field ] = index;
for ( size_t prev = 0; prev < field; ++prev )
assert ( ! str_eq ( state -> constants . constants [ created_class . indexes [ prev ] ] . string, state -> constants . constants [ index ] . string ) );
}
// try to find same class as created
for ( i = 0; i < state -> constants . constant_count; ++i )
if ( state -> constants . constants [ i ] . kind == CONSTANT_CLASS ) {
BCClass class = state -> constants . constants [ i ] . class;
if ( class . fields == created_class . fields )
for ( size_t j = 0; j < class . fields; ++j ) {
if ( created_class . indexes [ j ] != class . indexes [ j ] )
continue;
}
}
// destroy created class, if class with same indexes is found nad return it's index, otherwise insert class into pool
if ( i != state -> constants . constant_count )
free ( created_class . indexes );
else
insert_constant ( state, (BCConstant) { .kind = CONSTANT_CLASS, .class = created_class } );
return i;
}
u16 get_or_make_int ( BCCompilerState * state, i32 value ) {
u16 i;
for ( i = 0; i < state -> constants . constant_count; ++i )
if ( state -> constants . constants [ i ] . kind == CONSTANT_INTEGER && state -> constants . constants [ i ] . integer == value )
return i;
insert_constant ( state, (BCConstant) { .kind = CONSTANT_INTEGER, .integer = value } );
return i;
}
Michal Štěpánek
committed
void gen_cond_body ( BCCompilerState * state, Ast * cons, Ast * alt ) {
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
string_write_byte ( & function -> bc, 0x0D );
string_write_u16 ( & function -> bc, 0 );
u16 alt_pos = function -> bc . len;
add_scope ( state );
ast_to_bc ( state, alt );
remove_scope ( state );
Michal Štěpánek
committed
string_write_byte ( & function -> bc, 0x0E );
string_write_u16 ( & function -> bc, 0 );
u16 cons_pos = function -> bc . len;
u16 alt_len = cons_pos - alt_pos;
function -> bc . str [ alt_pos - 2 ] = alt_len & 255;
function -> bc . str [ alt_pos - 1 ] = (alt_len >> 8) & 255;
add_scope ( state );
ast_to_bc ( state, cons );
remove_scope ( state );
u16 cons_len = function -> bc . len - cons_pos;
function -> bc . str [ cons_pos - 2 ] = cons_len & 255;
function -> bc . str [ cons_pos - 1 ] = (cons_len >> 8) & 255;
}
void gen_loop ( BCCompilerState * state, Ast * cond, Ast * body ) {
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
size_t start_pos = function -> bc . len;
ast_to_bc ( state, cond );
string_write_byte ( & function -> bc, 0x0D );
string_write_u16 ( & function -> bc, 6 );
ast_to_bc ( state, (Ast*) & (AstNull) { .base = (Ast) { .kind = AST_NULL } } );
Michal Štěpánek
committed
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
string_write_byte ( & function -> bc, 0x0E );
string_write_u16 ( & function -> bc, 0 );
size_t body_pos = function -> bc . len;
add_scope ( state );
ast_to_bc ( state, body );
remove_scope ( state );
string_write_byte ( & function -> bc, 0x0E );
string_write_u16 ( & function -> bc, 0 );
size_t after_pos = function -> bc . len;
i16 loop_len = after_pos - start_pos;
function -> bc . str [ after_pos - 2 ] = (-loop_len) & 255;
function -> bc . str [ after_pos - 1 ] = ((-loop_len) >> 8) & 255;
u16 body_len = after_pos - body_pos;
function -> bc . str [ body_pos - 2 ] = body_len & 255;
function -> bc . str [ body_pos - 1 ] = (body_len >> 8) & 255;
}
void gen_loop_from_bc ( BCCompilerState * state, String * cond, String * body ) {
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
size_t start_pos = function -> bc . len;
for ( size_t i = 0; i < cond -> len; ++i )
string_write_byte ( & function -> bc, cond -> str [ i ] );
string_write_byte ( & function -> bc, 0x0D );
string_write_u16 ( & function -> bc, 3 );
string_write_byte ( & function -> bc, 0x0E );
string_write_u16 ( & function -> bc, 0 );
size_t body_pos = function -> bc . len;
for ( size_t i = 0; i < body -> len; ++i )
string_write_byte ( & function -> bc, body -> str [ i ] );
string_write_byte ( & function -> bc, 0x0E );
string_write_u16 ( & function -> bc, 0 );
size_t after_pos = function -> bc . len;
i16 loop_len = after_pos - start_pos;
function -> bc . str [ after_pos - 2 ] = (-loop_len) & 255;
function -> bc . str [ after_pos - 1 ] = ((-loop_len) >> 8) & 255;
u16 body_len = after_pos - body_pos;
function -> bc . str [ body_pos - 2 ] = body_len & 255;
function -> bc . str [ body_pos - 1 ] = (body_len >> 8) & 255;
}
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
void gen_bc_array_init ( BCCompilerState * state, AstArray * array, u16 size_index ) {
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
u16 array_index = make_local_index ( state, STR ("\0arr") );
gen_bc_set_local ( & function -> bc, array_index );
u16 one_index = get_or_make_int ( state, 1 );
gen_bc_constant ( state, one_index );
u16 i_index = make_local_index ( state, STR ("\0i") );
gen_bc_set_local ( & function -> bc, i_index );
string_write_byte ( & function -> bc, 0 );
String cond, body;
string_init ( & cond );
string_init ( & body );
// create cond BC
gen_bc_get_local ( & cond, i_index );
gen_bc_get_local ( & cond, size_index );
// call < operator to compare size and index
u16 index = get_string_index ( state, STR ("<") );
if ( index == 0 )
index = make_string_index ( state, STR ("<") );
string_write_byte ( & cond, 0x07 );
string_write_u16 ( & cond, index );
string_write_byte ( & cond, 2 );
// create body BC
gen_bc_get_local ( & body, array_index );
gen_bc_get_local ( & body, i_index );
size_t pos = function -> bc . len;
add_scope ( state );
ast_to_bc ( state, array -> initializer );
remove_scope ( state );
// value BC was created in function body, move to correct string
for ( size_t i = pos; i < function -> bc . len; ++i )
string_write_byte ( & body, function -> bc . str [ i ] );
function -> bc . len = pos;
// index assignment
index = get_string_index ( state, STR ("set") );
if ( index == 0 )
index = make_string_index ( state, STR ("set") );
string_write_byte ( & body, 0x07 );
string_write_u16 ( & body, index );
string_write_byte ( & body, 3 );
string_write_byte ( & body, 0 );
// increment i
index = get_string_index ( state, STR ("+") );
if ( index == 0 )
index = make_string_index ( state, STR ("+") );
gen_bc_get_local ( & body, i_index );
string_write_byte ( & body, 0x01 );
string_write_u16 ( & body, one_index );
string_write_byte ( & body, 0x07 );
string_write_u16 ( & body, index );
string_write_byte ( & body, 2 );
gen_bc_set_local ( & body, i_index );
string_write_byte ( & body, 0 );
string_destroy ( & cond );
string_destroy ( & body );
}
void gen_bc_get_local ( String * body, u16 index ) {
string_write_byte ( body, 0x0A );
string_write_u16 ( body, index );
}
void gen_bc_set_local ( String * body, u16 index ) {
string_write_byte ( body, 0x09 );
string_write_u16 ( body, index );
}
void gen_bc_constant ( BCCompilerState * state, u16 index ) {
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
string_write_byte ( & function -> bc, 0x01 );
string_write_u16 ( & function -> bc, index );
void insert_constant ( BCCompilerState * state, BCConstant constant ) {
state -> constants . constants [ state -> constants . constant_count ++ ] = constant;
}
void bc_state_init ( BCCompilerState * state ) {
state -> constants . constant_count = 0;
state -> constants . null_pos = -1;
state -> constants . bool_pos [ 0 ] = -1;
state -> constants . bool_pos [ 1 ] = -1;
state -> globals . global_count = 0;
state -> scope = NULL;
Michal Štěpánek
committed
state -> side_effect = false;
}
void bc_state_destroy ( BCCompilerState * state ) {
LocalScope * scope = state -> scope;
LocalScope * prev;
while ( scope ) {
prev = scope -> prev;
free ( scope );
scope = prev;
}
for ( size_t i = 0; i < state -> constants . constant_count; ++i ) {
BCConstant * constant = & state -> constants . constants [ i ];
if ( constant -> kind == CONSTANT_FUNCTION )
string_destroy ( & constant -> function . bc );
Michal Štěpánek
committed
if ( constant -> kind == CONSTANT_CLASS )
free ( constant -> class . indexes );
}
void ast_to_bc ( BCCompilerState * state, Ast * ast ) {
case AST_TOP: {
AstTop * top = (AstTop*) ast;
state -> ep = state -> fp = state -> constants . constant_count;
insert_constant ( state, create_function ( 1 ) );
state -> scope = create_function_scope ( 1 );
state -> scope -> prev = NULL;
state -> scope -> used_locals = 1;
state -> scope -> local_count = 1;
state -> top = state -> scope;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
for ( size_t i = 0; i < top -> expression_cnt; ++i ) {
ast_to_bc ( state, top -> expressions [ i ] );
if ( i != top -> expression_cnt - 1 )
string_write_byte ( & function -> bc, 0x00 );
}
string_write_byte ( & function -> bc, 0x0F );
return;
}
case AST_NULL: {
if ( state -> constants . null_pos < 0 ) {
state -> constants . null_pos = state -> constants . constant_count;
insert_constant ( state, (BCConstant) { .kind = CONSTANT_NULL } );
}
gen_bc_constant ( state, state -> constants . null_pos );
return;
}
case AST_INTEGER: {
AstInteger * integer = (AstInteger*) ast;
u16 i = get_or_make_int ( state, integer -> value );
}
case AST_BOOLEAN: {
AstBoolean * boolean = (AstBoolean*) ast;
size_t pos = boolean -> value ? 1 : 0;
if ( state -> constants . bool_pos [ pos ] < 0 ) {
state -> constants . bool_pos [ pos ] = state -> constants . constant_count;
insert_constant ( state, (BCConstant) { .kind = CONSTANT_BOOLEAN, .boolean = boolean -> value } );
}
gen_bc_constant ( state, state -> constants . bool_pos [ pos ] );
}
case AST_BLOCK: {
AstBlock * block = (AstBlock*) ast;
// make local scope
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
for ( size_t i = 0; i < block -> expression_cnt; ++i ) {
ast_to_bc ( state, block -> expressions [ i ] );
if ( i != block -> expression_cnt - 1 )
string_write_byte ( & function -> bc, 0x00 );
}
return;
}
case AST_FUNCTION: {
insert_constant ( state, (BCConstant) { .kind = CONSTANT_AST_FUNCTION, .ast = ast } );
gen_bc_constant ( state, state -> constants . constant_count - 1 );
return;
}
case AST_FUNCTION_CALL: {
AstFunctionCall * call = (AstFunctionCall*) ast;
ast_to_bc ( state, call -> function );
for ( size_t i = 0; i < call -> argument_cnt; ++i )
ast_to_bc ( state, call -> arguments [ i ] );
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
string_write_byte ( & function -> bc, 0x08 );
Michal Štěpánek
committed
string_write_byte ( & function -> bc, call -> argument_cnt & 255 );
state -> side_effect = true;
return;
}
case AST_PRINT: {
AstPrint * print = (AstPrint*) ast;
u16 index = get_string_index ( state, print -> format );
if ( index == 0 )
index = make_string_index ( state, print -> format );
for ( size_t i = 0; i < print -> argument_cnt; ++i )
ast_to_bc ( state, print -> arguments [ i ] );
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
string_write_byte ( & function -> bc, 0x02 );
string_write_u16 ( & function -> bc, index );
string_write_byte ( & function -> bc, print -> argument_cnt & 255 );
return;
}
case AST_DEFINITION: {
AstDefinition * def = (AstDefinition*) ast;
ast_to_bc ( state, def -> value );
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
if ( state -> scope == state -> top ) {
// GLOBAL
u16 index = get_string_index ( state, def -> name );
if ( index == 0 )
index = make_string_index ( state, def -> name );
u16 * count = & state -> globals . global_count;
size_t i;
for ( i = 0; i < *count; ++i )
if ( state -> globals . names [ i ] == index )
break;
if ( i == *count ) {
state -> globals . names [ *count ] = index;
++(*count);
}
string_write_byte ( & function -> bc, 0x0B );
string_write_u16 ( & function -> bc, index );
} else {
// LOCAL
for ( size_t i = 0; i < state -> scope -> used_locals; ++i )
if ( str_eq ( state -> scope -> locals [ i ], def -> name ) )
index = function -> parameters + ( state -> scope -> prev ? state -> scope -> prev -> local_count + i: i );
index = make_local_index ( state, def -> name );
}
return;
}
case AST_VARIABLE_ACCESS: {
AstVariableAccess * var = (AstVariableAccess*) ast;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
// try local
u16 index = get_local_index ( state, var -> name );
u16 str_index = get_string_index ( state, var -> name );
if ( str_index == 0 ) {
// create global / local
if ( state -> scope == state -> top ) {
str_index = make_string_index ( state, var -> name );
u16 * count = & state -> globals . global_count;
state -> globals . names [ *count ] = str_index;
++(*count);
string_write_byte ( & function -> bc, 0x0C );
string_write_u16 ( & function -> bc, str_index );
return;
} else {
index = make_local_index ( state, var -> name );
u16 * count = & state -> globals . global_count;
size_t i;
for ( i = 0; i < *count; ++i )
if ( state -> globals . names [ i ] == str_index )
break;
if ( i == *count )
assert ( false );
string_write_byte ( & function -> bc, 0x0C );
string_write_u16 ( & function -> bc, str_index );
}
return;
}
case AST_VARIABLE_ASSIGNMENT: {
AstVariableAssignment * assign = (AstVariableAssignment*) ast;
ast_to_bc ( state, assign -> value );
Michal Štěpánek
committed
state -> side_effect = true;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
// try local
u16 index = get_local_index ( state, assign -> name );
u16 str_index = get_string_index ( state, assign -> name );
if ( str_index == 0 ) {
// create global / local
if ( state -> scope == state -> top ) {
str_index = make_string_index ( state, assign -> name );
u16 * count = & state -> globals . global_count;
state -> globals . names [ *count ] = str_index;
++(*count);
string_write_byte ( & function -> bc, 0x0B );
string_write_u16 ( & function -> bc, str_index );
return;
} else {
index = make_local_index ( state, assign -> name );
return;
}
}
u16 * count = & state -> globals . global_count;
size_t i;
for ( i = 0; i < *count; ++i )
if ( state -> globals . names [ i ] == str_index )
break;
if ( i == *count )
assert ( false );
string_write_byte ( & function -> bc, 0x0B );
string_write_u16 ( & function -> bc, str_index );
case AST_CONDITIONAL: {
AstConditional * cond = (AstConditional*) ast;
ast_to_bc ( state, cond -> condition );
Michal Štěpánek
committed
gen_cond_body ( state, cond -> consequent, cond -> alternative );
case AST_LOOP: {
AstLoop * loop = (AstLoop*) ast;
Michal Štěpánek
committed
gen_loop ( state, loop -> condition, loop -> body );
return;
}
Michal Štěpánek
committed
case AST_OBJECT: {
AstObject * object = (AstObject*) ast;
u16 index = get_or_make_class ( state, object );
// push extends
ast_to_bc ( state, object -> extends );
// push members
AstDefinition * def;
add_scope ( state );
for ( size_t i = 0; i < object -> member_cnt; ++i ) {
def = (AstDefinition*) object -> members [ i ];
ast_to_bc ( state, def -> value );
}
remove_scope ( state );
// push class
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
string_write_byte ( & function -> bc, 0x04 );
string_write_u16 ( & function -> bc, index );
return;
}
case AST_FIELD_ASSIGNMENT: {
AstFieldAssignment * assign = (AstFieldAssignment*) ast;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
ast_to_bc ( state, assign -> object );
ast_to_bc ( state, assign -> value );
Michal Štěpánek
committed
state -> side_effect = true;
Michal Štěpánek
committed
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
u16 index = get_string_index ( state, assign -> field );
if ( index == 0 )
index = make_string_index ( state, assign -> field );
string_write_byte ( & function -> bc, 0x06 );
string_write_u16 ( & function -> bc, index );
return;
}
case AST_FIELD_ACCESS: {
AstFieldAccess * access = (AstFieldAccess*) ast;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
ast_to_bc ( state, access -> object );
u16 index = get_string_index ( state, access -> field );
if ( index == 0 )
index = make_string_index ( state, access -> field );
string_write_byte ( & function -> bc, 0x05 );
string_write_u16 ( & function -> bc, index );
return;
}
case AST_METHOD_CALL: {
AstMethodCall * method_call = (AstMethodCall*) ast;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
ast_to_bc ( state, method_call -> object );
for ( size_t i = 0; i < method_call -> argument_cnt; ++i )
ast_to_bc ( state, method_call -> arguments [ i ] );
u16 index = get_string_index ( state, method_call -> name );
if ( index == 0 )
index = make_string_index ( state, method_call -> name );
string_write_byte ( & function -> bc, 0x07 );
string_write_u16 ( & function -> bc, index );
string_write_byte ( & function -> bc, method_call -> argument_cnt + 1 );
Michal Štěpánek
committed
state -> side_effect = true;
Michal Štěpánek
committed
return;
}
case AST_ARRAY: {
AstArray * array = (AstArray*) ast;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
ast_to_bc ( state, array -> size );
Michal Štěpánek
committed
add_scope ( state );
Michal Štěpánek
committed
u16 size_index = make_local_index ( state, STR ("\0size") );
gen_bc_set_local ( & function -> bc, size_index );
Michal Štěpánek
committed
state -> side_effect = false;
Michal Štěpánek
committed
ast_to_bc ( state, array -> initializer );
Michal Štěpánek
committed
string_write_byte ( & function -> bc, 0x03 );
Michal Štěpánek
committed
if ( state -> side_effect ) {
gen_bc_array_init ( state, array, size_index );
} else {
// remove set local size if not needed
for ( size_t i = size_pos; i < function -> bc . len - 3; ++i )
function -> bc . str [ i ] = function -> bc . str [ i + 3 ];
function -> bc . len -= 3;
Michal Štěpánek
committed
}
remove_scope ( state );
Michal Štěpánek
committed
return;
}
case AST_INDEX_ASSIGNMENT: {
AstIndexAssignment * assign = (AstIndexAssignment*) ast;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
ast_to_bc ( state, assign -> object );
ast_to_bc ( state, assign -> index );
ast_to_bc ( state, assign -> value );
Michal Štěpánek
committed
state -> side_effect = true;
Michal Štěpánek
committed
u16 index = get_string_index ( state, STR ("set") );
if ( index == 0 )
index = make_string_index ( state, STR ("set") );
string_write_byte ( & function -> bc, 0x07 );
string_write_u16 ( & function -> bc, index );
string_write_byte ( & function -> bc, 3 );
return;
}
case AST_INDEX_ACCESS: {
AstIndexAccess * access = (AstIndexAccess*) ast;
BCFunction * function = & state -> constants . constants [ state -> fp ] . function;
ast_to_bc ( state, access -> object );
ast_to_bc ( state, access -> index );
u16 index = get_string_index ( state, STR ("get") );
if ( index == 0 )
index = make_string_index ( state, STR ("get") );
string_write_byte ( & function -> bc, 0x07 );
string_write_u16 ( & function -> bc, index );
string_write_byte ( & function -> bc, 2 );
return;
}
default:
assert ( false );
}
}
String generate_bc ( Ast * ast ) {
// init
String bc;
string_init ( & bc );
BCCompilerState bc_state;
bc_state_init ( & bc_state );
// generate internals (constants (exp. functions), globals)
string_write_byte ( & bc, 'F' );
string_write_byte ( & bc, 'M' );
string_write_byte ( & bc, 'L' );
// first functions to bc internals
for ( size_t i = 0; i < bc_state . constants . constant_count; ++i )
if ( bc_state . constants . constants [ i ] . kind == CONSTANT_AST_FUNCTION )
convert_function_to_bc ( & bc_state, i );
// fprintf ( stderr, "%d constants:\n", bc_state . constants . constant_count );
string_write_u16 ( & bc, bc_state . constants . constant_count );
for ( size_t i = 0; i < bc_state . constants . constant_count; ++i )
string_write_constant ( & bc, bc_state . constants . constants [ i ] );
string_write_u16 ( & bc, bc_state . globals . global_count );
for ( size_t i = 0; i < bc_state . globals . global_count; ++i ) {
string_write_u16 ( & bc, bc_state . globals . names [ i ] );
string_write_u16 ( & bc, bc_state . ep );