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
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@types/node": "^14.14.41",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"esbuild": "^0.11.16",
"esbuild": "^0.11.18",
"esbuild-register": "^2.5.0",
"eslint": "^7.25.0",
"mocha": "^8.3.2",
Expand Down
28 changes: 15 additions & 13 deletions src/ako_grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Ako {

// Statement
Block = "{" Stmt* "}"
Stmt = (Metadata | Assign | AssignTask | TaskDef | Task | If | ForLoop | Expr)
Stmt = (Metadata | If | Assign | AssignTask | TaskDef | Task | ForLoop | Expr)

Assign = AssignLeft | AssignAdd | AssignIncr | AssignDecr | AssignSub
AssignTask = Var "=" Task
Expand All @@ -12,19 +12,19 @@ Ako {
AssignSub = Var "-=" Expr
AssignIncr = Var "++"
AssignDecr = Var "--"
Metadata = "##" Id Term
Metadata = "##" id Term

TaskDef = "task" Id (Array)? Block
Task = "@" (Id ".")? Id "(" NamedArguments ")"
TaskDef = "task" id (Array)? Block
Task = "@" (id ".")? id "(" NamedArguments ")"
NamedArguments = ListOf<(KeyValue | Expr), ",">
Arguments = ListOf<Expr, ",">

// Expression
Expr = LambdaInline | Fn | MathExpr | Term
Term =Var | Number | String | bool | Array | Dictionary | Last
Fn = (Id ".")? Id "(" Arguments ")"
// Lambda = "(" ListOf<Id, ","> ")" "=>" Block
LambdaInline = "(" ListOf<Id, ","> ")" "=>" Expr
Fn = (id ".")? id "(" Arguments ")"
// Lambda = "(" ListOf<id, ","> ")" "=>" Block
LambdaInline = "(" ListOf<id, ","> ")" "=>" Expr

// Math
MathExpr = BinExpr
Expand Down Expand Up @@ -64,25 +64,27 @@ Ako {

// Loop
ForLoop = Foreach | While | Infinite | Continue | Return
Foreach = "for" Id ("," Id)? ":=" Expr Block
Foreach = "for" id ("," id)? ":=" Expr Block
While = "for" Expr Block
Infinite = "for" Block
Continue = "continue"
Return = "return" Expr
Return = "return" (Expr)?

// Identifier / Variable
Last = "$"
Var = Var "[" Expr "]" -- subscript
| Var "[" Expr? ":" Expr? "]" -- range
| Var "." Id -- select
| Id -- single
Id = ~(keyword) (letter alnum*)
| Var "." id -- select
| id -- single

id = ~keyword char
char = letter (letter | digit | "_")*
keyword = "$" | "task" | "for" | "false" | "true" | "or" | "and" | "not" | "if" | "elif" | "else" | "continue" | "return"

// List
Array = "[" ListOf<Expr, ","> "]"
Dictionary = "{" ListOf<KeyValue, ","> "}"
KeyValue = Id "=" Expr
KeyValue = id "=" Expr

// Boolean
bool = "true" | "false"
Expand Down
1 change: 1 addition & 0 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface Stack {
child: string | undefined
elements: any[]
elementsData: any[]
continue?: boolean
result?: any
}

Expand Down
2 changes: 2 additions & 0 deletions src/elements/conditional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const If = {
if (ctx.vm.evaluate(ctx, entry.ifCond, true)) {
const block = ctx.vm.createStack(entry.ifBlock.statements, ctx.stack.parent ? ctx.stack.parent : ctx.stack.uid)
entryData.meta = {block: block.uid}
console.log('CREATE IFBLOCK', entryData.meta)
}

// else if
Expand Down Expand Up @@ -35,6 +36,7 @@ export const If = {
const stack = ctx.vm.stacks.get(entryData.meta.block)
const res = ctx.vm.updateStack(stack, timeRemains, true)
if (res.done && 'result' in stack) ctx.vm.callReturn(ctx, stack.result)
if (res.done && 'continue' in stack) ctx.vm.callContinue(ctx)
return res
}
}
15 changes: 13 additions & 2 deletions src/elements/loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const LoopWhile = {

export const LoopFor = {
create: (item, index, iterator, block) => {
return {type: 'LoopFor', item, index, iterator, block} as LoopForData
return {type: 'LoopFor', item, index: index.length > 0 ? index[0] : index, iterator, block} as LoopForData
},
initialize: (ctx: Context, entry: LoopForData, entryData: any) => {
const block = ctx.vm.createStack(entry.block.statements, ctx.stack.parent ? ctx.stack.parent : ctx.stack.uid)
Expand Down Expand Up @@ -66,6 +66,13 @@ export const LoopFor = {
const res = ctx.vm.updateStack(stack, timeRemains, true)
timeRemains = res.timeRemains

if ('continue' in stack && stack.continue) {
entryData.meta.index++
LoopFor.next(ctx, entry, entryData, timeRemains)
stack.continue = false
continue
}

if (res.done && 'result' in stack) {
ctx.vm.callReturn(ctx, stack.result)
return {timeRemains, done: true}
Expand Down Expand Up @@ -95,6 +102,10 @@ export const Block = {
export const Continue = {
create: () => {
return {type: 'Continue'}
},
execute: (ctx: Context, entry, entryData, timeRemains: number) => {
ctx.vm.callContinue(ctx)
return {timeRemains, done: true}
}
}

Expand All @@ -103,7 +114,7 @@ export const Return = {
return {type: 'Return', expr}
},
execute: (ctx: Context, entry, entryData, timeRemains: number) => {
ctx.vm.callReturn(ctx, ctx.vm.evaluate(ctx, entry.expr, true))
ctx.vm.callReturn(ctx, ctx.vm.evaluate(ctx, entry.expr.length > 0 ? entry.expr[0] : entry.expr, true))
return {timeRemains, done: true}
}
}
5 changes: 5 additions & 0 deletions src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ export class Interpreter {
this.tasks.set(name, method)
}

callContinue(ctx: Context): void {
ctx.stack.continue = true
ctx.stack.index = ctx.stack.elements.length
}

callReturn(ctx: Context, val: any): void {
ctx.stack.result = val
ctx.stack.index = ctx.stack.elements.length
Expand Down
2 changes: 1 addition & 1 deletion src/semantic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export function getGrammar(akoGrammar: string) {
Return: (a, b) => AkoElement.Return.create(b.toAST()),

// Var
Id: (a, b) => AkoElement.String.create(a.sourceString + b.sourceString),
id: (a) => AkoElement.String.create(a.sourceString),
Var_single: (a) => AkoElement.Symbol.create(a.toAST()),
Var_select: (a, b, c) => AkoElement.SymbolSelect.create(a.toAST(), c.toAST()),
Var_range: (a, b, c, d, e, f) => AkoElement.SymbolRange.create(a.toAST(), c.toAST(), e.toAST()),
Expand Down
57 changes: 49 additions & 8 deletions tests/loop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,61 @@ for a := [1,2,3,4,5,6,7,8] {
assert.strictEqual((stack.data as any)['b'], 2)
})

it('Simple loop', () => {
it('Nested Loop', () => {
const {stack} = runCode(`
b = 38
for a := [1,2,3,4,5,6,7,8] {
if a > 3 { return 0 }
b -= a
counter = 0
for a := [1,2] {
for b := [3,4] {
for c, index := [1,2,3,4] {
counter += c
}
counter += b
}
counter += a
}
`)
assert.strictEqual((stack.data as any)['counter'], 57)
})

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] {
counter += c
if counter >= 3 {
return
}
}
counter += b
}
counter += a
}
`)
assert.strictEqual((stack.data as any)['counter'], 3)
})

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] {
if counter >= 3 {
continue
}
counter += c
}
counter += b
}
counter += a
}
`)
assert.strictEqual((stack.data as any)['b'], 32)
assert.strictEqual((stack.data as any)['counter'], 20)
})

// TODO: Implement continue
// TODO: Implement Infinite loop
// TODO: Check Index
/*
it('Check Index', () => {
const {stack} = runCode(`
Expand Down