aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/action.cpp107
-rw-r--r--src/action.h26
-rw-r--r--src/ast.cpp98
-rw-r--r--src/ast.h44
-rw-r--r--src/astbranch.cpp44
-rw-r--r--src/astbranch.h27
-rw-r--r--src/astleaf.cpp137
-rw-r--r--src/astleaf.h41
-rw-r--r--src/astnode.cpp113
-rw-r--r--src/astnode.h108
-rw-r--r--src/build.l216
-rw-r--r--src/build.y741
-rw-r--r--src/buildparser.cpp127
-rw-r--r--src/buildparser.h40
-rw-r--r--src/condition.cpp10
-rw-r--r--src/condition.h16
-rw-r--r--src/conditionalways.cpp21
-rw-r--r--src/conditionalways.h16
-rw-r--r--src/conditionfiletime.cpp73
-rw-r--r--src/conditionfiletime.h16
-rw-r--r--src/conditionnever.cpp21
-rw-r--r--src/conditionnever.h16
-rw-r--r--src/context.cpp524
-rw-r--r--src/context.h101
-rw-r--r--src/function.cpp16
-rw-r--r--src/function.h23
-rw-r--r--src/functionast.cpp33
-rw-r--r--src/functionast.h21
-rw-r--r--src/functiondirname.cpp38
-rw-r--r--src/functiondirname.h17
-rw-r--r--src/functiondirs.cpp61
-rw-r--r--src/functiondirs.h17
-rw-r--r--src/functionexecute.cpp68
-rw-r--r--src/functionexecute.h16
-rw-r--r--src/functionexists.cpp34
-rw-r--r--src/functionexists.h17
-rw-r--r--src/functionfilename.cpp36
-rw-r--r--src/functionfilename.h17
-rw-r--r--src/functionfiles.cpp61
-rw-r--r--src/functionfiles.h17
-rw-r--r--src/functiongetmakedeps.cpp59
-rw-r--r--src/functiongetmakedeps.h16
-rw-r--r--src/functionmatches.cpp141
-rw-r--r--src/functionmatches.h23
-rw-r--r--src/functionreplace.cpp47
-rw-r--r--src/functionreplace.h16
-rw-r--r--src/functiontargets.cpp39
-rw-r--r--src/functiontargets.h16
-rw-r--r--src/functiontostring.cpp50
-rw-r--r--src/functiontostring.h16
-rw-r--r--src/functionunlink.cpp51
-rw-r--r--src/functionunlink.h16
-rw-r--r--src/main.cpp255
-rw-r--r--src/profile.cpp116
-rw-r--r--src/profile.h30
-rw-r--r--src/rule.cpp167
-rw-r--r--src/rule.h53
-rw-r--r--src/runner.cpp922
-rw-r--r--src/runner.h43
-rw-r--r--src/target.cpp402
-rw-r--r--src/target.h89
-rw-r--r--src/types.h26
-rw-r--r--src/variable.cpp892
-rw-r--r--src/variable.h115
-rw-r--r--src/view.cpp10
-rw-r--r--src/view.h46
-rw-r--r--src/viewdefault.cpp170
-rw-r--r--src/viewdefault.h42
-rw-r--r--src/viewmake.cpp86
-rw-r--r--src/viewmake.h36
-rw-r--r--src/viewplugger.cpp14
-rw-r--r--src/viewplugger.h20
72 files changed, 7199 insertions, 0 deletions
diff --git a/src/action.cpp b/src/action.cpp
new file mode 100644
index 0000000..23c24cd
--- /dev/null
+++ b/src/action.cpp
@@ -0,0 +1,107 @@
1#include "action.h"
2#include "ast.h"
3#include "astbranch.h"
4#include "astleaf.h"
5#include "runner.h"
6#include "variable.h"
7
8Action::Action( const class AstBranch *pRoot ) :
9 pRoot( pRoot ),
10 pAst( NULL )
11{
12 sName = dynamic_cast<AstLeaf *>(
13 *(*pRoot->getBranchBegin()).begin()
14 )->getStrValue();
15}
16
17Action::~Action()
18{
19 delete pAst;
20 pAst = NULL;
21}
22
23const Bu::FString &Action::getName() const
24{
25 return sName;
26}
27
28void Action::call( class Runner *pRunner )
29{
30 pRunner->run( (*(pRoot->getBranchBegin()+1)).begin() );
31}
32
33Action *Action::genDefaultAll()
34{
35 Ast *pAst = new Ast();
36 pAst->addNode( AstNode::typeActionDef );
37 pAst->openBranch();
38 pAst->addNode( AstNode::typeString, "all" );
39 pAst->openBranch();
40 pAst->addNode( AstNode::typeProcessTarget );
41 pAst->openBranch();
42 pAst->addNode( AstNode::typeString, "build" );
43 pAst->openBranch();
44 pAst->addNode( AstNode::typeFunction );
45 pAst->openBranch();
46 pAst->addNode( AstNode::typeString, "targets" );
47 pAst->closeNode();
48 pAst->closeNode();
49 pAst->closeNode();
50 Action *pRet = new Action(
51 dynamic_cast<const AstBranch *>( *pAst->getNodeBegin() )
52 );
53 pRet->pAst = pAst;
54
55 return pRet;
56}
57
58Action *Action::genDefaultClean()
59{
60 Ast *pAst = new Ast();
61 pAst->addNode( AstNode::typeActionDef );
62 pAst->openBranch();
63 pAst->addNode( AstNode::typeString, "clean" );
64 pAst->openBranch();
65 pAst->addNode( AstNode::typeProcessTarget );
66 pAst->openBranch();
67 pAst->addNode( AstNode::typeString, "clean" );
68 pAst->openBranch();
69 pAst->addNode( AstNode::typeFunction );
70 pAst->openBranch();
71 pAst->addNode( AstNode::typeString, "targets" );
72 pAst->closeNode();
73 pAst->closeNode();
74 pAst->closeNode();
75 Action *pRet = new Action(
76 dynamic_cast<const AstBranch *>( *pAst->getNodeBegin() )
77 );
78 pRet->pAst = pAst;
79
80 return pRet;
81}
82
83Action *Action::genDefaultDefault()
84{
85 Ast *pAst = new Ast();
86 pAst->addNode( AstNode::typeActionDef );
87 pAst->openBranch();
88 pAst->addNode( AstNode::typeString, "default" );
89 pAst->openBranch();
90 pAst->addNode( AstNode::typeProcessTarget );
91 pAst->openBranch();
92 pAst->addNode( AstNode::typeString, "build" );
93 pAst->openBranch();
94 pAst->addNode( AstNode::typeFunction );
95 pAst->openBranch();
96 pAst->addNode( AstNode::typeString, "targets" );
97 pAst->closeNode();
98 pAst->closeNode();
99 pAst->closeNode();
100 Action *pRet = new Action(
101 dynamic_cast<const AstBranch *>( *pAst->getNodeBegin() )
102 );
103 pRet->pAst = pAst;
104
105 return pRet;
106}
107
diff --git a/src/action.h b/src/action.h
new file mode 100644
index 0000000..520f2f1
--- /dev/null
+++ b/src/action.h
@@ -0,0 +1,26 @@
1#ifndef ACTION_H
2#define ACTION_H
3
4#include <bu/fstring.h>
5
6class Action
7{
8public:
9 Action( const class AstBranch *pRoot );
10 virtual ~Action();
11
12 const Bu::FString &getName() const;
13
14 void call( class Runner *pRunner );
15
16 static Action *genDefaultAll();
17 static Action *genDefaultClean();
18 static Action *genDefaultDefault();
19
20private:
21 Bu::FString sName;
22 const class AstBranch *pRoot;
23 class Ast *pAst;
24};
25
26#endif
diff --git a/src/ast.cpp b/src/ast.cpp
new file mode 100644
index 0000000..03ed4b6
--- /dev/null
+++ b/src/ast.cpp
@@ -0,0 +1,98 @@
1#include "ast.h"
2
3#include "astleaf.h"
4#include "astbranch.h"
5
6Ast::Ast()
7{
8}
9
10Ast::~Ast()
11{
12}
13
14void Ast::addNode( AstNode::Type eType )
15{
16 switch( eType&AstNode::typeClassMask )
17 {
18 case AstNode::typeBranch:
19 {
20 AstBranch *pNode = new AstBranch( eType );
21 addNode( pNode );
22 sBranch.push( pNode );
23 }
24 break;
25
26 case AstNode::typeLeaf:
27 {
28 AstLeaf *pNode = new AstLeaf( eType );
29 addNode( pNode );
30 }
31 break;
32
33 default:
34 throw Bu::ExceptionBase("You got it wrong.");
35 break;
36 }
37}
38
39void Ast::addNode( AstNode::Type eType, int iVal )
40{
41 addNode( new AstLeaf( eType, iVal ) );
42}
43
44void Ast::addNode( AstNode::Type eType, float fVal )
45{
46 addNode( new AstLeaf( eType, fVal ) );
47}
48
49void Ast::addNode( AstNode::Type eType, bool bVal )
50{
51 addNode( new AstLeaf( eType, bVal ) );
52}
53
54void Ast::addNode( AstNode::Type eType, const Bu::FString &sVal )
55{
56 addNode( new AstLeaf( eType, sVal ) );
57}
58
59void Ast::addNode( AstNode::Type eType, const char *sVal )
60{
61 addNode( new AstLeaf( eType, sVal ) );
62}
63
64void Ast::addNode( AstNode *pNode )
65{
66 if( sBranch.isEmpty() )
67 lNode.append( pNode );
68 else
69 sBranch.peek()->addNode( pNode );
70}
71
72void Ast::openBranch()
73{
74 sBranch.peek()->addBranch();
75}
76
77void Ast::closeNode()
78{
79 sBranch.pop();
80}
81
82Ast::NodeList::const_iterator Ast::getNodeBegin() const
83{
84 return lNode.begin();
85}
86
87Bu::Formatter &operator<<( Bu::Formatter &f, const Ast &a )
88{
89 f << "Abstract Syntax Tree:";
90 f.incIndent();
91 f << f.nl;
92 for( Ast::NodeList::const_iterator i = a.getNodeBegin(); i; i++ )
93 f << **i << f.nl;
94 f << f.nl;
95 f.decIndent();
96 return f;
97}
98
diff --git a/src/ast.h b/src/ast.h
new file mode 100644
index 0000000..a4f9361
--- /dev/null
+++ b/src/ast.h
@@ -0,0 +1,44 @@
1#ifndef AST_H
2#define AST_H
3
4#include "bu/list.h"
5#include "bu/stack.h"
6#include "bu/fstring.h"
7#include "bu/formatter.h"
8
9#include "astnode.h"
10
11/**
12 * Abstract Symbol Tree. This is the thing that the parser builds for us. In
13 * the end, this is also what we "run" when we run build files.
14 */
15class Ast
16{
17public:
18 typedef Bu::List<AstNode *> NodeList;
19 Ast();
20 virtual ~Ast();
21
22 void addNode( AstNode::Type eType );
23 void addNode( AstNode::Type eType, int iVal );
24 void addNode( AstNode::Type eType, float fVal );
25 void addNode( AstNode::Type eType, bool bVal );
26 void addNode( AstNode::Type eType, const Bu::FString &sVal );
27 void addNode( AstNode::Type eType, const char *sVal );
28 void addNode( AstNode *pNode );
29
30 void openBranch();
31
32 void closeNode();
33
34 NodeList::const_iterator getNodeBegin() const;
35
36private:
37 NodeList lNode;
38 typedef Bu::Stack<class AstBranch *> BranchStack;
39 BranchStack sBranch;
40};
41
42Bu::Formatter &operator<<( Bu::Formatter &f, const Ast &a );
43
44#endif
diff --git a/src/astbranch.cpp b/src/astbranch.cpp
new file mode 100644
index 0000000..a6aa21c
--- /dev/null
+++ b/src/astbranch.cpp
@@ -0,0 +1,44 @@
1#include "astbranch.h"
2
3AstBranch::AstBranch( Type eType ) :
4 AstNode( eType )
5{
6}
7
8AstBranch::~AstBranch()
9{
10}
11
12void AstBranch::addBranch()
13{
14 lBranch.append( NodeList() );
15}
16
17void AstBranch::addNode( AstNode *pNode )
18{
19 lBranch.last().append( pNode );
20}
21
22AstBranch::BranchList::const_iterator AstBranch::getBranchBegin() const
23{
24 return lBranch.begin();
25}
26
27Bu::Formatter &operator<<( Bu::Formatter &f, const AstBranch &l )
28{
29 f.incIndent();
30 f << ":";
31 for( AstBranch::BranchList::const_iterator i = l.getBranchBegin(); i; i++ )
32 {
33 f << f.nl << "Branch:";
34 f.incIndent();
35 for( AstBranch::NodeList::const_iterator j = i->begin(); j; j++ )
36 {
37 f << f.nl << **j;
38 }
39 f.decIndent();
40 }
41 f.decIndent();
42 return f;
43}
44
diff --git a/src/astbranch.h b/src/astbranch.h
new file mode 100644
index 0000000..5ff8606
--- /dev/null
+++ b/src/astbranch.h
@@ -0,0 +1,27 @@
1#ifndef AST_BRANCH_H
2#define AST_BRANCH_H
3
4#include "bu/list.h"
5#include "astnode.h"
6#include "bu/formatter.h"
7
8class AstBranch : public AstNode
9{
10public:
11 typedef Bu::List<AstNode *> NodeList;
12 typedef Bu::List<NodeList> BranchList;
13 AstBranch( Type eType );
14 virtual ~AstBranch();
15
16 void addBranch();
17 void addNode( AstNode *pNode );
18
19 BranchList::const_iterator getBranchBegin() const;
20
21private:
22 BranchList lBranch;
23};
24
25Bu::Formatter &operator<<( Bu::Formatter &f, const AstBranch &l );
26
27#endif
diff --git a/src/astleaf.cpp b/src/astleaf.cpp
new file mode 100644
index 0000000..62773ce
--- /dev/null
+++ b/src/astleaf.cpp
@@ -0,0 +1,137 @@
1#include "astleaf.h"
2
3AstLeaf::AstLeaf( Type eType ) :
4 AstNode( eType ),
5 sVal( NULL )
6{
7}
8
9AstLeaf::AstLeaf( Type eType, int iNew ) :
10 AstNode( eType ),
11 sVal( NULL )
12{
13 setIntValue( iNew );
14}
15
16AstLeaf::AstLeaf( Type eType, float fNew ) :
17 AstNode( eType ),
18 sVal( NULL )
19{
20 setFloatValue( fNew );
21}
22
23AstLeaf::AstLeaf( Type eType, bool bNew ) :
24 AstNode( eType ),
25 sVal( NULL )
26{
27 setBoolValue( bNew );
28}
29
30AstLeaf::AstLeaf( Type eType, const Bu::FString &sNew ) :
31 AstNode( eType ),
32 sVal( NULL )
33{
34 setStrValue( sNew );
35}
36
37AstLeaf::AstLeaf( Type eType, const char *sNew ) :
38 AstNode( eType ),
39 sVal( NULL )
40{
41 setStrValue( sNew );
42}
43
44AstLeaf::~AstLeaf()
45{
46 if( getDataType() == typeDataString )
47 delete sVal;
48}
49
50void AstLeaf::setIntValue( int iNew )
51{
52 if( getDataType() != typeDataInt )
53 throw Bu::ExceptionBase("Type is not int.");
54 iVal = iNew;
55}
56
57void AstLeaf::setFloatValue( float fNew )
58{
59 if( getDataType() != typeDataFloat )
60 throw Bu::ExceptionBase("Type is not float.");
61 fVal = fNew;
62}
63
64void AstLeaf::setBoolValue( bool bNew )
65{
66 if( getDataType() != typeDataBool )
67 throw Bu::ExceptionBase("Type is not bool.");
68 bVal = bNew;
69}
70
71void AstLeaf::setStrValue( const Bu::FString &sNew )
72{
73 if( getDataType() != typeDataString )
74 throw Bu::ExceptionBase("Type is not string.");
75 if( sVal == NULL )
76 sVal = new Bu::FString( sNew );
77 else
78 *sVal = sNew;
79}
80
81int AstLeaf::getIntValue() const
82{
83 if( getDataType() != typeDataInt )
84 throw Bu::ExceptionBase("Type is not int.");
85 return iVal;
86}
87
88float AstLeaf::getFloatValue() const
89{
90 if( getDataType() != typeDataFloat )
91 throw Bu::ExceptionBase("Type is not float.");
92 return fVal;
93}
94
95bool AstLeaf::getBoolValue() const
96{
97 if( getDataType() != typeDataBool )
98 throw Bu::ExceptionBase("Type is not bool.");
99 return bVal;
100}
101
102Bu::FString &AstLeaf::getStrValue() const
103{
104 if( getDataType() != typeDataString )
105 throw Bu::ExceptionBase("Type is not string.");
106 return *sVal;
107}
108
109Bu::Formatter &operator<<( Bu::Formatter &f, const AstLeaf &l )
110{
111 switch( l.getDataType() )
112 {
113 case AstNode::typeDataInt:
114 f << ": " << l.getIntValue();
115 break;
116
117 case AstNode::typeDataFloat:
118 f << ": " << l.getFloatValue();
119 break;
120
121 case AstNode::typeDataBool:
122 f << ": " << l.getBoolValue();
123 break;
124
125 case AstNode::typeDataString:
126 f << ": '" << l.getStrValue() << "'";
127 break;
128
129 case AstNode::typeDataNone:
130 break;
131
132 default:
133 f << ": " << "!! Invalid Type !!";
134 }
135 return f;
136}
137
diff --git a/src/astleaf.h b/src/astleaf.h
new file mode 100644
index 0000000..0c8911b
--- /dev/null
+++ b/src/astleaf.h
@@ -0,0 +1,41 @@
1#ifndef AST_LEAF_H
2#define AST_LEAF_H
3
4#include "astnode.h"
5#include "bu/fstring.h"
6#include "bu/formatter.h"
7
8class AstLeaf : public AstNode
9{
10public:
11 AstLeaf( Type eType );
12 AstLeaf( Type eType, int iNew );
13 AstLeaf( Type eType, float fNew );
14 AstLeaf( Type eType, bool bNew );
15 AstLeaf( Type eType, const Bu::FString &sNew );
16 AstLeaf( Type eType, const char *sNew );
17 virtual ~AstLeaf();
18
19 void setIntValue( int iNew );
20 void setFloatValue( float fNew );
21 void setBoolValue( bool bNew );
22 void setStrValue( const Bu::FString &sNew );
23
24 int getIntValue() const;
25 float getFloatValue() const;
26 bool getBoolValue() const;
27 Bu::FString &getStrValue() const;
28
29private:
30 union
31 {
32 int iVal;
33 float fVal;
34 bool bVal;
35 Bu::FString *sVal;
36 };
37};
38
39Bu::Formatter &operator<<( Bu::Formatter &f, const AstLeaf &l );
40
41#endif
diff --git a/src/astnode.cpp b/src/astnode.cpp
new file mode 100644
index 0000000..5adb3ee
--- /dev/null
+++ b/src/astnode.cpp
@@ -0,0 +1,113 @@
1#include "astnode.h"
2#include "astleaf.h"
3#include "astbranch.h"
4
5AstNode::AstNode( Type eType ) :
6 eType( eType )
7{
8}
9
10AstNode::~AstNode()
11{
12}
13
14Bu::Formatter &operator<<( Bu::Formatter &f, const AstNode &n )
15{
16 f << n.getType();
17 if( n.getClass() == AstNode::typeBranch )
18 {
19 f << *dynamic_cast<const AstBranch *>(&n);
20 }
21 else
22 {
23 f << *dynamic_cast<const AstLeaf *>(&n);
24 }
25 return f;
26}
27
28Bu::Formatter &operator<<( Bu::Formatter &f, const AstNode::Type &t )
29{
30 switch( t )
31 {
32 case AstNode::typeFunction: f << "Function"; break;
33 case AstNode::typeSet: f << "Set"; break;
34 case AstNode::typeUnset: f << "Unset"; break;
35 case AstNode::typeIf: f << "If"; break;
36 case AstNode::typeInclude: f << "Include"; break;
37 case AstNode::typeTarget: f << "Target"; break;
38 case AstNode::typeRule: f << "Rule"; break;
39 case AstNode::typeConfig: f << "Config"; break;
40 case AstNode::typeList: f << "List"; break;
41 case AstNode::typeInlineFunc: f << "InlineFunc"; break;
42 case AstNode::typeRequires: f << "Requires"; break;
43 case AstNode::typeFor: f << "For"; break;
44 case AstNode::typeFunctionDef: f << "FunctionDef"; break;
45 case AstNode::typeReturn: f << "Return"; break;
46 case AstNode::typeProfile: f << "Profile"; break;
47 case AstNode::typeInput: f << "Input"; break;
48 case AstNode::typeRuleDef: f << "RuleDef"; break;
49 case AstNode::typeOutput: f << "Output"; break;
50 case AstNode::typeAutoConfig: f << "AutoConfig"; break;
51 case AstNode::typeGlobalConfig: f << "GlobalConfig"; break;
52 case AstNode::typeType: f << "Type"; break;
53 case AstNode::typeValue: f << "Value"; break;
54 case AstNode::typeAllow: f << "Allow"; break;
55 case AstNode::typeDefault: f << "Default"; break;
56 case AstNode::typeExport: f << "Export"; break;
57 case AstNode::typeExpr: f << "Expr"; break;
58 case AstNode::typeActionDef: f << "ActionDef"; break;
59 case AstNode::typeProcessTarget:f << "ProcessTarget"; break;
60 case AstNode::typeTag: f << "Tag"; break;
61
62 case AstNode::typeVariable: f << "Variable"; break;
63 case AstNode::typeString: f << "String"; break;
64 case AstNode::typeInt: f << "Int"; break;
65 case AstNode::typeFloat: f << "Float"; break;
66 case AstNode::typeBool: f << "Bool"; break;
67 case AstNode::typeVersion: f << "Version"; break;
68 case AstNode::typeOpEq: f << "Operator ="; break;
69 case AstNode::typeOpPlusEq: f << "Operator +="; break;
70 case AstNode::typeOpPlusEqRaw: f << "Operator <<"; break;
71 case AstNode::typeError: f << "Error"; break;
72 case AstNode::typeWarning: f << "Warning"; break;
73 case AstNode::typeNotice: f << "Notice"; break;
74 case AstNode::typeTypeString: f << "Type String"; break;
75 case AstNode::typeTypeInt: f << "Type Int"; break;
76 case AstNode::typeTypeFloat: f << "Type Float"; break;
77 case AstNode::typeTypeBool: f << "Type Bool"; break;
78 case AstNode::typeTypeVersion: f << "Type Version"; break;
79 case AstNode::typeCmpEq: f << "Compare ="; break;
80 case AstNode::typeCmpLt: f << "Compare <"; break;
81 case AstNode::typeCmpGt: f << "Compare >"; break;
82 case AstNode::typeCmpNe: f << "Compare !="; break;
83 case AstNode::typeCmpLtEq: f << "Compare <="; break;
84 case AstNode::typeCmpGtEq: f << "Compare >="; break;
85 case AstNode::typeCondition: f << "Condition"; break;
86 case AstNode::typeDisplay: f << "Display"; break;
87 case AstNode::typeCache: f << "Cache"; break;
88 case AstNode::typePushPrefix: f << "Push Prefix"; break;
89 case AstNode::typePopPrefix: f << "Pop Prefix"; break;
90 case AstNode::typeNull: f << "Null"; break;
91 case AstNode::typeVariableRef: f << "VariableRef"; break;
92 case AstNode::typeOpPlus: f << "Operator +"; break;
93 case AstNode::typeOpMinus: f << "Operator -"; break;
94 case AstNode::typeOpMultiply: f << "Operator *"; break;
95 case AstNode::typeOpDivide: f << "Operator /"; break;
96 case AstNode::typeOpNegate: f << "Operator negate"; break;
97 case AstNode::typeOpNot: f << "Operator not"; break;
98
99 case AstNode::typeBranch: f << "Branch"; break;
100 case AstNode::typeLeaf: f << "Leaf"; break;
101 case AstNode::typeClassMask: f << "ClassMask"; break;
102
103 case AstNode::typeDataNone: f << "<Data None>"; break;
104 case AstNode::typeDataString: f << "<Data String>"; break;
105 case AstNode::typeDataInt: f << "<Data Int>"; break;
106 case AstNode::typeDataFloat: f << "<Data Float>"; break;
107 case AstNode::typeDataBool: f << "<Data Bool>"; break;
108 case AstNode::typeDataVersion: f << "<Data Version>"; break;
109 case AstNode::typeDataMask: f << "<Data Mask>"; break;
110 }
111 return f;
112}
113
diff --git a/src/astnode.h b/src/astnode.h
new file mode 100644
index 0000000..6ade25b
--- /dev/null
+++ b/src/astnode.h
@@ -0,0 +1,108 @@
1#ifndef AST_NODE_H
2#define AST_NODE_H
3
4#include "bu/formatter.h"
5
6class AstNode
7{
8public:
9 enum Type
10 {
11 // Branching types
12 typeFunction = 0x100001,
13 typeSet = 0x100002,
14 typeUnset = 0x100003,
15 typeIf = 0x100004,
16 typeInclude = 0x100005,
17 typeTarget = 0x100006,
18 typeRule = 0x100007,
19 typeConfig = 0x100008,
20 typeList = 0x100009,
21 typeInlineFunc = 0x10000A,
22 typeRequires = 0x10000B,
23 typeFor = 0x10000C,
24 typeFunctionDef = 0x10000D,
25 typeReturn = 0x10000E,
26 typeProfile = 0x10000F,
27 typeInput = 0x100010,
28 typeRuleDef = 0x100011,
29 typeOutput = 0x100012,
30 typeAutoConfig = 0x100013,
31 typeGlobalConfig = 0x100014,
32 typeType = 0x100015,
33 typeValue = 0x100016,
34 typeAllow = 0x100017,
35 typeDefault = 0x100018,
36 typeExport = 0x100019,
37 typeExpr = 0x10001A, /***< Stack based compound expression.*/
38 typeActionDef = 0x10001B,
39 typeProcessTarget = 0x10001C,
40 typeTag = 0x10001D,
41
42 // Leaf types
43 typeVariable = 0x210001,
44 typeString = 0x210002,
45 typeInt = 0x220003,
46 typeFloat = 0x230004,
47 typeBool = 0x240005,
48 typeVersion = 0x250006,
49 typeOpEq = 0x200007,
50 typeOpPlusEq = 0x200008,
51 typeOpPlusEqRaw = 0x200009,
52 typeError = 0x21000A,
53 typeWarning = 0x21000B,
54 typeNotice = 0x21000C,
55 typeTypeString = 0x20000D,
56 typeTypeInt = 0x20000E,
57 typeTypeFloat = 0x20000F,
58 typeTypeBool = 0x200010,
59 typeTypeVersion = 0x200011,
60 typeCmpEq = 0x200012,
61 typeCmpLt = 0x200013,
62 typeCmpGt = 0x200014,
63 typeCmpNe = 0x200015,
64 typeCmpLtEq = 0x200016,
65 typeCmpGtEq = 0x200017,
66 typeCondition = 0x210018,
67 typeDisplay = 0x210019,
68 typeCache = 0x24001A,
69 typePushPrefix = 0x21001B,
70 typePopPrefix = 0x20001C,
71 typeNull = 0x20001D,
72 typeVariableRef = 0x21001E,
73 typeOpPlus = 0x20001F,
74 typeOpMinus = 0x200020,
75 typeOpMultiply = 0x200021,
76 typeOpDivide = 0x200022,
77 typeOpNegate = 0x200023,
78 typeOpNot = 0x200024,
79
80 typeBranch = 0x100000,
81 typeLeaf = 0x200000,
82 typeClassMask = 0x300000,
83
84 typeDataNone = 0x000000,
85 typeDataString = 0x010000,
86 typeDataInt = 0x020000,
87 typeDataFloat = 0x030000,
88 typeDataBool = 0x040000,
89 typeDataVersion = 0x050000,
90
91 typeDataMask = 0x0F0000
92 };
93public:
94 AstNode( Type eType );
95 virtual ~AstNode();
96
97 Type getType() const { return eType; }
98 Type getClass() const { return (Type)(eType&typeClassMask); }
99 Type getDataType() const { return (Type)(eType&typeDataMask); }
100
101private:
102 Type eType;
103};
104
105Bu::Formatter &operator<<( Bu::Formatter &f, const AstNode &n );
106Bu::Formatter &operator<<( Bu::Formatter &f, const AstNode::Type &t );
107
108#endif
diff --git a/src/build.l b/src/build.l
new file mode 100644
index 0000000..dc4ddda
--- /dev/null
+++ b/src/build.l
@@ -0,0 +1,216 @@
1%{
2 #include "buildparser.h"
3 #include "bu/fstring.h"
4
5char *fstrdup( const Bu::FString &s )
6{
7 char *sRet = new char[s.getSize()+1];
8 memcpy( sRet, s.getStr(), s.getSize()+1 );
9 return sRet;
10}
11
12char *rstrdup( const char *sIn )
13{
14 char *sRet = new char[strlen(sIn)+1];
15 strcpy( sRet, sIn );
16 return sRet;
17}
18void build_error( YYLTYPE *locp, yyscan_t yyscanner, BuildParser &bld, const char *msg );
19
20Bu::FString sBuf;
21int iStrDepth = 0;
22%}
23
24%{
25 #define YY_USER_ACTION yylloc->last_column += yyleng;
26%}
27
28%x strdq
29%x BlockComment
30%option noyywrap nounput batch debug bison-bridge bison-locations reentrant
31%option prefix="build_"
32%option outfile="src/build.yy.c"
33%option header-file="src/build.yy.h"
34%%
35\n+ {
36 yylloc->last_line += yyleng;
37 yylloc->first_line = yylloc->last_line;
38 yylloc->first_column = yylloc->last_column = 0;
39}
40[ \t\r]+ {
41 yylloc->first_line = yylloc->last_line;
42 yylloc->first_column = yylloc->last_column+1;
43}
44"#".* /* eol comment */
45"//".* /* eol comment */
46
47"/*" {
48 BEGIN( BlockComment );
49}
50
51<BlockComment>"*/" {
52 BEGIN( INITIAL );
53}
54
55<BlockComment>\n+ {
56 yylloc->last_column = -yyleng;
57 yylloc->last_line += yyleng;
58}
59<BlockComment>. { }
60 /*
61<BlockComment>[^*\n/]+ { }
62<BlockComment>"*"[^/\n]+ { }
63<BlockComment>"*"|"/" { }
64 */
65
66[(){}[\],.;=<>!+*/-] return yytext[0];
67"+=" return OP_ADDSETP;
68"<<" return OP_ADDSETR;
69"==" return OP_CMPEQUAL;
70"!=" return OP_INEQUAL;
71"<=" return OP_LTEQUAL;
72">=" return OP_GTEQUAL;
73"target" return TOK_TARGET;
74"input" return TOK_INPUT;
75"output" return TOK_OUTPUT;
76"unset" return TOK_UNSET;
77"set" return TOK_SET;
78"condition" return TOK_CONDITION;
79"requires" return TOK_REQUIRES;
80"auto" return TOK_AUTO;
81"config" return TOK_CONFIG;
82"display" return TOK_DISPLAY;
83"type" return TOK_TYPE;
84"int" return TOK_INT;
85"float" return TOK_FLOAT;
86"bool" return TOK_BOOL;
87"version" return TOK_VERSION;
88"string" return TOK_STRING;
89"default" return TOK_DEFAULT;
90"allow" return TOK_ALLOW;
91"rule" return TOK_RULE;
92"action" return TOK_ACTION;
93"profile" return TOK_PROFILE;
94"if" return TOK_IF;
95"then" return TOK_THEN;
96"else" return TOK_ELSE;
97"include" return TOK_INCLUDE;
98"warning" return TOK_WARNING;
99"error" return TOK_ERROR;
100"notice" return TOK_NOTICE;
101"cache" return TOK_CACHE;
102"always" return TOK_ALWAYS;
103"never" return TOK_NEVER;
104"global" return TOK_GLOBAL;
105"local" return TOK_LOCAL;
106"for" return TOK_FOR;
107"in" return TOK_IN;
108"do" return TOK_DO;
109"return" return TOK_RETURN;
110"function" return TOK_FUNCTION;
111"continue" return TOK_CONTINUE;
112"break" return TOK_BREAK;
113"value" return TOK_VALUE;
114"all" return TOK_ALL;
115"export" return TOK_EXPORT;
116"tag" return TOK_TAG;
117"null" return TOK_NULL;
118
119"true" {
120 yylval->bVal = true;
121 return BOOL;
122}
123"false" {
124 yylval->bVal = false;
125 return BOOL;
126}
127
128[a-zA-Z_][a-zA-Z0-9_]*: {
129 yytext[yyleng-1] = '\0';
130 yylval->sVal = rstrdup( yytext );
131 return PROFILE;
132}
133
134[a-zA-Z_][a-zA-Z0-9_]* {
135 yylval->sVal = rstrdup( yytext );
136 if( b.isKeyword( yylval->sVal ) )
137 return KEYWORD;
138 else if( b.isCond( yylval->sVal ) )
139 return CONDITION;
140 return UNDEF;
141}
142
143-?([1-9][0-9]*)|(0) {
144 yylval->iVal = strtol( yytext, NULL, 10 );
145 return INT;
146}
147
148(0\.0+)|(-?(([1-9][0-9]*)|(0))\.[0-9]*) {
149 yylval->fVal = strtof( yytext, NULL );
150 return FLOAT;
151}
152
153\" {
154 BEGIN( strdq );
155 sBuf.clear();
156 iStrDepth = 0;
157}
158<strdq>[^\\\n\"$()]+ {
159 sBuf += yytext;
160}
161<strdq>\$\$ {
162 sBuf += "$$";
163}
164<strdq>\$\( {
165 iStrDepth++; // TODO: Should this really count depth? I dunno...
166 sBuf += "$(";
167}
168<strdq>\\\) sBuf += "\\)";
169<strdq>\) {
170 if( iStrDepth > 0 )
171 iStrDepth--;
172 sBuf += ")";
173}
174<strdq>[$(] {
175 sBuf += yytext;
176}
177<strdq>\n {
178 build_error( yylloc, yyscanner, b, "newline encountered in string");
179}
180<strdq>\\n sBuf += "\n";
181<strdq>\\t sBuf += "\t";
182<strdq>\\r sBuf += "\r";
183<strdq>\\b sBuf += "\b";
184<strdq>\\f sBuf += "\f";
185<strdq>\\\\ sBuf += "\\";
186<strdq>\\\" sBuf += "\"";
187<strdq>\\\' sBuf += "\'";
188<strdq>\\\( sBuf += "(";
189<strdq>\\\` sBuf += "`";
190<strdq>\\. printf("Invalid escape sequence.\n");
191<strdq>\"[ \t\r\n]*\" {/* Ignore spaces between strings. */}
192<strdq>\" {
193 if( iStrDepth > 0 )
194 {
195 sBuf += "\"";
196 }
197 else
198 {
199 BEGIN( INITIAL );
200 yylval->sVal = fstrdup( sBuf );
201 return STRING;
202 }
203}
204
205<<EOF>> {
206 build_pop_buffer_state( yyscanner );
207 if( !YY_CURRENT_BUFFER )
208 yyterminate();
209 else
210 b.endInclude( yylloc );
211}
212
213. {
214 build_error( yylloc, yyscanner, b, "invalid character");
215}
216%%
diff --git a/src/build.y b/src/build.y
new file mode 100644
index 0000000..a6618e4
--- /dev/null
+++ b/src/build.y
@@ -0,0 +1,741 @@
1%defines
2%{ /* Prologue -- decls and stuff */
3 #include "buildparser.h"
4 #include "ast.h"
5void yyerror( YYLTYPE *locp, yyscan_t yyscanner, BuildParser &bld, const char *msg );
6%}
7/* Bison declerations */
8
9%parse-param { yyscan_t yyscanner }
10%parse-param { BuildParser &bld }
11%lex-param { yyscan_t yyscanner }
12%lex-param { BuildParser &bld }
13%pure-parser
14
15%locations
16
17%debug
18%error-verbose
19%name-prefix="build_"
20
21%union {
22 int iVal;
23 char *sVal;
24 float fVal;
25 bool bVal;
26}
27
28%token <sVal> STRING "string literal"
29%token <sVal> KEYWORD "keyword"
30%token <sVal> CONDITION "condition term"
31%token <sVal> VARIABLE "variable name"
32%token <sVal> FUNCTION "function name"
33%token <sVal> UNDEF "undefined identifier"
34%token <sVal> PROFILE "profile execute"
35%token <iVal> INT "integer literal"
36%token <fVal> FLOAT "floating point literal"
37%token <bVal> BOOL "boolean literal"
38
39%token TOK_TARGET "target"
40%token TOK_INPUT "input"
41%token TOK_OUTPUT "output"
42%token TOK_UNSET "unset"
43%token TOK_SET "set"
44%token TOK_CONDITION "condition"
45%token TOK_REQUIRES "requires"
46%token TOK_AUTO "auto"
47%token TOK_CONFIG "config"
48%token TOK_DISPLAY "display"
49%token TOK_TYPE "type"
50%token TOK_INT "int"
51%token TOK_FLOAT "float"
52%token TOK_BOOL "boolean"
53%token TOK_VERSION "version"
54%token TOK_STRING "string"
55%token TOK_DEFAULT "default"
56%token TOK_ALLOW "allow"
57%token TOK_RULE "rule"
58%token TOK_ACTION "action"
59%token TOK_PROFILE "profile"
60%token TOK_IF "if"
61%token TOK_THEN "then"
62%token TOK_ELSE "else"
63%token TOK_INCLUDE "include"
64%token TOK_ERROR "error"
65%token TOK_WARNING "warning"
66%token TOK_NOTICE "notice"
67%token TOK_CACHE "cache"
68%token TOK_ALWAYS "always"
69%token TOK_NEVER "never"
70%token TOK_GLOBAL "global"
71%token TOK_LOCAL "local"
72%token TOK_FOR "for"
73%token TOK_IN "in"
74%token TOK_DO "do"
75%token TOK_RETURN "return"
76%token TOK_FUNCTION "function"
77%token TOK_CONTINUE "continue"
78%token TOK_BREAK "break"
79%token TOK_VALUE "value"
80%token TOK_ALL "all"
81%token TOK_EXPORT "export"
82%token TOK_TAG "tag"
83%token TOK_NULL "null"
84
85%token OP_ADDSETP "+="
86%token OP_ADDSETR "<<"
87%token OP_CMPEQUAL "=="
88%token OP_INEQUAL "!="
89%token OP_LTEQUAL "<="
90%token OP_GTEQUAL ">="
91
92%token '(' ')' '{' '}' '[' ']' ',' ';' '=' '.' '<' '>' '+' '-' '*' '/'
93
94%right '=' OP_ADDSETP OPADDSETR
95%left OP_CMPEQUAL '<' '>' OP_INEQUAL OP_LTEQUAL OP_GTEQUAL '+' '-' '*' '/'
96%left '(' ')' '{' '}' '[' ']'
97%left IINEG IINOT
98
99%destructor { delete[] $$; } STRING
100%destructor { delete[] $$; } KEYWORD
101%destructor { delete[] $$; } CONDITION
102%destructor { delete[] $$; } VARIABLE
103%destructor { delete[] $$; } FUNCTION
104%destructor { delete[] $$; } UNDEF
105%destructor { delete[] $$; } PROFILE
106
107%% /* Grammar rules */
108
109/*
110 * root stuff
111 */
112
113root:
114// | root set
115 | root line_expr
116 | root unset
117 | root target
118 | root rule
119 | root config
120 | root root_if
121 | root root_for
122 | root include
123 | root notify
124 | root export
125 | root function_def
126 | root action_def
127 ;
128
129root_sub_exprs:
130// | root set
131 | root line_expr
132 | root unset
133 | root target
134 | root rule
135 | root config
136 | root root_if
137 | root root_for
138 | root include
139 | root notify
140 | root export
141 ;
142
143include: TOK_INCLUDE STRING ';' { bld.include( $2, yyscanner, &yylloc ); }
144 ;
145
146/*
147 * data related
148 */
149
150string: STRING { bld.xAst.addNode( AstNode::typeString, $1 ); }
151 ;
152
153int: INT { bld.xAst.addNode( AstNode::typeInt, $1 ); }
154 ;
155
156float: FLOAT { bld.xAst.addNode( AstNode::typeFloat, $1 ); }
157 ;
158
159bool: BOOL { bld.xAst.addNode( AstNode::typeBool, (bool)$1 ); }
160 ;
161
162null: TOK_NULL { bld.xAst.addNode( AstNode::typeNull ); }
163
164literal: string
165 | int
166 | float
167 | bool
168 | null
169 ;
170
171variable: UNDEF /*VARIABLE*/ { bld.xAst.addNode( AstNode::typeVariable, $1 ); }
172
173list_core:
174 | { bld.xAst.openBranch(); } expr
175 | list_core ',' { bld.xAst.openBranch(); } expr
176 ;
177
178list: '[' {
179 bld.xAst.addNode( AstNode::typeList );
180 } list_core ']' {
181 bld.xAst.closeNode();
182 }
183 ;
184
185value_mods:
186 | value_mods '.' function
187 ;
188
189value_core: variable
190 | literal
191 | function
192 | list
193 ;
194
195value: value_core value_mods
196 ;
197
198/*
199 * misc global things
200 */
201
202notify: TOK_ERROR STRING ';' { bld.xAst.addNode( AstNode::typeError, $2 ); }
203 | TOK_WARNING STRING ';' { bld.xAst.addNode( AstNode::typeWarning, $2 ); }
204 | TOK_NOTICE STRING ';' { bld.xAst.addNode( AstNode::typeNotice, $2 ); }
205 ;
206/*
207set_rhs: '=' { bld.xAst.addNode( AstNode::typeOpEq ); } value
208 | OP_ADDSETP { bld.xAst.addNode( AstNode::typeOpPlusEq ); } value
209 | OP_ADDSETR { bld.xAst.addNode( AstNode::typeOpPlusEqRaw ); } string
210 ;
211
212set: TOK_SET {
213 bld.xAst.addNode( AstNode::typeSet );
214 bld.xAst.openBranch();
215 } variable set_rhs ';' {
216 bld.xAst.closeNode();
217 }
218 ;*/
219
220unset: TOK_UNSET {
221 bld.xAst.addNode( AstNode::typeUnset );
222 bld.xAst.openBranch();
223 } variable ';' {
224 bld.xAst.closeNode();
225 }
226 ;
227
228export_rhs: '=' value
229 |
230 ;
231
232export: TOK_EXPORT {
233 bld.xAst.addNode( AstNode::typeExport );
234 bld.xAst.openBranch();
235 } variable export_rhs ';' {
236 bld.xAst.closeNode();
237 }
238 ;
239
240func_params:
241 | func_param_list
242 ;
243
244func_param_list: { bld.xAst.openBranch(); } value
245 | func_param_list ',' { bld.xAst.openBranch(); } value
246 ;
247
248function: UNDEF '(' {
249 bld.xAst.addNode( AstNode::typeFunction );
250 bld.xAst.openBranch();
251 bld.xAst.addNode( AstNode::typeString, $1 );
252 } func_params ')' {
253 bld.xAst.closeNode();
254 }
255 ;
256
257requires: TOK_REQUIRES {
258 bld.xAst.addNode( AstNode::typeRequires );
259 bld.xAst.openBranch();
260 } value ';' {
261 bld.xAst.closeNode();
262 }
263 ;
264
265type: TOK_STRING { bld.xAst.addNode( AstNode::typeTypeString ); }
266 | TOK_INT { bld.xAst.addNode( AstNode::typeTypeInt ); }
267 | TOK_FLOAT { bld.xAst.addNode( AstNode::typeTypeFloat ); }
268 | TOK_BOOL { bld.xAst.addNode( AstNode::typeTypeBool ); }
269 | TOK_VERSION { bld.xAst.addNode( AstNode::typeTypeVersion ); }
270 ;
271
272/*
273 * comparisons
274 */
275
276expr: value
277 | '(' expr ')'
278 | UNDEF '=' {
279 bld.xAst.addNode( AstNode::typeVariableRef, $1 );
280 } expr {
281 bld.xAst.addNode( AstNode::typeOpEq );
282 }
283 | UNDEF OP_ADDSETP {
284 bld.xAst.addNode( AstNode::typeVariableRef, $1 );
285 } expr {
286 bld.xAst.addNode( AstNode::typeOpPlusEq );
287 }
288 | expr OP_CMPEQUAL expr
289 {
290 bld.xAst.addNode( AstNode::typeCmpEq );
291 }
292 | expr '<' expr
293 {
294 bld.xAst.addNode( AstNode::typeCmpLt );
295 }
296 | expr '>' expr
297 {
298 bld.xAst.addNode( AstNode::typeCmpGt );
299 }
300 | expr OP_INEQUAL expr
301 {
302 bld.xAst.addNode( AstNode::typeCmpNe );
303 }
304 | expr OP_LTEQUAL expr
305 {
306 bld.xAst.addNode( AstNode::typeCmpLtEq );
307 }
308 | expr OP_GTEQUAL expr
309 {
310 bld.xAst.addNode( AstNode::typeCmpGtEq );
311 }
312 | expr '+' expr
313 {
314 bld.xAst.addNode( AstNode::typeOpPlus );
315 }
316 | expr '-' expr
317 {
318 bld.xAst.addNode( AstNode::typeOpMinus );
319 }
320 | expr '*' expr
321 {
322 bld.xAst.addNode( AstNode::typeOpMultiply );
323 }
324 | expr '/' expr
325 {
326 bld.xAst.addNode( AstNode::typeOpDivide );
327 }
328 | '-' expr %prec IINEG
329 {
330 bld.xAst.addNode( AstNode::typeOpNegate );
331 }
332 | '!' expr %prec IINOT
333 {
334 bld.xAst.addNode( AstNode::typeOpNot );
335 }
336 ;
337
338line_expr: {
339 bld.xAst.addNode( AstNode::typeExpr );
340 bld.xAst.openBranch();
341 } expr ';'
342 {
343 bld.xAst.closeNode();
344 }
345 ;
346
347if_core: TOK_IF {
348 bld.xAst.addNode( AstNode::typeIf );
349 bld.xAst.openBranch();
350// bld.xAst.addNode( AstNode::typeExpr );
351// bld.xAst.openBranch();
352 } expr TOK_THEN {
353// bld.xAst.closeNode();
354 bld.xAst.openBranch();
355 }
356 ;
357
358else: TOK_ELSE { bld.xAst.openBranch(); }
359 ;
360
361root_if: if_core '{' root_sub_exprs '}' root_else { bld.xAst.closeNode(); }
362 ;
363
364root_else:
365 | else '{' root_sub_exprs '}'
366 | else root_if
367 ;
368
369target_if: if_core '{' target_exprs '}' target_else { bld.xAst.closeNode(); }
370 ;
371
372target_else:
373 | else '{' target_exprs '}'
374 | else target_if
375 ;
376
377rule_if: if_core '{' rule_exprs '}' rule_else { bld.xAst.closeNode(); }
378 ;
379
380rule_else:
381 | else '{' rule_exprs '}'
382 | else rule_if
383 ;
384
385function_if: if_core '{' function_exprs '}' function_else
386 { bld.xAst.closeNode(); }
387 ;
388
389function_else:
390 | else '{' function_exprs '}'
391 | else function_if
392 ;
393
394/*
395 * loops
396 */
397
398for_base: TOK_FOR {
399 bld.xAst.addNode( AstNode::typeFor );
400 bld.xAst.openBranch();
401 } variable TOK_IN {
402 bld.xAst.openBranch();
403 } value TOK_DO {
404 bld.xAst.openBranch();
405 }
406 ;
407
408root_for: for_base '{' root_sub_exprs '}' { bld.xAst.closeNode(); }
409 ;
410
411target_for: for_base '{' target_exprs '}' { bld.xAst.closeNode(); }
412 ;
413
414rule_for: for_base '{' rule_exprs '}' { bld.xAst.closeNode(); }
415 ;
416
417function_for: for_base '{' function_exprs '}' { bld.xAst.closeNode(); }
418 ;
419
420/*
421 * functions
422 */
423
424function_def: TOK_FUNCTION UNDEF {
425 bld.xAst.addNode( AstNode::typeFunctionDef );
426 bld.xAst.openBranch();
427 bld.xAst.addNode( AstNode::typeString, $2 );
428 bld.xAst.openBranch();
429 } '(' param_defs ')' {
430 bld.xAst.openBranch();
431 } '{' function_exprs '}' {
432 bld.xAst.closeNode();
433 }
434 ;
435
436param_defs:
437 | param_def_list
438 ;
439
440param_def_list: variable
441 | param_def_list ',' variable
442 ;
443
444function_exprs:
445// | function_exprs function ';'
446// | function_exprs set
447 | function_exprs unset
448 | function_exprs line_expr
449 | function_exprs export
450 | function_exprs notify
451 | function_exprs function_if
452 | function_exprs function_for
453 | function_exprs return
454 | function_exprs process_target
455 ;
456
457return: TOK_RETURN {
458 bld.xAst.addNode( AstNode::typeReturn );
459 bld.xAst.openBranch();
460 } expr {
461 bld.xAst.closeNode();
462 } ';'
463 ;
464
465/*
466 * Actions, they're basically functions, no parameters
467 */
468
469action_def: TOK_ACTION STRING {
470 bld.xAst.addNode( AstNode::typeActionDef );
471 bld.xAst.openBranch();
472 bld.xAst.addNode( AstNode::typeString, $2 );
473 bld.xAst.openBranch();
474 } '{' function_exprs '}' {
475 bld.xAst.closeNode();
476 }
477 ;
478
479/*
480 * profiles
481 */
482
483profile: TOK_PROFILE {
484 bld.xAst.addNode( AstNode::typeProfile );
485 bld.xAst.openBranch();
486 } string {
487 bld.xAst.openBranch();
488 } '{' profile_exprs '}' {
489 bld.xAst.closeNode();
490 } /* in-line function */
491 ;
492
493profile_exprs:
494// | profile_exprs function ';'
495// | profile_exprs set
496 | profile_exprs unset
497 | profile_exprs line_expr
498 | profile_exprs export
499 | profile_exprs notify
500 | profile_exprs function_if
501 | profile_exprs function_for
502 | profile_exprs return
503 | profile_exprs process_target
504 | profile_exprs condition
505 ;
506/*
507 * targets
508 */
509
510target: TOK_TARGET {
511 bld.xAst.addNode( AstNode::typeTarget );
512 bld.xAst.openBranch();
513 } expr {
514 bld.xAst.openBranch();
515 } '{' target_exprs '}' {
516 bld.xAst.closeNode();
517 }
518 ;
519
520target_exprs:
521// | target_exprs set
522 | target_exprs unset
523 | target_exprs line_expr
524 | target_exprs export
525 | target_exprs target_input
526 | target_exprs requires
527 | target_exprs profile
528 | target_exprs target_if
529 | target_exprs target_for
530 | target_exprs notify
531 | target_exprs target_rule
532 | target_exprs tag
533 | target_exprs display
534 ;
535
536target_input: TOK_INPUT {
537 bld.xAst.addNode( AstNode::typeInput );
538 bld.xAst.openBranch();
539 } expr ';' {
540 bld.xAst.closeNode();
541 }
542 ;
543
544target_rule: TOK_RULE {
545 bld.xAst.addNode( AstNode::typeRule );
546 bld.xAst.openBranch();
547 } string ';' {
548 bld.xAst.closeNode();
549 }
550 ;
551
552condition: TOK_CONDITION CONDITION ';' {
553 bld.xAst.addNode( AstNode::typeCondition, $2 );
554 }
555 | TOK_CONDITION TOK_ALWAYS ';'{
556 bld.xAst.addNode( AstNode::typeCondition, "always" );
557 }
558 | TOK_CONDITION TOK_NEVER ';'{
559 bld.xAst.addNode( AstNode::typeCondition, "never" );
560 }
561 ;
562
563/*
564 * rules
565 */
566
567rule: TOK_RULE {
568 bld.xAst.addNode( AstNode::typeRuleDef );
569 bld.xAst.openBranch();
570 } string {
571 bld.xAst.openBranch();
572 } '{' rule_exprs '}' {
573 bld.xAst.closeNode();
574 }
575 ;
576
577rule_exprs:
578 | rule_exprs rule_input
579 | rule_exprs output
580 | rule_exprs requires
581 | rule_exprs profile
582 | rule_exprs rule_if
583 | rule_exprs rule_for
584 | rule_exprs notify
585 | rule_exprs display
586 | rule_exprs tag
587// | rule_exprs set
588 ;
589
590rule_input_func: function
591 | STRING {
592 /* In this case, when the input is just a string,
593 lets actually turn it into a call to the matches function.
594 */
595 bld.xAst.addNode( AstNode::typeFunction );
596 bld.xAst.openBranch();
597 bld.xAst.addNode( AstNode::typeString, "matches" );
598 bld.xAst.openBranch();
599 bld.xAst.addNode( AstNode::typeString, $1 );
600 bld.xAst.closeNode();
601 }
602/* | string */
603 ;
604
605rule_input: TOK_INPUT {
606 bld.xAst.addNode( AstNode::typeInput );
607 bld.xAst.openBranch();
608 } rule_input_func ';' {
609 bld.xAst.closeNode();
610 }
611 ;
612
613output: TOK_OUTPUT {
614 bld.xAst.addNode( AstNode::typeOutput );
615 bld.xAst.openBranch();
616 } value ';' {
617 bld.xAst.closeNode();
618 }
619 ;
620
621/*
622 * config
623 */
624config: TOK_CONFIG {
625 bld.xAst.addNode( AstNode::typeConfig );
626 bld.xAst.openBranch();
627 } string {
628 bld.xAst.openBranch();
629 } '{' config_exprs '}' {
630 bld.xAst.closeNode();
631 }
632 | TOK_AUTO TOK_CONFIG {
633 bld.xAst.addNode( AstNode::typeAutoConfig );
634 bld.xAst.openBranch();
635 } string {
636 bld.xAst.openBranch();
637 } '{' config_exprs '}' {
638 bld.xAst.closeNode();
639 }
640 | TOK_GLOBAL TOK_CONFIG {
641 bld.xAst.addNode( AstNode::typeGlobalConfig );
642 bld.xAst.openBranch();
643 } string {
644 bld.xAst.openBranch();
645 } '{' config_exprs '}' {
646 bld.xAst.closeNode();
647 }
648 ;
649
650config_exprs:
651 | config_exprs display
652 | config_exprs config_type
653 | config_exprs default
654 | config_exprs value_key
655 | config_exprs allow
656 | config_exprs cache
657 ;
658
659display: TOK_DISPLAY STRING ';' {
660 bld.xAst.addNode( AstNode::typeDisplay, $2 );
661 }
662 ;
663
664config_type: TOK_TYPE {
665 bld.xAst.addNode( AstNode::typeType );
666 bld.xAst.openBranch();
667 } type ';' {
668 bld.xAst.closeNode();
669 }
670 ;
671
672default: TOK_DEFAULT {
673 bld.xAst.addNode( AstNode::typeDefault );
674 bld.xAst.openBranch();
675 } literal ';' {
676 bld.xAst.closeNode();
677 }
678 ;
679
680value_key_val: value ';'
681 | '{' function_exprs '}' /* inline function */
682
683value_key: TOK_VALUE {
684 bld.xAst.addNode( AstNode::typeValue );
685 bld.xAst.openBranch();
686 } value_key_val {
687 bld.xAst.closeNode();
688 }
689 ;
690
691allow: TOK_ALLOW {
692 bld.xAst.addNode( AstNode::typeAllow );
693 bld.xAst.openBranch();
694 } value ';' {
695 bld.xAst.closeNode();
696 }
697 ;
698
699cache: TOK_CACHE TOK_ALWAYS ';'
700 { bld.xAst.addNode( AstNode::typeCache, true ); }
701 | TOK_CACHE TOK_NEVER ';'
702 { bld.xAst.addNode( AstNode::typeCache, false ); }
703 ;
704
705/*
706 * target/profile execute
707 */
708process_target: PROFILE
709 {
710 bld.xAst.addNode( AstNode::typeProcessTarget );
711 bld.xAst.openBranch();
712 bld.xAst.addNode( AstNode::typeString, $1 );
713 bld.xAst.openBranch();
714 } value ';' {
715 bld.xAst.closeNode();
716 }
717 ;
718
719tag: TOK_TAG
720 {
721 bld.xAst.addNode( AstNode::typeTag );
722 bld.xAst.openBranch();
723 } value ';' {
724 bld.xAst.closeNode();
725 }
726 ;
727
728
729%%
730
731/* Epilogue -- whatever you want, functions mainly */
732
733void build_error( YYLTYPE *locp, yyscan_t, BuildParser &bld, const char *msg )
734{
735 bld.error(
736 locp->first_line, locp->last_line,
737 locp->first_column, locp->last_column,
738 msg
739 );
740}
741
diff --git a/src/buildparser.cpp b/src/buildparser.cpp
new file mode 100644
index 0000000..e391523
--- /dev/null
+++ b/src/buildparser.cpp
@@ -0,0 +1,127 @@
1#include "buildparser.h"
2#include "ast.h"
3#include "build.yy.h"
4
5#include "bu/sio.h"
6using Bu::sio;
7
8BuildParser::BuildParser( Ast &rAst ) :
9 xAst( rAst )
10{
11 lIncludePaths.append("./");
12}
13
14BuildParser::~BuildParser()
15{
16}
17
18int build_parse( yyscan_t yyscanner, BuildParser &bld );
19
20void BuildParser::load( const Bu::FString &sFile )
21{
22 yyscan_t scanner;
23
24 sFilename.push( sFile );
25 FILE *fIn = fopen( sFile.getStr(), "rt" );
26 build_lex_init( &scanner );
27 // build_set_debug( true, scanner );
28 build_set_in( fIn, scanner );
29
30 build_parse( scanner, *this );
31
32 build_lex_destroy( scanner );
33 fclose( fIn );
34
35 // Bu::sio << xAst;
36}
37
38bool BuildParser::isKeyword( const Bu::FString &sStr )
39{
40 if( sStr == "important" )
41 return true;
42 if( sStr == "normal" )
43 return true;
44 if( sStr == "hidden" )
45 return true;
46 if( sStr == "autogenerated" )
47 return true;
48 return false;
49}
50
51bool BuildParser::isCond( const Bu::FString &sStr )
52{
53 if( sStr == "filetime" )
54 return true;
55 if( sStr == "always" )
56 return true;
57 if( sStr == "never" )
58 return true;
59 return false;
60}
61
62void BuildParser::include( const Bu::FString &sStr, void *scanner, YYLTYPE *loc )
63{
64 for( StrList::iterator pi = lIncludePaths.begin(); pi; pi++ )
65 {
66 FILE *fIn = fopen( (*pi + sStr).getStr(), "rt" );
67 if( fIn == NULL )
68 {
69 continue;
70 }
71 sFilename.push( sStr );
72 sLocation.push( *loc );
73 loc->first_line = loc->last_line = 1;
74 loc->first_column = loc->last_column = 0;
75 build_push_buffer_state(
76 build__create_buffer( fIn, YY_READ_BUF_SIZE, scanner ),
77 scanner
78 );
79 Bu::FString::const_iterator i = sStr.find('/');
80 if( i )
81 {
82 for(;;)
83 {
84 Bu::FString::const_iterator j = i.find('/');
85 if( !j )
86 break;
87 i = j+1;
88 }
89 sio << "Hey, found it from here: " << sStr.getSubStr( sStr.begin(), i ) << sio.nl;
90 xAst.addNode( AstNode::typePushPrefix, sStr.getSubStr( sStr.begin(), i ) );
91 }
92 else
93 {
94 xAst.addNode( AstNode::typePushPrefix, "" );
95 }
96 return;
97 }
98 Bu::FString msg("Could not open include file: ");
99 msg += sStr;
100 error(
101 loc->first_line, loc->last_line,
102 loc->first_column, loc->last_column,
103 msg
104 );
105}
106
107void BuildParser::endInclude( YYLTYPE *loc )
108{
109 sFilename.pop();
110 memcpy( loc, &sLocation.peek(), sizeof(YYLTYPE) );
111 sLocation.pop();
112 xAst.addNode( AstNode::typePopPrefix );
113}
114
115void BuildParser::error( int iLine1, int iLine2, int iCol1, int iCol2,
116 const Bu::FString &sMsg )
117{
118 throw Bu::ExceptionBase("%s: %d-%d:%d-%d: %s",
119 sFilename.peek().getStr(), iLine1, iLine2, iCol1, iCol2, sMsg.getStr()
120 );
121}
122
123void BuildParser::addIncludePath( const Bu::FString &sPath )
124{
125 lIncludePaths.append( sPath + "/" );
126}
127
diff --git a/src/buildparser.h b/src/buildparser.h
new file mode 100644
index 0000000..8e2af6c
--- /dev/null
+++ b/src/buildparser.h
@@ -0,0 +1,40 @@
1#ifndef BUILD_PARSER_H
2#define BUILD_PARSER_H
3
4#include "build.tab.h"
5
6#include "bu/stack.h"
7#include "bu/fstring.h"
8#include "types.h"
9
10class BuildParser
11{
12public:
13 BuildParser( class Ast &rAst );
14 virtual ~BuildParser();
15
16 void load( const Bu::FString &sFile );
17
18 bool isKeyword( const Bu::FString &sStr );
19 bool isCond( const Bu::FString &sStr );
20 void include( const Bu::FString &sStr, void *scanner, YYLTYPE *loc );
21 void endInclude( YYLTYPE *loc );
22
23 void error( int iLine1, int iLine2, int iCol1, int iCol2,
24 const Bu::FString &sMsg );
25
26 class Ast &xAst;
27
28 void addIncludePath( const Bu::FString &sPath );
29
30private:
31 Bu::Stack<Bu::FString> sFilename;
32 Bu::Stack<YYLTYPE> sLocation;
33 StrList lIncludePaths;
34};
35
36typedef void * yyscan_t;
37#define YY_DECL int build_lex( YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner, BuildParser &b )
38YY_DECL;
39
40#endif
diff --git a/src/condition.cpp b/src/condition.cpp
new file mode 100644
index 0000000..ec87c0e
--- /dev/null
+++ b/src/condition.cpp
@@ -0,0 +1,10 @@
1#include "condition.h"
2
3Condition::Condition()
4{
5}
6
7Condition::~Condition()
8{
9}
10
diff --git a/src/condition.h b/src/condition.h
new file mode 100644
index 0000000..2e9b26a
--- /dev/null
+++ b/src/condition.h
@@ -0,0 +1,16 @@
1#ifndef CONDITION_H
2#define CONDITION_H
3
4class Condition
5{
6public:
7 Condition();
8 virtual ~Condition();
9
10 virtual bool shouldExec( class Runner &r, class Target &rTarget )=0;
11 virtual Condition *clone()=0;
12
13private:
14};
15
16#endif
diff --git a/src/conditionalways.cpp b/src/conditionalways.cpp
new file mode 100644
index 0000000..077b5b5
--- /dev/null
+++ b/src/conditionalways.cpp
@@ -0,0 +1,21 @@
1#include "conditionalways.h"
2#include "target.h"
3
4ConditionAlways::ConditionAlways()
5{
6}
7
8ConditionAlways::~ConditionAlways()
9{
10}
11
12bool ConditionAlways::shouldExec( class Runner &/*r*/, Target &/*rTarget*/ )
13{
14 return true;
15}
16
17Condition *ConditionAlways::clone()
18{
19 return new ConditionAlways();
20}
21
diff --git a/src/conditionalways.h b/src/conditionalways.h
new file mode 100644
index 0000000..1eeeb71
--- /dev/null
+++ b/src/conditionalways.h
@@ -0,0 +1,16 @@
1#ifndef CONDITION_ALWAYS_H
2#define CONDITION_ALWAYS_H
3
4#include "condition.h"
5
6class ConditionAlways : public Condition
7{
8public:
9 ConditionAlways();
10 virtual ~ConditionAlways();
11
12 virtual bool shouldExec( class Runner &r, class Target &rTarget );
13 virtual Condition *clone();
14};
15
16#endif
diff --git a/src/conditionfiletime.cpp b/src/conditionfiletime.cpp
new file mode 100644
index 0000000..224caf1
--- /dev/null
+++ b/src/conditionfiletime.cpp
@@ -0,0 +1,73 @@
1#include "conditionfiletime.h"
2#include "target.h"
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <unistd.h>
7
8#include <bu/sio.h>
9using namespace Bu;
10
11ConditionFileTime::ConditionFileTime()
12{
13}
14
15ConditionFileTime::~ConditionFileTime()
16{
17}
18
19bool ConditionFileTime::shouldExec( class Runner &r, Target &rTarget )
20{
21 for( StrList::const_iterator j = rTarget.getOutputList().begin(); j; j++ )
22 {
23 if( access( (*j).getStr(), F_OK ) )
24 {
25 //sio << "-- Target processed because '" << *j << "' doesn't exist."
26 // << sio.nl;
27 // Output doesn't exist
28 return true;
29 }
30 }
31
32 time_t tOut = 0;
33 struct stat s;
34 for( StrList::const_iterator j = rTarget.getOutputList().begin();
35 j; j++ )
36 {
37 stat( (*j).getStr(), &s );
38 if( tOut == 0 || tOut > s.st_mtime )
39 {
40 tOut = s.st_mtime;
41 }
42 }
43 for( StrList::const_iterator j = rTarget.getInputList().begin();
44 j; j++ )
45 {
46 stat( (*j).getStr(), &s );
47 if( tOut < s.st_mtime )
48 {
49 //sio << "-- Target processed because '" << *j
50 // << "' is newer than output." << sio.nl;
51 return true;
52 }
53 }
54 rTarget.buildRequires( r );
55 for( StrList::const_iterator j = rTarget.getRequiresList().begin();
56 j; j++ )
57 {
58 stat( (*j).getStr(), &s );
59 if( tOut < s.st_mtime )
60 {
61 //sio << "-- Target processed because '" << *j
62 // << "' is newer than output." << sio.nl;
63 return true;
64 }
65 }
66 return false;
67}
68
69Condition *ConditionFileTime::clone()
70{
71 return new ConditionFileTime();
72}
73
diff --git a/src/conditionfiletime.h b/src/conditionfiletime.h
new file mode 100644
index 0000000..6fb2e9d
--- /dev/null
+++ b/src/conditionfiletime.h
@@ -0,0 +1,16 @@
1#ifndef CONDITION_FILE_TIME_H
2#define CONDITION_FILE_TIME_H
3
4#include "condition.h"
5
6class ConditionFileTime : public Condition
7{
8public:
9 ConditionFileTime();
10 virtual ~ConditionFileTime();
11
12 virtual bool shouldExec( class Runner &r, class Target &rTarget );
13 virtual Condition *clone();
14};
15
16#endif
diff --git a/src/conditionnever.cpp b/src/conditionnever.cpp
new file mode 100644
index 0000000..1ab4375
--- /dev/null
+++ b/src/conditionnever.cpp
@@ -0,0 +1,21 @@
1#include "conditionnever.h"
2#include "target.h"
3
4ConditionNever::ConditionNever()
5{
6}
7
8ConditionNever::~ConditionNever()
9{
10}
11
12bool ConditionNever::shouldExec( class Runner &/*r*/, Target &/*rTarget*/ )
13{
14 return false;
15}
16
17Condition *ConditionNever::clone()
18{
19 return new ConditionNever();
20}
21
diff --git a/src/conditionnever.h b/src/conditionnever.h
new file mode 100644
index 0000000..b7e5e92
--- /dev/null
+++ b/src/conditionnever.h
@@ -0,0 +1,16 @@
1#ifndef CONDITION_NEVER_H
2#define CONDITION_NEVER_H
3
4#include "condition.h"
5
6class ConditionNever : public Condition
7{
8public:
9 ConditionNever();
10 virtual ~ConditionNever();
11
12 virtual bool shouldExec( class Runner &r, class Target &rTarget );
13 virtual Condition *clone();
14};
15
16#endif
diff --git a/src/context.cpp b/src/context.cpp
new file mode 100644
index 0000000..c257a75
--- /dev/null
+++ b/src/context.cpp
@@ -0,0 +1,524 @@
1#include "context.h"
2#include "target.h"
3#include "rule.h"
4#include "function.h"
5#include "runner.h"
6#include "action.h"
7#include "profile.h"
8#include "view.h"
9
10#include "functionreplace.h"
11#include "functionexists.h"
12#include "functionfiles.h"
13#include "functionexecute.h"
14#include "functionmatches.h"
15#include "functiontostring.h"
16#include "functionunlink.h"
17#include "functiontargets.h"
18#include "functiondirs.h"
19#include "functiongetmakedeps.h"
20#include "functionfilename.h"
21#include "functiondirname.h"
22
23#include <bu/process.h>
24#include <bu/sio.h>
25using namespace Bu;
26
27Context::Context() :
28 pView( NULL )
29{
30 addFunction( new FunctionReplace() );
31 addFunction( new FunctionExists() );
32 addFunction( new FunctionFiles() );
33 addFunction( new FunctionExecute() );
34 addFunction( new FunctionMatches() );
35 addFunction( new FunctionToString() );
36 addFunction( new FunctionUnlink() );
37 addFunction( new FunctionTargets() );
38 addFunction( new FunctionDirs() );
39 addFunction( new FunctionGetMakeDeps() );
40 addFunction( new FunctionFileName() );
41 addFunction( new FunctionDirName() );
42 pushScope();
43}
44
45Context::~Context()
46{
47}
48
49void Context::addTarget( Target *pTarget )
50{
51 for( StrList::const_iterator i = pTarget->getOutputList().begin(); i; i++ )
52 {
53 hTarget.insert( (*i).getStr(), pTarget );
54 }
55}
56
57void Context::addRule( Rule *pRule )
58{
59 hRule.insert( pRule->getName(), pRule );
60}
61
62void Context::addFunction( Function *pFunction )
63{
64 pFunction->setContext( this );
65 hFunction.insert( pFunction->getName(), pFunction );
66}
67
68void Context::addVariable( const Bu::FString &sName, const Variable &vValue )
69{
70 for( ScopeStack::iterator i = sVars.begin(); i; i++ )
71 {
72 if( (*i).has( sName ) )
73 {
74// sio << "Replacing higher scope variable \"" << sName << "\" with value \"" << (*i).get( sName ) << "\" with new value \"" << vValue << "\"" << sio.nl;
75 (*i).insert( sName, vValue );
76 return;
77 }
78 }
79 sVars.first().insert( sName, vValue );
80}
81
82void Context::addAction( Action *pAction )
83{
84 hAction.insert( pAction->getName(), pAction );
85}
86
87Action *Context::getAction( const Bu::FString &sName )
88{
89 return hAction.get( sName );
90}
91
92void Context::addTargetToTag( Target *pTarget, const Bu::FString &sTag )
93{
94 if( !hTag.has( sTag ) )
95 {
96 hTag.insert( sTag, TargetList() );
97 }
98 hTag.get( sTag ).append( pTarget );
99}
100
101void Context::addTargetToTags( Target *pTarget, const StrList &sTags )
102{
103 for( StrList::const_iterator i = sTags.begin(); i; i++ )
104 {
105 addTargetToTag( pTarget, *i );
106 }
107}
108
109TargetList &Context::getTag( const Bu::FString &sTag )
110{
111 return hTag.get( sTag );
112}
113
114Variable &Context::getVariable( const Bu::FString &sName )
115{
116 for( ScopeStack::iterator i = sVars.begin(); i; i++ )
117 {
118 if( (*i).has( sName ) )
119 {
120 return (*i).get( sName );
121 }
122 }
123 throw Bu::ExceptionBase("No such variable.");
124}
125
126void Context::delVariable( const Bu::FString &sName )
127{
128 for( ScopeStack::iterator i = sVars.begin(); i; i++ )
129 {
130 if( (*i).has( sName ) )
131 {
132 (*i).erase( sName );
133 }
134 }
135}
136
137void Context::pushScope()
138{
139 VarHash h;
140 if( !sVars.isEmpty() )
141 h = sVars.peek();
142 sVars.push( h );
143}
144
145void Context::pushScope( const VarHash &hNewVars )
146{
147 VarHash h = hNewVars;
148 if( !sVars.isEmpty() )
149 {
150 for( VarHash::iterator i = sVars.peek().begin(); i; i++ )
151 {
152 if( !h.has( i.getKey() ) )
153 h.insert( i.getKey(), i.getValue() );
154 }
155 }
156 sVars.push( h );
157}
158
159VarHash &Context::getScope()
160{
161 return sVars.first();
162}
163
164void Context::popScope()
165{
166 sVars.pop();
167}
168
169Variable Context::call( const Bu::FString &sName, Variable &input,
170 VarList lParams )
171{
172 if( !hFunction.has( sName ) )
173 {
174 throw Bu::ExceptionBase("Unknown function called: %s", sName.getStr() );
175 }
176 return hFunction.get( sName )->call( input, lParams );
177}
178
179#include <bu/sio.h>
180using namespace Bu;
181Bu::FString Context::expand( const Bu::FString &sInS )
182{
183 Bu::FString sRet;
184 Bu::FString sIn = sInS;
185
186 for( int iPass = 0; iPass < 2; iPass++ )
187 {
188 Bu::FString::const_iterator b = sIn.begin();
189 sRet.clear();
190 for(;;)
191 {
192 Bu::FString::const_iterator e = b.find('$');
193 if( !e )
194 {
195 sRet.append( b );
196 break;
197 }
198 sRet.append( b, e );
199 b = e+1;
200 if( !b )
201 {
202 sRet.append('$');
203 }
204 else if( *b == '{' )
205 {
206 b++;
207 e = b.find('}');
208 Bu::FString sVar( b, e );
209 try
210 {
211 sRet.append( getVariable( sVar ).toString() );
212 } catch(...)
213 {
214 // TODO: This may be handy debugging later...
215 //sio << "No variable named " << sVar << sio.nl;
216 //sio << "Vars: " << sVars << sio.nl << sio.nl;
217 }
218 b = e+1;
219 }
220 else if( *b == '(' && iPass == 1 )
221 {
222 b++;
223 e = b.find(')');
224 Bu::FString sCmd( b, e );
225 Bu::FString sBuf;
226 try
227 {
228 //sio << "Executing command: >>>" << sCmd << "<<<" << sio.nl;
229 Process p( Process::StdOut, "/bin/bash", "/bin/bash", "-c", sCmd.getStr(), NULL );
230 while( p.isRunning() )
231 {
232 char buf[4096];
233 sBuf.append( buf, p.read( buf, 4096 ) );
234 }
235 sRet.append( sBuf );
236 } catch(...)
237 {
238 // TODO: This may be handy debugging later...
239 //sio << "No variable named " << sVar << sio.nl;
240 //sio << "Vars: " << sVars << sio.nl << sio.nl;
241 }
242 b = e+1;
243 }
244 else
245 {
246 // Not a match, uh, just output the $ for now...
247 sRet.append('$');
248 }
249 }
250
251 sIn = sRet;
252 }
253 return sRet;
254}
255
256Target *Context::getTarget( const Bu::FString &sOutput )
257{
258 return hTarget.get( sOutput );
259}
260
261TargetList Context::getExplicitTargets()
262{
263 TargetList lRet;
264 for( TargetHash::iterator i = hTarget.begin(); i; i++ )
265 {
266 if( (*i)->isExplicit() )
267 lRet.append( *i );
268 }
269 return lRet;
270}
271
272void Context::buildTargetTree( Runner &r )
273{
274 TargetList lTargets = hTarget.getValues();
275
276 for( TargetList::iterator i = lTargets.begin(); i; i++ )
277 {
278 // I believe we only want to autogenerate targets for explicit targets
279 // that have rules defined.
280 if( !(*i)->isExplicit() || !(*i)->hasRule() )
281 continue;
282
283 StrList lNewIns; // The new "changed" inputs for this target
284
285 Rule *pMaster = hRule.get( (*i)->getRule() );
286
287 for( StrList::const_iterator j = (*i)->getInputList().begin(); j; j++ )
288 {
289 if( pMaster->ruleMatches( r, *j ) )
290 {
291 lNewIns.append( *j );
292 }
293
294 if( hTarget.has( *j ) )
295 {
296 // Find the existing dependancy
297 lNewIns.append( *j );
298 }
299 //else
300 //{
301 buildTargetTree( r, *i, *j, pMaster, lNewIns );
302 //}
303 }
304
305 pMaster->prepTarget( *i );
306 (*i)->resetInputList( lNewIns );
307 }
308 //sio << "Building dependancies: " << Fmt(3) << 0 << "%\r" << sio.flush;
309 //int iSize = hTarget.getSize(), iCur = 0;
310 for( TargetHash::iterator i = hTarget.begin(); i; i++ )
311 {
312 // Before we can take a look at the requirements, we need to build
313 // them...
314 // (*i)->buildRequires( r );
315
316 // For every target we have to examine both it's inputs and it's
317 // additional requirements. Inputs first
318 StrList lDeps( (*i)->getInputList() );
319 lDeps += (*i)->getRequiresList();
320 for( StrList::const_iterator j = lDeps.begin(); j; j++ )
321 {
322 try
323 {
324 (*i)->addDep( hTarget.get( *j ) );
325 }
326 catch(...)
327 {
328 }
329 }
330 //iCur++;
331 // sio << "Building dependancies: " << Fmt(3) << (iCur*100/iSize) << "%\r" << sio.flush;
332 (*i)->collapseDeps();
333 }
334// sio << sio.nl;
335
336 for( TargetHash::iterator i = hTarget.begin(); i; i++ )
337 {
338 if( !(*i)->isExplicit() )
339 continue;
340 (*i)->setDepCount();
341 (*i)->resetRun( false );
342 }
343}
344
345void Context::buildTargetTree( class Runner &r, class Target * /*pTarget*/, const Bu::FString &sInput, Rule *pMaster, StrList &lNewIns )
346{
347 Target *pNewTarget = NULL;
348 for( RuleHash::iterator i = hRule.begin(); i; i++ )
349 {
350 if( (*i)->hasOutputs() && (*i)->ruleMatches( r, sInput ) )
351 {
352 pNewTarget = (*i)->createTarget( r, sInput );
353
354 Bu::Hash<ptrdiff_t, bool> hDone;
355 for( StrList::const_iterator oi =
356 pNewTarget->getOutputList().begin(); oi; oi++ )
357 {
358 try
359 {
360 Target *pOver = hTarget.get( *oi );
361 if( hDone.has( (ptrdiff_t)pOver ) )
362 continue;
363 hDone.insert( (ptrdiff_t)pOver, true );
364 if( !pOver->isExplicit() )
365 {
366 delete pNewTarget;
367 pNewTarget = pOver;
368 break;
369 }
370 pOver->mergeUnder( pNewTarget );
371 delete pNewTarget;
372// sio << "Delete: " << Fmt::ptr() << (ptrdiff_t)pNewTarget << sio.nl;
373 pNewTarget = pOver;
374 break;
375 }
376 catch(...)
377 {
378 }
379 }
380
381 // We actually want to add this either way, if the merge added new
382 // outputs, then we need to take them into account.
383 addTarget( pNewTarget );
384 addTargetToTags( pNewTarget, (*i)->getTagList() );
385
386 // We have created a new target (or not, either way, we need to
387 // check if it matches.)
388 for( StrList::const_iterator m =
389 pNewTarget->getOutputList().begin(); m; m++ )
390 {
391 // Does the new output match the master rule?
392 if( pMaster->ruleMatches( r, (*m) ) )
393 {
394 lNewIns.append( (*m) );
395
396// sio << "What?" << sio.nl;
397 // These relationships are difficult to pick up on except
398 // that one target was created by the other, I suppose.
399 // Anyway, that means that we need to add this while we
400 // can.
401// pTarget->addDep( pNewTarget );
402 }
403 // else
404 // {
405 buildTargetTree( r, pNewTarget, *m, pMaster, lNewIns );
406 // }
407 }
408
409 return;
410 }
411 }
412 if( !pNewTarget )
413 {
414 //sio << "Incomplete tree created, trying to find purpose for \""
415 // << sInput << "\"." << sio.nl;
416 return;
417 }
418}
419
420void Context::attachDefaults()
421{
422 for( TargetHash::iterator i = hTarget.begin(); i; i++ )
423 {
424 if( !(*i)->hasProfile("clean") )
425 {
426 (*i)->addProfile( Profile::genDefaultClean() );
427 }
428 }
429}
430
431void Context::genDefaultActions()
432{
433 if( !hAction.has("all") )
434 {
435 addAction( Action::genDefaultAll() );
436 }
437 if( !hAction.has("clean") )
438 {
439 addAction( Action::genDefaultClean() );
440 }
441 if( !hAction.has("default") )
442 {
443 addAction( Action::genDefaultDefault() );
444 }
445}
446
447void Context::writeTargetDot()
448{
449 Bu::Hash<ptrdiff_t, bool> hDone;
450 sio << "digraph {" << sio.nl
451 << "\trankdir=LR;" << sio.nl;
452 for( TargetHash::iterator i = hTarget.begin(); i; i++ )
453 {
454 if( hDone.has( (ptrdiff_t)*i ) )
455 continue;
456 hDone.insert( (ptrdiff_t)*i, true );
457 for( StrList::const_iterator l = (*i)->getOutputList().begin();
458 l; l++ )
459 {
460 for( StrList::const_iterator k = (*i)->getInputList().begin();
461 k; k++ )
462 {
463 sio << "\t\"" << *k << "\" -> \""
464 << *l << "\";" << sio.nl;
465 }
466 for( StrList::const_iterator k = (*i)->getRequiresList().begin();
467 k; k++ )
468 {
469 sio << "\t\"" << *k << "\" -> \""
470 << *l << "\" [color=red];" << sio.nl;
471 }
472 }
473
474 }
475 sio << "}" << sio.nl;
476}
477
478void Context::setView( View *pNewView )
479{
480 delete pView;
481 pView = pNewView;
482}
483
484View *Context::getView()
485{
486 return pView;
487}
488
489Bu::Formatter &operator<<( Bu::Formatter &f, const Context &c )
490{
491 f << "Variables: " << c.sVars << f.nl;
492 f << "Targets: " << c.hTarget << f.nl;
493 f << "Rules: " << c.hRule << f.nl;
494
495 return f;
496}
497
498void Context::printBasicInfo()
499{
500 sio << "Available actions:" << sio.nl << "\t";
501 for( ActionHash::iterator i = hAction.begin(); i; i++ )
502 {
503 if( i != hAction.begin() )
504 sio << ", ";
505 sio << i.getKey();
506 }
507
508 TargetList lTargets = getExplicitTargets();
509 sio << sio.nl << sio.nl << "Available targets:" << sio.nl << "\t";
510 for( TargetList::iterator i = lTargets.begin(); i; i++ )
511 {
512 if( i != lTargets.begin() )
513 sio << ", ";
514 for( StrList::const_iterator j = (*i)->getOutputList().begin(); j; j++ )
515 {
516 if( j != (*i)->getOutputList().begin() )
517 sio << ", ";
518 sio << (*j);
519 }
520 }
521
522 sio << sio.nl << sio.nl;
523}
524
diff --git a/src/context.h b/src/context.h
new file mode 100644
index 0000000..0d9aaff
--- /dev/null
+++ b/src/context.h
@@ -0,0 +1,101 @@
1#ifndef CONTEXT_H
2#define CONTEXT_H
3
4#include "bu/hash.h"
5#include "bu/fstring.h"
6
7#include "variable.h"
8
9class Target;
10class Rule;
11class Function;
12class Action;
13class View;
14
15class Context
16{
17 friend Bu::Formatter &operator<<( Bu::Formatter &f, const Context &c );
18public:
19 Context();
20 virtual ~Context();
21
22 void addTarget( Target *pTarget );
23 void addRule( Rule *pRule );
24 void addFunction( Function *pFunction );
25 void addVariable( const Bu::FString &sName, const Variable &vValue );
26 void addAction( Action *pAction );
27 Action *getAction( const Bu::FString &sName );
28
29 void addTargetToTag( Target *pTarget, const Bu::FString &sTag );
30 void addTargetToTags( Target *pTarget, const StrList &sTags );
31 TargetList &getTag( const Bu::FString &sTag );
32
33 Variable &getVariable( const Bu::FString &sName );
34 void delVariable( const Bu::FString &sName );
35
36 void pushScope();
37 void pushScope( const VarHash &hNewVars );
38 VarHash &getScope();
39 void popScope();
40
41 Variable call( const Bu::FString &sName, Variable &input, VarList lParams );
42
43 Bu::FString expand( const Bu::FString &sIn );
44
45 Target *getTarget( const Bu::FString &sOutput );
46 TargetList getExplicitTargets();
47
48 /**
49 * This function actually builds the dependancy tree, and is responsible
50 * for creating all of the auto-generated targets that are required by the
51 * explicitly created targets.
52 */
53 void buildTargetTree( class Runner &r );
54
55 /**
56 * This is done as a final step, it goes through all targets and
57 * attaches things that they should have even if they haven't defined them,
58 * like a clean profile, they'll get that even if they haven't added one of
59 * their own. The defaults in this routine are added only if they aren't
60 * already defined in the target. It should be excetued after
61 * buildTargetTree, which means it doesn't need to affect rules.
62 */
63 void attachDefaults();
64
65 /**
66 * This function generates some default actions if they don't already
67 * exist, pretty straight forward, it will create all, clean, and default
68 * (default is the same as all).
69 */
70 void genDefaultActions();
71
72 void writeTargetDot();
73
74 void setView( View *pNewView );
75 View *getView();
76
77 void printBasicInfo();
78
79private:
80 void buildTargetTree( class Runner &r, class Target *pTarget, const Bu::FString &sInput, class Rule *pMaster, StrList &lNewIns );
81
82private:
83 typedef Bu::Hash<Bu::FString, Target *> TargetHash;
84 typedef Bu::Hash<Bu::FString, Rule *> RuleHash;
85 typedef Bu::Hash<Bu::FString, Function *> FunctionHash;
86 typedef Bu::Hash<Bu::FString, Action *> ActionHash;
87 typedef Bu::List<VarHash> ScopeStack;
88 typedef Bu::Hash<Bu::FString, TargetList> TagHash;
89
90 TargetHash hTarget;
91 RuleHash hRule;
92 FunctionHash hFunction;
93 ScopeStack sVars;
94 ActionHash hAction;
95 TagHash hTag;
96 View *pView;
97};
98
99Bu::Formatter &operator<<( Bu::Formatter &f, const Context &c );
100
101#endif
diff --git a/src/function.cpp b/src/function.cpp
new file mode 100644
index 0000000..f73f576
--- /dev/null
+++ b/src/function.cpp
@@ -0,0 +1,16 @@
1#include "function.h"
2
3Function::Function() :
4 pContext( NULL )
5{
6}
7
8Function::~Function()
9{
10}
11
12void Function::setContext( class Context *p )
13{
14 pContext = p;
15}
16
diff --git a/src/function.h b/src/function.h
new file mode 100644
index 0000000..9573bd3
--- /dev/null
+++ b/src/function.h
@@ -0,0 +1,23 @@
1#ifndef FUNCTION_H
2#define FUNCTION_H
3
4#include "bu/fstring.h"
5#include "variable.h"
6
7class Function
8{
9public:
10 Function();
11 virtual ~Function();
12
13 virtual Bu::FString getName() const=0;
14
15 virtual Variable call( Variable &input, VarList lParams )=0;
16
17 void setContext( class Context *p );
18
19protected:
20 class Context *pContext;
21};
22
23#endif
diff --git a/src/functionast.cpp b/src/functionast.cpp
new file mode 100644
index 0000000..0d9a938
--- /dev/null
+++ b/src/functionast.cpp
@@ -0,0 +1,33 @@
1#include "functionast.h"
2#include "astbranch.h"
3#include "astleaf.h"
4#include "runner.h"
5#include "context.h"
6
7FunctionAst::FunctionAst( const AstBranch *pRoot, class Runner *pRunner ) :
8 pRoot( pRoot ),
9 pRunner( pRunner )
10{
11 sName = dynamic_cast<AstLeaf *>(
12 *(*pRoot->getBranchBegin()).begin()
13 )->getStrValue();
14}
15
16FunctionAst::~FunctionAst()
17{
18}
19
20Bu::FString FunctionAst::getName() const
21{
22 return sName;
23}
24
25Variable FunctionAst::call( Variable &input, VarList /*lParams*/ )
26{
27 pContext->pushScope();
28 pContext->addVariable("INPUT", input );
29 Variable vRet = pRunner->run( (*(pRoot->getBranchBegin()+2)).begin() );
30 pContext->popScope();
31 return vRet;
32}
33
diff --git a/src/functionast.h b/src/functionast.h
new file mode 100644
index 0000000..b971683
--- /dev/null
+++ b/src/functionast.h
@@ -0,0 +1,21 @@
1#ifndef FUNCTION_AST_H
2#define FUNCTION_AST_H
3
4#include "function.h"
5
6class FunctionAst : public Function
7{
8public:
9 FunctionAst( const class AstBranch *pRoot, class Runner *pRunner );
10 virtual ~FunctionAst();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14
15private:
16 Bu::FString sName;
17 const class AstBranch *pRoot;
18 class Runner *pRunner;
19};
20
21#endif
diff --git a/src/functiondirname.cpp b/src/functiondirname.cpp
new file mode 100644
index 0000000..e8b728b
--- /dev/null
+++ b/src/functiondirname.cpp
@@ -0,0 +1,38 @@
1#include "functiondirname.h"
2
3FunctionDirName::FunctionDirName()
4{
5}
6
7FunctionDirName::~FunctionDirName()
8{
9}
10
11Bu::FString FunctionDirName::getName() const
12{
13 return "dirName";
14}
15
16Variable FunctionDirName::call( Variable &input, VarList /*lParams*/ )
17{
18 Bu::FString sFile;
19 sFile = input.getString();
20
21 Bu::FString::const_iterator i = sFile.begin();
22 Bu::FString::const_iterator io;
23 for(;;)
24 {
25 Bu::FString::const_iterator b = i.find('/');
26 if( !b )
27 {
28 return Variable( Bu::FString( sFile.begin(), io ) );
29 }
30 io = b;
31 i = b+1;
32 if( !i )
33 {
34 return Variable( Bu::FString( sFile.begin(), io ) );
35 }
36 }
37}
38
diff --git a/src/functiondirname.h b/src/functiondirname.h
new file mode 100644
index 0000000..830a992
--- /dev/null
+++ b/src/functiondirname.h
@@ -0,0 +1,17 @@
1#ifndef FUNCTION_DIR_NAME_H
2#define FUNCTION_DIR_NAME_H
3
4#include "function.h"
5
6class FunctionDirName : public Function
7{
8public:
9 FunctionDirName();
10 virtual ~FunctionDirName();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14
15};
16
17#endif
diff --git a/src/functiondirs.cpp b/src/functiondirs.cpp
new file mode 100644
index 0000000..fb64ef3
--- /dev/null
+++ b/src/functiondirs.cpp
@@ -0,0 +1,61 @@
1#include "functiondirs.h"
2
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <glob.h>
6#include <unistd.h>
7
8FunctionDirs::FunctionDirs()
9{
10}
11
12FunctionDirs::~FunctionDirs()
13{
14}
15
16Bu::FString FunctionDirs::getName() const
17{
18 return "dirs";
19}
20
21Variable FunctionDirs::call( Variable &/*input*/, VarList lParams )
22{
23 glob_t globbuf;
24
25 int flags = 0;
26
27 for( VarList::const_iterator i = lParams.begin(); i; i++ )
28 {
29 switch( (*i).getType() )
30 {
31 case Variable::typeString:
32 glob( (*i).getString().getStr(), flags, NULL, &globbuf );
33 flags |= GLOB_APPEND;
34 break;
35
36 case Variable::typeList:
37 throw Bu::ExceptionBase("Lists not supported in glob yet.");
38 break;
39
40 default:
41 throw Bu::ExceptionBase(
42 "Cannot use a non-string or non-list as a parameter to glob"
43 );
44 break;
45 }
46 }
47
48 Variable vRet( Variable::typeList );
49 struct stat s;
50 for( size_t j = 0; j < globbuf.gl_pathc; j++ )
51 {
52 stat( globbuf.gl_pathv[j], &s );
53 if( S_ISDIR( s.st_mode ) )
54 vRet.append( globbuf.gl_pathv[j] );
55 }
56
57 globfree( &globbuf );
58
59 return vRet;
60}
61
diff --git a/src/functiondirs.h b/src/functiondirs.h
new file mode 100644
index 0000000..5edfaf9
--- /dev/null
+++ b/src/functiondirs.h
@@ -0,0 +1,17 @@
1#ifndef FUNCTION_DIRS_H
2#define FUNCTION_DIRS_H
3
4#include "function.h"
5
6class FunctionDirs : public Function
7{
8public:
9 FunctionDirs();
10 virtual ~FunctionDirs();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14
15};
16
17#endif
diff --git a/src/functionexecute.cpp b/src/functionexecute.cpp
new file mode 100644
index 0000000..619d2c2
--- /dev/null
+++ b/src/functionexecute.cpp
@@ -0,0 +1,68 @@
1#include "functionexecute.h"
2#include "context.h"
3#include "view.h"
4
5#include <bu/sio.h>
6#include <bu/process.h>
7using namespace Bu;
8
9FunctionExecute::FunctionExecute()
10{
11}
12
13FunctionExecute::~FunctionExecute()
14{
15}
16
17Bu::FString FunctionExecute::getName() const
18{
19 return "execute";
20}
21
22Variable FunctionExecute::call( Variable &/*input*/, VarList lParams )
23{
24 // TODO This is lame, really lame, we need to exec on our own and process
25 // output appropriately.
26 pContext->getView()->cmdStarted( lParams.first().getString() );
27 Process pCmd( Process::Both, "/bin/bash", "/bin/bash", "-c",
28 lParams.first().getString().getStr(), NULL );
29 FString sStdOut, sStdErr;
30 while( pCmd.isRunning() )
31 {
32 char buf[4096];
33 bool out, err;
34 pCmd.select( out, err );
35 if( err )
36 {
37 int iRead = pCmd.readErr( buf, 4096 );
38 sStdErr.append( buf, iRead );
39 //sio << "Read " << iRead << " bytes of stderr." << sio.nl;
40 }
41 if( out )
42 {
43 int iRead = pCmd.read( buf, 4096 );
44 sStdOut.append( buf, iRead );
45 //sio << "Read " << iRead << " bytes of stdout." << sio.nl;
46 }
47 }
48
49 pContext->getView()->cmdFinished(
50 sStdOut, sStdErr, pCmd.childExitStatus()
51 );
52 if( pCmd.childExited() )
53 {
54 if( pCmd.childExitStatus() != 0 )
55 {
56 throw Bu::ExceptionBase("Command exited with errorcode %d.", pCmd.childExitStatus() );
57 }
58 }
59 else
60 {
61 pContext->getView()->cmdFinished(
62 sStdOut, sStdErr, pCmd.childExitStatus()
63 );
64 throw Bu::ExceptionBase("Command Failed");
65 }
66 return Variable( pCmd.childExitStatus() );
67}
68
diff --git a/src/functionexecute.h b/src/functionexecute.h
new file mode 100644
index 0000000..ebeaa7f
--- /dev/null
+++ b/src/functionexecute.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_EXECUTE_H
2#define FUNCTION_EXECUTE_H
3
4#include "function.h"
5
6class FunctionExecute : public Function
7{
8public:
9 FunctionExecute();
10 virtual ~FunctionExecute();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14};
15
16#endif
diff --git a/src/functionexists.cpp b/src/functionexists.cpp
new file mode 100644
index 0000000..d2aa9e9
--- /dev/null
+++ b/src/functionexists.cpp
@@ -0,0 +1,34 @@
1#include "functionexists.h"
2
3#include <unistd.h>
4
5FunctionExists::FunctionExists()
6{
7}
8
9FunctionExists::~FunctionExists()
10{
11}
12
13Bu::FString FunctionExists::getName() const
14{
15 return "exists";
16}
17
18Variable FunctionExists::call( Variable &input, VarList lParams )
19{
20 Bu::FString sFile;
21 if( input.getType() != Variable::typeNone )
22 {
23 sFile = input.toString();
24 }
25 else
26 {
27 sFile = lParams.first().toString();
28 }
29 if( access( sFile.getStr(), F_OK ) == 0 )
30 return Variable( true );
31 else
32 return Variable( false );
33}
34
diff --git a/src/functionexists.h b/src/functionexists.h
new file mode 100644
index 0000000..8a3001a
--- /dev/null
+++ b/src/functionexists.h
@@ -0,0 +1,17 @@
1#ifndef FUNCTION_EXISTS_H
2#define FUNCTION_EXISTS_H
3
4#include "function.h"
5
6class FunctionExists : public Function
7{
8public:
9 FunctionExists();
10 virtual ~FunctionExists();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14
15};
16
17#endif
diff --git a/src/functionfilename.cpp b/src/functionfilename.cpp
new file mode 100644
index 0000000..21a4655
--- /dev/null
+++ b/src/functionfilename.cpp
@@ -0,0 +1,36 @@
1#include "functionfilename.h"
2
3FunctionFileName::FunctionFileName()
4{
5}
6
7FunctionFileName::~FunctionFileName()
8{
9}
10
11Bu::FString FunctionFileName::getName() const
12{
13 return "fileName";
14}
15
16Variable FunctionFileName::call( Variable &input, VarList /*lParams*/ )
17{
18 Bu::FString sFile;
19 sFile = input.getString();
20
21 Bu::FString::const_iterator i = sFile.begin();
22 for(;;)
23 {
24 Bu::FString::const_iterator b = i.find('/');
25 if( !b )
26 {
27 return Variable( Bu::FString( i ) );
28 }
29 i = b+1;
30 if( !i )
31 {
32 return Variable( Bu::FString( i ) );
33 }
34 }
35}
36
diff --git a/src/functionfilename.h b/src/functionfilename.h
new file mode 100644
index 0000000..1401fc7
--- /dev/null
+++ b/src/functionfilename.h
@@ -0,0 +1,17 @@
1#ifndef FUNCTION_FILE_NAME_H
2#define FUNCTION_FILE_NAME_H
3
4#include "function.h"
5
6class FunctionFileName : public Function
7{
8public:
9 FunctionFileName();
10 virtual ~FunctionFileName();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14
15};
16
17#endif
diff --git a/src/functionfiles.cpp b/src/functionfiles.cpp
new file mode 100644
index 0000000..e708d45
--- /dev/null
+++ b/src/functionfiles.cpp
@@ -0,0 +1,61 @@
1#include "functionfiles.h"
2
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <glob.h>
6#include <unistd.h>
7
8FunctionFiles::FunctionFiles()
9{
10}
11
12FunctionFiles::~FunctionFiles()
13{
14}
15
16Bu::FString FunctionFiles::getName() const
17{
18 return "files";
19}
20
21Variable FunctionFiles::call( Variable &/*input*/, VarList lParams )
22{
23 glob_t globbuf;
24
25 int flags = 0;
26
27 for( VarList::const_iterator i = lParams.begin(); i; i++ )
28 {
29 switch( (*i).getType() )
30 {
31 case Variable::typeString:
32 glob( (*i).getString().getStr(), flags, NULL, &globbuf );
33 flags |= GLOB_APPEND;
34 break;
35
36 case Variable::typeList:
37 throw Bu::ExceptionBase("Lists not supported in glob yet.");
38 break;
39
40 default:
41 throw Bu::ExceptionBase(
42 "Cannot use a non-string or non-list as a parameter to glob"
43 );
44 break;
45 }
46 }
47
48 Variable vRet( Variable::typeList );
49 struct stat s;
50 for( size_t j = 0; j < globbuf.gl_pathc; j++ )
51 {
52 stat( globbuf.gl_pathv[j], &s );
53 if( S_ISREG( s.st_mode ) )
54 vRet.append( globbuf.gl_pathv[j] );
55 }
56
57 globfree( &globbuf );
58
59 return vRet;
60}
61
diff --git a/src/functionfiles.h b/src/functionfiles.h
new file mode 100644
index 0000000..711288a
--- /dev/null
+++ b/src/functionfiles.h
@@ -0,0 +1,17 @@
1#ifndef FUNCTION_FILES_H
2#define FUNCTION_FILES_H
3
4#include "function.h"
5
6class FunctionFiles : public Function
7{
8public:
9 FunctionFiles();
10 virtual ~FunctionFiles();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14
15};
16
17#endif
diff --git a/src/functiongetmakedeps.cpp b/src/functiongetmakedeps.cpp
new file mode 100644
index 0000000..1aded15
--- /dev/null
+++ b/src/functiongetmakedeps.cpp
@@ -0,0 +1,59 @@
1#include "functiongetmakedeps.h"
2
3#include <bu/process.h>
4#include <bu/sio.h>
5using namespace Bu;
6
7FunctionGetMakeDeps::FunctionGetMakeDeps()
8{
9}
10
11FunctionGetMakeDeps::~FunctionGetMakeDeps()
12{
13}
14
15Bu::FString FunctionGetMakeDeps::getName() const
16{
17 return "getMakeDeps";
18}
19
20Variable FunctionGetMakeDeps::call( Variable &/*input*/, VarList lParams )
21{
22 Process p( Process::StdOut, "/bin/bash", "/bin/bash", "-c",
23 lParams.first().getString().getStr(), NULL );
24
25 // Gather all data from the command.
26 Bu::FString sBuf;
27 while( !p.isEos() )
28 {
29 char buf[4096];
30 int iRead = p.read( buf, 4096 );
31 sBuf.append( buf, iRead );
32 }
33
34 Variable vRet( Variable::typeList );
35
36 Bu::FString::iterator i, j;
37 i = sBuf.find(':')+2;
38 while( i )
39 {
40 // Find whitespace at the end of the word, this one is easy, there's
41 // always a space after a word
42 for( j = i; j && *j != ' ' && *j != '\n' && *j != '\r'; j++ ) { }
43
44 Bu::FString sTmp( i, j );
45 vRet.append( sTmp );
46
47 // Find the begining of the next word, trickier, we don't want to go
48 // off the end, and we need to skip \ chars at the ends of lines, right
49 // now this is too stupid to do that, so it may not work on windows.
50 // TODO: perhaps make this only skip \ chars at the ends of lines,
51 // we'll see if it matters.
52 for( i = j+1;
53 i && (*i == ' ' || *i == '\\' || *i == '\n' || *i == '\r'); i++ )
54 { }
55 }
56
57 return vRet;
58}
59
diff --git a/src/functiongetmakedeps.h b/src/functiongetmakedeps.h
new file mode 100644
index 0000000..b8f20d5
--- /dev/null
+++ b/src/functiongetmakedeps.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_GET_MAKE_DEPS_H
2#define FUNCTION_GET_MAKE_DEPS_H
3
4#include "function.h"
5
6class FunctionGetMakeDeps : public Function
7{
8public:
9 FunctionGetMakeDeps();
10 virtual ~FunctionGetMakeDeps();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14};
15
16#endif
diff --git a/src/functionmatches.cpp b/src/functionmatches.cpp
new file mode 100644
index 0000000..4e4b7ff
--- /dev/null
+++ b/src/functionmatches.cpp
@@ -0,0 +1,141 @@
1#include "functionmatches.h"
2
3#include <unistd.h>
4
5FunctionMatches::FunctionMatches()
6{
7}
8
9FunctionMatches::~FunctionMatches()
10{
11}
12
13Bu::FString FunctionMatches::getName() const
14{
15 return "matches";
16}
17
18bool FunctionMatches::globcmp( const Bu::FString &sTxt, const Bu::FString &sMatches )
19{
20 Bu::FString::const_iterator t, g;
21 t = sTxt.begin();
22 g = sMatches.begin();
23
24 while( g && t )
25 {
26 switch( *g )
27 {
28 case '*':
29 // First, if the * is at the end, then we do match, it doesn't
30 // matter what is in sTxt
31 if( !(g+1) )
32 return true;
33 // Now attempt to scan for the remainder as a matched set
34 {
35 Bu::FString::const_iterator tn = t+1, gn = g+1, gi=g+1;
36 bool bFoundMatch = false;
37 while( tn && gn )
38 {
39 if( *gn == '*' )
40 {
41 g = gn;
42 t = tn;
43 break;
44 }
45 if( *tn == *gn )
46 {
47 g = gn;
48 t = tn;
49 tn++;
50 gn++;
51 bFoundMatch = true;
52 }
53 else
54 {
55 gn = gi;
56 tn++;
57 bFoundMatch = false;
58 }
59 }
60 if( bFoundMatch == false )
61 return false;
62 if( !tn && !gn && bFoundMatch )
63 return true;
64 }
65 break;
66
67 case '?':
68 // Don't bother checking.
69 t++;
70 g++;
71 break;
72
73 default:
74 if( *t != *g )
75 return false;
76 t++;
77 g++;
78 break;
79 }
80 }
81 if( t || (g && *g != '*') )
82 return false;
83 return true;
84}
85
86bool FunctionMatches::matchlist( const Bu::FString &sTxt, VarList &lParams )
87{
88 for( VarList::iterator i = lParams.begin(); i; i++ )
89 {
90 if( (*i).getType() == Variable::typeList )
91 {
92 for( VarList::iterator j = (*i).begin(); j; j++ )
93 {
94 if( globcmp( sTxt, (*j).toString() ) )
95 return true;
96 }
97 }
98 else
99 {
100 if( globcmp( sTxt, (*i).toString() ) )
101 return true;
102 }
103 }
104 return false;
105}
106
107Variable FunctionMatches::call( Variable &input, VarList lParams )
108{
109 switch( input.getType() )
110 {
111 case Variable::typeString:
112 {
113 Bu::FString sTxt = input.getString();
114 return Variable( matchlist( sTxt, lParams ) );
115 }
116 break;
117
118 case Variable::typeList:
119 {
120 Variable vRet( Variable::typeList );
121 for( VarList::iterator i = input.begin(); i; i++ )
122 {
123 if( (*i).getType() != Variable::typeString )
124 continue;
125 Bu::FString sTxt = (*i).getString();
126 if( matchlist( sTxt, lParams ) )
127 vRet.append( *i );
128 }
129 return vRet;
130 }
131 break;
132
133 default:
134 throw Bu::ExceptionBase("You can only use a string or list as the "
135 "input to matches.");
136 break;
137 }
138
139 return Variable();
140}
141
diff --git a/src/functionmatches.h b/src/functionmatches.h
new file mode 100644
index 0000000..7757a44
--- /dev/null
+++ b/src/functionmatches.h
@@ -0,0 +1,23 @@
1#ifndef FUNCTION_MATCHES_H
2#define FUNCTION_MATCHES_H
3
4#include "function.h"
5
6class FunctionMatches : public Function
7{
8public:
9 FunctionMatches();
10 virtual ~FunctionMatches();
11
12 /**
13 * Really basic globbing function, it doesn't handle character classes,
14 * just * and ?. We can expand on it later, it may be handy.
15 */
16 bool globcmp( const Bu::FString &sTxt, const Bu::FString &sMatches );
17 bool matchlist( const Bu::FString &sTxt, VarList &lParams );
18 virtual Bu::FString getName() const;
19 virtual Variable call( Variable &input, VarList lParams );
20
21};
22
23#endif
diff --git a/src/functionreplace.cpp b/src/functionreplace.cpp
new file mode 100644
index 0000000..d269083
--- /dev/null
+++ b/src/functionreplace.cpp
@@ -0,0 +1,47 @@
1#include "functionreplace.h"
2
3FunctionReplace::FunctionReplace()
4{
5}
6
7FunctionReplace::~FunctionReplace()
8{
9}
10
11Bu::FString FunctionReplace::getName() const
12{
13 return "replace";
14}
15
16Variable FunctionReplace::call( Variable &input, VarList lParams )
17{
18 Bu::FString sA, sB;
19 sA = lParams.first().getString();
20 sB = lParams.last().getString();
21 switch( input.getType() )
22 {
23 case Variable::typeString:
24 {
25 Variable vOut( input.getString().replace( sA, sB ) );
26 return vOut;
27 }
28 break;
29
30 case Variable::typeList:
31 {
32 Variable vOut( Variable::typeList );
33 for( VarList::iterator i = input.begin(); i; i++ )
34 {
35 vOut.append( (*i).getString().replace( sA, sB ) );
36 }
37 return vOut;
38 }
39 break;
40
41 default:
42 break;
43 }
44 throw Bu::ExceptionBase(
45 "replace does not work on non-string or non-list types.");
46}
47
diff --git a/src/functionreplace.h b/src/functionreplace.h
new file mode 100644
index 0000000..1bf4dae
--- /dev/null
+++ b/src/functionreplace.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_REPLACE_H
2#define FUNCTION_REPLACE_H
3
4#include "function.h"
5
6class FunctionReplace : public Function
7{
8public:
9 FunctionReplace();
10 virtual ~FunctionReplace();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14};
15
16#endif
diff --git a/src/functiontargets.cpp b/src/functiontargets.cpp
new file mode 100644
index 0000000..93fbb96
--- /dev/null
+++ b/src/functiontargets.cpp
@@ -0,0 +1,39 @@
1#include "functiontargets.h"
2#include "context.h"
3#include "target.h"
4
5FunctionTargets::FunctionTargets()
6{
7}
8
9FunctionTargets::~FunctionTargets()
10{
11}
12
13Bu::FString FunctionTargets::getName() const
14{
15 return "targets";
16}
17
18Variable FunctionTargets::call( Variable &/*input*/, VarList lParams )
19{
20 Variable vRet( Variable::typeList );
21 TargetList lTrg;
22 if( lParams.getSize() == 0 )
23 {
24 lTrg = pContext->getExplicitTargets();
25 }
26 else
27 {
28 lTrg = pContext->getTag( lParams.first().toString() );
29 }
30 for( TargetList::const_iterator i = lTrg.begin(); i; i++ )
31 {
32 for( StrList::const_iterator j = (*i)->getOutputList().begin(); j; j++ )
33 {
34 vRet.append( *j );
35 }
36 }
37 return vRet;
38}
39
diff --git a/src/functiontargets.h b/src/functiontargets.h
new file mode 100644
index 0000000..9b65d30
--- /dev/null
+++ b/src/functiontargets.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_TARGETS_H
2#define FUNCTION_TARGETS_H
3
4#include "function.h"
5
6class FunctionTargets : public Function
7{
8public:
9 FunctionTargets();
10 virtual ~FunctionTargets();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14};
15
16#endif
diff --git a/src/functiontostring.cpp b/src/functiontostring.cpp
new file mode 100644
index 0000000..0c04091
--- /dev/null
+++ b/src/functiontostring.cpp
@@ -0,0 +1,50 @@
1#include "functiontostring.h"
2
3#include <stdlib.h>
4#include <bu/sio.h>
5using namespace Bu;
6
7FunctionToString::FunctionToString()
8{
9}
10
11FunctionToString::~FunctionToString()
12{
13}
14
15Bu::FString FunctionToString::getName() const
16{
17 return "toString";
18}
19
20Variable FunctionToString::call( Variable &input, VarList lParams )
21{
22 Bu::FString sStr;
23 Bu::FString sSep;
24 if( lParams.getSize() == 0 )
25 {
26 sSep = " ";
27 }
28 else
29 {
30 sSep = lParams.first().getString();
31 }
32 switch( input.getType() )
33 {
34 case Variable::typeString:
35 return input;
36
37 case Variable::typeList:
38 for( VarList::iterator i = input.begin(); i; i++ )
39 {
40 if( i != input.begin() )
41 sStr += sSep;
42 sStr += (*i).getString();
43 }
44 return Variable( sStr );
45
46 default:
47 return Variable( input.getString() );
48 }
49}
50
diff --git a/src/functiontostring.h b/src/functiontostring.h
new file mode 100644
index 0000000..3c3ecc7
--- /dev/null
+++ b/src/functiontostring.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_TO_STRING_H
2#define FUNCTION_TO_STRING_H
3
4#include "function.h"
5
6class FunctionToString : public Function
7{
8public:
9 FunctionToString();
10 virtual ~FunctionToString();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14};
15
16#endif
diff --git a/src/functionunlink.cpp b/src/functionunlink.cpp
new file mode 100644
index 0000000..addcfd9
--- /dev/null
+++ b/src/functionunlink.cpp
@@ -0,0 +1,51 @@
1#include "functionunlink.h"
2
3#include <unistd.h>
4#include <stdlib.h>
5#include <bu/sio.h>
6using namespace Bu;
7
8FunctionUnlink::FunctionUnlink()
9{
10}
11
12FunctionUnlink::~FunctionUnlink()
13{
14}
15
16Bu::FString FunctionUnlink::getName() const
17{
18 return "unlink";
19}
20
21Variable FunctionUnlink::call( Variable &/*input*/, VarList lParams )
22{
23 //sio << "Unlink called: " << lParams << sio.nl;
24 for( VarList::iterator p = lParams.begin(); p; p++ )
25 {
26 switch( (*p).getType() )
27 {
28 case Variable::typeString:
29 //sio << " xx> " << (*p).getString() << sio.nl;
30 unlink( (*p).getString().getStr() );
31 break;
32
33 case Variable::typeList:
34 //sio << " xx>";
35 for( VarList::iterator i = (*p).begin(); i; i++ )
36 {
37 //sio << " " << (*i).getString();
38 unlink( (*i).getString().getStr() );
39 }
40 //sio << sio.nl;
41 break;
42
43 default:
44 throw Bu::ExceptionBase("Hey, wrong type passed.");
45 break;
46 }
47 }
48
49 return Variable();
50}
51
diff --git a/src/functionunlink.h b/src/functionunlink.h
new file mode 100644
index 0000000..ac3f21e
--- /dev/null
+++ b/src/functionunlink.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_UNLINK_H
2#define FUNCTION_UNLINK_H
3
4#include "function.h"
5
6class FunctionUnlink : public Function
7{
8public:
9 FunctionUnlink();
10 virtual ~FunctionUnlink();
11
12 virtual Bu::FString getName() const;
13 virtual Variable call( Variable &input, VarList lParams );
14};
15
16#endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..142927d
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,255 @@
1#include "buildparser.h"
2#include "context.h"
3#include "ast.h"
4#include "runner.h"
5#include "target.h"
6
7#include "viewplugger.h"
8
9#include <bu/optparser.h>
10#include <bu/sio.h>
11#include <sys/types.h>
12#include <dirent.h>
13#include <stdlib.h>
14#include <unistd.h>
15
16extern char **environ;
17
18using namespace Bu;
19
20class Options : public Bu::OptParser
21{
22public:
23 Options( int argc, char *argv[] ) :
24 sView("default"),
25 sAction("default"),
26 sConfig("default.bld"),
27 bDot( false ),
28 bDebug( false ),
29 bAutoInclude( true ),
30 bAstDump( false ),
31 bEnviron( true ),
32 iInfoLevel( 0 )
33 {
34 bool bClean = false;
35 addHelpBanner("build mark 3\n");
36
37 Bu::FString sViews("Select a view from: ");
38 StrList lViews = ViewPlugger::getInstance().getPluginList();
39 for( StrList::iterator i = lViews.begin(); i; i++ )
40 {
41 if( i != lViews.begin() )
42 sViews += ", ";
43 sViews += *i;
44 }
45
46 addHelpBanner("The following options do things other than build:");
47 addOption( iInfoLevel, 'i', "info", "Display some basic info about the "
48 "loaded build config, including available targets.");
49
50 addHelpBanner("The following options control general execution:");
51 addOption( sView, 'v', "view", sViews );
52 addOption( sConfig, 'f', "file", "Select a different config file." );
53 addOption( bClean, 'c', "Shorthand for running action 'clean'. If an "
54 "action is specified, this will modify it to run 'clean-action'.");
55 addOption( slot(this, &Options::onChdir), 'C', "chdir",
56 "Change to directory before doing anything else.");
57
58 addHelpBanner("\nThe following options control debugging:");
59 addOption( bEnviron, "no-env", "Do not import environment variables.");
60 addOption( bDot, "dot", "Generate a dot chart after execution." );
61 addOption( bDebug, "debug",
62 "Dump massive amounts of hard to read debugging data." );
63 addOption( bAstDump, "debug-ast",
64 "Display the raw AST that is computed from parsing the input. "
65 "You should probably never ever use this, it'll scare you."
66 );
67
68 setOverride( "no-env", "false" );
69 setOverride( "dot", "true" );
70 setOverride( "debug", "true" );
71 setOverride( "debug-ast", "true" );
72 setOverride( "info", "1" );
73 setOverride( 'c', "true" );
74
75 addHelpOption();
76
77 setNonOption( slot( this, &Options::onNonOption ) );
78
79 parse( argc, argv );
80
81 if( bClean )
82 {
83 if( sAction == "default" )
84 sAction = "clean";
85 else
86 sAction.prepend("clean-");
87 }
88 }
89
90 virtual ~Options()
91 {
92 }
93
94 int onChdir( StrArray sParams )
95 {
96 if( sParams.getSize() == 0 )
97 {
98 sio << "You must specify a directory name!" << sio.nl << sio.nl;
99 exit(2);
100 }
101 chdir( sParams[1].getStr() );
102 return 1;
103 }
104
105 int onNonOption( StrArray sParams )
106 {
107 sAction = sParams[0];
108 return 0;
109 }
110
111 Bu::FString sView;
112 Bu::FString sAction;
113 Bu::FString sConfig;
114 bool bDot;
115 bool bDebug;
116 bool bAutoInclude;
117 bool bAstDump;
118 bool bEnviron;
119 int iInfoLevel;
120};
121
122int main( int argc, char *argv[] )
123{
124 typedef Bu::List<Bu::FString> StrList;
125 StrList lShareList;
126 lShareList.append("/usr/share/build/").append("./share/");
127 Ast ast;
128 Context cnt;
129 BuildParser bp( ast );
130
131 for( StrList::iterator i = lShareList.begin(); i; i++ )
132 {
133 bp.addIncludePath( *i + "include");
134 }
135
136 Options opts( argc, argv );
137
138 try
139 {
140 cnt.setView( ViewPlugger::getInstance().instantiate( opts.sView ) );
141 }
142 catch( Bu::HashException &e )
143 {
144 sio << "Error: Invalid view specified, please choose from the "
145 "following choices:" << sio.nl << sio.nl << "\t";
146
147 StrList lViews = ViewPlugger::getInstance().getPluginList();
148 for( StrList::iterator i = lViews.begin(); i; i++ )
149 {
150 if( i != lViews.begin() )
151 sio << ", ";
152 sio << *i;
153 }
154 sio << sio.nl << sio.nl;
155 return 1;
156 }
157
158 // Load up the environment as vars.
159 if( opts.bEnviron )
160 {
161 for( char **env = environ; *env; env++ )
162 {
163 int iSplit;
164 for( iSplit = 0; (*env)[iSplit] != '='; iSplit++ ) { }
165 cnt.addVariable(
166 FString( *env, iSplit ),
167 FString( *env+iSplit+1 )
168 );
169 }
170 }
171
172 if( opts.bAutoInclude )
173 {
174 DIR *d;
175 Bu::FString sAutoDir;
176 for( StrList::iterator i = lShareList.begin(); i; i++ )
177 {
178 sAutoDir = *i + "autoinclude";
179 d = opendir( sAutoDir.getStr() );
180 if( d )
181 break;
182 }
183 if( !d )
184 {
185 cnt.getView()->sysWarning(
186 "Could not find an autoinclude directory."
187 );
188 }
189 else
190 {
191 struct dirent *de;
192 while( (de = readdir( d )) )
193 {
194 if( de->d_name[0] == '.' || (de->d_type != DT_REG) )
195 continue;
196 //sio << "Auto-including: " << de->d_name << sio.nl;
197 bp.load( sAutoDir + "/" + de->d_name );
198 }
199 }
200 }
201
202 bp.load( opts.sConfig );
203
204 if( opts.bAstDump )
205 {
206 sio << ast << sio.nl << sio.nl;
207 return 0;
208 }
209
210// sio << ast << sio.nl;
211
212 Runner r( ast, cnt );
213 r.initialize();
214
215 r.run();
216
217 switch( opts.iInfoLevel )
218 {
219 case 0:
220 // Do nothing
221 break;
222
223 case 1:
224 cnt.printBasicInfo();
225 return 0;
226 }
227
228 try
229 {
230 r.execAction( opts.sAction );
231 }
232 catch( std::exception &e )
233 {
234 cnt.getView()->sysError(e.what());
235 }
236 catch( ... )
237 {
238 cnt.getView()->sysError(
239 "Unknown error occured, this is probably bad..."
240 );
241 }
242
243 if( opts.bDot )
244 {
245 cnt.writeTargetDot();
246 }
247
248 if( opts.bDebug )
249 {
250 sio << "Final context:" << sio.nl << cnt << sio.nl << sio.nl;
251 }
252
253 return 0;
254}
255
diff --git a/src/profile.cpp b/src/profile.cpp
new file mode 100644
index 0000000..878a6e9
--- /dev/null
+++ b/src/profile.cpp
@@ -0,0 +1,116 @@
1#include "profile.h"
2#include "ast.h"
3#include "astbranch.h"
4#include "astleaf.h"
5#include "condition.h"
6
7#include "conditionfiletime.h"
8#include "conditionalways.h"
9#include "conditionnever.h"
10
11#include <bu/sio.h>
12using namespace Bu;
13
14Profile::Profile( const class AstBranch *pRoot ) :
15 pRoot( pRoot ),
16 pCond( NULL ),
17 pAst( NULL )
18{
19 sName = dynamic_cast<const AstLeaf *>(
20 (*pRoot->getBranchBegin()).first()
21 )->getStrValue();
22
23 setCondition();
24}
25
26Profile::Profile( const Profile &rSrc ) :
27 sName( rSrc.sName ),
28 pRoot( rSrc.pRoot ),
29 pCond( rSrc.pCond->clone() ),
30 pAst( NULL )
31{
32}
33
34Profile::~Profile()
35{
36 delete pAst;
37 pAst = NULL;
38}
39
40const Bu::FString &Profile::getName() const
41{
42 return sName;
43}
44
45const AstBranch *Profile::getRoot() const
46{
47 return pRoot;
48}
49
50const Condition *Profile::getCond() const
51{
52 return pCond;
53}
54
55bool Profile::shouldExec( class Runner &r, class Target &rTarget ) const
56{
57 return pCond->shouldExec( r, rTarget );
58}
59
60Profile *Profile::genDefaultClean()
61{
62 Ast *pAst = new Ast();
63 pAst->addNode( AstNode::typeProfile );
64 pAst->openBranch();
65 pAst->addNode( AstNode::typeString, "clean" );
66 pAst->openBranch();
67 pAst->addNode( AstNode::typeCondition, "always" );
68 pAst->addNode( AstNode::typeFunction );
69 pAst->openBranch();
70 pAst->addNode( AstNode::typeString, "unlink" );
71 pAst->openBranch();
72 pAst->addNode( AstNode::typeVariable, "OUTPUT" );
73 pAst->closeNode();
74 pAst->closeNode();
75 //pAst->closeNode();
76 Profile *pRet = new Profile(
77 dynamic_cast<const AstBranch *>(*pAst->getNodeBegin())
78 );
79 pRet->pAst = pAst;
80
81 return pRet;
82}
83
84void Profile::setCondition()
85{
86 for( AstBranch::NodeList::const_iterator i =
87 (*(pRoot->getBranchBegin()+1)).begin(); i; i++ )
88 {
89 if( (*i)->getType() == AstNode::typeCondition )
90 {
91 Bu::FString sCond = dynamic_cast<const AstLeaf *>(*i)->getStrValue();
92 if( sCond == "filetime" )
93 {
94 delete pCond;
95 pCond = new ConditionFileTime();
96 }
97 else if( sCond == "always" )
98 {
99 delete pCond;
100 pCond = new ConditionAlways();
101 }
102 else if( sCond == "never" )
103 {
104 delete pCond;
105 pCond = new ConditionNever();
106 }
107 }
108 }
109
110 if( pCond == NULL )
111 {
112 // The default condition
113 pCond = new ConditionFileTime();
114 }
115}
116
diff --git a/src/profile.h b/src/profile.h
new file mode 100644
index 0000000..dbcc1ea
--- /dev/null
+++ b/src/profile.h
@@ -0,0 +1,30 @@
1#ifndef PROFILE_H
2#define PROFILE_H
3
4#include <bu/fstring.h>
5
6class Profile
7{
8public:
9 Profile( const class AstBranch *pRoot );
10 Profile( const Profile &rSrc );
11 virtual ~Profile();
12
13 const Bu::FString &getName() const;
14 const class AstBranch *getRoot() const;
15 const class Condition *getCond() const;
16 bool shouldExec( class Runner &r, class Target &rTarget ) const;
17
18 static Profile *genDefaultClean();
19
20private:
21 void setCondition();
22
23private:
24 Bu::FString sName;
25 const class AstBranch *pRoot;
26 class Condition *pCond;
27 class Ast *pAst;
28};
29
30#endif
diff --git a/src/rule.cpp b/src/rule.cpp
new file mode 100644
index 0000000..4c42346
--- /dev/null
+++ b/src/rule.cpp
@@ -0,0 +1,167 @@
1#include "rule.h"
2#include "target.h"
3#include "astbranch.h"
4#include "astleaf.h"
5#include "runner.h"
6#include "variable.h"
7#include "context.h"
8#include "condition.h"
9#include "profile.h"
10
11#include <bu/sio.h>
12using namespace Bu;
13
14Rule::Rule( const Bu::FString &sName ) :
15 sName( sName ),
16 pInput( NULL )
17{
18}
19
20Rule::~Rule()
21{
22}
23
24const Bu::FString &Rule::getName() const
25{
26 return sName;
27}
28
29void Rule::setInput( const AstBranch *pNewInput )
30{
31 pInput = pNewInput;
32}
33
34const AstBranch *Rule::getInput() const
35{
36 return pInput;
37}
38
39bool Rule::hasOutputs() const
40{
41 return !lOutput.isEmpty();
42}
43
44void Rule::addOutput( const AstBranch *pNewOutput )
45{
46 lOutput.append( pNewOutput );
47}
48
49void Rule::addProfile( const AstBranch *pProfRoot )
50{
51 Profile *pProf = new Profile( pProfRoot );
52 hProfiles.insert( pProf->getName(), pProf );
53 /*
54 hProfiles.insert(
55 dynamic_cast<const AstLeaf *>(
56 (*pProfile->getBranchBegin()).first()
57 )->getStrValue(),
58 pProfile
59 );
60 */
61}
62
63void Rule::prepTarget( class Target *pTarget )
64{
65 pTarget->setDisplay( getDisplay() );
66 for( ProfileHash::iterator i = hProfiles.begin(); i; i++ )
67 {
68 pTarget->addProfile( *i );
69 }
70 for( AstBranchList::iterator i = lRequires.begin(); i; i++ )
71 {
72 pTarget->addRequires( *i );
73 }
74}
75
76Target *Rule::createTarget( class Runner &r, const Bu::FString &sInput )
77{
78 r.getContext().pushScope();
79 r.getContext().addVariable("INPUT", sInput );
80 Target *pTrg = new Target( false );
81 for( AstBranchList::iterator i = lOutput.begin(); i; i++ )
82 {
83 Variable vOut = r.execExpr(
84 (*(*i)->getBranchBegin()).begin(),
85 Variable( sInput )
86 );
87 if( vOut.getType() == Variable::typeString )
88 {
89 pTrg->addOutput( vOut.getString() );
90 }
91 else if( vOut.getType() == Variable::typeList )
92 {
93 for( VarList::iterator j = vOut.begin(); j; j++ )
94 {
95 pTrg->addOutput( (*j).getString() );
96 }
97 }
98 }
99 r.getContext().addVariable("OUTPUT", pTrg->getOutputList() );
100 pTrg->addInput( sInput );
101 pTrg->setDisplay( getDisplay() );
102 for( ProfileHash::iterator i = hProfiles.begin(); i; i++ )
103 {
104 pTrg->addProfile( *i );
105 }
106 for( AstBranchList::iterator i = lRequires.begin(); i; i++ )
107 {
108 pTrg->addRequires( *i );
109 }
110 pTrg->setVars( r.getContext().getScope() );
111 r.getContext().popScope();
112
113 return pTrg;
114}
115
116bool Rule::ruleMatches( Runner &r, const Bu::FString &sInput )
117{
118 r.getContext().pushScope();
119 r.getContext().addVariable("INPUT", sInput );
120 Variable vInput( sInput );
121 Variable vOut = r.execExpr(
122 (*pInput->getBranchBegin()).begin(),
123 vInput
124 );
125 r.getContext().popScope();
126 if( vOut.getType() == Variable::typeBool )
127 return vOut.getBool();
128 else if( vOut.getType() == Variable::typeList )
129 return vOut.begin();
130 return false;
131}
132
133void Rule::addTag( const Bu::FString &sTag )
134{
135 lsTags.append( sTag );
136}
137
138const StrList &Rule::getTagList() const
139{
140 return lsTags;
141}
142
143void Rule::setDisplay( const Bu::FString &sStr )
144{
145 sDisplay = sStr;
146}
147
148const Bu::FString &Rule::getDisplay() const
149{
150 return ((bool)sDisplay)?(sDisplay):(sName);
151}
152
153void Rule::addRequires( const AstBranch *pBr )
154{
155 lRequires.append( pBr );
156}
157
158Bu::Formatter &operator<<( Bu::Formatter &f, const Rule &/*t*/ )
159{
160 return f << "rule";
161}
162
163template<> Bu::Formatter &Bu::operator<< <Rule>( Bu::Formatter &f, const Rule *t )
164{
165 return f << (*t);
166}
167
diff --git a/src/rule.h b/src/rule.h
new file mode 100644
index 0000000..a3c9344
--- /dev/null
+++ b/src/rule.h
@@ -0,0 +1,53 @@
1#ifndef RULE_H
2#define RULE_H
3
4#include "types.h"
5#include <bu/formatter.h>
6
7class Rule
8{
9 friend Bu::Formatter &operator<<( Bu::Formatter &f, const Rule &t );
10public:
11 Rule( const Bu::FString &sName );
12 virtual ~Rule();
13
14 const Bu::FString &getName() const;
15
16 void setInput( const AstBranch *pNewInput );
17 const AstBranch *getInput() const;
18
19 bool hasOutputs() const;
20
21 void addOutput( const AstBranch *pNewOutput );
22 void addProfile( const AstBranch *pProfile );
23
24 void prepTarget( class Target *pTarget );
25 class Target *createTarget( class Runner &r, const Bu::FString &sInput );
26 bool ruleMatches( class Runner &r, const Bu::FString &sInput );
27
28 void addTag( const Bu::FString &sTag );
29 const StrList &getTagList() const;
30
31 void setDisplay( const Bu::FString &sStr );
32 const Bu::FString &getDisplay() const;
33
34 void addRequires( const AstBranch *pBr );
35
36private:
37 Bu::FString sName;
38 Bu::FString sDisplay;
39 const AstBranch *pInput;
40 AstBranchList lOutput;
41 ProfileHash hProfiles;
42 StrList lsTags;
43 AstBranchList lRequires;
44};
45
46Bu::Formatter &operator<<( Bu::Formatter &f, const Rule &t );
47
48namespace Bu
49{
50 template<> Bu::Formatter &operator<< <Rule>( Bu::Formatter &f, const Rule *t );
51};
52
53#endif
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
diff --git a/src/runner.h b/src/runner.h
new file mode 100644
index 0000000..98894da
--- /dev/null
+++ b/src/runner.h
@@ -0,0 +1,43 @@
1#ifndef RUNNER_H
2#define RUNNER_H
3
4#include "astbranch.h"
5
6class Runner
7{
8public:
9 Runner( class Ast &rAst, class Context &rCont );
10 virtual ~Runner();
11
12 /**
13 * Run through and pull out all of the functions. Maybe more later.
14 */
15 void initialize();
16 class Variable execExpr( AstBranch::NodeList::const_iterator e );
17 class Variable execExpr( AstBranch::NodeList::const_iterator e,
18 const class Variable &vIn );
19 void run();
20 Variable run( AstBranch::NodeList::const_iterator n );
21 class Variable execFunc( const class AstBranch *pFunc,
22 class Variable &vIn );
23 void execProfile( class Target *pTarget, const Bu::FString &sProfile );
24 void execAction( const Bu::FString &sName );
25
26 Context &getContext();
27
28private:
29 class Target *buildTarget( const Bu::FString &sOutput,
30 AstBranch::NodeList::const_iterator n );
31 class Rule *buildRule( const Bu::FString &sName,
32 AstBranch::NodeList::const_iterator n );
33 void attachDefaults();
34 Variable doSet( const AstBranch *pRoot );
35
36private:
37 class Ast &rAst;
38 class Context &rCont;
39 Target *pCurTarget;
40 Rule *pCurRule;
41};
42
43#endif
diff --git a/src/target.cpp b/src/target.cpp
new file mode 100644
index 0000000..f3e54b7
--- /dev/null
+++ b/src/target.cpp
@@ -0,0 +1,402 @@
1#include "target.h"
2#include "variable.h"
3#include "condition.h"
4#include "astleaf.h"
5#include "astbranch.h"
6#include "runner.h"
7#include "context.h"
8#include "profile.h"
9#include "view.h"
10
11#include <bu/membuf.h>
12#include <bu/formatter.h>
13#include <bu/heap.h>
14
15#include <bu/sio.h>
16using namespace Bu;
17
18Target::Target( bool bExplicit ) :
19 bExplicit( bExplicit ),
20 bRun( false ),
21 iDepCount( 0 )
22{
23}
24
25Target::Target( const Bu::FString &sOutput, bool bExplicit ) :
26 bExplicit( bExplicit ),
27 lsOutput( sOutput ),
28 iDepCount( 0 )
29{
30}
31
32Target::~Target()
33{
34}
35
36void Target::addInput( const Bu::FString &sInput )
37{
38 lsInput.append( sInput );
39}
40
41const StrList &Target::getInputList() const
42{
43 return lsInput;
44}
45
46void Target::resetInputList( const StrList &lInputs )
47{
48 lsInput = lInputs;
49 if( lsInput.getSize() == 1 )
50 {
51 hVars.insert("INPUT", lsInput.first() );
52 }
53 else
54 {
55 Variable vInput( Variable::typeList );
56 for( StrList::iterator i = lsInput.begin(); i; i++ )
57 {
58 vInput.append( Variable( *i ) );
59 }
60 hVars.insert("INPUT", vInput );
61 }
62}
63
64void Target::addRequires( const Bu::FString &sReq )
65{
66 lsRequires.append( sReq );
67}
68
69void Target::addRequires( const AstBranch *pBr )
70{
71 lbRequires.append( pBr );
72}
73
74const StrList &Target::getRequiresList() const
75{
76 return lsRequires;
77}
78
79void Target::buildRequires( Runner &r )
80{
81 r.getContext().getView()->buildRequires( *this );
82 r.getContext().pushScope( hVars );
83 for( AstBranchList::iterator i = lbRequires.begin(); i; i++ )
84 {
85 Variable v = r.execExpr( (*(*i)->getBranchBegin()).begin() );
86 if( v.getType() == Variable::typeList )
87 {
88 for( VarList::iterator j = v.begin(); j; j++ )
89 {
90 Bu::FString sReq = (*j).toString();
91 addRequires( sReq );
92 try
93 {
94 addDep( r.getContext().getTarget( sReq ) );
95 }
96 catch(...) { }
97 }
98 }
99 else
100 {
101 Bu::FString sReq = v.toString();
102 addRequires( sReq );
103 try
104 {
105 addDep( r.getContext().getTarget( sReq ) );
106 }
107 catch(...) { }
108 }
109 }
110 r.getContext().popScope();
111}
112
113void Target::addOutput( const Bu::FString &sOutput )
114{
115 lsOutput.append( sOutput );
116}
117
118const StrList &Target::getOutputList() const
119{
120 return lsOutput;
121}
122
123void Target::setPrefix( const Bu::FString &sPrefix )
124{
125 this->sPrefix = sPrefix;
126}
127
128const Bu::FString &Target::getPrefix() const
129{
130 return sPrefix;
131}
132
133void Target::setRule( const Bu::FString &sRule )
134{
135 this->sRule = sRule;
136}
137
138const Bu::FString &Target::getRule() const
139{
140 return sRule;
141}
142
143bool Target::hasRule() const
144{
145 return !sRule.isEmpty();
146}
147
148bool Target::isExplicit() const
149{
150 return bExplicit;
151}
152
153void Target::addDep( Target *pDep )
154{
155 lDeps.append( pDep );
156}
157
158const TargetList &Target::getDepList() const
159{
160 return lDeps;
161}
162
163void Target::addProfile( const class AstBranch *pProfRoot )
164{
165 Profile *pProf = new Profile( pProfRoot );
166 hProfiles.insert( pProf->getName(), pProf );
167 /*
168 hProfiles.insert(
169 dynamic_cast<const AstLeaf *>(
170 (*pProfRoot->getBranchBegin()).first()
171 )->getStrValue(),
172 pProfRoot
173 );
174 */
175}
176
177void Target::addProfile( const class Profile *pSrc )
178{
179 hProfiles.insert( pSrc->getName(), new Profile( *pSrc ) );
180}
181
182bool Target::hasProfile( const Bu::FString &sName ) const
183{
184 return hProfiles.has( sName );
185}
186
187const Profile *Target::getProfile( const Bu::FString &sName ) const
188{
189 return hProfiles.get( sName );
190}
191
192void Target::setVars( const VarHash &hNewVars )
193{
194 hVars = hNewVars;
195}
196
197const VarHash &Target::getVars() const
198{
199 return hVars;
200}
201
202void Target::setDisplay( const Bu::FString &sNewDisplay )
203{
204 if( !sDisplay )
205 sDisplay = sNewDisplay;
206}
207
208const Bu::FString &Target::getDisplay() const
209{
210 return sDisplay;
211}
212
213void Target::process( class Runner &r, const Bu::FString &sProfile )
214{
215 r.getContext().getView()->beginTarget( sProfile, *this );
216 bRun = true;
217 bool bShouldExec = false;
218
219 for( TargetList::iterator i = lDeps.begin(); i; i++ )
220 {
221 if( (*i)->bRun )
222 continue;
223
224 // TODO: This is important, in the future, it may be possible for a
225 // target to be triggered by multiple dependant targets, to cover for
226 // this the below mergeUnder should be *TEMPORARY* and the target
227 // that was marged to be reset post processing.
228 (*i)->mergeUnder( hVars );
229 (*i)->process( r, sProfile );
230 }
231 try
232 {
233 bShouldExec = hProfiles.get( sProfile )->shouldExec( r, *this );
234 }
235 catch( Bu::HashException &e )
236 {
237 }
238
239 if( !bShouldExec )
240 {
241 r.getContext().getView()->skipTarget( sProfile, *this );
242 }
243 else
244 {
245 r.getContext().getView()->processTarget( sProfile, *this );
246 r.execProfile( this, sProfile );
247 }
248
249 r.getContext().getView()->endTarget();
250}
251
252void Target::mergeUnder( const VarHash &hNewVars )
253{
254 for( VarHash::const_iterator i = hNewVars.begin(); i; i++ )
255 {
256 if( !hVars.has( i.getKey() ) )
257 {
258 hVars.insert( i.getKey(), i.getValue() );
259 }
260 }
261}
262
263bool Target::hasRun()
264{
265 return bRun;
266}
267
268void Target::mergeUnder( const Target *pSrc )
269{
270 // If either are explicit, then it's explicit
271 bExplicit = bExplicit || pSrc->bExplicit;
272
273 merge( lsInput, pSrc->lsInput );
274 merge( lsRequires, pSrc->lsRequires );
275 merge( lsOutput, pSrc->lsOutput );
276
277 if( !sPrefix )
278 sPrefix = pSrc->sPrefix;
279
280 sRule = pSrc->sRule;
281
282 mergeUnder( pSrc->hVars );
283
284 // Deps? They should be computed much after merging anyway, peh!
285
286 for( ProfileHash::const_iterator i = pSrc->hProfiles.begin(); i; i++ )
287 {
288 if( !hProfiles.has( i.getKey() ) )
289 {
290 hProfiles.insert( i.getKey(), i.getValue() );
291 }
292 }
293
294 if( !sDisplay )
295 sDisplay = pSrc->sDisplay;
296
297 // Now we need to reset our vars.
298 hVars.insert("INPUT", lsInput );
299 hVars.insert("REQUIRES", lsRequires );
300 hVars.insert("OUTPUT", lsOutput );
301}
302
303void Target::merge( StrList &lOut, const StrList &lIn )
304{
305 Bu::Heap<Bu::FString> hStr;
306 for( StrList::const_iterator i = lOut.begin(); i; i++ )
307 {
308 hStr.enqueue( *i );
309 }
310 for( StrList::const_iterator i = lIn.begin(); i; i++ )
311 {
312 hStr.enqueue( *i );
313 }
314
315 lOut.clear();
316
317 if( hStr.isEmpty() )
318 return;
319
320 lOut.append( hStr.dequeue() );
321 while( !hStr.isEmpty() )
322 {
323 if( hStr.peek() == lOut.last() )
324 {
325 hStr.dequeue();
326 }
327 else
328 {
329 lOut.append( hStr.dequeue() );
330 }
331 }
332}
333
334void Target::resetRun( bool bHasRun )
335{
336 bRun = bHasRun;
337
338 for( TargetList::iterator i = lDeps.begin(); i; i++ )
339 {
340 (*i)->resetRun( bHasRun );
341 }
342}
343
344void Target::setDepCount()
345{
346 bRun = true;
347 iDepCount = 1;
348 for( TargetList::iterator i = lDeps.begin(); i; i++ )
349 {
350 if( (*i)->bRun )
351 {
352 continue;
353 }
354 (*i)->setDepCount();
355 iDepCount += (*i)->getDepCount();
356 }
357}
358
359int Target::getDepCount() const
360{
361 return iDepCount;
362}
363
364void Target::collapseDeps()
365{
366 if( lDeps.getSize() <= 1 )
367 return;
368 Bu::Hash<ptrdiff_t, bool> hDep;
369 for( TargetList::iterator i = lDeps.begin(); i; i++ )
370 {
371 if( hDep.has( (ptrdiff_t)*i ) )
372 {
373 lDeps.erase( i );
374 i--;
375 }
376 else
377 {
378 hDep.insert( (ptrdiff_t)*i, true );
379 }
380 }
381}
382
383Bu::Formatter &operator<<( Bu::Formatter &f, const Target &t )
384{
385 f.incIndent();
386 f << f.nl << "Input = " << t.lsInput << "," << f.nl
387 << "Requires = " << t.lsRequires << "," << f.nl
388 << "Output = \"" << t.lsOutput << "\"," << f.nl
389 << "Prefix = \"" << t.sPrefix << "\"," << f.nl
390 << "Rule = \"" << t.sRule << "\"," << f.nl
391 << "Explicit = " << t.bExplicit << "," << f.nl
392 << "Vars = " << t.hVars
393 << f.nl;
394 f.decIndent();
395 return f;
396}
397
398template<> Bu::Formatter &Bu::operator<< <Target>( Bu::Formatter &f, const Target *t )
399{
400 return f << (*t);
401}
402
diff --git a/src/target.h b/src/target.h
new file mode 100644
index 0000000..766366a
--- /dev/null
+++ b/src/target.h
@@ -0,0 +1,89 @@
1#ifndef TARGET_H
2#define TARGET_H
3
4#include "types.h"
5#include <bu/formatter.h>
6
7class Target
8{
9 friend Bu::Formatter &operator<<( Bu::Formatter &f, const Target &t );
10public:
11 Target( bool bExplicit );
12 Target( const Bu::FString &sOutput, bool bExplicit );
13 virtual ~Target();
14
15 void addInput( const Bu::FString &sInput );
16 const StrList &getInputList() const;
17 void resetInputList( const StrList &lInputs );
18
19 void addRequires( const Bu::FString &sReq );
20 void addRequires( const AstBranch *pBr );
21 const StrList &getRequiresList() const;
22 void buildRequires( class Runner &r );
23
24 void addOutput( const Bu::FString &sOutput );
25 const StrList &getOutputList() const;
26
27 void setPrefix( const Bu::FString &sPrefix );
28 const Bu::FString &getPrefix() const;
29
30 void setRule( const Bu::FString &sRule );
31 const Bu::FString &getRule() const;
32 bool hasRule() const;
33
34 bool isExplicit() const;
35
36 void addDep( Target *pDep );
37 const TargetList &getDepList() const;
38
39 void addProfile( const class AstBranch *pProfRoot );
40 void addProfile( const class Profile *pSrc );
41 bool hasProfile( const Bu::FString &sName ) const;
42 const class Profile *getProfile( const Bu::FString &sName ) const;
43
44 void setVars( const VarHash &hNewVars );
45 const VarHash &getVars() const;
46
47 void setDisplay( const Bu::FString &sNewDisplay );
48 const Bu::FString &getDisplay() const;
49
50 void process( class Runner &r, const Bu::FString &sProfile );
51
52 void mergeUnder( const Target *pSrc );
53
54 bool hasRun();
55
56 void resetRun( bool bHasRun=true );
57 void setDepCount();
58 int getDepCount() const;
59
60 void collapseDeps();
61
62private:
63 void mergeUnder( const VarHash &hVars );
64 void merge( StrList &lOut, const StrList &lIn );
65
66private:
67 bool bExplicit;
68 StrList lsInput;
69 StrList lsRequires;
70 StrList lsOutput;
71 Bu::FString sPrefix;
72 Bu::FString sRule;
73 VarHash hVars;
74 TargetList lDeps;
75 ProfileHash hProfiles;
76 Bu::FString sDisplay;
77 bool bRun;
78 AstBranchList lbRequires;
79 int iDepCount;
80};
81
82Bu::Formatter &operator<<( Bu::Formatter &f, const Target &t );
83
84namespace Bu
85{
86 template<> Bu::Formatter &operator<< <Target>( Bu::Formatter &f, const Target *t );
87};
88
89#endif
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..e405e35
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,26 @@
1#ifndef TYPES_H
2#define TYPES_H
3
4#include "bu/fstring.h"
5#include "bu/list.h"
6#include "bu/hash.h"
7
8typedef Bu::List<Bu::FString> StrList;
9
10class Variable;
11typedef Bu::List<Variable> VarList;
12typedef Bu::Hash<Bu::FString, Variable> VarHash;
13
14class Condition;
15
16class Target;
17typedef Bu::List<Target *> TargetList;
18class Profile;
19typedef Bu::Hash<Bu::FString, Profile *> ProfileHash;
20
21class AstNode;
22class AstBranch;
23class AstLeaf;
24typedef Bu::List<const AstBranch *> AstBranchList;
25
26#endif
diff --git a/src/variable.cpp b/src/variable.cpp
new file mode 100644
index 0000000..99bac59
--- /dev/null
+++ b/src/variable.cpp
@@ -0,0 +1,892 @@
1#include "variable.h"
2#include "astleaf.h"
3#include "bu/sio.h"
4using Bu::sio;
5
6#include <stdlib.h>
7
8Variable::Variable() :
9 eType( typeNone )
10{
11 memset( &uVal, 0, sizeof(uVal) );
12}
13
14Variable::Variable( Type t ) :
15 eType( t )
16{
17 memset( &uVal, 0, sizeof(uVal) );
18 if( eType == typeString || eType == typeRef )
19 {
20 uVal.sVal = new Bu::FString;
21 }
22 else if( eType == typeList )
23 {
24 uVal.lVal = new VarList;
25 }
26}
27
28Variable::Variable( int iVal ) :
29 eType( typeInt )
30{
31 memset( &uVal, 0, sizeof(uVal) );
32 uVal.iVal = iVal;
33}
34
35Variable::Variable( double fVal ) :
36 eType( typeFloat )
37{
38 memset( &uVal, 0, sizeof(uVal) );
39 uVal.fVal = fVal;
40}
41
42Variable::Variable( bool bVal ) :
43 eType( typeBool )
44{
45 memset( &uVal, 0, sizeof(uVal) );
46 uVal.bVal = bVal;
47}
48
49Variable::Variable( const Bu::FString &sVal ) :
50 eType( typeString )
51{
52 memset( &uVal, 0, sizeof(uVal) );
53 uVal.sVal = new Bu::FString( sVal );
54}
55
56Variable::Variable( const char *sVal ) :
57 eType( typeString )
58{
59 memset( &uVal, 0, sizeof(uVal) );
60 uVal.sVal = new Bu::FString( sVal );
61}
62
63Variable::Variable( const Variable &v ) :
64 eType( v.eType )
65{
66 memset( &uVal, 0, sizeof(uVal) );
67 if( eType == typeString || eType == typeRef )
68 {
69 uVal.sVal = new Bu::FString( *v.uVal.sVal );
70 }
71 else if( eType == typeList )
72 {
73 uVal.lVal = new VarList( *v.uVal.lVal );
74 }
75 else
76 {
77 uVal = v.uVal;
78 }
79}
80
81Variable::Variable( const class AstLeaf &l )
82{
83 switch( l.getDataType() )
84 {
85 case AstNode::typeDataInt:
86 eType = typeInt;
87 uVal.iVal = l.getIntValue();
88 break;
89
90 case AstNode::typeDataFloat:
91 eType = typeFloat;
92 uVal.fVal = l.getFloatValue();
93 break;
94
95 case AstNode::typeDataBool:
96 eType = typeBool;
97 uVal.bVal = l.getBoolValue();
98 break;
99
100 case AstNode::typeDataString:
101 eType = typeString;
102 uVal.sVal = new Bu::FString( l.getStrValue() );
103 break;
104
105 case AstNode::typeDataNone:
106 eType = typeNone;
107 memset( &uVal, 0, sizeof(uVal) );
108 break;
109
110 default:
111 sio << "Unhandled type <<!>>" << sio.nl << sio.nl;
112 break;
113 }
114}
115
116Variable::Variable( const StrList &lst )
117{
118 if( lst.getSize() == 1 )
119 {
120 eType = typeString;
121 uVal.sVal = new Bu::FString( lst.first() );
122 }
123 else
124 {
125 eType = typeList;
126 uVal.lVal = new VarList();
127 for( StrList::const_iterator i = lst.begin(); i; i++ )
128 {
129 uVal.lVal->append( Variable( *i ) );
130 }
131 }
132}
133
134Variable::Variable( const VarList &lst )
135{
136 eType = typeList;
137 uVal.lVal = new VarList( lst );
138}
139
140Variable::~Variable()
141{
142 if( eType == typeString || eType == typeRef )
143 {
144 delete uVal.sVal;
145 }
146 else if( eType == typeList )
147 {
148 delete uVal.lVal;
149 }
150}
151
152Variable Variable::mkRef( const Bu::FString &sVal )
153{
154 Variable v( typeRef );
155 (*v.uVal.sVal) = sVal;
156 return v;
157}
158
159Variable::Type Variable::getType() const
160{
161 return eType;
162}
163
164int Variable::getInt() const
165{
166 if( eType != typeInt ) throw Bu::ExceptionBase("Wrong variable type.");
167 return uVal.iVal;
168}
169
170double Variable::getFloat() const
171{
172 if( eType != typeFloat ) throw Bu::ExceptionBase("Wrong variable type.");
173 return uVal.fVal;
174}
175
176bool Variable::getBool() const
177{
178 if( eType != typeBool ) throw Bu::ExceptionBase("Wrong variable type.");
179 return uVal.bVal;
180}
181
182const Bu::FString &Variable::getString() const
183{
184 if( eType != typeString && eType != typeRef ) throw Bu::ExceptionBase("Wrong variable type.");
185 return *uVal.sVal;
186}
187
188const VarList &Variable::getList() const
189{
190 if( eType != typeList ) throw Bu::ExceptionBase("Wrong variable type.");
191 return *uVal.lVal;
192}
193
194int Variable::toInt() const
195{
196 switch( eType )
197 {
198 case typeInt:
199 return uVal.iVal;
200
201 case typeFloat:
202 return (int)uVal.fVal;
203
204 case typeBool:
205 return (uVal.bVal)?(1):(0);
206
207 case typeString:
208 case typeRef:
209 return strtol( uVal.sVal->getStr(), NULL, 0 );
210
211 default:
212 return 0;
213 }
214 return 0;
215}
216
217double Variable::toFloat() const
218{
219 switch( eType )
220 {
221 case typeInt:
222 return (double)uVal.iVal;
223
224 case typeFloat:
225 return uVal.fVal;
226
227 case typeBool:
228 return (uVal.bVal)?(1.0):(0.0);
229
230 case typeString:
231 case typeRef:
232 return strtod( uVal.sVal->getStr(), NULL );
233
234 default:
235 return 0.0;
236 }
237 return 0.0;
238}
239
240bool Variable::toBool() const
241{
242 switch( eType )
243 {
244 case typeInt:
245 return uVal.iVal != 0;
246
247 case typeFloat:
248 return uVal.fVal != 0.0;
249
250 case typeBool:
251 return uVal.bVal;
252
253 case typeString:
254 case typeRef:
255 return (*uVal.sVal) == "true";
256
257 case typeList:
258 return !(*uVal.lVal).isEmpty();
259
260 default:
261 return false;
262 }
263 return false;
264}
265
266Bu::FString Variable::toString() const
267{
268 Bu::FString sRet;
269 switch( eType )
270 {
271 case typeNone:
272 // No type, no data, we return empty string
273 break;
274
275 case typeInt:
276 sRet.format("%d", uVal.iVal );
277 break;
278
279 case typeFloat:
280 sRet.format("%f", uVal.fVal );
281 break;
282
283 case typeBool:
284 sRet = (uVal.bVal)?("true"):("false");
285 break;
286
287 case typeString:
288 case typeRef:
289 sRet = *uVal.sVal;
290 break;
291
292 case typeList:
293 {
294 for( VarList::const_iterator i = uVal.lVal->begin(); i; i++ )
295 {
296 if( i != uVal.lVal->begin() )
297 sRet += " ";
298 sRet += (*i).toString();
299 }
300 }
301 break;
302
303 case typeVersion:
304 break;
305 }
306
307 return sRet;
308}
309
310VarList Variable::toList() const
311{
312 if( eType == typeList )
313 return *this;
314 return VarList( *this );
315}
316
317Variable Variable::toType( Type eNewType ) const
318{
319 switch( eNewType )
320 {
321 case typeNone:
322 return Variable();
323
324 case typeBool:
325 return Variable( toBool() );
326
327 case typeInt:
328 return Variable( toInt() );
329
330 case typeFloat:
331 return Variable( toFloat() );
332
333 case typeVersion:
334 return Variable();
335
336 case typeString:
337 return Variable( toString() );
338
339 case typeList:
340 return Variable( toList() );
341
342 case typeRef:
343 return Variable::mkRef( toString() );
344 }
345 throw Bu::ExceptionBase("Unhandled case in Variable toType");
346}
347
348void Variable::append( const Variable &v )
349{
350 if( eType != typeList ) throw Bu::ExceptionBase("Wrong variable type.");
351
352 if( v.eType == typeList )
353 {
354 uVal.lVal->append( *v.uVal.lVal );
355 }
356 else
357 {
358 uVal.lVal->append( v );
359 }
360}
361
362VarList::iterator Variable::begin()
363{
364 if( eType != typeList ) throw Bu::ExceptionBase("Wrong variable type.");
365
366 return uVal.lVal->begin();
367}
368
369VarList::const_iterator Variable::begin() const
370{
371 if( eType != typeList ) throw Bu::ExceptionBase("Wrong variable type.");
372
373 return const_cast<const VarList *>(uVal.lVal)->begin();
374}
375
376void Variable::doNegate()
377{
378 switch( eType )
379 {
380 case typeNone:
381 break;
382
383 case typeBool:
384 throw Bu::ExceptionBase("You cannot negate boolean values.");
385
386 case typeInt:
387 uVal.iVal = -uVal.iVal;
388 break;
389
390 case typeFloat:
391 uVal.fVal = -uVal.fVal;
392 break;
393
394 case typeVersion:
395 throw Bu::ExceptionBase("You cannot negate version values.");
396
397 case typeString:
398 throw Bu::ExceptionBase("You cannot negate string values.");
399
400 case typeList:
401 throw Bu::ExceptionBase("You cannot negate list values.");
402
403 case typeRef:
404 throw Bu::ExceptionBase("You cannot negate reference values.");
405 }
406}
407
408void Variable::doNot()
409{
410 bool bVal = !toBool();
411 reset( typeBool );
412 uVal.bVal = bVal;
413}
414
415const Variable &Variable::operator=( const Variable &rhs )
416{
417 reset( rhs.eType );
418 if( rhs.eType == typeString || rhs.eType == typeRef )
419 {
420 uVal.sVal = new Bu::FString( *rhs.uVal.sVal );
421 }
422 else if( rhs.eType == typeList )
423 {
424 uVal.lVal = new VarList( *rhs.uVal.lVal );
425 }
426 else
427 {
428 uVal = rhs.uVal;
429 }
430
431 return *this;
432}
433
434const Variable &Variable::operator=( const int &rhs )
435{
436 reset( typeInt );
437 uVal.iVal = rhs;
438
439 return *this;
440}
441
442const Variable &Variable::operator=( const double &rhs )
443{
444 reset( typeFloat );
445 uVal.fVal = rhs;
446
447 return *this;
448}
449
450const Variable &Variable::operator=( const bool &rhs )
451{
452 reset( typeBool );
453 uVal.bVal = rhs;
454
455 return *this;
456}
457
458const Variable &Variable::operator=( const Bu::FString &rhs )
459{
460 reset( typeString );
461 uVal.sVal = new Bu::FString( rhs );
462
463 return *this;
464}
465
466const Variable &Variable::operator+=( const Variable &rhs )
467{
468 switch( eType )
469 {
470 case typeNone:
471 reset( rhs.eType );
472 if( eType == typeString || eType == typeRef )
473 {
474 uVal.sVal = new Bu::FString( *rhs.uVal.sVal );
475 }
476 else if( eType == typeList )
477 {
478 uVal.lVal = new VarList( *rhs.uVal.lVal );
479 }
480 else
481 {
482 uVal = rhs.uVal;
483 }
484 break;
485
486 case typeInt:
487 uVal.iVal += rhs.getInt();
488 break;
489
490 case typeFloat:
491 uVal.fVal += rhs.getFloat();
492 break;
493
494 case typeBool:
495 throw Bu::ExceptionBase("Can't += with a boolean...");
496 break;
497
498 case typeString:
499 uVal.sVal->append(" ");
500 uVal.sVal->append( rhs.getString() );
501 break;
502
503 case typeList:
504 uVal.lVal->append( rhs.getList() );
505 break;
506
507 case typeVersion:
508 break;
509
510 default:
511 break;
512 }
513 return *this;
514}
515
516const Variable &Variable::operator<<( const Variable &rhs )
517{
518 switch( eType )
519 {
520 case typeNone:
521 reset( rhs.eType );
522 if( eType == typeString )
523 {
524 uVal.sVal = new Bu::FString( *rhs.uVal.sVal );
525 }
526 else if( eType == typeList )
527 {
528 uVal.lVal = new VarList( *rhs.uVal.lVal );
529 }
530 else
531 {
532 uVal = rhs.uVal;
533 }
534 break;
535
536 case typeString:
537 uVal.sVal->append( rhs.getString() );
538 break;
539
540 case typeList:
541 uVal.lVal->append( rhs.getList() );
542 break;
543
544 default:
545 throw Bu::ExceptionBase("Can't << with non-string or non-list.");
546 break;
547 }
548 return *this;
549}
550
551bool Variable::operator==( const Variable &rhs ) const
552{
553 if( eType != rhs.eType )
554 return false;
555 switch( eType )
556 {
557 case typeNone:
558 return true;
559
560 case typeInt:
561 return uVal.iVal == rhs.uVal.iVal;
562
563 case typeFloat:
564 return uVal.fVal == rhs.uVal.fVal;
565
566 case typeBool:
567 return uVal.bVal == rhs.uVal.bVal;
568
569 case typeString:
570 case typeRef:
571 return *uVal.sVal == *rhs.uVal.sVal;
572
573 case typeList:
574 return *uVal.lVal == *rhs.uVal.lVal;
575
576 case typeVersion:
577 return false;
578 }
579
580 return false;
581}
582
583bool Variable::operator!=( const Variable &rhs ) const
584{
585 return !(*this == rhs);
586}
587
588bool Variable::operator<( const Variable &rhs ) const
589{
590 Type eTop = Bu::max( eType, rhs.eType );
591 switch( eTop )
592 {
593 case typeNone:
594 return false;
595
596 case typeBool:
597 throw Bu::ExceptionBase("You cannot < compare boolean values.");
598
599 case typeInt:
600 return toInt() < rhs.toInt();
601
602 case typeFloat:
603 return toFloat() < rhs.toFloat();
604
605 case typeVersion:
606 return true;
607
608 case typeString:
609 return toString() < rhs.toString();
610
611 case typeList:
612 throw Bu::ExceptionBase("You cannot < compare list values.");
613
614 case typeRef:
615 throw Bu::ExceptionBase("You cannot < compare reference values.");
616 }
617 throw Bu::ExceptionBase("Unhandled case in Variable < compare");
618}
619
620bool Variable::operator>( const Variable &rhs ) const
621{
622 Type eTop = Bu::max( eType, rhs.eType );
623 switch( eTop )
624 {
625 case typeNone:
626 return false;
627
628 case typeBool:
629 throw Bu::ExceptionBase("You cannot > compare boolean values.");
630
631 case typeInt:
632 return toInt() > rhs.toInt();
633
634 case typeFloat:
635 return toFloat() > rhs.toFloat();
636
637 case typeVersion:
638 return true;
639
640 case typeString:
641 return toString() > rhs.toString();
642
643 case typeList:
644 throw Bu::ExceptionBase("You cannot > compare list values.");
645
646 case typeRef:
647 throw Bu::ExceptionBase("You cannot > compare reference values.");
648 }
649 throw Bu::ExceptionBase("Unhandled case in Variable > compare");
650}
651
652bool Variable::operator<=( const Variable &rhs ) const
653{
654 Type eTop = Bu::max( eType, rhs.eType );
655 switch( eTop )
656 {
657 case typeNone:
658 return false;
659
660 case typeBool:
661 throw Bu::ExceptionBase("You cannot <= compare boolean values.");
662
663 case typeInt:
664 return toInt() <= rhs.toInt();
665
666 case typeFloat:
667 return toFloat() <= rhs.toFloat();
668
669 case typeVersion:
670 return true;
671
672 case typeString:
673 return toString() <= rhs.toString();
674
675 case typeList:
676 throw Bu::ExceptionBase("You cannot <= compare list values.");
677
678 case typeRef:
679 throw Bu::ExceptionBase("You cannot <= compare reference values.");
680 }
681 throw Bu::ExceptionBase("Unhandled case in Variable <= compare");
682}
683
684bool Variable::operator>=( const Variable &rhs ) const
685{
686 Type eTop = Bu::max( eType, rhs.eType );
687 switch( eTop )
688 {
689 case typeNone:
690 return false;
691
692 case typeBool:
693 throw Bu::ExceptionBase("You cannot >= compare boolean values.");
694
695 case typeInt:
696 return toInt() >= rhs.toInt();
697
698 case typeFloat:
699 return toFloat() >= rhs.toFloat();
700
701 case typeVersion:
702 return true;
703
704 case typeString:
705 return toString() >= rhs.toString();
706
707 case typeList:
708 throw Bu::ExceptionBase("You cannot >= compare list values.");
709
710 case typeRef:
711 throw Bu::ExceptionBase("You cannot >= compare reference values.");
712 }
713 throw Bu::ExceptionBase("Unhandled case in Variable >= compare");
714}
715
716Variable Variable::operator+( const Variable &rhs ) const
717{
718 Type eTop = Bu::max( eType, rhs.eType );
719 switch( eTop )
720 {
721 case typeNone:
722 return Variable();
723
724 case typeBool:
725 throw Bu::ExceptionBase("You cannot add boolean values.");
726
727 case typeInt:
728 return Variable( toInt() + rhs.toInt() );
729
730 case typeFloat:
731 return Variable( toFloat() + rhs.toFloat() );
732
733 case typeVersion:
734 throw Bu::ExceptionBase("You cannot add version values.");
735
736 case typeString:
737 return Variable( toString() + rhs.toString() );
738
739 case typeList:
740 return Variable( toList() + rhs.toList() );
741
742 case typeRef:
743 throw Bu::ExceptionBase("You cannot add reference values.");
744 }
745 throw Bu::ExceptionBase("Unhandled case in Variable add");
746}
747
748Variable Variable::operator-( const Variable &rhs ) const
749{
750 Type eTop = Bu::max( eType, rhs.eType );
751 switch( eTop )
752 {
753 case typeNone:
754 return Variable();
755
756 case typeBool:
757 throw Bu::ExceptionBase("You cannot subtract boolean values.");
758
759 case typeInt:
760 return Variable( toInt() - rhs.toInt() );
761
762 case typeFloat:
763 return Variable( toFloat() - rhs.toFloat() );
764
765 case typeVersion:
766 throw Bu::ExceptionBase("You cannot subtract version values.");
767
768 case typeString:
769 throw Bu::ExceptionBase("You cannot subtract string values.");
770
771 case typeList:
772 throw Bu::ExceptionBase("You cannot subtract list values.");
773
774 case typeRef:
775 throw Bu::ExceptionBase("You cannot subtract reference values.");
776 }
777 throw Bu::ExceptionBase("Unhandled case in Variable subtract");
778}
779
780Variable Variable::operator*( const Variable &rhs ) const
781{
782 Type eTop = Bu::max( eType, rhs.eType );
783 switch( eTop )
784 {
785 case typeNone:
786 return Variable();
787
788 case typeBool:
789 throw Bu::ExceptionBase("You cannot multiply boolean values.");
790
791 case typeInt:
792 return Variable( toInt() * rhs.toInt() );
793
794 case typeFloat:
795 return Variable( toFloat() * rhs.toFloat() );
796
797 case typeVersion:
798 throw Bu::ExceptionBase("You cannot multiply version values.");
799
800 case typeString:
801 throw Bu::ExceptionBase("You cannot multiply string values.");
802
803 case typeList:
804 throw Bu::ExceptionBase("You cannot multiply list values.");
805
806 case typeRef:
807 throw Bu::ExceptionBase("You cannot multiply reference values.");
808 }
809 throw Bu::ExceptionBase("Unhandled case in Variable multiply");
810}
811
812Variable Variable::operator/( const Variable &rhs ) const
813{
814 Type eTop = Bu::max( eType, rhs.eType );
815 switch( eTop )
816 {
817 case typeNone:
818 return Variable();
819
820 case typeBool:
821 throw Bu::ExceptionBase("You cannot divide boolean values.");
822
823 case typeInt:
824 return Variable( toInt() / rhs.toInt() );
825
826 case typeFloat:
827 return Variable( toFloat() / rhs.toFloat() );
828
829 case typeVersion:
830 throw Bu::ExceptionBase("You cannot divide version values.");
831
832 case typeString:
833 throw Bu::ExceptionBase("You cannot divide string values.");
834
835 case typeList:
836 throw Bu::ExceptionBase("You cannot divide list values.");
837
838 case typeRef:
839 throw Bu::ExceptionBase("You cannot divide reference values.");
840 }
841 throw Bu::ExceptionBase("Unhandled case in Variable divide");
842}
843
844void Variable::reset( Type eNewType )
845{
846 if( eType == typeString || eType == typeRef )
847 {
848 delete uVal.sVal;
849 }
850 else if( eType == typeList )
851 {
852 delete uVal.lVal;
853 }
854 memset( &uVal, 0, sizeof(uVal) );
855
856 eType = eNewType;
857}
858
859Bu::Formatter &operator<<( Bu::Formatter &f, const Variable::Type &t )
860{
861 switch( t )
862 {
863 case Variable::typeNone: f << "*typeless*"; break;
864 case Variable::typeInt: f << "int"; break;
865 case Variable::typeFloat: f << "double"; break;
866 case Variable::typeBool: f << "bool"; break;
867 case Variable::typeString: f << "string"; break;
868 case Variable::typeList: f << "list"; break;
869 case Variable::typeVersion: f << "version"; break;
870 case Variable::typeRef: f << "ref"; break;
871 }
872 return f;
873}
874
875Bu::Formatter &operator<<( Bu::Formatter &f, const Variable &v )
876{
877 f << "Variable(" << v.getType() << ") = ";
878 switch( v.getType() )
879 {
880 case Variable::typeNone: break;
881 case Variable::typeInt: f << v.getInt(); break;
882 case Variable::typeFloat: f << v.getFloat(); break;
883 case Variable::typeBool: f << v.getBool(); break;
884 case Variable::typeString: f << v.getString(); break;
885 case Variable::typeList: f << v.getList(); break;
886 case Variable::typeVersion:/*f << v.getVersion();*/ break;
887 case Variable::typeRef: f << v.getString(); break;
888 }
889
890 return f;
891}
892
diff --git a/src/variable.h b/src/variable.h
new file mode 100644
index 0000000..1b5542e
--- /dev/null
+++ b/src/variable.h
@@ -0,0 +1,115 @@
1#ifndef VARIABLE_H
2#define VARIABLE_H
3
4#include "types.h"
5
6/**
7 * A build variable, which is basically a flexible, limited type range variant.
8 */
9class Variable
10{
11public:
12 enum Type
13 {
14 typeNone,
15 typeBool,
16 typeInt,
17 typeFloat,
18 typeVersion,
19 typeString,
20 typeList,
21 typeRef /**< Reference by name, it's just a string. */
22 };
23
24public:
25 Variable();
26 Variable( Type t );
27 Variable( int iVal );
28 Variable( double fVal );
29 Variable( bool bVal );
30 Variable( const Bu::FString &sVal );
31 Variable( const char *sVal );
32 Variable( const Variable &v );
33 Variable( const class AstLeaf &l );
34 /**
35 * This special case function turns the variable into a string if there is
36 * only one string in the list, or a list of strings if there is more or
37 * less than one.
38 */
39 Variable( const StrList &lst );
40 Variable( const VarList &lst );
41 virtual ~Variable();
42
43 static Variable mkRef( const Bu::FString &sVal );
44
45 Type getType() const;
46
47 // Raw aquisition functions, if the type isn't right,
48 // they throw an exception
49 int getInt() const;
50 double getFloat() const;
51 bool getBool() const;
52 const Bu::FString &getString() const;
53 const VarList &getList() const;
54
55 // Conversion functions, they'll return the requested type, maybe an error
56 // if the source data is really bad
57 int toInt() const;
58 double toFloat() const;
59 bool toBool() const;
60 Bu::FString toString() const;
61 VarList toList() const;
62
63 Variable toType( Type eNewType ) const;
64
65 void append( const Variable &v );
66 VarList::iterator begin();
67 VarList::const_iterator begin() const;
68
69 void doNegate();
70 void doNot();
71
72 const Variable &operator=( const Variable &rhs );
73 const Variable &operator=( const int &rhs );
74 const Variable &operator=( const double &rhs );
75 const Variable &operator=( const bool &rhs );
76 const Variable &operator=( const Bu::FString &rhs );
77
78 const Variable &operator+=( const Variable &rhs );
79 const Variable &operator<<( const Variable &rhs );
80
81 bool operator==( const Variable &rhs ) const;
82 bool operator!=( const Variable &rhs ) const;
83 bool operator<( const Variable &rhs ) const;
84 bool operator>( const Variable &rhs ) const;
85 bool operator<=( const Variable &rhs ) const;
86 bool operator>=( const Variable &rhs ) const;
87
88 Variable operator+( const Variable &rhs ) const;
89 Variable operator-( const Variable &rhs ) const;
90 Variable operator*( const Variable &rhs ) const;
91 Variable operator/( const Variable &rhs ) const;
92
93private:
94 Type eType;
95 union
96 {
97 int iVal;
98 double fVal;
99 bool bVal;
100 Bu::FString *sVal;
101 VarList *lVal;
102 } uVal;
103
104 void reset( Type eType );
105};
106
107namespace Bu
108{
109 class Formatter;
110}
111
112Bu::Formatter &operator<<( Bu::Formatter &f, const Variable::Type &t );
113Bu::Formatter &operator<<( Bu::Formatter &f, const Variable &v );
114
115#endif
diff --git a/src/view.cpp b/src/view.cpp
new file mode 100644
index 0000000..6dcc9bb
--- /dev/null
+++ b/src/view.cpp
@@ -0,0 +1,10 @@
1#include "view.h"
2
3View::View()
4{
5}
6
7View::~View()
8{
9}
10
diff --git a/src/view.h b/src/view.h
new file mode 100644
index 0000000..fb172aa
--- /dev/null
+++ b/src/view.h
@@ -0,0 +1,46 @@
1#ifndef VIEW_H
2#define VIEW_H
3
4#include <bu/fstring.h>
5#include "types.h"
6
7/**
8 * Base class for all views. A view is the only way that build is allowed to
9 * communicate with the user during the processing of a buildfile, the main
10 * executable may output some things for command line arguments and whatnot on
11 * it's own, or debugging info, but all reports of everything happening during
12 * the process is sent through a view, so it can be made pretty and usable.
13 */
14class View
15{
16public:
17 View();
18 virtual ~View();
19
20 virtual void beginAction( const Bu::FString &sAction )=0;
21 virtual void endAction()=0;
22
23 virtual void skipTarget( const Bu::FString &sProfile,
24 const Target &rTarget )=0;
25 virtual void beginTarget( const Bu::FString &sProfile,
26 const Target &rTarget )=0;
27 virtual void processTarget( const Bu::FString &sProfile,
28 const Target &rTarget )=0;
29 virtual void endTarget()=0;
30
31 virtual void buildRequires( const Target &rTarget )=0;
32 virtual void cmdStarted( const Bu::FString &sCmd )=0;
33 virtual void cmdFinished( const Bu::FString &sStdOut,
34 const Bu::FString &sStdErr, long iExit )=0;
35
36 virtual void userError( const Bu::FString &sMsg )=0;
37 virtual void userWarning( const Bu::FString &sMsg )=0;
38 virtual void userNotice( const Bu::FString &sMsg )=0;
39
40 virtual void sysError( const Bu::FString &sMsg )=0;
41 virtual void sysWarning( const Bu::FString &sMsg )=0;
42
43private:
44};
45
46#endif
diff --git a/src/viewdefault.cpp b/src/viewdefault.cpp
new file mode 100644
index 0000000..c38c62f
--- /dev/null
+++ b/src/viewdefault.cpp
@@ -0,0 +1,170 @@
1#include "viewdefault.h"
2#include "target.h"
3
4#include <bu/plugger.h>
5
6#include <bu/sio.h>
7using namespace Bu;
8
9PluginInterface3( pluginViewDefault, default, ViewDefault, View,
10 "Mike Buland", 0, 1 );
11
12#define ESC "\x1b"
13
14#define C_RESET ESC "[0m"
15#define C_RED ESC "[31m"
16#define C_GREEN ESC "[32m"
17#define C_YELLOW ESC "[33m"
18#define C_BLUE ESC "[34m"
19#define C_MAGENTA ESC "[35m"
20#define C_CYAN ESC "[36m"
21#define C_WHITE ESC "[37m"
22#define C_DEFAULT ESC "[39m"
23
24#define C_BR_RED ESC "[1;31m"
25#define C_BR_GREEN ESC "[1;32m"
26#define C_BR_YELLOW ESC "[1;33m"
27#define C_BR_BLUE ESC "[1;34m"
28#define C_BR_MAGENTA ESC "[1;35m"
29#define C_BR_CYAN ESC "[1;36m"
30#define C_BR_WHITE ESC "[1;37m"
31
32ViewDefault::ViewDefault() :
33 bFirst( true ),
34 iDepth( 0 ),
35 iTotal( 0 ),
36 iCurrent( 0 )
37{
38}
39
40ViewDefault::~ViewDefault()
41{
42}
43
44void ViewDefault::beginAction( const Bu::FString &/*sAction*/ )
45{
46}
47
48void ViewDefault::endAction()
49{
50}
51
52void ViewDefault::skipTarget( const Bu::FString &/*sProfile*/,
53 const Target &/*rTarget*/ )
54{
55 iCurrent++;
56}
57
58void ViewDefault::beginTarget( const Bu::FString &sProfile,
59 const Target &rTarget )
60{
61 if( iDepth == 0 )
62 {
63 iTotal = rTarget.getDepCount();
64 iCurrent = 0;
65 if( bFirst == false )
66 {
67 sio << sio.nl;
68 }
69 bFirst = false;
70 sio << C_BR_WHITE << " --- " << C_BR_CYAN << sProfile << " "
71 << rTarget.getOutputList().first() << C_BR_WHITE << " --- "
72 << C_RESET << sio.nl;
73 }
74 iDepth++;
75}
76
77void ViewDefault::processTarget( const Bu::FString &/*sProfile*/,
78 const Target &rTarget )
79{
80 iCurrent++;
81
82 int iPct = (iTotal>0)?(iCurrent*100/iTotal):(100);
83 sio << C_BR_WHITE << "[" << C_BR_GREEN << Fmt(3) << iPct
84 << "%" << C_BR_WHITE << "] " << C_BR_MAGENTA
85 << Fmt(10) << rTarget.getDisplay() << C_BR_WHITE
86 << ": " << rTarget.getOutputList().first() << C_RESET << sio.nl;
87}
88
89void ViewDefault::endTarget()
90{
91 iDepth--;
92}
93
94void ViewDefault::buildRequires( const Target &rTarget )
95{
96 int iPct = (iTotal>0)?(iCurrent*100/iTotal):(100);
97 sio << C_BR_WHITE << "[" << C_BR_GREEN << Fmt(3) << iPct
98 << "%" << C_BR_WHITE << "] " << C_BR_MAGENTA
99 << Fmt(10) << "deps" << C_BR_WHITE
100 << ": " << rTarget.getOutputList().first() << C_RESET << sio.nl;
101}
102
103void ViewDefault::cmdStarted( const Bu::FString &/*sCmd*/ )
104{
105}
106
107void ViewDefault::cmdFinished( const Bu::FString &sStdOut,
108 const Bu::FString &sStdErr, long /*iExit*/ )
109{
110 if( sStdOut )
111 {
112 Bu::FString::const_iterator b;
113 b = sStdOut.begin();
114 while( b )
115 {
116 Bu::FString::const_iterator e, max;
117 max = b + 78;
118 for( e = b; e != max && *e != '\n'; e++ ) { }
119 sio << C_BR_GREEN << "| " << C_RESET << FString( b, e ) << sio.nl;
120 b = e;
121 if( *b == '\n' )
122 b++;
123 }
124 sio << C_BR_GREEN << "\\-----" << C_RESET << sio.nl;
125 }
126 if( sStdErr )
127 {
128 Bu::FString::const_iterator b;
129 b = sStdErr.begin();
130 while( b )
131 {
132 Bu::FString::const_iterator e, max;
133 max = b + 78;
134 for( e = b; e != max && *e != '\n'; e++ ) { }
135 sio << C_BR_RED << "| " << C_RESET << FString( b, e ) << sio.nl;
136 b = e;
137 if( *b == '\n' )
138 b++;
139 }
140 sio << C_BR_RED << "\\-----" << C_RESET << sio.nl;
141 }
142 //sio << C_BR_WHITE << "[" << C_BR_GREEN << sStdOut << C_BR_WHITE << "]" << sio.nl;
143 //sio << C_BR_WHITE << "[" << C_BR_RED << sStdErr << C_BR_WHITE << "]" << sio.nl;
144}
145
146void ViewDefault::userError( const Bu::FString &sMsg )
147{
148 sio << C_BR_RED << "Error: " << sMsg << C_RESET << sio.nl;
149}
150
151void ViewDefault::userWarning( const Bu::FString &sMsg )
152{
153 sio << C_BR_YELLOW << "Warning: " << sMsg << C_RESET << sio.nl;
154}
155
156void ViewDefault::userNotice( const Bu::FString &sMsg )
157{
158 sio << C_BR_GREEN << "Notice: " << sMsg << C_RESET << sio.nl;
159}
160
161void ViewDefault::sysError( const Bu::FString &sMsg )
162{
163 sio << C_BR_RED << sMsg << C_RESET << sio.nl;
164}
165
166void ViewDefault::sysWarning( const Bu::FString &sMsg )
167{
168 sio << C_BR_YELLOW << sMsg << C_RESET << sio.nl;
169}
170
diff --git a/src/viewdefault.h b/src/viewdefault.h
new file mode 100644
index 0000000..c9a554d
--- /dev/null
+++ b/src/viewdefault.h
@@ -0,0 +1,42 @@
1#ifndef VIEW_DEFAULT_H
2#define VIEW_DEFAULT_H
3
4#include "view.h"
5
6class ViewDefault : public View
7{
8public:
9 ViewDefault();
10 virtual ~ViewDefault();
11
12 virtual void beginAction( const Bu::FString &sAction );
13 virtual void endAction();
14
15 virtual void skipTarget( const Bu::FString &sProfile,
16 const Target &rTarget );
17 virtual void beginTarget( const Bu::FString &sProfile,
18 const Target &rTarget );
19 virtual void processTarget( const Bu::FString &sProfile,
20 const Target &rTarget );
21 virtual void endTarget();
22
23 virtual void buildRequires( const Target &rTarget );
24 virtual void cmdStarted( const Bu::FString &sCmd );
25 virtual void cmdFinished( const Bu::FString &sStdOut,
26 const Bu::FString &sStdErr, long iExit );
27
28 virtual void userError( const Bu::FString &sMsg );
29 virtual void userWarning( const Bu::FString &sMsg );
30 virtual void userNotice( const Bu::FString &sMsg );
31
32 virtual void sysError( const Bu::FString &sMsg );
33 virtual void sysWarning( const Bu::FString &sMsg );
34
35private:
36 bool bFirst;
37 int iDepth;
38 int iTotal;
39 int iCurrent;
40};
41
42#endif
diff --git a/src/viewmake.cpp b/src/viewmake.cpp
new file mode 100644
index 0000000..39d1327
--- /dev/null
+++ b/src/viewmake.cpp
@@ -0,0 +1,86 @@
1#include "viewmake.h"
2#include "target.h"
3
4#include <bu/plugger.h>
5
6#include <bu/sio.h>
7using namespace Bu;
8
9PluginInterface3( pluginViewMake, make, ViewMake, View,
10 "Mike Buland", 0, 1 );
11
12ViewMake::ViewMake()
13{
14}
15
16ViewMake::~ViewMake()
17{
18}
19
20void ViewMake::beginAction( const Bu::FString &/*sAction*/ )
21{
22}
23
24void ViewMake::endAction()
25{
26}
27
28void ViewMake::skipTarget( const Bu::FString &/*sProfile*/,
29 const Target &/*rTarget*/ )
30{
31}
32
33void ViewMake::beginTarget( const Bu::FString &/*sProfile*/,
34 const Target &/*rTarget*/ )
35{
36}
37
38void ViewMake::processTarget( const Bu::FString &/*sProfile*/,
39 const Target &/*rTarget*/ )
40{
41}
42
43void ViewMake::endTarget()
44{
45}
46
47void ViewMake::buildRequires( const Target &/*rTarget*/ )
48{
49}
50
51void ViewMake::cmdStarted( const Bu::FString &sCmd )
52{
53 sio << sCmd << sio.nl;
54}
55
56void ViewMake::cmdFinished( const Bu::FString &sStdOut,
57 const Bu::FString &sStdErr, long /*iExit*/ )
58{
59 sio << sStdOut << sStdErr;
60}
61
62void ViewMake::userError( const Bu::FString &sMsg )
63{
64 sio << "Error: " << sMsg << sio.nl;
65}
66
67void ViewMake::userWarning( const Bu::FString &sMsg )
68{
69 sio << "Warning: " << sMsg << sio.nl;
70}
71
72void ViewMake::userNotice( const Bu::FString &sMsg )
73{
74 sio << "Notice: " << sMsg << sio.nl;
75}
76
77void ViewMake::sysError( const Bu::FString &sMsg )
78{
79 sio << sMsg << sio.nl;
80}
81
82void ViewMake::sysWarning( const Bu::FString &sMsg )
83{
84 sio << sMsg << sio.nl;
85}
86
diff --git a/src/viewmake.h b/src/viewmake.h
new file mode 100644
index 0000000..9100a86
--- /dev/null
+++ b/src/viewmake.h
@@ -0,0 +1,36 @@
1#ifndef VIEW_MAKE_H
2#define VIEW_MAKE_H
3
4#include "view.h"
5
6class ViewMake : public View
7{
8public:
9 ViewMake();
10 virtual ~ViewMake();
11
12 virtual void beginAction( const Bu::FString &sAction );
13 virtual void endAction();
14
15 virtual void skipTarget( const Bu::FString &sProfile,
16 const Target &rTarget );
17 virtual void beginTarget( const Bu::FString &sProfile,
18 const Target &rTarget );
19 virtual void processTarget( const Bu::FString &sProfile,
20 const Target &rTarget );
21 virtual void endTarget();
22
23 virtual void buildRequires( const Target &rTarget );
24 virtual void cmdStarted( const Bu::FString &sCmd );
25 virtual void cmdFinished( const Bu::FString &sStdOut,
26 const Bu::FString &sStdErr, long iExit );
27
28 virtual void userError( const Bu::FString &sMsg );
29 virtual void userWarning( const Bu::FString &sMsg );
30 virtual void userNotice( const Bu::FString &sMsg );
31
32 virtual void sysError( const Bu::FString &sMsg );
33 virtual void sysWarning( const Bu::FString &sMsg );
34};
35
36#endif
diff --git a/src/viewplugger.cpp b/src/viewplugger.cpp
new file mode 100644
index 0000000..6046f82
--- /dev/null
+++ b/src/viewplugger.cpp
@@ -0,0 +1,14 @@
1#include "viewplugger.h"
2
3extern Bu::PluginInfo pluginViewDefault;
4extern Bu::PluginInfo pluginViewMake;
5ViewPlugger::ViewPlugger()
6{
7 registerBuiltinPlugin( &pluginViewDefault );
8 registerBuiltinPlugin( &pluginViewMake );
9}
10
11ViewPlugger::~ViewPlugger()
12{
13}
14
diff --git a/src/viewplugger.h b/src/viewplugger.h
new file mode 100644
index 0000000..b58635c
--- /dev/null
+++ b/src/viewplugger.h
@@ -0,0 +1,20 @@
1#ifndef VIEW_PLUGGER_H
2#define VIEW_PLUGGER_H
3
4#include "view.h"
5#include <bu/plugger.h>
6#include <bu/singleton.h>
7
8class ViewPlugger : public Bu::Plugger<View>, public Bu::Singleton<ViewPlugger>
9{
10 friend class Bu::Singleton<ViewPlugger>;
11private:
12 ViewPlugger();
13
14public:
15 virtual ~ViewPlugger();
16
17private:
18};
19
20#endif