2626#include < cxx/diagnostics_client.h>
2727#include < cxx/lexer.h>
2828#include < cxx/literals.h>
29+ #include < cxx/preprocessor.h>
2930#include < cxx/private/path.h>
30-
31- // fmt
32- #include < format>
33-
34- // utf8
3531#include < utf8/unchecked.h>
3632
37- // stl
38- #include < cxx/preprocessor.h>
39-
4033#include < algorithm>
4134#include < cassert>
35+ #include < format>
4236#include < forward_list>
4337#include < fstream>
4438#include < functional>
@@ -716,9 +710,10 @@ struct Preprocessor::Private {
716710 std::string_view local;
717711 Include include;
718712 bool isIncludeNext = false ;
719- int value = 0 ;
713+ bool exists = false ;
720714 };
721715 std::vector<Dep> dependencies_;
716+ std::function<void ()> continuation_;
722717 int localCount_ = 0 ;
723718
724719 int counter_ = 0 ;
@@ -1167,8 +1162,15 @@ struct Preprocessor::Private {
11671162 TokList *loc = nullptr ;
11681163 };
11691164
1165+ struct ParsedIfDirective {
1166+ std::function<void ()> resume;
1167+ };
1168+
1169+ using ParsedDirective =
1170+ std::variant<std::monostate, ParsedIncludeDirective, ParsedIfDirective>;
1171+
11701172 [[nodiscard]] auto parseDirective (SourceFile *source, TokList *start)
1171- -> std::optional<ParsedIncludeDirective> ;
1173+ -> ParsedDirective ;
11721174
11731175 [[nodiscard]] auto parseIncludeDirective (TokList *directive, TokList *ts)
11741176 -> std::optional<ParsedIncludeDirective>;
@@ -1203,7 +1205,9 @@ struct Preprocessor::Private {
12031205 [[nodiscard]] auto copyLine (TokList *ts, bool inMacroBody = false )
12041206 -> TokList *;
12051207
1206- [[nodiscard]] auto constantExpression (TokList *ts) -> long;
1208+ [[nodiscard]] auto prepareConstantExpression (TokList *ts) -> TokList *;
1209+
1210+ [[nodiscard]] auto evaluateConstantExpression (TokList *ts) -> long;
12071211 [[nodiscard]] auto conditionalExpression (TokList *&ts) -> long;
12081212 [[nodiscard]] auto binaryExpression (TokList *&ts) -> long;
12091213 [[nodiscard]] auto binaryExpressionHelper (TokList *&ts, long lhs, int minPrec)
@@ -1647,7 +1651,7 @@ auto Preprocessor::Private::expandTokens(TokIterator it, TokIterator last,
16471651
16481652auto Preprocessor::Private::expand (
16491653 const std::function<void (const Tok *)> &emitToken) -> Status {
1650- if (buffers_.empty ()) return IsDone {};
1654+ if (buffers_.empty ()) return ProcessingComplete {};
16511655
16521656 auto buffer = buffers_.back ();
16531657 buffers_.pop_back ();
@@ -1672,8 +1676,11 @@ auto Preprocessor::Private::expand(
16721676 // skip the rest of the line
16731677 it = skipLine (it, last);
16741678
1675- if (auto parsedInclude = parseDirective (source, start.toTokList ())) {
1676- NeedToResolveInclude status{
1679+ auto parsedDirective = parseDirective (source, start.toTokList ());
1680+
1681+ if (auto parsedInclude =
1682+ std::get_if<ParsedIncludeDirective>(&parsedDirective)) {
1683+ PendingInclude status{
16771684 .preprocessor = *preprocessor_,
16781685 .include = parsedInclude->header ,
16791686 .isIncludeNext = parsedInclude->includeNext ,
@@ -1691,6 +1698,37 @@ auto Preprocessor::Private::expand(
16911698 // reset the token stream, so we can start processing the continuation
16921699 it = last;
16931700
1701+ return status;
1702+ } else if (auto directive =
1703+ std::get_if<ParsedIfDirective>(&parsedDirective)) {
1704+ // suspend and resolve the dependencies
1705+ continuation_ = std::move (directive->resume );
1706+
1707+ // suspend the current file and start processing the continuation
1708+ buffers_.push_back (Buffer{
1709+ .source = source,
1710+ .currentPath = currentPath_,
1711+ .ts = it.toTokList (),
1712+ .includeDepth = includeDepth_,
1713+ });
1714+
1715+ // reset the token stream, so we can start processing the continuation
1716+ it = last;
1717+
1718+ std::vector<PendingHasIncludes::Rquest> dependencies;
1719+ for (auto &dep : dependencies_) {
1720+ dependencies.push_back ({
1721+ .include = dep.include ,
1722+ .isIncludeNext = dep.isIncludeNext ,
1723+ .exists = dep.exists ,
1724+ });
1725+ }
1726+
1727+ PendingHasIncludes status{
1728+ .preprocessor = *preprocessor_,
1729+ .requests = dependencies,
1730+ };
1731+
16941732 return status;
16951733 }
16961734 } else if (skipping) {
@@ -1701,16 +1739,16 @@ auto Preprocessor::Private::expand(
17011739 }
17021740 }
17031741
1704- if (buffers_.empty ()) return IsDone {};
1742+ if (buffers_.empty ()) return ProcessingComplete {};
17051743
1706- return CanContinue {};
1744+ return CanContinuePreprocessing {};
17071745}
17081746
17091747auto Preprocessor::Private::parseDirective (SourceFile *source, TokList *start)
1710- -> std::optional<ParsedIncludeDirective> {
1748+ -> ParsedDirective {
17111749 auto directive = start->next ;
17121750
1713- if (!lookat (directive, TokenKind::T_IDENTIFIER)) return std::nullopt ;
1751+ if (!lookat (directive, TokenKind::T_IDENTIFIER)) return std::monostate{} ;
17141752
17151753 dependencies_.clear ();
17161754
@@ -1725,7 +1763,11 @@ auto Preprocessor::Private::parseDirective(SourceFile *source, TokList *start)
17251763 case PreprocessorDirectiveKind::T_INCLUDE_NEXT:
17261764 case PreprocessorDirectiveKind::T_INCLUDE: {
17271765 if (skipping) break ;
1728- return parseIncludeDirective (directive, ts);
1766+ auto includeDirective = parseIncludeDirective (directive, ts);
1767+ if (includeDirective.has_value ()) {
1768+ return *includeDirective;
1769+ }
1770+ break ;
17291771 }
17301772
17311773 case PreprocessorDirectiveKind::T_DEFINE: {
@@ -1781,11 +1823,23 @@ auto Preprocessor::Private::parseDirective(SourceFile *source, TokList *start)
17811823 if (skipping) {
17821824 pushState (std::tuple (true , false ));
17831825 } else {
1784- const auto value = constantExpression (ts);
1785- if (value) {
1786- pushState (std::tuple (skipping, false ));
1826+ auto expression = prepareConstantExpression (ts);
1827+
1828+ auto resume = [=, this ] {
1829+ const auto value = evaluateConstantExpression (expression);
1830+
1831+ if (value) {
1832+ pushState (std::tuple (skipping, false ));
1833+ } else {
1834+ pushState (std::tuple (true , !skipping));
1835+ }
1836+ };
1837+
1838+ if (dependencies_.empty ()) {
1839+ resume ();
17871840 } else {
1788- pushState (std::tuple (true , !skipping));
1841+ // rewquest the resolution of the dependencies
1842+ return ParsedIfDirective{.resume = std::move (resume)};
17891843 }
17901844 }
17911845
@@ -1796,11 +1850,23 @@ auto Preprocessor::Private::parseDirective(SourceFile *source, TokList *start)
17961850 if (!evaluating) {
17971851 setState (std::tuple (true , false ));
17981852 } else {
1799- const auto value = constantExpression (ts);
1800- if (value) {
1801- setState (std::tuple (!evaluating, false ));
1853+ auto expression = prepareConstantExpression (ts);
1854+
1855+ auto resume = [=, this ] {
1856+ const auto value = evaluateConstantExpression (expression);
1857+
1858+ if (value) {
1859+ setState (std::tuple (!evaluating, false ));
1860+ } else {
1861+ setState (std::tuple (true , evaluating));
1862+ }
1863+ };
1864+
1865+ if (dependencies_.empty ()) {
1866+ resume ();
18021867 } else {
1803- setState (std::tuple (true , evaluating));
1868+ // rewquest the resolution of the dependencies
1869+ return ParsedIfDirective{.resume = std::move (resume)};
18041870 }
18051871 }
18061872
@@ -1899,7 +1965,7 @@ auto Preprocessor::Private::parseDirective(SourceFile *source, TokList *start)
18991965 break ;
19001966 } // switch
19011967
1902- return std::nullopt ;
1968+ return std::monostate{} ;
19031969}
19041970
19051971auto Preprocessor::Private::parseIncludeDirective (TokList *directive,
@@ -2348,18 +2414,22 @@ auto Preprocessor::Private::copyLine(TokList *ts, bool inMacroBody)
23482414 return line;
23492415}
23502416
2351- auto Preprocessor::Private::constantExpression (TokList *ts) -> long {
2417+ auto Preprocessor::Private::prepareConstantExpression (TokList *ts)
2418+ -> TokList * {
23522419 auto line = copyLine (ts);
2420+
23532421 dependencies_.clear ();
2422+
23542423 auto it = expandTokens (TokIterator{line}, TokIterator{},
23552424 /* inConditionalExpression*/ true );
2356- // evaluate the deps
2357- for (auto &d : dependencies_) {
2358- auto resolved = resolve (d.include , d.isIncludeNext );
2359- d.value = resolved.has_value ();
2360- }
2361- auto e = it.toTokList ();
2362- return conditionalExpression (e);
2425+
2426+ auto expression = it.toTokList ();
2427+
2428+ return expression;
2429+ }
2430+
2431+ auto Preprocessor::Private::evaluateConstantExpression (TokList *ts) -> long {
2432+ return conditionalExpression (ts);
23632433}
23642434
23652435auto Preprocessor::Private::conditionalExpression (TokList *&ts) -> long {
@@ -2543,7 +2613,7 @@ auto Preprocessor::Private::primaryExpression(TokList *&ts) -> long {
25432613 for (const auto &dep : dependencies_) {
25442614 if (dep.local == tk->text ) {
25452615 ts = ts->next ;
2546- return dep.value ;
2616+ return dep.exists ;
25472617 }
25482618 }
25492619 }
@@ -2856,37 +2926,28 @@ void Preprocessor::preprocess(std::string source, std::string fileName,
28562926 Preprocessor &self;
28572927 bool done = false ;
28582928
2859- void operator ()(const IsDone &) { done = true ; }
2929+ void operator ()(const ProcessingComplete &) { done = true ; }
28602930
2861- void operator ()(const CanContinue &) {
2862- // keep going
2863- }
2931+ void operator ()(const CanContinuePreprocessing &) {}
28642932
2865- void operator ()(const NeedToResolveInclude &status) {
2933+ void operator ()(const PendingInclude &status) {
28662934 auto d = self.d .get ();
28672935
2868- if (auto resolvedInclude =
2869- d->resolve (status.include , status.isIncludeNext )) {
2870- status.continueWith (resolvedInclude.value ());
2871- return ;
2872- }
2873-
2874- auto loc = static_cast <TokList *>(status.loc );
2936+ auto resolvedInclude = d->resolve (status.include , status.isIncludeNext );
28752937
2876- const auto file = getHeaderName (status.include );
2877-
2878- d->error (loc, std::format (" file '{}' not found" , file));
2938+ status.resolveWith (resolvedInclude);
28792939 }
28802940
2881- void operator ()(const NeedToKnowIfFileExists &status) {
2882- auto exists = self.d ->fileExists (status.fileName );
2883- status.setFileExists (exists);
2884- }
2941+ void operator ()(const PendingHasIncludes &status) {
2942+ auto d = self.d .get ();
28852943
2886- void operator ()(const NeedToReadFile &status) {
2887- auto source = self.d ->readFile (status.fileName );
2888- status.setContents (std::move (source));
2944+ std::ranges::for_each (
2945+ status.requests , [&](const PendingHasIncludes::Rquest &dep) {
2946+ auto resolved = d->resolve (dep.include , dep.isIncludeNext );
2947+ dep.setExists (resolved.has_value ());
2948+ });
28892949 }
2950+
28902951 } state{*this };
28912952
28922953 beginPreprocessing (std::move (source), std::move (fileName), tokens);
@@ -2898,11 +2959,18 @@ void Preprocessor::preprocess(std::string source, std::string fileName,
28982959 endPreprocessing (tokens);
28992960}
29002961
2901- void Preprocessor::NeedToResolveInclude::continueWith (
2902- std::string fileName) const {
2962+ void Preprocessor::PendingInclude::resolveWith (
2963+ std::optional<std:: string> fileName) const {
29032964 auto d = preprocessor.d .get ();
29042965
2905- auto continuation = d->findOrCreateSourceFile (fileName);
2966+ if (!fileName.has_value ()) {
2967+ const auto &header = getHeaderName (include);
2968+ d->error (static_cast <TokList *>(loc),
2969+ std::format (" file '{}' not found" , header));
2970+ return ;
2971+ }
2972+
2973+ auto continuation = d->findOrCreateSourceFile (*fileName);
29062974 if (!continuation) return ;
29072975
29082976 // make the continuation the current file
@@ -2917,10 +2985,6 @@ void Preprocessor::NeedToResolveInclude::continueWith(
29172985 });
29182986}
29192987
2920- void Preprocessor::NeedToKnowIfFileExists::setFileExists (bool exists) const {}
2921-
2922- void Preprocessor::NeedToReadFile::setContents (std::string contents) const {}
2923-
29242988void Preprocessor::beginPreprocessing (std::string source, std::string fileName,
29252989 std::vector<Token> &tokens) {
29262990 assert (!d->findSourceFile (fileName));
@@ -2948,6 +3012,11 @@ void Preprocessor::beginPreprocessing(std::string source, std::string fileName,
29483012}
29493013
29503014void Preprocessor::endPreprocessing (std::vector<Token> &tokens) {
3015+ // consume the continuation if there is one
3016+ std::function<void ()> continuation;
3017+ std::swap (continuation, d->continuation_ );
3018+ if (continuation) continuation ();
3019+
29513020 if (tokens.empty ()) return ;
29523021
29533022 // assume the main source file is the first one
@@ -2960,7 +3029,13 @@ void Preprocessor::endPreprocessing(std::vector<Token> &tokens) {
29603029}
29613030
29623031auto Preprocessor::continuePreprocessing (std::vector<Token> &tokens) -> Status {
3032+ // consume the continuation if there is one
3033+ std::function<void ()> continuation;
3034+ std::swap (continuation, d->continuation_ );
3035+ if (continuation) continuation ();
3036+
29633037 auto emitToken = [&](const Tok *tk) { d->finalizeToken (tokens, tk); };
3038+
29643039 return d->expand (emitToken);
29653040}
29663041
0 commit comments