c++ – AEC-to-WebAssembly compiler – Code Review Stack Exchange

Now that my new compiler is capable of compiling programs such as the Analog Clock in AEC, I’ve decided to share the code of that compiler with you, to see what you think about it.

File compiler.cpp:

#include "TreeNode.cpp"
#include "bitManipulations.cpp"

AssemblyCode convertToInteger32(const TreeNode node,
                                const CompilationContext context) {
  auto originalCode = node.compile(context);
  const AssemblyCode::AssemblyType i32 = AssemblyCode::AssemblyType::i32,
                                   i64 = AssemblyCode::AssemblyType::i64,
                                   f32 = AssemblyCode::AssemblyType::f32,
                                   f64 = AssemblyCode::AssemblyType::f64,
                                   null = AssemblyCode::AssemblyType::null;
  if (originalCode.assemblyType == null) {
    std::cerr
        << "Line " << node.lineNumber << ", Column " << node.columnNumber
        << ", Compiler error: Some part of the compiler attempted to convert ""
        << node.text
        << "" to "Integer32", which makes no sense. This could be an "
           "internal compiler error, or there could be something semantically "
           "(though not grammatically) very wrong with your program."
        << std::endl;
    exit(1);
  }
  if (originalCode.assemblyType == i32)
    return originalCode;
  if (originalCode.assemblyType == i64)
    return AssemblyCode(
        "(i32.wrap_i64n" + std::string(originalCode.indentBy(1)) + "n)", i32);
  if (originalCode.assemblyType == f32)
    return AssemblyCode(
        "(i32.trunc_f32_sn" + std::string(originalCode.indentBy(1)) + "n)",
        i32); // Makes little sense to me (that, when converting to an integer,
              // the decimal part of the number is simply truncated), but that's
              // how it is done in the vast majority of programming languages.
  if (originalCode.assemblyType == f64)
    return AssemblyCode("(i32.trunc_f64_sn" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        i32);
  std::cerr << "Line " << node.lineNumber << ", Column " << node.columnNumber
            << ", Compiler error: Internal compiler error, control reached the "
               "end of the "convertToInteger32" function!"
            << std::endl;
  exit(-1);
  return AssemblyCode("()");
}

AssemblyCode convertToInteger64(const TreeNode node,
                                const CompilationContext context) {
  auto originalCode = node.compile(context);
  const AssemblyCode::AssemblyType i32 = AssemblyCode::AssemblyType::i32,
                                   i64 = AssemblyCode::AssemblyType::i64,
                                   f32 = AssemblyCode::AssemblyType::f32,
                                   f64 = AssemblyCode::AssemblyType::f64,
                                   null = AssemblyCode::AssemblyType::null;
  if (originalCode.assemblyType == null) {
    std::cerr
        << "Line " << node.lineNumber << ", Column " << node.columnNumber
        << ", Compiler error: Some part of the compiler attempted to convert ""
        << node.text
        << "" to "Integer64", which makes no sense. This could be an "
           "internal compiler error, or there could be something semantically "
           "(though not grammatically) very wrong with your program."
        << std::endl;
    exit(1);
  }
  if (originalCode.assemblyType == i32)
    return AssemblyCode(
        "(i64.extend_i32_sn" + // If you don't put "_s", JavaScript Virtual
                                // Machine is going to interpret the argument as
                                // unsigned, leading to huge positive numbers
                                // instead of negative ones.
            std::string(originalCode.indentBy(1)) + "n)",
        i64);
  if (originalCode.assemblyType == i64)
    return originalCode;
  if (originalCode.assemblyType == f32)
    return AssemblyCode("(i64.trunc_f32_sn" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        i64);
  if (originalCode.assemblyType == f64)
    return AssemblyCode("(i64.trunc_f64_sn" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        i64);
  std::cerr << "Line " << node.lineNumber << ", Column " << node.columnNumber
            << ", Compiler error: Internal compiler error, control reached the "
               "end of the "convertToInteger64" function!"
            << std::endl;
  exit(-1);
  return AssemblyCode("()");
}

AssemblyCode convertToDecimal32(const TreeNode node,
                                const CompilationContext context) {
  auto originalCode = node.compile(context);
  const AssemblyCode::AssemblyType i32 = AssemblyCode::AssemblyType::i32,
                                   i64 = AssemblyCode::AssemblyType::i64,
                                   f32 = AssemblyCode::AssemblyType::f32,
                                   f64 = AssemblyCode::AssemblyType::f64,
                                   null = AssemblyCode::AssemblyType::null;
  if (originalCode.assemblyType == null) {
    std::cerr
        << "Line " << node.lineNumber << ", Column " << node.columnNumber
        << ", Compiler error: Some part of the compiler attempted to convert ""
        << node.text
        << "" to "Decimal32", which makes no sense. This could be an "
           "internal compiler error, or there could be something semantically "
           "(though not grammatically) very wrong with your program."
        << std::endl;
    exit(1);
  }
  if (originalCode.assemblyType == i32)
    return AssemblyCode(
        "(f32.convert_i32_sn" + // Again, those who designed JavaScript Virtual
                                 // Machine had a weird idea that integers
                                 // should be unsigned unless somebody makes
                                 // them explicitly signed via "_s".
            std::string(originalCode.indentBy(1)) + "n)",
        f32);
  if (originalCode.assemblyType == i64)
    return AssemblyCode("(f32.convert_i64_sn" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        f32);
  if (originalCode.assemblyType == f32)
    return originalCode;
  if (originalCode.assemblyType == f64)
    return AssemblyCode("(f32.demote_f64n" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        f32);
  std::cerr << "Line " << node.lineNumber << ", Column " << node.columnNumber
            << ", Compiler error: Internal compiler error, control reached the "
               "end of the "convertToDecimal32" function!"
            << std::endl;
  exit(-1);
  return AssemblyCode("()");
}

AssemblyCode convertToDecimal64(const TreeNode node,
                                const CompilationContext context) {
  auto originalCode = node.compile(context);
  const AssemblyCode::AssemblyType i32 = AssemblyCode::AssemblyType::i32,
                                   i64 = AssemblyCode::AssemblyType::i64,
                                   f32 = AssemblyCode::AssemblyType::f32,
                                   f64 = AssemblyCode::AssemblyType::f64,
                                   null = AssemblyCode::AssemblyType::null;
  if (originalCode.assemblyType == null) {
    std::cerr
        << "Line " << node.lineNumber << ", Column " << node.columnNumber
        << ", Compiler error: Some part of the compiler attempted to convert ""
        << node.text
        << "" to "Decimal64", which makes no sense. This could be an "
           "internal compiler error, or there could be something semantically "
           "(though not grammatically) very wrong with your program."
        << std::endl;
    exit(1);
  }
  if (originalCode.assemblyType == i32)
    return AssemblyCode("(f64.convert_i32_sn" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        f64);
  if (originalCode.assemblyType == i64)
    return AssemblyCode("(f64.convert_i64_sn" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        f64);
  if (originalCode.assemblyType == f32)
    return AssemblyCode("(f64.promote_f32n" +
                            std::string(originalCode.indentBy(1)) + "n)",
                        f64);
  if (originalCode.assemblyType == f64)
    return originalCode;
  std::cerr << "Line " << node.lineNumber << ", Column " << node.columnNumber
            << ", Compiler error: Internal compiler error, control reached the "
               "end of the "convertToDecimal64" function!"
            << std::endl;
  exit(-1);
  return AssemblyCode("()");
}

AssemblyCode convertTo(const TreeNode node, const std::string type,
                       const CompilationContext context) {
  if (type == "Character" or type == "Integer16" or type == "Integer32" or
      std::regex_search(
          type,
          std::regex(
              "Pointer$"))) // When, in JavaScript Virtual Machine, you can't
                            // push types of less than 4 bytes (32 bits) onto
                            // the system stack, you need to convert those to
                            // Integer32 (i32). Well, makes slightly more sense
                            // than the way it is in 64-bit x86 assembly, where
                            // you can put 16-bit values and 64-bit values onto
                            // the system stack, but you can't put 32-bit
                            // values.
    return convertToInteger32(node, context);
  if (type == "Integer64")
    return convertToInteger64(node, context);
  if (type == "Decimal32")
    return convertToDecimal32(node, context);
  if (type == "Decimal64")
    return convertToDecimal64(node, context);
  std::cerr << "Line " << node.lineNumber << ", Column " << node.columnNumber
            << ", Compiler error: Some part of the compiler attempted to get "
               "the assembly code for converting ""
            << node.text << "" into the type "" << type
            << "", which doesn't make sense. This could be an internal "
               "compiler error, or there could be something semantically "
               "(though not grammatically) very wrong with your program."
            << std::endl;
  exit(-1);
  return AssemblyCode("()");
}

std::string getStrongerType(int, int, std::string,
                            std::string); // When C++ doesn't support function
                                          // hoisting, like JavaScript does.

AssemblyCode TreeNode::compile(CompilationContext context) const {
  std::string typeOfTheCurrentNode = getType(context);
  if (!mappingOfAECTypesToWebAssemblyTypes.count(typeOfTheCurrentNode)) {
    std::cerr
        << "Line " << lineNumber << ", Column " << columnNumber
        << ", Internal compiler error: The function "getType" returned ""
        << typeOfTheCurrentNode
        << "", which is an invalid name of type. Aborting the compilation!"
        << std::endl;
    exit(1);
  }
  AssemblyCode::AssemblyType returnType =
      mappingOfAECTypesToWebAssemblyTypes.at(typeOfTheCurrentNode);
  auto iteratorOfTheCurrentFunction =
      std::find_if(context.functions.begin(), context.functions.end(),
                   (=)(function someFunction) {
                     return someFunction.name == context.currentFunctionName;
                   });
  if (iteratorOfTheCurrentFunction == context.functions.end()) {
    std::cerr
        << "Line " << lineNumber << ", Column " << columnNumber
        << ", Internal compiler error: The "compile(CompilationContext)" "
           "function was called without setting the current function name, "
           "aborting compilation (or else the compiler will segfault)!"
        << std::endl;
    exit(1);
  }
  function currentFunction = *iteratorOfTheCurrentFunction;
  std::string assembly;
  if (text == "Does" or text == "Then" or text == "Loop" or
      text == "Else") // Blocks of code are stored by the parser as child nodes
                      // of "Does", "Then", "Else" and "Loop".
  {
    if (text != "Does")
      context.stackSizeOfThisScope =
          0; //"TreeRootNode" is supposed to set up the arguments in the scope
             // before passing the recursion onto the "Does" node.
    for (auto childNode : children) {
      if (childNode.text == "Nothing")
        continue;
      else if (basicDataTypeSizes.count(childNode.text)) {
        // Local variables declaration.
        for (TreeNode variableName : childNode.children) {
          if (variableName.text.back() != '(') { // If it's not an array.
            context.localVariables(variableName.text) = 0;
            for (auto &pair : context.localVariables)
              pair.second += basicDataTypeSizes.at(childNode.text);
            context.variableTypes(variableName.text) = childNode.text;
            context.stackSizeOfThisFunction +=
                basicDataTypeSizes.at(childNode.text);
            context.stackSizeOfThisScope +=
                basicDataTypeSizes.at(childNode.text);
            assembly += "(global.set $stack_pointernt(i32.add (global.get "
                        "$stack_pointer) (i32.const " +
                        std::to_string(basicDataTypeSizes.at(childNode.text)) +
                        ")) ;;Allocating the space for the local variable "" +
                        variableName.text + "".n)n";
            if (variableName.children.size() and
                variableName.children(0).text ==
                    ":=") // Initial assignment to local variables.
            {
              TreeNode assignmentNode = variableName.children(0);
              assignmentNode.children.insert(assignmentNode.children.begin(),
                                             variableName);
              assembly += assignmentNode.compile(context) + "n";
            }
          } else { // If that's a local array declaration.
            int arraySizeInBytes =
                basicDataTypeSizes.at(childNode.text) *
                variableName.children(0)
                    .interpretAsACompileTimeIntegerConstant();
            context.localVariables(variableName.text) = 0;
            for (auto &pair : context.localVariables)
              pair.second += arraySizeInBytes;
            context.variableTypes(variableName.text) = childNode.text;
            context.stackSizeOfThisFunction += arraySizeInBytes;
            context.stackSizeOfThisScope += arraySizeInBytes;
            assembly += "(global.set $stack_pointernt(i32.add (global.get "
                        "$stack_pointer) (i32.const " +
                        std::to_string(arraySizeInBytes) +
                        ")) ;;Allocating the space for the local array "" +
                        variableName.text + "".n)n";
            if (variableName.children.size() == 2 and
                variableName.children(1).text == ":=" and
                variableName.children(1).children(0).text ==
                    "{}") // Initial assignments of local arrays.
            {
              TreeNode initialisationList =
                  variableName.children(1).children(0);
              for (unsigned int i = 0; i < initialisationList.children.size();
                   i++) {
                TreeNode element = initialisationList.children(i);
                TreeNode assignmentNode(
                    ":=", variableName.children(1).lineNumber,
                    variableName.children(1).columnNumber);
                TreeNode whereToAssignTheElement(
                    variableName.text, variableName.lineNumber,
                    variableName
                        .columnNumber); // Damn, can you think up a language in
                                        // which writing stuff like this isn't
                                        // as tedious and error-prone as it is
                                        // in C++ or JavaScript? Maybe some
                                        // language in which you can switch
                                        // between a C-like syntax and a
                                        // Lisp-like syntax at will?
                whereToAssignTheElement.children.push_back(TreeNode(
                    std::to_string(i), variableName.children(0).lineNumber,
                    variableName.children(1).columnNumber));
                assignmentNode.children.push_back(whereToAssignTheElement);
                assignmentNode.children.push_back(element);
                assembly += assignmentNode.compile(context) + "n";
              }
            }
          }
        }
      } else
        assembly += std::string(childNode.compile(context)) + "n";
    }
    assembly += "(global.set $stack_pointer (i32.sub (global.get "
                "$stack_pointer) (i32.const " +
                std::to_string(context.stackSizeOfThisScope) + ")))";
  } else if (text.front() == '"')
    assembly += "(i32.const " + std::to_string(context.globalVariables(text)) +
                ") ;;Pointer to " + text;
  else if (context.variableTypes.count(text)) {
    if (typeOfTheCurrentNode == "Character")
      assembly +=
          "(i32.load8_sn" + compileAPointer(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer16")
      assembly +=
          "(i32.load16_sn" + compileAPointer(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer32" or
             std::regex_search(typeOfTheCurrentNode, std::regex("Pointer$")))
      assembly += "(i32.loadn" + compileAPointer(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer64")
      assembly += "(i64.loadn" + compileAPointer(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Decimal32")
      assembly += "(f32.loadn" + compileAPointer(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Decimal64")
      assembly += "(f64.loadn" + compileAPointer(context).indentBy(1) + "n)";
    else {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Internal compiler error: Compiler got into a forbidden "
                   "state while compiling the token ""
                << text << "", aborting the compilation!" << std::endl;
      exit(1);
    }
  } else if (text == ":=") {
    TreeNode rightSide;
    if (children(1).text == ":=") { // Expressions such as "a:=b:=0" or similar.
      TreeNode tmp = children(1); // In case the "compile" changes the TreeNode
                                  // (which the GNU C++ compiler should forbid,
                                  // but apparently doesn't).
      assembly += children(1).compile(context) + "n";
      rightSide = tmp.children(0);
    } else
      rightSide = children(1);
    assembly += ";;Assigning " + rightSide.getLispExpression() + " to " +
                children(0).getLispExpression() + ".n";
    if (typeOfTheCurrentNode == "Character")
      assembly += "(i32.store8n" +
                  children(0).compileAPointer(context).indentBy(1) + "n" +
                  convertToInteger32(rightSide, context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer16")
      assembly += "(i32.store16n" +
                  children(0).compileAPointer(context).indentBy(1) + "n" +
                  convertToInteger32(rightSide, context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer32" or
             std::regex_search(typeOfTheCurrentNode, std::regex("Pointer$")))
      assembly += "(i32.storen" +
                  children(0).compileAPointer(context).indentBy(1) + "n" +
                  convertToInteger32(rightSide, context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer64")
      assembly += "(i64.storen" +
                  children(0).compileAPointer(context).indentBy(1) + "n" +
                  convertToInteger64(rightSide, context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Decimal32")
      assembly += "(f32.storen" +
                  children(0).compileAPointer(context).indentBy(1) + "n" +
                  convertToDecimal32(rightSide, context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Decimal64")
      assembly += "(f64.storen" +
                  children(0).compileAPointer(context).indentBy(1) + "n" +
                  convertToDecimal64(rightSide, context).indentBy(1) + "n)";
    else {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Internal compiler error: The compiler got into a "
                   "forbidden state while compiling the token ""
                << text << "", aborting the compilation!" << std::endl;
      exit(1);
    }
  } else if (text == "If") {
    if (children.size() < 2) {
      std::cerr
          << "Line " << lineNumber << ", Column " << columnNumber
          << ", Compiler error: Corrupt AST, the "If" node has less than 2 "
             "child nodes. Aborting the compilation (or else we will segfault)!"
          << std::endl;
      exit(1);
    }
    if (children(1).text != "Then") {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: Corrupt AST, the second child of the "
                   ""If" node isn't named "Then". Aborting the compilation "
                   "(or else we will probably segfault)!"
                << std::endl;
      exit(1);
    }
    if (children.size() >= 3 and children(2).text != "Else") {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: Corrupt AST, the third child of the "
                   ""If" node is not named "Else", aborting the "
                   "compilation (or else we will probably segfault)!"
                << std::endl;
      exit(1);
    }
    assembly += "(ifn" + convertToInteger32(children(0), context).indentBy(1) +
                "nt(thenn" + children(1).compile(context).indentBy(2) +
                "nt)" +
                ((children.size() == 3)
                     ? "nt(elsen" +
                           children(2).compile(context).indentBy(2) + "nt)n)"
                     : AssemblyCode("n)"));
  } else if (text == "While") {
    if (children.size() < 2 or children(1).text != "Loop") {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: Corrupt AST, aborting (or else we will "
                   "segfault)!"
                << std::endl;
      exit(1);
    }
    assembly += "(blocknt(loopntt(br_if 1nttt(i32.eqzn" +
                convertToInteger32(children(0), context).indentBy(4) +
                "nttt)ntt)" + children(1).compile(context).indentBy(2) +
                "ntt(br 0)nt)n)";
  } else if (std::regex_match(text,
                              std::regex("(^\d+$)|(^0x(\d|(a-f)|(A-F))+$)")))
    assembly += "(i64.const " + text + ")";
  else if (std::regex_match(text, std::regex("^\d+\.\d*$")))
    assembly += "(f64.const " + text + ")";
  else if (text == "Return") {
    if (currentFunction.returnType != "Nothing") {
      if (children.empty()) {
        std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                  << ", Compiler error: It's not specified what to return from "
                     "a function that's supposed to return ""
                  << currentFunction.returnType
                  << "", aborting the compilation (or else the compiler will "
                     "segfault)!"
                  << std::endl;
        exit(1);
      }
      TreeNode valueToBeReturned = children(0);
      if (valueToBeReturned.text == ":=") {
        TreeNode tmp =
            valueToBeReturned; // The C++ compiler is supposed to forbid
                               // side-effects in the "compile" method, since
                               // it's declared as "const", but apparently it
                               // doesn't. It seems to me there is some bug both
                               // in my code and in GNU C++ compiler (which is
                               // supposed to warn me about it).
        assembly += valueToBeReturned.compile(context) + "n";
        valueToBeReturned = tmp.children(0);
      }
      assembly +=
          ";;Setting for returning: " + valueToBeReturned.getLispExpression() +
          "n";
      assembly += "(local.set $return_valuen";
      assembly +=
          convertTo(valueToBeReturned, currentFunction.returnType, context)
              .indentBy(1) +
          "n)n";
    }
    assembly += "(global.set $stack_pointer (i32.sub (global.get "
                "$stack_pointer) (i32.const " +
                std::to_string(context.stackSizeOfThisFunction) +
                "))) ;;Cleaning up the system stack before returning.n";
    assembly += "(return";
    if (currentFunction.returnType == "Nothing")
      assembly += ")";
    else
      assembly += " (local.get $return_value))";
  } else if (text == "+") {
    std::vector<TreeNode> children =
        this->children; // So that compiler doesn't complain about iter_swap
                        // being called in a constant function.
    if (std::regex_search(children(1).getType(context), std::regex("Pointer$")))
      std::iter_swap(children.begin(), children.begin() + 1);
    std::string firstType = children(0).getType(context);
    std::string secondType = children(1).getType(context);
    if (std::regex_search(
            firstType,
            std::regex(
                "Pointer$"))) // Multiply the second operand by the numbers of
                              // bytes the data type that the pointer points to
                              // takes. That is, be compatible with pointers in
                              // C and C++, rather than with pointers in
                              // Assembly (which allows unaligned access).
      assembly += "(i32.addn" +
                  std::string(children(0).compile(context).indentBy(1)) +
                  "nt(i32.mul (i32.const " +
                  std::to_string(basicDataTypeSizes.at(firstType.substr(
                      0, firstType.size() - std::string("Pointer").size()))) +
                  ")n" + convertToInteger32(children(1), context).indentBy(2) +
                  "nt)n)";
    else
      assembly +=
          "(" + stringRepresentationOfWebAssemblyType.at(returnType) +
          ".addn" +
          convertTo(children(0), typeOfTheCurrentNode, context).indentBy(1) +
          "n" +
          convertTo(children(1), typeOfTheCurrentNode, context).indentBy(1) +
          "n)";
  } else if (text == "-") {
    std::string firstType = children(0).getType(context);
    std::string secondType = children(1).getType(context);
    if (!std::regex_search(firstType, std::regex("Pointer$")) and
        std::regex_search(secondType, std::regex("Pointer$"))) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: What exactly does it mean to subtract a "
                   "pointer from a number? Aborting the compilation!"
                << std::endl;
      exit(1);
    } else if (std::regex_search(firstType, std::regex("Pointer$")) and
               std::regex_search(
                   secondType,
                   std::regex("Pointer$"))) // Subtract two pointers as if they
                                            // were two Integer32s.
      assembly += "(i32.subn" + children(0).compile(context).indentBy(1) +
                  "n" + children(1).compile(context).indentBy(1) + "n)";
    else if (std::regex_search(firstType, std::regex("Pointer$")) and
             !std::regex_search(secondType, std::regex("Pointer$")))
      assembly += "(i32.subn" + children(0).compile(context).indentBy(1) +
                  "nt(i32.mul (i32.const " +
                  std::to_string(basicDataTypeSizes.at(firstType.substr(
                      0, firstType.size() - std::string("Pointer").size()))) +
                  ")n" + children(1).compile(context).indentBy(2) +
                  "ntt)nt)n)";
    else
      assembly +=
          "(" + stringRepresentationOfWebAssemblyType.at(returnType) +
          ".subn" +
          convertTo(children(0), typeOfTheCurrentNode, context).indentBy(1) +
          "n" +
          convertTo(children(1), typeOfTheCurrentNode, context).indentBy(1) +
          "n)";
  } else if (text == "*")
    assembly +=
        "(" + stringRepresentationOfWebAssemblyType.at(returnType) + ".muln" +
        convertTo(children(0), typeOfTheCurrentNode, context).indentBy(1) +
        "n" +
        convertTo(children(1), typeOfTheCurrentNode, context).indentBy(1) +
        "n)";
  else if (text == "/") {
    if (returnType == AssemblyCode::AssemblyType::i32 or
        returnType == AssemblyCode::AssemblyType::i64)
      assembly +=
          "(" + stringRepresentationOfWebAssemblyType.at(returnType) +
          ".div_sn" +
          convertTo(children(0), typeOfTheCurrentNode, context).indentBy(1) +
          "n" +
          convertTo(children(1), typeOfTheCurrentNode, context).indentBy(1) +
          "n)";
    else
      assembly +=
          "(" + stringRepresentationOfWebAssemblyType.at(returnType) +
          ".divn" +
          convertTo(children(0), typeOfTheCurrentNode, context).indentBy(1) +
          "n" +
          convertTo(children(1), typeOfTheCurrentNode, context).indentBy(1) +
          "n)";
  } else if (text == "<" or text == ">") {
    std::string firstType = children(0).getType(context);
    std::string secondType = children(1).getType(context);
    std::string strongerType;
    if (std::regex_search(firstType, std::regex("Pointer$")) and
        std::regex_search(secondType, std::regex("Pointer$")))
      strongerType =
          "Integer32"; // Let's allow people to shoot themselves in the foot by
                       // comparing pointers of different types.
    else
      strongerType =
          getStrongerType(lineNumber, columnNumber, firstType, secondType);
    AssemblyCode::AssemblyType assemblyType =
        mappingOfAECTypesToWebAssemblyTypes.at(strongerType);
    if (assemblyType == AssemblyCode::AssemblyType::i32 or
        assemblyType == AssemblyCode::AssemblyType::i64)
      assembly +=
          "(" + stringRepresentationOfWebAssemblyType.at(assemblyType) +
          (text == "<" ? ".lt_sn" : ".gt_sn") +
          convertTo(children(0), strongerType, context).indentBy(1) + "n" +
          convertTo(children(1), strongerType, context).indentBy(1) + "n)";
    else
      assembly +=
          "(" + stringRepresentationOfWebAssemblyType.at(assemblyType) +
          (text == "<" ? ".ltn" : ".gtn") +
          convertTo(children(0), strongerType, context).indentBy(1) + "n" +
          convertTo(children(1), strongerType, context).indentBy(1) + "n)";
  } else if (text == "=") {
    std::string firstType = children(0).getType(context);
    std::string secondType = children(1).getType(context);
    std::string strongerType;
    if (std::regex_search(firstType, std::regex("Pointer$")) and
        std::regex_search(secondType, std::regex("Pointer$")))
      strongerType = "Integer32";
    else
      strongerType =
          getStrongerType(lineNumber, columnNumber, firstType, secondType);
    AssemblyCode::AssemblyType assemblyType =
        mappingOfAECTypesToWebAssemblyTypes.at(strongerType);
    assembly +=
        "(" + stringRepresentationOfWebAssemblyType.at(assemblyType) + ".eqn" +
        convertTo(children(0), strongerType, context).indentBy(1) + "n" +
        convertTo(children(1), strongerType, context).indentBy(1) + "n)";
  } else if (text == "?:")
    assembly +=
        "(if (result " + stringRepresentationOfWebAssemblyType.at(returnType) +
        ")n" + convertToInteger32(children(0), context).indentBy(1) +
        "nt(thenn" +
        convertTo(children(1), typeOfTheCurrentNode, context).indentBy(2) +
        "nt)nt(elsen" +
        convertTo(children(2), typeOfTheCurrentNode, context).indentBy(2) +
        "nt)n)";
  else if (text == "not(")
    assembly += "(i32.eqzn" +
                convertToInteger32(children(0), context).indentBy(1) + "n)";
  else if (text == "mod(")
    assembly +=
        "(" + stringRepresentationOfWebAssemblyType.at(returnType) +
        ".rem_sn" +
        convertTo(children(0), typeOfTheCurrentNode, context).indentBy(1) +
        "n" +
        convertTo(children(1), typeOfTheCurrentNode, context).indentBy(1) +
        "n)";
  else if (text == "invertBits(")
    assembly += "(i32.xor (i32.const -1)n" +
                convertToInteger32(children(0), context).indentBy(1) + "n)";
  else if (text == "and")
    assembly += "(i32.andn" +
                convertToInteger32(children(0), context).indentBy(1) + "n" +
                convertToInteger32(children(1), context).indentBy(1) + "n)";
  else if (text == "or")
    assembly += "(i32.orn" +
                convertToInteger32(children(0), context).indentBy(1) + "n" +
                convertToInteger32(children(1), context).indentBy(1) + "n)";
  else if (text.back() == '(' and
           basicDataTypeSizes.count(
               text.substr(0, text.size() - 1))) // The casting operator.
    assembly +=
        convertTo(children(0), text.substr(0, text.size() - 1), context);
  else if (std::count_if(context.functions.begin(), context.functions.end(),
                         (=)(function someFunction) {
                           return someFunction.name == text;
                         })) {
    function functionToBeCalled = *find_if(
        context.functions.begin(), context.functions.end(),
        (=)(function someFunction) { return someFunction.name == text; });
    assembly += "(call $" + text.substr(0, text.size() - 1) + "n";
    for (unsigned int i = 0; i < children.size(); i++) {
      if (i >= functionToBeCalled.argumentTypes.size()) {
        std::cerr
            << "Line " << children(i).lineNumber << ", Column "
            << children(i).columnNumber
            << ", Compiler error: Too many arguments passed to the function ""
            << text << "" (it expects "
            << functionToBeCalled.argumentTypes.size()
            << " arguments). Aborting the compilation (or else the compiler "
               "will segfault)!"
            << std::endl;
        exit(1);
      }
      assembly +=
          convertTo(children(i), functionToBeCalled.argumentTypes(i), context)
              .indentBy(1) +
          "n";
    }
    for (unsigned int i = children.size();
         i < functionToBeCalled.defaultArgumentValues.size(); i++) {
      if (!functionToBeCalled.defaultArgumentValues(i))
        std::cerr
            << "Line " << lineNumber << ", Column " << columnNumber
            << ", Compiler warning: The argument #" << i + 1 << " (called ""
            << functionToBeCalled.argumentNames(i)
            << "") of the function named "" << text
            << "" isn't being passed to that function, nor does it have some "
               "default value. Your program will very likely crash because of "
               "that!"
            << std::endl; // JavaScript doesn't even warn about such errors,
                          // while C++ refuses to compile a program then. I
                          // suppose I should take a middle ground here.
      assembly +=
          convertTo(TreeNode(std::to_string(
                                 functionToBeCalled.defaultArgumentValues(i)),
                             lineNumber, columnNumber),
                    functionToBeCalled.argumentTypes(i), context)
              .indentBy(1);
    }
    assembly += ")";
  } else if (text == "ValueAt(") {
    if (typeOfTheCurrentNode == "Character")
      assembly +=
          "(i32.load8_sn" + children(0).compile(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer16")
      assembly +=
          "(i32.load16_sn" + children(0).compile(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer32" or
             std::regex_search(typeOfTheCurrentNode, std::regex("Pointer$")))
      assembly +=
          "(i32.loadn" + children(0).compile(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Integer64")
      assembly +=
          "(i64.loadn" + children(0).compile(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Decimal32")
      assembly +=
          "(f32.loadn" + children(0).compile(context).indentBy(1) + "n)";
    else if (typeOfTheCurrentNode == "Decimal64")
      assembly +=
          "(f64.loadn" + children(0).compile(context).indentBy(1) + "n)";
    else {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Internal compiler error: The compiler got into a "
                   "forbidden state while compiling "ValueAt", aborting!"
                << std::endl;
      exit(1);
    }
  } else if (text == "AddressOf(")
    return children(0).compileAPointer(context);
  else {
    std::cerr << "Line " << lineNumber << ", Column " << columnNumber
              << ", Compiler error: No rule to compile the token "" << text
              << "", quitting now!" << std::endl;
    exit(1);
  }
  return AssemblyCode(assembly, returnType);
}

AssemblyCode TreeNode::compileAPointer(CompilationContext context) const {
  if (text == "ValueAt(")
    return children(0).compile(context);
  if (context.localVariables.count(text) and text.back() != '(')
    return AssemblyCode(
        "(i32.subnt(global.get $stack_pointer)nt(i32.const " +
            std::to_string(context.localVariables(text)) + ") ;;" + text +
            "n)",
        AssemblyCode::AssemblyType::i32);
  if (context.localVariables.count(text) and text.back() == '(') {
    if (children.empty()) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: The array ""
                << text.substr(0, text.size() - 1)
                << "" has no index in the AST. Aborting the compilation, or "
                   "else the compiler will segfault!"
                << std::endl;
      exit(1);
    }
    return AssemblyCode(
        "(i32.addnt(i32.subntt(global.get "
        "$stack_pointer)ntt(i32.const " +
            std::to_string(context.localVariables(text)) + ") ;;" + text +
            "nt)nt(i32.mulntt(i32.const " +
            std::to_string(basicDataTypeSizes.at(getType(context))) + ")n" +
            std::string(convertToInteger32(children(0), context).indentBy(2)) +
            "nt)n)",
        AssemblyCode::AssemblyType::i32);
  }
  if (context.globalVariables.count(text) and text.back() != '(')
    return AssemblyCode("(i32.const " +
                            std::to_string(context.globalVariables(text)) +
                            ") ;;" + text,
                        AssemblyCode::AssemblyType::i32);
  if (context.globalVariables.count(text) and text.back() == '(') {
    if (children.empty()) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: The array ""
                << text.substr(0, text.size() - 1)
                << "" has no index in the AST. Aborting the compilation, or "
                   "else the compiler will segfault!"
                << std::endl;
      exit(1);
    }
    return AssemblyCode(
        "(i32.addnt(i32.const " +
            std::to_string(context.globalVariables(text)) + ") ;;" + text +
            "nt(i32.mulntt(i32.const " +
            std::to_string(basicDataTypeSizes.at(getType(context))) + ")n" +
            std::string(convertToInteger32(children(0), context).indentBy(3)) +
            "nt)n)",
        AssemblyCode::AssemblyType::i32);
  }
  std::cerr << "Line " << lineNumber << ", Column " << columnNumber
            << ", Compiler error: Some part of the compiler attempted to get "
               "the assembly of the pointer to ""
            << text
            << "", which makes no sense. This could be an internal compiler "
               "error, or there could be something semantically (though not "
               "grammatically) very wrong with your program."
            << std::endl;
  exit(1);
  return AssemblyCode("()");
}

std::string getStrongerType(int lineNumber, int columnNumber,
                            std::string firstType, std::string secondType) {
  if (firstType == "Nothing" or secondType == "Nothing") {
    std::cerr << "Line " << lineNumber << ", Column " << columnNumber
              << ", Compiler error: Can't add, subtract, multiply or divide "
                 "with something of the type "Nothing"!";
    exit(1);
  }
  if (std::regex_search(firstType, std::regex("Pointer$")) and
      !std::regex_search(secondType, std::regex("Pointer$")))
    return firstType;
  if (std::regex_search(secondType, std::regex("Pointer$")) and
      !std::regex_search(firstType, std::regex("Pointer$")))
    return secondType;
  if (std::regex_search(firstType, std::regex("Pointer$")) and
      std::regex_search(secondType, std::regex("Pointer$"))) {
    std::cerr
        << "Line " << lineNumber << ", Column " << columnNumber
        << ", Compiler error: Can't add, multiply or divide two pointers!";
  }
  if (firstType == "Decimal64" or secondType == "Decimal64")
    return "Decimal64";
  if (firstType == "Decimal32" or secondType == "Decimal32")
    return "Decimal32";
  if (firstType == "Integer64" or secondType == "Integer64")
    return "Integer64";
  if (firstType == "Integer32" or secondType == "Integer32")
    return "Integer32";
  if (firstType == "Integer16" or secondType == "Integer16")
    return "Integer16";
  return firstType;
}

std::string TreeNode::getType(CompilationContext context) const {
  if (std::regex_match(text, std::regex("(^\d+$)|(^0x(\d|(a-f)|(A-F))+$)")))
    return "Integer64";
  if (std::regex_match(text, std::regex("^\d+\.\d*$")))
    return "Decimal64";
  if (text == "AddressOf(") {
    if (children.empty()) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: "AddressOf" is without the argument!"
                << std::endl;
      exit(1);
    }
    if (children.size() > 1) {
      std::cerr
          << "Line " << lineNumber << ", Column " << columnNumber
          << ", Compiler error: Can't take the address of multiple variables!"
          << std::endl;
      exit(1);
    }
    if (children(0).getType(context) == "Nothing") {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: "AddressOf" has an argument of type "
                   ""Nothing"!"
                << std::endl;
      exit(1);
    }
    return children(0).getType(context) + "Pointer";
  }
  if (text == "ValueAt(") {
    if (children.empty()) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: "ValueAt" is without the argument!"
                << std::endl;
      exit(1);
    }
    if (children.size() > 1) {
      std::cerr
          << "Line " << lineNumber << ", Column " << columnNumber
          << ", Compiler error: Can't dereference multiple variables at once!"
          << std::endl;
      exit(1);
    }
    if (std::regex_search(children(0).getType(context),
                          std::regex("Pointer$")) == false) {
      std::cerr
          << "Line " << lineNumber << ", Column " << columnNumber
          << ", Compiler error: The argument to "ValueAt" is not a pointer!"
          << std::endl;
      exit(1);
    }
    return children(0).getType(context).substr(
        0, children(0).getType(context).size() - std::string("Pointer").size());
  }
  if (context.variableTypes.count(text))
    return context.variableTypes(text);
  if (text(0) == '"') {
    std::cerr << "Line " << lineNumber << ", Column " << columnNumber
              << ", Internal compiler error: A pointer to the string " << text
              << " is being attempted to compile before the string itself has "
                 "been compiled, aborting the compilation!"
              << std::endl;
    exit(1);
  }
  if (text == "and" or text == "or" or text == "<" or text == ">" or
      text == "=" or text == "not(" or text == "invertBits(") {
    if (children.empty()) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: The operator "" << text
                << "" has no operands. Aborting the compilation (or else we "
                   "will segfault)!"
                << std::endl;
      exit(1);
    }
    if (children.size() < 2 and text != "not(" and text != "invertBits(") {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: The binary operator "" << text
                << "" has less than two operands. Aborting the compilation "
                   "(or else we will segfault)!"
                << std::endl;
      exit(1);
    }
    return "Integer32"; // Because "if" and "br_if" in WebAssembly expect a
                        // "i32", so let's adapt to that.
  }
  if (text == "mod(") {
    if (children.size() != 2) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: "mod(" operator requires two integer "
                   "arguments!"
                << std::endl;
      exit(1);
    }
    if (std::regex_search(children(0).getType(context),
                          std::regex("^Decimal")) or
        std::regex_search(children(1).getType(context),
                          std::regex("^Decimal"))) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: Unfortunately, WebAssembly (unlike x86 "
                   "assembly) doesn't support computing remaining of division "
                   "of decimal numbers, so we can't support that either "
                   "outside of compile-time constants."
                << std::endl;
      exit(1);
    }
    return getStrongerType(lineNumber, columnNumber,
                           children(0).getType(context),
                           children(1).getType(context));
  }
  if (text == "If" or text == "Then" or text == "Else" or text == "While" or
      text == "Loop" or text == "Does" or
      text == "Return") // Or else the compiler will claim those
                        // tokens are undeclared variables.
    return "Nothing";
  if (std::regex_match(text, std::regex("^(_|(a-z)|(A-Z))\w*\(?"))) {
    std::cerr << "Line " << lineNumber << ", Column " << columnNumber
              << ", Compiler error: The variable name "" << text
              << "" is not declared!" << std::endl;
    exit(1);
  }
  if (text == "+" or text == "*" or text == "/") {
    if (children.size() != 2) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: The binary operator "" << text
                << "" doesn't have exactly two operands. Aborting the "
                   "compilation (or else we will segfault)!"
                << std::endl;
      exit(1);
    }
    return getStrongerType(lineNumber, columnNumber,
                           children(0).getType(context),
                           children(1).getType(context));
  }
  if (text == "-") {
    if (children.size() != 2) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: The binary operator "" << text
                << "" doesn't have exactly two operands. Aborting the "
                   "compilation (or else we will segfault)!"
                << std::endl;
      exit(1);
    }
    if (std::regex_search(children(0).getType(context),
                          std::regex("Pointer$")) and
        std::regex_search(children(1).getType(context), std::regex("Pointer$")))
      return "Integer32"; // Difference between pointers is an integer of the
                          // same size as the pointers (32-bit).
    return getStrongerType(lineNumber, columnNumber,
                           children(0).getType(context),
                           children(1).getType(context));
  }
  if (text == ":=") {
    if (children.size() < 2) {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: The assignment operator ":=" has less "
                   "than two operands. Aborting the compilation, or else the "
                   "compiler will segfault."
                << std::endl;
      exit(1);
    }
    if (children(1).getType(context) == "Nothing") {
      std::cerr << "Line " << lineNumber << ", Column " << columnNumber
                << ", Compiler error: Attempting to assign something of the "
                   "type "Nothing" to a variable. Aborting the compilation!"
                << std::endl;
    }
    return children(0).getType(context);
  }
  auto potentialFunction =
      std::find_if(context.functions.begin(), context.functions.end(),
                   (=)(function fn) { return fn.name == text; });
  if (potentialFunction != context.functions.end())
    return potentialFunction->returnType;
  if (text.back() == '(' and
      basicDataTypeSizes.count(text.substr(0, text.size() - 1))) // Casting
    return text.substr(0, text.size() - 1);
  if (text.back() == '(') {
    std::cerr << "Line " << lineNumber << ", Column " << columnNumber
              << ", Compiler error: Function "" << text
              << "" is not declared!" << std::endl;
    exit(1);
  }
  if (text == "?:")
    return getStrongerType(lineNumber, columnNumber,
                           children(1).getType(context),
                           children(2).getType(context));
  return "Nothing";
}

The rest of the code is available on my GitHub profile, it’s about 4’000 lines long, and I don’t think most of it is relevant here.

pathfinder 1e – Does the rogue advanced talent, petrifying strike damage stack?

Yes, it does. Ability damage is like hp damage — you deal it, and it happens instantaneously, “for real.” There’s no “effect” in place reducing their ability score; it’s simply been damaged, and has to heal in order to recover its original value. Thus, ability damage almost always stacks (and even when the rules say it doesn’t, that’s often pretty confusing).

Contrast this with ability drain, which is an ongoing effect that reduces an ability score. Applying the same ability-draining effect more than once would not stack.

python – Pandas dtype error while parsing Stack Overflow Datadump CSV file

I faced some errors while reading a csv generated from https://data.stackexchange.com/stackoverflow/query/new using this query:

select * from Posts Q, Posts A where Q.PostTypeId = 1 and Q.Tags like '%<java>%' and Q.CreationDate <= '2018-12-31 11:11:59' and Q.AnswerCount >= 2 and Q.AcceptedAnswerId > 0 and A.PostTypeID = 2 and Q.Id = A.ParentId order by Q.Id asc
Then I downloaded the CSV. I tried to read the CSV with Pandas and encountered with the following error:

/opt/anaconda3/lib/python3.7/site-packages/IPython/core/interactiveshell.py:3063: DtypeWarning: Columns (35) have mixed types.Specify dtype option on import or set low_memory=False. interactivity=interactivity, compiler=compiler, result=result)

The NaN field should be a number. Moreover this works clearly with turicreate SFrame. Please help.
Error snapshot.

Decompiling shellcode – Information Security Stack Exchange

I’m trying to understand how shellcode works.

I wrote a simple program in C#, then I used Donut to create the shellcode from that exe in base64 format.
Then, I wrote again another program to convert the base64 shellcode in a sequence of bytes, in order to reproduce the original exe.

I noticed a difference: ILSpy is able to open the first one, but no the latter since it says “pe file does not contain any managed metadata”, indicating that is not a C# program.
Moreover, there is a small difference in the size so definitively the checksum is different.

Could someone explain what happened? Is there a way to decompile this program?

About Bitcoin Core – Bitcoin Stack Exchange

Stack Exchange Network


Stack Exchange network consists of 177 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.

Visit Stack Exchange

Condição Se em Excel – Stack Overflow em Português

Estou a tentar criar uma condição em excel em que se o texto numa folha for = sim então faz uma acção, eu tentei fazer assim mas diz que é um referencia circular.

=SE('Dados do paciente'!N3="Sim";0; A3='Dados do paciente'!A3)

A coisa é que ele diz que é um referencia circular mas quando eu analiso ele dá Sim=Sim logo deveria depois deveria realizar a operação

inserir a descrição da imagem aqui

inserir a descrição da imagem aqui

lens – Bird photography – Photography Stack Exchange

I have Canon 1200D. I use the 55-250mm kit lens for bird photography.

Laughing Dove

Laughing Dove

Indian White-eye

Indian White-eye

The Laughing Dove was far as compared to Indian White-eye. My point is whenever I click photos of birds near to the lens , it gives a very sharp image. But if it has to focus far it produces not-so-sharp images.
Any suggestion on how to improve focus for longer focal lengths? I use both manual as well as autofocus and shoot in RAW.

vectors – Demonstrations exercises – Mathematics Stack Exchange

Thanks for contributing an answer to Mathematics Stack Exchange!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

Use MathJax to format equations. MathJax reference.

To learn more, see our tips on writing great answers.

Help with Taylor expansion – Mathematica Stack Exchange

I need help Taylor expanding the following

(k^2 (-z + z2 + Sqrt((z - z2)^2 + (Rho)^2)) (-z + z4 + 
     Sqrt((z - z4)^2 + (Rho)^2)) ((Rho)^2 + (-z + z1 + 
        Sqrt((z - z1)^2 + (Rho)^2)) (-z + z2 + 
        Sqrt((z - z2)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z2 + 
        Sqrt((z - z2)^2 + (Rho)^2)) (-z + z3 + 
        Sqrt((z - z3)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z1 + 
        Sqrt((z - z1)^2 + (Rho)^2)) (-z + z4 + 
        Sqrt((z - z4)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z3 + 
        Sqrt((z - z3)^2 + (Rho)^2)) (-z + z4 + 
        Sqrt((z - z4)^2 + (Rho)^2)))^2)/((-z + z1 + 
     Sqrt((z - z1)^2 + (Rho)^2)) (-z + z3 + 
     Sqrt((z - z3)^2 + (Rho)^2)) ((Rho)^2 + (-z + z1 + 
       Sqrt((z - z1)^2 + (Rho)^2))^2) ((Rho)^2 + (-z + z2 + 
       Sqrt((z - z2)^2 + (Rho)^2))^2) ((Rho)^2 + (-z + z1 + 
        Sqrt((z - z1)^2 + (Rho)^2)) (-z + z3 + 
        Sqrt((z - z3)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z3 + 
       Sqrt((z - z3)^2 + (Rho)^2))^2) ((Rho)^2 + (-z + z2 + 
        Sqrt((z - z2)^2 + (Rho)^2)) (-z + z4 + 
        Sqrt((z - z4)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z4 + 
       Sqrt((z - z4)^2 + (Rho)^2))^2)

around (Rho)=0 within z1 <= z <= z2 for z1 <= z2 <= z3 <= z4 where k is some
real constant

I tried

$Assumptions := z1 <= z <= z2 && z1 <= z2 <= z3 <= z4

(k^2 (-z + z2 + Sqrt((z - z2)^2 + (Rho)^2)) (-z + z4 + 
     Sqrt((z - z4)^2 + (Rho)^2)) ((Rho)^2 + (-z + z1 + 
        Sqrt((z - z1)^2 + (Rho)^2)) (-z + z2 + 
        Sqrt((z - z2)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z2 + 
        Sqrt((z - z2)^2 + (Rho)^2)) (-z + z3 + 
        Sqrt((z - z3)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z1 + 
        Sqrt((z - z1)^2 + (Rho)^2)) (-z + z4 + 
        Sqrt((z - z4)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z3 + 
        Sqrt((z - z3)^2 + (Rho)^2)) (-z + z4 + 
        Sqrt((z - z4)^2 + (Rho)^2)))^2)/((-z + z1 + 
     Sqrt((z - z1)^2 + (Rho)^2)) (-z + z3 + 
     Sqrt((z - z3)^2 + (Rho)^2)) ((Rho)^2 + (-z + z1 + 
       Sqrt((z - z1)^2 + (Rho)^2))^2) ((Rho)^2 + (-z + z2 + 
       Sqrt((z - z2)^2 + (Rho)^2))^2) ((Rho)^2 + (-z + z1 + 
        Sqrt((z - z1)^2 + (Rho)^2)) (-z + z3 + 
        Sqrt((z - z3)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z3 + 
       Sqrt((z - z3)^2 + (Rho)^2))^2) ((Rho)^2 + (-z + z2 + 
        Sqrt((z - z2)^2 + (Rho)^2)) (-z + z4 + 
        Sqrt((z - z4)^2 + (Rho)^2)))^2 ((Rho)^2 + (-z + z4 + 
       Sqrt((z - z4)^2 + (Rho)^2))^2) // FullSimplify

But I was unable to get the correct expansion

Python circular dependency – Software Engineering Stack Exchange

I have two classes AST and ASTNode for working with some tree-like data. Both these classes have networkx graph as a field and a node id (integer). For AST this id refers to the root of a tree. These two classes looks pretty similar, but I have splited functionality in a following way:

  • I use AST for global functionality like get nodes of some type from a whole tree
  • I use ASTNode for local functionality like get direct child of a node and other node properties

I need to be able to shift from AST to ASTNode functionality and backward when needed. Here comes circular dependency. I want to be able:

  • to query some ASTNode from AST
  • to build a subtree from ASTNode with this node as a root

So this makes ASTNode to know how to create AST. How can I deal with it? Should I use absolute module import? Or it can be done otherwise?

Currently I moved get_subtree(node) function to AST, but this make usage really uncomfortable (you have to pass node and a tree together all the time).