import peforth

"""
Explanation: peforth magic command on jupyter notebook
peforth supports jupyter notebook magic command %f since v1.15 (released to Pypi on 2018.3.12) with both line magic and cell magic.
If you are running this jupyter notebook page online through mybinder.org then no installation is needed. 
If you would like to work on your computer, so you can save changes you made, then 
pip install peforth to install peforth and that's all, assume you already have jupyter notebook installed.
1. import peforth $^i$
peforth magics are unknown to jupyter notebook at first untill we import peforth.
End of explanation
"""


%f version .s

%f ." Hello World!" cr

"""
Explanation: 2. Hello World!
Here after, in any python code cell, a %f leading line is interpreted as a FORTH line, called line magic. The next cell is an example of the version command that shows peforth greeting message and leaves the version number on the data stack.
End of explanation
"""


# use %f line magic in a python code function definition,
def hi():
    %f ." Hello World!" cr

# believe it or not, it works!
hi()

"""
Explanation: The amazing thing here is that the %f line magic can be used in python code. . .
End of explanation
"""


%f __main__ :> hi .source

"""
Explanation: 3. line magic is compiled to a python statement
Now use peforth command .source to find out why this is possible . . .
End of explanation
"""



%%f Nothing allowed before %%f except white spaces; everything in this line after %%f is ignored.

\ Demonstrating the peforth interpret mode [for]..[next] loop

5 [for] t@ . space [next] cr

\ For experienced FORTH users
\ Where t@ is like the FORTH word r@ but it fetches TIB stack instead of the traditional 
\ FORTH return stack. Because TIB is the only resource that belongs to this interpreting 
\ life cycle alone.

"""
Explanation: The %f line magic is compiled into a python statement, that's why. Some more explanations given at the end of this page.
4. peforth %%f cell magic
A cell leading with a %%f (double %% instead of single % in line magic form) becomes a block of FORTH code.
End of explanation
"""


%%f
: star ." *" ;
: 2stars star star ;
: stars for star next ;
star cr 2stars cr 10 [for] 13 t@ - stars cr [next] 

"""
Explanation: Now use the [for] loop to print a pyramid:
End of explanation
"""


x = 123
%f x . cr

"""
Explanation: 5. peforth to access the main name space directly
Peforth and the Jupyter Notebook are of different name spaces, meaning that peforth can't see the x variable in the example below:
End of explanation
"""


%%f   Now we redefine the 'unknown' command (it does nothing by default)

: unknown // ( token -- thing y|n) Try to find the unknown token in __main__
  py> getattr(sys.modules['__main__'],pop(),"Ûnknôwn") 
  py> str(tos())=="Ûnknôwn" if drop false else true then ;
    
\ here after, when FORTH come accross an unknown token, instead of printing the
\ error message, it try to find the token in python __main__ module name space.

"""
Explanation: The reason why we choose FORTH is for its super flexibility. Now let's redefine the way peforth handles an unknown token, i.e. the x of the above example. Instead of alerting "Error! x unknown." we let it try to find the token in the Jupyter Notebook __main__ module object. 
Note: peforth v1.16 and newer version is required to play this trick. Since v1.23 the 'unknown' introduced below has become a built-in so we don't need the re-definition. Instead, use marker command '===' to forget it so the 'x' would be an 'unknown' again.
End of explanation
"""


y = 'abc'
%f y . cr
%f x . cr

"""
Explanation: now test again:
End of explanation
"""


# Run this cell to enter peforth console (REPL loop or command line interface)
# Note the Out[ ] of this cell, the `[*]` indicates that the command line interface
# is running. Play with it or copy-paste this line: 
#     "star cr 2stars cr 10 [for] 13 t@ - stars cr [next] exit"
# to try again the pyramid example above. 'exit' command to terminate.
peforth.ok()  

"""
Explanation: peforth seems know the 'x' and 'y' now while it doesn't. This trick is vary useful when we are studying and we can investigate things in FORTH way.
5. So where is the muggle FORTH that works as a REPL shell environment?
peforth.ok() is the peforth interpreter itself. Run peforth.ok() to shell a level of the FORTH interpreter and exit command to come back.
End of explanation
"""


peforth.dictate(" .' hello world!' cr ")  # Note the Out[ ] of this cell

"""
Explanation: 6. Cascading peforth exported functions
%f and %%f magics are actually performing the peforth.dictate('command lines') exported function, while peforth.ok() is the REPL loop of the same function. Try:
peforth.dictate(" .' hello world!' cr ")

that works exactly as we have tried at first.
End of explanation
"""


%%f
' star   \ get the word object, we defined 'star' above remember?
:> type  \ get 'type' attribute of the word object
. cr     \ show what we have got ... it is a 'colon' word, isn't it?

"""
Explanation: Observed from the above outputs, peforth.ok() and peforth.dictate() both return the peforth module object.  This means that we can cascade these functions. The next example sees the type of the 'star' command that we definded above:
End of explanation
"""


# Example of cascaded functions, to check a given FORTH word's type  

type_of_star = peforth.push('star').dictate("(') :> type").pop() # cascaded functions 
print(type_of_star)

"""
Explanation: It's correctly a 'colon' word. The next example in python code is actually doing the same thing as the above FORTH code:
End of explanation
"""


%f help (')

%f help :>         

"""
Explanation: Where (') and :&gt; are peforth words explained by help command as shown below. Function cascading is very useful for peforth to debug or to investigate your python target code. 
Peforth functions that can be called cascadedly are: peforth.ok(), peforth.dictate() , peforth.push() and peforth.execute().
End of explanation
"""


