/* // Dao Virtual Machine // http://daoscript.org // // Copyright (c) 2006-2017, Limin Fu // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef DAO_VMCODE_H #define DAO_VMCODE_H #include"daoBase.h" /* TODO: more detailed description! */ enum DaoOpcode { DVM_DATA , /* Create primitive data: C = B; A: data type id; B: direct value; */ DVM_GETCL , /* Get local const: C = A:::B; B, index; A=0, implicit; A=1, explicit; */ DVM_GETCK , /* Get class const: C = A:::B; B, index; A=0; */ DVM_GETCG , /* Get global const: C = A:::B; B, index; A=0; */ DVM_GETVH , /* Get host variable: C = A:::B; B, index; A, section level; */ DVM_GETVS , /* Get closure variable: C = A:::B; B, index; A=0; */ DVM_GETVO , /* Get instance object variable: C = A:::B; B, index; A=0; */ DVM_GETVK , /* Get class static variable: C = A:::B; B, index; A=0; */ DVM_GETVG , /* Get global/static variable: C = A:::B; B, index; A=0/1; */ DVM_GETI , /* Get item(s): C = A[B]; A, register; B, register; */ DVM_GETDI , /* Get item(s): C = A[B]; A, register; B, direct index; */ DVM_GETMI , /* Get item(s): C = A[A+1, ..., A+B]; */ DVM_GETF , /* Get field: C = A.B or C = A::B; */ DVM_SETVH , /* Set host variable: C:::B = A; B, index; C, section level; */ DVM_SETVS , /* Set closure variable: C:::B = A; B, index; C=0; */ DVM_SETVO , /* Set instance object variable: C:::B = A; B, index; C=0; */ DVM_SETVK , /* Set class static variable: C:::B = A; B, index; C=0; */ DVM_SETVG , /* Set global/static variable: C:::B = A; C: C1, 0/1; C2, decl; C3, invar; */ DVM_SETI , /* Set item(s): C[B] = A; */ DVM_SETDI , /* Set item(s): C[B] = A; B, direct index; */ DVM_SETMI , /* Set item(s): C[C+1, ..., C+B] = A; */ DVM_SETF , /* Set field: C.B = A or C::B = A; */ DVM_LOAD , /* Put local value A as reference at C; */ DVM_MOVE , /* Move A to C: C = A; B: B1, explicit; B2, decl; B3, invar; */ DVM_UNTAG , /* Untag A of type X|none to X type at C; */ DVM_CAST , /* Cast A to B and store at C: C = (B)A; B, local const index; */ DVM_NOT , /* Not: C = ! A; */ DVM_MINUS , /* Unary minus: C = - A; */ DVM_TILDE , /* Bitwise not: C = ~ A */ DVM_SIZE , /* Size: C = % A; */ DVM_ADD , /* Addition: C = A + B; */ DVM_SUB , /* Subtraction: C = A - B; */ DVM_MUL , /* Multiplication: C = A * B; */ DVM_DIV , /* Division: C = A / B; */ DVM_MOD , /* Modulo: C = A % B; */ DVM_POW , /* Power: C = A ** B; */ DVM_AND , /* And: C = A && B; */ DVM_OR , /* Or: C = A || B; */ DVM_LT , /* Less than: C = A < B; */ DVM_LE , /* Less or equal: C = A <= B; */ DVM_EQ , /* Equal: C = A == B; */ DVM_NE , /* Not equal: C = A != B; */ DVM_IN , /* In: C = A in B; */ DVM_BITAND , /* Bit and: C = A & B */ DVM_BITOR , /* Bit or: C = A | B */ DVM_BITXOR , /* Bit xor: C = A ^ B */ DVM_BITLFT , /* Bit shift left: C = A << B */ DVM_BITRIT , /* Bit shift right: C = A >> B */ DVM_SAME , /* Same: C = A ?= B, same type; A, B, both are data objects or type objects; */ DVM_ISA , /* Isa: C = A ?< B; B, type; A (data) is a B; A (type) is a sub type of B; */ DVM_NAMEVA , /* C = (A = B): name A, local constant, value B, local register */ DVM_RANGE , /* C = A : B; create a pair of index, as a tuple; */ DVM_TUPLE , /* tuple: C = ( A, A+1, ..., A+B-1 ); items can be: name=value */ DVM_LIST , /* list: C = { A, A+1, ..., A+B-1 }; */ DVM_MAP , /* map: C = { A => A+1, ..., A+B-2 => A+B-1 }; if B==0, empty; */ DVM_VECTOR , /* vector: C = [ A, A+1, ..., A+B-1 ]; */ DVM_MATRIX , /* matrix: C=[A,..,A+c-1;..;A+c*(r-1),..,A+c*r-1]; B=rc;r,c:8-bits each.*/ DVM_PACK , /* packing: A.{ A+1, ..., A+B }; A, routine, class or type object; */ DVM_ROUTINE , /* create a function, possibly with closure */ DVM_GOTO , /* go to B; */ DVM_SWITCH , /* A: variable, B: location of default block, C: number of cases */ DVM_CASE , /* A: constant of the case, B: location of the case block, C: case mode */ DVM_ITER , /* create an iterator at C for A if B==0, else test an array of iterators; */ DVM_TEST , /* if A, go to the next one; else, goto B-th instruction; */ DVM_MATH , /* C = A( B ); A: sin,cos,...; B: double,complex */ DVM_CALL , /* function call: C = A( A+1, A+2, ..., A+B ); If B==0, no parameters; */ DVM_MCALL , /* method call: x.y(...), pass x as the first parameter; */ DVM_RETURN , /* return A,A+1,..,A+B-1; B==0: no returns; C==1: return from functional; */ DVM_YIELD , /* yield A, A+1,.., A+B-1; return data at C when resumed; */ DVM_SECT , /* code section label, parameters: A,A+1,...,A+B-1; C, #explicit params; */ DVM_MAIN , /* run the __main__ function of module/namespace A; A, global const index; */ DVM_JITC , /* run Just-In-Time compiled Code A, and skip the next B instructions; */ /* optimized opcodes: */ DVM_DATA_B , DVM_DATA_I , DVM_DATA_F , DVM_DATA_C , DVM_GETCL_B , DVM_GETCL_I , DVM_GETCL_F , DVM_GETCL_C , DVM_GETCK_B , DVM_GETCK_I , DVM_GETCK_F , DVM_GETCK_C , DVM_GETCG_B , DVM_GETCG_I , DVM_GETCG_F , DVM_GETCG_C , DVM_GETVH_B , DVM_GETVH_I , DVM_GETVH_F , DVM_GETVH_C , DVM_GETVS_B , DVM_GETVS_I , DVM_GETVS_F , DVM_GETVS_C , DVM_GETVO_B , DVM_GETVO_I , DVM_GETVO_F , DVM_GETVO_C , DVM_GETVK_B , DVM_GETVK_I , DVM_GETVK_F , DVM_GETVK_C , DVM_GETVG_B , DVM_GETVG_I , DVM_GETVG_F , DVM_GETVG_C , DVM_SETVH_BB , DVM_SETVH_II , DVM_SETVH_FF , DVM_SETVH_CC , DVM_SETVS_BB , DVM_SETVS_II , DVM_SETVS_FF , DVM_SETVS_CC , DVM_SETVO_BB , DVM_SETVO_II , DVM_SETVO_FF , DVM_SETVO_CC , DVM_SETVK_BB , DVM_SETVK_II , DVM_SETVK_FF , DVM_SETVK_CC , DVM_SETVG_BB , DVM_SETVG_II , DVM_SETVG_FF , DVM_SETVG_CC , DVM_MOVE_BB , DVM_MOVE_BI , DVM_MOVE_BF , DVM_MOVE_IB , DVM_MOVE_II , DVM_MOVE_IF , DVM_MOVE_FB , DVM_MOVE_FI , DVM_MOVE_FF , DVM_MOVE_CB , DVM_MOVE_CI , DVM_MOVE_CF , DVM_MOVE_CC , /* complex = complex */ DVM_MOVE_SS , /* string = string */ DVM_MOVE_PP , /* C = A; C and A are of the same non-primitive type, A must not be const; */ DVM_MOVE_XX , /* C = A; C and A are of the same type, or C is of any type; */ DVM_NOT_B , DVM_NOT_I , DVM_NOT_F , DVM_MINUS_I , DVM_MINUS_F , DVM_MINUS_C , DVM_TILDE_I , DVM_TILDE_C , DVM_SIZE_X , /* On operands with known types with integer results; */ /* // C = A + B: will be compiled into: ADD, MOVE, // and the C operand of ADD is always an intermediate data with type to be inferred, // so it is only necessary to add specialized opcode according the A,B operands. */ DVM_AND_BBB , DVM_OR_BBB , DVM_LT_BBB , DVM_LE_BBB , DVM_EQ_BBB , DVM_NE_BBB , DVM_ADD_III , DVM_SUB_III , DVM_MUL_III , DVM_DIV_III , DVM_MOD_III , DVM_POW_III , DVM_AND_BII , DVM_OR_BII , DVM_LT_BII , DVM_LE_BII , DVM_EQ_BII , DVM_NE_BII , DVM_BITAND_III , DVM_BITOR_III , DVM_BITXOR_III , DVM_BITLFT_III , DVM_BITRIT_III , DVM_ADD_FFF , DVM_SUB_FFF , DVM_MUL_FFF , DVM_DIV_FFF , DVM_MOD_FFF , DVM_POW_FFF , DVM_AND_BFF , DVM_OR_BFF , DVM_LT_BFF , DVM_LE_BFF , DVM_EQ_BFF , DVM_NE_BFF , DVM_ADD_CCC , DVM_SUB_CCC , DVM_MUL_CCC , DVM_DIV_CCC , DVM_EQ_BCC , DVM_NE_BCC , /* string */ DVM_ADD_SSS , DVM_LT_BSS , DVM_LE_BSS , DVM_EQ_BSS , DVM_NE_BSS , /* single indexing C=A[B]: GETI and MOVE */ /* index should be integer, may be casted from float/double by the typing system */ DVM_GETI_LI , /* get item : C = A[B]; X=list[int] */ DVM_SETI_LI , /* set item : C[B] = A; list[int]=X, or list[int]=X; */ DVM_GETI_SI , /* get char from a string: string[int] */ DVM_SETI_SII , /* set char to a string: string[int]=int */ DVM_GETI_LBI , /* get item : C = A[B]; list[int] */ DVM_GETI_LII , /* get item : C = A[B]; list[int] */ DVM_GETI_LFI , /* get item : C = A[B]; list[int] */ DVM_GETI_LCI , /* get item : C = A[B]; list[int] */ DVM_GETI_LSI , /* get item : C = A[B]; list[int] */ DVM_SETI_LBIB , /* set item : C[B] = A; list[bool]=bool */ DVM_SETI_LIII , /* set item : C[B] = A; list[int]=int */ DVM_SETI_LFIF , /* set item : C[B] = A; */ DVM_SETI_LCIC , /* set item : C[B] = A; */ DVM_SETI_LSIS , /* set item : C[B] = A; */ DVM_GETI_ABI , /* get item : C = A[B]; array[int] */ DVM_GETI_AII , /* get item : C = A[B]; array[int] */ DVM_GETI_AFI , /* get item : C = A[B]; array[int] */ DVM_GETI_ACI , /* get item : C = A[B]; array[int] */ DVM_SETI_ABIB , /* set item : C[B] = A; */ DVM_SETI_AIII , /* set item : C[B] = A; */ DVM_SETI_AFIF , /* set item : C[B] = A; */ DVM_SETI_ACIC , /* set item : C[B] = A; */ DVM_GETI_TI , /* get item : C = A[B]; tuple<...>[int] */ DVM_SETI_TI , /* set item : C[B] = A; tuple<...>[int]=X; */ /* access field by constant index; specialized from GETI[const] or GETF */ DVM_GETF_TB , /* get boolean field by constant index; */ DVM_GETF_TI , /* get integer field by constant index; */ DVM_GETF_TF , /* get float field by constant index; */ DVM_GETF_TC , /* get complex field by constant index; */ DVM_GETF_TX , /* get type checked field by constant index; */ DVM_SETF_TBB , /* set boolean field to boolean. */ DVM_SETF_TII , /* set integer field to integer. */ DVM_SETF_TFF , /* set float field to float. */ DVM_SETF_TCC , /* set complex field to double. */ DVM_SETF_TSS , /* set string field to string. */ DVM_SETF_TPP , /* set item: C[B]=A or C.B=A; tuple<..X..>[int]=X, or tuple<..any..>[int]=X; */ DVM_SETF_TXX , /* set item: C[B]=A or C.B=A; tuple<..X..>[int]=X, or tuple<..any..>[int]=X; */ /* multiple indexing a[i,j] */ DVM_GETMI_ABI , /* array: get item(s) : C = A[B]; B,C: integer, A boolean array; */ DVM_GETMI_AII , /* array: get item(s) : C = A[B]; B,C: integer, A integer array; */ DVM_GETMI_AFI , /* array: get item(s) : C = A[B]; B,C: integer, A float array; */ DVM_GETMI_ACI , /* array: get item(s) : C = A[B]; B,C: integer, A complex array; */ DVM_SETMI_ABIB , /* set item(s) : C[B] = A; A,B: integer, C boolean array; */ DVM_SETMI_AIII , /* set item(s) : C[B] = A; A,B: integer, C integer array; */ DVM_SETMI_AFIF , /* set item(s) : C[B] = A; A,B: integer, C float array; */ DVM_SETMI_ACIC , /* set item(s) : C[B] = A; A,B: integer, C complex array; */ DVM_GETF_CX , /* get complex field: real/imag; */ DVM_SETF_CX , /* set complex field: real/imag; */ /* setters and getters */ /* get/set member of class instance by index instead of name: */ DVM_GETF_KC , /* get class field, const; code: GET Member Field Const*/ DVM_GETF_KG , /* get class field, global */ DVM_GETF_OC , /* get class instance field, const; code: GET Member Field Const*/ DVM_GETF_OG , /* get class instance field, global */ DVM_GETF_OV , /* get class instance field, variable */ DVM_SETF_KG , /* set class static field: field type equals to opa type, or is "any" type; */ DVM_SETF_OG , /* set class static field: field type equals to opa type, or is "any" type; */ DVM_SETF_OV , /* set class instance field: field type equals to opa type, or is "any" type; */ /* C=A.B : GETF and MOVE */ DVM_GETF_KCB , DVM_GETF_KCI , DVM_GETF_KCF , DVM_GETF_KCC , DVM_GETF_KGB , DVM_GETF_KGI , DVM_GETF_KGF , DVM_GETF_KGC , DVM_GETF_OCB , DVM_GETF_OCI , DVM_GETF_OCF , DVM_GETF_OCC , DVM_GETF_OGB , DVM_GETF_OGI , DVM_GETF_OGF , DVM_GETF_OGC , DVM_GETF_OVB , DVM_GETF_OVI , DVM_GETF_OVF , DVM_GETF_OVC , /* C.B=A specialize according to both: C.B and A */ DVM_SETF_KGBB , DVM_SETF_KGII , DVM_SETF_KGFF , DVM_SETF_KGCC , DVM_SETF_OGBB , DVM_SETF_OGII , DVM_SETF_OGFF , DVM_SETF_OGCC , DVM_SETF_OVBB , DVM_SETF_OVII , DVM_SETF_OVFF , DVM_SETF_OVCC , DVM_TEST_B , DVM_TEST_I , DVM_TEST_F , DVM_MATH_B , DVM_MATH_I , DVM_MATH_F , DVM_CAST_B , DVM_CAST_I , DVM_CAST_F , DVM_CAST_C , DVM_CAST_S , DVM_CAST_VE , /* cast variant to one of its distinct enum types; */ DVM_CAST_VX , /* cast variant to one of its distinct and non primitve member types; */ DVM_ISA_ST , /* check against simple types: int, float, double, complex, long, string; */ DVM_TUPLE_SIM , DVM_NULL }; typedef enum DaoOpcode DaoOpcode; /* // Additional notes for the virtual machine instructions: // // DVM_GETVH and DVM_SETVH: // // These two instructions are for accessing up-values from closures or from code sections. // The value of operand ::a (DVM_GETVH) or ::c (DVM_SETVH) instructs what kind of up-value // is accessed; and the value of operand ::b tells which up-value is accessed. // // Zero value of the operand ::a or ::c indicates the up-value is accessed from a closure. // The up-value is a local variable of the routine in which the closure was created. // // A non-zero value of ::a or ::c indicates the up-value // TODO // // DVM_ROUTINE // TODO */ /* // Extra vmcode type for compiling: // They are used to setup proper indexing, branching or jumping. After this, // they will be removed or replaced with proper instructions from DaoOpcode. */ enum DaoOpcodeExtra { DVM_NOP = DVM_NULL + 1 , DVM_LOAD2 , DVM_LABEL , DVM_LOOP , DVM_BRANCH , DVM_DO , DVM_LBRA , DVM_RBRA , DVM_DEFAULT , DVM_UNUSED }; /* // Enum modes for DVM_LIST, DVM_VECTOR, DVM_MAP, DVM_TUPLE: */ enum DaoEnumCodeModes { DVM_ENUM_MODE0 , /* Default mode; */ DVM_ENUM_MODE1 , /* LIST/VECTOR: arithmetic progression; MAP: hashing; TUPLE: arguments; */ DVM_ENUM_MODE2 , /* TUPLE: code section arguments; */ DVM_ENUM_MODE3 /* Reserved; */ }; enum DaoMathFunct { DVM_MATH_CEIL , DVM_MATH_FLOOR , DVM_MATH_SIGN , DVM_MATH_ABS , DVM_MATH_ARG , DVM_MATH_IMAG , DVM_MATH_NORM , DVM_MATH_REAL , DVM_MATH_ACOS , DVM_MATH_ASIN , DVM_MATH_ATAN , DVM_MATH_COS , DVM_MATH_COSH , DVM_MATH_EXP , DVM_MATH_LOG , DVM_MATH_SIN , DVM_MATH_SINH , DVM_MATH_SQRT , DVM_MATH_TAN , DVM_MATH_TANH , DVM_MATH_MIN , DVM_MATH_MAX }; enum DaoFunctMeth { DVM_FUNCT_APPLY , DVM_FUNCT_SORT , DVM_FUNCT_MAP , DVM_FUNCT_COLLECT , DVM_FUNCT_ASSOCIATE , DVM_FUNCT_FOLD , DVM_FUNCT_FIND , DVM_FUNCT_SELECT , DVM_FUNCT_INDEX , DVM_FUNCT_COUNT , DVM_FUNCT_ITERATE , DVM_FUNCT_STRING , DVM_FUNCT_ARRAY , DVM_FUNCT_LIST , DVM_FUNCT_NULL }; enum DaoCodeType { DAO_CODE_NOP , /* Local variable operands: None; */ DAO_CODE_GETC , /* C; local variable operand; */ DAO_CODE_GETG , /* C; */ DAO_CODE_GETU , /* B,C; */ DAO_CODE_GETF , /* A,C; */ DAO_CODE_GETI , /* A,B,C; */ DAO_CODE_GETM , /* C,A,A+1,...,A+B; */ DAO_CODE_SETG , /* A; */ DAO_CODE_SETU , /* A,B; */ DAO_CODE_SETF , /* A,C; */ DAO_CODE_SETI , /* A,B,C; */ DAO_CODE_SETM , /* A,C,C+1,...,C+B; */ DAO_CODE_MOVE , /* A,C; */ DAO_CODE_UNARY , /* A,C; */ DAO_CODE_BINARY , /* A,B,C; */ DAO_CODE_UNARY2 , /* B,C; */ DAO_CODE_BINARY2 , /* B,B+1,C; */ DAO_CODE_MATRIX , /* C,A,A+1,...,A+N-1; where N=(B>>8)*(B&0xff); */ DAO_CODE_ENUM , /* C,A,A+1,...,A+B-1; */ DAO_CODE_ENUM2 , /* C,A,A+1,...,A+B; */ DAO_CODE_CALL , /* C,A,A+1,...,A+N; where N=B&0xff*/ DAO_CODE_ROUTINE , /* C,A,A+1,...,A+B; */ DAO_CODE_YIELD , /* C,A,A+1,...,A+B-1; */ DAO_CODE_EXPLIST , /* A,A+1,...,A+B-1; */ DAO_CODE_BRANCH , /* A; */ DAO_CODE_JUMP }; enum DaoCodeState { DAO_CODE_BREAKING = 1 }; struct DaoVmCode { unsigned short code; /* opcode; */ unsigned short a, b, c; /* operands; */ #ifdef DAO_USE_CODE_STATE unsigned short state; /* state; */ #endif }; DAO_DLL const char* DaoVmCode_GetOpcodeName( int code ); DAO_DLL ushort_t DaoVmCode_GetOpcodeBase( int code ); DAO_DLL uchar_t DaoVmCode_CheckPermutable( int code ); DAO_DLL uchar_t DaoVmCode_GetOpcodeType( DaoVmCode *self ); DAO_DLL DaoVmCode DaoVmCode_CheckOperands( DaoVmCode *self ); DAO_DLL int DaoVmCode_MayCreateReference( int code ); DAO_DLL const char* DaoVmCode_GetOperator( int opcode ); DAO_DLL const char* DaoVmCode_GetCompoundOperator( int opcode ); DAO_DLL DaoVmCode* DArray_PushCode( DArray *self, DaoVmCode code ); struct DaoVmCodeX { unsigned short code; /* opcode */ unsigned short a, b, c; /* register ids for operands */ unsigned short state; /* state; */ unsigned short level; /* lexical level */ unsigned short line; /* line number in the source file */ unsigned int first; /* first token */ unsigned short middle; /* middle token, with respect to first */ unsigned short last; /* last token, with respect to first */ }; void DaoVmCode_Print( DaoVmCode self, char *buffer ); void DaoVmCodeX_Print( DaoVmCodeX self, char *annot, char *buffer ); #endif