Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion _sidebar.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
* [Home](/)
* [Grammar](./docs/grammar_basic.md)
* [Basic](./docs/grammar_basic.md)
* [Loop](./docs/grammar_loop.md)
* [Task](./docs/grammar_task.md)
* [Interpreter](./docs/interpreter_basic.md)
* [Basic](./docs/interpreter_basic.md)
* [Basic](./docs/interpreter_basic.md)
37 changes: 37 additions & 0 deletions docs/grammar_loop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Loop

In Ako there is only one loop `For` but with 3 different behaviours:

## Iterate List
To iterate a list of elements, the syntax is `for [val] in [list] [block]`
```js
for a in [1,2,3,4,5,6,7,8] {
@print("{a}")
}
```
you can also have the iteration index
```js
for val, index in [1,2,3,4,5,6,7,8] {
@print("{index} = {val}")
}
```

## Until condition
This is commonly named `until` or `while` loop in other language.

The syntax is `for [condition] [block]`
```js
for counter < 10 {
counter += 1
}
```

## Infinite Loop
This is an infinite loop, make sure to put some

The syntax is `for [block]`
```js
for {
counter += 1
}
```
4 changes: 2 additions & 2 deletions samples/vec/main.ako
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
for countdown := [5,4,3,2,1,0] {
for countdown in [5,4,3,2,1,0] {
if countdown > 0 {
@print("{countdown} !")
@sleep(0.1)
} else {
@print("Countdown Finish !")
}
}
}
2 changes: 1 addition & 1 deletion src/ako_grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Ako {

// Loop
ForLoop = Foreach | While | Infinite | Continue | Return
Foreach = "for" id ("," id)? ":=" Expr Block
Foreach = "for" id ("," id)? "in" Expr Block
While = "for" Expr Block
Infinite = "for" Block
Continue = "continue"
Expand Down
2 changes: 1 addition & 1 deletion src/dist/ako-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function loadAkoModule(vm: Interpreter, projectFolder: string) {
const method = namespace ? `${namespace}.${fileId}` : fileId
const match = grammar.match(`@${method}()`)
const ast = ASTBuilder(match).toAST()
console.log('Create Stack >', fileId)
// console.log('Create Stack >', fileId)
vm.createStack(ast)
}
}
Expand Down
69 changes: 65 additions & 4 deletions src/elements/loop.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import {Context} from '../core'
import {Number} from './scalar'

export interface LoopWhileData {
type: string
cond: any
block: any
}

export interface LoopForData {
type: string
Expand All @@ -12,12 +19,69 @@ export interface LoopForData {
export const LoopInfinite = {
create: (block) => {
return {type: 'LoopInfinite', block}
},
initialize: (ctx: Context, entry: LoopWhileData, entryData: any) => {
entry.cond = Number.create(1)
},
execute: (ctx: Context, entry: LoopWhileData, entryData: any, timeRemains: number) => {
// Initialize
if (!entryData.meta) LoopInfinite.initialize(ctx, entry, entryData)
return LoopWhile.execute(ctx, entry, entryData, timeRemains)
}
}

export const LoopWhile = {
create: (cond, block) => {
return {type: 'LoopWhile', cond, block}
},
initialize: (ctx: Context, entry: LoopWhileData, entryData: any) => {
entryData.meta = {
block: 0,
cond: ctx.vm.evaluate(ctx, entry.cond, true)
}

if (!entryData.meta.cond) return
const block = ctx.vm.createStack(entry.block.statements, ctx.stack.parent ? ctx.stack.parent : ctx.stack.uid)
entryData.meta.block = block.uid
},
next: (ctx: Context, entry: LoopWhileData, entryData: any, timeRemains: number) => {
if (timeRemains <= 0) return

entryData.meta.cond = ctx.vm.evaluate(ctx, entry.cond, true)
if (!entryData.meta.cond) return
const block = ctx.vm.createStack(entry.block.statements, ctx.stack.parent ? ctx.stack.parent : ctx.stack.uid)
entryData.meta.block = block.uid
},
execute: (ctx: Context, entry: LoopWhileData, entryData: any, timeRemains: number) => {
// Initialize
if (!entryData.meta) LoopWhile.initialize(ctx, entry, entryData)

// Iterate
while (timeRemains > 0 && !!entryData.meta.cond) {
const stack = ctx.vm.stacks.get(entryData.meta.block)

// Prepare next loop
if (!stack || stack.done) LoopWhile.next(ctx, entry, entryData, timeRemains)

if (stack && !stack.done) {
const res = ctx.vm.updateStack(stack, timeRemains, true)
timeRemains = res.timeRemains

if ('continue' in stack && stack.continue) {
LoopWhile.next(ctx, entry, entryData, timeRemains)
stack.continue = false
continue
}

if (res.done && 'result' in stack) {
ctx.vm.callReturn(ctx, stack.result)
entryData.meta.cond = false
return {timeRemains, done: true}
}
}
}

return {timeRemains, done: !entryData.meta.cond}
}
}

Expand Down Expand Up @@ -86,10 +150,7 @@ export const LoopFor = {
}
}

return {
timeRemains,
done: entryData.meta.index >= entryData.meta.iterator.length
}
return {timeRemains, done: entryData.meta.index >= entryData.meta.iterator.length}
}
}

Expand Down
28 changes: 28 additions & 0 deletions tests/expr.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
import assert from 'assert'
import {runCode} from './helper'

describe('Math Expression', () => {
it('Math Functions', () => {
const {stack: stack1} = runCode(`
a = Math.PI()
b = Math.max(1,2,12,2)
c = Math.min(1,2,12,2)
d = List.map([1,-2,3], (val) => Math.abs(val))
e = List.map([1.2,-2.6,3.6], (val) => Math.ceil(val))
f = List.map([1.2,-2.6,3.6], (val) => Math.floor(val))
`)
assert.strictEqual((stack1.data as any)['a'], Math.PI)
assert.strictEqual((stack1.data as any)['b'], 12)
assert.strictEqual((stack1.data as any)['c'], 1)
assert.deepStrictEqual((stack1.data as any)['d'], [1, 2, 3])
assert.deepStrictEqual((stack1.data as any)['e'], [2, -2, 4])
assert.deepStrictEqual((stack1.data as any)['f'], [1, -3, 3])
})

it('Degree Functions', () => {
const {stack: stack1} = runCode(`
a = List.map([0, 45, 90, 180], (val) => Angle.toRad(val))
b = List.map([0, 45, 90, 180], (val) => Angle.toDeg(Angle.toRad(val)))
`)
assert.deepStrictEqual((stack1.data as any)['a'], [0, Math.PI / 4, Math.PI / 2, Math.PI])
assert.deepStrictEqual((stack1.data as any)['b'], [0, 45, 90, 180])
})
})

describe('Equality Expression', () => {
it('Equality', () => {
const {stack: stack1} = runCode(`
Expand Down
16 changes: 13 additions & 3 deletions tests/function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import assert from 'assert'
import {runCode} from './helper'

describe('Function', function () {
it('Unexisting Function', () => {
assert.throws(() => {
runCode(`
a = unknown(1,2,3,4,5)
`)
})
})

it('Check Expression Function', () => {
const {stack} = runCode(`
a = Math.max(1,2,3,4,5)
Expand All @@ -12,16 +20,18 @@ a = Math.max(1,2,3,4,5)

it('Array Function', () => {
const {stack} = runCode(`
list = [1,5,2,3,4]
list = [1,5,2,3,4,1]
sorted = List.sort(list)
sorted2 = List.sort(list, (a, b) => b - a)
filtered = List.filter(sorted2, (a) => a >= 3)
rev = List.reverse(filtered)
rev2 = List.map(filtered, (a) => a * 2)
`)
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)['sorted'], [1, 1, 2, 3, 4, 5])
assert.deepStrictEqual((stack.data as any)['sorted2'], [5, 4, 3, 2, 1, 1])
assert.deepStrictEqual((stack.data as any)['filtered'], [5, 4, 3])
assert.deepStrictEqual((stack.data as any)['rev'], [3, 4, 5])
assert.deepStrictEqual((stack.data as any)['rev2'], [10, 8, 6])
})

it('Vector', () => {
Expand Down
60 changes: 40 additions & 20 deletions tests/loop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe('Loop', function () {
it('Simple loop', () => {
const {stack} = runCode(`
b = 38
for a := [1,2,3,4,5,6,7,8] {
for a in [1,2,3,4,5,6,7,8] {
b -= a
}
`)
Expand All @@ -15,9 +15,9 @@ for a := [1,2,3,4,5,6,7,8] {
it('Nested Loop', () => {
const {stack} = runCode(`
counter = 0
for a := [1,2] {
for b := [3,4] {
for c, index := [1,2,3,4] {
for a in [1,2] {
for b in [3,4] {
for c, index in [1,2,3,4] {
counter += c
}
counter += b
Expand All @@ -31,9 +31,9 @@ for a := [1,2] {
it('Nested Loop with return', () => {
const {stack} = runCode(`
counter = 0
for a := [1,2] {
for b := [3,4] {
for c, index := [1,2,3,4] {
for a in [1,2] {
for b in [3,4] {
for c, index in [1,2,3,4] {
counter += c
if counter >= 3 {
return
Expand All @@ -50,9 +50,9 @@ for a := [1,2] {
it('Nested Loop with continue', () => {
const {stack} = runCode(`
counter = 0
for a := [1,2] {
for b := [3,4] {
for c, index := [1,2,3,4] {
for a in [1,2] {
for b in [3,4] {
for c, index in [1,2,3,4] {
if counter >= 3 {
continue
}
Expand All @@ -66,18 +66,38 @@ for a := [1,2] {
assert.strictEqual((stack.data as any)['counter'], 20)
})

// TODO: Implement Infinite loop
/*
it('Check Index', () => {
it('Until Loop', () => {
const {stack} = runCode(`
b = 0
for val, index := [1,2,3,4,5,6,7,8] {
@print("this is {val} {index}")
if index > 1 { return 0 }
b += val
counter = 0
for counter < 10 {
counter += 1
}
`)
assert.strictEqual((stack.data as any)['counter'], 10)
})

it('Infinite Loop', () => {
const {stack} = runCode(`
counter = 0
for {
counter += 1
if counter >= 10 { return }
}
`)
assert.strictEqual((stack.data as any)['counter'], 10)
})

it('Infinite Loop with delay', () => {
const {vm, stack} = runCode(`
counter = 0
for {
@print("{counter}")
counter += 1
if counter >= 10 { return }
@sleep(1)
}
`)
assert.strictEqual((stack.data as any)['b'], 3)
vm.update(16)
assert.strictEqual((stack.data as any)['counter'], 10)
})
*/
})
8 changes: 8 additions & 0 deletions tests/task.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import assert from 'assert'
import {runCode, runFileCode} from './helper'

describe('Task', () => {
it('Unexisting Task', () => {
assert.throws(() => {
runCode(`
a = @unknown(1,2,3,4,5)
`)
})
})

it('Create and run task', () => {
const {stack} = runCode(`
task Method1 {
Expand Down