toeb / cmakepp

An Enhancement Suite for the CMake Build System
Other
433 stars 37 forks source link

Add map function for lists #68

Closed letmaik closed 9 years ago

letmaik commented 9 years ago

I have a list of filenames without file extensions, and now I want to create two new derived lists which each add different file extensions to each list entry. E.g. in pseudocode:

set(files filea fileb) set(sources lists_map(${files}, function(el) {return el ++ ".c"})) set(headers lists_map(${files}, function(el) {return el ++ ".h"}))

toeb commented 9 years ago

Hi! this function already exists its called list_select(<list ref> <callable>)-> <any...>
though I have to say that the lambda ()-> ... syntax would ordinarily be used will be reworked because it does not work too well in more complex cases. therefore I suggest you just write plain cmake functions as a string even if the escaped syntax is cumbersome....

  set(files filea fileb)
  assign(sources = list_select(files "function(_ el)\nreturn(\"\${el}.c\")\nendfunction()"))
  assign(headers = list_select(files "function(_ el)\nreturn(\"\${el}.h\")\nendfunction()"))
letmaik commented 9 years ago

What's the assign(var = ..) syntax? Haven't seen that before. Can you write an example how the lambda syntax would look like with list_select?

toeb commented 9 years ago

Excerpt from the not yet comitted README.md:

Using the map and list functions can be cumbersome. Therefore I have added a universal function called assign() It allows you to use statements known from other programming languages.

The easiest way to illustrate the usefullness is by example:

Examples

## assign the string value 3 to x  - single quotes indicate a value
assign(x = '3') 
assert("${x}" EQUAL 3)

## assign a string containing spaces to x (notice the double quoted single quoted string)
assign(x = "'hello there!'") 
assert("${x}" STREQUAL "hello there!" )

## assign the result of a function call to x
assign(x = string_length("abcde"))
assert("${x}" EQUAL 5)

## assign x the result of an expression
assign(x = "{id:1}")  # the string {id:1} is parsed into a map because is enclosed by {} or []
assertf("{x.id}" EQUAL 1)

## append a value to x
set(x)
assign(x[] = '1')
assign(x[] = '2')
assign(x[] = '3')
assign(x[] = '4')
assert(${x} EQUALS 1 2 3 4)

## reverse x
set(x 1 2 3 4)
assign(x = x[$:0:-1]) # read: assign from x at end to 0 in -1 increments to x
assert(${x} EQUALS 4 3 2 1)

## replace a range of x
set(x 1 2 3 4)
assign(x[1:2] = '5')
assert(${x} EQUALS 1 5 4)

## create a object path if it does not exist by prepending '!'
set(x)
assign(!x.y.z = '3')
assert_matches("{y:{z:3}}" "${x}")

... more examples coming soon

instead of the cmake function in a string I wrote above you could write

(el)-> string_combine('' $el '.c') 

## lambda syntax transforms into
function(_ el)
 string_combine("" "${el}" ".c")
 return_ans()
endfunction()

I do not want you to use it currently because it is really broken and I plan to fix it - so you can be sure that anything you write now will probably not work in the future. However if your willing to update your code in future iterations then go ahead ;)

letmaik commented 9 years ago

Thanks, nice work! So only thing I don't like is the double-single quotes in assign(x = "'hello there!'").

toeb commented 9 years ago

yeah I don't like it either however its necessary because of the way cmake works (I can't parse the double quotes). an alternative would be to only use double quoted strings but that would be ambiguous because "value" could mean both a variable called value or a "value" as a value itself ;)

so i chose the unambiguous syntax over ease of use.

toeb commented 9 years ago

I thought about it a little to find a way how to not use single quotes. my solution is now that if you want to assign a literal value you can just omit the = sign. The previous behaviour = 'value' still works.

example:

assign(!result.a "abc def ghi" "123 432 987")
assertf({result.a} EQUALS "abc def ghi" "123 432 987")
letmaik commented 9 years ago

Well, I think this will lead to confusion. What about having two, like assign(!result.a = "abc def ghi" "123 432 987") for literal things, and eval(!result.a = str_length(foo)) for function evaluation?