Open kchaloux opened 10 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
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.
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:
TrTerm a
field from the TrLambda
constructor of Kitten.Types.TrTerm
.TrLambda
is parsed and used in Kitten.Parse
.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.TrLambda
case of Kitten.Infer.infer
:
drop
.Kitten.Infer.local
should not be scoped, but only introduce a new local in the current frame.TrClosure
case of inferValue
to use scope
.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.
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?
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.
OK, I'm giving myself the deadline of 29th October
How’s it going? Is there anything I can help with?
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.
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.
The REPL currently supports semantics for binding locals to variable names:
In normal code, this would be accessible within functions or pushable directly onto the stack as desired. In the REPL, it is inaccessible:
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: