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

polserver / polserver / 25918451630

15 May 2026 12:43PM UTC coverage: 60.929% (+2.1%) from 58.859%
25918451630

push

github

turleypol
added dynamic property which returns a pointer of the object instead of
a copy like the current imp.
needed to be able to eg store a vector

43 of 61 new or added lines in 2 files covered. (70.49%)

14455 existing lines in 345 files now uncovered.

44695 of 73356 relevant lines covered (60.93%)

449621.59 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,447✔
25
                            BuilderWorkspace& workspace )
13,447✔
26
    : TreeBuilder( source_file_identifier, workspace ), current_scope_name( ScopeName::Global )
13,447✔
27
{
28
  in_constructor_function.push( false );
13,447✔
29
}
13,447✔
30

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

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

50
  return std::make_unique<BooleanValue>( loc, value );
942✔
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
    {
UNCOV
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(
224,019✔
111
    EscriptParser::IntegerLiteralContext* ctx )
112
{
113
  auto loc = location_for( *ctx );
224,019✔
114
  return std::make_unique<IntegerValue>( loc, to_int( ctx ) );
448,036✔
115
}
116

117
std::unique_ptr<StringValue> ValueBuilder::string_value( antlr4::tree::TerminalNode* string_literal,
48,907✔
118
                                                         bool expect_quotes )
119
{
120
  auto loc = location_for( *string_literal );
48,907✔
121
  return std::make_unique<StringValue>( loc, unquote( string_literal, expect_quotes ) );
97,814✔
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
  {
UNCOV
136
    location_for( *regular_expression_literal )
×
UNCOV
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 )
49,532✔
148
{
149
  std::string input = string_literal->getSymbol()->getText();
49,532✔
150
  const char* s = input.c_str();
49,532✔
151
  if ( *s != '\"' && expect_quotes )
49,532✔
UNCOV
152
    location_for( *string_literal ).internal_error( "string does not begin with a quote?" );
×
153

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

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

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

176
    if ( escnext )
392,334✔
177
    {
178
      // waiting for 2nd character after a backslash
179
      escnext = false;
15,711✔
180
      if ( *end == 'n' )
15,711✔
181
        lit += '\n';
186✔
182
      else if ( *end == 't' )
15,525✔
183
        lit += '\t';
19✔
184
      else if ( *end == 'x' )
15,506✔
185
        hexnext = 2;
15,342✔
186
      else
187
        lit += *end;
164✔
188
    }
189
    else if ( hexnext )
376,623✔
190
    {
191
      // waiting for next (two) chars in hex escape sequence (eg. \xFF)
192
      hexstr[2 - hexnext] = *end;
30,684✔
193
      if ( !--hexnext )
30,684✔
194
      {
195
        char* endptr;
196
        char ord = static_cast<char>( strtol( hexstr, &endptr, 16 ) );
15,342✔
197
        if ( *endptr != '\0' )
15,342✔
198
        {
UNCOV
199
          report.error( location_for( *string_literal ), "Invalid hex escape sequence '{}'.",
×
200
                        hexstr );
UNCOV
201
          return lit;
×
202
        }
203
        lit += ord;
15,342✔
204
      }
205
    }
206
    else
207
    {
208
      if ( *end == '\\' )
345,939✔
209
        escnext = true;
15,711✔
210
      else if ( *end == '\"' )
330,228✔
211
        break;
45,385✔
212
      else
213
        lit += *end;
284,843✔
214
    }
215
    ++end;
346,949✔
216
  }
346,949✔
217
  if ( !Clib::isValidUnicode( lit ) )
49,532✔
218
  {
UNCOV
219
    report.warning( location_for( *string_literal ),
×
220
                    "Warning: invalid unicode character detected. Assuming ISO8859." );
221

UNCOV
222
    Clib::sanitizeUnicodeWithIso( &lit );
×
223
  }
224
  return lit;
49,532✔
225
}
49,532✔
226

227
std::unique_ptr<Value> ValueBuilder::value( EscriptParser::LiteralContext* ctx )
270,039✔
228
{
229
  if ( auto string_literal = ctx->STRING_LITERAL() )
270,039✔
230
  {
231
    return string_value( string_literal );
44,659✔
232
  }
233
  if ( auto integer_literal = ctx->integerLiteral() )
225,380✔
234
  {
235
    return integer_value( integer_literal );
223,925✔
236
  }
237
  if ( auto float_literal = ctx->floatLiteral() )
1,455✔
238
  {
239
    return float_value( float_literal );
723✔
240
  }
241
  if ( auto bool_literal = ctx->boolLiteral() )
732✔
242
  {
243
    return bool_value( bool_literal );
459✔
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
  }
UNCOV
253
  location_for( *ctx ).internal_error( "unhandled literal" );
×
254
}
255

256
int ValueBuilder::to_int( EscriptParser::IntegerLiteralContext* ctx )
224,019✔
257
{
258
  try
259
  {
260
    if ( auto decimal_literal = ctx->DECIMAL_LITERAL() )
224,019✔
261
    {
262
      return std::stoi( decimal_literal->getSymbol()->getText() );
191,044✔
263
    }
264
    if ( auto hex_literal = ctx->HEX_LITERAL() )
32,977✔
265
    {
266
      return static_cast<int>( std::stoul( hex_literal->getSymbol()->getText(), nullptr, 16 ) );
32,968✔
267
    }
268
    if ( auto oct_literal = ctx->OCT_LITERAL() )
9✔
269
    {
270
      return std::stoi( oct_literal->getSymbol()->getText(), nullptr, 8 );
9✔
271
    }
UNCOV
272
    if ( auto binary_literal = ctx->BINARY_LITERAL() )
×
273
    {
UNCOV
274
      return std::stoi( binary_literal->getSymbol()->getText(), nullptr, 2 );
×
275
    }
276
  }
277
  catch ( std::invalid_argument& )
2✔
278
  {
UNCOV
279
    report.error( location_for( *ctx ), "unable to convert integer value '{}'.", ctx->getText() );
×
UNCOV
280
    throw;
×
UNCOV
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

UNCOV
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