/* * Register the built-in constants defined above. */ JX9_PRIVATE void jx9RegisterBuiltInConstant(jx9_vm *pVm) { sxu32 n; /* * Note that all built-in constants have access to the jx9 virtual machine * that trigger the constant invocation as their private data. */ for( n = 0 ; n < SX_ARRAYSIZE(aBuiltIn) ; ++n ){ jx9_create_constant(&(*pVm), aBuiltIn[n].zName, aBuiltIn[n].xExpand, &(*pVm)); } }
/* * Register all the UnQLite foreign functions defined above. */ UNQLITE_PRIVATE int unqliteRegisterJx9Functions(unqlite_vm *pVm) { static const jx9_builtin_func aBuiltin[] = { { "db_version" , unqliteBuiltin_db_version }, { "db_copyright", unqliteBuiltin_db_credits }, { "db_credits" , unqliteBuiltin_db_credits }, { "db_sig" , unqliteBuiltin_db_sig }, { "db_errlog", unqliteBuiltin_db_errlog }, { "collection_exists", unqliteBuiltin_collection_exists }, { "db_exists", unqliteBuiltin_collection_exists }, { "collection_create", unqliteBuiltin_collection_create }, { "db_create", unqliteBuiltin_collection_create }, { "db_fetch", unqliteBuiltin_db_fetch_next }, { "db_get", unqliteBuiltin_db_fetch_next }, { "db_fetch_by_id", unqliteBuiltin_db_fetch_by_id }, { "db_get_by_id", unqliteBuiltin_db_fetch_by_id }, { "db_fetch_all", unqliteBuiltin_db_fetch_all }, { "db_get_all", unqliteBuiltin_db_fetch_all }, { "db_last_record_id", unqliteBuiltin_db_last_record_id }, { "db_current_record_id", unqliteBuiltin_db_current_record_id }, { "db_reset_record_cursor", unqliteBuiltin_db_reset_record_cursor }, { "db_total_records", unqliteBuiltin_db_total_records }, { "db_creation_date", unqliteBuiltin_db_creation_date }, { "db_store", unqliteBuiltin_db_store }, { "db_put", unqliteBuiltin_db_store }, { "db_drop_collection", unqliteBuiltin_db_drop_col }, { "collection_delete", unqliteBuiltin_db_drop_col }, { "db_drop_record", unqliteBuiltin_db_drop_record }, { "db_update_record", unqliteBuiltin_db_update_record }, { "db_set_schema", unqliteBuiltin_db_set_schema }, { "db_get_schema", unqliteBuiltin_db_get_schema }, { "db_begin", unqliteBuiltin_db_begin }, { "db_commit", unqliteBuiltin_db_commit }, { "db_rollback", unqliteBuiltin_db_rollback }, }; int rc = UNQLITE_OK; sxu32 n; /* Register the unQLite functions defined above in the Jx9 call table */ for( n = 0 ; n < SX_ARRAYSIZE(aBuiltin) ; ++n ){ rc = jx9_create_function(pVm->pJx9Vm,aBuiltin[n].zName,aBuiltin[n].xFunc,pVm); } return rc; }
/* * Check if the given token is a potential operator or not. * This function is called by the lexer each time it extract a token that may * look like an operator. * Return a structure [i.e: jx9_expr_op instnace ] that describe the operator on success. * Otherwise NULL. * Note that the function take care of handling ambiguity [i.e: whether we are dealing with * a binary minus or unary minus.] */ JX9_PRIVATE const jx9_expr_op * jx9ExprExtractOperator(SyString *pStr, SyToken *pLast) { sxu32 n = 0; sxi32 rc; /* Do a linear lookup on the operators table */ for(;;){ if( n >= SX_ARRAYSIZE(aOpTable) ){ break; } rc = SyStringCmp(pStr, &aOpTable[n].sOp, SyMemcmp); if( rc == 0 ){ if( aOpTable[n].sOp.nByte != sizeof(char) || (aOpTable[n].iOp != EXPR_OP_UMINUS && aOpTable[n].iOp != EXPR_OP_UPLUS) || pLast == 0 ){ if( aOpTable[n].iOp == EXPR_OP_SUBSCRIPT && (pLast == 0 || (pLast->nType & (JX9_TK_ID|JX9_TK_CSB/*]*/|JX9_TK_RPAREN/*)*/)) == 0) ){ /* JSON Array not subscripting, return NULL */ return 0; } /* There is no ambiguity here, simply return the first operator seen */ return &aOpTable[n]; } /* Handle ambiguity */ if( pLast->nType & (JX9_TK_LPAREN/*'('*/|JX9_TK_OCB/*'{'*/|JX9_TK_OSB/*'['*/|JX9_TK_COLON/*:*/|JX9_TK_COMMA/*, '*/) ){ /* Unary opertors have prcedence here over binary operators */ return &aOpTable[n]; } if( pLast->nType & JX9_TK_OP ){ const jx9_expr_op *pOp = (const jx9_expr_op *)pLast->pUserData; /* Ticket 1433-31: Handle the '++', '--' operators case */ if( pOp->iOp != EXPR_OP_INCR && pOp->iOp != EXPR_OP_DECR ){ /* Unary opertors have prcedence here over binary operators */ return &aOpTable[n]; } } } ++n; /* Next operator in the table */ } /* No such operator */ return 0; }
/* * Make sure we are dealing with a valid expression tree. * This function check for balanced parenthesis, braces, brackets and so on. * When errors, JX9 take care of generating the appropriate error message. * Return SXRET_OK on success. Any other return value indicates syntax error. */ static sxi32 ExprVerifyNodes(jx9_gen_state *pGen, jx9_expr_node **apNode, sxi32 nNode) { sxi32 iParen, iSquare, iBraces; sxi32 i, rc; if( nNode > 0 && apNode[0]->pOp && (apNode[0]->pOp->iOp == EXPR_OP_ADD || apNode[0]->pOp->iOp == EXPR_OP_SUB) ){ /* Fix and mark as an unary not binary plus/minus operator */ apNode[0]->pOp = jx9ExprExtractOperator(&apNode[0]->pStart->sData, 0); apNode[0]->pStart->pUserData = (void *)apNode[0]->pOp; } iParen = iSquare = iBraces = 0; for( i = 0 ; i < nNode ; ++i ){ if( apNode[i]->pStart->nType & JX9_TK_LPAREN /*'('*/){ if( i > 0 && ( apNode[i-1]->xCode == jx9CompileVariable || apNode[i-1]->xCode == jx9CompileLiteral || (apNode[i - 1]->pStart->nType & (JX9_TK_ID|JX9_TK_KEYWORD|JX9_TK_SSTR|JX9_TK_DSTR|JX9_TK_RPAREN/*')'*/|JX9_TK_CSB/*]*/))) ){ /* Ticket 1433-033: Take care to ignore alpha-stream [i.e: or, xor] operators followed by an opening parenthesis */ if( (apNode[i - 1]->pStart->nType & JX9_TK_OP) == 0 ){ /* We are dealing with a postfix [i.e: function call] operator * not a simple left parenthesis. Mark the node. */ apNode[i]->pStart->nType |= JX9_TK_OP; apNode[i]->pStart->pUserData = (void *)&sFCallOp; /* Function call operator */ apNode[i]->pOp = &sFCallOp; } } iParen++; }else if( apNode[i]->pStart->nType & JX9_TK_RPAREN/*')*/){ if( iParen <= 0 ){ rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token ')'"); if( rc != SXERR_ABORT ){ rc = SXERR_SYNTAX; } return rc; } iParen--; }else if( apNode[i]->pStart->nType & JX9_TK_OSB /*'['*/ && apNode[i]->xCode == 0 ){ iSquare++; }else if (apNode[i]->pStart->nType & JX9_TK_CSB /*']'*/){ if( iSquare <= 0 ){ rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token ']'"); if( rc != SXERR_ABORT ){ rc = SXERR_SYNTAX; } return rc; } iSquare--; }else if( apNode[i]->pStart->nType & JX9_TK_OCB /*'{'*/ && apNode[i]->xCode == 0 ){ iBraces++; }else if (apNode[i]->pStart->nType & JX9_TK_CCB /*'}'*/){ if( iBraces <= 0 ){ rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token '}'"); if( rc != SXERR_ABORT ){ rc = SXERR_SYNTAX; } return rc; } iBraces--; }else if( apNode[i]->pStart->nType & JX9_TK_OP ){ const jx9_expr_op *pOp = (const jx9_expr_op *)apNode[i]->pOp; if( i > 0 && (pOp->iOp == EXPR_OP_UMINUS || pOp->iOp == EXPR_OP_UPLUS)){ if( apNode[i-1]->xCode == jx9CompileVariable || apNode[i-1]->xCode == jx9CompileLiteral ){ sxi32 iExprOp = EXPR_OP_SUB; /* Binary minus */ sxu32 n = 0; if( pOp->iOp == EXPR_OP_UPLUS ){ iExprOp = EXPR_OP_ADD; /* Binary plus */ } /* * TICKET 1433-013: This is a fix around an obscure bug when the user uses * a variable name which is an alpha-stream operator [i.e: $and, $xor, $eq..]. */ while( n < SX_ARRAYSIZE(aOpTable) && aOpTable[n].iOp != iExprOp ){ ++n; } pOp = &aOpTable[n]; /* Mark as binary '+' or '-', not an unary */ apNode[i]->pOp = pOp; apNode[i]->pStart->pUserData = (void *)pOp; } } } } if( iParen != 0 || iSquare != 0 || iBraces != 0){ rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[0]->pStart->nLine, "Syntax error, mismatched '(', '[' or '{'"); if( rc != SXERR_ABORT ){ rc = SXERR_SYNTAX; } return rc; } return SXRET_OK; }