kitten icon indicating copy to clipboard operation
kitten copied to clipboard

Locals bound in REPL should be accessible

Open kchaloux opened this issue 10 years ago • 9 comments

The REPL currently supports semantics for binding locals to variable names:

>>> 100 -> x

In normal code, this would be accessible within functions or pushable directly onto the stack as desired. In the REPL, it is inaccessible:

>>> 100 -> x
>>> x
REPL:2:1: error: undefined word 'x'
>>>

Bound local variables that exist outside of function scope should be maintained in memory and be able to be pushed back onto the stack when desired. The following input should ultimately be valid:

>>> 100 -> x
>>> x

----
100
>>>

kchaloux avatar Nov 26 '13 14:11 kchaloux

I think that one of the main causes of this bug is that an expression such as 100 -> x is compiled into:

label 0
push int 100
enter 1
local 0 

i.e. 100 is pushed to the Local stack, and then left there. After optimization, this even shortens to ret 0, or something to that effect, i.e. a null program.

Another main problem is that once something is put in a local, the compiler always generates a leave instruction to pop it from the locals stack, so the REPL can't get access to it.

I think this is low enough hanging fruit that I can fix it, however I need guidance, how should I best approach this bug . I think that a quick hack would be to have a flag that allows for one to identify single line programs of the form 100 -> x and convert them to def x (-> int) and to turn on this flag by default for REPL interpretation but I can't think of anything better

11Kilobytes avatar Oct 09 '14 16:10 11Kilobytes

Maybe, I can make Kitten.Interpret.interpret return a tuple of (envCalls, envClosures, envData, envIp), i.e. all stacks and the instruction pointer. From the perspective of the "ML culture" in functional programming this is a bad idea, because it exposes components in the program to "internals" of interpret. From the perspective of the "Lisp and Smalltalk" culture, this is a good idea because, programs are viewed as "living things", the interpreter works on the basis of introspecting the details of a running program.

11Kilobytes avatar Oct 09 '14 17:10 11Kilobytes

Yeah, right now the -> syntax is parsed in such a way that it introduces a local scope which lasts until the end of the enclosing block. That’s not really correct.

I think the best way to solve this issue is to separate the introduction of names (->) from the manipulation of the local stack ({…}). We should push a local frame when we enter a function, and pop it when we return, regardless of the number of locals. -> should only add a new local. So in interactive mode, we’re simply in a scope that never ends.

These are the basic changes that would need to be made:

  • Remove the TrTerm a field from the TrLambda constructor of Kitten.Types.TrTerm.
  • Change how TrLambda is parsed and used in Kitten.Parse.
  • Change the type of the inferenceLocals field of Kitten.Types.Program from [Type Scalar] to [[Type Scalar]] and make a scope function like Kitten.Infer.local that introduces a new local scope.
  • Change the TrLambda case of Kitten.Infer.infer:
    • From the perspective of the data stack, it should have the same type as drop.
    • Kitten.Infer.local should not be scoped, but only introduce a new local in the current frame.
  • Change the TrClosure case of inferValue to use scope.
  • Change the TrLambda case of Kitten.IR.irTerm.

I’m not entirely sure about the IR and codegen parts, but we can deal with those when we come to them.

evincarofautumn avatar Oct 10 '14 18:10 evincarofautumn

I understand why all of these changes have to be done, except for the ones having to do with inferenceLocals, as I understand it, this field contains a list of the types of all locals that are in scope during the execution of some program. Why would this have to change after your suggestion?

11Kilobytes avatar Oct 14 '14 12:10 11Kilobytes

Ah, right, the type doesn’t need to change. Every function starts with 0 locals and drops all of them at the end; -> only adds locals. And the leave instruction is unnecessary.

evincarofautumn avatar Oct 14 '14 16:10 evincarofautumn

OK, I'm giving myself the deadline of 29th October

11Kilobytes avatar Oct 24 '14 06:10 11Kilobytes

How’s it going? Is there anything I can help with?

evincarofautumn avatar Nov 01 '14 21:11 evincarofautumn

I'm afraid it's not going well, due to the demands of school (~6hrs homework) per day, I have only finished the first three bullet points you listed above.

11Kilobytes avatar Nov 01 '14 22:11 11Kilobytes

This is semi-fixed in the new compiler. In top-level code, variable scopes can cross other top-level program elements:

"hello" -> x;
define f (…) { … }
x say

Using Kitten.Parse.composeUnderLambda. This is not yet working in the REPL because Kitten.Enter.defineWord needs to be updated.

evincarofautumn avatar Nov 06 '16 09:11 evincarofautumn