functions now capture variables :D

This commit is contained in:
Neemek 2026-07-09 23:21:41 +02:00
parent 43e450c207
commit d315a53fbd
Signed by: neemek
GPG key ID: 84FFE4D7D40AB25E
5 changed files with 49 additions and 11 deletions

View file

@ -587,6 +587,7 @@ func (c *Compiler) compile(tree Node) error {
n.yield, n.yield,
c.Chunk, c.Chunk,
nil, nil,
nil,
} }
// restore old chunk and ip // restore old chunk and ip
@ -958,6 +959,13 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
} }
return nil, c.error(fmt.Sprintf("unimplemented result type deduction for unary %s", n.UnaryOperation), n) return nil, c.error(fmt.Sprintf("unimplemented result type deduction for unary %s", n.UnaryOperation), n)
case BlockNodeType:
n := tree.(*BlockNode)
if len(n.statements) == 0 {
return &NilSignature{}, nil
}
return c.deduceSignature(n.statements[len(n.statements)-1])
default: default:
return nil, c.error(fmt.Sprintf("impossible to deduce signature of %s", tree.Type()), tree) return nil, c.error(fmt.Sprintf("impossible to deduce signature of %s", tree.Type()), tree)
} }

View file

@ -1387,10 +1387,16 @@ func (p *Parser) parseSignature() (TypeSignature, error) {
in = append(in, sig) in = append(in, sig)
} }
out, err := p.parseSignature() var out TypeSignature
var err error
if p.accept(TokenArrow) {
out, err = p.parseSignature()
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else {
out = &NilSignature{}
}
s = &FunctionSignature{ s = &FunctionSignature{
in, in,

View file

@ -603,6 +603,7 @@ type FunctionValue struct {
Yield TypeSignature Yield TypeSignature
Chunk *Chunk Chunk *Chunk
Parent Value Parent Value
Scope *Scope
} }
func (v *FunctionValue) Type() ValueType { func (v *FunctionValue) Type() ValueType {
@ -633,6 +634,7 @@ func (v *FunctionValue) Clone() Value {
v.Yield, v.Yield,
v.Chunk, v.Chunk,
v.Parent, v.Parent,
v.Scope,
} }
} }

View file

@ -698,7 +698,13 @@ func (vm *VM) Next() bool {
vm.stack.Pop() vm.stack.Pop()
case InstructionConstant: case InstructionConstant:
vm.stack.Push(vm.ReadConstant()) c := vm.ReadConstant()
if c, ok := c.(*FunctionValue); ok {
c.Scope = vm.scope
}
vm.stack.Push(c)
case InstructionAddFloat: case InstructionAddFloat:
r := vm.stack.Pop().(*FloatValue).Number r := vm.stack.Pop().(*FloatValue).Number
@ -840,6 +846,7 @@ func (vm *VM) Next() bool {
scope: vm.scope, scope: vm.scope,
}) })
vm.scope = f.Scope
vm.descend() vm.descend()
for i := len(f.Params) - 1; i >= 0; i-- { for i := len(f.Params) - 1; i >= 0; i-- {
@ -993,6 +1000,15 @@ func (vm *VM) Next() bool {
vm.stack.Push(member) vm.stack.Push(member)
case InstructionBreakpoint: case InstructionBreakpoint:
/*
// I'm keeping this
s := vm.scope
log.Printf("breakpoint %d", vm.ip)
for s != nil {
log.Printf("%s", s.current)
s = s.parent
}
*/
vm.stack.Push(&NilValue{}) vm.stack.Push(&NilValue{})
default: default:
@ -1122,7 +1138,7 @@ func (vm *VM) HasNext() bool {
} }
func (vm *VM) GetConstant(id Bytecode) Value { func (vm *VM) GetConstant(id Bytecode) Value {
return vm.chunk.Constants[id] return vm.chunk.Constants[id].Clone()
} }
func (vm *VM) ReadConstant() Value { func (vm *VM) ReadConstant() Value {

View file

@ -1,10 +1,16 @@
fn counter() -> (fn() -> int) {
i := 0
fn double(a: int) -> int { fn() -> int {
2*a i = i + 1
}
} }
a := 1 next := counter()
other := counter()
a = 2 println(next())
println(next())
println(double(2) == 4) println(other())
println(other())
println(next())