Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jkleiser committed May 30, 2016
1 parent 70ade1d commit 6032842
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# toy-forth-in-pony
A rudimentary Forth written in Pony
This will not teach you much about how to implement real Forth. The most interesting part is probably
how one can keep references to Pony functions (the Forth words) in a Map (the `_dict`).
Without the crucial help I got from Chris and Joe, I would have had problems solving that part.

I more or less ported the Scala code found at [/~https://github.com/joneshf/forla](/~https://github.com/joneshf/forla).

The readline part is based on the Pony [readline example](/~https://github.com/ponylang/ponyc/tree/master/examples/readline).

There may of course be things in my Pony code that could be improved. Feel free to file an issue.
78 changes: 78 additions & 0 deletions forthrepl/repl.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use "collections"
use "promises"
use "term"

type PartialFunRef is ({ref() ?} ref)
type FunBox is ({box()} ref)
type AnyMethod is (PartialFunRef | FunBox)

class ForthRepl is ReadlineNotify
let _env: Env
let _dict: Map[String, AnyMethod] = _dict.create()
let _stack: Array[I64] = _stack.create()
var _i: U64 = 0

new create(env: Env) =>
_env = env
_dict("+") = this~_add()
_dict("-") = this~_sub()
_dict("*") = this~_mul()
_dict("/") = this~_div()
_dict(".") = this~_print()

fun ref apply(line: String, prompt: Promise[String]) =>
if line == "bye" then
prompt.reject()
else
_interpret(line)
_i = _i + 1
prompt(_i.string() + " > ")
end

fun ref _interpret(line: String) =>
for each_token in line.split(" ").values() do
try
_execute(_dict(each_token))
else
_number(each_token)
end
end

fun ref _execute(func: AnyMethod) =>
match func
| let fun_ref: PartialFunRef => try fun_ref() else _env.out.print("Stack underflow") end
| let fun_box: FunBox => fun_box()
end

fun ref _number(token: String) =>
try
_stack.push(token.i64())
else
_env.out.print(token + " ?")
end

fun ref _add() ? => _stack.push(_stack.pop() + _stack.pop())
fun ref _sub() ? => _stack.push(_stack.pop() - _stack.pop())
fun ref _mul() ? => _stack.push(_stack.pop() * _stack.pop())
fun ref _div() ? => _stack.push(_stack.pop() / _stack.pop())

fun _print() =>
for n in _stack.reverse().values() do
_env.out.write(n.string() + " ")
end
_env.out.write("\n")

actor Main
new create(env: Env) =>
env.out.print("Use 'bye' to exit.")

let term = ANSITerm(Readline(recover ForthRepl(env) end, env.out), env.input)
term.prompt("0 > ")

let notify = object iso
let term: ANSITerm = term
fun ref apply(data: Array[U8] iso) => term(consume data)
fun ref dispose() => term.dispose()
end

env.input(consume notify)

0 comments on commit 6032842

Please sign in to comment.