diff options
author | Mike Buland <eichlan@xagasoft.com> | 2009-12-21 18:04:02 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2009-12-21 18:04:02 +0000 |
commit | fb28f6800864176be2ffca29e8e664b641f33170 (patch) | |
tree | ba9180ac442939edc4eacbe1fdae93c5a7f87cee | |
parent | 51e21a316be6e052251b3dfc7d671061ebd67cee (diff) | |
download | build-fb28f6800864176be2ffca29e8e664b641f33170.tar.gz build-fb28f6800864176be2ffca29e8e664b641f33170.tar.bz2 build-fb28f6800864176be2ffca29e8e664b641f33170.tar.xz build-fb28f6800864176be2ffca29e8e664b641f33170.zip |
m3 is copied into trunk, we should be good to go, now.
83 files changed, 8081 insertions, 0 deletions
diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..8bc84f8 --- /dev/null +++ b/Doxyfile | |||
@@ -0,0 +1,275 @@ | |||
1 | # Doxyfile 1.4.1-KDevelop | ||
2 | |||
3 | #--------------------------------------------------------------------------- | ||
4 | # Project related configuration options | ||
5 | #--------------------------------------------------------------------------- | ||
6 | PROJECT_NAME = build | ||
7 | PROJECT_NUMBER = m3 | ||
8 | OUTPUT_DIRECTORY = api | ||
9 | CREATE_SUBDIRS = NO | ||
10 | OUTPUT_LANGUAGE = English | ||
11 | USE_WINDOWS_ENCODING = NO | ||
12 | BRIEF_MEMBER_DESC = YES | ||
13 | REPEAT_BRIEF = YES | ||
14 | ABBREVIATE_BRIEF = "The $name class" \ | ||
15 | "The $name widget" \ | ||
16 | "The $name file" \ | ||
17 | is \ | ||
18 | provides \ | ||
19 | specifies \ | ||
20 | contains \ | ||
21 | represents \ | ||
22 | a \ | ||
23 | an \ | ||
24 | the | ||
25 | ALWAYS_DETAILED_SEC = NO | ||
26 | INLINE_INHERITED_MEMB = NO | ||
27 | FULL_PATH_NAMES = NO | ||
28 | STRIP_FROM_PATH = | ||
29 | STRIP_FROM_INC_PATH = | ||
30 | SHORT_NAMES = NO | ||
31 | JAVADOC_AUTOBRIEF = YES | ||
32 | MULTILINE_CPP_IS_BRIEF = NO | ||
33 | DETAILS_AT_TOP = YES | ||
34 | INHERIT_DOCS = YES | ||
35 | DISTRIBUTE_GROUP_DOC = NO | ||
36 | TAB_SIZE = 4 | ||
37 | ALIASES = | ||
38 | OPTIMIZE_OUTPUT_FOR_C = NO | ||
39 | OPTIMIZE_OUTPUT_JAVA = NO | ||
40 | SUBGROUPING = YES | ||
41 | #--------------------------------------------------------------------------- | ||
42 | # Build related configuration options | ||
43 | #--------------------------------------------------------------------------- | ||
44 | EXTRACT_ALL = YES | ||
45 | EXTRACT_PRIVATE = YES | ||
46 | EXTRACT_STATIC = YES | ||
47 | EXTRACT_LOCAL_CLASSES = YES | ||
48 | EXTRACT_LOCAL_METHODS = YES | ||
49 | HIDE_UNDOC_MEMBERS = NO | ||
50 | HIDE_UNDOC_CLASSES = NO | ||
51 | HIDE_FRIEND_COMPOUNDS = NO | ||
52 | HIDE_IN_BODY_DOCS = NO | ||
53 | INTERNAL_DOCS = YES | ||
54 | CASE_SENSE_NAMES = YES | ||
55 | HIDE_SCOPE_NAMES = NO | ||
56 | SHOW_INCLUDE_FILES = YES | ||
57 | INLINE_INFO = YES | ||
58 | SORT_MEMBER_DOCS = YES | ||
59 | SORT_BRIEF_DOCS = NO | ||
60 | SORT_BY_SCOPE_NAME = NO | ||
61 | GENERATE_TODOLIST = YES | ||
62 | GENERATE_TESTLIST = YES | ||
63 | GENERATE_BUGLIST = YES | ||
64 | GENERATE_DEPRECATEDLIST= YES | ||
65 | ENABLED_SECTIONS = | ||
66 | MAX_INITIALIZER_LINES = 30 | ||
67 | SHOW_USED_FILES = YES | ||
68 | SHOW_DIRECTORIES = NO | ||
69 | FILE_VERSION_FILTER = | ||
70 | #--------------------------------------------------------------------------- | ||
71 | # configuration options related to warning and progress messages | ||
72 | #--------------------------------------------------------------------------- | ||
73 | QUIET = NO | ||
74 | WARNINGS = YES | ||
75 | WARN_IF_UNDOCUMENTED = YES | ||
76 | WARN_IF_DOC_ERROR = YES | ||
77 | WARN_NO_PARAMDOC = YES | ||
78 | WARN_FORMAT = "$file:$line: $text" | ||
79 | WARN_LOGFILE = Doxywarn | ||
80 | #--------------------------------------------------------------------------- | ||
81 | # configuration options related to the input files | ||
82 | #--------------------------------------------------------------------------- | ||
83 | INPUT = src | ||
84 | FILE_PATTERNS = *.c \ | ||
85 | *.cc \ | ||
86 | *.cxx \ | ||
87 | *.cpp \ | ||
88 | *.c++ \ | ||
89 | *.java \ | ||
90 | *.ii \ | ||
91 | *.ixx \ | ||
92 | *.ipp \ | ||
93 | *.i++ \ | ||
94 | *.inl \ | ||
95 | *.h \ | ||
96 | *.hh \ | ||
97 | *.hxx \ | ||
98 | *.hpp \ | ||
99 | *.h++ \ | ||
100 | *.idl \ | ||
101 | *.odl \ | ||
102 | *.cs \ | ||
103 | *.php \ | ||
104 | *.php3 \ | ||
105 | *.inc \ | ||
106 | *.m \ | ||
107 | *.mm \ | ||
108 | *.dox \ | ||
109 | *.C \ | ||
110 | *.CC \ | ||
111 | *.C++ \ | ||
112 | *.II \ | ||
113 | *.I++ \ | ||
114 | *.H \ | ||
115 | *.HH \ | ||
116 | *.H++ \ | ||
117 | *.CS \ | ||
118 | *.PHP \ | ||
119 | *.PHP3 \ | ||
120 | *.M \ | ||
121 | *.MM \ | ||
122 | *.C \ | ||
123 | *.H \ | ||
124 | *.tlh \ | ||
125 | *.diff \ | ||
126 | *.patch \ | ||
127 | *.moc \ | ||
128 | *.xpm \ | ||
129 | *.dox | ||
130 | RECURSIVE = YES | ||
131 | EXCLUDE = | ||
132 | EXCLUDE_SYMLINKS = NO | ||
133 | EXCLUDE_PATTERNS = | ||
134 | EXAMPLE_PATH = | ||
135 | EXAMPLE_PATTERNS = * | ||
136 | EXAMPLE_RECURSIVE = NO | ||
137 | IMAGE_PATH = | ||
138 | INPUT_FILTER = | ||
139 | FILTER_PATTERNS = | ||
140 | FILTER_SOURCE_FILES = NO | ||
141 | #--------------------------------------------------------------------------- | ||
142 | # configuration options related to source browsing | ||
143 | #--------------------------------------------------------------------------- | ||
144 | SOURCE_BROWSER = YES | ||
145 | INLINE_SOURCES = NO | ||
146 | STRIP_CODE_COMMENTS = YES | ||
147 | REFERENCED_BY_RELATION = YES | ||
148 | REFERENCES_RELATION = YES | ||
149 | VERBATIM_HEADERS = YES | ||
150 | #--------------------------------------------------------------------------- | ||
151 | # configuration options related to the alphabetical class index | ||
152 | #--------------------------------------------------------------------------- | ||
153 | ALPHABETICAL_INDEX = YES | ||
154 | COLS_IN_ALPHA_INDEX = 4 | ||
155 | IGNORE_PREFIX = | ||
156 | #--------------------------------------------------------------------------- | ||
157 | # configuration options related to the HTML output | ||
158 | #--------------------------------------------------------------------------- | ||
159 | GENERATE_HTML = YES | ||
160 | HTML_OUTPUT = html | ||
161 | HTML_FILE_EXTENSION = .html | ||
162 | HTML_HEADER = | ||
163 | HTML_FOOTER = | ||
164 | HTML_STYLESHEET = | ||
165 | HTML_ALIGN_MEMBERS = YES | ||
166 | GENERATE_HTMLHELP = NO | ||
167 | CHM_FILE = | ||
168 | HHC_LOCATION = | ||
169 | GENERATE_CHI = NO | ||
170 | BINARY_TOC = NO | ||
171 | TOC_EXPAND = NO | ||
172 | DISABLE_INDEX = NO | ||
173 | ENUM_VALUES_PER_LINE = 4 | ||
174 | GENERATE_TREEVIEW = NO | ||
175 | TREEVIEW_WIDTH = 250 | ||
176 | #--------------------------------------------------------------------------- | ||
177 | # configuration options related to the LaTeX output | ||
178 | #--------------------------------------------------------------------------- | ||
179 | GENERATE_LATEX = NO | ||
180 | LATEX_OUTPUT = latex | ||
181 | LATEX_CMD_NAME = latex | ||
182 | MAKEINDEX_CMD_NAME = makeindex | ||
183 | COMPACT_LATEX = NO | ||
184 | PAPER_TYPE = letter | ||
185 | EXTRA_PACKAGES = | ||
186 | LATEX_HEADER = | ||
187 | PDF_HYPERLINKS = YES | ||
188 | USE_PDFLATEX = YES | ||
189 | LATEX_BATCHMODE = NO | ||
190 | LATEX_HIDE_INDICES = NO | ||
191 | #--------------------------------------------------------------------------- | ||
192 | # configuration options related to the RTF output | ||
193 | #--------------------------------------------------------------------------- | ||
194 | GENERATE_RTF = NO | ||
195 | RTF_OUTPUT = rtf | ||
196 | COMPACT_RTF = NO | ||
197 | RTF_HYPERLINKS = YES | ||
198 | RTF_STYLESHEET_FILE = | ||
199 | RTF_EXTENSIONS_FILE = | ||
200 | #--------------------------------------------------------------------------- | ||
201 | # configuration options related to the man page output | ||
202 | #--------------------------------------------------------------------------- | ||
203 | GENERATE_MAN = NO | ||
204 | MAN_OUTPUT = man | ||
205 | MAN_EXTENSION = .3 | ||
206 | MAN_LINKS = NO | ||
207 | #--------------------------------------------------------------------------- | ||
208 | # configuration options related to the XML output | ||
209 | #--------------------------------------------------------------------------- | ||
210 | GENERATE_XML = NO | ||
211 | XML_OUTPUT = xml | ||
212 | XML_SCHEMA = | ||
213 | XML_DTD = | ||
214 | XML_PROGRAMLISTING = YES | ||
215 | #--------------------------------------------------------------------------- | ||
216 | # configuration options for the AutoGen Definitions output | ||
217 | #--------------------------------------------------------------------------- | ||
218 | GENERATE_AUTOGEN_DEF = NO | ||
219 | #--------------------------------------------------------------------------- | ||
220 | # configuration options related to the Perl module output | ||
221 | #--------------------------------------------------------------------------- | ||
222 | GENERATE_PERLMOD = NO | ||
223 | PERLMOD_LATEX = YES | ||
224 | PERLMOD_PRETTY = YES | ||
225 | PERLMOD_MAKEVAR_PREFIX = | ||
226 | #--------------------------------------------------------------------------- | ||
227 | # Configuration options related to the preprocessor | ||
228 | #--------------------------------------------------------------------------- | ||
229 | ENABLE_PREPROCESSING = YES | ||
230 | MACRO_EXPANSION = YES | ||
231 | EXPAND_ONLY_PREDEF = NO | ||
232 | SEARCH_INCLUDES = YES | ||
233 | INCLUDE_PATH = | ||
234 | INCLUDE_FILE_PATTERNS = | ||
235 | PREDEFINED = | ||
236 | EXPAND_AS_DEFINED = | ||
237 | SKIP_FUNCTION_MACROS = YES | ||
238 | #--------------------------------------------------------------------------- | ||
239 | # Configuration::additions related to external references | ||
240 | #--------------------------------------------------------------------------- | ||
241 | TAGFILES = | ||
242 | GENERATE_TAGFILE = | ||
243 | ALLEXTERNALS = NO | ||
244 | EXTERNAL_GROUPS = YES | ||
245 | PERL_PATH = /usr/bin/perl | ||
246 | #--------------------------------------------------------------------------- | ||
247 | # Configuration options related to the dot tool | ||
248 | #--------------------------------------------------------------------------- | ||
249 | CLASS_DIAGRAMS = YES | ||
250 | HIDE_UNDOC_RELATIONS = YES | ||
251 | HAVE_DOT = YES | ||
252 | CLASS_GRAPH = YES | ||
253 | COLLABORATION_GRAPH = YES | ||
254 | GROUP_GRAPHS = YES | ||
255 | UML_LOOK = NO | ||
256 | TEMPLATE_RELATIONS = NO | ||
257 | INCLUDE_GRAPH = YES | ||
258 | INCLUDED_BY_GRAPH = YES | ||
259 | CALL_GRAPH = NO | ||
260 | GRAPHICAL_HIERARCHY = YES | ||
261 | DIRECTORY_GRAPH = NO | ||
262 | DOT_IMAGE_FORMAT = png | ||
263 | DOT_PATH = | ||
264 | DOTFILE_DIRS = | ||
265 | MAX_DOT_GRAPH_WIDTH = 1024 | ||
266 | MAX_DOT_GRAPH_HEIGHT = 1024 | ||
267 | MAX_DOT_GRAPH_DEPTH = 1000 | ||
268 | DOT_TRANSPARENT = NO | ||
269 | DOT_MULTI_TARGETS = NO | ||
270 | GENERATE_LEGEND = YES | ||
271 | DOT_CLEANUP = YES | ||
272 | #--------------------------------------------------------------------------- | ||
273 | # Configuration::additions related to the search engine | ||
274 | #--------------------------------------------------------------------------- | ||
275 | SEARCHENGINE = NO | ||
diff --git a/build.conf b/build.conf new file mode 100644 index 0000000..cab11a8 --- /dev/null +++ b/build.conf | |||
@@ -0,0 +1,35 @@ | |||
1 | # build.conf for build, kind of whacky, eh? | ||
2 | |||
3 | default action: check targets() | ||
4 | |||
5 | set "CXXFLAGS" += "-ggdb -W -Wall" | ||
6 | |||
7 | "build": | ||
8 | rule "exe", | ||
9 | target file, | ||
10 | requires "libbu++/libbu++.a", | ||
11 | set "LDFLAGS" += "-Llibbu++ -lbu++ -ldl", | ||
12 | set "CXXFLAGS" += "-Ilibbu++", | ||
13 | input filesIn("src") filter regexp(".*\\.(cpp|y|l)$") | ||
14 | |||
15 | rule "exe": | ||
16 | matches regexp("(.*)\\.o$"), | ||
17 | aggregate toString(" "), | ||
18 | perform command("g++ -o {target} {match} {LDFLAGS}") | ||
19 | |||
20 | rule "cpp": | ||
21 | matches regexp("(.*)\\.(cpp|c)$"), | ||
22 | produces "{re:1}.o", | ||
23 | requires commandToList("g++ -M {CXXFLAGS} {match}", "make"), | ||
24 | perform command("g++ {CXXFLAGS} -c -o {target} {match}") | ||
25 | |||
26 | rule "bison": | ||
27 | matches regexp("(.*)\\.y$"), | ||
28 | produces ["{re:1}.tab.c", "{re:1}.tab.h", "{re:1}.output"], | ||
29 | perform command("bison -v -b{re:1} {match}") | ||
30 | |||
31 | rule "flex": | ||
32 | matches regexp("(.*)\\.l$"), | ||
33 | produces ["{re:1}.yy.c","{re:1}.yy.h"], | ||
34 | perform command("flex {FLEXFLAGS} {match}") | ||
35 | |||
diff --git a/default.bld b/default.bld new file mode 100644 index 0000000..9b71c4b --- /dev/null +++ b/default.bld | |||
@@ -0,0 +1,129 @@ | |||
1 | # | ||
2 | # default.bld for build mark 3. This guy does it all, so watch out! | ||
3 | # :) | ||
4 | # | ||
5 | |||
6 | CXXFLAGS += "-ggdb -W -Wall"; | ||
7 | |||
8 | action "default" | ||
9 | { | ||
10 | build: "build-m3"; | ||
11 | } | ||
12 | |||
13 | action "man" | ||
14 | { | ||
15 | build: targets("all"); | ||
16 | } | ||
17 | |||
18 | action "pkg" | ||
19 | { | ||
20 | build: targets("pkg"); | ||
21 | } | ||
22 | |||
23 | action "clean" | ||
24 | { | ||
25 | clean: "build-m3"; | ||
26 | } | ||
27 | |||
28 | action "devinstall" | ||
29 | { | ||
30 | if "$(id -u)" != "0\n" then | ||
31 | { | ||
32 | error "You can only install as the root user, su then run this."; | ||
33 | } | ||
34 | install: targets("devinstall"); | ||
35 | } | ||
36 | |||
37 | action "viminstall" | ||
38 | { | ||
39 | if "$(id -u)" != "0\n" then | ||
40 | { | ||
41 | error "You can only install as the root user, su then run this."; | ||
42 | } | ||
43 | install: targets("viminstall"); | ||
44 | } | ||
45 | |||
46 | target "build-m3" | ||
47 | { | ||
48 | input [files("src/*.y"), files("src/*.l"), files("src/*.cpp")]; | ||
49 | rule "exe"; | ||
50 | LDFLAGS += "-Llibbu++ -lbu++ -ldl"; | ||
51 | CXXFLAGS += "-Ilibbu++"; | ||
52 | tag "tools"; | ||
53 | } | ||
54 | |||
55 | target "build-r$(svnversion "-n").tar.bz2" | ||
56 | { | ||
57 | input [ | ||
58 | "build.conf", | ||
59 | "Doxyfile", | ||
60 | "default.bld", | ||
61 | "docs/build.1", | ||
62 | "docs/build.7", | ||
63 | "support/vim/syntax/build.vim", | ||
64 | "support/vim/ftdetect/build.vim", | ||
65 | "support/vim/ftplugin/build.vim", | ||
66 | files("src/*.y"), | ||
67 | files("src/*.l"), | ||
68 | files("src/*.cpp"), | ||
69 | files("src/*.h"), | ||
70 | files("share/autoinclude/*"), | ||
71 | files("share/include/*") | ||
72 | ]; | ||
73 | rule "tarball"; | ||
74 | tag "pkg"; | ||
75 | } | ||
76 | |||
77 | // We want to override the c rule, and just use c++ for it | ||
78 | rule "c" | ||
79 | { | ||
80 | input "*.c"; | ||
81 | output replace(".c", ".o"); | ||
82 | tag "auto-source"; | ||
83 | requires getMakeDeps("g++ ${CXXFLAGS} -M ${INPUT}"); | ||
84 | profile "build" | ||
85 | { | ||
86 | execute("g++ ${CXXFLAGS} -c -o ${OUTPUT} ${INPUT}"); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | rule "tarball" | ||
91 | { | ||
92 | input matches("*.cpp", "*.h", "*.c", "*.y", "*.l", "*.conf", "Doxyfile", | ||
93 | "*.1", "*.7", "*.vim"); | ||
94 | profile "build" | ||
95 | { | ||
96 | OUTDIR = OUTPUT.replace(".tar.bz2",""); | ||
97 | execute("tar --transform=\"s@^@${OUTDIR}/@\" -c ${INPUT} |" | ||
98 | " bzip2 -9 > ${OUTPUT}"); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | target "/usr/share/build" | ||
103 | { | ||
104 | input "$(echo -n $PWD)/share"; | ||
105 | tag "devinstall"; | ||
106 | profile "install" | ||
107 | { | ||
108 | execute("ln -fsv ${INPUT} \"${OUTPUT}\""); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | for vimdir in dirs("/usr/share/vim/vim*") do | ||
113 | { | ||
114 | for ftype in ["ftplugin/build.vim", "ftdetect/build.vim", | ||
115 | "syntax/build.vim"] do | ||
116 | { | ||
117 | target vimdir + "/" + ftype | ||
118 | { | ||
119 | input "support/vim/" + ftype; | ||
120 | tag "viminstall"; | ||
121 | display "install"; | ||
122 | profile "install" | ||
123 | { | ||
124 | execute("cp -f ${INPUT} ${OUTPUT}"); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
diff --git a/docs/build.1 b/docs/build.1 new file mode 100644 index 0000000..118c744 --- /dev/null +++ b/docs/build.1 | |||
@@ -0,0 +1,5 @@ | |||
1 | .TH build 1 "October 30, 2009" "Xagasoft" "Geekgene" | ||
2 | Build is awesome, try it out | ||
3 | .P | ||
4 | This is a new paragraph | ||
5 | .SH SYNOPSIS | ||
diff --git a/docs/build.7 b/docs/build.7 new file mode 100644 index 0000000..5d6ab34 --- /dev/null +++ b/docs/build.7 | |||
@@ -0,0 +1,84 @@ | |||
1 | .TH build 1 "October 30, 2009" "Xagasoft" "Geekgene" | ||
2 | .SH NAME | ||
3 | .P | ||
4 | build.conf configuration files. | ||
5 | .SH SYNOPSIS | ||
6 | .P | ||
7 | These files describe how to build something, generally software from source | ||
8 | code, but it can really be anything. | ||
9 | .SH DESCRIPTION | ||
10 | .P | ||
11 | For now, I'm just going to list some things here, here are the functions | ||
12 | available to you for general use at the moment: | ||
13 | .TP | ||
14 | .B | ||
15 | dirs() | ||
16 | Takes any number of string parameters, matches the file system based on glob | ||
17 | patterns and returns all directories that match the given patterns. | ||
18 | .TP | ||
19 | .B | ||
20 | files() | ||
21 | Takes any number of string parameters, matches the file system based on glob | ||
22 | patterns and returns all files that match the given patterns. | ||
23 | .TP | ||
24 | .B | ||
25 | execute() | ||
26 | Takes one string parameter, and executes it as a command using your shell. | ||
27 | .TP | ||
28 | .B | ||
29 | exists() | ||
30 | Checks to see if the given file/directory/etc exists on the file system, if it | ||
31 | does, true is returned, otherwise, false. | ||
32 | .TP | ||
33 | .B | ||
34 | matches() | ||
35 | Checks the input of the function to see if it matches a given wildcard pattern, | ||
36 | the pattern may include any number of * (meaning match any number of any | ||
37 | character) or ? (meaning match one of any character) symbols. If the input is | ||
38 | a string, then true or false is returned. If the input is a list, a filtered | ||
39 | version of the list is returned, containing only the elements that matched the | ||
40 | pattern. | ||
41 | .TP | ||
42 | .B | ||
43 | replace() | ||
44 | Takes two string parameters and replaces all occurances of the first with the | ||
45 | second in the input string or list of strings. | ||
46 | .TP | ||
47 | .B | ||
48 | targets() | ||
49 | Returns a list of target outputs, this will return every output for any target | ||
50 | that it finds seperately, so targets with multiple outputs will be in the list | ||
51 | more than once. With no parametrs it returns a list of all explicitly defined | ||
52 | targets, with a string parameter it returns all targets that have the given | ||
53 | tag. | ||
54 | .TP | ||
55 | .B | ||
56 | toString() | ||
57 | Takes the input and converts it to a string, with no parameters it uses default | ||
58 | formatting, this means that for lists it puts a space between each element. | ||
59 | .TP | ||
60 | .B | ||
61 | unlink() | ||
62 | Unlinks (deletes) the given file or files from the filesystem. It can take any | ||
63 | number of string or string list parameters. | ||
64 | .TP | ||
65 | .B | ||
66 | getMakeDeps() | ||
67 | Returns a list of files ready for use in a requires statement from the stdout of the command provided in the only string parameter. The command should output the dependancies in makefile format. | ||
68 | .TP | ||
69 | .B | ||
70 | fileName() | ||
71 | Returns the file portion of the string provided as input. That is, it returns everything after the last '/' character. This may not always be a file, it could be a directory, or even just an arbitrary part of a string that may or may not have '/' in it. If the input ends with a slash this will return an empty string. | ||
72 | .TP | ||
73 | .B | ||
74 | dirName() | ||
75 | Returns the directory portion of the string provided as input. That is, it returns everything before the last '/' character. Read the caveat for fileName about what this really means. If the input ends with a slash this will return the entire string, except the trailing slash. | ||
76 | .P | ||
77 | Here, lets list functions we wish we had... | ||
78 | .SH ENVIRONMENT | ||
79 | .SH FILES | ||
80 | .SH CONFORMING TO | ||
81 | .SH NOTES | ||
82 | .SH BUGS | ||
83 | .SH EXAMPLE | ||
84 | .SH SEE ALSO | ||
diff --git a/docs/buildm3notes.txt b/docs/buildm3notes.txt new file mode 100644 index 0000000..72e68e4 --- /dev/null +++ b/docs/buildm3notes.txt | |||
@@ -0,0 +1,99 @@ | |||
1 | Rules | ||
2 | Targets | ||
3 | Profiles | ||
4 | Build | ||
5 | Clean | ||
6 | Install | ||
7 | Package | ||
8 | etc. | ||
9 | Dependancies | ||
10 | Force Ruleset / mode | ||
11 | Input | ||
12 | Produces / Output | ||
13 | Actions (functions) | ||
14 | Execute | ||
15 | Delete | ||
16 | Download | ||
17 | GetDependencies | ||
18 | ExecuteTest | ||
19 | RunTarget | ||
20 | |||
21 | Mode Variables - switch modes for a variety of things (debug/release, platforms) | ||
22 | |||
23 | Includes (including default includes) | ||
24 | |||
25 | Bash style variable replacements / execute / etc. | ||
26 | |||
27 | Functions? | ||
28 | files() returns list (globbing) | ||
29 | querySystemParam() | ||
30 | |||
31 | if blocks can be anywhere. | ||
32 | |||
33 | semi-typed variables, default to string | ||
34 | |||
35 | variables in a target: INPUT, OUTPUT (by default instead of target and match) | ||
36 | |||
37 | ---- ast processing order ---- | ||
38 | 1) import all environment variables | ||
39 | 2) import all cached data | ||
40 | 3) set all variables specified on the command line | ||
41 | 4) root level "script" | ||
42 | 4.1) execute root level items, for target, rule, and non-auto, non-global config | ||
43 | this means building the target, rule, and config tables. | ||
44 | for global config and auto-config, run them as we hit them. | ||
45 | 5) execute specified target(s) with specified profile | ||
46 | |||
47 | ---- pseudo code ----- | ||
48 | |||
49 | set CXXFLAGS += "param"; // ensure there are spaces so it works for a command | ||
50 | set CXXFLAGS << "param"; // append like you'd expect, no extra changes | ||
51 | |||
52 | unset PREFIX; // may be handy to be able to unset things | ||
53 | |||
54 | include "otherbuild.h"; // oh yeah includes | ||
55 | |||
56 | notice "something good?"; // display a notice to the user, just info... | ||
57 | warning "yeah yeah yeah..."; // display a warning message, but don't exit | ||
58 | error "something or other"; // exit immediately with an error message | ||
59 | |||
60 | target "libbu++.a" | ||
61 | { | ||
62 | input files("src/*.cpp"); | ||
63 | set CXXFLAGS="-ggdb"; | ||
64 | condition file; | ||
65 | requires []; | ||
66 | |||
67 | hidden; // Hides this from the user, but still callable | ||
68 | } | ||
69 | |||
70 | target ["file a", files("src/*.cpp), files("src/*y")].replace("bob", "sam")... | ||
71 | { | ||
72 | condition always; | ||
73 | } | ||
74 | |||
75 | auto config "X" | ||
76 | { | ||
77 | } | ||
78 | |||
79 | config "EXTRA_DEBUG" | ||
80 | { | ||
81 | display "Debugging/Extra debugging"; | ||
82 | type int; (or string, or bool, or list, or version) | ||
83 | default 0; | ||
84 | allow ["0-5","6"]; | ||
85 | |||
86 | } | ||
87 | |||
88 | rule "cpp" | ||
89 | { | ||
90 | input glob("*.cpp"); // or just a string, pretend it's a glob | ||
91 | output "${INPUT}".replace(".cpp",".o"); | ||
92 | requires getDeps("g++ ${CXXFLAGS} -M ${OUTPUT} ${INPUT}", "make"); | ||
93 | profile "build" | ||
94 | { | ||
95 | fnc1() tag "c++"; | ||
96 | fnc2(); | ||
97 | } | ||
98 | } | ||
99 | |||
diff --git a/share/autoinclude/general-rules.bld b/share/autoinclude/general-rules.bld new file mode 100644 index 0000000..16217e0 --- /dev/null +++ b/share/autoinclude/general-rules.bld | |||
@@ -0,0 +1,64 @@ | |||
1 | |||
2 | rule "exe" | ||
3 | { | ||
4 | input "*.o"; | ||
5 | profile "build" | ||
6 | { | ||
7 | execute("g++ -o ${OUTPUT} ${INPUT} ${LDFLAGS}"); | ||
8 | } | ||
9 | } | ||
10 | |||
11 | rule "lib" | ||
12 | { | ||
13 | input "*.o"; | ||
14 | profile "build" | ||
15 | { | ||
16 | execute("ar cr ${OUTPUT} ${INPUT}"); | ||
17 | } | ||
18 | } | ||
19 | |||
20 | rule "cpp" | ||
21 | { | ||
22 | input "*.cpp"; | ||
23 | output replace(".cpp", ".o"); | ||
24 | requires getMakeDeps("g++ ${CXXFLAGS} -M ${INPUT}"); | ||
25 | profile "build" | ||
26 | { | ||
27 | execute("g++ ${CXXFLAGS} -c -o ${OUTPUT} ${INPUT}", "g++"); | ||
28 | } | ||
29 | } | ||
30 | |||
31 | // Heh, we're not going to use this one. | ||
32 | rule "c" | ||
33 | { | ||
34 | input "*.c"; | ||
35 | output replace(".c", ".o"); | ||
36 | requires getMakeDeps("gcc ${CXXFLAGS} -M ${INPUT}"); | ||
37 | profile "build" | ||
38 | { | ||
39 | execute("gcc ${CFLAGS} -c -o ${OUTPUT} ${INPUT}"); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | rule "bison" | ||
44 | { | ||
45 | input "*.y"; | ||
46 | output [INPUT.replace(".y", ".tab.c"), INPUT.replace(".y", ".tab.h")]; | ||
47 | profile "build" | ||
48 | { | ||
49 | BASE = INPUT.replace(".y", ""); | ||
50 | execute("bison -b${BASE} ${INPUT}"); | ||
51 | // if you add a -v bison will produce a .output file | ||
52 | } | ||
53 | } | ||
54 | |||
55 | rule "flex" | ||
56 | { | ||
57 | input "*.l"; | ||
58 | output replace(".l", ".yy.c"); | ||
59 | output replace(".l", ".yy.h"); | ||
60 | profile "build" | ||
61 | { | ||
62 | execute("flex ${FLEXFLAGS} ${INPUT}"); | ||
63 | } | ||
64 | } | ||
diff --git a/share/include/qt4.bld b/share/include/qt4.bld new file mode 100644 index 0000000..749cc52 --- /dev/null +++ b/share/include/qt4.bld | |||
@@ -0,0 +1,96 @@ | |||
1 | |||
2 | function qt_uiToH() | ||
3 | { | ||
4 | if "${UI_DIR}" == "" then | ||
5 | { | ||
6 | DIR = INPUT.dirName(); | ||
7 | } | ||
8 | else | ||
9 | { | ||
10 | DIR = UI_DIR; | ||
11 | } | ||
12 | FILE = INPUT.fileName(); | ||
13 | OUTFILE = FILE.replace(".ui",".h"); | ||
14 | return "${DIR}/ui_${OUTFILE}"; | ||
15 | } | ||
16 | |||
17 | rule "qt_ui" | ||
18 | { | ||
19 | display "ui"; | ||
20 | input "*.ui"; | ||
21 | output INPUT.qt_uiToH(); | ||
22 | tag "headers"; | ||
23 | profile "build" | ||
24 | { | ||
25 | execute("${QTDIR}/bin/uic -o ${OUTPUT} ${INPUT}"); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | function qt_qrcToCpp() | ||
30 | { | ||
31 | if "${RCC_DIR}" == "" then | ||
32 | { | ||
33 | DIR = INPUT.dirName(); | ||
34 | } | ||
35 | else | ||
36 | { | ||
37 | DIR = RCC_DIR; | ||
38 | } | ||
39 | FILE = INPUT.fileName(); | ||
40 | OUTFILE = FILE.replace(".qrc",".cpp"); | ||
41 | return "${DIR}/qrc_${OUTFILE}"; | ||
42 | } | ||
43 | |||
44 | rule "qt_rcc" | ||
45 | { | ||
46 | display "rcc"; | ||
47 | input "*.qrc"; | ||
48 | output INPUT.qt_qrcToCpp(); | ||
49 | profile "build" | ||
50 | { | ||
51 | NAME = INPUT.fileName().replace(".qrc",""); | ||
52 | execute("${QTDIR}/bin/rcc -name ${NAME} -o ${OUTPUT} ${INPUT}"); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | function qt_isMocable() | ||
57 | { | ||
58 | if INPUT.matches("*.h") then | ||
59 | { | ||
60 | if exists( INPUT ) then | ||
61 | { | ||
62 | if "$(grep Q_OBJECT ${INPUT})" != "" then | ||
63 | { | ||
64 | return true; | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | return false; | ||
69 | } | ||
70 | |||
71 | function qt_hToMocCpp() | ||
72 | { | ||
73 | if "${MOC_DIR}" == "" then | ||
74 | { | ||
75 | DIR = INPUT.dirName(); | ||
76 | } | ||
77 | else | ||
78 | { | ||
79 | DIR = MOC_DIR; | ||
80 | } | ||
81 | FILE = INPUT.fileName(); | ||
82 | OUTFILE = FILE.replace(".h",".cpp"); | ||
83 | return "${DIR}/moc_${OUTFILE}"; | ||
84 | } | ||
85 | |||
86 | rule "qt_moc" | ||
87 | { | ||
88 | display "moc"; | ||
89 | input qt_isMocable(); | ||
90 | output INPUT.qt_hToMocCpp(); | ||
91 | profile "build" | ||
92 | { | ||
93 | execute("${QTDIR}/bin/moc -o${OUTPUT} ${INPUT}"); | ||
94 | } | ||
95 | } | ||
96 | |||
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 | ||
diff --git a/support/vim/ftdetect/build.vim b/support/vim/ftdetect/build.vim new file mode 100644 index 0000000..8419934 --- /dev/null +++ b/support/vim/ftdetect/build.vim | |||
@@ -0,0 +1 @@ | |||
au BufRead,BufNewFile *.bld set filetype=build | |||
diff --git a/support/vim/ftplugin/build.vim b/support/vim/ftplugin/build.vim new file mode 100644 index 0000000..6b24838 --- /dev/null +++ b/support/vim/ftplugin/build.vim | |||
@@ -0,0 +1,24 @@ | |||
1 | " Vim filetype plugin file | ||
2 | " Language: Build | ||
3 | |||
4 | " Only do this when not done yet for this buffer | ||
5 | if exists("b:did_ftplugin") | ||
6 | finish | ||
7 | endif | ||
8 | |||
9 | " Don't load another plugin for this buffer | ||
10 | let b:did_ftplugin = 1 | ||
11 | |||
12 | " Set format options -- allow comment formatting with gq, but disable | ||
13 | " other processing | ||
14 | setlocal fo-=tcrowan2 fo+=q | ||
15 | |||
16 | " Set 'comments' to be the same as C/C++ | ||
17 | setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// | ||
18 | |||
19 | " Win32 can filter files in the browse dialog | ||
20 | if has("gui_win32") && !exists("b:browsefilter") | ||
21 | let b:browsefilter = "Build files (*.bld)\t*.bld\n" . | ||
22 | \ "All Files (*.*)\t*.*\n" | ||
23 | endif | ||
24 | |||
diff --git a/support/vim/syntax/build.vim b/support/vim/syntax/build.vim new file mode 100644 index 0000000..ae83d94 --- /dev/null +++ b/support/vim/syntax/build.vim | |||
@@ -0,0 +1,70 @@ | |||
1 | " Vim syntax file | ||
2 | " Language: Buildscript | ||
3 | " Maintainer: Mike Buland :) | ||
4 | " Last Change: 2009 Dec 4 | ||
5 | |||
6 | " For version 5.x: Clear all syntax items | ||
7 | " For version 6.x: Quit when a syntax file was already loaded | ||
8 | if version < 600 | ||
9 | syntax clear | ||
10 | elseif exists("b:current_syntax") | ||
11 | finish | ||
12 | endif | ||
13 | |||
14 | " Keywords | ||
15 | syn keyword Conditional if then else | ||
16 | syn keyword Loop for do in | ||
17 | syn keyword Logic not and or | ||
18 | syn keyword Statement include set unset function target input condition requires rule profile auto config display type default cache global value return output allow action warning error notice local continue break all export tag | ||
19 | syn keyword Todo TODO FIXME XXX | ||
20 | syn keyword Type int string bool float version | ||
21 | syn keyword Constant null true false file never always important normal hidden autogenerated filetime | ||
22 | syn keyword Builtins files dirs matches replace regexp execute unlink exists getMakeDeps toString targets fileName dirName | ||
23 | |||
24 | syn match TargetProcess /[a-zA-Z_][a-zA-Z0-9_]*:/he=e-1 | ||
25 | |||
26 | syn cluster CommentGroup contains=Todo | ||
27 | |||
28 | syn match Special display contained "\\\(x\x\+\|\o\{1,3}\|.\|$\)" | ||
29 | syn match Special display contained "\\\(u\x\{4}\|U\x\{8}\)" | ||
30 | |||
31 | " TODO: do we want to end at end of line too? | ||
32 | syn region doubleString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=Special,CmdEx | ||
33 | |||
34 | syn region CmdEx start=+$(+ skip=+"\|\\)\|\\\\+ end=+)+ | ||
35 | |||
36 | syn case ignore | ||
37 | syn match Numbers display transparent "\<\d\|\.\d" contains=Number,Float,OctalError,Octal | ||
38 | syn match Number display contained "\d\+\(u\=l\{0,2}\|ll\=u\)\>" | ||
39 | " Hex | ||
40 | syn match Number display contained "0x\x\+\(u\=l\{0,2}\|ll\=u\)\>" | ||
41 | syn match Octal display contained "0\o\+\(u\=l\{0,2}\|ll\=u\)\>" contains=cOctalZero | ||
42 | syn match OctalZero display contained "\<0" | ||
43 | syn match Float display contained "\d\+f" | ||
44 | syn match Float display contained "\d\+\.\d*\(e[-+]\=\d\+\)\=[fl]\=" | ||
45 | syn match Float display contained "\.\d\+\(e[-+]\=\d\+\)\=[fl]\=\>" | ||
46 | syn match Float display contained "\d\+e[-+]\=\d\+[fl]\=\>" | ||
47 | " Flag bad digits in octal | ||
48 | syn match OctalError display contained "0\o*[89]\d*" | ||
49 | syn case match | ||
50 | |||
51 | |||
52 | syn region cppComment start="#" skip="\\$" end="$" contains=@CommentGroup keepend | ||
53 | syn region cComment start="/\*" end="\*/" contains=@CommentGroup fold | ||
54 | syn region cppComment start="//" skip="\\$" end="$" contains=@CommentGroup keepend | ||
55 | |||
56 | |||
57 | syntax region Block start="{" end="}" transparent fold | ||
58 | |||
59 | hi def link OctalError Error | ||
60 | hi def link cComment Comment | ||
61 | hi def link cppComment Comment | ||
62 | hi def link singleString String | ||
63 | hi def link doubleString String | ||
64 | hi def link cmdEx String | ||
65 | hi def link Constructor Operator | ||
66 | hi def link Logic Statement | ||
67 | hi def link Loop Conditional | ||
68 | hi def link Builtins Function | ||
69 | hi def link TargetProcess Type | ||
70 | |||