/*
 * Copyright 2016 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.
 */

#ifndef wasm_builder_h
#define wasm_builder_h

#include <wasm.h>

namespace wasm {

// Useful data structures

struct NameType {
  Name name;
  WasmType type;
  NameType() : name(nullptr), type(none) {}
  NameType(Name name, WasmType type) : name(name), type(type) {}
};

// General AST node builder

class Builder {
public:
  Builder(MixedArena& allocator) : allocator(allocator) {}
  Builder(Module& wasm) : allocator(wasm.allocator) {}

  MixedArena& allocator;

  // make* functions, create nodes

  Function* makeFunction(Name name,
                         std::vector<NameType>&& params,
                         WasmType resultType,
                         std::vector<NameType>&& vars,
                         Expression* body = nullptr) {
    auto* func = new Function;
    func->name = name;
    func->result = resultType;
    func->body = body;

    for (auto& param : params) {
      func->params.push_back(param.type);
      func->localIndices[param.name] = func->localNames.size();
      func->localNames.push_back(param.name);
    }
    for (auto& var : vars) {
      func->vars.push_back(var.type);
      func->localIndices[var.name] = func->localNames.size();
      func->localNames.push_back(var.name);
    }

    return func;
  }

  Nop* makeNop() {
    return allocator.alloc<Nop>();
  }
  Block* makeBlock(Expression* first = nullptr) {
    auto* ret = allocator.alloc<Block>();
    if (first) {
      ret->list.push_back(first, allocator);
      ret->finalize();
    }
    return ret;
  }
  If* makeIf(Expression* condition, Expression* ifTrue, Expression* ifFalse = nullptr) {
    auto* ret = allocator.alloc<If>();
    ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse;
    ret->finalize();
    return ret;
  }
  Loop* makeLoop(Name name, Expression* body) {
    auto* ret = allocator.alloc<Loop>();
    ret->name = name; ret->body = body;
    ret->finalize();
    return ret;
  }
  Break* makeBreak(Name name, Expression* value = nullptr, Expression* condition = nullptr) {
    auto* ret = allocator.alloc<Break>();
    ret->name = name; ret->value = value; ret->condition = condition;
    ret->finalize();
    return ret;
  }
  template<typename T>
  Switch* makeSwitch(T& list, Name default_, Expression* condition, Expression* value = nullptr) {
    auto* ret = allocator.alloc<Switch>();
    ret->targets.set(list, allocator);
    ret->default_ = default_; ret->value = value; ret->condition = condition;
    return ret;
  }
  Call* makeCall(Name target, const std::vector<Expression*>& args, WasmType type) {
    auto* call = allocator.alloc<Call>();
    call->type = type; // not all functions may exist yet, so type must be provided
    call->target = target;
    call->operands.set(args, allocator);
    return call;
  }
  CallImport* makeCallImport(Name target, const std::vector<Expression*>& args, WasmType type) {
    auto* call = allocator.alloc<CallImport>();
    call->type = type; // similar to makeCall, for consistency
    call->target = target;
    call->operands.set(args, allocator);
    return call;
  }
  template<typename T>
  Call* makeCall(Name target, const T& args, WasmType type) {
    auto* call = allocator.alloc<Call>();
    call->type = type; // not all functions may exist yet, so type must be provided
    call->target = target;
    call->operands.set(args, allocator);
    return call;
  }
  template<typename T>
  CallImport* makeCallImport(Name target, const T& args, WasmType type) {
    auto* call = allocator.alloc<CallImport>();
    call->type = type; // similar to makeCall, for consistency
    call->target = target;
    call->operands.set(args, allocator);
    return call;
  }
  CallIndirect* makeCallIndirect(FunctionType* type, Expression* target, const std::vector<Expression*>& args) {
    auto* call = allocator.alloc<CallIndirect>();
    call->fullType = type->name;
    call->type = type->result;
    call->target = target;
    call->operands.set(args, allocator);
    return call;
  }
  CallIndirect* makeCallIndirect(Name fullType, Expression* target, const std::vector<Expression*>& args, WasmType type) {
    auto* call = allocator.alloc<CallIndirect>();
    call->fullType = fullType;
    call->type = type;
    call->target = target;
    call->operands.set(args, allocator);
    return call;
  }
  // FunctionType
  GetLocal* makeGetLocal(Index index, WasmType type) {
    auto* ret = allocator.alloc<GetLocal>();
    ret->index = index;
    ret->type = type;
    return ret;
  }
  SetLocal* makeSetLocal(Index index, Expression* value) {
    auto* ret = allocator.alloc<SetLocal>();
    ret->index = index;
    ret->value = value;
    ret->type = none;
    return ret;
  }
  SetLocal* makeTeeLocal(Index index, Expression* value) {
    auto* ret = allocator.alloc<SetLocal>();
    ret->index = index;
    ret->value = value;
    ret->type = value->type;
    return ret;
  }
  GetGlobal* makeGetGlobal(Name name, WasmType type) {
    auto* ret = allocator.alloc<GetGlobal>();
    ret->name = name;
    ret->type = type;
    return ret;
  }
  SetGlobal* makeSetGlobal(Name name, Expression* value) {
    auto* ret = allocator.alloc<SetGlobal>();
    ret->name = name;
    ret->value = value;
    return ret;
  }
  Load* makeLoad(unsigned bytes, bool signed_, uint32_t offset, unsigned align, Expression *ptr, WasmType type) {
    auto* ret = allocator.alloc<Load>();
    ret->bytes = bytes; ret->signed_ = signed_; ret->offset = offset; ret->align = align; ret->ptr = ptr;
    ret->type = type;
    return ret;
  }
  Store* makeStore(unsigned bytes, uint32_t offset, unsigned align, Expression *ptr, Expression *value, WasmType type) {
    auto* ret = allocator.alloc<Store>();
    ret->bytes = bytes; ret->offset = offset; ret->align = align; ret->ptr = ptr; ret->value = value; ret->valueType = type;
    ret->finalize();
    assert(isConcreteWasmType(ret->value->type) ? ret->value->type == type : true);
    return ret;
  }
  Const* makeConst(Literal value) {
    assert(isConcreteWasmType(value.type));
    auto* ret = allocator.alloc<Const>();
    ret->value = value;
    ret->type = value.type;
    return ret;
  }
  Unary* makeUnary(UnaryOp op, Expression *value) {
    auto* ret = allocator.alloc<Unary>();
    ret->op = op; ret->value = value;
    ret->finalize();
    return ret;
  }
  Binary* makeBinary(BinaryOp op, Expression *left, Expression *right) {
    auto* ret = allocator.alloc<Binary>();
    ret->op = op; ret->left = left; ret->right = right;
    ret->finalize();
    return ret;
  }
  Select* makeSelect(Expression* condition, Expression *ifTrue, Expression *ifFalse) {
    auto* ret = allocator.alloc<Select>();
    ret->condition = condition; ret->ifTrue = ifTrue; ret->ifFalse = ifFalse;
    ret->finalize();
    return ret;
  }
  Return* makeReturn(Expression *value = nullptr) {
    auto* ret = allocator.alloc<Return>();
    ret->value = value;
    return ret;
  }
  Host* makeHost(HostOp op, Name nameOperand, std::vector<Expression*>&& operands) {
    auto* ret = allocator.alloc<Host>();
    ret->op = op;
    ret->nameOperand = nameOperand;
    ret->operands.set(operands, allocator);
    ret->finalize();
    return ret;
  }
  Unreachable* makeUnreachable() {
    return allocator.alloc<Unreachable>();
  }

  // Additional helpers

  Drop* makeDrop(Expression *value) {
    auto* ret = allocator.alloc<Drop>();
    ret->value = value;
    ret->finalize();
    return ret;
  }

  // Additional utility functions for building on top of nodes
  // Convenient to have these on Builder, as it has allocation built in

  static Index addParam(Function* func, Name name, WasmType type) {
    // only ok to add a param if no vars, otherwise indices are invalidated
    assert(func->localIndices.size() == func->params.size());
    func->params.push_back(type);
    Index index = func->localNames.size();
    func->localIndices[name] = index;
    func->localNames.push_back(name);
    return index;
  }

  static Index addVar(Function* func, Name name, WasmType type) {
    // always ok to add a var, it does not affect other indices
    Index index = func->getNumLocals();
    if (name.is()) {
      // if there is a name, apply it, but here we assume all the rest have names too FIXME
      assert(func->localIndices.size() == func->params.size() + func->vars.size());
      func->localIndices[name] = index;
      func->localNames.push_back(name);
    }
    func->vars.emplace_back(type);
    return index;
  }

  static Index addVar(Function* func, WasmType type) {
    return addVar(func, Name(), type);
  }

  static void clearLocals(Function* func) {
    func->params.clear();
    func->vars.clear();
    func->localNames.clear();
    func->localIndices.clear();
  }

  // ensure a node is a block, if it isn't already, and optionally append to the block
  Block* blockify(Expression* any, Expression* append = nullptr) {
    Block* block = nullptr;
    if (any) block = any->dynCast<Block>();
    if (!block) block = makeBlock(any);
    if (append) {
      block->list.push_back(append, allocator);
      block->finalize(); // TODO: move out of if
    }
    return block;
  }

  // ensure a node is a block, if it isn't already, and optionally append to the block
  // this variant sets a name for the block, so it will not reuse a block already named
  Block* blockifyWithName(Expression* any, Name name, Expression* append = nullptr) {
    Block* block = nullptr;
    if (any) block = any->dynCast<Block>();
    if (!block || block->name.is()) block = makeBlock(any);
    block->name = name;
    if (append) {
      block->list.push_back(append, allocator);
      block->finalize(); // TODO: move out of if
    }
    return block;
  }

  // ensures the first node is a block, if it isn't already, and merges in the second,
  // either as a single element or, if a block, by appending to the first block
  Block* blockifyMerge(Expression* any, Expression* append) {
    Block* block = nullptr;
    if (any) block = any->dynCast<Block>();
    if (!block) {
      block = makeBlock(any);
    } else {
      assert(!isConcreteWasmType(block->type));
    }
    auto* other = append->dynCast<Block>();
    if (!other) {
      block->list.push_back(append, allocator);
    } else {
      for (auto* item : other->list) {
        block->list.push_back(item, allocator);
      }
    }
    block->finalize(); // TODO: move out of if
    return block;
  }

  // a helper for the common pattern of a sequence of two expressions. Similar to
  // blockify, but does *not* reuse a block if the first is one.
  Block* makeSequence(Expression* left, Expression* right) {
    auto* block = makeBlock(left);
    block->list.push_back(right, allocator);
    block->finalize();
    return block;
  }

  // Grab a slice out of a block, replacing it with nops, and returning
  // either another block with the contents (if more than 1) or a single expression
  Expression* stealSlice(Block* input, Index from, Index to) {
    Expression* ret;
    if (to == from + 1) {
      // just one
      ret = input->list[from];
    } else {
      auto* block = allocator.alloc<Block>();
      for (Index i = from; i < to; i++) {
        block->list.push_back(input->list[i], allocator);
      }
      block->finalize();
      ret = block;
    }
    if (to == input->list.size()) {
      input->list.resize(from, allocator);
    } else {
      for (Index i = from; i < to; i++) {
        input->list[i] = allocator.alloc<Nop>();
      }
    }
    input->finalize();
    return ret;
  }

  // Drop an expression if it has a concrete type
  Expression* dropIfConcretelyTyped(Expression* curr) {
    if (!isConcreteWasmType(curr->type)) return curr;
    return makeDrop(curr);
  }

  void flip(If* iff) {
    std::swap(iff->ifTrue, iff->ifFalse);
    iff->condition = makeUnary(EqZInt32, iff->condition);
  }
};

} // namespace wasm

#endif // wasm_builder_h
