<commit_before>// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include <ctype.h>  // isspace.

#include "vm/bootstrap_natives.h"

#include "vm/bigint_operations.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/random.h"
#include "vm/scanner.h"
#include "vm/symbols.h"

namespace dart {

DEFINE_NATIVE_ENTRY(MathNatives_sqrt, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(sqrt(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_sin, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(sin(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_cos, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(cos(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_tan, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(tan(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_asin, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(asin(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_acos, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(acos(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_atan, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(atan(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_atan2, 2) {
  GET_NATIVE_ARGUMENT(Double, operand1, arguments->At(0));
  GET_NATIVE_ARGUMENT(Double, operand2, arguments->At(1));
  return Double::New(atan2(operand1.value(), operand2.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_exp, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(exp(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_log, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(log(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_random, 0) {
  return Double::New(static_cast<double>(Random::RandomInt32()-1)/0x80000000);
}


// TODO(srdjan): Investigate for performance hit; the integer and double parsing
// may not be efficient as we need to generate two extra growable arrays.
static bool IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
                           Token::Kind literal_kind,
                           bool* is_positive,
                           String** value) {
  if ((tokens.length() == 2) &&
      (tokens[0].kind == literal_kind) &&
      (tokens[1].kind == Token::kEOS)) {
    *is_positive = true;
    *value = tokens[0].literal;
    return true;
  }
  if ((tokens.length() == 3) &&
      ((tokens[0].kind == Token::kTIGHTADD) ||
          (tokens[0].kind == Token::kSUB)) &&
      (tokens[1].kind == literal_kind) &&
      (tokens[2].kind == Token::kEOS)) {
    // Check there is no space between "+/-" and number.
    if ((tokens[0].offset + 1) != tokens[1].offset) {
      return false;
    }
    *is_positive = tokens[0].kind == Token::kTIGHTADD;
    *value = tokens[1].literal;
    return true;
  }
  return false;
}


DEFINE_NATIVE_ENTRY(MathNatives_parseInt, 1) {
  GET_NATIVE_ARGUMENT(String, value, arguments->At(0));
  Scanner scanner(value, String::Handle());
  const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
  String* int_string;
  bool is_positive;
  if (IsValidLiteral(tokens, Token::kINTEGER, &is_positive, &int_string)) {
    if (is_positive) {
      return Integer::New(*int_string);
    } else {
      String& temp = String::Handle();
      temp = String::Concat(String::Handle(Symbols::New("-")),
                            *int_string);
      return Integer::New(temp);
    }
  } else {
    GrowableArray<const Object*> args;
    args.Add(&value);
    Exceptions::ThrowByType(Exceptions::kFormat, args);
    return Object::null();
  }
}


DEFINE_NATIVE_ENTRY(MathNatives_parseDouble, 1) {
  GET_NATIVE_ARGUMENT(String, value, arguments->At(0));
  Scanner scanner(value, String::Handle());
  const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
  String* number_string;
  bool is_positive;
  if (IsValidLiteral(tokens, Token::kDOUBLE, &is_positive, &number_string)) {
    const char* cstr = number_string->ToCString();
    char* p_end = NULL;
    double double_value = strtod(cstr, &p_end);
    ASSERT(p_end != cstr);
    if (!is_positive) {
      double_value = -double_value;
    }
    return Double::New(double_value);
  }
<commit_msg>Fix for issue 4808 (The vm crashes when parseInt is called with string containing a $). Review URL: https://chromiumcodereview.appspot.com//10909152<commit_after>// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include <ctype.h>  // isspace.

#include "vm/bootstrap_natives.h"

#include "vm/bigint_operations.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/random.h"
#include "vm/scanner.h"
#include "vm/symbols.h"

namespace dart {

DEFINE_NATIVE_ENTRY(MathNatives_sqrt, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(sqrt(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_sin, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(sin(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_cos, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(cos(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_tan, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(tan(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_asin, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(asin(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_acos, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(acos(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_atan, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(atan(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_atan2, 2) {
  GET_NATIVE_ARGUMENT(Double, operand1, arguments->At(0));
  GET_NATIVE_ARGUMENT(Double, operand2, arguments->At(1));
  return Double::New(atan2(operand1.value(), operand2.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_exp, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(exp(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_log, 1) {
  GET_NATIVE_ARGUMENT(Double, operand, arguments->At(0));
  return Double::New(log(operand.value()));
}

DEFINE_NATIVE_ENTRY(MathNatives_random, 0) {
  return Double::New(static_cast<double>(Random::RandomInt32()-1)/0x80000000);
}


// TODO(srdjan): Investigate for performance hit; the integer and double parsing
// may not be efficient as we need to generate two extra growable arrays.
static bool IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
                           Token::Kind literal_kind,
                           bool* is_positive,
                           String** value) {
  if ((tokens.length() == 2) &&
      (tokens[0].kind == literal_kind) &&
      (tokens[1].kind == Token::kEOS)) {
    *is_positive = true;
    *value = tokens[0].literal;
    return true;
  }
  if ((tokens.length() == 3) &&
      ((tokens[0].kind == Token::kTIGHTADD) ||
          (tokens[0].kind == Token::kSUB)) &&
      (tokens[1].kind == literal_kind) &&
      (tokens[2].kind == Token::kEOS)) {
    // Check there is no space between "+/-" and number.
    if ((tokens[0].offset + 1) != tokens[1].offset) {
      return false;
    }
    *is_positive = tokens[0].kind == Token::kTIGHTADD;
    *value = tokens[1].literal;
    return true;
  }
  return false;
}


DEFINE_NATIVE_ENTRY(MathNatives_parseInt, 1) {
  GET_NATIVE_ARGUMENT(String, value, arguments->At(0));
  const String& dummy_key = String::Handle(Symbols::Empty());
  Scanner scanner(value, dummy_key);
  const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
  String* int_string;
  bool is_positive;
  if (IsValidLiteral(tokens, Token::kINTEGER, &is_positive, &int_string)) {
    if (is_positive) {
      return Integer::New(*int_string);
    } else {
      String& temp = String::Handle();
      temp = String::Concat(String::Handle(Symbols::New("-")),
                            *int_string);
      return Integer::New(temp);
    }
  } else {
    GrowableArray<const Object*> args;
    args.Add(&value);
    Exceptions::ThrowByType(Exceptions::kFormat, args);
    return Object::null();
  }
}


DEFINE_NATIVE_ENTRY(MathNatives_parseDouble, 1) {
  GET_NATIVE_ARGUMENT(String, value, arguments->At(0));
  const String& dummy_key = String::Handle(Symbols::Empty());
  Scanner scanner(value, dummy_key);
  const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
  String* number_string;
  bool is_positive;
  if (IsValidLiteral(tokens, Token::kDOUBLE, &is_positive, &number_string)) {
    const char* cstr = number_string->ToCString();
    char* p_end = NULL;
    double double_value = strtod(cstr, &p_end);
    ASSERT(p_end != cstr);
    if (!is_positive) {
      double_value = -double_value;
    }
    return Double::New(double_value);
  }

{'fraction_non_alphanumeric': 0.14947524647514046, 'fraction_numerical': 0.014417470581999364, 'mean_word_length': 4.403207331042383, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 37, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, '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': '1734741', 'n_tokens_mistral': 3364, 'n_tokens_neox': 3211, 'n_words': 625}