• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 21100551564

17 Jan 2026 08:40PM UTC coverage: 60.504% (+0.01%) from 60.492%
21100551564

Pull #857

github

turleypol
fixed scope
Pull Request #857: ClangTidy readability-else-after-return

837 of 1874 new or added lines in 151 files covered. (44.66%)

48 existing lines in 26 files now uncovered.

44445 of 73458 relevant lines covered (60.5%)

515341.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.43
/pol-core/bscript/compiler/astbuilder/ValueBuilder.cpp
1
#include "ValueBuilder.h"
2

3
#include <cstring>
4

5
#include "bscript/compiler/Report.h"
6
#include "bscript/compiler/ast/BooleanValue.h"
7
#include "bscript/compiler/ast/FloatValue.h"
8
#include "bscript/compiler/ast/FunctionExpression.h"
9
#include "bscript/compiler/ast/FunctionReference.h"
10
#include "bscript/compiler/ast/IntegerValue.h"
11
#include "bscript/compiler/ast/RegularExpressionValue.h"
12
#include "bscript/compiler/ast/StringValue.h"
13
#include "bscript/compiler/ast/UninitializedValue.h"
14
#include "bscript/compiler/astbuilder/BuilderWorkspace.h"
15
#include "bscript/compiler/file/SourceLocation.h"
16
#include "bscript/compiler/model/CompilerWorkspace.h"
17
#include "bscript/compiler/model/FunctionLink.h"
18
#include "clib/strutil.h"
19

20
using EscriptGrammar::EscriptParser;
21

22
namespace Pol::Bscript::Compiler
23
{
24
ValueBuilder::ValueBuilder( const SourceFileIdentifier& source_file_identifier,
13,355✔
25
                            BuilderWorkspace& workspace )
13,355✔
26
    : TreeBuilder( source_file_identifier, workspace ), current_scope_name( ScopeName::Global )
13,355✔
27
{
28
  in_constructor_function.push( false );
13,355✔
29
}
13,355✔
30

31
std::unique_ptr<BooleanValue> ValueBuilder::bool_value(
467✔
32
    EscriptGrammar::EscriptParser::BoolLiteralContext* ctx )
33
{
34
  bool value;
35
  auto loc = location_for( *ctx );
467✔
36

37
  if ( ctx->BOOL_TRUE() )
467✔
38
  {
39
    value = true;
270✔
40
  }
41
  else if ( ctx->BOOL_FALSE() )
197✔
42
  {
43
    value = false;
197✔
44
  }
45
  else
46
  {
47
    location_for( *ctx ).internal_error( "unhandled boolean literal" );
×
48
  }
49

50
  return std::make_unique<BooleanValue>( loc, value );
934✔
51
}
52

53
std::unique_ptr<FloatValue> ValueBuilder::float_value(
723✔
54
    EscriptGrammar::EscriptParser::FloatLiteralContext* ctx )
55
{
56
  auto loc = location_for( *ctx );
723✔
57
  auto terminal = ctx->FLOAT_LITERAL();
723✔
58
  if ( !terminal )
723✔
59
  {
60
    terminal = ctx->HEX_FLOAT_LITERAL();
9✔
61
    if ( !terminal )
9✔
62
    {
63
      location_for( *ctx ).internal_error( "unhandled float literal" );
×
64
    }
65
  }
66
  double value = std::stod( text( terminal ) );
723✔
67
  return std::make_unique<FloatValue>( loc, value );
1,446✔
68
}
69

70
std::unique_ptr<FunctionReference> ValueBuilder::function_reference(
765✔
71
    EscriptParser::FunctionReferenceContext* ctx )
72
{
73
  auto source_location = location_for( *ctx );
765✔
74

75
  auto name = text( ctx->function );
765✔
76
  auto scope = ctx->scope          ? ScopeName( text( ctx->scope ) )  // scope exists
809✔
77
               : ctx->COLONCOLON() ? ScopeName::Global                // colon exists
721✔
78
                                   : ScopeName::None;                 // has no scope specified
1,530✔
79

80
  auto function_link =
81
      std::make_shared<FunctionLink>( source_location, current_scope_name.string() );
765✔
82
  auto function_reference =
83
      std::make_unique<FunctionReference>( source_location, name, function_link );
765✔
84

85
  workspace.function_resolver.register_function_link( ScopableName( scope, name ), function_link );
765✔
86

87
  return function_reference;
1,530✔
88
}
765✔
89

90
std::unique_ptr<FunctionExpression> ValueBuilder::function_expression(
675✔
91
    EscriptGrammar::EscriptParser::FunctionExpressionContext* ctx )
92
{
93
  auto loc = location_for( *ctx );
675✔
94
  auto name = workspace.function_resolver.register_function_expression( loc, ctx );
675✔
95

96
  workspace.compiler_workspace.all_function_locations.emplace( name, loc );
675✔
97
  workspace.function_resolver.force_reference( ScopableName( ScopeName::Global, name ), loc );
675✔
98

99
  auto function_link =
100
      std::make_shared<FunctionLink>( loc, current_scope_name.string() /* calling scope */ );
675✔
101

102
  // A unique name, as it is based on source location, so registering the link
103
  // in global scope is okay.
104
  workspace.function_resolver.register_function_link( ScopableName( ScopeName::Global, name ),
675✔
105
                                                      function_link );
106

107
  return std::make_unique<FunctionExpression>( loc, function_link );
1,350✔
108
}
675✔
109

110
std::unique_ptr<IntegerValue> ValueBuilder::integer_value(
221,359✔
111
    EscriptParser::IntegerLiteralContext* ctx )
112
{
113
  auto loc = location_for( *ctx );
221,359✔
114
  return std::make_unique<IntegerValue>( loc, to_int( ctx ) );
442,716✔
115
}
116

117
std::unique_ptr<StringValue> ValueBuilder::string_value( antlr4::tree::TerminalNode* string_literal,
48,310✔
118
                                                         bool expect_quotes )
119
{
120
  auto loc = location_for( *string_literal );
48,310✔
121
  return std::make_unique<StringValue>( loc, unquote( string_literal, expect_quotes ) );
96,620✔
122
}
123

124
std::unique_ptr<RegularExpressionValue> ValueBuilder::regular_expression_value(
150✔
125
    antlr4::tree::TerminalNode* regular_expression_literal )
126
{
127
  std::string input = regular_expression_literal->getSymbol()->getText();
150✔
128

129
  std::string pattern;
150✔
130
  std::string flags;
150✔
131

132
  std::size_t pos = input.rfind( '/' );
150✔
133

134
  if ( input.size() < 2 || input[0] != '/' || pos == std::string::npos )
150✔
135
  {
136
    location_for( *regular_expression_literal )
×
137
        .internal_error( "regular expression does not begin with a slash?" );
×
138
  }
139

140
  pattern = input.substr( 1, pos - 1 );
150✔
141
  flags = input.substr( pos + 1 );
150✔
142

143
  auto loc = location_for( *regular_expression_literal );
150✔
144
  return std::make_unique<RegularExpressionValue>( loc, std::move( pattern ), std::move( flags ) );
300✔
145
}
150✔
146

147
std::string ValueBuilder::unquote( antlr4::tree::TerminalNode* string_literal, bool expect_quotes )
48,924✔
148
{
149
  std::string input = string_literal->getSymbol()->getText();
48,924✔
150
  const char* s = input.c_str();
48,924✔
151
  if ( *s != '\"' && expect_quotes )
48,924✔
152
    location_for( *string_literal ).internal_error( "string does not begin with a quote?" );
×
153

154
  const char* end = s + ( expect_quotes ? 1 : 0 );
48,924✔
155
  std::string lit;
48,924✔
156
  lit.reserve( input.length() );
48,924✔
157
  bool escnext = false;  // true when waiting for 2nd char in an escape sequence
48,924✔
158
  u8 hexnext = 0;        // tells how many more chars in a \xNN escape sequence
48,924✔
159
  char hexstr[3];        // will contain the \x escape chars to be processed
160
  memset( hexstr, 0, 3 );
48,924✔
161

162
  for ( ;; )
163
  {
164
    if ( !*end )
388,328✔
165
    {
166
      if ( !expect_quotes )
3,961✔
167
        break;
3,961✔
168
      // parser should catch this.
169
      location_for( *string_literal ).internal_error( "unterminated string" );
×
170
    }
171

172
    if ( escnext && hexnext )
384,367✔
173
      location_for( *string_literal )
×
174
          .internal_error( "Bug in the compiler. Please report this on the forums." );
×
175

176
    if ( escnext )
384,367✔
177
    {
178
      // waiting for 2nd character after a backslash
179
      escnext = false;
15,687✔
180
      if ( *end == 'n' )
15,687✔
181
        lit += '\n';
180✔
182
      else if ( *end == 't' )
15,507✔
183
        lit += '\t';
19✔
184
      else if ( *end == 'x' )
15,488✔
185
        hexnext = 2;
15,324✔
186
      else
187
        lit += *end;
164✔
188
    }
189
    else if ( hexnext )
368,680✔
190
    {
191
      // waiting for next (two) chars in hex escape sequence (eg. \xFF)
192
      hexstr[2 - hexnext] = *end;
30,648✔
193
      if ( !--hexnext )
30,648✔
194
      {
195
        char* endptr;
196
        char ord = static_cast<char>( strtol( hexstr, &endptr, 16 ) );
15,324✔
197
        if ( *endptr != '\0' )
15,324✔
198
        {
199
          report.error( location_for( *string_literal ), "Invalid hex escape sequence '{}'.",
×
200
                        hexstr );
201
          return lit;
×
202
        }
203
        lit += ord;
15,324✔
204
      }
205
    }
206
    else
207
    {
208
      if ( *end == '\\' )
338,032✔
209
        escnext = true;
15,687✔
210
      else if ( *end == '\"' )
322,345✔
211
        break;
44,963✔
212
      else
213
        lit += *end;
277,382✔
214
    }
215
    ++end;
339,404✔
216
  }
339,404✔
217
  if ( !Clib::isValidUnicode( lit ) )
48,924✔
218
  {
219
    report.warning( location_for( *string_literal ),
×
220
                    "Warning: invalid unicode character detected. Assuming ISO8859." );
221

222
    Clib::sanitizeUnicodeWithIso( &lit );
×
223
  }
224
  return lit;
48,924✔
225
}
48,924✔
226

227
std::unique_ptr<Value> ValueBuilder::value( EscriptParser::LiteralContext* ctx )
266,964✔
228
{
229
  if ( auto string_literal = ctx->STRING_LITERAL() )
266,964✔
230
  {
231
    return string_value( string_literal );
44,248✔
232
  }
233
  if ( auto integer_literal = ctx->integerLiteral() )
222,716✔
234
  {
235
    return integer_value( integer_literal );
221,265✔
236
  }
237
  if ( auto float_literal = ctx->floatLiteral() )
1,451✔
238
  {
239
    return float_value( float_literal );
723✔
240
  }
241
  if ( auto bool_literal = ctx->boolLiteral() )
728✔
242
  {
243
    return bool_value( bool_literal );
455✔
244
  }
245
  if ( ctx->UNINIT() )
273✔
246
  {
247
    return std::make_unique<UninitializedValue>( location_for( *ctx ) );
123✔
248
  }
249
  if ( auto regex = ctx->REGEXP_LITERAL() )
150✔
250
  {
251
    return regular_expression_value( regex );
150✔
252
  }
NEW
253
  location_for( *ctx ).internal_error( "unhandled literal" );
×
254
}
255

256
int ValueBuilder::to_int( EscriptParser::IntegerLiteralContext* ctx )
221,359✔
257
{
258
  try
259
  {
260
    if ( auto decimal_literal = ctx->DECIMAL_LITERAL() )
221,359✔
261
    {
262
      return std::stoi( decimal_literal->getSymbol()->getText() );
188,852✔
263
    }
264
    if ( auto hex_literal = ctx->HEX_LITERAL() )
32,509✔
265
    {
266
      return static_cast<int>( std::stoul( hex_literal->getSymbol()->getText(), nullptr, 16 ) );
32,500✔
267
    }
268
    if ( auto oct_literal = ctx->OCT_LITERAL() )
9✔
269
    {
270
      return std::stoi( oct_literal->getSymbol()->getText(), nullptr, 8 );
9✔
271
    }
NEW
272
    if ( auto binary_literal = ctx->BINARY_LITERAL() )
×
273
    {
274
      return std::stoi( binary_literal->getSymbol()->getText(), nullptr, 2 );
×
275
    }
276
  }
277
  catch ( std::invalid_argument& )
2✔
278
  {
279
    report.error( location_for( *ctx ), "unable to convert integer value '{}'.", ctx->getText() );
×
280
    throw;
×
281
  }
×
282
  catch ( std::out_of_range& )
2✔
283
  {
284
    report.error( location_for( *ctx ), "integer value '{}' out of range.", ctx->getText() );
2✔
285
    throw;
2✔
286
  }
2✔
287

288
  location_for( *ctx ).internal_error( "unhandled integer literal" );
×
289
}
290

291
}  // namespace Pol::Bscript::Compiler
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc