diff options
Diffstat (limited to 'src')
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 | |||
8 | Action::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 | |||
17 | Action::~Action() | ||
18 | { | ||
19 | delete pAst; | ||
20 | pAst = NULL; | ||
21 | } | ||
22 | |||
23 | const Bu::FString &Action::getName() const | ||
24 | { | ||
25 | return sName; | ||
26 | } | ||
27 | |||
28 | void Action::call( class Runner *pRunner ) | ||
29 | { | ||
30 | pRunner->run( (*(pRoot->getBranchBegin()+1)).begin() ); | ||
31 | } | ||
32 | |||
33 | Action *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 | |||
58 | Action *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 | |||
83 | Action *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 | |||
6 | class Action | ||
7 | { | ||
8 | public: | ||
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 | |||
20 | private: | ||
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 | |||
6 | Ast::Ast() | ||
7 | { | ||
8 | } | ||
9 | |||
10 | Ast::~Ast() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void 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 | |||
39 | void Ast::addNode( AstNode::Type eType, int iVal ) | ||
40 | { | ||
41 | addNode( new AstLeaf( eType, iVal ) ); | ||
42 | } | ||
43 | |||
44 | void Ast::addNode( AstNode::Type eType, float fVal ) | ||
45 | { | ||
46 | addNode( new AstLeaf( eType, fVal ) ); | ||
47 | } | ||
48 | |||
49 | void Ast::addNode( AstNode::Type eType, bool bVal ) | ||
50 | { | ||
51 | addNode( new AstLeaf( eType, bVal ) ); | ||
52 | } | ||
53 | |||
54 | void Ast::addNode( AstNode::Type eType, const Bu::FString &sVal ) | ||
55 | { | ||
56 | addNode( new AstLeaf( eType, sVal ) ); | ||
57 | } | ||
58 | |||
59 | void Ast::addNode( AstNode::Type eType, const char *sVal ) | ||
60 | { | ||
61 | addNode( new AstLeaf( eType, sVal ) ); | ||
62 | } | ||
63 | |||
64 | void Ast::addNode( AstNode *pNode ) | ||
65 | { | ||
66 | if( sBranch.isEmpty() ) | ||
67 | lNode.append( pNode ); | ||
68 | else | ||
69 | sBranch.peek()->addNode( pNode ); | ||
70 | } | ||
71 | |||
72 | void Ast::openBranch() | ||
73 | { | ||
74 | sBranch.peek()->addBranch(); | ||
75 | } | ||
76 | |||
77 | void Ast::closeNode() | ||
78 | { | ||
79 | sBranch.pop(); | ||
80 | } | ||
81 | |||
82 | Ast::NodeList::const_iterator Ast::getNodeBegin() const | ||
83 | { | ||
84 | return lNode.begin(); | ||
85 | } | ||
86 | |||
87 | Bu::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 | */ | ||
15 | class Ast | ||
16 | { | ||
17 | public: | ||
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 | |||
36 | private: | ||
37 | NodeList lNode; | ||
38 | typedef Bu::Stack<class AstBranch *> BranchStack; | ||
39 | BranchStack sBranch; | ||
40 | }; | ||
41 | |||
42 | Bu::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 | |||
3 | AstBranch::AstBranch( Type eType ) : | ||
4 | AstNode( eType ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | AstBranch::~AstBranch() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | void AstBranch::addBranch() | ||
13 | { | ||
14 | lBranch.append( NodeList() ); | ||
15 | } | ||
16 | |||
17 | void AstBranch::addNode( AstNode *pNode ) | ||
18 | { | ||
19 | lBranch.last().append( pNode ); | ||
20 | } | ||
21 | |||
22 | AstBranch::BranchList::const_iterator AstBranch::getBranchBegin() const | ||
23 | { | ||
24 | return lBranch.begin(); | ||
25 | } | ||
26 | |||
27 | Bu::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 | |||
8 | class AstBranch : public AstNode | ||
9 | { | ||
10 | public: | ||
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 | |||
21 | private: | ||
22 | BranchList lBranch; | ||
23 | }; | ||
24 | |||
25 | Bu::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 | |||
3 | AstLeaf::AstLeaf( Type eType ) : | ||
4 | AstNode( eType ), | ||
5 | sVal( NULL ) | ||
6 | { | ||
7 | } | ||
8 | |||
9 | AstLeaf::AstLeaf( Type eType, int iNew ) : | ||
10 | AstNode( eType ), | ||
11 | sVal( NULL ) | ||
12 | { | ||
13 | setIntValue( iNew ); | ||
14 | } | ||
15 | |||
16 | AstLeaf::AstLeaf( Type eType, float fNew ) : | ||
17 | AstNode( eType ), | ||
18 | sVal( NULL ) | ||
19 | { | ||
20 | setFloatValue( fNew ); | ||
21 | } | ||
22 | |||
23 | AstLeaf::AstLeaf( Type eType, bool bNew ) : | ||
24 | AstNode( eType ), | ||
25 | sVal( NULL ) | ||
26 | { | ||
27 | setBoolValue( bNew ); | ||
28 | } | ||
29 | |||
30 | AstLeaf::AstLeaf( Type eType, const Bu::FString &sNew ) : | ||
31 | AstNode( eType ), | ||
32 | sVal( NULL ) | ||
33 | { | ||
34 | setStrValue( sNew ); | ||
35 | } | ||
36 | |||
37 | AstLeaf::AstLeaf( Type eType, const char *sNew ) : | ||
38 | AstNode( eType ), | ||
39 | sVal( NULL ) | ||
40 | { | ||
41 | setStrValue( sNew ); | ||
42 | } | ||
43 | |||
44 | AstLeaf::~AstLeaf() | ||
45 | { | ||
46 | if( getDataType() == typeDataString ) | ||
47 | delete sVal; | ||
48 | } | ||
49 | |||
50 | void AstLeaf::setIntValue( int iNew ) | ||
51 | { | ||
52 | if( getDataType() != typeDataInt ) | ||
53 | throw Bu::ExceptionBase("Type is not int."); | ||
54 | iVal = iNew; | ||
55 | } | ||
56 | |||
57 | void AstLeaf::setFloatValue( float fNew ) | ||
58 | { | ||
59 | if( getDataType() != typeDataFloat ) | ||
60 | throw Bu::ExceptionBase("Type is not float."); | ||
61 | fVal = fNew; | ||
62 | } | ||
63 | |||
64 | void AstLeaf::setBoolValue( bool bNew ) | ||
65 | { | ||
66 | if( getDataType() != typeDataBool ) | ||
67 | throw Bu::ExceptionBase("Type is not bool."); | ||
68 | bVal = bNew; | ||
69 | } | ||
70 | |||
71 | void 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 | |||
81 | int AstLeaf::getIntValue() const | ||
82 | { | ||
83 | if( getDataType() != typeDataInt ) | ||
84 | throw Bu::ExceptionBase("Type is not int."); | ||
85 | return iVal; | ||
86 | } | ||
87 | |||
88 | float AstLeaf::getFloatValue() const | ||
89 | { | ||
90 | if( getDataType() != typeDataFloat ) | ||
91 | throw Bu::ExceptionBase("Type is not float."); | ||
92 | return fVal; | ||
93 | } | ||
94 | |||
95 | bool AstLeaf::getBoolValue() const | ||
96 | { | ||
97 | if( getDataType() != typeDataBool ) | ||
98 | throw Bu::ExceptionBase("Type is not bool."); | ||
99 | return bVal; | ||
100 | } | ||
101 | |||
102 | Bu::FString &AstLeaf::getStrValue() const | ||
103 | { | ||
104 | if( getDataType() != typeDataString ) | ||
105 | throw Bu::ExceptionBase("Type is not string."); | ||
106 | return *sVal; | ||
107 | } | ||
108 | |||
109 | Bu::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 | |||
8 | class AstLeaf : public AstNode | ||
9 | { | ||
10 | public: | ||
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 | |||
29 | private: | ||
30 | union | ||
31 | { | ||
32 | int iVal; | ||
33 | float fVal; | ||
34 | bool bVal; | ||
35 | Bu::FString *sVal; | ||
36 | }; | ||
37 | }; | ||
38 | |||
39 | Bu::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 | |||
5 | AstNode::AstNode( Type eType ) : | ||
6 | eType( eType ) | ||
7 | { | ||
8 | } | ||
9 | |||
10 | AstNode::~AstNode() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | Bu::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 | |||
28 | Bu::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 | |||
6 | class AstNode | ||
7 | { | ||
8 | public: | ||
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 | }; | ||
93 | public: | ||
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 | |||
101 | private: | ||
102 | Type eType; | ||
103 | }; | ||
104 | |||
105 | Bu::Formatter &operator<<( Bu::Formatter &f, const AstNode &n ); | ||
106 | Bu::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 | |||
5 | char *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 | |||
12 | char *rstrdup( const char *sIn ) | ||
13 | { | ||
14 | char *sRet = new char[strlen(sIn)+1]; | ||
15 | strcpy( sRet, sIn ); | ||
16 | return sRet; | ||
17 | } | ||
18 | void build_error( YYLTYPE *locp, yyscan_t yyscanner, BuildParser &bld, const char *msg ); | ||
19 | |||
20 | Bu::FString sBuf; | ||
21 | int 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" | ||
5 | void 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 | |||
113 | root: | ||
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 | |||
129 | root_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 | |||
143 | include: TOK_INCLUDE STRING ';' { bld.include( $2, yyscanner, &yylloc ); } | ||
144 | ; | ||
145 | |||
146 | /* | ||
147 | * data related | ||
148 | */ | ||
149 | |||
150 | string: STRING { bld.xAst.addNode( AstNode::typeString, $1 ); } | ||
151 | ; | ||
152 | |||
153 | int: INT { bld.xAst.addNode( AstNode::typeInt, $1 ); } | ||
154 | ; | ||
155 | |||
156 | float: FLOAT { bld.xAst.addNode( AstNode::typeFloat, $1 ); } | ||
157 | ; | ||
158 | |||
159 | bool: BOOL { bld.xAst.addNode( AstNode::typeBool, (bool)$1 ); } | ||
160 | ; | ||
161 | |||
162 | null: TOK_NULL { bld.xAst.addNode( AstNode::typeNull ); } | ||
163 | |||
164 | literal: string | ||
165 | | int | ||
166 | | float | ||
167 | | bool | ||
168 | | null | ||
169 | ; | ||
170 | |||
171 | variable: UNDEF /*VARIABLE*/ { bld.xAst.addNode( AstNode::typeVariable, $1 ); } | ||
172 | |||
173 | list_core: | ||
174 | | { bld.xAst.openBranch(); } expr | ||
175 | | list_core ',' { bld.xAst.openBranch(); } expr | ||
176 | ; | ||
177 | |||
178 | list: '[' { | ||
179 | bld.xAst.addNode( AstNode::typeList ); | ||
180 | } list_core ']' { | ||
181 | bld.xAst.closeNode(); | ||
182 | } | ||
183 | ; | ||
184 | |||
185 | value_mods: | ||
186 | | value_mods '.' function | ||
187 | ; | ||
188 | |||
189 | value_core: variable | ||
190 | | literal | ||
191 | | function | ||
192 | | list | ||
193 | ; | ||
194 | |||
195 | value: value_core value_mods | ||
196 | ; | ||
197 | |||
198 | /* | ||
199 | * misc global things | ||
200 | */ | ||
201 | |||
202 | notify: 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 | /* | ||
207 | set_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 | |||
212 | set: TOK_SET { | ||
213 | bld.xAst.addNode( AstNode::typeSet ); | ||
214 | bld.xAst.openBranch(); | ||
215 | } variable set_rhs ';' { | ||
216 | bld.xAst.closeNode(); | ||
217 | } | ||
218 | ;*/ | ||
219 | |||
220 | unset: TOK_UNSET { | ||
221 | bld.xAst.addNode( AstNode::typeUnset ); | ||
222 | bld.xAst.openBranch(); | ||
223 | } variable ';' { | ||
224 | bld.xAst.closeNode(); | ||
225 | } | ||
226 | ; | ||
227 | |||
228 | export_rhs: '=' value | ||
229 | | | ||
230 | ; | ||
231 | |||
232 | export: TOK_EXPORT { | ||
233 | bld.xAst.addNode( AstNode::typeExport ); | ||
234 | bld.xAst.openBranch(); | ||
235 | } variable export_rhs ';' { | ||
236 | bld.xAst.closeNode(); | ||
237 | } | ||
238 | ; | ||
239 | |||
240 | func_params: | ||
241 | | func_param_list | ||
242 | ; | ||
243 | |||
244 | func_param_list: { bld.xAst.openBranch(); } value | ||
245 | | func_param_list ',' { bld.xAst.openBranch(); } value | ||
246 | ; | ||
247 | |||
248 | function: 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 | |||
257 | requires: TOK_REQUIRES { | ||
258 | bld.xAst.addNode( AstNode::typeRequires ); | ||
259 | bld.xAst.openBranch(); | ||
260 | } value ';' { | ||
261 | bld.xAst.closeNode(); | ||
262 | } | ||
263 | ; | ||
264 | |||
265 | type: 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 | |||
276 | expr: 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 | |||
338 | line_expr: { | ||
339 | bld.xAst.addNode( AstNode::typeExpr ); | ||
340 | bld.xAst.openBranch(); | ||
341 | } expr ';' | ||
342 | { | ||
343 | bld.xAst.closeNode(); | ||
344 | } | ||
345 | ; | ||
346 | |||
347 | if_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 | |||
358 | else: TOK_ELSE { bld.xAst.openBranch(); } | ||
359 | ; | ||
360 | |||
361 | root_if: if_core '{' root_sub_exprs '}' root_else { bld.xAst.closeNode(); } | ||
362 | ; | ||
363 | |||
364 | root_else: | ||
365 | | else '{' root_sub_exprs '}' | ||
366 | | else root_if | ||
367 | ; | ||
368 | |||
369 | target_if: if_core '{' target_exprs '}' target_else { bld.xAst.closeNode(); } | ||
370 | ; | ||
371 | |||
372 | target_else: | ||
373 | | else '{' target_exprs '}' | ||
374 | | else target_if | ||
375 | ; | ||
376 | |||
377 | rule_if: if_core '{' rule_exprs '}' rule_else { bld.xAst.closeNode(); } | ||
378 | ; | ||
379 | |||
380 | rule_else: | ||
381 | | else '{' rule_exprs '}' | ||
382 | | else rule_if | ||
383 | ; | ||
384 | |||
385 | function_if: if_core '{' function_exprs '}' function_else | ||
386 | { bld.xAst.closeNode(); } | ||
387 | ; | ||
388 | |||
389 | function_else: | ||
390 | | else '{' function_exprs '}' | ||
391 | | else function_if | ||
392 | ; | ||
393 | |||
394 | /* | ||
395 | * loops | ||
396 | */ | ||
397 | |||
398 | for_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 | |||
408 | root_for: for_base '{' root_sub_exprs '}' { bld.xAst.closeNode(); } | ||
409 | ; | ||
410 | |||
411 | target_for: for_base '{' target_exprs '}' { bld.xAst.closeNode(); } | ||
412 | ; | ||
413 | |||
414 | rule_for: for_base '{' rule_exprs '}' { bld.xAst.closeNode(); } | ||
415 | ; | ||
416 | |||
417 | function_for: for_base '{' function_exprs '}' { bld.xAst.closeNode(); } | ||
418 | ; | ||
419 | |||
420 | /* | ||
421 | * functions | ||
422 | */ | ||
423 | |||
424 | function_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 | |||
436 | param_defs: | ||
437 | | param_def_list | ||
438 | ; | ||
439 | |||
440 | param_def_list: variable | ||
441 | | param_def_list ',' variable | ||
442 | ; | ||
443 | |||
444 | function_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 | |||
457 | return: 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 | |||
469 | action_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 | |||
483 | profile: 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 | |||
493 | profile_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 | |||
510 | target: 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 | |||
520 | target_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 | |||
536 | target_input: TOK_INPUT { | ||
537 | bld.xAst.addNode( AstNode::typeInput ); | ||
538 | bld.xAst.openBranch(); | ||
539 | } expr ';' { | ||
540 | bld.xAst.closeNode(); | ||
541 | } | ||
542 | ; | ||
543 | |||
544 | target_rule: TOK_RULE { | ||
545 | bld.xAst.addNode( AstNode::typeRule ); | ||
546 | bld.xAst.openBranch(); | ||
547 | } string ';' { | ||
548 | bld.xAst.closeNode(); | ||
549 | } | ||
550 | ; | ||
551 | |||
552 | condition: 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 | |||
567 | rule: 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 | |||
577 | rule_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 | |||
590 | rule_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 | |||
605 | rule_input: TOK_INPUT { | ||
606 | bld.xAst.addNode( AstNode::typeInput ); | ||
607 | bld.xAst.openBranch(); | ||
608 | } rule_input_func ';' { | ||
609 | bld.xAst.closeNode(); | ||
610 | } | ||
611 | ; | ||
612 | |||
613 | output: 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 | */ | ||
624 | config: 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 | |||
650 | config_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 | |||
659 | display: TOK_DISPLAY STRING ';' { | ||
660 | bld.xAst.addNode( AstNode::typeDisplay, $2 ); | ||
661 | } | ||
662 | ; | ||
663 | |||
664 | config_type: TOK_TYPE { | ||
665 | bld.xAst.addNode( AstNode::typeType ); | ||
666 | bld.xAst.openBranch(); | ||
667 | } type ';' { | ||
668 | bld.xAst.closeNode(); | ||
669 | } | ||
670 | ; | ||
671 | |||
672 | default: TOK_DEFAULT { | ||
673 | bld.xAst.addNode( AstNode::typeDefault ); | ||
674 | bld.xAst.openBranch(); | ||
675 | } literal ';' { | ||
676 | bld.xAst.closeNode(); | ||
677 | } | ||
678 | ; | ||
679 | |||
680 | value_key_val: value ';' | ||
681 | | '{' function_exprs '}' /* inline function */ | ||
682 | |||
683 | value_key: TOK_VALUE { | ||
684 | bld.xAst.addNode( AstNode::typeValue ); | ||
685 | bld.xAst.openBranch(); | ||
686 | } value_key_val { | ||
687 | bld.xAst.closeNode(); | ||
688 | } | ||
689 | ; | ||
690 | |||
691 | allow: TOK_ALLOW { | ||
692 | bld.xAst.addNode( AstNode::typeAllow ); | ||
693 | bld.xAst.openBranch(); | ||
694 | } value ';' { | ||
695 | bld.xAst.closeNode(); | ||
696 | } | ||
697 | ; | ||
698 | |||
699 | cache: 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 | */ | ||
708 | process_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 | |||
719 | tag: 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 | |||
733 | void 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" | ||
6 | using Bu::sio; | ||
7 | |||
8 | BuildParser::BuildParser( Ast &rAst ) : | ||
9 | xAst( rAst ) | ||
10 | { | ||
11 | lIncludePaths.append("./"); | ||
12 | } | ||
13 | |||
14 | BuildParser::~BuildParser() | ||
15 | { | ||
16 | } | ||
17 | |||
18 | int build_parse( yyscan_t yyscanner, BuildParser &bld ); | ||
19 | |||
20 | void 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 | |||
38 | bool 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 | |||
51 | bool 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 | |||
62 | void 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 | |||
107 | void 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 | |||
115 | void 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 | |||
123 | void 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 | |||
10 | class BuildParser | ||
11 | { | ||
12 | public: | ||
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 | |||
30 | private: | ||
31 | Bu::Stack<Bu::FString> sFilename; | ||
32 | Bu::Stack<YYLTYPE> sLocation; | ||
33 | StrList lIncludePaths; | ||
34 | }; | ||
35 | |||
36 | typedef void * yyscan_t; | ||
37 | #define YY_DECL int build_lex( YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner, BuildParser &b ) | ||
38 | YY_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 | |||
3 | Condition::Condition() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Condition::~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 | |||
4 | class Condition | ||
5 | { | ||
6 | public: | ||
7 | Condition(); | ||
8 | virtual ~Condition(); | ||
9 | |||
10 | virtual bool shouldExec( class Runner &r, class Target &rTarget )=0; | ||
11 | virtual Condition *clone()=0; | ||
12 | |||
13 | private: | ||
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 | |||
4 | ConditionAlways::ConditionAlways() | ||
5 | { | ||
6 | } | ||
7 | |||
8 | ConditionAlways::~ConditionAlways() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | bool ConditionAlways::shouldExec( class Runner &/*r*/, Target &/*rTarget*/ ) | ||
13 | { | ||
14 | return true; | ||
15 | } | ||
16 | |||
17 | Condition *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 | |||
6 | class ConditionAlways : public Condition | ||
7 | { | ||
8 | public: | ||
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> | ||
9 | using namespace Bu; | ||
10 | |||
11 | ConditionFileTime::ConditionFileTime() | ||
12 | { | ||
13 | } | ||
14 | |||
15 | ConditionFileTime::~ConditionFileTime() | ||
16 | { | ||
17 | } | ||
18 | |||
19 | bool 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 | |||
69 | Condition *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 | |||
6 | class ConditionFileTime : public Condition | ||
7 | { | ||
8 | public: | ||
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 | |||
4 | ConditionNever::ConditionNever() | ||
5 | { | ||
6 | } | ||
7 | |||
8 | ConditionNever::~ConditionNever() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | bool ConditionNever::shouldExec( class Runner &/*r*/, Target &/*rTarget*/ ) | ||
13 | { | ||
14 | return false; | ||
15 | } | ||
16 | |||
17 | Condition *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 | |||
6 | class ConditionNever : public Condition | ||
7 | { | ||
8 | public: | ||
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> | ||
25 | using namespace Bu; | ||
26 | |||
27 | Context::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 | |||
45 | Context::~Context() | ||
46 | { | ||
47 | } | ||
48 | |||
49 | void 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 | |||
57 | void Context::addRule( Rule *pRule ) | ||
58 | { | ||
59 | hRule.insert( pRule->getName(), pRule ); | ||
60 | } | ||
61 | |||
62 | void Context::addFunction( Function *pFunction ) | ||
63 | { | ||
64 | pFunction->setContext( this ); | ||
65 | hFunction.insert( pFunction->getName(), pFunction ); | ||
66 | } | ||
67 | |||
68 | void 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 | |||
82 | void Context::addAction( Action *pAction ) | ||
83 | { | ||
84 | hAction.insert( pAction->getName(), pAction ); | ||
85 | } | ||
86 | |||
87 | Action *Context::getAction( const Bu::FString &sName ) | ||
88 | { | ||
89 | return hAction.get( sName ); | ||
90 | } | ||
91 | |||
92 | void 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 | |||
101 | void 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 | |||
109 | TargetList &Context::getTag( const Bu::FString &sTag ) | ||
110 | { | ||
111 | return hTag.get( sTag ); | ||
112 | } | ||
113 | |||
114 | Variable &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 | |||
126 | void 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 | |||
137 | void Context::pushScope() | ||
138 | { | ||
139 | VarHash h; | ||
140 | if( !sVars.isEmpty() ) | ||
141 | h = sVars.peek(); | ||
142 | sVars.push( h ); | ||
143 | } | ||
144 | |||
145 | void 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 | |||
159 | VarHash &Context::getScope() | ||
160 | { | ||
161 | return sVars.first(); | ||
162 | } | ||
163 | |||
164 | void Context::popScope() | ||
165 | { | ||
166 | sVars.pop(); | ||
167 | } | ||
168 | |||
169 | Variable 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> | ||
180 | using namespace Bu; | ||
181 | Bu::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 | |||
256 | Target *Context::getTarget( const Bu::FString &sOutput ) | ||
257 | { | ||
258 | return hTarget.get( sOutput ); | ||
259 | } | ||
260 | |||
261 | TargetList 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 | |||
272 | void 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 | |||
345 | void 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 | |||
420 | void 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 | |||
431 | void 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 | |||
447 | void 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 | |||
478 | void Context::setView( View *pNewView ) | ||
479 | { | ||
480 | delete pView; | ||
481 | pView = pNewView; | ||
482 | } | ||
483 | |||
484 | View *Context::getView() | ||
485 | { | ||
486 | return pView; | ||
487 | } | ||
488 | |||
489 | Bu::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 | |||
498 | void 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 | |||
9 | class Target; | ||
10 | class Rule; | ||
11 | class Function; | ||
12 | class Action; | ||
13 | class View; | ||
14 | |||
15 | class Context | ||
16 | { | ||
17 | friend Bu::Formatter &operator<<( Bu::Formatter &f, const Context &c ); | ||
18 | public: | ||
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 | |||
79 | private: | ||
80 | void buildTargetTree( class Runner &r, class Target *pTarget, const Bu::FString &sInput, class Rule *pMaster, StrList &lNewIns ); | ||
81 | |||
82 | private: | ||
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 | |||
99 | Bu::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 | |||
3 | Function::Function() : | ||
4 | pContext( NULL ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Function::~Function() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | void 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 | |||
7 | class Function | ||
8 | { | ||
9 | public: | ||
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 | |||
19 | protected: | ||
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 | |||
7 | FunctionAst::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 | |||
16 | FunctionAst::~FunctionAst() | ||
17 | { | ||
18 | } | ||
19 | |||
20 | Bu::FString FunctionAst::getName() const | ||
21 | { | ||
22 | return sName; | ||
23 | } | ||
24 | |||
25 | Variable 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 | |||
6 | class FunctionAst : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
15 | private: | ||
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 | |||
3 | FunctionDirName::FunctionDirName() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | FunctionDirName::~FunctionDirName() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | Bu::FString FunctionDirName::getName() const | ||
12 | { | ||
13 | return "dirName"; | ||
14 | } | ||
15 | |||
16 | Variable 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 | |||
6 | class FunctionDirName : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
8 | FunctionDirs::FunctionDirs() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | FunctionDirs::~FunctionDirs() | ||
13 | { | ||
14 | } | ||
15 | |||
16 | Bu::FString FunctionDirs::getName() const | ||
17 | { | ||
18 | return "dirs"; | ||
19 | } | ||
20 | |||
21 | Variable 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 | |||
6 | class FunctionDirs : public Function | ||
7 | { | ||
8 | public: | ||
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> | ||
7 | using namespace Bu; | ||
8 | |||
9 | FunctionExecute::FunctionExecute() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | FunctionExecute::~FunctionExecute() | ||
14 | { | ||
15 | } | ||
16 | |||
17 | Bu::FString FunctionExecute::getName() const | ||
18 | { | ||
19 | return "execute"; | ||
20 | } | ||
21 | |||
22 | Variable 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 | |||
6 | class FunctionExecute : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
5 | FunctionExists::FunctionExists() | ||
6 | { | ||
7 | } | ||
8 | |||
9 | FunctionExists::~FunctionExists() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | Bu::FString FunctionExists::getName() const | ||
14 | { | ||
15 | return "exists"; | ||
16 | } | ||
17 | |||
18 | Variable 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 | |||
6 | class FunctionExists : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
3 | FunctionFileName::FunctionFileName() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | FunctionFileName::~FunctionFileName() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | Bu::FString FunctionFileName::getName() const | ||
12 | { | ||
13 | return "fileName"; | ||
14 | } | ||
15 | |||
16 | Variable 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 | |||
6 | class FunctionFileName : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
8 | FunctionFiles::FunctionFiles() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | FunctionFiles::~FunctionFiles() | ||
13 | { | ||
14 | } | ||
15 | |||
16 | Bu::FString FunctionFiles::getName() const | ||
17 | { | ||
18 | return "files"; | ||
19 | } | ||
20 | |||
21 | Variable 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 | |||
6 | class FunctionFiles : public Function | ||
7 | { | ||
8 | public: | ||
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> | ||
5 | using namespace Bu; | ||
6 | |||
7 | FunctionGetMakeDeps::FunctionGetMakeDeps() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | FunctionGetMakeDeps::~FunctionGetMakeDeps() | ||
12 | { | ||
13 | } | ||
14 | |||
15 | Bu::FString FunctionGetMakeDeps::getName() const | ||
16 | { | ||
17 | return "getMakeDeps"; | ||
18 | } | ||
19 | |||
20 | Variable 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 | |||
6 | class FunctionGetMakeDeps : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
5 | FunctionMatches::FunctionMatches() | ||
6 | { | ||
7 | } | ||
8 | |||
9 | FunctionMatches::~FunctionMatches() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | Bu::FString FunctionMatches::getName() const | ||
14 | { | ||
15 | return "matches"; | ||
16 | } | ||
17 | |||
18 | bool 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 | |||
86 | bool 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 | |||
107 | Variable 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 | |||
6 | class FunctionMatches : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
3 | FunctionReplace::FunctionReplace() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | FunctionReplace::~FunctionReplace() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | Bu::FString FunctionReplace::getName() const | ||
12 | { | ||
13 | return "replace"; | ||
14 | } | ||
15 | |||
16 | Variable 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 | |||
6 | class FunctionReplace : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
5 | FunctionTargets::FunctionTargets() | ||
6 | { | ||
7 | } | ||
8 | |||
9 | FunctionTargets::~FunctionTargets() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | Bu::FString FunctionTargets::getName() const | ||
14 | { | ||
15 | return "targets"; | ||
16 | } | ||
17 | |||
18 | Variable 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 | |||
6 | class FunctionTargets : public Function | ||
7 | { | ||
8 | public: | ||
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> | ||
5 | using namespace Bu; | ||
6 | |||
7 | FunctionToString::FunctionToString() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | FunctionToString::~FunctionToString() | ||
12 | { | ||
13 | } | ||
14 | |||
15 | Bu::FString FunctionToString::getName() const | ||
16 | { | ||
17 | return "toString"; | ||
18 | } | ||
19 | |||
20 | Variable 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 | |||
6 | class FunctionToString : public Function | ||
7 | { | ||
8 | public: | ||
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> | ||
6 | using namespace Bu; | ||
7 | |||
8 | FunctionUnlink::FunctionUnlink() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | FunctionUnlink::~FunctionUnlink() | ||
13 | { | ||
14 | } | ||
15 | |||
16 | Bu::FString FunctionUnlink::getName() const | ||
17 | { | ||
18 | return "unlink"; | ||
19 | } | ||
20 | |||
21 | Variable 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 | |||
6 | class FunctionUnlink : public Function | ||
7 | { | ||
8 | public: | ||
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 | |||
16 | extern char **environ; | ||
17 | |||
18 | using namespace Bu; | ||
19 | |||
20 | class Options : public Bu::OptParser | ||
21 | { | ||
22 | public: | ||
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 | |||
122 | int 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> | ||
12 | using namespace Bu; | ||
13 | |||
14 | Profile::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 | |||
26 | Profile::Profile( const Profile &rSrc ) : | ||
27 | sName( rSrc.sName ), | ||
28 | pRoot( rSrc.pRoot ), | ||
29 | pCond( rSrc.pCond->clone() ), | ||
30 | pAst( NULL ) | ||
31 | { | ||
32 | } | ||
33 | |||
34 | Profile::~Profile() | ||
35 | { | ||
36 | delete pAst; | ||
37 | pAst = NULL; | ||
38 | } | ||
39 | |||
40 | const Bu::FString &Profile::getName() const | ||
41 | { | ||
42 | return sName; | ||
43 | } | ||
44 | |||
45 | const AstBranch *Profile::getRoot() const | ||
46 | { | ||
47 | return pRoot; | ||
48 | } | ||
49 | |||
50 | const Condition *Profile::getCond() const | ||
51 | { | ||
52 | return pCond; | ||
53 | } | ||
54 | |||
55 | bool Profile::shouldExec( class Runner &r, class Target &rTarget ) const | ||
56 | { | ||
57 | return pCond->shouldExec( r, rTarget ); | ||
58 | } | ||
59 | |||
60 | Profile *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 | |||
84 | void 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 | |||
6 | class Profile | ||
7 | { | ||
8 | public: | ||
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 | |||
20 | private: | ||
21 | void setCondition(); | ||
22 | |||
23 | private: | ||
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> | ||
12 | using namespace Bu; | ||
13 | |||
14 | Rule::Rule( const Bu::FString &sName ) : | ||
15 | sName( sName ), | ||
16 | pInput( NULL ) | ||
17 | { | ||
18 | } | ||
19 | |||
20 | Rule::~Rule() | ||
21 | { | ||
22 | } | ||
23 | |||
24 | const Bu::FString &Rule::getName() const | ||
25 | { | ||
26 | return sName; | ||
27 | } | ||
28 | |||
29 | void Rule::setInput( const AstBranch *pNewInput ) | ||
30 | { | ||
31 | pInput = pNewInput; | ||
32 | } | ||
33 | |||
34 | const AstBranch *Rule::getInput() const | ||
35 | { | ||
36 | return pInput; | ||
37 | } | ||
38 | |||
39 | bool Rule::hasOutputs() const | ||
40 | { | ||
41 | return !lOutput.isEmpty(); | ||
42 | } | ||
43 | |||
44 | void Rule::addOutput( const AstBranch *pNewOutput ) | ||
45 | { | ||
46 | lOutput.append( pNewOutput ); | ||
47 | } | ||
48 | |||
49 | void 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 | |||
63 | void 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 | |||
76 | Target *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 | |||
116 | bool 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 | |||
133 | void Rule::addTag( const Bu::FString &sTag ) | ||
134 | { | ||
135 | lsTags.append( sTag ); | ||
136 | } | ||
137 | |||
138 | const StrList &Rule::getTagList() const | ||
139 | { | ||
140 | return lsTags; | ||
141 | } | ||
142 | |||
143 | void Rule::setDisplay( const Bu::FString &sStr ) | ||
144 | { | ||
145 | sDisplay = sStr; | ||
146 | } | ||
147 | |||
148 | const Bu::FString &Rule::getDisplay() const | ||
149 | { | ||
150 | return ((bool)sDisplay)?(sDisplay):(sName); | ||
151 | } | ||
152 | |||
153 | void Rule::addRequires( const AstBranch *pBr ) | ||
154 | { | ||
155 | lRequires.append( pBr ); | ||
156 | } | ||
157 | |||
158 | Bu::Formatter &operator<<( Bu::Formatter &f, const Rule &/*t*/ ) | ||
159 | { | ||
160 | return f << "rule"; | ||
161 | } | ||
162 | |||
163 | template<> 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 | |||
7 | class Rule | ||
8 | { | ||
9 | friend Bu::Formatter &operator<<( Bu::Formatter &f, const Rule &t ); | ||
10 | public: | ||
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 | |||
36 | private: | ||
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 | |||
46 | Bu::Formatter &operator<<( Bu::Formatter &f, const Rule &t ); | ||
47 | |||
48 | namespace 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" | ||
17 | using Bu::sio; | ||
18 | |||
19 | Runner::Runner( Ast &rAst, Context &rCont ) : | ||
20 | rAst( rAst ), | ||
21 | rCont( rCont ), | ||
22 | pCurTarget( NULL ), | ||
23 | pCurRule( NULL ) | ||
24 | { | ||
25 | } | ||
26 | |||
27 | Runner::~Runner() | ||
28 | { | ||
29 | } | ||
30 | |||
31 | void 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 | |||
48 | Variable 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 | |||
63 | Variable Runner::execExpr( AstBranch::NodeList::const_iterator e ) | ||
64 | { | ||
65 | Variable vBlank; | ||
66 | return execExpr( e, vBlank ); | ||
67 | } | ||
68 | |||
69 | Variable 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 | |||
349 | void 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 | |||
361 | Variable 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 | |||
809 | void 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 | |||
817 | void 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 | |||
832 | Context &Runner::getContext() | ||
833 | { | ||
834 | return rCont; | ||
835 | } | ||
836 | |||
837 | Target *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 | |||
867 | Rule *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 | |||
881 | Variable 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 | |||
6 | class Runner | ||
7 | { | ||
8 | public: | ||
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 | |||
28 | private: | ||
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 | |||
36 | private: | ||
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> | ||
16 | using namespace Bu; | ||
17 | |||
18 | Target::Target( bool bExplicit ) : | ||
19 | bExplicit( bExplicit ), | ||
20 | bRun( false ), | ||
21 | iDepCount( 0 ) | ||
22 | { | ||
23 | } | ||
24 | |||
25 | Target::Target( const Bu::FString &sOutput, bool bExplicit ) : | ||
26 | bExplicit( bExplicit ), | ||
27 | lsOutput( sOutput ), | ||
28 | iDepCount( 0 ) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | Target::~Target() | ||
33 | { | ||
34 | } | ||
35 | |||
36 | void Target::addInput( const Bu::FString &sInput ) | ||
37 | { | ||
38 | lsInput.append( sInput ); | ||
39 | } | ||
40 | |||
41 | const StrList &Target::getInputList() const | ||
42 | { | ||
43 | return lsInput; | ||
44 | } | ||
45 | |||
46 | void 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 | |||
64 | void Target::addRequires( const Bu::FString &sReq ) | ||
65 | { | ||
66 | lsRequires.append( sReq ); | ||
67 | } | ||
68 | |||
69 | void Target::addRequires( const AstBranch *pBr ) | ||
70 | { | ||
71 | lbRequires.append( pBr ); | ||
72 | } | ||
73 | |||
74 | const StrList &Target::getRequiresList() const | ||
75 | { | ||
76 | return lsRequires; | ||
77 | } | ||
78 | |||
79 | void 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 | |||
113 | void Target::addOutput( const Bu::FString &sOutput ) | ||
114 | { | ||
115 | lsOutput.append( sOutput ); | ||
116 | } | ||
117 | |||
118 | const StrList &Target::getOutputList() const | ||
119 | { | ||
120 | return lsOutput; | ||
121 | } | ||
122 | |||
123 | void Target::setPrefix( const Bu::FString &sPrefix ) | ||
124 | { | ||
125 | this->sPrefix = sPrefix; | ||
126 | } | ||
127 | |||
128 | const Bu::FString &Target::getPrefix() const | ||
129 | { | ||
130 | return sPrefix; | ||
131 | } | ||
132 | |||
133 | void Target::setRule( const Bu::FString &sRule ) | ||
134 | { | ||
135 | this->sRule = sRule; | ||
136 | } | ||
137 | |||
138 | const Bu::FString &Target::getRule() const | ||
139 | { | ||
140 | return sRule; | ||
141 | } | ||
142 | |||
143 | bool Target::hasRule() const | ||
144 | { | ||
145 | return !sRule.isEmpty(); | ||
146 | } | ||
147 | |||
148 | bool Target::isExplicit() const | ||
149 | { | ||
150 | return bExplicit; | ||
151 | } | ||
152 | |||
153 | void Target::addDep( Target *pDep ) | ||
154 | { | ||
155 | lDeps.append( pDep ); | ||
156 | } | ||
157 | |||
158 | const TargetList &Target::getDepList() const | ||
159 | { | ||
160 | return lDeps; | ||
161 | } | ||
162 | |||
163 | void 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 | |||
177 | void Target::addProfile( const class Profile *pSrc ) | ||
178 | { | ||
179 | hProfiles.insert( pSrc->getName(), new Profile( *pSrc ) ); | ||
180 | } | ||
181 | |||
182 | bool Target::hasProfile( const Bu::FString &sName ) const | ||
183 | { | ||
184 | return hProfiles.has( sName ); | ||
185 | } | ||
186 | |||
187 | const Profile *Target::getProfile( const Bu::FString &sName ) const | ||
188 | { | ||
189 | return hProfiles.get( sName ); | ||
190 | } | ||
191 | |||
192 | void Target::setVars( const VarHash &hNewVars ) | ||
193 | { | ||
194 | hVars = hNewVars; | ||
195 | } | ||
196 | |||
197 | const VarHash &Target::getVars() const | ||
198 | { | ||
199 | return hVars; | ||
200 | } | ||
201 | |||
202 | void Target::setDisplay( const Bu::FString &sNewDisplay ) | ||
203 | { | ||
204 | if( !sDisplay ) | ||
205 | sDisplay = sNewDisplay; | ||
206 | } | ||
207 | |||
208 | const Bu::FString &Target::getDisplay() const | ||
209 | { | ||
210 | return sDisplay; | ||
211 | } | ||
212 | |||
213 | void 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 | |||
252 | void 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 | |||
263 | bool Target::hasRun() | ||
264 | { | ||
265 | return bRun; | ||
266 | } | ||
267 | |||
268 | void 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 | |||
303 | void 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 | |||
334 | void 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 | |||
344 | void 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 | |||
359 | int Target::getDepCount() const | ||
360 | { | ||
361 | return iDepCount; | ||
362 | } | ||
363 | |||
364 | void 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 | |||
383 | Bu::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 | |||
398 | template<> 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 | |||
7 | class Target | ||
8 | { | ||
9 | friend Bu::Formatter &operator<<( Bu::Formatter &f, const Target &t ); | ||
10 | public: | ||
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 | |||
62 | private: | ||
63 | void mergeUnder( const VarHash &hVars ); | ||
64 | void merge( StrList &lOut, const StrList &lIn ); | ||
65 | |||
66 | private: | ||
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 | |||
82 | Bu::Formatter &operator<<( Bu::Formatter &f, const Target &t ); | ||
83 | |||
84 | namespace 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 | |||
8 | typedef Bu::List<Bu::FString> StrList; | ||
9 | |||
10 | class Variable; | ||
11 | typedef Bu::List<Variable> VarList; | ||
12 | typedef Bu::Hash<Bu::FString, Variable> VarHash; | ||
13 | |||
14 | class Condition; | ||
15 | |||
16 | class Target; | ||
17 | typedef Bu::List<Target *> TargetList; | ||
18 | class Profile; | ||
19 | typedef Bu::Hash<Bu::FString, Profile *> ProfileHash; | ||
20 | |||
21 | class AstNode; | ||
22 | class AstBranch; | ||
23 | class AstLeaf; | ||
24 | typedef 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" | ||
4 | using Bu::sio; | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | |||
8 | Variable::Variable() : | ||
9 | eType( typeNone ) | ||
10 | { | ||
11 | memset( &uVal, 0, sizeof(uVal) ); | ||
12 | } | ||
13 | |||
14 | Variable::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 | |||
28 | Variable::Variable( int iVal ) : | ||
29 | eType( typeInt ) | ||
30 | { | ||
31 | memset( &uVal, 0, sizeof(uVal) ); | ||
32 | uVal.iVal = iVal; | ||
33 | } | ||
34 | |||
35 | Variable::Variable( double fVal ) : | ||
36 | eType( typeFloat ) | ||
37 | { | ||
38 | memset( &uVal, 0, sizeof(uVal) ); | ||
39 | uVal.fVal = fVal; | ||
40 | } | ||
41 | |||
42 | Variable::Variable( bool bVal ) : | ||
43 | eType( typeBool ) | ||
44 | { | ||
45 | memset( &uVal, 0, sizeof(uVal) ); | ||
46 | uVal.bVal = bVal; | ||
47 | } | ||
48 | |||
49 | Variable::Variable( const Bu::FString &sVal ) : | ||
50 | eType( typeString ) | ||
51 | { | ||
52 | memset( &uVal, 0, sizeof(uVal) ); | ||
53 | uVal.sVal = new Bu::FString( sVal ); | ||
54 | } | ||
55 | |||
56 | Variable::Variable( const char *sVal ) : | ||
57 | eType( typeString ) | ||
58 | { | ||
59 | memset( &uVal, 0, sizeof(uVal) ); | ||
60 | uVal.sVal = new Bu::FString( sVal ); | ||
61 | } | ||
62 | |||
63 | Variable::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 | |||
81 | Variable::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 | |||
116 | Variable::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 | |||
134 | Variable::Variable( const VarList &lst ) | ||
135 | { | ||
136 | eType = typeList; | ||
137 | uVal.lVal = new VarList( lst ); | ||
138 | } | ||
139 | |||
140 | Variable::~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 | |||
152 | Variable Variable::mkRef( const Bu::FString &sVal ) | ||
153 | { | ||
154 | Variable v( typeRef ); | ||
155 | (*v.uVal.sVal) = sVal; | ||
156 | return v; | ||
157 | } | ||
158 | |||
159 | Variable::Type Variable::getType() const | ||
160 | { | ||
161 | return eType; | ||
162 | } | ||
163 | |||
164 | int Variable::getInt() const | ||
165 | { | ||
166 | if( eType != typeInt ) throw Bu::ExceptionBase("Wrong variable type."); | ||
167 | return uVal.iVal; | ||
168 | } | ||
169 | |||
170 | double Variable::getFloat() const | ||
171 | { | ||
172 | if( eType != typeFloat ) throw Bu::ExceptionBase("Wrong variable type."); | ||
173 | return uVal.fVal; | ||
174 | } | ||
175 | |||
176 | bool Variable::getBool() const | ||
177 | { | ||
178 | if( eType != typeBool ) throw Bu::ExceptionBase("Wrong variable type."); | ||
179 | return uVal.bVal; | ||
180 | } | ||
181 | |||
182 | const Bu::FString &Variable::getString() const | ||
183 | { | ||
184 | if( eType != typeString && eType != typeRef ) throw Bu::ExceptionBase("Wrong variable type."); | ||
185 | return *uVal.sVal; | ||
186 | } | ||
187 | |||
188 | const VarList &Variable::getList() const | ||
189 | { | ||
190 | if( eType != typeList ) throw Bu::ExceptionBase("Wrong variable type."); | ||
191 | return *uVal.lVal; | ||
192 | } | ||
193 | |||
194 | int 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 | |||
217 | double 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 | |||
240 | bool 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 | |||
266 | Bu::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 | |||
310 | VarList Variable::toList() const | ||
311 | { | ||
312 | if( eType == typeList ) | ||
313 | return *this; | ||
314 | return VarList( *this ); | ||
315 | } | ||
316 | |||
317 | Variable 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 | |||
348 | void 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 | |||
362 | VarList::iterator Variable::begin() | ||
363 | { | ||
364 | if( eType != typeList ) throw Bu::ExceptionBase("Wrong variable type."); | ||
365 | |||
366 | return uVal.lVal->begin(); | ||
367 | } | ||
368 | |||
369 | VarList::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 | |||
376 | void 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 | |||
408 | void Variable::doNot() | ||
409 | { | ||
410 | bool bVal = !toBool(); | ||
411 | reset( typeBool ); | ||
412 | uVal.bVal = bVal; | ||
413 | } | ||
414 | |||
415 | const 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 | |||
434 | const Variable &Variable::operator=( const int &rhs ) | ||
435 | { | ||
436 | reset( typeInt ); | ||
437 | uVal.iVal = rhs; | ||
438 | |||
439 | return *this; | ||
440 | } | ||
441 | |||
442 | const Variable &Variable::operator=( const double &rhs ) | ||
443 | { | ||
444 | reset( typeFloat ); | ||
445 | uVal.fVal = rhs; | ||
446 | |||
447 | return *this; | ||
448 | } | ||
449 | |||
450 | const Variable &Variable::operator=( const bool &rhs ) | ||
451 | { | ||
452 | reset( typeBool ); | ||
453 | uVal.bVal = rhs; | ||
454 | |||
455 | return *this; | ||
456 | } | ||
457 | |||
458 | const Variable &Variable::operator=( const Bu::FString &rhs ) | ||
459 | { | ||
460 | reset( typeString ); | ||
461 | uVal.sVal = new Bu::FString( rhs ); | ||
462 | |||
463 | return *this; | ||
464 | } | ||
465 | |||
466 | const 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 | |||
516 | const 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 | |||
551 | bool 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 | |||
583 | bool Variable::operator!=( const Variable &rhs ) const | ||
584 | { | ||
585 | return !(*this == rhs); | ||
586 | } | ||
587 | |||
588 | bool 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 | |||
620 | bool 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 | |||
652 | bool 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 | |||
684 | bool 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 | |||
716 | Variable 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 | |||
748 | Variable 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 | |||
780 | Variable 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 | |||
812 | Variable 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 | |||
844 | void 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 | |||
859 | Bu::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 | |||
875 | Bu::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 | */ | ||
9 | class Variable | ||
10 | { | ||
11 | public: | ||
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 | |||
24 | public: | ||
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 | |||
93 | private: | ||
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 | |||
107 | namespace Bu | ||
108 | { | ||
109 | class Formatter; | ||
110 | } | ||
111 | |||
112 | Bu::Formatter &operator<<( Bu::Formatter &f, const Variable::Type &t ); | ||
113 | Bu::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 | |||
3 | View::View() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | View::~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 | */ | ||
14 | class View | ||
15 | { | ||
16 | public: | ||
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 | |||
43 | private: | ||
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> | ||
7 | using namespace Bu; | ||
8 | |||
9 | PluginInterface3( 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 | |||
32 | ViewDefault::ViewDefault() : | ||
33 | bFirst( true ), | ||
34 | iDepth( 0 ), | ||
35 | iTotal( 0 ), | ||
36 | iCurrent( 0 ) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | ViewDefault::~ViewDefault() | ||
41 | { | ||
42 | } | ||
43 | |||
44 | void ViewDefault::beginAction( const Bu::FString &/*sAction*/ ) | ||
45 | { | ||
46 | } | ||
47 | |||
48 | void ViewDefault::endAction() | ||
49 | { | ||
50 | } | ||
51 | |||
52 | void ViewDefault::skipTarget( const Bu::FString &/*sProfile*/, | ||
53 | const Target &/*rTarget*/ ) | ||
54 | { | ||
55 | iCurrent++; | ||
56 | } | ||
57 | |||
58 | void 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 | |||
77 | void 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 | |||
89 | void ViewDefault::endTarget() | ||
90 | { | ||
91 | iDepth--; | ||
92 | } | ||
93 | |||
94 | void 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 | |||
103 | void ViewDefault::cmdStarted( const Bu::FString &/*sCmd*/ ) | ||
104 | { | ||
105 | } | ||
106 | |||
107 | void 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 | |||
146 | void ViewDefault::userError( const Bu::FString &sMsg ) | ||
147 | { | ||
148 | sio << C_BR_RED << "Error: " << sMsg << C_RESET << sio.nl; | ||
149 | } | ||
150 | |||
151 | void ViewDefault::userWarning( const Bu::FString &sMsg ) | ||
152 | { | ||
153 | sio << C_BR_YELLOW << "Warning: " << sMsg << C_RESET << sio.nl; | ||
154 | } | ||
155 | |||
156 | void ViewDefault::userNotice( const Bu::FString &sMsg ) | ||
157 | { | ||
158 | sio << C_BR_GREEN << "Notice: " << sMsg << C_RESET << sio.nl; | ||
159 | } | ||
160 | |||
161 | void ViewDefault::sysError( const Bu::FString &sMsg ) | ||
162 | { | ||
163 | sio << C_BR_RED << sMsg << C_RESET << sio.nl; | ||
164 | } | ||
165 | |||
166 | void 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 | |||
6 | class ViewDefault : public View | ||
7 | { | ||
8 | public: | ||
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 | |||
35 | private: | ||
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> | ||
7 | using namespace Bu; | ||
8 | |||
9 | PluginInterface3( pluginViewMake, make, ViewMake, View, | ||
10 | "Mike Buland", 0, 1 ); | ||
11 | |||
12 | ViewMake::ViewMake() | ||
13 | { | ||
14 | } | ||
15 | |||
16 | ViewMake::~ViewMake() | ||
17 | { | ||
18 | } | ||
19 | |||
20 | void ViewMake::beginAction( const Bu::FString &/*sAction*/ ) | ||
21 | { | ||
22 | } | ||
23 | |||
24 | void ViewMake::endAction() | ||
25 | { | ||
26 | } | ||
27 | |||
28 | void ViewMake::skipTarget( const Bu::FString &/*sProfile*/, | ||
29 | const Target &/*rTarget*/ ) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | void ViewMake::beginTarget( const Bu::FString &/*sProfile*/, | ||
34 | const Target &/*rTarget*/ ) | ||
35 | { | ||
36 | } | ||
37 | |||
38 | void ViewMake::processTarget( const Bu::FString &/*sProfile*/, | ||
39 | const Target &/*rTarget*/ ) | ||
40 | { | ||
41 | } | ||
42 | |||
43 | void ViewMake::endTarget() | ||
44 | { | ||
45 | } | ||
46 | |||
47 | void ViewMake::buildRequires( const Target &/*rTarget*/ ) | ||
48 | { | ||
49 | } | ||
50 | |||
51 | void ViewMake::cmdStarted( const Bu::FString &sCmd ) | ||
52 | { | ||
53 | sio << sCmd << sio.nl; | ||
54 | } | ||
55 | |||
56 | void ViewMake::cmdFinished( const Bu::FString &sStdOut, | ||
57 | const Bu::FString &sStdErr, long /*iExit*/ ) | ||
58 | { | ||
59 | sio << sStdOut << sStdErr; | ||
60 | } | ||
61 | |||
62 | void ViewMake::userError( const Bu::FString &sMsg ) | ||
63 | { | ||
64 | sio << "Error: " << sMsg << sio.nl; | ||
65 | } | ||
66 | |||
67 | void ViewMake::userWarning( const Bu::FString &sMsg ) | ||
68 | { | ||
69 | sio << "Warning: " << sMsg << sio.nl; | ||
70 | } | ||
71 | |||
72 | void ViewMake::userNotice( const Bu::FString &sMsg ) | ||
73 | { | ||
74 | sio << "Notice: " << sMsg << sio.nl; | ||
75 | } | ||
76 | |||
77 | void ViewMake::sysError( const Bu::FString &sMsg ) | ||
78 | { | ||
79 | sio << sMsg << sio.nl; | ||
80 | } | ||
81 | |||
82 | void 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 | |||
6 | class ViewMake : public View | ||
7 | { | ||
8 | public: | ||
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 | |||
3 | extern Bu::PluginInfo pluginViewDefault; | ||
4 | extern Bu::PluginInfo pluginViewMake; | ||
5 | ViewPlugger::ViewPlugger() | ||
6 | { | ||
7 | registerBuiltinPlugin( &pluginViewDefault ); | ||
8 | registerBuiltinPlugin( &pluginViewMake ); | ||
9 | } | ||
10 | |||
11 | ViewPlugger::~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 | |||
8 | class ViewPlugger : public Bu::Plugger<View>, public Bu::Singleton<ViewPlugger> | ||
9 | { | ||
10 | friend class Bu::Singleton<ViewPlugger>; | ||
11 | private: | ||
12 | ViewPlugger(); | ||
13 | |||
14 | public: | ||
15 | virtual ~ViewPlugger(); | ||
16 | |||
17 | private: | ||
18 | }; | ||
19 | |||
20 | #endif | ||