|
|
| version 1.78, 2008/06/10 14:06:36 | version 1.94, 2009/06/04 09:31:38 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: compiler support helper functions decls. | Parser: compiler support helper functions decls. |
| Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| Line 62 public: | Line 62 public: |
| /// @name input | /// @name input |
| Request& request; | Request& request; |
| VStateless_class* cclass; | VStateless_class* cclass; |
| VStateless_class* cclass_new; | |
| ArrayClass* cclasses; | ArrayClass* cclasses; |
| const char* source; | const char* source; |
| uint file_no; | uint file_no; |
| Line 82 public: | Line 83 public: |
| bool in_call_value; | bool in_call_value; |
| bool explicit_result; | bool explicit_result; |
| bool append; | |
| //@} | //@} |
| /// output: filled input 'methods' and 'error' if any | /// output: filled input 'methods' and 'error' if any |
| Line 99 public: | Line 101 public: |
| // we were told the class to compile to? | // we were told the class to compile to? |
| cclass(aclass), // until changed with @CLASS would consider operators loading | cclass(aclass), // until changed with @CLASS would consider operators loading |
| cclass_new(0), | |
| cclasses(new ArrayClass(1)), | cclasses(new ArrayClass(1)), |
| source(asource), | source(asource), |
| file_no(afile_no), | file_no(afile_no), |
| Line 110 public: | Line 113 public: |
| ls(LS_USER), | ls(LS_USER), |
| ls_sp(0), | ls_sp(0), |
| in_call_value(false), | in_call_value(false), |
| explicit_result(false) { | explicit_result(false), |
| append(false) { | |
| *cclasses+=aclass; | *cclasses+=aclass; |
| } | } |
| void class_add(){ | |
| if(cclass_new){ | |
| cclass=cclass_new; | |
| // append to request's classes | |
| request.classes().put(cclass->name(), cclass); | |
| *cclasses+=cclass; | |
| cclass_new=0; | |
| append=false; | |
| } | |
| } | |
| VStateless_class* get_existed_class(VStateless_class* aclass){ | |
| if(aclass){ | |
| if(Value* class_value=request.classes().get(aclass->name())){ | |
| return class_value->get_class(); | |
| } | |
| } | |
| return 0; | |
| } | |
| bool reuse_existed_class(VStateless_class* aclass){ | |
| if(aclass->is_partial()){ | |
| cclass=aclass; | |
| cclass_new=0; | |
| append=true; | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| void set_all_vars_local(){ | |
| if(cclass_new){ | |
| cclass_new->set_all_vars_local(); | |
| } else { | |
| cclass->set_all_vars_local(); | |
| } | |
| } | |
| void pos_next_line() { | void pos_next_line() { |
| pos.line++; | pos.line++; |
| last_line_end_col=pos.col; | last_line_end_col=pos.col; |
| Line 145 inline ArrayOperation* N() { | Line 188 inline ArrayOperation* N() { |
| } | } |
| /// Assembler instruction // append ordinary instruction to ops | /// Assembler instruction // append ordinary instruction to ops |
| inline void O(ArrayOperation& result, OPCODE code) { | inline void O(ArrayOperation& result, OP::OPCODE code) { |
| result+=Operation(code); | result+=Operation(code); |
| } | } |
| Line 158 inline void P(ArrayOperation& result, Ar | Line 201 inline void P(ArrayOperation& result, Ar |
| result.append(code_array, offset); | result.append(code_array, offset); |
| } | } |
| /// aPpend part of 'code_array', starting from offset, to 'result' | |
| inline void P(ArrayOperation& result, ArrayOperation& code_array, int offset, int limit) { | |
| result.append(code_array, offset, limit); | |
| } | |
| /// append cOde Array | /// append cOde Array |
| inline void OA(ArrayOperation& result, OPCODE code, ArrayOperation* code_array) { | inline void OA(ArrayOperation& result, OP::OPCODE code, ArrayOperation* code_array) { |
| result+=Operation(code); // append OP_CODE | result+=Operation(code); // append OP_CODE |
| result+=Operation(code_array); // append 'code_array' | result+=Operation(code_array); // append 'code_array' |
| } | } |
| Line 175 inline ArrayOperation* VL(Value* value, | Line 223 inline ArrayOperation* VL(Value* value, |
| ArrayOperation& result=*N(); | ArrayOperation& result=*N(); |
| // append 'value' to 'result' | // append 'value' to 'result' |
| result+=Operation(OP_VALUE); | result+=Operation(OP::OP_VALUE); |
| result+=Operation(file_no, line, col); // append origin | result+=Operation(file_no, line, col); // append origin |
| result+=Operation(value); // append 'value' | result+=Operation(value); // append 'value' |
| Line 183 inline ArrayOperation* VL(Value* value, | Line 231 inline ArrayOperation* VL(Value* value, |
| } | } |
| /// Literal Array to(2) Value @return Value from literal Array OP+origin+Value | /// Literal Array to(2) Value @return Value from literal Array OP+origin+Value |
| Value* LA2V(ArrayOperation& literal_string_array, int offset=0); | Value* LA2V(ArrayOperation& literal_string_array, int offset=0, OP::OPCODE code=OP::OP_VALUE); |
| /// Literal Array to(2) String @return String value from literal Array OP+origin+String array | /// Literal Array to(2) String @return String value from literal Array OP+origin+String array |
| inline const String* LA2S(ArrayOperation& literal_string_array, int offset=0) { | inline const String* LA2S(ArrayOperation& literal_string_array, int offset=0, OP::OPCODE code=OP::OP_VALUE) { |
| if(Value* value=LA2V(literal_string_array, offset)) | if(Value* value=LA2V(literal_string_array, offset, code)) |
| return value->get_string(); | return value->get_string(); |
| return 0; | return 0; |
| } | } |
| inline void change_string_literal_to_write_string_literal(ArrayOperation& literal_string_array) { | inline void change_string_literal_to_write_string_literal(ArrayOperation& literal_string_array) { |
| literal_string_array.put(0, OP_STRING__WRITE); | literal_string_array.put(0, OP::OP_STRING__WRITE); |
| } | } |
| void maybe_change_string_literal_to_double_literal(ArrayOperation& literal_string_array); | void maybe_change_string_literal_to_double_literal(ArrayOperation& literal_string_array); |
| void change_string_literal_value(ArrayOperation& literal_string_array, const String& new_value); | void change_string_literal_value(ArrayOperation& literal_string_array, const String& new_value); |
| void changetail_or_append(ArrayOperation& opcodes, | void changetail_or_append(ArrayOperation& opcodes, |
| OPCODE find, bool with_argument, OPCODE replace, OPCODE notfound); | OP::OPCODE find, bool with_argument, OP::OPCODE replace, OP::OPCODE notfound); |
| bool maybe_change_first_opcode(ArrayOperation& opcodes, OP::OPCODE find, OP::OPCODE replace); | |
| #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT | |
| // OP_VALUE+origin+value+OP_GET_ELEMENT+OP_VALUE+origin+value+OP_GET_ELEMENT => OP_GET_OBJECT_ELEMENT+origin+value+origin+value | |
| inline bool maybe_make_get_object_element(ArrayOperation& opcodes, ArrayOperation& diving_code, size_t divine_count){ | |
| if(divine_count!=8) | |
| return false; | |
| assert(diving_code[0].code==OP::OP_VALUE); | |
| if( | |
| diving_code[3].code==OP::OP_GET_ELEMENT | |
| && diving_code[4].code==OP::OP_VALUE | |
| && diving_code[divine_count-1].code==OP::OP_GET_ELEMENT | |
| ){ | |
| O(opcodes, OP::OP_GET_OBJECT_ELEMENT); | |
| P(opcodes, diving_code, 1/*offset*/, 2/*limit*/); // copy first origin+value | |
| P(opcodes, diving_code, 5, 2); // second origin+value | |
| return true; | |
| } | |
| return false; | |
| } | |
| #endif | |
| #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT | |
| // OP_VALUE+origin+value+OP_GET_ELEMENT+OP_WITH_READ+OP_VALUE+origin+value+OP_GET_ELEMENT+OP_GET_ELEMENT => OP_GET_OBJECT_VAR_ELEMENT+origin+value+origin+value | |
| inline bool maybe_make_get_object_var_element(ArrayOperation& opcodes, ArrayOperation& diving_code, size_t divine_count){ | |
| if(divine_count!=10) | |
| return false; | |
| assert(diving_code[0].code==OP::OP_VALUE); | |
| if( | |
| diving_code[4].code==OP::OP_WITH_READ | |
| && diving_code[5].code==OP::OP_VALUE | |
| && diving_code[divine_count-1].code==OP::OP_GET_ELEMENT | |
| ){ | |
| O(opcodes, OP::OP_GET_OBJECT_VAR_ELEMENT); | |
| P(opcodes, diving_code, 1/*offset*/, 2/*limit*/); // copy first origin+value | |
| P(opcodes, diving_code, 6, 2); // second origin+value | |
| return true; | |
| } | |
| return false; | |
| } | |
| #endif | |
| // OP_VALUE+origin+self+OP_GET_ELEMENT+OP_VALUE+origin+value+OP_GET_ELEMENT => OP_WITH_SELF__VALUE__GET_ELEMENT+origin+value | |
| #ifdef OPTIMIZE_BYTECODE_GET_SELF_ELEMENT | |
| inline bool maybe_make_with_self_get_element(ArrayOperation& opcodes, ArrayOperation& diving_code, size_t divine_count){ | |
| if(divine_count!=8) | |
| return false; | |
| assert(diving_code[0].code==OP::OP_VALUE); | |
| if( | |
| diving_code[3].code==OP::OP_GET_ELEMENT | |
| && diving_code[4].code==OP::OP_VALUE | |
| && diving_code[divine_count-1].code==OP::OP_GET_ELEMENT | |
| ){ | |
| O(opcodes, OP::OP_WITH_SELF__VALUE__GET_ELEMENT); | |
| P(opcodes, diving_code, 5/*offset*/, 2/*limit*/); // copy second origin+value. we know that the first one is "self" | |
| return true; | |
| } | |
| return false; | |
| } | |
| #endif | |
| #ifdef OPTIMIZE_BYTECODE_CONSTRUCT | |
| inline bool maybe_optimize_construct(ArrayOperation& opcodes, ArrayOperation& var_ops, ArrayOperation& expr_ops){ | |
| size_t expr_count=expr_ops.count(); | |
| OP::OPCODE construct_op=expr_ops[expr_count-1].code; | |
| size_t construct=(construct_op==OP::OP_CONSTRUCT_VALUE)?0x01:(construct_op==OP::OP_CONSTRUCT_EXPR)?0x02:0x00; | |
| if(construct){ | |
| P(opcodes, expr_ops, 0/*offset*/, expr_count-1/*limit*/); // copy constructor body without CONSTRUCT_(VALUE|EXPR) | |
| size_t with=0x00; | |
| switch(var_ops[0].code){ | |
| case OP::OP_WITH_ROOT: | |
| { | |
| with=0x10; | |
| break; | |
| } | |
| case OP::OP_WITH_WRITE: | |
| { | |
| with=0x20; | |
| break; | |
| } | |
| case OP::OP_WITH_SELF: | |
| { | |
| with=0x30; | |
| break; | |
| } | |
| } | |
| if(with && var_ops[1].code==OP::OP_VALUE && var_ops.count()==4){ | |
| OP::OPCODE code=OP::OP_VALUE; // calm down compiler. will be reassigned for sure. | |
| switch( with | construct ) { | |
| case 0x11: | |
| { | |
| code=OP::OP_WITH_ROOT__VALUE__CONSTRUCT_VALUE; | |
| break; | |
| } | |
| case 0x12: | |
| { | |
| code=OP::OP_WITH_ROOT__VALUE__CONSTRUCT_EXPR; | |
| break; | |
| } | |
| case 0x21: | |
| { | |
| code=OP::OP_WITH_WRITE__VALUE__CONSTRUCT_VALUE; | |
| break; | |
| } | |
| case 0x22: | |
| { | |
| code=OP::OP_WITH_WRITE__VALUE__CONSTRUCT_EXPR; | |
| break; | |
| } | |
| case 0x31: | |
| { | |
| code=OP::OP_WITH_SELF__VALUE__CONSTRUCT_VALUE; | |
| break; | |
| } | |
| case 0x32: | |
| { | |
| code=OP::OP_WITH_SELF__VALUE__CONSTRUCT_EXPR; | |
| break; | |
| } | |
| } | |
| O(opcodes, code); | |
| P(opcodes, var_ops, 2/*offset*/, 2/*limit*/); // copy origin+value | |
| } else { | |
| P(opcodes, var_ops); | |
| O(opcodes, construct_op); | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| #endif | |
| void push_LS(Parse_control& pc, lexical_state new_state); | void push_LS(Parse_control& pc, lexical_state new_state); |