Skip to content

Commit

Permalink
Add support for "else if" in gyp conditions
Browse files Browse the repository at this point in the history
Right now, a gyp condition consists of exactly two or three parts:

  [cond_expr, true_dict]
  [cond_expr, true_dict, false_dict]

This means if we want to have an "else if" condition, it needs to be inside a
nested 'conditions' list inside the false_dict.  This leads to unnecessarily
deep levels of nesting in gyp files.

This commit makes it so that if the 'false_dict' is not a dict, then we will
treat it as another cond_expr.  We keep looping like this until we find a
false_dict, or until we reach the end of the list.

This means we can now have conditions that look like this:

  [cond_expr1, true_dict1, cond_expr2, true_dict2, false_dict]

or:

  [cond_expr1, true_dict1, cond_expr2, true_dict2, cond_expr3, true_dict3]

BUG=
R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/601353002

git-svn-id: http://gyp.googlecode.com/svn/trunk@2004 78cadc50-ecff-11dd-a971-7dbc132099af
  • Loading branch information
bulldy80 committed Nov 18, 2014
1 parent 0131ede commit fb8a7bd
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 7 deletions.
38 changes: 31 additions & 7 deletions pylib/gyp/input.py
Expand Up @@ -341,7 +341,8 @@ def ProcessToolsetsInDict(data):
for condition in data['conditions']:
if type(condition) is list:
for condition_dict in condition[1:]:
ProcessToolsetsInDict(condition_dict)
if type(condition_dict) is dict:
ProcessToolsetsInDict(condition_dict)


# TODO(mark): I don't love this name. It just means that it's going to load
Expand Down Expand Up @@ -1037,17 +1038,40 @@ def EvalCondition(condition, conditions_key, phase, variables, build_file):
that nothing should be used."""
if type(condition) is not list:
raise GypError(conditions_key + ' must be a list')
if len(condition) != 2 and len(condition) != 3:
if len(condition) < 2:
# It's possible that condition[0] won't work in which case this
# attempt will raise its own IndexError. That's probably fine.
raise GypError(conditions_key + ' ' + condition[0] +
' must be length 2 or 3, not ' + str(len(condition)))
' must be at least length 2, not ' + str(len(condition)))

i = 0
result = None
while i < len(condition):
cond_expr = condition[i]
true_dict = condition[i + 1]
if type(true_dict) is not dict:
raise GypError('{} {} must be followed by a dictionary, not {}'.format(
conditions_key, cond_expr, type(true_dict)))
if len(condition) > i + 2 and type(condition[i + 2]) is dict:
false_dict = condition[i + 2]
i = i + 3
if i != len(condition):
raise GypError('{} {} has {} unexpected trailing items'.format(
conditions_key, cond_expr, len(condition) - i))
else:
false_dict = None
i = i + 2
if result == None:
result = EvalSingleCondition(
cond_expr, true_dict, false_dict, phase, variables, build_file)

return result

[cond_expr, true_dict] = condition[0:2]
false_dict = None
if len(condition) == 3:
false_dict = condition[2]

def EvalSingleCondition(
cond_expr, true_dict, false_dict, phase, variables, build_file):
"""Returns true_dict if cond_expr evaluates to true, and false_dict
otherwise."""
# Do expansions on the condition itself. Since the conditon can naturally
# contain variable references without needing to resort to GYP expansion
# syntax, this is of dubious value for variables, but someone might want to
Expand Down
43 changes: 43 additions & 0 deletions test/conditions/elseif/elseif.gyp
@@ -0,0 +1,43 @@
# Copyright (c) 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

{
'targets': [
{
'variables': { 'test_var': 0 },
'target_name': 'program0',
'type': 'executable',
'sources': [ 'program.cc' ],
'includes': [ 'elseif_conditions.gypi' ],
},
{
'variables': { 'test_var': 1 },
'target_name': 'program1',
'type': 'executable',
'sources': [ 'program.cc' ],
'includes': [ 'elseif_conditions.gypi' ],
},
{
'variables': { 'test_var': 2 },
'target_name': 'program2',
'type': 'executable',
'sources': [ 'program.cc' ],
'includes': [ 'elseif_conditions.gypi' ],
},
{
'variables': { 'test_var': 3 },
'target_name': 'program3',
'type': 'executable',
'sources': [ 'program.cc' ],
'includes': [ 'elseif_conditions.gypi' ],
},
{
'variables': { 'test_var': 4 },
'target_name': 'program4',
'type': 'executable',
'sources': [ 'program.cc' ],
'includes': [ 'elseif_conditions.gypi' ],
},
],
}
20 changes: 20 additions & 0 deletions test/conditions/elseif/elseif_bad1.gyp
@@ -0,0 +1,20 @@
# Copyright (c) 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Trigger an error because of two consecutive string conditions.

{
'targets': [
{
'variables': { 'test_var': 0 },
'target_name': 'program',
'type': 'executable',
'sources': [ 'program.cc' ],
'conditions': [
['test_var==0', 'test_var==1', {
}],
],
},
],
}
22 changes: 22 additions & 0 deletions test/conditions/elseif/elseif_bad2.gyp
@@ -0,0 +1,22 @@
# Copyright (c) 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Trigger an error because of two consecutive string conditions, even if the
# conditions are not actually evaluated.

{
'targets': [
{
'variables': { 'test_var': 0 },
'target_name': 'program',
'type': 'executable',
'sources': [ 'program.cc' ],
'conditions': [
['test_var==0', {
}, 'test_var==1', 'test_var==2', {
}],
],
},
],
}
23 changes: 23 additions & 0 deletions test/conditions/elseif/elseif_bad3.gyp
@@ -0,0 +1,23 @@
# Copyright (c) 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Trigger an error because there are unexpected trailing items in a condition.

{
'targets': [
{
'variables': { 'test_var': 0 },
'target_name': 'program',
'type': 'executable',
'sources': [ 'program.cc' ],
'conditions': [
['test_var==0' {
}, 'test_var==1', {
}, {
}, 'test_var==2', {
}],
],
},
],
}
15 changes: 15 additions & 0 deletions test/conditions/elseif/elseif_conditions.gypi
@@ -0,0 +1,15 @@
{
'conditions': [
['test_var==0', {
'defines': ['FOO="first_if"'],
}, 'test_var==1', {
'defines': ['FOO="first_else_if"'],
}, 'test_var==2', {
'defines': ['FOO="second_else_if"'],
}, 'test_var==3', {
'defines': ['FOO="third_else_if"'],
}, {
'defines': ['FOO="last_else"'],
}],
],
}
33 changes: 33 additions & 0 deletions test/conditions/elseif/gyptest_elseif.py
@@ -0,0 +1,33 @@
#!/usr/bin/env python

# Copyright (c) 2014 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""
Verify that "else-if" conditions work.
"""

import TestGyp

test = TestGyp.TestGyp()

test.run_gyp('elseif.gyp')
test.build('elseif.gyp', test.ALL)
test.run_built_executable(
'program0', stdout='first_if\n')
test.run_built_executable(
'program1', stdout='first_else_if\n')
test.run_built_executable(
'program2', stdout='second_else_if\n')
test.run_built_executable(
'program3', stdout='third_else_if\n')
test.run_built_executable(
'program4', stdout='last_else\n')

# Verify that bad condition blocks fail at gyp time.
test.run_gyp('elseif_bad1.gyp', status=1, stderr=None)
test.run_gyp('elseif_bad2.gyp', status=1, stderr=None)
test.run_gyp('elseif_bad3.gyp', status=1, stderr=None)

test.pass_test()
10 changes: 10 additions & 0 deletions test/conditions/elseif/program.cc
@@ -0,0 +1,10 @@
// Copyright (c) 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>

int main() {
printf("%s\n", FOO);
return 0;
}

0 comments on commit fb8a7bd

Please sign in to comment.