pocketlang/tests/random/lisp_eval.pk
Thakee Nathees 6e91b66e69 else if change to elif again.
The primary purpose of this change is to disambiguate between
`else if` and `else \n if`.

Even though it's a breaking change, since it's at the very early
state we're allowed to make such breaking syntax change.

lang.write function moved to io and io.stdin, io.stdout, io.stderr
added for future streamed io operations

io.File read, write, open, close, getline, seek, tell implemented

str * int multiplication implemented
2022-05-24 15:31:36 +05:30

106 lines
2.2 KiB
Plaintext

## Evalivate a lisp like expression.
## - Only single digit numbers are allowed.
## - No space is allowed.
##
## (+(*23)(/9(-85))) is equivalent of
## (+ (* 2 3) (/ 9 (-8 5))) = 9
tests = {
"(+(*23)(/9(-85)))" : 9,
"(-(*33)(+5(-43)))" : 3,
"+(/6(+1(-65)))(-9(*42))" : 4,
"-(*(+2(*1(-54)))3)(+1(/88))" : 7
}
def main()
for expr in tests
r = eval(expr, 0); assert(r[1] != -1)
val = r[0]
assert(val == tests[expr])
end
print("ALL TESTS PASSED")
end
## -------------------------------------------------
## Return [value, index], if error index will be -1.
def eval(expr, ind)
c = expr[ind]; ind += 1
if c == '('
r = eval(expr, ind)
val = r[0]
ind = r[1]
if ind == -1 then return [null, -1] end
if ind == expr.length then
print("Invalid expression.")
return [null, -1]
end
assert(ind < expr.length)
c = expr[ind]; ind += 1
if c != ')'
print("Expected ')'"); return [null, -1]
end
return [val, ind]
elif c == '+'
r = binary_op(expr, ind)
if not r[0] then return [null, -1] end
return [r[1] + r[2], r[3]]
elif c == '-'
r = binary_op(expr, ind)
if not r[0] then return [null, -1] end
return [r[1] - r[2], r[3]]
elif c == '*'
r = binary_op(expr, ind)
if not r[0] then return [null, -1] end
return [r[1] * r[2], r[3]]
elif c == '/'
r = binary_op(expr, ind)
if not r[0] then return [null, -1] end
return [r[1] / r[2], r[3]]
elif isnum(c)
val = ord(c) - ord('0')
assert(0 <= val and val < 10)
return [val, ind]
else
print("Uexpected token:", c)
return [null, -1]
end ## switch(c)
end
## return [success, v1, v2, index]
def binary_op(expr, ind)
r = eval(expr, ind)
v1 = r[0]; ind = r[1]
if ind == -1 then return [false, null, null, -1] end
r = eval(expr, ind)
v2 = r[0]; ind = r[1]
if ind == -1 then return [false, null, null, -1] end
return [true, v1, v2, ind]
end
## Return true if c in numeric.
def isnum(c)
k = ord(c) - ord('0')
## TODO: k in 0..10
return (0 <= k and k < 10)
end
## -------------------------------------------------
## if __name__ == '__main__' ;)
main()