Exemple #1
0
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);
	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);
	pValue->Discard(&CC);

	//	Add the y coordinate

	pValue = CC.CreateInteger(rcRect.top);
	pList->Append(CC, pValue);
	pValue->Discard(&CC);

	//	Add width

	pValue = CC.CreateInteger(RectWidth(rcRect));
	pList->Append(CC, pValue);
	pValue->Discard(&CC);

	//	Add height

	pValue = CC.CreateInteger(RectHeight(rcRect));
	pList->Append(CC, pValue);
	pValue->Discard(&CC);

	//	Done

	return pResult;
	}
Exemple #2
0
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();
		}
	}
Exemple #3
0
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;
	}
Exemple #4
0
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;
	}
Exemple #5
0
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();
		}
	}
Exemple #6
0
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();
		}
	}
Exemple #7
0
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;
	}
Exemple #8
0
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;
	}
Exemple #9
0
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;
	}