Intel® Implicit SPMD Program Compiler (Intel® ISPC)  1.13.0
util.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2010-2020, Intel Corporation
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8 
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11 
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15 
16  * Neither the name of Intel Corporation nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 /** @file util.cpp
35  @brief Various small utility routines.
36 */
37 
38 #include "util.h"
39 #include "module.h"
40 
41 #ifdef ISPC_HOST_IS_LINUX
42 #include <alloca.h>
43 #include <unistd.h>
44 #elif defined(ISPC_HOST_IS_WINDOWS)
45 #include <malloc.h>
46 #include <shlwapi.h>
47 #ifndef __MINGW32__
48 #define alloca _alloca
49 #endif // __MINGW32__
50 #endif // ISPC_HOST_IS_LINUX
51 #include <ctype.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #ifdef ISPC_HOST_IS_WINDOWS
57 #include <direct.h>
58 #include <io.h>
59 #include <windows.h>
60 #else
61 #include <errno.h>
62 #include <sys/ioctl.h>
63 #include <unistd.h>
64 #endif // ISPC_HOST_IS_WINDOWS
65 #include <algorithm>
66 #include <set>
67 
68 #include <llvm/IR/DataLayout.h>
69 
70 /** Returns the width of the terminal where the compiler is running.
71  Finding this out may fail in a variety of reasonable situations (piping
72  compiler output to 'less', redirecting output to a file, running the
73  compiler under a debuffer; in this case, just return a reasonable
74  default.
75  */
77  if (g->disableLineWrap)
78  return 1 << 30;
79 
80 #if defined(ISPC_HOST_IS_WINDOWS)
81  HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
82  if (h == INVALID_HANDLE_VALUE || h == NULL)
83  return 80;
84  CONSOLE_SCREEN_BUFFER_INFO bufferInfo = {{0}};
85  GetConsoleScreenBufferInfo(h, &bufferInfo);
86  return bufferInfo.dwSize.X;
87 #else
88  struct winsize w;
89  if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0)
90  return 80;
91  return w.ws_col;
92 #endif // ISPC_HOST_IS_WINDOWS
93 }
94 
95 static bool lHaveANSIColors() {
96  static bool r = (getenv("TERM") != NULL && strcmp(getenv("TERM"), "dumb") != 0);
97 #ifndef ISPC_HOST_IS_WINDOWS
98  r &= (bool)isatty(2);
99  r |= g->forceColoredOutput;
100 #endif // !ISPC_HOST_IS_WINDOWS
101  return r;
102 }
103 
104 static const char *lStartBold() {
105  if (lHaveANSIColors())
106  return "\033[1m";
107  else
108  return "";
109 }
110 
111 static const char *lStartRed() {
112  if (lHaveANSIColors())
113  return "\033[31m";
114  else
115  return "";
116 }
117 
118 static const char *lStartBlue() {
119  if (lHaveANSIColors())
120  return "\033[34m";
121  else
122  return "";
123 }
124 
125 static const char *lResetColor() {
126  if (lHaveANSIColors())
127  return "\033[0m";
128  else
129  return "";
130 }
131 
132 /** Given a pointer into a string, find the end of the current word and
133  return a pointer to its last character.
134 */
135 static const char *lFindWordEnd(const char *buf) {
136  while (*buf != '\0' && !isspace(*buf))
137  ++buf;
138  return buf;
139 }
140 
141 /** When printing error messages, we sometimes want to include the source
142  file line for context. This function print the line(s) of the file
143  corresponding to the provided SourcePos and underlines the range of the
144  SourcePos with '^' symbols.
145 */
147  if (p.first_line == 0)
148  return;
149 
150  FILE *f = fopen(p.name, "r");
151  if (!f)
152  return;
153 
154  int c, curLine = 1;
155  while ((c = fgetc(f)) != EOF) {
156  // Don't print more than three lines of context. (More than that,
157  // and we're probably doing the wrong thing...)
158  if (curLine >= std::max(p.first_line, p.last_line - 2) && curLine <= p.last_line) {
159  if (c == '\t')
160  c = ' ';
161 
162  fputc(c, stderr);
163  }
164  if (c == '\n')
165  ++curLine;
166  if (curLine > p.last_line)
167  break;
168  }
169 
170  int i = 1;
171  for (; i < p.first_column; ++i)
172  fputc(' ', stderr);
173  fputc('^', stderr);
174  ++i;
175  for (; i < p.last_column; ++i)
176  fputc('^', stderr);
177  fputc('\n', stderr);
178  fputc('\n', stderr);
179 
180  fclose(f);
181 }
182 
183 /** Counts the number of characters into the buf at which the numColons
184  colon character is found. Skips over ANSI escape sequences and doesn't
185  include their characters in the final count.
186  */
187 static int lFindIndent(int numColons, const char *buf) {
188  int indent = 0;
189  while (*buf != '\0') {
190  if (*buf == '\033') {
191  while (*buf != '\0' && *buf != 'm')
192  ++buf;
193  if (*buf == 'm')
194  ++buf;
195  } else {
196  if (*buf == ':') {
197  if (--numColons == 0)
198  break;
199  }
200  ++indent;
201  ++buf;
202  }
203  }
204  return indent + 2;
205 }
206 
207 /** Print the given string to the given FILE, assuming the given output
208  column width. Break words as needed to avoid words spilling past the
209  last column. */
210 void PrintWithWordBreaks(const char *buf, int indent, int columnWidth, FILE *out) {
211 #ifdef ISPC_HOST_IS_WINDOWS
212  fputs(buf, out);
213  fputs("\n", out);
214 #else
215  int column = 0;
216  int width = std::max(40, columnWidth - 2);
217 
218  // Collect everything into a string and print it all at once at the end
219  // -> try to avoid troubles with mangled error messages with
220  // multi-threaded builds.
221  std::string outStr;
222 
223  const char *msgPos = buf;
224  while (true) {
225  if (*msgPos == '\033') {
226  // handle ANSI color escape: copy it to the output buffer
227  // without charging for the characters it uses
228  do {
229  outStr.push_back(*msgPos++);
230  } while (*msgPos != '\0' && *msgPos != 'm');
231  continue;
232  } else if (*msgPos == '\n') {
233  // Handle newlines cleanly
234  column = indent;
235  outStr.push_back('\n');
236  for (int i = 0; i < indent; ++i)
237  outStr.push_back(' ');
238  // Respect spaces after newlines
239  ++msgPos;
240  while (*msgPos == ' ') {
241  outStr.push_back(' ');
242  ++msgPos;
243  }
244  continue;
245  }
246 
247  while (*msgPos != '\0' && isspace(*msgPos))
248  ++msgPos;
249  if (*msgPos == '\0')
250  break;
251 
252  const char *wordEnd = lFindWordEnd(msgPos);
253  if (column > indent && column + wordEnd - msgPos > width) {
254  // This word would overflow, so start a new line
255  column = indent;
256  outStr.push_back('\n');
257  // Indent to the same column as the ":" at the start of the
258  // message.
259  for (int i = 0; i < indent; ++i)
260  outStr.push_back(' ');
261  }
262 
263  // Finally go and copy the word
264  while (msgPos != wordEnd) {
265  outStr.push_back(*msgPos++);
266  ++column;
267  }
268  outStr.push_back(' ');
269  ++column;
270  }
271  outStr.push_back('\n');
272  fputs(outStr.c_str(), out);
273 #endif
274 }
275 
276 #ifdef ISPC_HOST_IS_WINDOWS
277 // we cover for the lack vasprintf and asprintf on windows (also covers mingw)
278 int vasprintf(char **sptr, const char *fmt, va_list argv) {
279  int wanted = vsnprintf(*sptr = NULL, 0, fmt, argv);
280  if ((wanted < 0) || ((*sptr = (char *)malloc(1 + wanted)) == NULL))
281  return -1;
282 
283  return vsprintf(*sptr, fmt, argv);
284 }
285 
286 int asprintf(char **sptr, const char *fmt, ...) {
287  int retval;
288  va_list argv;
289  va_start(argv, fmt);
290  retval = vasprintf(sptr, fmt, argv);
291  va_end(argv);
292  return retval;
293 }
294 #endif
295 
296 /** Helper function for Error(), Warning(), etc.
297 
298  @param type The type of message being printed (e.g. "Warning")
299  @param p Position in source file that is connected to the message
300  being printed
301  @param fmt printf()-style format string
302  @param args Arguments with values for format string % entries
303 */
304 static void lPrint(const char *type, bool isError, SourcePos p, const char *fmt, va_list args) {
305  char *errorBuf, *formattedBuf;
306  if (vasprintf(&errorBuf, fmt, args) == -1) {
307  fprintf(stderr, "vasprintf() unable to allocate memory!\n");
308  exit(1);
309  }
310 
311  int indent = 0;
312  if (p.first_line == 0) {
313  // We don't have a valid SourcePos, so create a message without it
314  if (asprintf(&formattedBuf, "%s%s%s%s%s: %s%s", lStartBold(), isError ? lStartRed() : lStartBlue(), type,
315  lResetColor(), lStartBold(), errorBuf, lResetColor()) == -1) {
316  fprintf(stderr, "asprintf() unable to allocate memory!\n");
317  exit(1);
318  }
319  indent = lFindIndent(1, formattedBuf);
320  } else {
321  // Create an error message that includes the file and line number
322  if (asprintf(&formattedBuf, "%s%s:%d:%d: %s%s%s%s: %s%s", lStartBold(), p.name, p.first_line, p.first_column,
323  isError ? lStartRed() : lStartBlue(), type, lResetColor(), lStartBold(), errorBuf,
324  lResetColor()) == -1) {
325  fprintf(stderr, "asprintf() unable to allocate memory!\n");
326  exit(1);
327  }
328  indent = lFindIndent(3, formattedBuf);
329  }
330  // Don't indent too much with long filenames
331  indent = std::min(indent, 8);
332 
333  // Now that we've done all that work, see if we've already printed the
334  // exact same error message. If so, return, so we don't redundantly
335  // print it and annoy the user.
336  static std::set<std::string> printed;
337  if (printed.find(formattedBuf) != printed.end()) {
338  free(errorBuf);
339  free(formattedBuf);
340  return;
341  }
342  printed.insert(formattedBuf);
343 
344  PrintWithWordBreaks(formattedBuf, indent, TerminalWidth(), stderr);
346 
347  free(errorBuf);
348  free(formattedBuf);
349 }
350 
351 void Error(SourcePos p, const char *fmt, ...) {
352  if (m != NULL) {
353  ++m->errorCount;
354  if ((g->errorLimit != -1) && (g->errorLimit <= m->errorCount - 1))
355  return;
356  }
357  if (g->quiet)
358  return;
359 
360  va_list args;
361  va_start(args, fmt);
362  lPrint("Error", true, p, fmt, args);
363  va_end(args);
364 }
365 
366 void Debug(SourcePos p, const char *fmt, ...) {
367 #ifndef ISPC_NO_DUMPS
368  if (!g->debugPrint || g->quiet)
369  return;
370 
371  va_list args;
372  va_start(args, fmt);
373  lPrint("Debug", false, p, fmt, args);
374  va_end(args);
375 #endif
376 }
377 
378 void Warning(SourcePos p, const char *fmt, ...) {
379 
380  std::map<std::pair<int, std::string>, bool>::iterator turnOffWarnings_it =
381  g->turnOffWarnings.find(std::pair<int, std::string>(p.last_line, std::string(p.name)));
382  if ((turnOffWarnings_it != g->turnOffWarnings.end()) && (turnOffWarnings_it->second == false))
383  return;
384 
385  if (g->warningsAsErrors && m != NULL)
386  ++m->errorCount;
387 
388  if (g->disableWarnings || g->quiet)
389  return;
390 
391  va_list args;
392  va_start(args, fmt);
393  lPrint(g->warningsAsErrors ? "Error" : "Warning", g->warningsAsErrors, p, fmt, args);
394  va_end(args);
395 }
396 
397 void PerformanceWarning(SourcePos p, const char *fmt, ...) {
398  std::string stdlibFile = "stdlib.ispc";
399  std::string sourcePosName = p.name;
400  if (!g->emitPerfWarnings ||
401  (sourcePosName.length() >= stdlibFile.length() &&
402  sourcePosName.compare(sourcePosName.length() - stdlibFile.length(), stdlibFile.length(), stdlibFile) == 0) ||
403  g->quiet)
404  return;
405 
406  std::map<std::pair<int, std::string>, bool>::iterator turnOffWarnings_it =
407  g->turnOffWarnings.find(std::pair<int, std::string>(p.last_line, p.name));
408  if (turnOffWarnings_it != g->turnOffWarnings.end())
409  return;
410 
411  if (g->warningsAsErrors && m != NULL)
412  ++m->errorCount;
413 
414  va_list args;
415  va_start(args, fmt);
416  lPrint("Performance Warning", false, p, fmt, args);
417  va_end(args);
418 }
419 
420 static void lPrintBugText() {
421  static bool printed = false;
422  if (printed)
423  return;
424 
425  printed = true;
426  fprintf(stderr, "***\n"
427  "*** Please file a bug report at https://github.com/ispc/ispc/issues\n"
428  "*** (Including as much information as you can about how to "
429  "reproduce this error).\n"
430  "*** You have apparently encountered a bug in the compiler that we'd "
431  "like to fix!\n***\n");
432 }
433 
434 [[noreturn]] void FatalError(const char *file, int line, const char *message) {
435  fprintf(stderr, "%s(%d): FATAL ERROR: %s\n", file, line, message);
436  lPrintBugText();
437  abort();
438 }
439 
440 void DoAssert(const char *file, int line, const char *expr) {
441  fprintf(stderr, "%s:%u: Assertion failed: \"%s\".\n", file, line, expr);
442  lPrintBugText();
443  abort();
444 }
445 
446 void DoAssertPos(SourcePos pos, const char *file, int line, const char *expr) {
447  Error(pos, "Assertion failed (%s:%u): \"%s\".", file, line, expr);
448  lPrintBugText();
449  abort();
450 }
451 
452 ///////////////////////////////////////////////////////////////////////////
453 
454 // http://en.wikipedia.org/wiki/Levenshtein_distance
455 int StringEditDistance(const std::string &str1, const std::string &str2, int maxDist) {
456  // Small hack: don't return 0 if the strings are the same; if we've
457  // gotten here, there's been a parsing error, and suggesting the same
458  // string isn't going to actually help things.
459  if (str1 == str2)
460  return maxDist;
461 
462  int n1 = (int)str1.size(), n2 = (int)str2.size();
463  int nmax = std::max(n1, n2);
464 
465  int *current = (int *)alloca((nmax + 1) * sizeof(int));
466  int *previous = (int *)alloca((nmax + 1) * sizeof(int));
467 
468  for (int i = 0; i <= n2; ++i)
469  previous[i] = i;
470 
471  for (int y = 1; y <= n1; ++y) {
472  current[0] = y;
473  int rowBest = y;
474 
475  for (int x = 1; x <= n2; ++x) {
476  current[x] = std::min(previous[x - 1] + (str1[y - 1] == str2[x - 1] ? 0 : 1),
477  std::min(current[x - 1], previous[x]) + 1);
478  rowBest = std::min(rowBest, current[x]);
479  }
480 
481  if (maxDist != 0 && rowBest > maxDist)
482  return maxDist + 1;
483 
484  std::swap(current, previous);
485  }
486 
487  return previous[n2];
488 }
489 
490 std::vector<std::string> MatchStrings(const std::string &str, const std::vector<std::string> &options) {
491  if (str.size() == 0 || (str.size() == 1 && !isalpha(str[0])))
492  // don't even try...
493  return std::vector<std::string>();
494 
495  const int maxDelta = 2;
496  std::vector<std::string> matches[maxDelta + 1];
497 
498  // For all of the options that are up to maxDelta edit distance, store
499  // them in the element of matches[] that corresponds to their edit
500  // distance.
501  for (int i = 0; i < (int)options.size(); ++i) {
502  int dist = StringEditDistance(str, options[i], maxDelta + 1);
503  if (dist <= maxDelta)
504  matches[dist].push_back(options[i]);
505  }
506 
507  // And return the first one of them, if any, that has at least one
508  // match.
509  for (int i = 0; i <= maxDelta; ++i) {
510  if (matches[i].size())
511  return matches[i];
512  }
513  return std::vector<std::string>();
514 }
515 
516 void GetDirectoryAndFileName(const std::string &currentDirectory, const std::string &relativeName,
517  std::string *directory, std::string *filename) {
518 #ifdef ISPC_HOST_IS_WINDOWS
519  char path[MAX_PATH];
520  const char *combPath = PathCombine(path, currentDirectory.c_str(), relativeName.c_str());
521  Assert(combPath != NULL);
522  const char *filenamePtr = PathFindFileName(combPath);
523  *filename = filenamePtr;
524  *directory = std::string(combPath, filenamePtr - combPath);
525 #else
526  // We need a fully qualified path. First, see if the current file name
527  // is fully qualified itself--in that case, the current working
528  // directory isn't needed.
529  // @todo This probably needs to be smarter for Windows...
530  std::string fullPath;
531  if (relativeName[0] == '/')
532  fullPath = relativeName;
533  else {
534  fullPath = g->currentDirectory;
535  if (fullPath[fullPath.size() - 1] != '/')
536  fullPath.push_back('/');
537  fullPath += relativeName;
538  }
539 
540  // now, we need to separate it into the base name and the directory
541  const char *fp = fullPath.c_str();
542  const char *basenameStart = strrchr(fp, '/');
543  Assert(basenameStart != NULL);
544  ++basenameStart;
545  Assert(basenameStart[0] != '\0');
546  *filename = basenameStart;
547  *directory = std::string(fp, basenameStart - fp);
548 #endif // ISPC_HOST_IS_WINDOWS
549 }
550 
551 static std::set<std::string> lGetStringArray(const std::string &str) {
552  std::set<std::string> result;
553 
554  Assert(str.find('-') != str.npos);
555 
556  size_t pos_prev = 0, pos;
557  do {
558  pos = str.find('-', pos_prev);
559  std::string substr = str.substr(pos_prev, pos - pos_prev);
560  result.insert(substr);
561  pos_prev = pos;
562  pos_prev++;
563  } while (pos != str.npos);
564 
565  return result;
566 }
567 
568 bool VerifyDataLayoutCompatibility(const std::string &module_dl, const std::string &lib_dl) {
569  if (lib_dl.empty()) {
570  // This is the case for most of library pre-compiled .ll files.
571  return true;
572  }
573 
574  // Get "canonical" form. Instead of looking at "raw" DataLayout string, we
575  // look at the actual representation, as DataLayout class understands it.
576  // In the most cases there's no difference. But on x86 Windows (i386-pc-win32),
577  // clang generates a DataLayout string, which contains two definitions of f80,
578  // which contradic: f80:128:128 followed by f80:32:32. This is a bug, but
579  // correct thing to do is to interpret this exactly how LLVM would treat it,
580  // so we create a DataLayout class and take its string representation.
581 
582  llvm::DataLayout d1(module_dl);
583  llvm::DataLayout d2(lib_dl);
584 
585  std::string module_dl_canonic = d1.getStringRepresentation();
586  std::string lib_dl_canonic = d2.getStringRepresentation();
587 
588  // Break down DataLayout strings to separate type definitions.
589  std::set<std::string> module_dl_set = lGetStringArray(module_dl_canonic);
590  std::set<std::string> lib_dl_set = lGetStringArray(lib_dl_canonic);
591 
592  // For each element in library data layout, find matching module element.
593  // If no match is found, then we are in trouble and the library can't be used.
594  for (std::set<std::string>::iterator it = lib_dl_set.begin(); it != lib_dl_set.end(); ++it) {
595  // We use the simplest possible definition of "match", which is match exactly.
596  // Ideally it should be relaxed and for triples [p|i|v|f|a|s]<size>:<abi>:<pref>
597  // we should allow <pref> part (preferred alignment) to not match.
598  // But this seems to have no practical value at this point.
599  std::set<std::string>::iterator module_match = std::find(module_dl_set.begin(), module_dl_set.end(), *it);
600  if (module_match == module_dl_set.end()) {
601  // No match for this piece of library DataLayout was found,
602  // return false.
603  return false;
604  }
605  // Remove matching piece from Module set.
606  module_dl_set.erase(module_match);
607  }
608 
609  // We allow extra types to be defined in the Module, but we should check
610  // that it's something that we expect. And we expect vectors and floats.
611  for (std::set<std::string>::iterator it = module_dl_set.begin(); it != module_dl_set.end(); ++it) {
612  if ((*it)[0] == 'v' || (*it)[0] == 'f') {
613  continue;
614  }
615  return false;
616  }
617 
618  return true;
619 }
620 
621 bool IsStdin(const char *filepath) {
622  Assert(filepath != nullptr);
623  if (!strcmp(filepath, "-")) {
624  return true;
625  } else {
626  return false;
627  }
628 }
static const char * lStartBold()
Definition: util.cpp:104
static void lPrintBugText()
Definition: util.cpp:420
int last_column
Definition: ispc.h:130
bool disableWarnings
Definition: ispc.h:558
std::map< std::pair< int, std::string >, bool > turnOffWarnings
Definition: ispc.h:633
int TerminalWidth()
Definition: util.cpp:76
int first_line
Definition: ispc.h:127
bool forceColoredOutput
Definition: ispc.h:576
bool emitPerfWarnings
Definition: ispc.h:569
bool warningsAsErrors
Definition: ispc.h:561
Module * m
Definition: ispc.cpp:73
static const char * lStartRed()
Definition: util.cpp:111
bool disableLineWrap
Definition: ispc.h:565
std::vector< std::string > MatchStrings(const std::string &str, const std::vector< std::string > &options)
Definition: util.cpp:490
bool VerifyDataLayoutCompatibility(const std::string &module_dl, const std::string &lib_dl)
Definition: util.cpp:568
void FatalError(const char *file, int line, const char *message)
Definition: util.cpp:434
static const char * lResetColor()
Definition: util.cpp:125
void PerformanceWarning(SourcePos p, const char *fmt,...)
Definition: util.cpp:397
bool debugPrint
Definition: ispc.h:536
static void lPrintFileLineContext(SourcePos p)
Definition: util.cpp:146
int errorLimit
Definition: ispc.h:639
void DoAssertPos(SourcePos pos, const char *file, int line, const char *expr)
Definition: util.cpp:446
char currentDirectory[1024]
Definition: ispc.h:615
void GetDirectoryAndFileName(const std::string &currentDirectory, const std::string &relativeName, std::string *directory, std::string *filename)
Definition: util.cpp:516
static const char * lStartBlue()
Definition: util.cpp:118
Representation of a range of positions in a source file.
Definition: ispc.h:123
static bool lHaveANSIColors()
Definition: util.cpp:95
const char * name
Definition: ispc.h:126
static const char * lFindWordEnd(const char *buf)
Definition: util.cpp:135
void Error(SourcePos p, const char *fmt,...)
Definition: util.cpp:351
int last_line
Definition: ispc.h:129
int first_column
Definition: ispc.h:128
int StringEditDistance(const std::string &str1, const std::string &str2, int maxDist)
Definition: util.cpp:455
#define Assert(expr)
Definition: util.h:128
static void lPrint(const char *type, bool isError, SourcePos p, const char *fmt, va_list args)
Definition: util.cpp:304
static int lFindIndent(int numColons, const char *buf)
Definition: util.cpp:187
Globals * g
Definition: ispc.cpp:72
void Debug(SourcePos p, const char *fmt,...)
Definition: util.cpp:366
void PrintWithWordBreaks(const char *buf, int indent, int columnWidth, FILE *out)
Definition: util.cpp:210
static std::set< std::string > lGetStringArray(const std::string &str)
Definition: util.cpp:551
bool quiet
Definition: ispc.h:572
Declaration of the Module class, which is the ispc-side representation of the results of compiling a ...
int errorCount
Definition: module.h:144
void Warning(SourcePos p, const char *fmt,...)
Definition: util.cpp:378
void DoAssert(const char *file, int line, const char *expr)
Definition: util.cpp:440
bool IsStdin(const char *filepath)
Definition: util.cpp:621