Skip to content

Commit

Permalink
Mejoras al manejo de void (y algo de nulls), especialmente para bloqu…
Browse files Browse the repository at this point in the history
…es (#218)

* Fix issue 274 in wollok-ts

* Achieved throwing error for void parameters in all cases

* Removing checkValidClosure

* Removing === void

* Fix assignments to void

* add validation for void singleton

* Enhancing validation test

* Using void expressions instead of void wko & add validations
  • Loading branch information
fdodino authored Nov 11, 2024
1 parent f52bd6d commit f09e1a8
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 42 deletions.
1 change: 1 addition & 0 deletions src/resources/validationMessages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"shouldNotUseOverride": "Method does not override anything",
"shouldNotUseReservedWords": "{0} is a reserved name for a core element",
"shouldNotUseVoidMethodAsValue": "Message send \"{0}\" produces no value (missing return in method?)",
"shouldNotUseVoidSingleton": "Named object 'void' produces no value, use 'null' instead",
"shouldOnlyInheritFromMixin": "Mixin can only inherit from another mixin",
"shouldPassValuesToAllAttributes": "{0} cannot be instantiated, you must pass values to the following attributes: {1}",
"shouldUseBooleanValueInIfCondition": "Expecting a boolean",
Expand Down
1 change: 1 addition & 0 deletions src/resources/validationMessages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"shouldNotUseOverride": "Este método no sobrescribe ningún otro método",
"shouldNotUseReservedWords": "{0} es una palabra reservada por la biblioteca de Wollok",
"shouldNotUseVoidMethodAsValue": "El mensaje \"{0}\" no retorna ningún valor (quizás te falte un return en el método)",
"shouldNotUseVoidSingleton": "El objeto nombrado 'void' no retorna ningún valor (puede usar 'null' en su lugar)",
"shouldOnlyInheritFromMixin": "Los mixines solo pueden heredar de otros mixines",
"shouldPassValuesToAllAttributes": "No se puede instanciar {0}. Falta pasar valores a los siguientes atributos: {1}",
"shouldUseBooleanValueInIfCondition": "Se espera un booleano",
Expand Down
8 changes: 4 additions & 4 deletions src/wollok/game.wlk
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ object game {
self.height(5)
self.cellSize(50)
self.ground("ground.png")
}
}

/**
* Adds an object to the board for drawing it.
Expand Down Expand Up @@ -99,9 +99,9 @@ object game {
* game.whenCollideDo(pepita, { comida => pepita.comer(comida) })
*/
method whenCollideDo(visual, action) {
io.addCollitionHandler(visual.identity(), { =>
self.colliders(visual).forEach({it => action.apply(it)})
})
io.addCollitionHandler(visual.identity(), { =>
self.colliders(visual).forEach({it => action.apply(it)})
})
}

/**
Expand Down
53 changes: 31 additions & 22 deletions src/wollok/lang.wlk
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ class Pair {
*/
@Type(variable="Element")
class Collection {

/**
* Answers the element that is considered to be/have the maximum value.
* The criteria is given by a closure that receives a single element
Expand Down Expand Up @@ -542,7 +543,13 @@ class Collection {
*/
method all(predicate) {
self.checkNotNull(predicate, "all")
return self.fold(true, { seed, element => if (!seed) seed else predicate.apply(element) })
return self.fold(true, { seed, element =>
if (!seed)
seed
else
predicate.apply(element)
}
)
}

/**
Expand All @@ -558,7 +565,13 @@ class Collection {
*/
method any(predicate) {
self.checkNotNull(predicate, "any")
return self.fold(false, { seed, element => if (seed) seed else predicate.apply(element) })
return self.fold(false, { seed, element =>
if (seed)
seed
else
predicate.apply(element)
}
)
}

/**
Expand Down Expand Up @@ -626,7 +639,9 @@ class Collection {
*/
method count(predicate) {
self.checkNotNull(predicate, "count")
return self.fold(0, { total, element => if (predicate.apply(element)) total+1 else total })
return self.fold(0, { total, element =>
if (predicate.apply(element)) total+1 else total
})
}

/**
Expand Down Expand Up @@ -654,7 +669,9 @@ class Collection {
*/
method sum(closure) {
self.checkNotNull(closure, "sum")
return self.fold(0, { total, element => total + closure.apply(element) })
return self.fold(0, { total, element =>
total + closure.apply(element)
})
}

/**
Expand All @@ -666,7 +683,7 @@ class Collection {
* [].sum() => Answers 0
*/
method sum() = self.sum( {it => it} )

/**
* Calculates the average of the transformation of each element into a numerical value
* This is similar to call a map {} to transform each element into a
Expand Down Expand Up @@ -757,9 +774,10 @@ class Collection {
*/
method filter(closure) {
self.checkNotNull(closure, "filter")
return self.fold(self.newInstance(), { newCollection, element =>
if (closure.apply(element))
newCollection.add(element)
return self.fold(self.newInstance(), { newCollection, element =>
if (closure.apply(element)) {
newCollection.add(element)
}
newCollection
})
}
Expand Down Expand Up @@ -2597,12 +2615,7 @@ class Range {
* Example:
* (1..10).map({ n => n * 2}) ==> Answers [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
*/
method map(closure) {
self.checkNotNull(closure, "map")
const list = []
self.forEach { element => list.add(closure.apply(element)) }
return list
}
method map(closure) = self.asList().map(closure)

/**
* Map + flatten operation
Expand All @@ -2612,17 +2625,13 @@ class Range {
* Example:
* (1..4).flatMap({ n => 1 .. n }) ==> Answers [1, 1, 2, 1, 2, 3, 1, 2, 3, 4]
*/
method flatMap(closure) {
self.checkNotNull(closure, "flatMap")
return self.fold([], { seed, element =>
seed.addAll(closure.apply(element))
seed
})
}
method flatMap(closure) = self.asList().flatMap(closure)

/** @private */
method asList() {
return self.map({ elem => elem })
const list = []
self.forEach { element => list.add(element) }
return list
}

/**
Expand Down
73 changes: 68 additions & 5 deletions test/sanity/basics/ranges/ranges.wtest
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ describe "ranges" {
assert.equals(90, range.sum({ n => n * 2 }))
}

test "sum using void closure should fail" {
const range = 0 .. 9
assert.throwsException { range.sum({ [1].add(2) }) }
}

test "sum using null should fail" {
const range = 0 .. 9
assert.throwsException { range.sum(null) }
}

test "contains" {
const range = 0 .. 9
assert.that(range.contains(9))
Expand Down Expand Up @@ -71,12 +81,29 @@ describe "ranges" {
assert.notThat((0..10).any({ elem => elem == 15}))
}

test "any using null should fail" {
assert.throwsException { => (1..3).any(null) }
}

test "any using void closure should fail" {
assert.throwsException { => (1..3).any { [1, 2].add(3) } }
}


test "all" {
const range = 0 .. 10
assert.notThat(range.all({ elem => elem.even()}))
assert.that(range.any({ elem => elem < 11}))
}

test "all using null should fail" {
assert.throwsException { => (1..3).all(null) }
}

test "all using void closure should fail" {
assert.throwsException { => (1..4).all { [1, 2].add(3) } }
}

test "map" {
const range = 0 .. 5
assert.equals([0, 2, 4, 6, 8, 10], range.map({ elem => elem * 2}))
Expand All @@ -88,6 +115,14 @@ describe "ranges" {
assert.equals([0, 2, 4, 6, 8, 10], evenFiltered)
}

test "filter using null should fail" {
assert.throwsException { => (1..4).filter(null) }
}

test "filter using void closure should fail" {
assert.throwsException { => (1..4).filter { [1, 2].add(3) } }
}

test "count" {
const range = 0 .. 9
const evenCount = range.count({ elem => elem.even() })
Expand Down Expand Up @@ -126,6 +161,14 @@ describe "ranges" {
assert.equals(3, range2.min())
}

test "min using null should fail" {
assert.throwsException { => (1..4).min(null) }
}

test "min using void closure should fail" {
assert.throwsException { => (1..4).min { [1, 2].add(3) } }
}

test "max" {
const range = -22 .. -3
const range2 = 7 .. 3
Expand All @@ -151,6 +194,14 @@ describe "ranges" {
assert.equals(2, evenFound)
}

test "find using null should fail" {
assert.throwsException { => (1..3).find(null) }
}

test "find using void closure should fail" {
assert.throwsException { => (1..4).find { [1, 2].add(3) } }
}

test "findOrValue" {
const range = 1 .. 9
const valueNotFound = range.findOrDefault({ elem => elem > 55 }, 22)
Expand All @@ -160,7 +211,7 @@ describe "ranges" {
test "findOrElse" {
var encontro = true
const range = 1 .. 9
const valueNotFound = range.findOrElse({ elem => elem > 55 }, { encontro = false })
range.findOrElse({ elem => elem > 55 }, { encontro = false })
assert.notThat(encontro)
}

Expand All @@ -182,6 +233,14 @@ describe "ranges" {
assert.equals(2, range.count({ elem => elem.even() }))
}

test "count using null should fail" {
assert.throwsException { => (1..3).count(null) }
}

test "count using void closure should fail" {
assert.throwsException { => (1..3).count { [1, 2].add(3) } }
}

test "filter step minus 3" {
const range = 8 .. 1
range.step(-3)
Expand All @@ -201,10 +260,6 @@ describe "ranges" {
assert.throwsException { => (1..4).forEach(null) }
}

test "filter using null should fail" {
assert.throwsException { => (1..4).filter(null) }
}

test "map using null should fail" {
assert.throwsException { => (1..4).map(null) }
}
Expand All @@ -213,6 +268,14 @@ describe "ranges" {
assert.throwsException { => (1..4).any(null) }
}

test "max using void closure should fail" {
assert.throwsException { => (1..4).max { number => [1, 2].add(number) } }
}

test "max using null should fail" {
assert.throwsException { => (1..4).max(null) }
}

test "toString with default step, ascending order" {
assert.equals("1..5", new Range(start = 1, end = 5).toString())
}
Expand Down
Loading

0 comments on commit f09e1a8

Please sign in to comment.