Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / gn / operators.cc
index 5824ac3..3a815ea 100644 (file)
@@ -53,6 +53,25 @@ void AppendFilteredSourcesToValue(const Scope* scope,
   }
 }
 
+Value GetValueOrFillError(const BinaryOpNode* op_node,
+                          const ParseNode* node,
+                          const char* name,
+                          Scope* scope,
+                          Err* err) {
+  Value value = node->Execute(scope, err);
+  if (err->has_error())
+    return Value();
+  if (value.type() == Value::NONE) {
+    *err = Err(op_node->op(),
+               "Operator requires a value.",
+               "This thing on the " + std::string(name) +
+                   " does not evaluate to a value.");
+    err->AppendRange(node->GetRange());
+    return Value();
+  }
+  return value;
+}
+
 void RemoveMatchesFromList(const BinaryOpNode* op_node,
                            Value* list,
                            const Value& to_remove,
@@ -412,30 +431,59 @@ Value ExecuteLess(Scope* scope,
 
 Value ExecuteOr(Scope* scope,
                 const BinaryOpNode* op_node,
-                const Value& left,
-                const Value& right,
+                const ParseNode* left_node,
+                const ParseNode* right_node,
                 Err* err) {
+  Value left = GetValueOrFillError(op_node, left_node, "left", scope, err);
+  if (err->has_error())
+    return Value();
   if (left.type() != Value::BOOLEAN) {
-    *err = Err(left, "Left side of || operator is not a boolean.");
-    err->AppendRange(op_node->GetRange());
-  } else if (right.type() != Value::BOOLEAN) {
-    *err = Err(right, "Right side of || operator is not a boolean.");
-    err->AppendRange(op_node->GetRange());
+    *err = Err(op_node->left(), "Left side of || operator is not a boolean.",
+        "Type is \"" + std::string(Value::DescribeType(left.type())) +
+        "\" instead.");
+    return Value();
   }
+  if (left.boolean_value())
+    return Value(op_node, left.boolean_value());
+
+  Value right = GetValueOrFillError(op_node, right_node, "right", scope, err);
+  if (err->has_error())
+    return Value();
+  if (right.type() != Value::BOOLEAN) {
+    *err = Err(op_node->right(), "Right side of || operator is not a boolean.",
+        "Type is \"" + std::string(Value::DescribeType(right.type())) +
+        "\" instead.");
+    return Value();
+  }
+
   return Value(op_node, left.boolean_value() || right.boolean_value());
 }
 
 Value ExecuteAnd(Scope* scope,
                  const BinaryOpNode* op_node,
-                 const Value& left,
-                 const Value& right,
+                 const ParseNode* left_node,
+                 const ParseNode* right_node,
                  Err* err) {
+  Value left = GetValueOrFillError(op_node, left_node, "left", scope, err);
+  if (err->has_error())
+    return Value();
   if (left.type() != Value::BOOLEAN) {
-    *err = Err(left, "Left side of && operator is not a boolean.");
-    err->AppendRange(op_node->GetRange());
-  } else if (right.type() != Value::BOOLEAN) {
-    *err = Err(right, "Right side of && operator is not a boolean.");
-    err->AppendRange(op_node->GetRange());
+    *err = Err(op_node->left(), "Left side of && operator is not a boolean.",
+        "Type is \"" + std::string(Value::DescribeType(left.type())) +
+        "\" instead.");
+    return Value();
+  }
+  if (!left.boolean_value())
+    return Value(op_node, left.boolean_value());
+
+  Value right = GetValueOrFillError(op_node, right_node, "right", scope, err);
+  if (err->has_error())
+    return Value();
+  if (right.type() != Value::BOOLEAN) {
+    *err = Err(op_node->right(), "Right side of && operator is not a boolean.",
+        "Type is \"" + std::string(Value::DescribeType(right.type())) +
+        "\" instead.");
+    return Value();
   }
   return Value(op_node, left.boolean_value() && right.boolean_value());
 }
@@ -487,8 +535,9 @@ Value ExecuteUnaryOperator(Scope* scope,
   DCHECK(op_node->op().type() == Token::BANG);
 
   if (expr.type() != Value::BOOLEAN) {
-    *err = Err(expr, "Operand of ! operator is not a boolean.");
-    err->AppendRange(op_node->GetRange());
+    *err = Err(op_node, "Operand of ! operator is not a boolean.",
+        "Type is \"" + std::string(Value::DescribeType(expr.type())) +
+        "\" instead.");
     return Value();
   }
   // TODO(scottmg): Why no unary minus?
@@ -535,28 +584,19 @@ Value ExecuteBinaryOperator(Scope* scope,
     return Value();
   }
 
-  // Left value.
-  Value left_value = left->Execute(scope, err);
-  if (err->has_error())
-    return Value();
-  if (left_value.type() == Value::NONE) {
-    *err = Err(op, "Operator requires a value.",
-               "This thing on the left does not evaluate to a value.");
-    err->AppendRange(left->GetRange());
-    return Value();
-  }
+  // ||, &&. Passed the node instead of the value so that they can avoid
+  // evaluating the RHS on early-out.
+  if (op.type() == Token::BOOLEAN_OR)
+    return ExecuteOr(scope, op_node, left, right, err);
+  if (op.type() == Token::BOOLEAN_AND)
+    return ExecuteAnd(scope, op_node, left, right, err);
 
-  // Right value. Note: don't move this above to share code with the lvalue
-  // version since in this case we want to execute the left side first.
-  Value right_value = right->Execute(scope, err);
+  Value left_value = GetValueOrFillError(op_node, left, "left", scope, err);
   if (err->has_error())
     return Value();
-  if (right_value.type() == Value::NONE) {
-    *err = Err(op, "Operator requires a value.",
-               "This thing on the right does not evaluate to a value.");
-    err->AppendRange(right->GetRange());
+  Value right_value = GetValueOrFillError(op_node, right, "right", scope, err);
+  if (err->has_error())
     return Value();
-  }
 
   // +, -.
   if (op.type() == Token::MINUS)
@@ -578,11 +618,5 @@ Value ExecuteBinaryOperator(Scope* scope,
   if (op.type() == Token::LESS_THAN)
     return ExecuteLess(scope, op_node, left_value, right_value, err);
 
-  // ||, &&.
-  if (op.type() == Token::BOOLEAN_OR)
-    return ExecuteOr(scope, op_node, left_value, right_value, err);
-  if (op.type() == Token::BOOLEAN_AND)
-    return ExecuteAnd(scope, op_node, left_value, right_value, err);
-
   return Value();
 }