set a bunch of svn:executable properties
[couchdbimport.git] / CouchProjects / Fabric / SpecialNodes.h
blobb2e9fa92ae5e549f929d3938dac90c1f318df2ce
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 class IdentifierExpectedException : public Formula::SyntaxException
24 public:
25 IdentifierExpectedException()
26 : Formula::SyntaxException("Variable identifier expected.")
31 // Branching node
32 class If : public RuntimeNode
34 public:
36 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
38 frame.boolVal = false;
40 return m_pFirstChild;
43 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
45 if (frame.boolVal) {
46 // This means the node just executed must be the desired return result.
47 frame.PushArg(pPreviousValue);
48 return NULL; // no more nodes to execute
50 else {
51 if (pPreviousExecuteNode->GetNextSibling() == NULL) {
52 // this means we are an else clause
53 frame.PushArg(pPreviousValue);
54 return NULL;
55 } else if (pPreviousValue->ToBool()) {
56 // We hit a true conditional.
57 // Signal we hit a true conditional for the next time through
58 frame.boolVal = true;
60 // execute the body of the clause
61 return pPreviousExecuteNode->GetNextSibling();
63 else {
64 // conditional wasn't true, skip over the body onto the next
65 // conditional (which will be null if there is no else clause)
67 return pPreviousExecuteNode->GetNextSibling()->GetNextSibling();
72 const List* Execute(StackFrame& frame) const
74 if (frame.ArgCount() == 0) {
75 // this happens when there is no true "if" or "else if" cases and no "else" found
76 return f->NilList();
78 return &frame.LastArg();
83 // Early return: Return(Foo)
84 class Fun_return : public RuntimeNode
86 public:
88 const List* Execute(StackFrame& frame) const
90 f->SetEarlyReturnList(&frame.LastArg());
91 return &frame.LastArg();
96 // var := value;
97 class VariableAssignment : public RuntimeNode
99 public:
101 void CompilerValidateArgsAndInit()
103 ASSERT(m_numChildren == 2); // should have been validated by the compiler
104 if (m_pFirstChild->GetNodeType() != NodeType_VariableReferenceNode) {
105 throw IdentifierExpectedException();
109 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
111 ASSERT(m_pFirstChild->GetNextSibling());
113 return m_pFirstChild->GetNextSibling();
116 const List* Execute(StackFrame& frame) const
118 f->SetVariableValue( m_pFirstChild->GetTokenIdAtom(), &frame.LastArg());
119 return &frame.LastArg();
123 class SelectStatement : public RuntimeNode
125 const List* Execute(StackFrame& frame) const
127 if (frame.ArgCount() == 0) {
128 // "SELECT *" case
129 f->SetSelected(true);
130 return f->TrueList();
133 const List& list = frame.LastArg();
135 if (list.ToBool()) {
136 f->SetSelected(true);
138 else {
139 f->SetSelected(false);
140 f->SetEarlyReturnList(&list); // causes abortion of execution
142 return &list;
146 class ColumnAssignment : public RuntimeNode
148 NodeType GetNodeType() const
150 return NodeType_ColumnAssignment;
153 void CompilerValidateArgsAndInit()
155 if (m_pFirstChild->GetNodeType() != NodeType_VariableReferenceNode) {
156 throw Formula::SyntaxException("Column identifier expected");
160 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
162 // first arg is var reference, skip
163 return m_pFirstChild->GetNextSibling(); // may return null
166 const List* Execute(StackFrame& frame) const
168 const List* pList;
169 if (frame.ArgCount() == 1) {
170 // COLUMN X := Expr;
171 pList = &frame.LastArg();
173 else {
174 // COLUMN X;
176 pList = f->GetVariableValue( m_pFirstChild->GetTokenIdAtom());
177 if (pList == NULL) {
178 pList = f->GetDocument().GetValue(ma, m_pFirstChild->GetTokenText());
180 if (pList == NULL) {
181 pList = f->NilList();
184 f->AppendColumnList(pList);
185 return pList;
189 // FIELD var := value;
190 class FieldAssignment : public RuntimeNode
192 public:
194 void CompilerValidateArgsAndInit()
196 ASSERT(m_numChildren == 2); // should have been validated by the compiler
197 if (m_pFirstChild->GetNodeType() != NodeType_VariableReferenceNode) {
198 throw Formula::SyntaxException("Field identifier expected");
202 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
204 ASSERT(m_pFirstChild->GetNextSibling());
206 return m_pFirstChild->GetNextSibling();
209 const List* Execute(StackFrame& frame) const
211 f->SetVariableValue( m_pFirstChild->GetTokenIdAtom(), NULL); // clear out the local var
212 f->GetDocument().SetValue(m_pFirstChild->GetTokenText(), &frame.LastArg());
213 return &frame.LastArg();
217 class UnknownFunction : public RuntimeNode
219 const List* pErrorList;
220 public:
221 void CompilerValidateArgsAndInit()
223 // we make this a runtime error instead of compile time
224 // so a future script written for a future Fabric engine
225 // can still run if properly written and degrade gracefully
226 // if language features aren't available
228 StringBuilder str(ma, 50);
229 str += "No built-in function \"";
230 str += GetTokenText();
231 str += "\" found.";
233 pErrorList = new(&f->indefMa) List(&f->indefMa, ErrorElement("UnknownFunction", str));
235 const List* Execute(StackFrame& frame) const
238 return pErrorList;
243 class StringLiteral : public RuntimeNode
245 const List* pLiteral;
246 public:
247 void CompilerValidateArgsAndInit()
249 ASSERT(m_numChildren == 0);
250 const TextElement& token = GetTokenText();
251 char* newString = new(&f->indefMa) char[token.Length()];
252 char* out = newString;
253 const char* in = token.Ptr();
254 const char* inEnd = in + token.Length();
256 // NOTE, we need not do error checking on the input characters, they have
257 // already been validated for correctness.
258 // (impossible input example: "string with single trailing slash\")
261 while (in < inEnd) {
262 if (*in == '\\') {
263 in++;
264 switch (*in) {
265 case 'n':
266 *out = '\n';
267 break;
268 case 't':
269 *out = '\t';
270 break;
271 default:
272 *out = *in;
275 else {
276 *out = *in;
278 out++;
279 in++;
281 pLiteral = new(&f->indefMa) List(&f->indefMa, TextElement(newString, out - newString));
284 const List* Execute(StackFrame& frame) const
286 return pLiteral;
290 class DateTimeLiteral : public RuntimeNode
293 public:
295 const List* Execute(StackFrame& frame) const
297 return f->FalseList();
301 class NumberLiteral : public RuntimeNode
303 const List* pLiteral;
304 public:
305 void CompilerValidateArgsAndInit()
307 ASSERT(m_numChildren == 0);
308 pLiteral = new(&f->indefMa) List(&f->indefMa, GetTokenText().ToNumber());
311 const List* Execute(StackFrame& frame) const
313 return pLiteral;
317 //function Foo(arg) {
318 // expr;
319 //};
320 class UserFunction : public RuntimeNode
322 UserFunctionDescriptor* m_pFunctionDescriptor;
323 public:
324 void CompilerValidateArgsAndInit()
326 ASSERT(m_numChildren >= 1);
328 m_pFunctionDescriptor = new(&f->indefMa) UserFunctionDescriptor(&f->indefMa);
330 m_pFunctionDescriptor->m_argIds.reserve(m_numChildren - 1);
332 const RuntimeNode* pChildNode = m_pFirstChild;
334 // if pChildNode->GetNextSibling() is null, then it means its the last
335 // child node and its not an arg id
336 while (pChildNode->GetNextSibling()) {
337 m_pFunctionDescriptor->m_argIds.push_back(pChildNode->GetTokenIdAtom());
338 pChildNode = pChildNode->GetNextSibling();
341 // pChildNode now points to the last arg, the actual function expression
342 // so store if of in the function descriptor (its the actual function really)
343 m_pFunctionDescriptor->pRuntimeNode = pChildNode;
346 virtual const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
348 // we never execute our args, we wait until called.
349 return NULL;
352 const List* Execute(StackFrame& frame) const
354 f->SetUserFunction(GetTokenIdAtom(), m_pFunctionDescriptor);
356 return NULL;
360 // %UserFunction(args);
361 class UserFunctionCall : public RuntimeNode
363 IdAtom m_argCountIdAtom;
364 const List* m_pArgCountList;
365 public:
367 NodeType GetNodeType() const
369 return NodeType_UserFunctionCall;
372 void CompilerValidateArgsAndInit()
375 ASSERT(m_tokenText.Ptr()[0] == '%');
377 // strip off the leading % sign.
378 m_tokenText = TextElement(m_tokenText.Ptr() + 1, m_tokenText.Length() - 1);
380 m_argCountIdAtom = f->GetIdAtom(TEXT_ELEMENT("$argcount"));
382 m_pArgCountList = new(&f->indefMa) List(&f->indefMa, NumberElement(m_numChildren));
386 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
388 // init our frame vars
389 frame.boolVal = false;
391 if (m_pFirstChild == NULL) {
392 // no args from the caller
393 const UserFunctionDescriptor* pUserFunction = f->GetUserFunction(GetTokenIdAtom());
394 if (pUserFunction) {
395 // we have a function, create a variable map for it and save off the old one
396 f->PushVariableScope();
398 f->SetVariableValue(m_argCountIdAtom, m_pArgCountList);
400 // we don't have any args to put into the variable map
401 return pUserFunction->pRuntimeNode;
403 else {
404 return NULL;
407 return m_pFirstChild;
410 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
412 frame.PushArg(pPreviousValue);
414 if (frame.boolVal) {
415 // we just executed the function, return baby!!!
416 f->PopVariableScope();
417 return NULL;
420 if (pPreviousExecuteNode->GetNextSibling() != NULL) {
421 return pPreviousExecuteNode->GetNextSibling();
424 const UserFunctionDescriptor* pUserFunction = f->GetUserFunction(GetTokenIdAtom());
426 if (pUserFunction) {
427 f->PushVariableScope();
429 const List** args = frame.ArgArray();
430 size_t argCount = frame.ArgCount();
432 // we can have less specified args than actual args being passed in
433 if (pUserFunction->m_argIds.size() < argCount) {
434 argCount = pUserFunction->m_argIds.size();
437 // and set the variables to the function arg ids
438 for (size_t i = 0; i < argCount; i++) {
439 f->SetVariableValue(pUserFunction->m_argIds[i], args[i]);
442 // store the number of args in the variable $ArgCount
443 f->SetVariableValue(m_argCountIdAtom, m_pArgCountList);
445 VariableScope& scope = f->GetCurrentScope();
446 scope.inputArgs.reserve(argCount);
447 scope.inputArgs.insert(scope.inputArgs.begin(), args, args + argCount);
449 // clear off our args, they are now stored in the varaible scope
450 frame.ClearArgs();
452 frame.boolVal = true; // signal that we are about to execute the function
454 return pUserFunction->pRuntimeNode;
457 else {
458 // no function found. Clear the args and return no node
460 frame.ClearArgs();
462 return NULL;
466 const List* Execute(StackFrame& frame) const
468 ASSERT(frame.ArgCount() <= 1);
470 if (frame.ArgCount() == 0) {
471 // we have no arg to return because the function wasn't found
472 StringBuilder str(ma, 50);
473 str += "No user function \"%";
474 str += GetTokenText();
475 str += "\" found.";
477 return new(ma) List(ma, ErrorElement("UnknownFunction", str));
480 return &frame.LastArg();
484 // Expressions between curly braces:
485 // {x:=1;x + 1}; // result value is 2
486 class NestedExprs : public RuntimeNode
488 public:
489 const List* Execute(StackFrame& frame) const
491 ASSERT(frame.ArgCount() != 0);
493 return &frame.LastArg();
497 // this the "element in list" portion of a forall statement:
498 // forall(x in listx) {...};
499 class ForAllIn : public RuntimeNode
501 public:
503 size_t increment;
505 NodeType GetNodeType() const
507 return NodeType_ForAllInNode;
510 virtual void CompilerValidateArgsAndInit()
512 ASSERT(m_numChildren == 1 || m_numChildren == 2);
514 if (m_numChildren == 2) {
515 // the by-increment clause is specified, gets it value
517 const RuntimeNode* pArg = m_pFirstChild->GetNextSibling();
518 int inc = (int)pArg->GetTokenText().ToNumber();
519 if (inc <= 0) {
520 // zero/negative is not allowed! (maybe negative could have special meaning someday?)
521 throw Formula::SyntaxException("The \"by\" clause must be a positive integer.");
523 else {
524 increment = (size_t)inc;
527 else {
528 increment = 1;
532 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
534 return m_pFirstChild;
537 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
539 frame.PushArg(pPreviousValue);
541 return NULL;
544 const List* Execute(StackFrame& frame) const
546 ASSERT(frame.ArgCount() == 1);
547 return &frame.LastArg();
551 class ForAll : public RuntimeNode
553 public:
554 const RuntimeNode* NextNodeToExecute(StackFrame& frame, const RuntimeNode* pPreviousExecuteNode, const List* pPreviousValue) const
556 size_t numberOfForAllInNodes = m_numChildren - 1;
558 frame.PushArg(pPreviousValue);
560 if (frame.ArgCount() < numberOfForAllInNodes) {
561 // We still have at least one more forallIn node to execute
562 // before we get to the body loop.;
563 return pPreviousExecuteNode->GetNextSibling();
565 else {
566 if (frame.ArgCount() == numberOfForAllInNodes) {
567 // we just executed the very last forallin node
568 // now initialize for the loop body
570 // for each subsequent time through, this will be true:
571 // frame.ArgCount() + 1 == numberOfForAllInNodes
573 size_t maxSize = 0;
574 size_t maxIterations = 0;
576 const ForAllIn* pForAllInNode = (const ForAllIn*)m_pFirstChild;
577 for (size_t i = 0; i < frame.ArgCount(); i++) {
578 const List& arg = frame.GetArg(i);
580 size_t increment = pForAllInNode->increment;
581 size_t iterations = arg.size()/increment;
583 if(iterations*increment != arg.size()) {
584 // iterations was trucated down because the division
585 // has a remainder, so add one.
586 iterations++;
589 maxSize = std::max(arg.size(), maxSize);
590 maxIterations = std::max(iterations, maxIterations);
592 pForAllInNode = (const ForAllIn*)pForAllInNode->GetNextSibling();
595 frame.forAllLoopData.currentIteration = 0;
596 frame.forAllLoopData.totalIterations = maxIterations;
597 frame.forAllLoopData.pReturnList = new(ma) List(ma);
598 frame.forAllLoopData.pReturnList->Reserve(maxSize);
600 else {
601 frame.forAllLoopData.pReturnList->Append(*pPreviousValue);
602 frame.forAllLoopData.currentIteration++;
603 frame.PopArg(); // don't leave the previousvalue on the stack
605 if (frame.forAllLoopData.currentIteration == frame.forAllLoopData.totalIterations) {
606 // we are done!
607 // clear off the stack
608 // and return
609 frame.ClearArgs();
610 frame.PushArg(frame.forAllLoopData.pReturnList);
611 return NULL;
614 // now populate the loop variables
616 ASSERT(frame.ArgCount() == numberOfForAllInNodes);
618 const ForAllIn* pForAllInNode = (const ForAllIn*)m_pFirstChild;
619 size_t iteration = frame.forAllLoopData.currentIteration;
621 for (size_t i = 0; i < numberOfForAllInNodes; i++) {
622 size_t increment = pForAllInNode->increment;
623 size_t offset = iteration*increment;
624 const List& list = frame.GetArg(i);
626 List* pNewSubvalue = new(ma) List(ma);
627 pNewSubvalue->Reserve(increment);
629 for (size_t j = 0; j < increment; j++) {
630 if (list.size() > offset + j) {
631 pNewSubvalue->Add(list[offset + j]);
635 // now set the loop variable with the new value
636 f->SetVariableValue(pForAllInNode->GetTokenIdAtom(), pNewSubvalue);
638 pForAllInNode = (const ForAllIn*)pForAllInNode->GetNextSibling();
641 if (pPreviousExecuteNode->GetNextSibling() == NULL) {
642 return pPreviousExecuteNode;
644 else {
645 return pPreviousExecuteNode->GetNextSibling();
650 const List* Execute(StackFrame& frame) const
652 return &frame.LastArg();
656 class VariableReference : public RuntimeNode
658 public:
660 virtual NodeType GetNodeType() const
662 return NodeType_VariableReferenceNode;
665 const List* Execute(StackFrame& frame) const
667 const List* pList = f->GetVariableValue(GetTokenIdAtom());
668 if (pList == NULL) {
669 pList = f->GetDocument().GetValue(ma, GetTokenText());
671 return pList;
676 class OuterFormula : public RuntimeNode
678 const List* Execute(StackFrame& frame) const
680 // get our return value, if set
681 const List* pReturn = f->GetCurrentScope().pReturnList;
683 if (pReturn == NULL) {
684 // the return value wasn't explicitly set
685 if (frame.ArgCount() != 0) {
686 // return the last arg
687 pReturn = &frame.LastArg();
690 return pReturn;
694 class KeywordLiteral : public RuntimeNode
695 { const List* pKeyword;
696 public:
697 void CompilerValidateArgsAndInit()
699 ASSERT(m_numChildren == 0);
701 // convert our text to a KeywordElement and put that element into a Value.
702 // That is the value that will be returned when Execute is called.
704 KeywordElement keyword(f->GetIdAtom(GetTokenText()), GetTokenText().ToNullTermStr(ma));
706 pKeyword = new(&f->indefMa) List(&f->indefMa,keyword);
710 const List* Execute(StackFrame& frame) const
712 return pKeyword;
716 class Fun_assert : public RuntimeNode
718 public:
719 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
721 if (f->GetFailedAssertHandler()) {
722 return m_pFirstChild;
724 else {
725 return NULL;
729 const List* Execute(StackFrame& frame) const
732 if (frame.ArgCount() > 0) {
733 FailedAssertHandler* pHandler = f->GetFailedAssertHandler();
734 // We can't have args unless we also have a FailedAssertHandler
735 // the code in FirstNodeToExecute ensures that
736 ASSERT(pHandler);
738 for (size_t i = 0; i < frame.ArgCount(); i++) {
739 const List* pList = &frame.GetArg(i);
741 if (!pList->ToBool()) {
742 pHandler->HandleFailedAssert();
747 return f->TrueList();
752 class Fun_assertfalse : public RuntimeNode
754 public:
755 const RuntimeNode* FirstNodeToExecute(StackFrame& frame) const
757 if (f->GetFailedAssertHandler()) {
758 return m_pFirstChild;
760 else {
761 return NULL;
765 const List* Execute(StackFrame& frame) const
768 if (frame.ArgCount() > 0) {
769 FailedAssertHandler* pHandler = f->GetFailedAssertHandler();
770 // We can't have args unless we also have a FailedAssertHandler
771 // the code in FirstNodeToExecute ensures that
772 ASSERT(pHandler);
774 for (size_t i = 0; i < frame.ArgCount(); i++) {
775 const List* pList = &frame.GetArg(i);
777 if (pList->ToBool()) {
778 pHandler->HandleFailedAssert();
783 return f->TrueList();
788 class TrueLiteral : public RuntimeNode
790 public:
791 const List* Execute(StackFrame& frame) const
793 return f->TrueList();
797 class FalseLiteral : public RuntimeNode
799 public:
800 const List* Execute(StackFrame& frame) const
802 return f->FalseList();
807 class NilLiteral : public RuntimeNode
809 public:
810 const List* Execute(StackFrame& frame) const
812 return f->NilList();