From 1d097cb6b99bbd18edd488f0ba61db59f9c3c959 Mon Sep 17 00:00:00 2001 From: Kefniark Date: Tue, 4 May 2021 15:46:23 +0900 Subject: [PATCH 1/3] Add function Named Args & more tests --- .github/workflows/release.yml | 4 +- package.json | 1 + samples/math/module.json | 12 +++--- samples/module.json | 14 ++++--- samples/vec/module.json | 8 ++-- src/ako_grammar.txt | 3 +- src/dist/ako-cli.ts | 21 +--------- src/elements/function.ts | 40 +++++++++++------- src/helpers/args.ts | 45 ++++++++++++++++++++ src/interpreter.ts | 21 ++++++++++ src/semantic.ts | 1 - src/std/collections/list.ts | 14 +++---- src/std/geometry/vector.ts | 27 ++++-------- src/std/system/cache.ts | 22 ---------- src/std/system/index.ts | 3 +- src/std/system/print.ts | 6 ++- src/std/system/sleep.ts | 11 +++-- tests/function.test.ts | 27 ++++++++++++ tests/helper.ts | 15 ++++++- tests/task.test.ts | 78 +++++++++++++++++++++++++++++++++-- 20 files changed, 256 insertions(+), 117 deletions(-) create mode 100644 src/helpers/args.ts delete mode 100644 src/std/system/cache.ts create mode 100644 tests/function.test.ts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00a9e8c..5cd9a83 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,5 +32,5 @@ jobs: dist/bin/ako.exe dist/bin/ako-linux dist/bin/ako-osx - dist/node/ako.js - dist/web/ako-web.js \ No newline at end of file + dist/ako-node.js + dist/ako-web.js diff --git a/package.json b/package.json index 9d8c403..996aefe 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "build:types:web-light": "node ./tools/gen-typings.js ako-weblight", "build:post": "node ./tools/prepend.js", "coverage": "nyc --reporter=text-lcov mocha ./tests/**.test.ts > coverage.lcov", + "coverage-user": "nyc mocha ./tests/**.test.ts", "package": "run-s package:*", "package:win": "cd dist && nexe --input=./ako-cli.js --output=./bin/ako.exe --target=win-12.12.0", "package:macos": "cd dist && nexe --input=./ako-cli.js --output=./bin/ako-osx --target=darwin-12.12.0", diff --git a/samples/math/module.json b/samples/math/module.json index 33a1bc1..bd57494 100644 --- a/samples/math/module.json +++ b/samples/math/module.json @@ -1,7 +1,7 @@ { - "id": "Math module", - "namespace": "Math", - "deps": [ - "../vec" - ] -} \ No newline at end of file + "id": "Math module", + "namespace": "Math", + "deps": [ + "../vec" + ] +} diff --git a/samples/module.json b/samples/module.json index ad235a9..be5cfd5 100644 --- a/samples/module.json +++ b/samples/module.json @@ -1,7 +1,9 @@ { - "id": "Test Project", - "entry": ["main.ako"], - "deps": [ - "./math" - ] -} \ No newline at end of file + "id": "Test Project", + "entry": [ + "main.ako" + ], + "deps": [ + "./math" + ] +} diff --git a/samples/vec/module.json b/samples/vec/module.json index 9802150..7958cf3 100644 --- a/samples/vec/module.json +++ b/samples/vec/module.json @@ -1,5 +1,5 @@ { - "id": "Vec module", - "namespace": "Vec", - "deps": [] -} \ No newline at end of file + "id": "Vec module", + "namespace": "Vec", + "deps": [] +} diff --git a/src/ako_grammar.txt b/src/ako_grammar.txt index 0a8044b..e5d8b11 100644 --- a/src/ako_grammar.txt +++ b/src/ako_grammar.txt @@ -15,7 +15,8 @@ Ako { Metadata = "##" Id Term TaskDef = "task" Id (Array)? Block - Task = "@" (Id ".")? Id "(" Arguments ")" + Task = "@" (Id ".")? Id "(" NamedArguments ")" + NamedArguments = ListOf<(KeyValue | Expr), ","> Arguments = ListOf // Expression diff --git a/src/dist/ako-cli.ts b/src/dist/ako-cli.ts index 573adda..1a82b35 100644 --- a/src/dist/ako-cli.ts +++ b/src/dist/ako-cli.ts @@ -35,27 +35,8 @@ function loadAkoModule(vm: Interpreter, projectFolder: string) { if (vm.tasks.has(methodName)) { throw new Error(`Task Name Already Used : ${methodName}`) } - vm.registerTask(methodName, (ctx, _, fnData, timeRemains) => { - if (!fnData.meta.block) { - const argsMeta = ast.filter((x) => x.type === 'Metadata' && x.key === 'Args') - const block = ctx.vm.createStack(ast) - ctx.vm.setData({vm: ctx.vm, stack: block}, 'args', fnData.meta.args || []) - if (argsMeta && argsMeta[0]) { - const val = ctx.vm.evaluate(ctx, argsMeta[0].value, true) - for (let i = 0; i < val.length; i++) { - if (!val[i] || !val[i].name) continue - if (i < fnData.meta.args.length) ctx.vm.setData({vm: ctx.vm, stack: block}, val[i].name, fnData.meta.args[i]) - else if ('default' in val[i]) ctx.vm.setData({vm: ctx.vm, stack: block}, val[i].name, val[i].default) - } - } - fnData.meta.block = block.uid - } - const stack = ctx.vm.stacks.get(fnData.meta.block) as Stack - const res = ctx.vm.updateStack(stack, timeRemains, true) - if (res.done) res.result = stack.result - return res - }) + vm.addFile(methodName, ast) } // execute entry point diff --git a/src/elements/function.ts b/src/elements/function.ts index 0f9a404..acd2e6f 100644 --- a/src/elements/function.ts +++ b/src/elements/function.ts @@ -1,3 +1,5 @@ +import {mapArgs} from '../helpers/args' + export const Metadata = { create: (key: any, value: any) => { return {type: 'Metadata', key: key.value ? key.value : key, value} @@ -32,7 +34,23 @@ export const Task = { const namespace = ctx.vm.evaluate(ctx, entry.namespace[0], true) fn = `${namespace}.${fn}` } - const args = entry.args.map((x) => ctx.vm.evaluate(ctx, x, true)) + let i = -1 + const args = entry.args.map((x) => { + if (x.type === 'KeyValue') { + return { + type: 'NamedArgs', + name: ctx.vm.evaluate(ctx, x.symbol, true), + value: ctx.vm.evaluate(ctx, x.value, true) + } + } + i = i + 1 + return { + type: 'Args', + index: i, + value: ctx.vm.evaluate(ctx, x, true) + } + }) + // console.log(args) entryData.meta = {fn, args} } @@ -49,19 +67,12 @@ export const TaskDef = { execute: (ctx, entry, entryData, timeRemains) => { ctx.vm.registerTask(entry.name.value, (ctx2, entry2, entryData2, time) => { if (!entryData2.meta.block) { - const directArgs = entry.args.map((x) => ctx.vm.evaluate(ctx, x, true)) - const argsMeta = entry.block.statements.filter((x) => x.type === 'Metadata' && x.key === 'Args') + const args = mapArgs(ctx, entry.args, entry.block.statements, entryData2.meta.args || []) const block = ctx2.vm.createStack(entry.block.statements) - ctx2.vm.setData({vm: ctx2.vm, stack: block}, 'args', entryData2.meta.args || []) - if (directArgs || (argsMeta && argsMeta[0])) { - const val = ctx.vm.evaluate(ctx, directArgs || argsMeta[0].value, true) - for (let i = 0; i < val.length; i++) { - if (!val[i]) continue - const name = val[i].name || val[i] - if (i < entryData2.meta.args.length) ctx2.vm.setData({vm: ctx2.vm, stack: block}, name, entryData2.meta.args[i]) - else if ('default' in val[i]) ctx.vm.setData({vm: ctx2.vm, stack: block}, name, val[i].default) - } + for (const key in args) { + ctx2.vm.setData({vm: ctx2.vm, stack: block}, key, args[key]) } + ctx2.vm.setData({vm: ctx2.vm, stack: block}, 'args', Object.values(args)) entryData2.meta.block = block.uid } @@ -84,11 +95,8 @@ export const Function = { const entries = entry.namespace.map((x) => ctx.vm.evaluate(ctx, x)) fn = `${entries.join(',')}.${ctx.vm.evaluate(ctx, entry.name)}` } - const args = entry.args.map((x) => ctx.vm.evaluate(ctx, x, true)) - - // console.log('Call function', fn, entry, args) - return ctx.vm.callFunction(fn, args) + return ctx.vm.callFunction(fn, ...args) } } diff --git a/src/helpers/args.ts b/src/helpers/args.ts new file mode 100644 index 0000000..fa79dde --- /dev/null +++ b/src/helpers/args.ts @@ -0,0 +1,45 @@ +import {Context} from '../core' + +export function mapArgs(ctx: Context, taskDefArgs: any, blocks: any, values: any) { + // console.log(taskDefArgs, blocks) + const taskDefMetaArgs = taskDefArgs.filter((x) => !!x).map((x: any) => ctx.vm.evaluate(ctx, x, true)) + const inlineMetaArgs = blocks + .filter((x: any) => !!x && x.type === 'Metadata' && x.key === 'Args') + .map((x: any) => x.value.value.map((y) => ctx.vm.evaluate(ctx, y, true))) + + let args = [] + if (taskDefMetaArgs.length > 0) { + args = taskDefMetaArgs.map((val, index) => { + if (typeof val === 'string' || val instanceof String) { + return {index, name: val} + } else { + return {...val, index} + } + }) + } else if (inlineMetaArgs.length > 0) { + args = inlineMetaArgs[0].map((x, index) => { + return {...x, index} + }) + } + + const params: {[id: string]: any} = {} + for (const arg of args) { + if ('default' in arg) params[arg.name] = arg.default + } + for (const arg of values) { + if (arg.type === 'Args') { + const entry = args.find((x) => x.index === arg.index) + if (entry) { + params[entry.name] = arg.value + } else { + params[`param_${arg.index}`] = arg.value + } + } else if (arg.type === 'NamedArgs') { + const entry = args.find((x) => x.name === arg.name) + if (entry) params[entry.name] = arg.value + } + } + + // console.log('Params >>', params, values, '<<') + return params +} diff --git a/src/interpreter.ts b/src/interpreter.ts index d22cbf5..b339cd4 100644 --- a/src/interpreter.ts +++ b/src/interpreter.ts @@ -2,6 +2,7 @@ import {uid} from './helpers/id' import * as AkoElement from './elements' import {stdTasks, stdFunctions} from './std' import {Task, Context, Func, Stack, UpdateStackResult} from './core' +import {mapArgs} from './helpers/args' export class Interpreter { stacks: Map = new Map() @@ -35,6 +36,25 @@ export class Interpreter { return stack } + addFile(name: string, ast: any): void { + this.registerTask(name, (ctx, fn, fnData, timeRemains) => { + if (!fnData.meta.block) { + const args = mapArgs(ctx, [], ast, fnData.meta.args) + const block = ctx.vm.createStack(ast) + for (const key in args) { + ctx.vm.setData({vm: ctx.vm, stack: block}, key, args[key]) + } + ctx.vm.setData({vm: ctx.vm, stack: block}, 'args', Object.values(args)) + fnData.meta.block = block.uid + } + + const stack = ctx.vm.stacks.get(fnData.meta.block) as Stack + const res = ctx.vm.updateStack(stack, timeRemains, true) + if (res.done) res.result = stack.result + return res + }) + } + registerFunction(name: string, method: Func): void { this.functions.set(name, method) } @@ -62,6 +82,7 @@ export class Interpreter { evaluate(ctx: Context, expr, resolveSymbol = false): any { if (!expr || !expr.type) return expr + if (!AkoElement[expr.type].evaluate) throw new Error(`Cannot Evaluate ${expr.type}`) return AkoElement[expr.type].evaluate(ctx, expr, resolveSymbol) } diff --git a/src/semantic.ts b/src/semantic.ts index 4d7b590..de592b9 100644 --- a/src/semantic.ts +++ b/src/semantic.ts @@ -13,7 +13,6 @@ export function getGrammar(akoGrammar: string) { return parseFloat(this.sourceString) }, hex: function (a, b) { - console.log(this.sourceString) return Number(`0x${this.sourceString.slice(1)}`) } }) diff --git a/src/std/collections/list.ts b/src/std/collections/list.ts index dde7aa5..337beca 100644 --- a/src/std/collections/list.ts +++ b/src/std/collections/list.ts @@ -1,18 +1,14 @@ export const list = { - 'List.filter': (args: [any[], (item: any, index: number) => any]) => { - const [arr, lambda] = args + 'List.filter': (arr: any[], lambda: (item1: any, item2: any) => number) => { return arr.filter(lambda) }, - 'List.map': (args: [any[], (item: any, index: number) => any]) => { - const [arr, lambda] = args + 'List.map': (arr: any[], lambda: (item1: any, item2: any) => number) => { return arr.map(lambda) }, - 'List.sort': (args: [any[], (item1: any, item2: any) => number]) => { - const [arr, lambda] = args - return lambda ? arr.sort(lambda) : arr.sort() + 'List.sort': (arr: any[], lambda: (item1: any, item2: any) => number) => { + return lambda ? [...arr].sort(lambda) : [...arr].sort() }, - 'List.reverse': (args: [any[]]) => { - const [arr] = args + 'List.reverse': (arr: any[]) => { return arr.reverse() } } diff --git a/src/std/geometry/vector.ts b/src/std/geometry/vector.ts index d33f20b..b7b071c 100644 --- a/src/std/geometry/vector.ts +++ b/src/std/geometry/vector.ts @@ -3,22 +3,19 @@ import {deg2rad, rad2deg} from './angle' type Vec2 = [number, number] -const create = (args?: number[]) => { +const create = (...args: number[]): Vec2 => { const [x, y] = args || [] return [x || 0, y || 0] as Vec2 } -const clone = (arg: Vec2) => create(arg) -const precisionRoundVec = (arg: Vec2, precision = 7) => { +const clone = (args: Vec2) => create(...args) +const precisionRoundVec = (arg: Vec2, precision = 7): Vec2 => { return [precisionRound(arg[0], precision), precisionRound(arg[1], precision)] } export const vector2 = { 'Vec2.create': create, - 'Vec2.clone': (arg: Vec2[]) => { - return clone(arg[0]) - }, - 'Vec2.add': (args: Vec2[]) => { - // console.log('Vector2 Add', args) + 'Vec2.clone': (vec: Vec2): Vec2 => clone(vec), + 'Vec2.add': (...args: Vec2[]): Vec2 => { const vec = create() for (const arg of args) { vec[0] = vec[0] + arg[0] || 0 @@ -26,31 +23,25 @@ export const vector2 = { } return precisionRoundVec(vec) }, - 'Vec2.sub': (args: Vec2[]) => { + 'Vec2.sub': (...args: Vec2[]): Vec2 => { const [origin, ...other] = args const vec = clone(origin) for (const arg of other) { vec[0] = vec[0] - arg[0] || 0 vec[1] = vec[1] - arg[1] || 0 } - // console.log('Vector2 Sub', args, '=>', vec) return precisionRoundVec(vec) }, - 'Vec2.scale': (args: [Vec2, number]) => { - const [origin, scale] = args + 'Vec2.scale': (origin: Vec2, scale: number): Vec2 => { const vec = clone(origin) vec[0] = precisionRound(vec[0] * scale) vec[1] = precisionRound(vec[1] * scale) - // console.log('Vector2 Scale', origin, '*', scale, '=>', vec) return precisionRoundVec(vec) }, - 'Vec2.angle': (args: [Vec2]) => { - const [origin] = args - // console.log('Vector2 Angle', origin) + 'Vec2.angle': (origin: Vec2): number => { return precisionRound(rad2deg(Math.atan2(origin[1], origin[0]))) }, - 'Vec2.rotate': (args: [Vec2, number]) => { - const [origin, angle] = args + 'Vec2.rotate': (origin: Vec2, angle: number): Vec2 => { const rad = deg2rad(angle) const cos = Math.cos(rad) const sin = Math.sin(rad) diff --git a/src/std/system/cache.ts b/src/std/system/cache.ts deleted file mode 100644 index 823770f..0000000 --- a/src/std/system/cache.ts +++ /dev/null @@ -1,22 +0,0 @@ -const cache = {} - -export default { - CacheReturn: (ctx, entry, entryData, timeRemains) => { - const cacheId = entryData.meta.args[0] - if (cacheId in cache) { - ctx.vm.callReturn(ctx, cache[cacheId]) - } - return {timeRemains, done: true} - }, - CacheGet: (ctx, entry, entryData, timeRemains) => { - const cacheId = entryData.meta.args[0] - if (cacheId in cache) { - ctx.vm.setData(ctx, '$', cache[entryData.meta.args[0]]) - } - return {timeRemains, done: true} - }, - CacheSet: (ctx, entry, entryData, timeRemains) => { - cache[entryData.meta.args[0]] = entryData.meta.args[1] - return {timeRemains, done: true} - } -} diff --git a/src/std/system/index.ts b/src/std/system/index.ts index b92d945..0367c4b 100644 --- a/src/std/system/index.ts +++ b/src/std/system/index.ts @@ -1,6 +1,5 @@ import log from './print' import sleep from './sleep' import ask from './ask' -import cache from './cache' -export default {...log, ...sleep, ...ask, ...cache} +export default {...log, ...sleep, ...ask} diff --git a/src/std/system/print.ts b/src/std/system/print.ts index d463270..e2ec060 100644 --- a/src/std/system/print.ts +++ b/src/std/system/print.ts @@ -1,6 +1,10 @@ +import {mapArgs} from '../../helpers/args' + export default { print: (ctx, entry, entryData, timeRemains) => { - console.log(...entryData.meta.args) + const args = mapArgs(ctx, [], [], entryData.meta.args || []) + console.log(...Object.values(args)) + return {timeRemains, done: true} } } diff --git a/src/std/system/sleep.ts b/src/std/system/sleep.ts index e9d52d1..62bf48f 100644 --- a/src/std/system/sleep.ts +++ b/src/std/system/sleep.ts @@ -1,11 +1,16 @@ +import {mapArgs} from '../../helpers/args' + export default { sleep: (ctx, entry, entryData, timeRemains) => { - const duration = entryData.meta.args[0] || 0 - if (!entryData.elapsed) entryData.elapsed = 0 + if (!entryData.elapsed) { + const args = mapArgs(ctx, ['duration'], [], entryData.meta.args || []) + entryData.elapsed = 0 + entryData.duration = args.duration + } entryData.elapsed += timeRemains - if (entryData.elapsed >= duration) return {timeRemains: entryData.elapsed - duration, done: true} + if (entryData.elapsed >= entryData.duration) return {timeRemains: entryData.elapsed - entryData.duration, done: true} return {timeRemains: 0, done: false} } } diff --git a/tests/function.test.ts b/tests/function.test.ts new file mode 100644 index 0000000..8a3060b --- /dev/null +++ b/tests/function.test.ts @@ -0,0 +1,27 @@ +import assert from 'assert' +import {runCode} from './helper' + +describe('Function', function () { + it('Check Expression Function', () => { + const {stack} = runCode(` +a = Math.max(1,2,3,4,5) +list = [1,5,2,3,4] +sorted = List.sort(list) +sorted2 = List.sort(list, (entry1,entry2) => entry2 - entry1) + `) + assert.strictEqual((stack.data as any)['a'], 5) + assert.deepStrictEqual((stack.data as any)['sorted'], [1, 2, 3, 4, 5]) + assert.deepStrictEqual((stack.data as any)['sorted2'], [5, 4, 3, 2, 1]) + }) + + it('Vector', () => { + const {stack} = runCode(` +a = Vec2.create(1, 1) +b = Vec2.add(a, Vec2.create(2, 2)) +c = Vec2.sub(Vec2.scale(a, 5), Vec2.create(5, 5)) + `) + assert.deepStrictEqual((stack.data as any)['a'], [1, 1]) + assert.deepStrictEqual((stack.data as any)['b'], [3, 3]) + assert.deepStrictEqual((stack.data as any)['c'], [0, 0]) + }) +}) diff --git a/tests/helper.ts b/tests/helper.ts index be82ef0..f8e54c3 100644 --- a/tests/helper.ts +++ b/tests/helper.ts @@ -1,8 +1,19 @@ import {toAst, Interpreter} from '../src/dist/ako-node' -export function runCode(code: string) { +export function createInterpreter() { + return new Interpreter() +} + +export function runFileCode(name: string, code: string, vm?: Interpreter) { + const ast = toAst(code) + if (!vm) vm = createInterpreter() + vm.addFile(name, ast) + return vm +} + +export function runCode(code: string, vm?: Interpreter) { const ast = toAst(code) - const vm = new Interpreter() + if (!vm) vm = createInterpreter() const stack = vm.createStack(ast) vm.update(1) return {stack, vm} diff --git a/tests/task.test.ts b/tests/task.test.ts index 7e7a5bc..210c9ae 100644 --- a/tests/task.test.ts +++ b/tests/task.test.ts @@ -1,19 +1,19 @@ import assert from 'assert' -import {runCode} from './helper' +import {runCode, runFileCode} from './helper' describe('Task', () => { it('Create and run task', () => { const {stack} = runCode(` task Method1 { + @print(args) return args[0] * 10 } task Method2 ["val"] { + @print(args) return val * 10 } task Method3 [ { name = "val" } ] { - return val * 10 -} -task Method4 { + @print(args) return val * 10 } a = @Method1(4.2) @@ -24,4 +24,74 @@ c = @Method3(4.2) assert.strictEqual((stack.data as any)['b'], 42) assert.strictEqual((stack.data as any)['c'], 42) }) + + it('Task call', () => { + const {stack} = runCode(` +task Method [ { name = "val1" }, { name = "val2" }, { name = "val3" } ] { + entries = [val1, val2, val3] + @print('entries', entries) + return entries +} + +task Method2 { + ## Args [ + { name = "val1", default = -1 }, + { name = "val2", default = -2 }, + { name = "val3", default = -3 } + ] + entries = [val1, val2, val3] + @print('entries', entries) + return entries +} + +a = @Method(1, 2, 3) +b = @Method(val2=2, val1=1, val3=3) +c = @Method2(1, 2) +d = @Method2(val1=1, val3=3) +`) + assert.deepStrictEqual((stack.data as any)['a'], [1, 2, 3]) + assert.deepStrictEqual((stack.data as any)['b'], [1, 2, 3]) + assert.deepStrictEqual((stack.data as any)['c'], [1, 2, -3]) + assert.deepStrictEqual((stack.data as any)['d'], [1, -2, 3]) + }) + + it('Task File', () => { + const vm = runFileCode( + 'MethodName', + ` +## Args [ + { name = "val1", default = -1 }, + { name = "val2", default = -2 }, + { name = "val3", default = -3 } +] +entries = [val1, val2, val3] +@print('entries', entries) +return entries` + ) + const {stack} = runCode( + ` +a = @MethodName(1, 2, 3) +b = @MethodName(val2=2, val1=1, val3=3) +c = @MethodName(1, 2) +d = @MethodName(val1=1, val3=3) + `, + vm + ) + //console.log(stack.data) + assert.deepStrictEqual((stack.data as any)['a'], [1, 2, 3]) + assert.deepStrictEqual((stack.data as any)['b'], [1, 2, 3]) + assert.deepStrictEqual((stack.data as any)['c'], [1, 2, -3]) + assert.deepStrictEqual((stack.data as any)['d'], [1, -2, 3]) + }) + + it('Sleep', () => { + const {stack, vm} = runCode(` +a = 1 +@sleep(1) +a = 2 + `) + assert.strictEqual((stack.data as any)['a'], 1) + vm.update(2) + assert.strictEqual((stack.data as any)['a'], 2) + }) }) From 74fce7e7c9a20ff7a6c21ddb2e6895ffbb5bc238 Mon Sep 17 00:00:00 2001 From: Kefniark Date: Tue, 4 May 2021 16:33:32 +0900 Subject: [PATCH 2/3] Udate tests --- src/std/collections/list.ts | 10 +++++----- tests/assign.test.ts | 2 ++ tests/function.test.ts | 14 ++++++++++++-- tests/task.test.ts | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/std/collections/list.ts b/src/std/collections/list.ts index 337beca..38264ea 100644 --- a/src/std/collections/list.ts +++ b/src/std/collections/list.ts @@ -1,14 +1,14 @@ export const list = { - 'List.filter': (arr: any[], lambda: (item1: any, item2: any) => number) => { + 'List.filter': (arr: number[], lambda: (item1: number, item2: number) => number): number[] => { return arr.filter(lambda) }, - 'List.map': (arr: any[], lambda: (item1: any, item2: any) => number) => { + 'List.map': (arr: number[], lambda: (item: number) => number): number[] => { return arr.map(lambda) }, - 'List.sort': (arr: any[], lambda: (item1: any, item2: any) => number) => { + 'List.sort': (arr: number[], lambda: (item1: number, item2: number) => number): number[] => { return lambda ? [...arr].sort(lambda) : [...arr].sort() }, - 'List.reverse': (arr: any[]) => { - return arr.reverse() + 'List.reverse': (arr: number[]): number[] => { + return [...arr].reverse() } } diff --git a/tests/assign.test.ts b/tests/assign.test.ts index 06539b6..72f0634 100644 --- a/tests/assign.test.ts +++ b/tests/assign.test.ts @@ -14,12 +14,14 @@ b = "" c = 'abc' d = '' e = "I don't want this string to be truncated !" +f = "{a}def" `) assert.strictEqual((stack.data as any)['a'], 'abc') assert.strictEqual((stack.data as any)['b'], '') assert.strictEqual((stack.data as any)['c'], 'abc') assert.strictEqual((stack.data as any)['d'], '') assert.strictEqual((stack.data as any)['e'], "I don't want this string to be truncated !") + assert.strictEqual((stack.data as any)['f'], 'abcdef') }) it('Assign boolean', () => { diff --git a/tests/function.test.ts b/tests/function.test.ts index 8a3060b..f5ddbe5 100644 --- a/tests/function.test.ts +++ b/tests/function.test.ts @@ -5,13 +5,23 @@ describe('Function', function () { it('Check Expression Function', () => { const {stack} = runCode(` a = Math.max(1,2,3,4,5) + + `) + assert.strictEqual((stack.data as any)['a'], 5) + }) + + it('Array Function', () => { + const {stack} = runCode(` list = [1,5,2,3,4] sorted = List.sort(list) -sorted2 = List.sort(list, (entry1,entry2) => entry2 - entry1) +sorted2 = List.sort(list, (a, b) => b - a) +filtered = List.filter(sorted2, (a) => a >= 3) +rev = List.reverse(filtered) `) - assert.strictEqual((stack.data as any)['a'], 5) assert.deepStrictEqual((stack.data as any)['sorted'], [1, 2, 3, 4, 5]) assert.deepStrictEqual((stack.data as any)['sorted2'], [5, 4, 3, 2, 1]) + assert.deepStrictEqual((stack.data as any)['filtered'], [5, 4, 3]) + assert.deepStrictEqual((stack.data as any)['rev'], [3, 4, 5]) }) it('Vector', () => { diff --git a/tests/task.test.ts b/tests/task.test.ts index 210c9ae..6c575d9 100644 --- a/tests/task.test.ts +++ b/tests/task.test.ts @@ -45,7 +45,7 @@ task Method2 { } a = @Method(1, 2, 3) -b = @Method(val2=2, val1=1, val3=3) +b = @Method(val2=2, val1=1, val3 = 3) c = @Method2(1, 2) d = @Method2(val1=1, val3=3) `) From d3f764904b6f353378a09bfee9537c4c81ab5e67 Mon Sep 17 00:00:00 2001 From: Kefniark Date: Tue, 4 May 2021 16:51:37 +0900 Subject: [PATCH 3/3] Fix the default compare sort issue --- src/std/collections/list.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/std/collections/list.ts b/src/std/collections/list.ts index 38264ea..01053ee 100644 --- a/src/std/collections/list.ts +++ b/src/std/collections/list.ts @@ -6,7 +6,13 @@ export const list = { return arr.map(lambda) }, 'List.sort': (arr: number[], lambda: (item1: number, item2: number) => number): number[] => { - return lambda ? [...arr].sort(lambda) : [...arr].sort() + return lambda + ? [...arr].sort(lambda) + : [...arr].sort((a, b) => { + if (a < b) return -1 + if (a > b) return 1 + return 0 + }) }, 'List.reverse': (arr: number[]): number[] => { return [...arr].reverse()