ICCItem *CreateListFromImage (CCodeChain &CC, const CObjectImageArray &Image, int iRotation) // CreateListFromImage // // Creates an imageDesc from an image { ICCItem *pResult = CC.CreateLinkedList(); if (pResult->IsError()) return pResult; CCLinkedList *pList = (CCLinkedList *)pResult; // Add the bitmap UNID ICCItem *pValue = CC.CreateInteger(Image.GetBitmapUNID()); pList->Append(&CC, pValue, NULL); pValue->Discard(&CC); // Get the rect RECT rcRect = Image.GetImageRect(0, iRotation); // Add the x coordinate pValue = CC.CreateInteger(rcRect.left); pList->Append(&CC, pValue, NULL); pValue->Discard(&CC); // Add the y coordinate pValue = CC.CreateInteger(rcRect.top); pList->Append(&CC, pValue, NULL); pValue->Discard(&CC); // Add width pValue = CC.CreateInteger(RectWidth(rcRect)); pList->Append(&CC, pValue, NULL); pValue->Discard(&CC); // Add height pValue = CC.CreateInteger(RectHeight(rcRect)); pList->Append(&CC, pValue, NULL); pValue->Discard(&CC); // Done return pResult; }
ICCItem *fnAppend (CEvalContext *pCtx, ICCItem *pArgs, DWORD dwData) // fnAppend // // Appends two or more elements together { int i, j; CCodeChain *pCC = pCtx->pCC; // Create a new list to store the result in ICCItem *pResult = pCC->CreateLinkedList(); if (pResult->IsError()) return pResult; CCLinkedList *pList = (CCLinkedList *)pResult; // Loop over all arguments and add to result list for (i = 0; i < pArgs->GetCount(); i++) { ICCItem *pItem = pArgs->GetElement(i); for (j = 0; j < pItem->GetCount(); j++) pList->Append(pCC, pItem->GetElement(j), NULL); } // Done return pResult; }
ICCItem *fnShuffle (CEvalContext *pCtx, ICCItem *pArgs, DWORD dwData) // fnShuffle // // Shuffles a list randomly { int i; CCodeChain *pCC = pCtx->pCC; if (pArgs->GetElement(0)->IsNil()) return pCC->CreateNil(); // Create a destination list ICCItem *pResult = pCC->CreateLinkedList(); if (pResult->IsError()) return pResult; CCLinkedList *pList = (CCLinkedList *)pResult; // Copy the list ICCItem *pSource = pArgs->GetElement(0); for (i = 0; i < pSource->GetCount(); i++) pList->Append(pCC, pSource->GetElement(i), NULL); // Shuffle the new list pList->Shuffle(pCC); // Done return pResult; }
ICCItem *CreateListFromBinary (CCodeChain &CC, void const *pvSource, int iLengthBytes) // CreateListFromBinary // // Creates a code chain list from a block of memory { ICCItem *pResult = CC.CreateLinkedList(); if (pResult->IsError()) return pResult; CCLinkedList *pList = (CCLinkedList *)pResult; // CItem is two DWORD long DWORD *pSource = (DWORD *)pvSource; int iCount = AlignUp(iLengthBytes, sizeof(DWORD)) / sizeof(DWORD); for (int i = 0; i < iCount; i++) { ICCItem *pInt = CC.CreateInteger(*pSource++); pList->Append(&CC, pInt, NULL); pInt->Discard(&CC); } return pResult; }
ICCItem *CreateListFromBinary (CCodeChain &CC, const CString &sClass, void const *pvSource, int iLengthBytes) // CreateListFromBinary // // Creates a code chain list from a block of memory { ICCItem *pResult = CC.CreateLinkedList(); if (pResult->IsError()) return pResult; CCLinkedList *pList = (CCLinkedList *)pResult; // Add a class, if provided if (!sClass.IsBlank()) pList->AppendString(CC, sClass); // Add binary bytes in DWORD chunks. DWORD *pSource = (DWORD *)pvSource; int iCount = AlignUp(iLengthBytes, sizeof(DWORD)) / sizeof(DWORD); for (int i = 0; i < iCount; i++) { ICCItem *pInt = CC.CreateInteger(*pSource++); pList->Append(CC, pInt); pInt->Discard(&CC); } return pResult; }
ICCItem *CCSymbolTable::GetElement (CCodeChain *pCC, int iIndex) // GetElement // // Returns a key/value pair { if (iIndex < 0 || iIndex >= m_Symbols.GetCount()) return pCC->CreateNil(); CCLinkedList *pList = (CCLinkedList *)pCC->CreateLinkedList(); ICCItem *pKey = pCC->CreateString(m_Symbols.GetKey(iIndex)); pList->Append(pCC, pKey); pKey->Discard(pCC); pList->Append(pCC, GetElement(iIndex)); // Done return pList; }
ICCItem *CCodeChain::PoolUsage (void) // PoolUsage // // Returns a count of each pool { int iPoolCount[POOL_COUNT]; int i; ICCItem *pResult; CCLinkedList *pList; // Get the counts now so we don't affect the results iPoolCount[INTEGER_POOL] = m_IntegerPool.GetCount(); iPoolCount[STRING_POOL] = m_StringPool.GetCount(); iPoolCount[LIST_POOL] = m_ListPool.GetCount(); iPoolCount[PRIMITIVE_POOL] = m_PrimitivePool.GetCount(); iPoolCount[SYMBOLTABLE_POOL] = m_SymbolTablePool.GetCount(); iPoolCount[LAMBDA_POOL] = m_LambdaPool.GetCount(); iPoolCount[ATOMTABLE_POOL] = m_AtomTablePool.GetCount(); iPoolCount[VECTOR_POOL] = m_VectorPool.GetCount(); iPoolCount[DOUBLE_POOL] = m_DoublePool.GetCount(); // Create pResult = CreateLinkedList(); if (pResult->IsError()) return pResult; pList = (CCLinkedList *)pResult; for (i = 0; i < POOL_COUNT; i++) { ICCItem *pItem; // Make an item for the count pItem = CreateInteger(iPoolCount[i]); // Add the item to the list pList->Append(*this, pItem); pItem->Discard(this); } return pList; }
ICCItem *CCAtomTable::ListSymbols (CCodeChain *pCC) // ListSymbols // // Returns a list of all the atoms in the table { // If there are no symbols, return Nil if (m_Table.GetCount() == 0) return pCC->CreateNil(); // Otherwise, make a list else { int i; ICCItem *pResult; CCLinkedList *pList; pResult = pCC->CreateLinkedList(); if (pResult->IsError()) return pResult; pList = (CCLinkedList *)pResult; for (i = 0; i < m_Table.GetCount(); i++) { ICCItem *pItem; int iKey; m_Table.GetEntry(i, &iKey, NULL); // Make an item for the symbol pItem = pCC->CreateInteger(iKey); // Add the item to the list pList->Append(pCC, pItem, NULL); pItem->Discard(pCC); } return pList; } }
ICCItem *fnFilter (CEvalContext *pCtx, ICCItem *pArgs, DWORD dwData) // fnFilter // // Filters a list based on a boolean expression. // // (filter list var exp) -> list { int i; CCodeChain *pCC = pCtx->pCC; if (pArgs->GetElement(0)->IsNil()) return pCC->CreateNil(); // Args ICCItem *pSource = pArgs->GetElement(0); ICCItem *pVar = pArgs->GetElement(1); ICCItem *pBody = pArgs->GetElement(2); // Create a destination list ICCItem *pResult = pCC->CreateLinkedList(); if (pResult->IsError()) return pResult; CCLinkedList *pList = (CCLinkedList *)pResult; // Setup the locals. We start by creating a local symbol table ICCItem *pLocalSymbols = pCC->CreateSymbolTable(); if (pLocalSymbols->IsError()) { pResult->Discard(pCC); return pLocalSymbols; } // Associate the enumaration variable ICCItem *pError = pLocalSymbols->AddEntry(pCC, pVar, pCC->CreateNil()); if (pError->IsError()) { pLocalSymbols->Discard(pCC); pResult->Discard(pCC); return pError; } pError->Discard(pCC); // Setup the context if (pCtx->pLocalSymbols) pLocalSymbols->SetParent(pCtx->pLocalSymbols); else pLocalSymbols->SetParent(pCtx->pLexicalSymbols); ICCItem *pOldSymbols = pCtx->pLocalSymbols; pCtx->pLocalSymbols = pLocalSymbols; // Get the offset of the variable so we don't have to // search for it all the time int iVarOffset = pLocalSymbols->FindOffset(pCC, pVar); // Loop over all elements of the list for (i = 0; i < pSource->GetCount(); i++) { ICCItem *pItem = pSource->GetElement(i); // Set the element pLocalSymbols->AddByOffset(pCC, iVarOffset, pItem); // Eval ICCItem *pSelect = pCC->Eval(pCtx, pBody); if (pSelect->IsError()) { pResult->Discard(pCC); pResult = pSelect; break; } // If the evaluation is not Nil, then we include the // item in the result if (!pSelect->IsNil()) pList->Append(pCC, pItem, NULL); pSelect->Discard(pCC); } // Clean up pCtx->pLocalSymbols = pOldSymbols; pLocalSymbols->Discard(pCC); // Done if (pResult->GetCount() > 0) return pResult; else { pResult->Discard(pCC); return pCC->CreateNil(); } }
ICCItem *fnApply (CEvalContext *pCtx, ICCItem *pArguments, DWORD dwData) // fnApply // // Applies the given parameter list to the lambda expression // // (apply exp arg1 arg2 ... argn list) { CCodeChain *pCC = pCtx->pCC; ICCItem *pArgs; ICCItem *pResult; ICCItem *pFunction; ICCItem *pLast; CCLinkedList *pList; int i; // Evaluate the arguments and validate them pArgs = pCC->EvaluateArgs(pCtx, pArguments, CONSTLIT("v*")); if (pArgs->IsError()) return pArgs; // We better have at least two arguments if (pArgs->GetCount() < 2) { pArgs->Discard(pCC); return pCC->CreateError(CONSTLIT("apply needs a function and a list of arguments."), NULL); } // The last argument better be a list pLast = pArgs->GetElement(pArgs->GetCount() - 1); if (!pLast->IsList()) { pArgs->Discard(pCC); return pCC->CreateError(CONSTLIT("Last argument for apply must be a list."), NULL); } // The first argument is the function pFunction = pArgs->Head(pCC); // Create a new list to store the arguments in pResult = pCC->CreateLinkedList(); if (pResult->IsError()) { pArgs->Discard(pCC); return pResult; } pList = (CCLinkedList *)pResult; // Add each of the arguments except the last for (i = 1; i < pArgs->GetCount() - 1; i++) { pList->Append(pCC, pArgs->GetElement(i), &pResult); if (pResult->IsError()) { pList->Discard(pCC); pArgs->Discard(pCC); return pResult; } pResult->Discard(pCC); } // Add each of the elements of the last list for (i = 0; i < pLast->GetCount(); i++) { pList->Append(pCC, pLast->GetElement(i), &pResult); if (pResult->IsError()) { pList->Discard(pCC); pArgs->Discard(pCC); return pResult; } pResult->Discard(pCC); } // Set the literal flag to indicate that the arguments should // not be evaluated. pList->SetQuoted(); // Execute the function if (pFunction->IsFunction()) pResult = pFunction->Execute(pCtx, pList); else pResult = pFunction->Reference(); pList->Discard(pCC); // Done pArgs->Discard(pCC); return pResult; }
ICCItem *fnLinkedList (CEvalContext *pCtx, ICCItem *pArguments, DWORD dwData) // fnLinkedList // // Handles linked-list specific functions // // (lnkAppend linked-list item) -> list // (lnkRemove linked-list index) -> list // (lnkRemoveNil linked-list) -> list // (lnkReplace linked-list index item) -> list // // HACK: This function has different behavior depending on the first // argument. If the first argument is a variable holding a linked list, // then the variable contents will be changed. If the variable holds Nil, // then the variable contents are not changed. In all cases, the caller // should structure the call as: (setq ListVar (lnkAppend ListVar ...)) // in order to handle all cases. { CCodeChain *pCC = pCtx->pCC; ICCItem *pArgs; ICCItem *pList; CCLinkedList *pLinkedList; ICCItem *pResult; // Evaluate the arguments if (dwData == FN_LINKEDLIST_APPEND) pArgs = pCC->EvaluateArgs(pCtx, pArguments, CONSTLIT("lv")); else if (dwData == FN_LINKEDLIST_REMOVE_NIL) pArgs = pCC->EvaluateArgs(pCtx, pArguments, CONSTLIT("l")); else pArgs = pCC->EvaluateArgs(pCtx, pArguments, CONSTLIT("liv")); if (pArgs->IsError()) return pArgs; // Get the linked list pList = pArgs->GetElement(0); if (pList->GetClass()->GetObjID() == OBJID_CCLINKEDLIST) pLinkedList = (CCLinkedList *)pList->Reference(); else if (pList->IsNil()) { pList = pCC->CreateLinkedList(); if (pList->IsError()) { pArgs->Discard(pCC); return pList; } pLinkedList = (CCLinkedList *)pList; } else { pArgs->Discard(pCC); return pCC->CreateError(CONSTLIT("Linked-list expected:"), NULL); } // Do the right thing switch (dwData) { case FN_LINKEDLIST_APPEND: { ICCItem *pItem = pArgs->GetElement(1); ICCItem *pError; pLinkedList->Append(pCC, pItem, &pError); if (pError->IsError()) { pLinkedList->Discard(pCC); pResult = pError; } else { pError->Discard(pCC); pResult = pLinkedList; } break; } case FN_LINKEDLIST_REMOVE: { int iIndex = pArgs->GetElement(1)->GetIntegerValue(); // Make sure we're in range if (iIndex < 0 || iIndex >= pLinkedList->GetCount()) { pLinkedList->Discard(pCC); pResult = pCC->CreateError(CONSTLIT("Index out of range:"), pArgs->GetElement(1)); } else { pLinkedList->RemoveElement(pCC, iIndex); pResult = pLinkedList; } break; } case FN_LINKEDLIST_REMOVE_NIL: { // Iterate over all elements and remove any elements that are Nil int iIndex = 0; while (iIndex < pLinkedList->GetCount()) { if (pLinkedList->GetElement(iIndex)->IsNil()) pLinkedList->RemoveElement(pCC, iIndex); else iIndex++; } // Done pResult = pLinkedList; break; } case FN_LINKEDLIST_REPLACE: { int iIndex = pArgs->GetElement(1)->GetIntegerValue(); ICCItem *pItem = pArgs->GetElement(2); // Make sure we're in range if (iIndex < 0 || iIndex >= pLinkedList->GetCount()) { pLinkedList->Discard(pCC); pResult = pCC->CreateError(CONSTLIT("Index out of range:"), pArgs->GetElement(1)); } else { pLinkedList->ReplaceElement(pCC, iIndex, pItem); pResult = pLinkedList; } break; } default: ASSERT(FALSE); return NULL; } // Done pArgs->Discard(pCC); return pResult; }
ICCItem *fnPageMap (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) // fnPageMap // // (pageMap address|pageID enumMethod ['excludeNil] var exp) -> filtered list { CCodeChain *pCC = pEvalCtx->pCC; // Args ICCItem *pAddress = pArgs->GetElement(0); ICCItem *pMethod = pArgs->GetElement(1); bool bExcludeNil; int iOptionalArg = 2; if (pArgs->GetCount() > 4) bExcludeNil = strEquals(pArgs->GetElement(iOptionalArg++)->GetStringValue(), CONSTLIT("excludeNil")); else bExcludeNil = false; ICCItem *pVar = pArgs->GetElement(iOptionalArg++); ICCItem *pBody = pArgs->GetElement(iOptionalArg++); // Open the page IPage *pPage; CString sError; if (g_PM.OpenPage(pAddress->GetStringValue(), &pPage, &sError) != NOERROR) return pCC->CreateError(sError, NULL); // Prepare the method SPageEnumCtx EnumCtx; if (pPage->EnumReset(*pCC, pMethod, EnumCtx, &sError)) { g_PM.ClosePage(pPage); return pCC->CreateError(sError, NULL); } // Create a destination list ICCItem *pResult = pCC->CreateLinkedList(); if (pResult->IsError()) { g_PM.ClosePage(pPage); return pResult; } CCLinkedList *pList = (CCLinkedList *)pResult; // Setup the locals. We start by creating a local symbol table ICCItem *pLocalSymbols = pCC->CreateSymbolTable(); if (pLocalSymbols->IsError()) { pResult->Discard(pCC); g_PM.ClosePage(pPage); return pLocalSymbols; } // Associate the enumaration variable ICCItem *pError = pLocalSymbols->AddEntry(pCC, pVar, pCC->CreateNil()); if (pError->IsError()) { pLocalSymbols->Discard(pCC); pResult->Discard(pCC); g_PM.ClosePage(pPage); return pError; } pError->Discard(pCC); // Setup the context if (pEvalCtx->pLocalSymbols) pLocalSymbols->SetParent(pEvalCtx->pLocalSymbols); else pLocalSymbols->SetParent(pEvalCtx->pLexicalSymbols); ICCItem *pOldSymbols = pEvalCtx->pLocalSymbols; pEvalCtx->pLocalSymbols = pLocalSymbols; // Get the offset of the variable so we don't have to // search for it all the time int iVarOffset = pLocalSymbols->FindOffset(pCC, pVar); // Enumerate the page while (pPage->EnumHasMore(EnumCtx)) { ICCItem *pItem = pPage->EnumGetNext(*pCC, EnumCtx); if (pItem->IsError()) { pResult->Discard(pCC); pResult = pItem; break; } // Set the element pLocalSymbols->AddByOffset(pCC, iVarOffset, pItem); // Eval ICCItem *pMapped = pCC->Eval(pEvalCtx, pBody); if (pMapped->IsError()) { pItem->Discard(pCC); pResult->Discard(pCC); pResult = pMapped; break; } // If the evaluation is not Nil, then we include the // item in the result if (!bExcludeNil || !pMapped->IsNil()) pList->Append(*pCC, pMapped); pItem->Discard(pCC); pMapped->Discard(pCC); } // Clean up pEvalCtx->pLocalSymbols = pOldSymbols; pLocalSymbols->Discard(pCC); g_PM.ClosePage(pPage); // Done if (pResult->GetCount() > 0) return pResult; else { pResult->Discard(pCC); return pCC->CreateNil(); } }
ICCItem *fnPageGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) // fnPageGet // // (pageGet address|pageID enumMethod [startIndex] [count]) -> list { CCodeChain *pCC = pEvalCtx->pCC; // Args ICCItem *pAddress = pArgs->GetElement(0); ICCItem *pMethod = pArgs->GetElement(1); int iStart = (pArgs->GetCount() > 2 ? pArgs->GetElement(2)->GetIntegerValue() : 0); int iCount = (pArgs->GetCount() > 3 ? pArgs->GetElement(3)->GetIntegerValue() : -1); // Open the page IPage *pPage; CString sError; if (g_PM.OpenPage(pAddress->GetStringValue(), &pPage, &sError) != NOERROR) return pCC->CreateError(sError, NULL); // Prepare the method SPageEnumCtx EnumCtx; if (pPage->EnumReset(*pCC, pMethod, EnumCtx, &sError)) { g_PM.ClosePage(pPage); return pCC->CreateError(sError, NULL); } // Create a destination list ICCItem *pResult = pCC->CreateLinkedList(); if (pResult->IsError()) { g_PM.ClosePage(pPage); return pResult; } CCLinkedList *pList = (CCLinkedList *)pResult; // Enumerate the page while ((iCount == -1 || iCount > 0) && pPage->EnumHasMore(EnumCtx)) { ICCItem *pItem = pPage->EnumGetNext(*pCC, EnumCtx); if (pItem->IsError()) { pResult->Discard(pCC); pResult = pItem; break; } // Add to list if (iStart == 0) { pList->Append(*pCC, pItem); iCount--; } else iStart--; pItem->Discard(pCC); } // Clean up g_PM.ClosePage(pPage); // Done if (pResult->GetCount() > 0) return pResult; else { pResult->Discard(pCC); return pCC->CreateNil(); } }
ICCItem *CCodeChain::EvaluateArgs (CEvalContext *pCtx, ICCItem *pArgs, const CString &sArgValidation) // EvaluateArgs // // Evaluate arguments and validate their types { ICCItem *pArg; ICCItem *pNew; ICCItem *pError; CCLinkedList *pEvalList; char *pValidation; int i; BOOL bNoEval; // If the argument list if quoted, then it means that the arguments // have already been evaluated. This happens if we've been called by // (apply). bNoEval = pArgs->IsQuoted(); // Create a list to hold the results pNew = CreateLinkedList(); if (pNew->IsError()) return pNew; pEvalList = dynamic_cast<CCLinkedList *>(pNew); // Start parsing at the beginning pValidation = sArgValidation.GetPointer(); // If there is a '*' in the validation, figure out // how many arguments it represents int iVarArgs = Max(0, pArgs->GetCount() - (sArgValidation.GetLength() - 1)); // Loop over each argument for (i = 0; i < pArgs->GetCount(); i++) { ICCItem *pResult; pArg = pArgs->GetElement(i); // If we're processing variable args, see if we're done if (*pValidation == '*') { if (iVarArgs == 0) pValidation++; else iVarArgs--; } // Evaluate the item. If the arg is 'q' or 'u' then we // don't evaluate it. if (bNoEval || *pValidation == 'q' || *pValidation == 'u') pResult = pArg->Reference(); // If the arg is 'c' then we don't evaluate unless it is // a lambda expression (or an identifier) else if (*pValidation == 'c' && !pArg->IsLambdaExpression() && !pArg->IsIdentifier()) pResult = pArg->Reference(); // Evaluate else { pResult = Eval(pCtx, pArg); // We don't want to return on error because some functions // might want to pass errors around if (*pValidation != 'v' && *pValidation != '*') { if (pResult->IsError()) { pEvalList->Discard(this); return pResult; } } } // Check to see if the item is valid switch (*pValidation) { // We expect a function... case 'f': { if (!pResult->IsFunction()) { pError = CreateError(LITERAL("Function expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect a numeral... // // NOTE: We treat integer the same a numeral because it's not always // clear to the user when they've created a double or an integer. // It is up to the actual function to use the integer or double // value appropriately. case 'i': case 'n': { if (!pResult->IsDouble() && !pResult->IsInteger()) { pError = CreateError(LITERAL("Numeral expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect a double... case 'd': { if (!pResult->IsDouble()) { pError = CreateError(LITERAL("Double expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect a vEctor... case 'e': { if (!(pResult->GetValueType() == ICCItem::Vector)) { pError = CreateError(LITERAL("Vector expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect a linked list case 'k': { if (pResult->GetClass()->GetObjID() != OBJID_CCLINKEDLIST) { pError = CreateError(LITERAL("Linked-list expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect a list case 'l': { if (!pResult->IsList()) { pError = CreateError(LITERAL("List expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect an identifier case 's': case 'q': { if (!pResult->IsIdentifier()) { pError = CreateError(LITERAL("Identifier expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect an atom table case 'x': { if (!pResult->IsAtomTable()) { pError = CreateError(LITERAL("Atom table expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect a symbol table case 'y': { if (!pResult->IsSymbolTable()) { pError = CreateError(LITERAL("Symbol table expected"), pResult); pResult->Discard(this); pEvalList->Discard(this); return pError; } break; } // We expect anything case 'c': case 'u': case 'v': break; // We expect any number of anythings... case '*': break; // Too many arguments case '\0': { pError = CreateError(LITERAL("Too many arguments"), NULL); pResult->Discard(this); pEvalList->Discard(this); return pError; } default: ASSERT(FALSE); } // Add the result to the list pEvalList->Append(*this, pResult); pResult->Discard(this); // Next validation sequence (note that *pValidation can never // be '\0' because we return above if we find it) if (*pValidation != '*') pValidation++; } // Make sure we have enough arguments if (*pValidation != '\0' && *pValidation != '*') { pError = CreateError(LITERAL("Insufficient arguments"), NULL); pEvalList->Discard(this); return pError; } // Return the evaluation list return pEvalList; }
ICCItem *CCLambda::Execute (CEvalContext *pCtx, ICCItem *pArgs) // Execute // // Executes the function and returns a result { CCodeChain *pCC = pCtx->pCC; ICCItem *pItem; ICCItem *pOldSymbols; ICCItem *pLocalSymbols; ICCItem *pVar; ICCItem *pArg; ICCItem *pResult; int i; BOOL bNoEval; // We must have been initialized if (m_pArgList == NULL || m_pCode == NULL) return pCC->CreateNil(); // If the argument list if quoted, then it means that the arguments // have already been evaluated. This happens if we've been called by // (apply). bNoEval = pArgs->IsQuoted(); // Set up the symbol table pLocalSymbols = pCC->CreateSymbolTable(); if (pLocalSymbols->IsError()) return pLocalSymbols; // Loop over each item and associate it for (i = 0; i < m_pArgList->GetCount(); i++) { pVar = m_pArgList->GetElement(i); pArg = pArgs->GetElement(i); // If the name of this variable is %args, then the rest of the arguments // should go into a list if (strCompareAbsolute(pVar->GetStringValue(), CONSTLIT("%args")) == 0) { ICCItem *pVarArgs; // If there are arguments left, add them to a list if (pArg) { int j; ICCItem *pError; CCLinkedList *pList; // Create a list pVarArgs = pCC->CreateLinkedList(); if (pVarArgs->IsError()) { pLocalSymbols->Discard(pCC); return pVarArgs; } pList = (CCLinkedList *)pVarArgs; // Add each argument to the list for (j = i; j < pArgs->GetCount(); j++) { pArg = pArgs->GetElement(j); if (bNoEval) pResult = pArg->Reference(); else pResult = pCC->Eval(pCtx, pArg); pList->Append(pCC, pResult, &pError); pResult->Discard(pCC); if (pError->IsError()) { pVarArgs->Discard(pCC); pLocalSymbols->Discard(pCC); return pError; } pError->Discard(pCC); } } else pVarArgs = pCC->CreateNil(); // Add to the local symbol table pItem = pLocalSymbols->AddEntry(pCC, pVar, pVarArgs); pVarArgs->Discard(pCC); } // Bind the variable to the argument else if (pArg == NULL) pItem = pLocalSymbols->AddEntry(pCC, pVar, pCC->CreateNil()); else { ICCItem *pResult; // Evaluate the arg and add to the table if (bNoEval) pResult = pArg->Reference(); else pResult = pCC->Eval(pCtx, pArg); pItem = pLocalSymbols->AddEntry(pCC, pVar, pResult); pResult->Discard(pCC); } // Check for error if (pItem->IsError()) { pLocalSymbols->Discard(pCC); return pItem; } pItem->Discard(pCC); } // Setup the context pLocalSymbols->SetParent(pCtx->pLexicalSymbols); pOldSymbols = pCtx->pLocalSymbols; pCtx->pLocalSymbols = pLocalSymbols; // Evalute the code pResult = pCC->Eval(pCtx, m_pCode); // Clean up pCtx->pLocalSymbols = pOldSymbols; pLocalSymbols->Discard(pCC); return pResult; }
ICCItem *CCodeChain::Link (const CString &sString, int iOffset, int *retiLinked, int *ioiCurLine) // Link // // Parses the given string and converts it into a linked // chain of items { char *pStart; char *pPos; ICCItem *pResult = NULL; int iCurLine = (ioiCurLine ? *ioiCurLine : 1); pStart = sString.GetPointer() + iOffset; pPos = pStart; // Skip any whitespace pPos = SkipWhiteSpace(pPos, &iCurLine); // If we've reached the end, then we have // nothing if (*pPos == '\0') pResult = CreateNil(); // If we've got a literal quote, then remember it else if (*pPos == SYMBOL_QUOTE) { int iLinked; pPos++; pResult = Link(sString, iOffset + (pPos - pStart), &iLinked, &iCurLine); if (pResult->IsError()) return pResult; pPos += iLinked; // Make it a literal pResult->SetQuoted(); } // If we've got an open paren then we start a list else if (*pPos == SYMBOL_OPENPAREN) { ICCItem *pNew = CreateLinkedList(); if (pNew->IsError()) return pNew; CCLinkedList *pList = dynamic_cast<CCLinkedList *>(pNew); // Keep reading until we find the end pPos++; // If the list is empty, then there's nothing to do pPos = SkipWhiteSpace(pPos, &iCurLine); if (*pPos == SYMBOL_CLOSEPAREN) { pList->Discard(this); pResult = CreateNil(); pPos++; } // Get all the items in the list else { while (*pPos != SYMBOL_CLOSEPAREN && *pPos != '\0') { ICCItem *pItem; int iLinked; pItem = Link(sString, iOffset + (pPos - pStart), &iLinked, &iCurLine); if (pItem->IsError()) return pItem; // Add the item to the list pList->Append(this, pItem, NULL); pItem->Discard(this); // Move the position pPos += iLinked; // Skip whitespace pPos = SkipWhiteSpace(pPos, &iCurLine); } // If we have a close paren then we're done; Otherwise we've // got an error of some kind if (*pPos == SYMBOL_CLOSEPAREN) { pPos++; pResult = pList; } else { pList->Discard(this); pResult = CreateParseError(iCurLine, CONSTLIT("Mismatched open parenthesis")); } } } // If this is an open brace then we've got a literal structure else if (*pPos == SYMBOL_OPENBRACE) { ICCItem *pNew = CreateSymbolTable(); if (pNew->IsError()) return pNew; CCSymbolTable *pTable = dynamic_cast<CCSymbolTable *>(pNew); // Always literal pTable->SetQuoted(); // Keep reading until we find the end pPos++; // If the list is empty, then there's nothing to do pPos = SkipWhiteSpace(pPos, &iCurLine); if (*pPos == SYMBOL_CLOSEBRACE) { pResult = pTable; pPos++; } // Get all the items in the list else { while (*pPos != SYMBOL_CLOSEBRACE && *pPos != '\0') { // Get the key ICCItem *pKey; int iLinked; pKey = Link(sString, iOffset + (pPos - pStart), &iLinked, &iCurLine); if (pKey->IsError()) { pTable->Discard(this); return pKey; } // Move the position and read a colon pPos += iLinked; pPos = SkipWhiteSpace(pPos, &iCurLine); if (*pPos != SYMBOL_COLON) { pKey->Discard(this); pTable->Discard(this); return CreateParseError(iCurLine, CONSTLIT("Struct value not found.")); } pPos++; // Get the value ICCItem *pValue; pValue = Link(sString, iOffset + (pPos - pStart), &iLinked, &iCurLine); if (pValue->IsError()) { pKey->Discard(this); pTable->Discard(this); return pValue; } // Move the position pPos += iLinked; // Add the item to the table pResult = pTable->AddEntry(this, pKey, pValue); pKey->Discard(this); pValue->Discard(this); if (pResult->IsError()) { pTable->Discard(this); return pResult; } // Skip whitespace because otherwise we won't know whether we // hit the end brace. pPos = SkipWhiteSpace(pPos, &iCurLine); } // If we have a close paren then we're done; Otherwise we've // got an error of some kind if (*pPos == SYMBOL_CLOSEBRACE) { pPos++; pResult = pTable; } else { pTable->Discard(this); pResult = CreateParseError(iCurLine, CONSTLIT("Mismatched open brace")); } } } // If this is an open quote, then read everything until // the close quote else if (*pPos == SYMBOL_OPENQUOTE) { // Parse the string, until the end quote, parsing escape codes char *pStartFragment = NULL; CString sResultString; bool bDone = false; while (!bDone) { pPos++; switch (*pPos) { case SYMBOL_CLOSEQUOTE: case '\0': { if (pStartFragment) { sResultString.Append(CString(pStartFragment, pPos - pStartFragment)); pStartFragment = NULL; } bDone = true; break; } case SYMBOL_BACKSLASH: { if (pStartFragment) { sResultString.Append(CString(pStartFragment, pPos - pStartFragment)); pStartFragment = NULL; } pPos++; if (*pPos == '\0') bDone = true; else if (*pPos == 'n') sResultString.Append(CString("\n", 1)); else if (*pPos == 'r') sResultString.Append(CString("\r", 1)); else if (*pPos == 't') sResultString.Append(CString("\t", 1)); else if (*pPos == '0') sResultString.Append(CString("\0", 1)); else if (*pPos == 'x' || *pPos == 'X') { pPos++; int iFirstDigit = strGetHexDigit(pPos); pPos++; int iSecondDigit = 0; if (*pPos == '\0') bDone = true; else iSecondDigit = strGetHexDigit(pPos); char chChar = (char)(16 * iFirstDigit + iSecondDigit); sResultString.Append(CString(&chChar, 1)); } else sResultString.Append(CString(pPos, 1)); break; } default: { if (pStartFragment == NULL) pStartFragment = pPos; break; } } } // If we found the close, then create a string; otherwise, // it is an error if (*pPos == SYMBOL_CLOSEQUOTE) { pResult = CreateString(sResultString); // Always a literal pResult->SetQuoted(); // Skip past quote pPos++; } else pResult = CreateParseError(iCurLine, CONSTLIT("Mismatched quote")); } // If this is a close paren, then it is an error else if (*pPos == SYMBOL_CLOSEPAREN) pResult = CreateParseError(iCurLine, CONSTLIT("Mismatched close parenthesis")); // If this is a close brace, then it is an error else if (*pPos == SYMBOL_CLOSEBRACE) pResult = CreateParseError(iCurLine, CONSTLIT("Mismatched close brace")); // Colons cannot appear alone else if (*pPos == SYMBOL_COLON) pResult = CreateParseError(iCurLine, CONSTLIT("':' character must appear inside quotes or in a struct definition.")); // Otherwise this is an string of some sort else { char *pStartString; CString sIdentifier; int iInt; bool bNotInteger; pStartString = pPos; // Look for whitespace while (*pPos != '\0' && *pPos != ' ' && *pPos != '\n' && *pPos != '\r' && *pPos != '\t' && *pPos != SYMBOL_OPENPAREN && *pPos != SYMBOL_CLOSEPAREN && *pPos != SYMBOL_OPENQUOTE && *pPos != SYMBOL_CLOSEQUOTE && *pPos != SYMBOL_OPENBRACE && *pPos != SYMBOL_CLOSEBRACE && *pPos != SYMBOL_COLON && *pPos != SYMBOL_QUOTE && *pPos != ';') pPos++; // If we did not advance, then we clearly hit an error if (pStartString == pPos) pResult = CreateParseError(iCurLine, strPatternSubst(CONSTLIT("Unexpected character: %s"), CString(pPos, 1))); // If we ended in a quote then that's a bug else if (*pPos == SYMBOL_QUOTE) pResult = CreateParseError(iCurLine, strPatternSubst(CONSTLIT("Identifiers must not use single quote characters: %s"), strSubString(sString, iOffset + (pStartString - pStart), (pPos + 1 - pStartString)))); // Otherwise, get the identifier else { // Create a string from the portion sIdentifier = strSubString(sString, iOffset + (pStartString - pStart), (pPos - pStartString)); // Check to see if this is a reserved identifier if (strCompareAbsolute(sIdentifier, CONSTLIT("Nil")) == 0) pResult = CreateNil(); else if (strCompareAbsolute(sIdentifier, CONSTLIT("True")) == 0) pResult = CreateTrue(); else { // If this is an integer, create an integer; otherwise // create a string iInt = strToInt(sIdentifier, 0, &bNotInteger); if (bNotInteger) pResult = CreateString(sIdentifier); else pResult = CreateInteger(iInt); } } } // Return the result and the number of characters // that we read if (retiLinked) *retiLinked = (pPos - pStart); if (ioiCurLine) *ioiCurLine = iCurLine; return pResult; }