flofriday / Moose

🐐 A new fun programming language
MIT License
6 stars 1 forks source link

Interpreter - weird object overlapping for methods #33

Closed Jozott00 closed 1 year ago

Jozott00 commented 1 year ago

When calling a method, in perspective of the method, the environment does always equal the environment of the latest created object.

 c1 = C(1)
c2 = C(2)

t1 = c1.b       // is 1
t2 = c1.num()   // is 2, should be 1
t3 = c2.b       // is 2
t4 = c2.num()   // is 2

b1true = t1 == t2   // is false, should be true
b2false = t2 == t3  // is true, should be false
b3true = t3 == t4   // is true

class C { b: Int; func num() > Int { return b } }

This example shows that b in C.num() is always 2, because the latest created object has b = 2

Jozott00 commented 1 year ago

Ok the problem lies here in the Interpreter:

 func callFunctionOrOperator(callee: MooseObject, args: [MooseObject]) throws -> MooseObject {
      ...
        } else if let callee = callee as? FunctionObj {
            // Activate the  environment in which the function was defined
            let oldEnv = environment
            environment = callee.closure

            pushEnvironment()

...
}

since the closure of the function apparently holds the environment of the latest object...

@flofriday you implemented the closure, so i guess you can fix it in a better way than me

Jozott00 commented 1 year ago

Ok found the reason.

In the interpreter when a constructor node is called (callConstructor(...)) we execute classObject.bindMethods() which makes perfect sense. The only problem is, that we do a copy of the ClassEnvironment, however since the FunctionObjs in the funcs dict of the environment are classes, they are copied by reference. So even if we bind the methods on the copied class, we always rebind them on the exact same FunctionObjs.

So the most straight forward solution would be to implement a copy constructor for the FunctionObjs and on copying the classEnvironment, we also copy each function manually.