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
25 IdentifierExpectedException()
26 : Formula::SyntaxException("Variable identifier expected.")
32 class If
: public RuntimeNode
36 const RuntimeNode
* FirstNodeToExecute(StackFrame
& frame
) const
38 frame
.boolVal
= false;
43 const RuntimeNode
* NextNodeToExecute(StackFrame
& frame
, const RuntimeNode
* pPreviousExecuteNode
, const List
* pPreviousValue
) const
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
51 if (pPreviousExecuteNode
->GetNextSibling() == NULL
) {
52 // this means we are an else clause
53 frame
.PushArg(pPreviousValue
);
55 } else if (pPreviousValue
->ToBool()) {
56 // We hit a true conditional.
57 // Signal we hit a true conditional for the next time through
60 // execute the body of the clause
61 return pPreviousExecuteNode
->GetNextSibling();
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
78 return &frame
.LastArg();
83 // Early return: Return(Foo)
84 class Fun_return
: public RuntimeNode
88 const List
* Execute(StackFrame
& frame
) const
90 f
->SetEarlyReturnList(&frame
.LastArg());
91 return &frame
.LastArg();
97 class VariableAssignment
: public RuntimeNode
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) {
129 f
->SetSelected(true);
130 return f
->TrueList();
133 const List
& list
= frame
.LastArg();
136 f
->SetSelected(true);
139 f
->SetSelected(false);
140 f
->SetEarlyReturnList(&list
); // causes abortion of execution
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
169 if (frame
.ArgCount() == 1) {
171 pList
= &frame
.LastArg();
176 pList
= f
->GetVariableValue( m_pFirstChild
->GetTokenIdAtom());
178 pList
= f
->GetDocument().GetValue(ma
, m_pFirstChild
->GetTokenText());
181 pList
= f
->NilList();
184 f
->AppendColumnList(pList
);
189 // FIELD var := value;
190 class FieldAssignment
: public RuntimeNode
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
;
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();
233 pErrorList
= new(&f
->indefMa
) List(&f
->indefMa
, ErrorElement("UnknownFunction", str
));
235 const List
* Execute(StackFrame
& frame
) const
243 class StringLiteral
: public RuntimeNode
245 const List
* pLiteral
;
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\")
281 pLiteral
= new(&f
->indefMa
) List(&f
->indefMa
, TextElement(newString
, out
- newString
));
284 const List
* Execute(StackFrame
& frame
) const
290 class DateTimeLiteral
: public RuntimeNode
295 const List
* Execute(StackFrame
& frame
) const
297 return f
->FalseList();
301 class NumberLiteral
: public RuntimeNode
303 const List
* pLiteral
;
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
317 //function Foo(arg) {
320 class UserFunction
: public RuntimeNode
322 UserFunctionDescriptor
* m_pFunctionDescriptor
;
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.
352 const List
* Execute(StackFrame
& frame
) const
354 f
->SetUserFunction(GetTokenIdAtom(), m_pFunctionDescriptor
);
360 // %UserFunction(args);
361 class UserFunctionCall
: public RuntimeNode
363 IdAtom m_argCountIdAtom
;
364 const List
* m_pArgCountList
;
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());
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
;
407 return m_pFirstChild
;
410 const RuntimeNode
* NextNodeToExecute(StackFrame
& frame
, const RuntimeNode
* pPreviousExecuteNode
, const List
* pPreviousValue
) const
412 frame
.PushArg(pPreviousValue
);
415 // we just executed the function, return baby!!!
416 f
->PopVariableScope();
420 if (pPreviousExecuteNode
->GetNextSibling() != NULL
) {
421 return pPreviousExecuteNode
->GetNextSibling();
424 const UserFunctionDescriptor
* pUserFunction
= f
->GetUserFunction(GetTokenIdAtom());
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
452 frame
.boolVal
= true; // signal that we are about to execute the function
454 return pUserFunction
->pRuntimeNode
;
458 // no function found. Clear the args and return no node
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();
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
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
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();
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.");
524 increment
= (size_t)inc
;
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
);
544 const List
* Execute(StackFrame
& frame
) const
546 ASSERT(frame
.ArgCount() == 1);
547 return &frame
.LastArg();
551 class ForAll
: public RuntimeNode
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();
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
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.
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
);
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
) {
607 // clear off the stack
610 frame
.PushArg(frame
.forAllLoopData
.pReturnList
);
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
;
645 return pPreviousExecuteNode
->GetNextSibling();
650 const List
* Execute(StackFrame
& frame
) const
652 return &frame
.LastArg();
656 class VariableReference
: public RuntimeNode
660 virtual NodeType
GetNodeType() const
662 return NodeType_VariableReferenceNode
;
665 const List
* Execute(StackFrame
& frame
) const
667 const List
* pList
= f
->GetVariableValue(GetTokenIdAtom());
669 pList
= f
->GetDocument().GetValue(ma
, GetTokenText());
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();
694 class KeywordLiteral
: public RuntimeNode
695 { const List
* pKeyword
;
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
716 class Fun_assert
: public RuntimeNode
719 const RuntimeNode
* FirstNodeToExecute(StackFrame
& frame
) const
721 if (f
->GetFailedAssertHandler()) {
722 return m_pFirstChild
;
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
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
755 const RuntimeNode
* FirstNodeToExecute(StackFrame
& frame
) const
757 if (f
->GetFailedAssertHandler()) {
758 return m_pFirstChild
;
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
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
791 const List
* Execute(StackFrame
& frame
) const
793 return f
->TrueList();
797 class FalseLiteral
: public RuntimeNode
800 const List
* Execute(StackFrame
& frame
) const
802 return f
->FalseList();
807 class NilLiteral
: public RuntimeNode
810 const List
* Execute(StackFrame
& frame
) const