add Markdown lib
[couchdbimport.git] / CouchProjects / Fabric / SpecialNodes.h
blobf12bb9e5e91e9c028ba39695075364202928003e
1 /*
2 Fabric formula engine
3 Copyright (C) 2006 Damien Katz
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 // Branching node
23 class If : public RuntimeNode
25 public:
27 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
29 frame.boolVal = false;
31 return m_pFirstChild;
34 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
36 if (frame.boolVal) {
37 // This means the node just executed must be the desired return result.
38 frame.PushArg(pPreviousValue);
39 return NULL; // no more nodes to execute
41 else {
42 if (pPreviousExecuteNode->GetNextSibling() == NULL) {
43 // this means we are an else clause
44 frame.PushArg(pPreviousValue);
45 return NULL;
46 } else if (pPreviousValue->ToBool()) {
47 // We hit a true conditional.
48 // Signal we hit a true conditional for the next time through
49 frame.boolVal = true;
51 // execute the body of the clause
52 return pPreviousExecuteNode->GetNextSibling();
54 else {
55 // conditional wasn't true, skip over the body onto the next
56 // conditional (which will be null if there is no else clause)
58 return pPreviousExecuteNode->GetNextSibling()->GetNextSibling();
63 const List* Execute(StackFrame& frame) const
65 if (frame.ArgCount() == 0) {
66 // this happens when there is no true "if" or "else if" cases and no "else" found
67 return f->NilList();
69 return &frame.LastArg();
74 // Early return: Return(Foo)
75 class Fun_return : public RuntimeNode
77 public:
79 const List* Execute(StackFrame& frame) const
81 f->SetEarlyReturnList(&frame.LastArg());
82 return &frame.LastArg();
87 // var := value;
88 class VariableAssignment : public RuntimeNode
90 public:
92 const List* Execute(StackFrame& frame) const
94 const List* pRetList = &frame.LastArg();
95 f->SetVariableValue(GetTokenIdAtom(), pRetList);
96 return pRetList;
100 // var ?= value;
101 class VariableInit : public RuntimeNode
103 public:
104 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
106 const List* pExistingValue = f->GetValue(GetTokenText(), GetTokenIdAtom());
107 if (pExistingValue) {
108 frame.pReturnList = pExistingValue;
109 return NULL;
111 else {
112 frame.pReturnList = NULL;
113 return m_pFirstChild;
117 const List* Execute(StackFrame& frame) const
119 if (frame.pReturnList) {
120 return frame.pReturnList;
122 else {
123 const List* pRetList = &frame.LastArg();
124 f->SetVariableValue(GetTokenIdAtom(), pRetList);
125 return pRetList;
130 class SelectStatement : public RuntimeNode
132 const List* Execute(StackFrame& frame) const
134 if (frame.ArgCount() == 0) {
135 // "SELECT *" case
136 f->SetSelected(true);
137 return f->TrueList();
140 const List& list = frame.LastArg();
142 if (list.ToBool()) {
143 f->SetSelected(true);
145 else {
146 f->SetSelected(false);
147 f->SetEarlyReturnList(&list); // causes abortion of execution
149 return &list;
153 class Column : public RuntimeNode
155 NodeType GetNodeType() const
157 return NodeType_ColumnAssignment;
160 const List* Execute(StackFrame& frame) const
162 const List* pList = f->GetValue(GetTokenText(), GetTokenIdAtom());
163 f->AppendColumnList(pList);
164 return pList;
169 class ColumnAssignment : public RuntimeNode
171 NodeType GetNodeType() const
173 return NodeType_ColumnAssignment;
176 const List* Execute(StackFrame& frame) const
178 const List* pList = &frame.LastArg();
179 f->AppendColumnList(pList);
180 return pList;
186 class ColumnInit : public RuntimeNode
188 NodeType GetNodeType() const
190 return NodeType_ColumnAssignment;
193 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
195 const List* pExistingValue = f->GetValue(GetTokenText(), GetTokenIdAtom());
196 if (pExistingValue) {
197 frame.pReturnList = pExistingValue;
198 return NULL;
200 else {
201 frame.pReturnList = NULL;
202 return m_pFirstChild;
206 const List* Execute(StackFrame& frame) const
208 if (frame.pReturnList) {
209 f->AppendColumnList(frame.pReturnList);
210 return frame.pReturnList;
212 else {
213 const List* pRetList = &frame.LastArg();
214 f->AppendColumnList(pRetList);
215 return pRetList;
220 // FIELD var := value;
221 class FieldAssignment : public RuntimeNode
223 public:
225 const List* Execute(StackFrame& frame) const
227 f->SetVariableValue(GetTokenIdAtom(), NULL); // clear out the local var
228 const List* pRet = &frame.LastArg();
229 f->GetDocument().SetValue(GetTokenText(), pRet);
230 return pRet;
234 class FieldInit : public RuntimeNode
237 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
239 const List* pExistingValue = f->GetDocument().GetValue(ma, GetTokenText());
240 if (pExistingValue) {
241 frame.pReturnList = pExistingValue;
242 return NULL;
244 else {
245 frame.pReturnList = NULL;
246 return m_pFirstChild;
250 const List* Execute(StackFrame& frame) const
252 if (frame.pReturnList) {
253 return frame.pReturnList;
255 else {
256 f->SetVariableValue(GetTokenIdAtom(), NULL); // clear out the local var
257 const List* pRetList = &frame.LastArg();
258 f->GetDocument().SetValue(GetTokenText(), pRetList);
259 return pRetList;
264 class UnknownFunction : public RuntimeNode
266 const List* pErrorList;
267 public:
268 void CompilerValidateArgsAndInit()
270 // we make this a runtime error instead of compile time
271 // so a future script written for a future Fabric engine
272 // can still run if properly written and degrade gracefully
273 // if language features aren't available
275 StringBuilder str(ma, 50);
276 str += "No built-in function \"";
277 str += GetTokenText();
278 str += "\" found.";
280 pErrorList = new(&f->indefMa) List(&f->indefMa, ErrorElement("UnknownFunction", str));
282 const List* Execute(StackFrame& frame) const
285 return pErrorList;
290 class StringLiteral : public RuntimeNode
292 const List* pLiteral;
293 public:
294 void CompilerValidateArgsAndInit()
296 ASSERT(m_numChildren == 0);
297 const TextElement& token = GetTokenText();
298 char* newString = new(&f->indefMa) char[token.Length()];
299 char* out = newString;
300 const char* in = token.Ptr();
301 const char* inEnd = in + token.Length();
303 // NOTE, we need not do error checking on the input characters, they have
304 // already been validated for correctness.
305 // (impossible input example: "string with single trailing slash\")
308 while (in < inEnd) {
309 if (*in == '\\') {
310 in++;
311 switch (*in) {
312 case 'n':
313 *out = '\n';
314 break;
315 case 't':
316 *out = '\t';
317 break;
318 default:
319 *out = *in;
322 else {
323 *out = *in;
325 out++;
326 in++;
328 pLiteral = new(&f->indefMa) List(&f->indefMa, TextElement(newString, out - newString));
331 const List* Execute(StackFrame& frame) const
333 return pLiteral;
337 class DateTimeLiteral : public RuntimeNode
340 public:
342 const List* Execute(StackFrame& frame) const
344 return f->FalseList();
348 class NumberLiteral : public RuntimeNode
350 const List* pLiteral;
351 public:
352 void CompilerValidateArgsAndInit()
354 ASSERT(m_numChildren == 0);
355 pLiteral = new(&f->indefMa) List(&f->indefMa, GetTokenText().ToNumber());
358 const List* Execute(StackFrame& frame) const
360 return pLiteral;
364 //function Foo(arg) {
365 // expr;
366 //};
367 class UserFunction : public RuntimeNode
369 UserFunctionDescriptor* m_pFunctionDescriptor;
370 public:
371 void CompilerValidateArgsAndInit()
373 ASSERT(m_numChildren >= 1);
375 m_pFunctionDescriptor = new(&f->indefMa) UserFunctionDescriptor(&f->indefMa);
377 m_pFunctionDescriptor->m_argIds.reserve(m_numChildren - 1);
379 const RuntimeNode* pChildNode = m_pFirstChild;
381 // if pChildNode->GetNextSibling() is null, then it means its the last
382 // child node and its not an arg id
383 while (pChildNode->GetNextSibling()) {
384 m_pFunctionDescriptor->m_argIds.push_back(pChildNode->GetTokenIdAtom());
385 pChildNode = pChildNode->GetNextSibling();
388 // pChildNode now points to the last arg, the actual function expression
389 // so store if of in the function descriptor (its the actual function really)
390 m_pFunctionDescriptor->pRuntimeNode = pChildNode;
393 virtual const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
395 // we never execute our args, we wait until called.
396 return NULL;
399 const List* Execute(StackFrame& frame) const
401 f->SetUserFunction(GetTokenIdAtom(), m_pFunctionDescriptor);
403 return NULL;
407 // %UserFunction(args);
408 class UserFunctionCall : public RuntimeNode
410 IdAtom m_argCountIdAtom;
411 const List* m_pArgCountList;
412 public:
414 NodeType GetNodeType() const
416 return NodeType_UserFunctionCall;
419 void CompilerValidateArgsAndInit()
422 ASSERT(m_tokenText.Ptr()[0] == '%');
424 // strip off the leading % sign.
425 m_tokenText = TextElement(m_tokenText.Ptr() + 1, m_tokenText.Length() - 1);
427 m_argCountIdAtom = f->GetIdAtom(TEXT_ELEMENT("$argcount"));
429 m_pArgCountList = new(&f->indefMa) List(&f->indefMa, NumberElement(m_numChildren));
433 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
435 // init our frame vars
436 frame.boolVal = false;
438 if (m_pFirstChild == NULL) {
439 // no args from the caller
440 const UserFunctionDescriptor* pUserFunction = f->GetUserFunction(GetTokenIdAtom());
441 if (pUserFunction) {
442 // we have a function, create a variable map for it and save off the old one
443 f->PushVariableScope();
445 f->SetVariableValue(m_argCountIdAtom, m_pArgCountList);
447 // we don't have any args to put into the variable map
448 return pUserFunction->pRuntimeNode;
450 else {
451 return NULL;
454 return m_pFirstChild;
457 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
459 frame.PushArg(pPreviousValue);
461 if (frame.boolVal) {
462 // we just executed the function, return baby!!!
463 f->PopVariableScope();
464 return NULL;
467 if (pPreviousExecuteNode->GetNextSibling() != NULL) {
468 return pPreviousExecuteNode->GetNextSibling();
471 const UserFunctionDescriptor* pUserFunction = f->GetUserFunction(GetTokenIdAtom());
473 if (pUserFunction) {
474 f->PushVariableScope();
476 const List** args = frame.ArgArray();
477 size_t argCount = frame.ArgCount();
479 // we can have less specified args than actual args being passed in
480 if (pUserFunction->m_argIds.size() < argCount) {
481 argCount = pUserFunction->m_argIds.size();
484 // and set the variables to the function arg ids
485 for (size_t i = 0; i < argCount; i++) {
486 f->SetVariableValue(pUserFunction->m_argIds[i], args[i]);
489 // store the number of args in the variable $ArgCount
490 f->SetVariableValue(m_argCountIdAtom, m_pArgCountList);
492 VariableScope& scope = f->GetCurrentScope();
493 scope.inputArgs.reserve(argCount);
494 scope.inputArgs.insert(scope.inputArgs.begin(), args, args + argCount);
496 // clear off our args, they are now stored in the varaible scope
497 frame.ClearArgs();
499 frame.boolVal = true; // signal that we are about to execute the function
501 return pUserFunction->pRuntimeNode;
504 else {
505 // no function found. Clear the args and return no node
507 frame.ClearArgs();
509 return NULL;
513 const List* Execute(StackFrame& frame) const
515 ASSERT(frame.ArgCount() <= 1);
517 if (frame.ArgCount() == 0) {
518 // we have no arg to return because the function wasn't found
519 StringBuilder str(ma, 50);
520 str += "No user function \"%";
521 str += GetTokenText();
522 str += "\" found.";
524 return new(ma) List(ma, ErrorElement("UnknownFunction", str));
527 return &frame.LastArg();
531 // Expressions between curly braces:
532 // {x:=1;x + 1}; // result value is 2
533 class NestedExprs : public RuntimeNode
535 public:
536 const List* Execute(StackFrame& frame) const
538 ASSERT(frame.ArgCount() != 0);
540 return &frame.LastArg();
544 // this the "element in list" portion of a forall statement:
545 // forall(x in listx) {...};
546 class ForAllIn : public RuntimeNode
548 public:
550 size_t increment;
552 NodeType GetNodeType() const
554 return NodeType_ForAllInNode;
557 virtual void CompilerValidateArgsAndInit()
559 ASSERT(m_numChildren == 1 || m_numChildren == 2);
561 if (m_numChildren == 2) {
562 // the by-increment clause is specified, gets it value
564 const RuntimeNode* pArg = m_pFirstChild->GetNextSibling();
565 int inc = (int)pArg->GetTokenText().ToNumber();
566 if (inc <= 0) {
567 // zero/negative is not allowed! (maybe negative could have special meaning someday?)
568 throw Formula::SyntaxException("The \"by\" clause must be a positive integer.");
570 else {
571 increment = (size_t)inc;
574 else {
575 increment = 1;
579 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
581 return m_pFirstChild;
584 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
586 frame.PushArg(pPreviousValue);
588 return NULL;
591 const List* Execute(StackFrame& frame) const
593 ASSERT(frame.ArgCount() == 1);
594 return &frame.LastArg();
598 class ForAll : public RuntimeNode
600 public:
601 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
603 size_t numberOfForAllInNodes = m_numChildren - 1;
605 frame.PushArg(pPreviousValue);
607 if (frame.ArgCount() < numberOfForAllInNodes) {
608 // We still have at least one more forallIn node to execute
609 // before we get to the body loop.;
610 return pPreviousExecuteNode->GetNextSibling();
612 else {
613 if (frame.ArgCount() == numberOfForAllInNodes) {
614 // we just executed the very last forallin node
615 // now initialize for the loop body
617 // for each subsequent time through, this will be true:
618 // frame.ArgCount() + 1 == numberOfForAllInNodes
620 size_t maxSize = 0;
621 size_t maxIterations = 0;
623 const ForAllIn* pForAllInNode = (const ForAllIn*)m_pFirstChild;
624 for (size_t i = 0; i < frame.ArgCount(); i++) {
625 const List& arg = frame.GetArg(i);
627 size_t increment = pForAllInNode->increment;
628 size_t iterations = arg.size()/increment;
630 if(iterations*increment != arg.size()) {
631 // iterations was trucated down because the division
632 // has a remainder, so add one.
633 iterations++;
636 maxSize = std::max(arg.size(), maxSize);
637 maxIterations = std::max(iterations, maxIterations);
639 pForAllInNode = (const ForAllIn*)pForAllInNode->GetNextSibling();
642 frame.forAllLoopData.currentIteration = 0;
643 frame.forAllLoopData.totalIterations = maxIterations;
644 frame.forAllLoopData.pReturnList = new(ma) List(ma);
645 frame.forAllLoopData.pReturnList->Reserve(maxSize);
647 else {
648 frame.forAllLoopData.pReturnList->Append(*pPreviousValue);
649 frame.forAllLoopData.currentIteration++;
650 frame.PopArg(); // don't leave the previousvalue on the stack
652 if (frame.forAllLoopData.currentIteration == frame.forAllLoopData.totalIterations) {
653 // we are done!
654 // clear off the stack
655 // and return
656 frame.ClearArgs();
657 frame.PushArg(frame.forAllLoopData.pReturnList);
658 return NULL;
661 // now populate the loop variables
663 ASSERT(frame.ArgCount() == numberOfForAllInNodes);
665 const ForAllIn* pForAllInNode = (const ForAllIn*)m_pFirstChild;
666 size_t iteration = frame.forAllLoopData.currentIteration;
668 for (size_t i = 0; i < numberOfForAllInNodes; i++) {
669 size_t increment = pForAllInNode->increment;
670 size_t offset = iteration*increment;
671 const List& list = frame.GetArg(i);
673 List* pNewSubvalue = new(ma) List(ma);
674 pNewSubvalue->Reserve(increment);
676 for (size_t j = 0; j < increment; j++) {
677 if (list.size() > offset + j) {
678 pNewSubvalue->Add(list[offset + j]);
682 // now set the loop variable with the new value
683 f->SetVariableValue(pForAllInNode->GetTokenIdAtom(), pNewSubvalue);
685 pForAllInNode = (const ForAllIn*)pForAllInNode->GetNextSibling();
688 if (pPreviousExecuteNode->GetNextSibling() == NULL) {
689 return pPreviousExecuteNode;
691 else {
692 return pPreviousExecuteNode->GetNextSibling();
697 const List* Execute(StackFrame& frame) const
699 return &frame.LastArg();
703 class VariableReference : public RuntimeNode
705 public:
707 virtual NodeType GetNodeType() const
709 return NodeType_VariableReferenceNode;
712 const List* Execute(StackFrame& frame) const
714 return f->GetValue(GetTokenText(), GetTokenIdAtom());
719 class OuterFormula : public RuntimeNode
721 const List* Execute(StackFrame& frame) const
723 // get our return value, if set
724 const List* pReturn = f->GetCurrentScope().pReturnList;
726 if (pReturn == NULL) {
727 // the return value wasn't explicitly set
728 if (frame.ArgCount() != 0) {
729 // return the last arg
730 pReturn = &frame.LastArg();
733 return pReturn;
737 class KeywordLiteral : public RuntimeNode
738 { const List* pKeyword;
739 public:
740 void CompilerValidateArgsAndInit()
742 ASSERT(m_numChildren == 0);
744 // convert our text to a KeywordElement and put that element into a Value.
745 // That is the value that will be returned when Execute is called.
747 KeywordElement keyword(f->GetIdAtom(GetTokenText()), GetTokenText().ToNullTermStr(ma));
749 pKeyword = new(&f->indefMa) List(&f->indefMa,keyword);
753 const List* Execute(StackFrame& frame) const
755 return pKeyword;
759 class Fun_assert : public RuntimeNode
761 public:
762 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
764 if (f->GetFailedAssertHandler()) {
765 return m_pFirstChild;
767 else {
768 return NULL;
772 const List* Execute(StackFrame& frame) const
775 if (frame.ArgCount() > 0) {
776 FailedAssertHandler* pHandler = f->GetFailedAssertHandler();
777 // We can't have args unless we also have a FailedAssertHandler
778 // the code in FirstNodeToExecute ensures that
779 ASSERT(pHandler);
781 for (size_t i = 0; i < frame.ArgCount(); i++) {
782 const List* pList = &frame.GetArg(i);
784 if (!pList->ToBool()) {
785 pHandler->HandleFailedAssert();
790 return f->TrueList();
795 class Fun_assertfalse : public RuntimeNode
797 public:
798 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
800 if (f->GetFailedAssertHandler()) {
801 return m_pFirstChild;
803 else {
804 return NULL;
808 const List* Execute(StackFrame& frame) const
811 if (frame.ArgCount() > 0) {
812 FailedAssertHandler* pHandler = f->GetFailedAssertHandler();
813 // We can't have args unless we also have a FailedAssertHandler
814 // the code in FirstNodeToExecute ensures that
815 ASSERT(pHandler);
817 for (size_t i = 0; i < frame.ArgCount(); i++) {
818 const List* pList = &frame.GetArg(i);
820 if (pList->ToBool()) {
821 pHandler->HandleFailedAssert();
826 return f->TrueList();
831 class TrueLiteral : public RuntimeNode
833 public:
834 const List* Execute(StackFrame& frame) const
836 return f->TrueList();
840 class FalseLiteral : public RuntimeNode
842 public:
843 const List* Execute(StackFrame& frame) const
845 return f->FalseList();
850 class NilLiteral : public RuntimeNode
852 public:
853 const List* Execute(StackFrame& frame) const
855 return f->NilList();