diff --git a/README.md b/README.md index f691dea..3dedb9d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ It's where Shrimp live. - Dictionary operations (MAKE_DICT, DICT_GET, DICT_SET, DICT_HAS) - Function operations (MAKE_FUNCTION, CALL, TAIL_CALL, RETURN) with parameter binding - Variadic functions with positional rest parameters (`...rest`) -- Named arguments (kwargs) that collect unmatched named args into a dict (`@named`) +- Named arguments (named) that collect unmatched named args into a dict (`@named`) - Mixed positional and named arguments with proper priority binding - Tail call optimization with unbounded recursion (10,000+ iterations without stack overflow) - Exception handling (PUSH_TRY, PUSH_FINALLY, POP_TRY, THROW) with nested try/finally blocks and call stack unwinding diff --git a/src/vm.ts b/src/vm.ts index eb5d859..6de55a8 100644 --- a/src/vm.ts +++ b/src/vm.ts @@ -386,7 +386,7 @@ export class VM { // Check if named argument was provided for this param if (namedArgs.has(paramName)) { this.scope.set(paramName, namedArgs.get(paramName)!) - namedArgs.delete(paramName) // Remove from named args so it won't go to kwargs + namedArgs.delete(paramName) // Remove from named args so it won't go to named } else if (positionalArgs[i] !== undefined) { this.scope.set(paramName, positionalArgs[i]!) } else if (fn.defaults[paramName] !== undefined) { @@ -410,11 +410,11 @@ export class VM { // Handle named parameter (collect remaining named args that didn't match params) if (fn.named) { const namedParamName = fn.params[fn.params.length - 1]! - const kwargsDict = new Map() + const namedDict = new Map() for (const [key, value] of namedArgs) { - kwargsDict.set(key, value) + namedDict.set(key, value) } - this.scope.set(namedParamName, { type: 'dict', value: kwargsDict }) + this.scope.set(namedParamName, { type: 'dict', value: namedDict }) } // subtract 1 because pc was incremented @@ -488,11 +488,11 @@ export class VM { // Handle named parameter if (tailFn.named) { const namedParamName = tailFn.params[tailFn.params.length - 1]! - const kwargsDict = new Map() + const namedDict = new Map() for (const [key, value] of tailNamedArgs) { - kwargsDict.set(key, value) + namedDict.set(key, value) } - this.scope.set(namedParamName, { type: 'dict', value: kwargsDict }) + this.scope.set(namedParamName, { type: 'dict', value: namedDict }) } // subtract 1 because PC was incremented diff --git a/tests/functions.test.ts b/tests/functions.test.ts index a905cc9..61a8d8f 100644 --- a/tests/functions.test.ts +++ b/tests/functions.test.ts @@ -201,7 +201,7 @@ test("TAIL_CALL - variadic function", async () => { test("CALL - named args function with no fixed params", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (@kwargs) #9 + MAKE_FUNCTION (@named) #9 PUSH "name" PUSH "Bob" PUSH "age" @@ -210,7 +210,7 @@ test("CALL - named args function with no fixed params", async () => { PUSH 2 CALL HALT - LOAD kwargs + LOAD named RETURN `) @@ -224,7 +224,7 @@ test("CALL - named args function with no fixed params", async () => { test("CALL - named args function with one fixed param", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (x @kwargs) #8 + MAKE_FUNCTION (x @named) #8 PUSH 10 PUSH "name" PUSH "Alice" @@ -232,7 +232,7 @@ test("CALL - named args function with one fixed param", async () => { PUSH 1 CALL HALT - LOAD kwargs + LOAD named RETURN `) @@ -244,9 +244,9 @@ test("CALL - named args function with one fixed param", async () => { } }) -test("CALL - named args with matching param name should bind to param not kwargs", async () => { +test("CALL - named args with matching param name should bind to param not named", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (name @kwargs) #8 + MAKE_FUNCTION (name @named) #8 PUSH "Bob" PUSH "age" PUSH 50 @@ -259,13 +259,13 @@ test("CALL - named args with matching param name should bind to param not kwargs `) const result = await new VM(bytecode).run() - // name should be bound as regular param, not collected in kwargs + // name should be bound as regular param, not collected in named expect(result).toEqual({ type: 'string', value: 'Bob' }) }) -test("CALL - named args that match param names should not be in kwargs", async () => { +test("CALL - named args that match param names should not be in named", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (name age @kwargs) #9 + MAKE_FUNCTION (name age @named) #9 PUSH "name" PUSH "Bob" PUSH "city" @@ -274,14 +274,14 @@ test("CALL - named args that match param names should not be in kwargs", async ( PUSH 2 CALL HALT - LOAD kwargs + LOAD named RETURN `) const result = await new VM(bytecode).run() expect(result.type).toBe('dict') if (result.type === 'dict') { - // Only city should be in kwargs, name should be bound to param + // Only city should be in named, name should be bound to param expect(result.value.get('city')).toEqual({ type: 'string', value: 'NYC' }) expect(result.value.has('name')).toBe(false) expect(result.value.size).toBe(1) @@ -290,7 +290,7 @@ test("CALL - named args that match param names should not be in kwargs", async ( test("CALL - mixed variadic and named args", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (x ...rest @kwargs) #10 + MAKE_FUNCTION (x ...rest @named) #10 PUSH 1 PUSH 2 PUSH 3 @@ -315,9 +315,9 @@ test("CALL - mixed variadic and named args", async () => { }) }) -test("CALL - mixed variadic and named args, check kwargs", async () => { +test("CALL - mixed variadic and named args, check named", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (x ...rest @kwargs) #10 + MAKE_FUNCTION (x ...rest @named) #10 PUSH 1 PUSH 2 PUSH 3 @@ -327,7 +327,7 @@ test("CALL - mixed variadic and named args, check kwargs", async () => { PUSH 1 CALL HALT - LOAD kwargs + LOAD named RETURN `) @@ -340,18 +340,18 @@ test("CALL - mixed variadic and named args, check kwargs", async () => { test("CALL - named args with no extra named args", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (x @kwargs) #6 + MAKE_FUNCTION (x @named) #6 PUSH 10 PUSH 1 PUSH 0 CALL HALT - LOAD kwargs + LOAD named RETURN `) const result = await new VM(bytecode).run() - // kwargs should be empty dict + // named should be empty dict expect(result.type).toBe('dict') if (result.type === 'dict') { expect(result.value.size).toBe(0) @@ -360,7 +360,7 @@ test("CALL - named args with no extra named args", async () => { test("CALL - named args with defaults on fixed params", async () => { const bytecode = toBytecode(` - MAKE_FUNCTION (x=5 @kwargs) #7 + MAKE_FUNCTION (x=5 @named) #7 PUSH "name" PUSH "Alice" PUSH 0