146 lines
3.8 KiB
Nim
146 lines
3.8 KiB
Nim
#[
|
|
|
|
Copyright © 2021 Simon Forman
|
|
|
|
This file is part of Bliss
|
|
|
|
Bliss is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Bliss is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Bliss. If not see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
]#
|
|
import rdstdin, bigints, fp, printer, reader, types, joylib, utils, defs
|
|
|
|
|
|
# Handle Ctrl-C by raising an IOError to break out of the mainloop
|
|
# without waiting for the user to press enter.
|
|
proc ctrlc() {.noconv.} =
|
|
raise newException(IOError, "Got Ctrl-C, bye!")
|
|
|
|
setControlCHook(ctrlc)
|
|
|
|
|
|
proc joy_eval(sym: string, state: var JoyState): JoyState =
|
|
case sym
|
|
|
|
# Integer Math
|
|
|
|
of "+": push_int(pop_int(state) + pop_int(state), state)
|
|
of "*": push_int(pop_int(state) * pop_int(state), state)
|
|
of "-":
|
|
let tos = pop_int(state)
|
|
push_int(pop_int(state) - tos, state)
|
|
of "/":
|
|
let tos = pop_int(state)
|
|
push_int(pop_int(state) div tos, state)
|
|
of "%":
|
|
let tos = pop_int(state)
|
|
push_int(pop_int(state) mod tos, state)
|
|
|
|
# Comparision
|
|
|
|
of "<":
|
|
let tos = pop_int(state)
|
|
let second = pop_int(state)
|
|
push_bool(second < tos, state)
|
|
of ">":
|
|
let tos = pop_int(state)
|
|
let second = pop_int(state)
|
|
push_bool(second > tos, state)
|
|
of "<=":
|
|
let tos = pop_int(state)
|
|
let second = pop_int(state)
|
|
push_bool(second <= tos, state)
|
|
of ">=":
|
|
let tos = pop_int(state)
|
|
let second = pop_int(state)
|
|
push_bool(second >= tos, state)
|
|
of "=":
|
|
let tos = pop_int(state)
|
|
let second = pop_int(state)
|
|
push_bool(second == tos, state)
|
|
of "<>":
|
|
let tos = pop_int(state)
|
|
let second = pop_int(state)
|
|
push_bool(second != tos, state)
|
|
|
|
# Boolean logic
|
|
|
|
of "and": # Have to pop, Nim `and` short-circuits.
|
|
let tos = pop_bool(state)
|
|
let second = pop_bool(state)
|
|
push_bool(tos and second, state)
|
|
of "or": # Have to pop, Nim `or` short-circuits.
|
|
let tos = pop_bool(state)
|
|
let second = pop_bool(state)
|
|
push_bool(tos or second, state)
|
|
|
|
# Built-in Functions and Combinators
|
|
|
|
of "bool": truthy(state)
|
|
of "branch": branch(state)
|
|
of "clear": clear(state)
|
|
of "concat": concat(state)
|
|
of "cons": cons(state)
|
|
of "dip": dip(state)
|
|
of "dup": dup(state)
|
|
of "first": first(state)
|
|
of "i": i(state)
|
|
of "loop": loop(state)
|
|
of "pop": pop(state)
|
|
of "rest": rest(state)
|
|
of "stack": stack(state)
|
|
of "swaack": swaack(state)
|
|
of "swap": swap(state)
|
|
|
|
else:
|
|
let def = dictionary.get(sym)
|
|
if def.isEmpty:
|
|
raise newException(ValueError, "Unknown: " & sym)
|
|
state.expression = def.get() ++ state.expression
|
|
state
|
|
|
|
|
|
proc joy(state: var JoyState) =
|
|
while not state.expression.isEmpty:
|
|
# echo print_stack(state.stack), " . ", print_expression(state.expression)
|
|
let term = state.expression.head
|
|
state.expression = state.expression.tail
|
|
case term.kind
|
|
of joyInt, joyList, joyTrue, joyFalse:
|
|
state.stack = term ^^ state.stack
|
|
of joyAtom:
|
|
state = joy_eval(term.atomVal, state)
|
|
of joyParseError:
|
|
echo term.errorMessage
|
|
break
|
|
|
|
|
|
|
|
var state0: JoyState = (stack: Nil[JoyType](), expression: Nil[JoyType]())
|
|
var state: JoyState
|
|
while true:
|
|
try:
|
|
let e = read_str(readLineFromStdin("joy? "))
|
|
state = (stack: state0.stack, expression: e)
|
|
except IOError:
|
|
break
|
|
try:
|
|
joy(state)
|
|
except:
|
|
echo getCurrentExceptionMsg()
|
|
echo print_stack(state0.stack)
|
|
continue
|
|
echo print_stack(state.stack)
|
|
state0 = state
|