<commit_before>/*
 * Copyright 2015 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format)
// and executes it. This provides similar functionality as the reference
// interpreter, like assert_* calls, so it can run the spec test suite.
//

#include <memory>

#include "pass.h"
#include "shell-interface.h"
#include "support/command-line.h"
#include "support/file.h"
#include "wasm-interpreter.h"
#include "wasm-printing.h"
#include "wasm-s-parser.h"
#include "wasm-validator.h"

using namespace cashew;
using namespace wasm;

Name ASSERT_RETURN("assert_return"),
     ASSERT_TRAP("assert_trap"),
     ASSERT_INVALID("assert_invalid"),
     ASSERT_MALFORMED("assert_malformed"),
     ASSERT_UNLINKABLE("assert_unlinkable"),
     INVOKE("invoke"),
     GET("get");

// Modules named in the file

std::map<Name, std::unique_ptr<Module>> modules;
std::map<Name, std::unique_ptr<SExpressionWasmBuilder>> builders;
std::map<Name, std::unique_ptr<ShellExternalInterface>> interfaces;
std::map<Name, std::unique_ptr<ModuleInstance>> instances;

//
// An operation on a module
//

struct Operation {
  ModuleInstance* instance;
  Name operation;
  Name name;
  LiteralList arguments;

  Operation(Element& element, ModuleInstance* instanceInit, SExpressionWasmBuilder& builder) : instance(instanceInit) {
    operation = element[0]->str();
    Index i = 1;
    if (element.size() >= 3 && element[2]->isStr()) {
      // module also specified
      Name moduleName = element[i++]->str();
      instance = instances[moduleName].get();
    }
    name = element[i++]->str();
    for (size_t j = i; j < element.size(); j++) {
      Expression* argument = builder.parseExpression(*element[j]);
      arguments.push_back(argument->dynCast<Const>()->value);
    }
  }

  Literal operate() {
    if (operation == INVOKE) {
      return instance->callExport(name, arguments);
    } else if (operation == GET) {
      return instance->getExport(name);
    } else {
      Fatal() << "unknown operation: " << operation << '\n';
      WASM_UNREACHABLE();
    }
  }
};

static void verify_result(Literal a, Literal b) {
  if (a == b) return;
  // accept equal nans if equal in all bits
  assert(a.type == b.type);
  if (a.type == f32) {
    assert(a.reinterpreti32() == b.reinterpreti32());
  } else if (a.type == f64) {
    assert(a.reinterpreti64() == b.reinterpreti64());
  } else {
    abort();
  }
}

static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
                        Element* root,
                        SExpressionWasmBuilder* builder,
                        Name entry) {
  ModuleInstance* instance = nullptr;
  if (wasm) {
    auto tempInterface = wasm::make_unique<ShellExternalInterface>(); // prefix make_unique to work around visual studio bugs
    auto tempInstance = wasm::make_unique<ModuleInstance>(*wasm, tempInterface.get());
    interfaces[moduleName].swap(tempInterface);
    instances[moduleName].swap(tempInstance);
    instance = instances[moduleName].get();
    if (entry.is()) {
      Function* function = wasm->getFunction(entry);
      if (!function) {
        std::cerr << "Unknown entry " << entry << std::endl;
      } else {
        LiteralList arguments;
        for (WasmType param : function->params) {
          arguments.push_back(Literal(param));
        }
        try {
          instance->callExport(entry, arguments);
        } catch (ExitException&) {
        }
      }
    }
  }
  while (*i < root->size()) {
    Element& curr = *(*root)[*i];
    IString id = curr[0]->str();
    if (id == MODULE) break;
    *checked = true;
    Colors::red(std::cerr);
    std::cerr << *i << '/' << (root->size() - 1);
    Colors::green(std::cerr);
    std::cerr << " CHECKING: ";
    Colors::normal(std::cerr);
    std::cerr << curr;
    Colors::green(std::cerr);
    std::cerr << " [line: " << curr.line << "]\n";
    Colors::normal(std::cerr);
    if (id == ASSERT_INVALID || id == ASSERT_MALFORMED || id == ASSERT_UNLINKABLE) {
      // a module invalidity test
      Module wasm;
      bool invalid = false;
      std::unique_ptr<SExpressionWasmBuilder> builder;
      try {
        builder = std::unique_ptr<SExpressionWasmBuilder>(
          new SExpressionWasmBuilder(wasm, *curr[1])
        );
      } catch (const ParseException&) {
        invalid = true;
      }
      if (!invalid) {
        // maybe parsed ok, but otherwise incorrect
        invalid = !WasmValidator().validate(wasm);
      }
      if (!invalid && id == ASSERT_UNLINKABLE) {
        // validate "instantiating" the mdoule
        for (auto& import : wasm.imports) {
          if (import->module != SPECTEST || import->base != PRINT) {
            std::cerr << "unknown import: " << import->module << '.' << import->base << '\n';
            invalid = true;
            break;
          }
        }
      }
      if (!invalid) {
        Colors::red(std::cerr);
        std::cerr << "[should have been invalid]\n";
        Colors::normal(std::cerr);
        std::cerr << &wasm << '\n';
        abort();
      }
    } else if (id == INVOKE) {
      assert(wasm);<commit_msg>validate spectest.print as a function<commit_after>/*
 * Copyright 2015 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format)
// and executes it. This provides similar functionality as the reference
// interpreter, like assert_* calls, so it can run the spec test suite.
//

#include <memory>

#include "pass.h"
#include "shell-interface.h"
#include "support/command-line.h"
#include "support/file.h"
#include "wasm-interpreter.h"
#include "wasm-printing.h"
#include "wasm-s-parser.h"
#include "wasm-validator.h"

using namespace cashew;
using namespace wasm;

Name ASSERT_RETURN("assert_return"),
     ASSERT_TRAP("assert_trap"),
     ASSERT_INVALID("assert_invalid"),
     ASSERT_MALFORMED("assert_malformed"),
     ASSERT_UNLINKABLE("assert_unlinkable"),
     INVOKE("invoke"),
     GET("get");

// Modules named in the file

std::map<Name, std::unique_ptr<Module>> modules;
std::map<Name, std::unique_ptr<SExpressionWasmBuilder>> builders;
std::map<Name, std::unique_ptr<ShellExternalInterface>> interfaces;
std::map<Name, std::unique_ptr<ModuleInstance>> instances;

//
// An operation on a module
//

struct Operation {
  ModuleInstance* instance;
  Name operation;
  Name name;
  LiteralList arguments;

  Operation(Element& element, ModuleInstance* instanceInit, SExpressionWasmBuilder& builder) : instance(instanceInit) {
    operation = element[0]->str();
    Index i = 1;
    if (element.size() >= 3 && element[2]->isStr()) {
      // module also specified
      Name moduleName = element[i++]->str();
      instance = instances[moduleName].get();
    }
    name = element[i++]->str();
    for (size_t j = i; j < element.size(); j++) {
      Expression* argument = builder.parseExpression(*element[j]);
      arguments.push_back(argument->dynCast<Const>()->value);
    }
  }

  Literal operate() {
    if (operation == INVOKE) {
      return instance->callExport(name, arguments);
    } else if (operation == GET) {
      return instance->getExport(name);
    } else {
      Fatal() << "unknown operation: " << operation << '\n';
      WASM_UNREACHABLE();
    }
  }
};

static void verify_result(Literal a, Literal b) {
  if (a == b) return;
  // accept equal nans if equal in all bits
  assert(a.type == b.type);
  if (a.type == f32) {
    assert(a.reinterpreti32() == b.reinterpreti32());
  } else if (a.type == f64) {
    assert(a.reinterpreti64() == b.reinterpreti64());
  } else {
    abort();
  }
}

static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm,
                        Element* root,
                        SExpressionWasmBuilder* builder,
                        Name entry) {
  ModuleInstance* instance = nullptr;
  if (wasm) {
    auto tempInterface = wasm::make_unique<ShellExternalInterface>(); // prefix make_unique to work around visual studio bugs
    auto tempInstance = wasm::make_unique<ModuleInstance>(*wasm, tempInterface.get());
    interfaces[moduleName].swap(tempInterface);
    instances[moduleName].swap(tempInstance);
    instance = instances[moduleName].get();
    if (entry.is()) {
      Function* function = wasm->getFunction(entry);
      if (!function) {
        std::cerr << "Unknown entry " << entry << std::endl;
      } else {
        LiteralList arguments;
        for (WasmType param : function->params) {
          arguments.push_back(Literal(param));
        }
        try {
          instance->callExport(entry, arguments);
        } catch (ExitException&) {
        }
      }
    }
  }
  while (*i < root->size()) {
    Element& curr = *(*root)[*i];
    IString id = curr[0]->str();
    if (id == MODULE) break;
    *checked = true;
    Colors::red(std::cerr);
    std::cerr << *i << '/' << (root->size() - 1);
    Colors::green(std::cerr);
    std::cerr << " CHECKING: ";
    Colors::normal(std::cerr);
    std::cerr << curr;
    Colors::green(std::cerr);
    std::cerr << " [line: " << curr.line << "]\n";
    Colors::normal(std::cerr);
    if (id == ASSERT_INVALID || id == ASSERT_MALFORMED || id == ASSERT_UNLINKABLE) {
      // a module invalidity test
      Module wasm;
      bool invalid = false;
      std::unique_ptr<SExpressionWasmBuilder> builder;
      try {
        builder = std::unique_ptr<SExpressionWasmBuilder>(
          new SExpressionWasmBuilder(wasm, *curr[1])
        );
      } catch (const ParseException&) {
        invalid = true;
      }
      if (!invalid) {
        // maybe parsed ok, but otherwise incorrect
        invalid = !WasmValidator().validate(wasm);
      }
      if (!invalid && id == ASSERT_UNLINKABLE) {
        // validate "instantiating" the mdoule
        for (auto& import : wasm.imports) {
          if (import->module == SPECTEST && import->base == PRINT) {
            if (import->kind != Import::Function) {
              std::cerr << "spectest.print should be a function, but is " << import->kind << '\n';
              invalid = true;
              break;
            }
          } else {
            std::cerr << "unknown import: " << import->module << '.' << import->base << '\n';
            invalid = true;
            break;
          }
        }
      }
      if (!invalid) {
        Colors::red(std::cerr);
        std::cerr << "[should have been invalid]\n";
        Colors::normal(std::cerr);
        std::cerr << &wasm << '\n';
        abort();
      }
    } else if (id == INVOKE) {
      assert(wasm);
{'fraction_non_alphanumeric': 0.1448929089512757, 'fraction_numerical': 0.004607901698097107, 'mean_word_length': 2.8795100959947035, 'pattern_counts': {'":': 0, '<': 129, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '7286806', 'n_tokens_mistral': 3553, 'n_tokens_neox': 3514, 'n_words': 926}