update spec
This commit is contained in:
parent
8c187a89aa
commit
0270424f9b
77
SPEC.md
77
SPEC.md
|
|
@ -38,8 +38,8 @@ type Value =
|
||||||
| { type: 'string', value: string }
|
| { type: 'string', value: string }
|
||||||
| { type: 'array', value: Value[] }
|
| { type: 'array', value: Value[] }
|
||||||
| { type: 'dict', value: Map<string, Value> }
|
| { type: 'dict', value: Map<string, Value> }
|
||||||
| { type: 'function', params: string[], defaults: Record<string, Value>,
|
| { type: 'function', params: string[], defaults: Record<string, number>,
|
||||||
body: number, parentScope: Scope, variadic: boolean, kwargs: boolean }
|
body: number, parentScope: Scope, variadic: boolean, named: boolean }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Type Coercion
|
### Type Coercion
|
||||||
|
|
@ -67,7 +67,7 @@ type Instruction = {
|
||||||
type Constant =
|
type Constant =
|
||||||
| Value
|
| Value
|
||||||
| { type: 'function_def', params: string[], defaults: Record<string, number>,
|
| { type: 'function_def', params: string[], defaults: Record<string, number>,
|
||||||
body: number, variadic: boolean, kwargs: boolean }
|
body: number, variadic: boolean, named: boolean }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Scope Chain
|
## Scope Chain
|
||||||
|
|
@ -276,12 +276,12 @@ Adds a finally block to the current try/catch. The finally block will execute wh
|
||||||
|
|
||||||
**Behavior**:
|
**Behavior**:
|
||||||
1. Pop exception handler
|
1. Pop exception handler
|
||||||
2. If handler has `finallyAddress`, jump there
|
2. Continue to next instruction
|
||||||
3. Otherwise continue to next instruction
|
|
||||||
|
|
||||||
**Notes**:
|
**Notes**:
|
||||||
- The VM ensures finally runs when try completes normally
|
- The VM does NOT automatically jump to finally blocks on POP_TRY
|
||||||
- The compiler must ensure catch blocks jump to finally when present
|
- The compiler must explicitly generate JUMP instructions to finally blocks when the try block completes normally
|
||||||
|
- The compiler must ensure catch blocks also jump to finally when present
|
||||||
- Finally blocks should end with normal control flow (no special terminator needed)
|
- Finally blocks should end with normal control flow (no special terminator needed)
|
||||||
|
|
||||||
#### THROW
|
#### THROW
|
||||||
|
|
@ -296,8 +296,12 @@ Adds a finally block to the current try/catch. The finally block will execute wh
|
||||||
4. Unwind call stack to handler's depth
|
4. Unwind call stack to handler's depth
|
||||||
5. Restore handler's scope
|
5. Restore handler's scope
|
||||||
6. Push error value back onto stack
|
6. Push error value back onto stack
|
||||||
7. Jump to handler's catch address
|
7. If handler has `finallyAddress`, jump there; otherwise jump to `catchAddress`
|
||||||
8. **Note**: After catch block executes, compiler must jump to finally if present
|
|
||||||
|
**Notes**:
|
||||||
|
- When THROW jumps to finally (if present), the error value remains on stack for the finally block
|
||||||
|
- The compiler must structure catch/finally blocks appropriately to handle the error value
|
||||||
|
- If finally is present, the catch block is typically entered via a jump from the finally block or through explicit compiler-generated control flow
|
||||||
|
|
||||||
### Function Operations
|
### Function Operations
|
||||||
|
|
||||||
|
|
@ -310,8 +314,8 @@ The constant must be a `function_def` with:
|
||||||
- `params`: Parameter names
|
- `params`: Parameter names
|
||||||
- `defaults`: Map of param names to constant indices for default values
|
- `defaults`: Map of param names to constant indices for default values
|
||||||
- `body`: Instruction address of function body
|
- `body`: Instruction address of function body
|
||||||
- `variadic`: If true, last param collects remaining positional args as array
|
- `variadic`: If true, second-to-last param (if `named` is also true) or last param collects remaining positional args as array
|
||||||
- `kwargs`: If true, last param collects all named args as dict
|
- `named`: If true, last param collects unmatched named args as dict
|
||||||
|
|
||||||
The created function captures `currentScope` as its `parentScope`.
|
The created function captures `currentScope` as its `parentScope`.
|
||||||
|
|
||||||
|
|
@ -332,7 +336,7 @@ The created function captures `currentScope` as its `parentScope`.
|
||||||
9. Bind parameters:
|
9. Bind parameters:
|
||||||
- For regular functions: bind params by position, then by name, then defaults, then null
|
- For regular functions: bind params by position, then by name, then defaults, then null
|
||||||
- For variadic functions: bind fixed params, collect rest into array
|
- For variadic functions: bind fixed params, collect rest into array
|
||||||
- For kwargs functions: bind fixed params by position/name, collect unmatched named args into dict
|
- For functions with `named: true`: bind fixed params by position/name, collect unmatched named args into dict
|
||||||
10. Set currentScope to new scope
|
10. Set currentScope to new scope
|
||||||
11. Jump to function body
|
11. Jump to function body
|
||||||
|
|
||||||
|
|
@ -344,8 +348,8 @@ The created function captures `currentScope` as its `parentScope`.
|
||||||
|
|
||||||
**Named Args Handling**:
|
**Named Args Handling**:
|
||||||
- Named args that match fixed parameter names are bound to those params
|
- Named args that match fixed parameter names are bound to those params
|
||||||
- Remaining named args (that don't match any fixed param) are collected into `@kwargs` dict
|
- If the function has `named: true`, remaining named args (that don't match any fixed param) are collected into the last parameter as a dict
|
||||||
- This allows flexible calling: `fn(x=10, y=20, extra=30)` where `extra` goes to kwargs
|
- This allows flexible calling: `fn(x=10, y=20, extra=30)` where `extra` goes to the named args dict
|
||||||
|
|
||||||
**Errors**: Throws if top of stack is not a function
|
**Errors**: Throws if top of stack is not a function
|
||||||
|
|
||||||
|
|
@ -510,14 +514,30 @@ skip_body:
|
||||||
|
|
||||||
### Try-Catch
|
### Try-Catch
|
||||||
```
|
```
|
||||||
PUSH_TRY catch_label
|
PUSH_TRY #3 ; Jump to catch block (3 instructions ahead)
|
||||||
# try block
|
; try block
|
||||||
POP_TRY
|
POP_TRY
|
||||||
JUMP end_label
|
JUMP #2 ; Jump past catch block
|
||||||
catch_label:
|
; catch:
|
||||||
STORE 'errorVar' # Error is on stack
|
STORE 'errorVar' ; Error is on stack
|
||||||
# catch block
|
; catch block
|
||||||
end_label:
|
; end:
|
||||||
|
```
|
||||||
|
|
||||||
|
### Try-Catch-Finally
|
||||||
|
```
|
||||||
|
PUSH_TRY #4 ; Jump to catch block (4 instructions ahead)
|
||||||
|
PUSH_FINALLY #7 ; Jump to finally block (7 instructions ahead)
|
||||||
|
; try block
|
||||||
|
POP_TRY
|
||||||
|
JUMP #5 ; Jump to finally
|
||||||
|
; catch:
|
||||||
|
STORE 'errorVar' ; Error is on stack
|
||||||
|
; catch block
|
||||||
|
JUMP #2 ; Jump to finally
|
||||||
|
; finally:
|
||||||
|
; finally block (executes in both cases)
|
||||||
|
; end:
|
||||||
```
|
```
|
||||||
|
|
||||||
### Named Function Call
|
### Named Function Call
|
||||||
|
|
@ -601,7 +621,7 @@ All of these should throw errors:
|
||||||
### Function Parameter Binding
|
### Function Parameter Binding
|
||||||
- Missing positional args → use named args → use defaults → use null
|
- Missing positional args → use named args → use defaults → use null
|
||||||
- Extra positional args → collected by variadic parameter or ignored
|
- Extra positional args → collected by variadic parameter or ignored
|
||||||
- Extra named args → collected by kwargs parameter or ignored
|
- Extra named args → collected by named args parameter (if `named: true`) or ignored
|
||||||
- Named arg matching is case-sensitive
|
- Named arg matching is case-sensitive
|
||||||
|
|
||||||
### Tail Call Optimization
|
### Tail Call Optimization
|
||||||
|
|
@ -615,11 +635,12 @@ All of these should throw errors:
|
||||||
- CONTINUE is implemented by the compiler using JUMPs
|
- CONTINUE is implemented by the compiler using JUMPs
|
||||||
|
|
||||||
### Exception Unwinding
|
### Exception Unwinding
|
||||||
- THROW unwinds call stack to handler's depth, not just to handler
|
- THROW unwinds call stack to handler's depth
|
||||||
- Exception handlers form a stack (nested try blocks)
|
- Exception handlers form a stack (nested try blocks)
|
||||||
- Error value on stack is available in catch block via STORE
|
- Error value on stack is available in catch/finally blocks
|
||||||
- Finally blocks always execute, even if there's a return/break in try or catch
|
- When THROW occurs and handler has finallyAddress, VM jumps to finally first
|
||||||
- Finally executes after try (if no exception) or after catch (if exception)
|
- Compiler is responsible for structuring control flow so finally executes in all cases
|
||||||
|
- Finally typically executes after try (if no exception) or after catch (if exception), but control flow is compiler-managed
|
||||||
|
|
||||||
## VM Initialization
|
## VM Initialization
|
||||||
|
|
||||||
|
|
@ -643,7 +664,7 @@ const result = await vm.execute()
|
||||||
6. **Break/continue** (nested functions, iterator pattern)
|
6. **Break/continue** (nested functions, iterator pattern)
|
||||||
7. **Closures** (capturing variables, multiple nesting levels)
|
7. **Closures** (capturing variables, multiple nesting levels)
|
||||||
8. **Tail calls** (self-recursive, mutual recursion)
|
8. **Tail calls** (self-recursive, mutual recursion)
|
||||||
9. **Parameter binding** (positional, named, defaults, variadic, kwargs, combinations)
|
9. **Parameter binding** (positional, named, defaults, variadic, named args collection, combinations)
|
||||||
10. **Array/dict operations** (creation, access, mutation)
|
10. **Array/dict operations** (creation, access, mutation)
|
||||||
11. **Error conditions** (all error cases listed above)
|
11. **Error conditions** (all error cases listed above)
|
||||||
12. **Edge cases** (empty stack, null values, shadowing, etc.)
|
12. **Edge cases** (empty stack, null values, shadowing, etc.)
|
||||||
|
|
@ -655,7 +676,7 @@ const result = await vm.execute()
|
||||||
3. **Closure examples** (counters, adder factories)
|
3. **Closure examples** (counters, adder factories)
|
||||||
4. **Exception examples** (try/catch/throw chains)
|
4. **Exception examples** (try/catch/throw chains)
|
||||||
5. **Complex scope** (deeply nested functions)
|
5. **Complex scope** (deeply nested functions)
|
||||||
6. **Mixed features** (variadic + defaults + kwargs)
|
6. **Mixed features** (variadic + defaults + named args)
|
||||||
|
|
||||||
### Property-Based Tests Should Cover
|
### Property-Based Tests Should Cover
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user