diff --git a/docs/spec/lib/basic/functional.md b/docs/spec/lib/basic/functional.md index e488aedfd..16b47f28e 100644 --- a/docs/spec/lib/basic/functional.md +++ b/docs/spec/lib/basic/functional.md @@ -1,40 +1,41 @@ -# Functional +# Enumerable ## Overview -The `Functional` is a global instance having functional methods which is useful with [a pipeline operator](../../statement/expression/pipeline.md). +The `Enumerable` is not only `module` but also a global instance having functional enumerable methods +which is useful with [a pipeline operator](../../statement/expression/pipeline.md). For example, when multiple valuse are passed to the next function via pipeline, -a method in `Functional` can fetch a value one by one and pass the value to a next function in order. +a method in `Enumerable` can fetch a value one by one and pass the value to a next function in order. -Therefore, `Functional` can handle an infinite sequence. +Therefore, `Enumerable` can handle an infinite sequence. This is an example below. ```javascript 1.. |> Functional.enumerable - |> Functional.drop(10) - |> Functional.filter { => _1 % 3 == 0 } - |> Functional.take(10) - |> Functional.toArray + |> Enumerable.drop(10) + |> Enumerable.filter { => _1 % 3 == 0 } + |> Enumerable.take(10) + |> Enumerable.toArray |> System.println; ``` -The `Functional.enumerable` is a magic function to make a sequence change to an item which `Functional` methods can use. +The `Functional.enumerable` is a magic function to make a sequence change to an item which `Enumerable` methods can use. You can write it also like an example below, but the way how to write in the above example is more useful. ```javascript new Functional.Enumerator(1..) - |> Functional.drop(10) - |> Functional.filter { => _1 % 3 == 0 } - |> Functional.take(10) - |> Functional.toArray + |> Enumerable.drop(10) + |> Enumerable.filter { => _1 % 3 == 0 } + |> Enumerable.take(10) + |> Enumerable.toArray |> System.println; ``` ### Methods -The methods of `Functional` to pass values in pipeline is currently as follows. +The methods of `Enumerable` to pass values in pipeline is currently as follows. | Name | Outline | | -------------------- | ----------------------------------------------------------------------------------------------------------------------- | @@ -63,20 +64,20 @@ By one of those, the pipeline will be terminated once and a value will be aggreg | partition(func) | Returns an array of 2 groups of a group which is returning true by `func` and a group which is returning false by `func`. | | printlnAll | Apply `System.println` for all elements. | -### Functional.trace +### Enumerable.trace This is not a `functional` method but a method just to trace and display items passed in the pipeline. This method will display an item and pass it to the next as it is. -Therefore, `Functional.trace` can be used before `Functional.enumerable` as an example below. +Therefore, `Enumerable.trace` can be used before `Functional.enumerable` as an example below. ```javascript [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - |> Functional.trace + |> Enumerable.trace |> Functional.enumerable - |> Functional.each { => Functional.trace(_1) } - |> Functional.reduce(&(r, e) => r += e, 0) - |> Functional.trace + |> Enumerable.each { => Enumerable.trace(_1) } + |> Enumerable.reduce(&(r, e) => r += e, 0) + |> Enumerable.trace ; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] @@ -100,13 +101,13 @@ Therefore, `Functional.trace` can be used before `Functional.enumerable` as an e #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; -new $F.Enumerator(1..10) - |> $F.filter({ => _1 <= 4 }) - |> $F.map({ => _1 * 10 }) +new Functional.Enumerator(1..10) + |> $E.filter({ => _1 <= 4 }) + |> $E.map({ => _1 * 10 }) |> printlnArray; ``` @@ -121,13 +122,13 @@ new $F.Enumerator(1..10) #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; 1..10 - |> $F.enumerable - |> $F.filter({ => _1 < 7 }) +> $F.map({ => _1 * 100 }) +> printlnArray + |> Functional.enumerable + |> $E.filter({ => _1 < 7 }) +> $E.map({ => _1 * 100 }) +> printlnArray ; ``` @@ -142,13 +143,13 @@ var printlnArray = $F.toArray +> println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; 1..20 - |> $F.enumerable - |> $F.dropWhile { => _1 < 10 || _1 % 2 == 0 } + |> Functional.enumerable + |> $E.dropWhile { => _1 < 10 || _1 % 2 == 0 } |> printlnArray; ``` @@ -163,13 +164,13 @@ var printlnArray = $F.toArray +> println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; [[1, 2], [3, 4]] - |> $F.enumerable - |> $F.flatMap { => _1.map { => _1 * 2 } } + |> Functional.enumerable + |> $E.flatMap { => _1.map { => _1 * 2 } } |> printlnArray; ``` @@ -184,13 +185,13 @@ var printlnArray = $F.toArray +> println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - |> $F.enumerable - |> $F.flatMap { => [_1, _1 * 2] } + |> Functional.enumerable + |> $E.flatMap { => [_1, _1 * 2] } |> printlnArray; ``` @@ -205,15 +206,15 @@ var printlnArray = $F.toArray +> println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; [10, 21, 92, 22, 37, 23, 98, 76, 56 , 48, 88, 76, 109, 2, 54] - |> $F.trace - |> $F.enumerable - |> $F.shuffle - |> printlnArray <+ $F.sort + |> $E.trace + |> Functional.enumerable + |> $E.shuffle + |> printlnArray <+ $E.sort ; ``` @@ -229,16 +230,16 @@ var printlnArray = $F.toArray +> println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; 100.. - |> $F.enumerable - |> $F.println("==> ") - |> $F.filter { => _1 % 2 == 0 } - |> $F.println("filterred: ") - |> $F.take(10) + |> Functional.enumerable + |> $E.println("==> ") + |> $E.filter { => _1 % 2 == 0 } + |> $E.println("filterred: ") + |> $E.take(10) |> printlnArray; ``` @@ -282,12 +283,12 @@ filterred: 118 #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; 1..20 - |> $F.enumerable - |> $F.all({ => _1 > 0 }) + |> Functional.enumerable + |> $E.all({ => _1 > 0 }) |> println; ``` @@ -302,12 +303,12 @@ var println = System.println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; 0..20 - |> $F.enumerable - |> $F.all({ => _1 < 20 }) + |> Functional.enumerable + |> $E.all({ => _1 < 20 }) |> println; ``` @@ -322,12 +323,12 @@ var println = System.println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; 0...20 - |> $F.enumerable - |> $F.all({ => _1 < 20 }) + |> Functional.enumerable + |> $E.all({ => _1 < 20 }) |> println; ``` @@ -342,12 +343,12 @@ var println = System.println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; 0..20 - |> $F.enumerable - |> $F.any({ => _1 >= 20 }) + |> Functional.enumerable + |> $E.any({ => _1 >= 20 }) |> println; ``` @@ -362,12 +363,12 @@ var println = System.println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; 0...20 - |> $F.enumerable - |> $F.any({ => _1 >= 20 }) + |> Functional.enumerable + |> $E.any({ => _1 >= 20 }) |> println; ``` @@ -382,13 +383,13 @@ var println = System.println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; 1..100 - |> $F.enumerable - |> $F.sum + |> Functional.enumerable + |> $E.sum |> println; ``` @@ -403,15 +404,15 @@ var printlnArray = $F.toArray +> println; #### Code ```javascript -var $F = Functional; +var $E = Enumerable; var println = System.println; -var printlnArray = $F.toArray +> println; +var printlnArray = $E.toArray +> println; [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - |> $F.enumerable - |> $F.partition { => _1 % 3 == 0 } - |> $F.enumerable - |> $F.printlnAll; + |> Functional.enumerable + |> $E.partition { => _1 % 3 == 0 } + |> Functional.enumerable + |> $E.printlnAll; ``` #### Result @@ -428,10 +429,10 @@ var printlnArray = $F.toArray +> println; ```javascript 1.. |> Functional.enumerable - |> Functional.drop(10) - |> Functional.filter { => _1 % 3 == 0 } - |> Functional.take(10) - |> Functional.toArray + |> Enumerable.drop(10) + |> Enumerable.filter { => _1 % 3 == 0 } + |> Enumerable.take(10) + |> Enumerable.toArray |> System.println; ``` @@ -447,11 +448,11 @@ var printlnArray = $F.toArray +> println; ```javascript [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - |> Functional.trace + |> Enumerable.trace |> Functional.enumerable - |> Functional.each { => Functional.trace(_1) } - |> Functional.reduce(&(r, e) => r += e, 0) - |> Functional.trace + |> Enumerable.each { => Enumerable.trace(_1) } + |> Enumerable.reduce(&(r, e) => r += e, 0) + |> Enumerable.trace ; ``` diff --git a/lib/std/kxenumerable.kx b/lib/std/kxenumerable.kx index ec19088ca..7bdb598f1 100644 --- a/lib/std/kxenumerable.kx +++ b/lib/std/kxenumerable.kx @@ -392,6 +392,293 @@ _module _Enumerable { } } +_Enumerable.filter = _function(predicate) { + return _function(sequence) { + return _function() { + while (true) { + const value = sequence(); + if (value.done) { + break; + } + if (predicate(value.value)) { + return value; + } + } + return { done: true }; + }; + }; +}; +_Enumerable.reject = _function(predicate) { + return _function(sequence) { + return _function() { + while (true) { + const value = sequence(); + if (value.done) { + break; + } + if (!predicate(value.value)) { + return value; + } + } + return { done: true }; + }; + }; +}; +_Enumerable.map = _function(mapping) { + return _function(sequence) { + return _function() { + const value = sequence(); + if (!value.done) { + return { value: mapping(value.value), done: false }; + } + return { done: true }; + }; + }; +}; +_Enumerable.flatMap = _function(mapping) { + return _function(sequence) { + var r = []; + return _function() { + var active = true; + while (active) { + if (r.length() > 0) { + return r.shift(); + } + const value = sequence(); + if (value.done) { + active = false; + break; + } + var mapped = mapping(value.value); + if (mapped.isArray) { + mapped.flatten().each { &(e) => r.push({ value: e, done: false }) }; + } else { + return { value: mapped, done: false }; + } + } + return { done: true }; + }; + }; +}; +_Enumerable.take = _function(n) { + return _function(sequence) { + var count = 0; + return _function() { + if (count < n) { + count++; + return sequence(); + } + return { done: true }; + }; + }; +}; +_Enumerable.takeWhile = _function(predicate) { + return _function(sequence) { + return _function() { + const value = sequence(); + if (!value.done && predicate(value.value)) { + return value; + } + return { done: true }; + }; + }; +}; +_Enumerable.drop = _function(n) { + return _function(sequence) { + var count = 0; + return _function() { + for ( ; count < n; ++count) { + const value = sequence(); + if (value.done) { + count = n; + return { done: true }; + } + } + return sequence(); + }; + }; +}; +_Enumerable.dropWhile = _function(predicate) { + return _function(sequence) { + var active = true; + return _function() { + while (active) { + const value = sequence(); + if (value.done) { + active = false; + return { done: true }; + } + if (!predicate(value.value)) { + active = false; + return value; + } + } + return sequence(); + }; + }; +}; +_Enumerable.each = _function(procedure) { + return _function(sequence) { + return _function() { + var value = sequence(); + if (!value.done) { + procedure(value.value); + } + return value; + }; + }; +}; +_Enumerable.sort = _function(sequence) { + var r = []; + var value = sequence(); + while (!value.done) { + r.push(value.value); + value = sequence(); + } + r = r.sort(); + var index = 0; + return _function() { + if (index < r.length()) { + return { value: r[index++], done: false }; + } + return { done: true }; + }; +}; +_Enumerable.shuffle = _function(sequence) { + var r = []; + var value = sequence(); + while (!value.done) { + r.push(value.value); + value = sequence(); + } + r = r.shuffle(); + var index = 0; + return _function() { + if (index < r.length()) { + return { value: r[index++], done: false }; + } + return { done: true }; + }; +}; +_function printImpl(func, argument, value) { + if (!value.done) { + func(argument, value.value); + } + return value; +} +_Enumerable.print = _function(argument) { + if (argument.isString) { + return _function(sequence) { + return _function() { + return printImpl(System.print, argument, sequence()); + }; + }; + } + const sequence = argument; + return _function() { + return printImpl(System.print, argument, sequence()); + }; +}; +_Enumerable.println = _function(argument) { + if (argument.isString) { + return _function(sequence) { + return _function() { + return printImpl(System.println, argument, sequence()); + }; + }; + } + const sequence = argument; + return _function() { + return printImpl(System.println, argument, sequence()); + }; +}; +_Enumerable.trace = _function(value) { + System.println(value); + return value; +}; + +_Enumerable.any = _function(predicate) { + return _function(sequence) { + var value = sequence(); + while (!value.done) { + if (predicate(value.value)) { + return true; + } + value = sequence(); + } + return false; + }; +}; +_Enumerable.all = _function(predicate) { + return _function(sequence) { + var value = sequence(); + while (!value.done) { + if (!predicate(value.value)) { + return false; + } + value = sequence(); + } + return true; + }; +}; +_Enumerable.partition = _function(predicate) { + return _function(sequence) { + var t = []; + var f = []; + var value = sequence(); + while (!value.done) { + if (predicate(value.value)) { + t.push(value.value); + } else { + f.push(value.value); + } + value = sequence(); + } + return [t, f]; + }; +}; +_Enumerable.sum = _function(sequence) { + var result = 0; + var value = sequence(); + while (!value.done) { + result += value.value; + value = sequence(); + } + return result; +}; +_Enumerable.toArray = _function(sequence) { + const arr = []; + var value = sequence(); + while (!value.done) { + arr.push(value.value); + value = sequence(); + } + return arr; +}; +_Enumerable.reduce = _function(accumulator, startValue) { + return _function(sequence) { + var result = startValue; + var value = sequence(); + while (!value.done) { + result = accumulator(result, value.value); + value = sequence(); + } + return result; + }; +}; +_Enumerable.printlnAll = _function(sequence) { + var value = sequence(); + while (!value.done) { + System.println(value.value); + value = sequence(); + } +}; + +_Enumerable.collect = _Enumerable.map; +_Enumerable.collectConcat = _Enumerable.flatMap; +_Enumerable.inject = _Enumerable.reduce; +_Enumerable.select = _Enumerable.findAll = _Enumerable.filter; + _class _RangeEnumerator(obj_) { var f_; private initialize() { diff --git a/lib/std/kxfunctional.kx b/lib/std/kxfunctional.kx index 0448b713d..444e9abd0 100644 --- a/lib/std/kxfunctional.kx +++ b/lib/std/kxfunctional.kx @@ -79,332 +79,39 @@ __functional_compose2 = _function(f1, f2) { return _functional_pipe2(f2, f1); }; -_Functional = (_function() { - _function _functional_enumerator(e) { - if (e.isFunction) { - return _function() { - return { value: e(), done: false }; - }; - } - if (e.isFiber) { - e.reset(); - return _function() { - const value = e.resume(); - if (e.isAlive()) { - return { value: value, done: false }; - } - return { done: true }; - }; - } - if (e.enumerator.isFunction || e.isFile || e.isArray || e.isObject) { - var enumerator = new Enumerator(e); - return _function() { - const value = enumerator.next(); - if (!enumerator.isEnded()) { - return { value: value, done: false }; - } - return { done: true }; - }; - } - var count = 0; +_function _functional_enumerator(e) { + if (e.isFunction) { return _function() { - if (count++ == 0) { - return { value: e, done: false }; + return { value: e(), done: false }; + }; + } + if (e.isFiber) { + e.reset(); + return _function() { + const value = e.resume(); + if (e.isAlive()) { + return { value: value, done: false }; } return { done: true }; }; } - - _class Functional { - @enumerable = @Enumerator.create = _functional_enumerator; - private initialize() { - @collect = @map; - @collectConcat = @flatMap; - @inject = @reduce; - @select = @findAll = @filter; - } - public filter(predicate) { - return _function(sequence) { - return _function() { - while (true) { - const value = sequence(); - if (value.done) { - break; - } - if (predicate(value.value)) { - return value; - } - } - return { done: true }; - }; - }; - } - public reject(predicate) { - return _function(sequence) { - return _function() { - while (true) { - const value = sequence(); - if (value.done) { - break; - } - if (!predicate(value.value)) { - return value; - } - } - return { done: true }; - }; - }; - } - public map(mapping) { - return _function(sequence) { - return _function() { - const value = sequence(); - if (!value.done) { - return { value: mapping(value.value), done: false }; - } - return { done: true }; - }; - }; - } - public flatMap(mapping) { - return _function(sequence) { - var r = []; - return _function() { - var active = true; - while (active) { - if (r.length() > 0) { - return r.shift(); - } - const value = sequence(); - if (value.done) { - active = false; - break; - } - var mapped = mapping(value.value); - if (mapped.isArray) { - mapped.flatten().each { &(e) => r.push({ value: e, done: false }) }; - } else { - return { value: mapped, done: false }; - } - } - return { done: true }; - }; - }; - } - public take(n) { - return _function(sequence) { - var count = 0; - return _function() { - if (count < n) { - count++; - return sequence(); - } - return { done: true }; - }; - }; - } - public takeWhile(predicate) { - return _function(sequence) { - return _function() { - const value = sequence(); - if (!value.done && predicate(value.value)) { - return value; - } - return { done: true }; - }; - }; - } - public drop(n) { - return _function(sequence) { - var count = 0; - return _function() { - for ( ; count < n; ++count) { - const value = sequence(); - if (value.done) { - count = n; - return { done: true }; - } - } - return sequence(); - }; - }; - } - public dropWhile(predicate) { - return _function(sequence) { - var active = true; - return _function() { - while (active) { - const value = sequence(); - if (value.done) { - active = false; - return { done: true }; - } - if (!predicate(value.value)) { - active = false; - return value; - } - } - return sequence(); - }; - }; - } - public each(procedure) { - return _function(sequence) { - return _function() { - var value = sequence(); - if (!value.done) { - procedure(value.value); - } - return value; - }; - }; - } - public sort(sequence) { - var r = []; - var value = sequence(); - while (!value.done) { - r.push(value.value); - value = sequence(); - } - r = r.sort(); - var index = 0; - return _function() { - if (index < r.length()) { - return { value: r[index++], done: false }; - } - return { done: true }; - }; - } - public shuffle(sequence) { - var r = []; - var value = sequence(); - while (!value.done) { - r.push(value.value); - value = sequence(); - } - r = r.shuffle(); - var index = 0; - return _function() { - if (index < r.length()) { - return { value: r[index++], done: false }; - } - return { done: true }; - }; - } - private printImpl(func, argument, value) { - if (!value.done) { - func(argument, value.value); - } - return value; - } - public print(argument) { - if (argument.isString) { - return _function(sequence) { - return _function() { - return printImpl(System.print, argument, sequence()); - }; - }; - } - const sequence = argument; - return _function() { - return printImpl(System.print, argument, sequence()); - }; - } - public println(argument) { - if (argument.isString) { - return _function(sequence) { - return _function() { - return printImpl(System.println, argument, sequence()); - }; - }; - } - const sequence = argument; - return _function() { - return printImpl(System.println, argument, sequence()); - }; - } - public trace(value) { - System.println(value); - return value; - } - - public any(predicate) { - return _function(sequence) { - var value = sequence(); - while (!value.done) { - if (predicate(value.value)) { - return true; - } - value = sequence(); - } - return false; - }; - } - public all(predicate) { - return _function(sequence) { - var value = sequence(); - while (!value.done) { - if (!predicate(value.value)) { - return false; - } - value = sequence(); - } - return true; - }; - } - public partition(predicate) { - return _function(sequence) { - var t = []; - var f = []; - var value = sequence(); - while (!value.done) { - if (predicate(value.value)) { - t.push(value.value); - } else { - f.push(value.value); - } - value = sequence(); - } - return [t, f]; - }; - } - public sum(sequence) { - var result = 0; - var value = sequence(); - while (!value.done) { - result += value.value; - value = sequence(); - } - return result; - } - public toArray(sequence) { - const arr = []; - var value = sequence(); - while (!value.done) { - arr.push(value.value); - value = sequence(); - } - return arr; - } - public reduce(accumulator, startValue) { - return _function(sequence) { - var result = startValue; - var value = sequence(); - while (!value.done) { - result = accumulator(result, value.value); - value = sequence(); - } - return result; - }; - } - public printlnAll(sequence) { - var value = sequence(); - while (!value.done) { - System.println(value.value); - value = sequence(); + if (e.enumerator.isFunction || e.isFile || e.isArray || e.isObject) { + var enumerator = new Enumerator(e); + return _function() { + const value = enumerator.next(); + if (!enumerator.isEnded()) { + return { value: value, done: false }; } - } + return { done: true }; + }; } + var count = 0; + return _function() { + if (count++ == 0) { + return { value: e, done: false }; + } + return { done: true }; + }; +} - return new Functional(); -})(); +Functional.enumerable = Functional.Enumerator.create = _functional_enumerator; diff --git a/lib/std/kxstartup.kx b/lib/std/kxstartup.kx index 026eb726b..85a612fed 100644 --- a/lib/std/kxstartup.kx +++ b/lib/std/kxstartup.kx @@ -46,7 +46,6 @@ var Xml, Net; Enumerator = _Enumerator; _functional_pipe2 = __functional_pipe2; _functional_compose2 = __functional_compose2; - Functional = _Functional; Range = _Range; System.setupRange(Range.create); System.getopt = new Fiber(new GetOpt().getopt).resume; diff --git a/src/ast_analyzer.c b/src/ast_analyzer.c index 575eb669b..b2dc5c7fb 100644 --- a/src/ast_analyzer.c +++ b/src/ast_analyzer.c @@ -285,8 +285,10 @@ static int is_anon_var(kxana_context_t *actx, kx_object_t *node) if (name && name[0] == '_') { if (!actx->in_case_when && name[1] == 0) { node->var_type = actx->in_native ? KX_INT_T : KX_UNKNOWN_T; - node->lexical = 0; - node->index = actx->anon_arg++; + int index_max = node->index + 1; + if (actx->anon_arg < index_max) { + actx->anon_arg = index_max; + } return 1; } if (name[2] == 0) { @@ -675,9 +677,6 @@ LOOP_HEAD:; break; } } - if (node->var_type == KX_UND_T && !node->lhs) { - node->lhs = kx_gen_special_object(KXVL_NULL); - } kxana_symbol_t *sym = search_symbol_table(ctx, node, node->value.s, actx); if (!sym) { if (!node->lhs && !actx->decl && !actx->lvalue) { @@ -735,7 +734,6 @@ LOOP_HEAD:; kx_gen_int_object(actx->arg_index) ) ); - int arg_index = actx->arg_index; int lvalue = actx->lvalue; int decl = actx->decl; actx->lvalue = 0; @@ -743,7 +741,6 @@ LOOP_HEAD:; analyze_ast(ctx, node->lhs, actx); actx->lvalue = lvalue; actx->decl = decl; - actx->arg_index = arg_index; actx->arg_index = -1; } else { ++(actx->arg_index); @@ -1305,8 +1302,6 @@ LOOP_HEAD:; } case KXOP_COMPOSITL: - analyze_ast(ctx, node->lhs, actx); - analyze_ast(ctx, node->rhs, actx); node->lhs = kx_gen_bexpr_object(KXOP_CALL, kx_gen_var_object("_functional_pipe2", KX_FNC_T), kx_gen_bexpr_object(KXST_EXPRLIST, node->rhs, node->lhs) @@ -1316,8 +1311,6 @@ LOOP_HEAD:; node->type = KXST_EXPRLIST; break; case KXOP_COMPOSITR: - analyze_ast(ctx, node->lhs, actx); - analyze_ast(ctx, node->rhs, actx); node->lhs = kx_gen_bexpr_object(KXOP_CALL, kx_gen_var_object("_functional_compose2", KX_FNC_T), kx_gen_bexpr_object(KXST_EXPRLIST, node->rhs, node->lhs) @@ -1616,6 +1609,8 @@ LOOP_HEAD:; } kx_object_t *func = actx->func; actx->func = node; + kvec_pt(kx_object_t) *vars = actx->vars; + actx->vars = kx_calloc(1, sizeof(kvec_pt(kx_object_t))); kv_push(kxana_symbol_t, actx->symbols, kx_empty_symbols); int decl = actx->decl; actx->decl = 1; @@ -1634,8 +1629,6 @@ LOOP_HEAD:; int anon_arg = actx->anon_arg; actx->anon_arg = 0; - kvec_pt(kx_object_t) *vars = actx->vars; - actx->vars = kx_calloc(1, sizeof(kvec_pt(kx_object_t))); analyze_ast(ctx, node->rhs, actx); int vdiff = actx->anon_arg - node->count_args; if (vdiff > 0) { @@ -1733,6 +1726,8 @@ LOOP_HEAD:; } kx_object_t *func = actx->func; actx->func = node; + kvec_pt(kx_object_t) *vars = actx->vars; + actx->vars = kx_calloc(1, sizeof(kvec_pt(kx_object_t))); kv_push(kxana_symbol_t, actx->symbols, kx_empty_symbols); int decl = actx->decl; actx->decl = 1; @@ -1748,8 +1743,6 @@ LOOP_HEAD:; int anon_arg = actx->anon_arg; actx->anon_arg = 0; - kvec_pt(kx_object_t) *vars = actx->vars; - actx->vars = kx_calloc(1, sizeof(kvec_pt(kx_object_t))); analyze_ast(ctx, node->rhs, actx); int vdiff = actx->anon_arg - node->count_args; if (vdiff > 0) { @@ -1770,7 +1763,6 @@ LOOP_HEAD:; if (node->local_vars < node->count_args) { node->local_vars = node->count_args; } - kv_destroy(*(actx->vars)); kx_free(actx->vars); actx->vars = vars; diff --git a/src/ast_display.c b/src/ast_display.c index 5d227ec7c..e97eecfe6 100644 --- a/src/ast_display.c +++ b/src/ast_display.c @@ -105,15 +105,17 @@ LOOP_HEAD:; case KXOP_VAR: if (node->lhs) { - printf("optimized - "); - } - if (node->var_type == KX_FNC_T || node->var_type == KX_NFNC_T) { - printf("%c(fnc:%s)(%s) [%d:%d]\n", lvalue ? '*' : '-', node->value.s, get_disp_ret_typename(node), node->lexical, node->index); + printf("var:optimized\n"); + display_ast(node->lhs, indent + 1, lvalue); } else { - if (node->refdepth > 0) { - printf("%c(var:%s[depth:%d]):%s [%d:%d]\n", lvalue ? '*' : '-', node->value.s, node->refdepth, get_short_typename(node->var_type), node->lexical, node->index); + if (node->var_type == KX_FNC_T || node->var_type == KX_NFNC_T) { + printf("%c(fnc:%s)(%s) [%d:%d]\n", lvalue ? '*' : '-', node->value.s, get_disp_ret_typename(node), node->lexical, node->index); } else { - printf("%c(var:%s):%s [%d:%d]\n", lvalue ? '*' : '-', node->value.s, get_disp_node_typename(node), node->lexical, node->index); + if (node->refdepth > 0) { + printf("%c(var:%s[depth:%d]):%s [%d:%d]\n", lvalue ? '*' : '-', node->value.s, node->refdepth, get_short_typename(node->var_type), node->lexical, node->index); + } else { + printf("%c(var:%s):%s [%d:%d]\n", lvalue ? '*' : '-', node->value.s, get_disp_node_typename(node), node->lexical, node->index); + } } } break; diff --git a/src/extlib/kxarray.c b/src/extlib/kxarray.c index a6a46fd3c..04d786633 100644 --- a/src/extlib/kxarray.c +++ b/src/extlib/kxarray.c @@ -447,8 +447,14 @@ int Array_flatten(int args, kx_frm_t *frmv, kx_frm_t *lexv, kx_context_t *ctx) { kx_obj_t *obj = get_arg_obj(1, args, ctx); if (obj) { + int level = -1; kx_obj_t *ary = allocate_obj(ctx); - int level = args > 1 ? get_arg_int(2, args, ctx) : -1; + if (args > 1) { + kx_val_t val = kv_last_by(ctx->stack, 2); + if (val.type == KX_INT_T) { + level = get_arg_int(2, args, ctx); + } + } int r = Array_flatten_impl(args, ctx, ary, obj, 0, level); if (r > 0) { KX_ADJST_STACK(); diff --git a/src/optimizer/opt_cfold.c b/src/optimizer/opt_cfold.c index 5d06461b5..affaf4385 100644 --- a/src/optimizer/opt_cfold.c +++ b/src/optimizer/opt_cfold.c @@ -17,7 +17,14 @@ } \ /**/ -void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) +typedef struct folding_context_ { + int anon_check; + int anon_arg; + int exprlist_r2l; + int in_case_when; +} folding_context_t; + +static void opt_ast_constant_folding_impl(kx_context_t *ctx, kx_object_t *node, folding_context_t *cctx) { if (!node) { return; @@ -45,65 +52,73 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) case KXVL_REGEX: break; - case KXOP_VAR: + case KXOP_VAR: { + if (cctx->anon_check) { + const char *name = node->value.s; + if (!cctx->in_case_when && name && name[0] == '_' && name[1] == 0) { + node->lexical = 0; + node->index = cctx->anon_arg++; + } + } break; + } case KXOP_KEYVALUE: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_BNOT: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_NOT: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_POSITIVE: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_NEGATIVE: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_CONV: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_INC: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_DEC: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_INCP: /* postfix */ - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_DECP: /* postfix */ - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_MKRANGE: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_MKBIN: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_MKARY: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_MKOBJ: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_DECL: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_ASSIGN: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_SHL: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -117,8 +132,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_SHR: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -130,8 +145,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_ADD: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -147,8 +162,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_SUB: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -164,8 +179,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_POW: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -179,8 +194,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_MUL: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -196,8 +211,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_DIV: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -216,8 +231,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_MOD: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -227,8 +242,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_AND: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -238,8 +253,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_OR: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -249,8 +264,8 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) } break; case KXOP_XOR: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); KX_CONST_VAR_CHECK(node, lhs); KX_CONST_VAR_CHECK(node, rhs); if (node->lhs->type == KXVL_INT && node->rhs->type == KXVL_INT) { @@ -262,15 +277,15 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) case KXOP_LAND: case KXOP_LOR: case KXOP_LUNDEF: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_IDX: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_YIELD: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_EQEQ: @@ -280,24 +295,37 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) case KXOP_GE: case KXOP_GT: case KXOP_LGE: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_REGEQ: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_REGNE: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; - case KXOP_CALL: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + + case KXOP_CALLPL: + case KXOP_CALLPR: + case KXOP_CALL: { + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + int exprlist_r2l = cctx->exprlist_r2l; + cctx->exprlist_r2l = 1; + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + cctx->exprlist_r2l = exprlist_r2l; + break; + } + + case KXOP_COMPOSITL: + case KXOP_COMPOSITR: + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXOP_TYPEOF: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXOP_CAST: { /* do nothing */ @@ -307,98 +335,136 @@ void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) break; } case KXOP_SPREAD: { - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + break; + } + + case KXOP_CASE: { + int in_case_when = cctx->in_case_when; + cctx->in_case_when = 1; + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->ex, cctx); + cctx->in_case_when = in_case_when; + break; + } + case KXOP_WHEN: { + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->ex, cctx); break; } case KXOP_TER: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); - opt_ast_constant_folding(ctx, node->ex); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->ex, cctx); break; case KXST_BREAK: case KXST_CONTINUE: case KXST_LABEL: - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXST_EXPR: /* lhs: expr */ - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; - case KXST_EXPRSEQ: /* lhs: expr1: rhs: expr2 */ case KXST_EXPRLIST: /* lhs: expr1: rhs: expr2 */ + if (cctx->exprlist_r2l) { + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + } else { + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + } + break; + case KXST_EXPRSEQ: /* lhs: expr1: rhs: expr2 */ case KXST_STMTLIST: /* lhs: stmt1: rhs: stmt2 */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXST_BLOCK: /* lhs: block */ - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXST_IF: { /* lhs: cond, rhs: then-block: ex: else-block */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); - opt_ast_constant_folding(ctx, node->ex); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->ex, cctx); break; } case KXST_SWITCH: { /* lhs: cond: rhs: block */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; } case KXST_CASE: { /* lhs: cond */ - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; } case KXST_WHILE: /* lhs: cond: rhs: block */ case KXST_DO: /* lhs: cond: rhs: block */ case KXST_FOR: { /* lhs: forcond: rhs: block */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; } case KXST_FORCOND: /* lhs: init, rhs: cond: ex: inc */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); - opt_ast_constant_folding(ctx, node->ex); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->ex, cctx); break; case KXST_TRY: { /* lhs: try, rhs: catch: ex: finally */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); - opt_ast_constant_folding(ctx, node->ex); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->ex, cctx); break; } case KXST_CATCH: { /* lhs: name: rhs: block */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; } case KXST_RET: /* lhs: expr */ - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXST_SYSRET_NV: break; case KXST_THROW: /* lhs: expr */ - opt_ast_constant_folding(ctx, node->lhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); break; case KXST_MIXIN: - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); break; case KXST_SYSCLASS: case KXST_CLASS: { /* s: name, lhs: arglist, rhs: block: ex: expr (inherit) */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); - opt_ast_constant_folding(ctx, node->ex); + int anon_arg = cctx->anon_arg; + cctx->anon_arg = 0; + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + opt_ast_constant_folding_impl(ctx, node->ex, cctx); + cctx->anon_arg = anon_arg; break; } case KXST_COROUTINE: /* s: name, lhs: arglist, rhs: block: optional: public/private/protected */ case KXST_FUNCTION: /* s: name, lhs: arglist, rhs: block: optional: public/private/protected */ case KXST_NATIVE: { /* s: name, lhs: arglist, rhs: block: ret_type: return type */ - opt_ast_constant_folding(ctx, node->lhs); - opt_ast_constant_folding(ctx, node->rhs); + int anon_arg = cctx->anon_arg; + cctx->anon_arg = 0; + opt_ast_constant_folding_impl(ctx, node->lhs, cctx); + opt_ast_constant_folding_impl(ctx, node->rhs, cctx); + cctx->anon_arg = anon_arg; break; } default: break; } } + +void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) +{ + folding_context_t cctx = {0}; + cctx.anon_check = (node->type == KXST_STMTLIST && node->optional == 0); + ++node->optional; + opt_ast_constant_folding_impl(ctx, node, &cctx); +}