<commit_before>// Copyright (c) 2015 <NAME>
// All rights reserved

#include "beaker/convert.hpp"
#include "beaker/type.hpp"
#include "beaker/expr.hpp"
#include "beaker/decl.hpp"
#include "beaker/builder.hpp"

#include <iostream>


// Determines how to convert a scalar type to another scalar type.
// TODO: Does not currently convert with bools or chars.
Type const*
get_scalar_conversion_target(Expr* e1, Expr* e2)
{
  assert(e1->type());
  assert(e2->type());
  Type const* t1 = e1->type()->nonref();
  Type const* t2 = e2->type()->nonref();

  // If they're already equal.
  if (t1 == t2)
    return t1;

  // If they're both integers.
  if (is<Integer_type>(t1) && is<Integer_type>(t2))
  {
    Integer_type const* int1 = as<Integer_type>(t1);
    Integer_type const* int2 = as<Integer_type>(t2);

    // Check precision.
    int prec1 = int1->precision();
    int prec2 = int2->precision();
    int largest_prec = prec1;
    if (prec1 < prec2)
      largest_prec = prec2;

    // Check sign.
    Integer_sign sign = signed_int;
    if (int1->is_unsigned() || int2->is_unsigned())
      sign = unsigned_int;

    // Return the integer type with the correct sign and precision.
    return get_integer_type(largest_prec, sign, native_order);
  }

  // If e1 has integer type, try to return that and convert e2 to it later.
  if (!is<Integer_type>(t1) && is<Integer_type>(t2))
    return t2;
  if (is<Integer_type>(t1) && !is<Integer_type>(t2))
    return t1;

  // Default return nullptr.
  return nullptr;
}


// Determines how to convert a scalar type to another scalar type.
// TODO: Does not currently convert with bools or chars.
Type const*
get_scalar_conversion_target(Type const* t1, Type const* t2)
{
  // If they're already equal.
  if (t1 == t2)
    return t1;

  // If they're both integers.
  if (is<Integer_type>(t1) && is<Integer_type>(t2))
  {
    Integer_type const* int1 = as<Integer_type>(t1);
    Integer_type const* int2 = as<Integer_type>(t2);

    // Check precision.
    int prec1 = int1->precision();
    int prec2 = int2->precision();
    int largest_prec = prec1;
    if (prec1 < prec2)
      largest_prec = prec2;

    // Check sign.
    Integer_sign sign = unsigned_int;
    if (int1->is_signed() || int2->is_signed())
      sign = signed_int;

    // Return the integer type with the correct sign and precision.
    return get_integer_type(largest_prec, sign, native_order);
  }

  // If e1 has integer type, try to return that and convert e2 to it later.
  if (!is<Integer_type>(t1) && is<Integer_type>(t2))
    return t2;
  if (is<Integer_type>(t1) && !is<Integer_type>(t2))
    return t1;

  // Default return nullptr.
  return nullptr;
}


// If e has reference type T&, return a conversion
// to the value type T. Otherwise, no conversions
// are required and e is returned.
Expr*
convert_to_value(Expr* e)
{
  if (Reference_type const* t = as<Reference_type>(e->type())) {
    // Do not perform value conversion on types that get translated to opaque type.
    if (is_opaque_translated_type(t->nonref()))
      return e;
    // Otherwise, perform regular value conversion.
    else
      return new Value_conv(t->nonref(), e);
  }
  else
    return e;
}


// If e has type T[N], return a conversion to
// the chunk T[]. Otherwise, just return e.
Expr*
convert_to_block(Expr* e)
{
  if (Array_type const* a = as<Array_type>(e->type()))
    return new Block_conv(get_block_type(a->type()), e);
  else
    return e;
}


// Perform integer conversion
//
// FIXME: All conversions are brute force conversions from one integer type to
//        another. Loss of precision is unhandled.
//
// TODO: see if truncation of integers does not result in loss of precision.
//       Is this even possible on non-constant integers? Seems unlikely.
//
// - Promotion of e's type to t if e's precision is less
//   than t's precision.
//
// - Truncation of e's type to t if e's value can fit within the
//   range possible by t's type.
//
// TODO: support signed and unsigned conversions
//
// - Signed conversion if e is unsigned but it needs to be signed.
//
// Allow LLVM to do the conversions for us.
Expr*
convert_integer_type(Expr* e, Integer_type const* dst)
{
  Integer_type const* src = as<Integer_type>(e->type());
  assert(src);

  return new Promotion_conv(dst, e);
}


// Converting ports to integer types allows us to form keys using port
// identifiers.
Expr*
convert_to_integer_type(Expr* e, Integer_type const* dst)
{
  return new Integer_conv(dst, e);
}


// Perform conversions on argument list passed to variadic function.
Expr_seq
convert_variadic_args(Expr_seq const& args, Type_seq const& parms)
{
  // Converted arguments.
  Expr_seq conv(args.size(), nullptr);

  auto a = args.begin();
  auto p = parms.begin();
  int i = 0;

  while (true) {
    // Stop one-to-one conversions at varargs parameter.
    if (is<Varargs_type>(*p))
      break;

    Expr* c = convert(*a, *p);
    conv[i] = c;
    ++a, ++p, ++i; // Update iterators.
  }

  // Add the rest of the arguments that bind to the variadic parameter.
  // Apply variadic conversions to them.
  while (a != args.end()) {
    conv[i] = variadic_conv((*a)->type(), *a);
    ++a;
  }

  return conv;
}

<commit_msg>fixed bug where multiple variadic arguments were not converted correctly and rvalues passed as variadic arguments were not converted to lvalues.<commit_after>// Copyright (c) 2015 <NAME>
// All rights reserved

#include "beaker/convert.hpp"
#include "beaker/type.hpp"
#include "beaker/expr.hpp"
#include "beaker/decl.hpp"
#include "beaker/builder.hpp"

#include <iostream>


// Determines how to convert a scalar type to another scalar type.
// TODO: Does not currently convert with bools or chars.
Type const*
get_scalar_conversion_target(Expr* e1, Expr* e2)
{
  assert(e1->type());
  assert(e2->type());
  Type const* t1 = e1->type()->nonref();
  Type const* t2 = e2->type()->nonref();

  // If they're already equal.
  if (t1 == t2)
    return t1;

  // If they're both integers.
  if (is<Integer_type>(t1) && is<Integer_type>(t2))
  {
    Integer_type const* int1 = as<Integer_type>(t1);
    Integer_type const* int2 = as<Integer_type>(t2);

    // Check precision.
    int prec1 = int1->precision();
    int prec2 = int2->precision();
    int largest_prec = prec1;
    if (prec1 < prec2)
      largest_prec = prec2;

    // Check sign.
    Integer_sign sign = signed_int;
    if (int1->is_unsigned() || int2->is_unsigned())
      sign = unsigned_int;

    // Return the integer type with the correct sign and precision.
    return get_integer_type(largest_prec, sign, native_order);
  }

  // If e1 has integer type, try to return that and convert e2 to it later.
  if (!is<Integer_type>(t1) && is<Integer_type>(t2))
    return t2;
  if (is<Integer_type>(t1) && !is<Integer_type>(t2))
    return t1;

  // Default return nullptr.
  return nullptr;
}


// Determines how to convert a scalar type to another scalar type.
// TODO: Does not currently convert with bools or chars.
Type const*
get_scalar_conversion_target(Type const* t1, Type const* t2)
{
  // If they're already equal.
  if (t1 == t2)
    return t1;

  // If they're both integers.
  if (is<Integer_type>(t1) && is<Integer_type>(t2))
  {
    Integer_type const* int1 = as<Integer_type>(t1);
    Integer_type const* int2 = as<Integer_type>(t2);

    // Check precision.
    int prec1 = int1->precision();
    int prec2 = int2->precision();
    int largest_prec = prec1;
    if (prec1 < prec2)
      largest_prec = prec2;

    // Check sign.
    Integer_sign sign = unsigned_int;
    if (int1->is_signed() || int2->is_signed())
      sign = signed_int;

    // Return the integer type with the correct sign and precision.
    return get_integer_type(largest_prec, sign, native_order);
  }

  // If e1 has integer type, try to return that and convert e2 to it later.
  if (!is<Integer_type>(t1) && is<Integer_type>(t2))
    return t2;
  if (is<Integer_type>(t1) && !is<Integer_type>(t2))
    return t1;

  // Default return nullptr.
  return nullptr;
}


// If e has reference type T&, return a conversion
// to the value type T. Otherwise, no conversions
// are required and e is returned.
Expr*
convert_to_value(Expr* e)
{
  if (Reference_type const* t = as<Reference_type>(e->type())) {
    // Do not perform value conversion on types that get translated to opaque type.
    if (is_opaque_translated_type(t->nonref()))
      return e;
    // Otherwise, perform regular value conversion.
    else
      return new Value_conv(t->nonref(), e);
  }
  else
    return e;
}


// If e has type T[N], return a conversion to
// the chunk T[]. Otherwise, just return e.
Expr*
convert_to_block(Expr* e)
{
  if (Array_type const* a = as<Array_type>(e->type()))
    return new Block_conv(get_block_type(a->type()), e);
  else
    return e;
}


// Perform integer conversion
//
// FIXME: All conversions are brute force conversions from one integer type to
//        another. Loss of precision is unhandled.
//
// TODO: see if truncation of integers does not result in loss of precision.
//       Is this even possible on non-constant integers? Seems unlikely.
//
// - Promotion of e's type to t if e's precision is less
//   than t's precision.
//
// - Truncation of e's type to t if e's value can fit within the
//   range possible by t's type.
//
// TODO: support signed and unsigned conversions
//
// - Signed conversion if e is unsigned but it needs to be signed.
//
// Allow LLVM to do the conversions for us.
Expr*
convert_integer_type(Expr* e, Integer_type const* dst)
{
  Integer_type const* src = as<Integer_type>(e->type());
  assert(src);

  return new Promotion_conv(dst, e);
}


// Converting ports to integer types allows us to form keys using port
// identifiers.
Expr*
convert_to_integer_type(Expr* e, Integer_type const* dst)
{
  return new Integer_conv(dst, e);
}


// Perform conversions on argument list passed to variadic function.
Expr_seq
convert_variadic_args(Expr_seq const& args, Type_seq const& parms)
{
  // Converted arguments.
  Expr_seq conv(args.size(), nullptr);

  auto a = args.begin();
  auto p = parms.begin();
  int i = 0;

  while (true) {
    // Stop one-to-one conversions at varargs parameter.
    if (is<Varargs_type>(*p))
      break;

    Expr* c = convert(*a, *p);
    conv[i] = c;
    ++a, ++p, ++i; // Update iterators.
  }

  // Add the rest of the arguments that bind to the variadic parameter.
  // Apply variadic conversions to them.
  while (a != args.end()) {
    // All variadic arguments should be value types.
    Expr* v = convert_to_value(*a);
    conv[i] = variadic_conv(v->type(), v);
    ++a, ++i;
  }

  return conv;
}


{'fraction_non_alphanumeric': 0.12548099483810418, 'fraction_numerical': 0.01295166588456124, 'mean_word_length': 3.1722787783868442, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1258220', 'n_tokens_mistral': 3616, 'n_tokens_neox': 3454, 'n_words': 1193}