aboutsummaryrefslogtreecommitdiff
path: root/src/runner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/runner.cpp')
-rw-r--r--src/runner.cpp922
1 files changed, 922 insertions, 0 deletions
diff --git a/src/runner.cpp b/src/runner.cpp
new file mode 100644
index 0000000..ace9ce9
--- /dev/null
+++ b/src/runner.cpp
@@ -0,0 +1,922 @@
1#include "runner.h"
2
3#include "ast.h"
4#include "astnode.h"
5#include "astleaf.h"
6#include "astbranch.h"
7#include "context.h"
8#include "functionast.h"
9#include "rule.h"
10#include "variable.h"
11#include "target.h"
12#include "action.h"
13#include "profile.h"
14#include "view.h"
15
16#include "bu/sio.h"
17using Bu::sio;
18
19Runner::Runner( Ast &rAst, Context &rCont ) :
20 rAst( rAst ),
21 rCont( rCont ),
22 pCurTarget( NULL ),
23 pCurRule( NULL )
24{
25}
26
27Runner::~Runner()
28{
29}
30
31void Runner::initialize()
32{
33 for( Ast::NodeList::const_iterator i = rAst.getNodeBegin(); i; i++ )
34 {
35 if( (*i)->getType() == AstNode::typeFunctionDef )
36 {
37 AstBranch *pFnc = dynamic_cast<AstBranch *>(*i);
38 rCont.addFunction( new FunctionAst( pFnc, this ) );
39 }
40 else if( (*i)->getType() == AstNode::typeActionDef )
41 {
42 AstBranch *pAction = dynamic_cast<AstBranch *>(*i);
43 rCont.addAction( new Action( pAction ) );
44 }
45 }
46}
47
48Variable Runner::execFunc( const AstBranch *pFunc, Variable &vIn )
49{
50 Bu::FString sName = dynamic_cast<const AstLeaf *>(
51 (*pFunc->getBranchBegin()).first())->getStrValue();
52
53 VarList lParams;
54 for( AstBranch::BranchList::const_iterator p =
55 pFunc->getBranchBegin()+1; p; p++ )
56 {
57 lParams.append( execExpr( (*p).begin() ) );
58 }
59
60 return rCont.call( sName, vIn, lParams );
61}
62
63Variable Runner::execExpr( AstBranch::NodeList::const_iterator e )
64{
65 Variable vBlank;
66 return execExpr( e, vBlank );
67}
68
69Variable Runner::execExpr( AstBranch::NodeList::const_iterator e,
70 const Variable &vIn )
71{
72// Variable v( vIn );
73 VarList lStack;
74 lStack.push( vIn );
75
76 for(; e; e++ )
77 {
78 if( ((*e)->getType()&AstNode::typeClassMask) == AstNode::typeBranch )
79 {
80 const AstBranch *pBranch = dynamic_cast<const AstBranch *>( *e );
81 switch( pBranch->getType() )
82 {
83 case AstNode::typeFunction:
84 //sio << "FUNC: " << *pBranch << sio.nl << sio.nl;
85 {
86 Variable v = lStack.peekPop();
87 lStack.push( execFunc( pBranch, v ) );
88 }
89 break;
90
91 case AstNode::typeSet:
92 lStack.push( doSet( pBranch ) );
93 break;
94
95 case AstNode::typeList:
96 {
97 Variable vLst( Variable::typeList );
98 for( AstBranch::BranchList::const_iterator i =
99 pBranch->getBranchBegin(); i; i++ )
100 {
101 vLst.append( execExpr( (*i).begin() ) );
102 }
103 lStack.push( vLst );
104 }
105 break;
106
107 case AstNode::typeExpr:
108 {
109 sio << "!!! typeExpr in an expr maybe should be an error..." << sio.nl;
110 for( AstBranch::BranchList::const_iterator i =
111 pBranch->getBranchBegin(); i; i++ )
112 {
113 lStack.push(
114 execExpr( (*i).begin() ) // Are they atomic?
115 );
116 }
117 if( lStack.getSize() != 1 )
118 {
119 throw Bu::ExceptionBase(
120 "Something went wrong, expression processing "
121 "left %d elements on stack, should be 1.",
122 lStack.getSize() );
123 }
124 }
125 break;
126
127 default:
128 sio << "?? branch ???: "
129 << (pBranch)->getType();
130 break;
131 }
132 }
133 else
134 {
135 const AstLeaf *pLeaf = dynamic_cast<const AstLeaf *>( *e );
136 switch( pLeaf->getType() )
137 {
138 case AstNode::typeVariable:
139 try
140 {
141 lStack.push(
142 rCont.getVariable( pLeaf->getStrValue() )
143 );
144 }
145 catch(...)
146 {
147 lStack.push( Variable() );
148 }
149 break;
150
151 case AstNode::typeVariableRef:
152 lStack.push(
153 Variable::mkRef( pLeaf->getStrValue() )
154 );
155 break;
156
157 case AstNode::typeString:
158 lStack.push(
159 rCont.expand( pLeaf->getStrValue() )
160 );
161 break;
162
163 case AstNode::typeInt:
164 lStack.push(
165 pLeaf->getIntValue()
166 );
167 break;
168
169 case AstNode::typeFloat:
170 lStack.push(
171 pLeaf->getFloatValue()
172 );
173 break;
174
175 case AstNode::typeBool:
176 lStack.push(
177 pLeaf->getBoolValue()
178 );
179 break;
180
181 case AstNode::typeVersion:
182 break;
183
184 case AstNode::typeNull:
185 lStack.push(
186 Variable()
187 );
188 break;
189
190 case AstNode::typeCmpEq:
191 {
192 Variable a, b;
193 a = lStack.peekPop();
194 b = lStack.peekPop();
195 lStack.push( Variable( a == b ) );
196 }
197 break;
198
199 case AstNode::typeCmpLt:
200 {
201 Variable a, b;
202 a = lStack.peekPop();
203 b = lStack.peekPop();
204 lStack.push( Variable( b < a ) );
205 }
206 break;
207
208 case AstNode::typeCmpGt:
209 {
210 Variable a, b;
211 a = lStack.peekPop();
212 b = lStack.peekPop();
213 lStack.push( Variable( b > a ) );
214 }
215 break;
216
217 case AstNode::typeCmpNe:
218 {
219 Variable a, b;
220 a = lStack.peekPop();
221 b = lStack.peekPop();
222 lStack.push( Variable( a != b ) );
223 }
224 break;
225
226 case AstNode::typeCmpLtEq:
227 {
228 Variable a, b;
229 a = lStack.peekPop();
230 b = lStack.peekPop();
231 lStack.push( Variable( b <= a ) );
232 }
233 break;
234
235 case AstNode::typeCmpGtEq:
236 {
237 Variable a, b;
238 a = lStack.peekPop();
239 b = lStack.peekPop();
240 lStack.push( Variable( b >= a ) );
241 }
242 break;
243
244 case AstNode::typeOpEq:
245 {
246 Variable ref, val;
247 val = lStack.peekPop();
248 ref = lStack.peekPop();
249 rCont.addVariable( ref.getString(), val );
250 lStack.push( val );
251 }
252 break;
253
254 case AstNode::typeOpPlusEq:
255 {
256 Variable ref, val;
257 val = lStack.peekPop();
258 ref = lStack.peekPop();
259 try
260 {
261 Variable &nVal = rCont.getVariable(
262 ref.getString()
263 );
264 nVal += val;
265 lStack.push( nVal );
266 } catch(...)
267 {
268 rCont.addVariable( ref.getString(), val );
269 lStack.push( val );
270 }
271 }
272 break;
273
274 case AstNode::typeOpPlusEqRaw:
275 {
276 Variable ref, val;
277 val = lStack.peekPop();
278 ref = lStack.peekPop();
279 try
280 {
281 Variable &nVal = rCont.getVariable(
282 ref.getString()
283 );
284 nVal << val;
285 lStack.push( nVal );
286 } catch(...)
287 {
288 rCont.addVariable( ref.getString(), val );
289 lStack.push( val );
290 }
291 }
292 break;
293
294 case AstNode::typeOpPlus:
295 {
296 Variable a, b;
297 a = lStack.peekPop();
298 b = lStack.peekPop();
299 lStack.push( Variable( b + a ) );
300 }
301 break;
302
303 case AstNode::typeOpMinus:
304 {
305 Variable a, b;
306 a = lStack.peekPop();
307 b = lStack.peekPop();
308 lStack.push( Variable( b - a ) );
309 }
310 break;
311
312 case AstNode::typeOpMultiply:
313 {
314 Variable a, b;
315 a = lStack.peekPop();
316 b = lStack.peekPop();
317 lStack.push( Variable( b * a ) );
318 }
319 break;
320
321 case AstNode::typeOpDivide:
322 {
323 Variable a, b;
324 a = lStack.peekPop();
325 b = lStack.peekPop();
326 lStack.push( Variable( b / a ) );
327 }
328 break;
329
330 case AstNode::typeOpNegate:
331 lStack.peek().doNegate();
332 break;
333
334 case AstNode::typeOpNot:
335 lStack.peek().doNot();
336 break;
337
338 default:
339 sio << "?? leaf ???: "
340 << (pLeaf)->getType();
341 break;
342 }
343 }
344 }
345
346 return lStack.peek();
347}
348
349void Runner::run()
350{
351 run( rAst.getNodeBegin() );
352
353 rCont.buildTargetTree( *this );
354
355 rCont.attachDefaults();
356 rCont.genDefaultActions();
357
358// rCont.writeTargetDot();
359}
360
361Variable Runner::run( AstBranch::NodeList::const_iterator n )
362{
363 /* Execute the top level code. */
364
365 Variable vReturn;
366 Bu::List<Ast::NodeList::const_iterator> sI;
367 sI.push( n );
368// for( Ast::NodeList::const_iterator i = rAst.getNodeBegin(); i; i++ )
369 while( !sI.isEmpty() )
370 {
371 while( !sI.isEmpty() && !(sI.peek()) )
372 {
373 sI.pop();
374 }
375 if( sI.isEmpty() )
376 break;
377 Ast::NodeList::const_iterator &i = sI.peek();
378 if( ((*i)->getType()&AstNode::typeClassMask) == AstNode::typeLeaf )
379 {
380 const AstLeaf *pExpr = dynamic_cast<const AstLeaf *>( *i );
381 switch( pExpr->getType() )
382 {
383 case AstNode::typeError:
384 {
385 Bu::FString sMsg = rCont.expand( pExpr->getStrValue() );
386 rCont.getView()->userError( sMsg.getStr() );
387 throw Bu::ExceptionBase( sMsg.getStr() );
388 }
389 break;
390
391 case AstNode::typeWarning:
392 rCont.getView()->userWarning(
393 rCont.expand( pExpr->getStrValue() )
394 );
395 break;
396
397 case AstNode::typeNotice:
398 rCont.getView()->userNotice(
399 rCont.expand( pExpr->getStrValue() )
400 );
401 break;
402
403 case AstNode::typeCondition:
404 break;
405
406 case AstNode::typeDisplay:
407 if( pCurTarget )
408 {
409 pCurTarget->setDisplay(
410 rCont.expand( pExpr->getStrValue() )
411 );
412 }
413 else if( pCurRule )
414 {
415 pCurRule->setDisplay(
416 rCont.expand( pExpr->getStrValue() )
417 );
418 }
419 break;
420/*
421 case AstNode::typeCondition:
422 if( pCurTarget )
423 {
424 if( pExpr->getStrValue() == "filetime" )
425 {
426 pCurTarget->setCondition(
427 new ConditionFileTime()
428 );
429 }
430 }
431 else if( pCurRule )
432 {
433 if( pExpr->getStrValue() == "filetime" )
434 {
435 pCurRule->setCondition(
436 new ConditionFileTime()
437 );
438 }
439 }
440 else
441 {
442 throw Bu::ExceptionBase(
443 "You can only set a condition in a target or rule.");
444 }
445 break;
446*/
447 default:
448 sio << "Leaf? " << (*i)->getType() << sio.nl;
449 break;
450 }
451 }
452 else
453 {
454 const AstBranch *pExpr = dynamic_cast<const AstBranch *>( *i );
455 switch( pExpr->getType() )
456 {
457 case AstNode::typeSet:
458 {
459 // This is effectively legacy, if we add the set
460 // keyword back in I want it to work.
461 doSet( pExpr );
462 }
463 break;
464
465 case AstNode::typeUnset:
466 {
467 AstBranch::NodeList::const_iterator n =
468 (*pExpr->getBranchBegin()).begin();
469 Bu::FString sVar = dynamic_cast<const AstLeaf *>(
470 *n )->getStrValue();
471 rCont.delVariable( sVar );
472 }
473 break;
474
475 case AstNode::typeIf:
476 {
477 AstBranch::BranchList::const_iterator b =
478 pExpr->getBranchBegin();
479
480 Variable v = execExpr( (*b).begin() );
481 if( v.getType() != Variable::typeBool )
482 {
483 throw Bu::ExceptionBase(
484 "If statement evaluated to non-boolean.");
485 }
486 b++;
487 if( v.getBool() )
488 {
489 i++;
490 sI.push( (*b).begin() );
491 continue;
492 }
493 else
494 {
495 b++;
496 if( b )
497 {
498 i++;
499 sI.push( (*b).begin() );
500 continue;
501 }
502 }
503 }
504 break;
505
506 case AstNode::typeFor:
507 {
508 AstBranch::BranchList::const_iterator b =
509 pExpr->getBranchBegin();
510 Bu::FString sVar = dynamic_cast<const AstLeaf *>(
511 (*b).first() )->getStrValue();
512 b++;
513 Variable v = execExpr( (*b).begin() );
514 b++;
515 for( VarList::const_iterator vi = v.getList().begin();
516 vi; vi++ )
517 {
518 rCont.addVariable( sVar, *vi );
519 run( (*b).begin() );
520 }
521 }
522 break;
523
524 case AstNode::typeFunction:
525 {
526 Variable vIn;
527 execFunc( pExpr, vIn );
528 }
529 break;
530
531 case AstNode::typeReturn:
532 vReturn = execExpr( (*pExpr->getBranchBegin()).begin() );
533 return vReturn;
534 break;
535
536 case AstNode::typeFunctionDef:
537 case AstNode::typeActionDef:
538 // We ignore these, we already dealt with them
539 break;
540
541 case AstNode::typeTarget:
542 // This actually runs exactly like a for loop, if there's
543 // only one item, then we only go once, if it's a list, go
544 // more than once :-P
545 if( pCurTarget == NULL )
546 {
547 AstBranch::BranchList::const_iterator b =
548 pExpr->getBranchBegin();
549 Variable vLoop = execExpr( (*b).begin() );
550 b++;
551 if( vLoop.getType() == Variable::typeString )
552 {
553 rCont.addTarget(
554 buildTarget(
555 vLoop.getString(), (*b).begin()
556 )
557 );
558 }
559 else if( vLoop.getType() == Variable::typeList )
560 {
561 for( VarList::iterator i = vLoop.begin(); i; i++ )
562 {
563 rCont.addTarget(
564 buildTarget(
565 (*i).getString(), (*b).begin()
566 )
567 );
568 }
569 }
570 }
571 else
572 {
573 throw Bu::ExceptionBase(
574 "You cannot declare a target within "
575 "a target decleration.");
576 }
577 break;
578
579 case AstNode::typeRuleDef:
580 if( pCurRule == NULL )
581 {
582 AstBranch::BranchList::const_iterator b =
583 pExpr->getBranchBegin();
584 Bu::FString sName = dynamic_cast<const AstLeaf *>(
585 (*b).first()
586 )->getStrValue();
587 b++;
588 rCont.addRule( buildRule( sName, (*b).begin() ) );
589 }
590 else
591 {
592 throw Bu::ExceptionBase(
593 "You cannot declare a rule within "
594 "a rule decleration.");
595 }
596 break;
597
598 case AstNode::typeInput:
599 if( pCurTarget != NULL )
600 {
601 Variable vRet = execExpr(
602 (*pExpr->getBranchBegin()).begin()
603 );
604 if( vRet.getType() == Variable::typeString )
605 {
606 pCurTarget->addInput( vRet.getString() );
607 }
608 else if( vRet.getType() == Variable::typeList )
609 {
610 for( VarList::iterator i = vRet.begin(); i; i++ )
611 {
612 pCurTarget->addInput(
613 (*i).getString()
614 );
615 }
616 }
617 }
618 else if( pCurRule != NULL )
619 {
620 pCurRule->setInput( pExpr );
621 }
622 else
623 {
624 throw Bu::ExceptionBase(
625 "input can only occur within a target or rule.");
626 }
627 break;
628
629 case AstNode::typeRequires:
630 if( pCurTarget != NULL )
631 {
632 Variable vRet = execExpr(
633 (*pExpr->getBranchBegin()).begin()
634 );
635 if( vRet.getType() == Variable::typeString )
636 {
637 pCurTarget->addRequires( vRet.getString() );
638 }
639 else if( vRet.getType() == Variable::typeList )
640 {
641 for( VarList::iterator i = vRet.begin(); i; i++ )
642 {
643 pCurTarget->addRequires(
644 (*i).getString()
645 );
646 }
647 }
648 }
649 else if( pCurRule != NULL )
650 {
651 pCurRule->addRequires( pExpr );
652 }
653 else
654 {
655 throw Bu::ExceptionBase(
656 "requires can only occur within a target or rule.");
657 }
658 break;
659
660 case AstNode::typeRule:
661 if( pCurTarget )
662 {
663 pCurTarget->setRule(
664 dynamic_cast<const AstLeaf *>(
665 (*pExpr->getBranchBegin()).first()
666 )->getStrValue()
667 );
668 }
669 else
670 {
671 throw Bu::ExceptionBase(
672 "rule can only occur within a target.");
673 }
674 break;
675
676 case AstNode::typeProfile:
677 if( pCurTarget )
678 {
679 pCurTarget->addProfile( pExpr );
680 }
681 else if( pCurRule )
682 {
683 pCurRule->addProfile( pExpr );
684 }
685 else
686 {
687 throw Bu::ExceptionBase(
688 "profile can only occur within a target or rule.");
689 }
690 break;
691
692 case AstNode::typeOutput:
693 if( pCurRule )
694 {
695 pCurRule->addOutput( pExpr );
696 }
697 else
698 {
699 throw Bu::ExceptionBase(
700 "output can only occur within a rule.");
701 }
702 break;
703
704 case AstNode::typeProcessTarget:
705 {
706 AstBranch::BranchList::const_iterator b =
707 pExpr->getBranchBegin();
708 Bu::FString sProfile = dynamic_cast<const AstLeaf *>(
709 (*b).first()
710 )->getStrValue();
711 b++;
712 Variable vTargs = execExpr( (*b).begin() );
713 if( vTargs.getType() == Variable::typeString )
714 {
715 rCont.getTarget( vTargs.getString() )->process(
716 *this, sProfile
717 );
718 }
719 else if( vTargs.getType() == Variable::typeList )
720 {
721 for( VarList::iterator v = vTargs.begin();
722 v; v++ ) {
723 rCont.getTarget( (*v).getString() )->process(
724 *this, sProfile
725 );
726 }
727 }
728 }
729 break;
730
731 case AstNode::typeTag:
732 if( pCurTarget )
733 {
734 AstBranch::BranchList::const_iterator b =
735 pExpr->getBranchBegin();
736 Variable vTags = execExpr( (*b).begin() );
737 if( vTags.getType() == Variable::typeList )
738 {
739 for( VarList::iterator i = vTags.begin(); i; i++ )
740 {
741 rCont.addTargetToTag( pCurTarget, (*i).toString() );
742 }
743 }
744 else
745 {
746 Bu::FString sTag = vTags.toString();
747 if( sTag )
748 {
749 rCont.addTargetToTag( pCurTarget, sTag );
750 }
751 else
752 {
753 throw Bu::ExceptionBase(
754 "A tag evaluted to empty string."
755 );
756 }
757 }
758 }
759 else if( pCurRule )
760 {
761 AstBranch::BranchList::const_iterator b =
762 pExpr->getBranchBegin();
763 Variable vTags = execExpr( (*b).begin() );
764 if( vTags.getType() == Variable::typeList )
765 {
766 for( VarList::iterator i = vTags.begin(); i; i++ )
767 {
768 pCurRule->addTag( (*i).toString() );
769 }
770 }
771 else
772 {
773 Bu::FString sTag = vTags.toString();
774 if( sTag )
775 {
776 pCurRule->addTag( sTag );
777 }
778 else
779 {
780 throw Bu::ExceptionBase(
781 "A tag evaluted to empty string."
782 );
783 }
784 }
785 }
786 else
787 {
788 throw Bu::ExceptionBase(
789 "tag can only occur within a target or rule.");
790 }
791 break;
792
793 case AstNode::typeExpr:
794 execExpr( (*pExpr->getBranchBegin()).begin() );
795 break;
796
797 default:
798 sio << "Branch? " << (*i)->getType() << sio.nl;
799 break;
800 }
801 }
802
803 i++;
804 }
805
806 return vReturn;
807}
808
809void Runner::execProfile( Target *pTarget, const Bu::FString &sProfile )
810{
811 rCont.pushScope( pTarget->getVars() );
812 run( (*(pTarget->getProfile( sProfile )->getRoot()->
813 getBranchBegin()+1)).begin() );
814 rCont.popScope();
815}
816
817void Runner::execAction( const Bu::FString &sName )
818{
819 try
820 {
821 Action *pAct = rCont.getAction( sName );
822
823 pAct->call( this );
824 }
825 catch( Bu::HashException &e )
826 {
827 Bu::FString sError("No such action '" + sName + "' found.");
828 rCont.getView()->sysError( sError );
829 }
830}
831
832Context &Runner::getContext()
833{
834 return rCont;
835}
836
837Target *Runner::buildTarget( const Bu::FString &sOutput,
838 AstBranch::NodeList::const_iterator n )
839{
840 Target *pTrg = NULL;
841 try
842 {
843 pTrg = rCont.getTarget( sOutput );
844 rCont.pushScope( pTrg->getVars() );
845 }
846 catch( Bu::HashException &e )
847 {
848 pTrg = new Target( sOutput, true );
849 rCont.pushScope();
850 }
851
852 // sio << " (target) \"" << sOutput << "\" explicit." << sio.nl;
853
854 rCont.addVariable("OUTPUT", sOutput );
855 pCurTarget = pTrg;
856 run( n );
857
858 rCont.addVariable("INPUT", pTrg->getInputList() );
859 pCurTarget = NULL;
860
861 pTrg->setVars( rCont.getScope() );
862 rCont.popScope();
863
864 return pTrg;
865}
866
867Rule *Runner::buildRule( const Bu::FString &sName,
868 AstBranch::NodeList::const_iterator n )
869{
870 Rule *pRule = new Rule( sName );
871
872 rCont.pushScope();
873 pCurRule = pRule;
874 run( n );
875 rCont.popScope();
876 pCurRule = NULL;
877
878 return pRule;
879}
880
881Variable Runner::doSet( const AstBranch *pRoot )
882{
883 AstBranch::NodeList::const_iterator n =
884 (*pRoot->getBranchBegin()).begin();
885 Bu::FString sVar = dynamic_cast<const AstLeaf *>( *n )->getStrValue();
886 n++;
887 const AstLeaf *pLeaf = dynamic_cast<const AstLeaf *>( *n );
888 n++;
889 Variable v = execExpr( n );
890
891 switch( pLeaf->getType() )
892 {
893 case AstNode::typeOpEq:
894 rCont.addVariable( sVar, v );
895 break;
896
897 case AstNode::typeOpPlusEq:
898 try
899 {
900 rCont.getVariable( sVar ) += v;
901 } catch(...)
902 {
903 rCont.addVariable( sVar, v );
904 }
905 break;
906
907 case AstNode::typeOpPlusEqRaw:
908 try
909 {
910 rCont.getVariable( sVar ) << v;
911 } catch(...)
912 {
913 rCont.addVariable( sVar, v );
914 }
915 break;
916
917 default: break;
918 }
919
920 return v;
921}
922