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.
23 class If
: public RuntimeNode
27 const RuntimeNode
* FirstNodeToExecute(StackFrame
& frame
) const
29 frame
.boolVal
= false;
34 const RuntimeNode
* NextNodeToExecute(StackFrame
& frame
, const RuntimeNode
* pPreviousExecuteNode
, const List
* pPreviousValue
) const
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
42 if (pPreviousExecuteNode
->GetNextSibling() == NULL
) {
43 // this means we are an else clause
44 frame
.PushArg(pPreviousValue
);
46 } else if (pPreviousValue
->ToBool()) {
47 // We hit a true conditional.
48 // Signal we hit a true conditional for the next time through
51 // execute the body of the clause
52 return pPreviousExecuteNode
->GetNextSibling();
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
69 return &frame
.LastArg();
74 // Early return: Return(Foo)
75 class Fun_return
: public RuntimeNode
79 const List
* Execute(StackFrame
& frame
) const
81 f
->SetEarlyReturnList(&frame
.LastArg());
82 return &frame
.LastArg();
88 class VariableAssignment
: public RuntimeNode
92 const List
* Execute(StackFrame
& frame
) const
94 const List
* pRetList
= &frame
.LastArg();
95 f
->SetVariableValue(GetTokenIdAtom(), pRetList
);
101 class VariableInit
: public RuntimeNode
104 const RuntimeNode
* FirstNodeToExecute(StackFrame
& frame
) const
106 const List
* pExistingValue
= f
->GetValue(GetTokenText(), GetTokenIdAtom());
107 if (pExistingValue
) {
108 frame
.pReturnList
= pExistingValue
;
112 frame
.pReturnList
= NULL
;
113 return m_pFirstChild
;
117 const List
* Execute(StackFrame
& frame
) const
119 if (frame
.pReturnList
) {
120 return frame
.pReturnList
;
123 const List
* pRetList
= &frame
.LastArg();
124 f
->SetVariableValue(GetTokenIdAtom(), pRetList
);
130 class SelectStatement
: public RuntimeNode
132 const List
* Execute(StackFrame
& frame
) const
134 if (frame
.ArgCount() == 0) {
136 f
->SetSelected(true);
137 return f
->TrueList();
140 const List
& list
= frame
.LastArg();
143 f
->SetSelected(true);
146 f
->SetSelected(false);
147 f
->SetEarlyReturnList(&list
); // causes abortion of execution
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
);
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
);
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
;
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
;
213 const List
* pRetList
= &frame
.LastArg();
214 f
->AppendColumnList(pRetList
);
220 // FIELD var := value;
221 class FieldAssignment
: public RuntimeNode
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
);
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
;
245 frame
.pReturnList
= NULL
;
246 return m_pFirstChild
;
250 const List
* Execute(StackFrame
& frame
) const
252 if (frame
.pReturnList
) {
253 return frame
.pReturnList
;
256 f
->SetVariableValue(GetTokenIdAtom(), NULL
); // clear out the local var
257 const List
* pRetList
= &frame
.LastArg();
258 f
->GetDocument().SetValue(GetTokenText(), pRetList
);
264 class UnknownFunction
: public RuntimeNode
266 const List
* pErrorList
;
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();
280 pErrorList
= new(&f
->indefMa
) List(&f
->indefMa
, ErrorElement("UnknownFunction", str
));
282 const List
* Execute(StackFrame
& frame
) const
290 class StringLiteral
: public RuntimeNode
292 const List
* pLiteral
;
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\")
328 pLiteral
= new(&f
->indefMa
) List(&f
->indefMa
, TextElement(newString
, out
- newString
));
331 const List
* Execute(StackFrame
& frame
) const
337 class DateTimeLiteral
: public RuntimeNode
342 const List
* Execute(StackFrame
& frame
) const
344 return f
->FalseList();
348 class NumberLiteral
: public RuntimeNode
350 const List
* pLiteral
;
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
364 //function Foo(arg) {
367 class UserFunction
: public RuntimeNode
369 UserFunctionDescriptor
* m_pFunctionDescriptor
;
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.
399 const List
* Execute(StackFrame
& frame
) const
401 f
->SetUserFunction(GetTokenIdAtom(), m_pFunctionDescriptor
);
407 // %UserFunction(args);
408 class UserFunctionCall
: public RuntimeNode
410 IdAtom m_argCountIdAtom
;
411 const List
* m_pArgCountList
;
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());
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
;
454 return m_pFirstChild
;
457 const RuntimeNode
* NextNodeToExecute(StackFrame
& frame
, const RuntimeNode
* pPreviousExecuteNode
, const List
* pPreviousValue
) const
459 frame
.PushArg(pPreviousValue
);
462 // we just executed the function, return baby!!!
463 f
->PopVariableScope();
467 if (pPreviousExecuteNode
->GetNextSibling() != NULL
) {
468 return pPreviousExecuteNode
->GetNextSibling();
471 const UserFunctionDescriptor
* pUserFunction
= f
->GetUserFunction(GetTokenIdAtom());
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
499 frame
.boolVal
= true; // signal that we are about to execute the function
501 return pUserFunction
->pRuntimeNode
;
505 // no function found. Clear the args and return no node
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();
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
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
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();
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.");
571 increment
= (size_t)inc
;
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
);
591 const List
* Execute(StackFrame
& frame
) const
593 ASSERT(frame
.ArgCount() == 1);
594 return &frame
.LastArg();
598 class ForAll
: public RuntimeNode
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();
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
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.
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
);
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
) {
654 // clear off the stack
657 frame
.PushArg(frame
.forAllLoopData
.pReturnList
);
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
;
692 return pPreviousExecuteNode
->GetNextSibling();
697 const List
* Execute(StackFrame
& frame
) const
699 return &frame
.LastArg();
703 class VariableReference
: public RuntimeNode
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();
737 class KeywordLiteral
: public RuntimeNode
738 { const List
* pKeyword
;
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
759 class Fun_assert
: public RuntimeNode
762 const RuntimeNode
* FirstNodeToExecute(StackFrame
& frame
) const
764 if (f
->GetFailedAssertHandler()) {
765 return m_pFirstChild
;
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
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
798 const RuntimeNode
* FirstNodeToExecute(StackFrame
& frame
) const
800 if (f
->GetFailedAssertHandler()) {
801 return m_pFirstChild
;
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
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
834 const List
* Execute(StackFrame
& frame
) const
836 return f
->TrueList();
840 class FalseLiteral
: public RuntimeNode
843 const List
* Execute(StackFrame
& frame
) const
845 return f
->FalseList();
850 class NilLiteral
: public RuntimeNode
853 const List
* Execute(StackFrame
& frame
) const