evincarofautumn / kitten

A statically typed concatenative systems programming language.
http://kittenlang.org/
Other
1.09k stars 39 forks source link

Locals bound in REPL should be accessible #115

Open kchaloux opened 10 years ago

kchaloux commented 10 years ago

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
>>>
11Kilobytes commented 9 years ago

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 commented 9 years ago

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.

evincarofautumn commented 9 years ago

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:

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

11Kilobytes commented 9 years ago

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?

evincarofautumn commented 9 years ago

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.

11Kilobytes commented 9 years ago

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

evincarofautumn commented 9 years ago

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

11Kilobytes commented 9 years ago

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.

evincarofautumn commented 7 years ago

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.