from .Parser import Parse from .Scanner import Scan def test_expr(scan,parse): x = """ input ⇒ expected output (in s-expr form) ⇒ None # projection/composition/application a+ ⇒ (prj + a) +- ⇒ (cmp + (prj -)) (+)- ⇒ (prj - +) +(-) ⇒ (+ -) a:b ⇒ (: a b) (a:)2 ⇒ (app (prj : a) 2) (-+:) ⇒ (cmp - (prj +:)) -+: ⇒ (cmp - (prj +:)) a::b ⇒ (:: a b) a:f/y ⇒ (: a (app (fld f) y)) 1 2+ ⇒ (prj + (vec 1 2)) 1 2+3 4 ⇒ (+ (vec 1 2) (vec 3 4)) 1 2+``a ⇒ (+ (vec 1 2) (vec ` `a)) a b 1 2 ⇒ (app a (app b (vec 1 2))) 1 2 a 3 4 ⇒ (app (vec 1 2) (app a (vec 3 4))) a+- ⇒ (cmp (prj + a) (prj -)) *a+- ⇒ (cmp * (cmp (prj + a) (prj -))) +-* ⇒ (cmp + (cmp - (prj *))) a+; ⇒ (seq (prj + a) NIL) (+-)/y ⇒ (app (fld (cmp + (prj -))) y) (2+)/y ⇒ (app (fld (prj + 2)) y) x(+-)/y ⇒ (app (fld (cmp + (prj -))) x y) x(+-*)/y ⇒ (app (fld (cmp + (cmp - (prj *)))) x y) x(2+)/y ⇒ (app (fld (prj + 2)) x y) () ⇒ (lst NIL) ()/y ⇒ (app (fld (lst NIL)) y) +/ ⇒ (fld +) (+/) ⇒ (fld +) (+)/y ⇒ (app (fld +) y) (+/)'y ⇒ (app (ech (fld +)) y) +//y ⇒ (app (fld (fld +)) y) 1-+/y ⇒ (- 1 (app (fld +) y)) (+/)/y ⇒ (app (fld (fld +)) y) x(+/)y ⇒ (app x (app (fld +) y)) (-a)*b ⇒ (* (- a) b) # lists (;) ⇒ (lst NIL NIL) (;b) ⇒ (lst NIL b) (a) ⇒ a (a)b ⇒ (app a b) (a;) ⇒ (lst a NIL) (a;;b) ⇒ (lst a NIL b) (a;b) ⇒ (lst a b) (f)/y ⇒ (app (fld f) y) *+/y ⇒ (* (app (fld +) y)) +/y ⇒ (app (fld +) y) f[x]/y ⇒ (app (fld (app f (prg x))) y) +[;;] ⇒ (+ (prg NIL NIL NIL)) +[;] ⇒ (+ (prg NIL NIL)) +[] ⇒ (+ (prg NIL)) +[x;y;z] ⇒ (+ (prg x y z)) +[x;y] ⇒ (+ (prg x y)) +[x] ⇒ (+ (prg x)) --a ⇒ (- (- a)) (2)-3 ⇒ (- 2 3) -(2)-3 ⇒ (- (- 2 3)) -(2) ⇒ (- 2) +- 1 ⇒ (+ (- 1)) +-1 ⇒ (+ -1) --4 ⇒ (- -4) 2-3 ⇒ (- 2 3) -2 - 3 ⇒ (- -2 3) -2- 3 ⇒ (- -2 3) -2 -3 ⇒ (vec -2 -3) 2 - 3 ⇒ (- 2 3) 2- 3 ⇒ (- 2 3) 2 -3 ⇒ (vec 2 -3) -a ⇒ (- a) ; ⇒ (seq NIL NIL) ;b ⇒ (seq NIL b) [] ⇒ (prg NIL) [x] ⇒ (prg x) a.b.c ⇒ (. a (. b c)) a.b - 1 ⇒ (- (. a b) 1) 1 - a.b ⇒ (- 1 (. a b)) a ⇒ a a(b) ⇒ (app a b) a++b ⇒ (+ a (+ b)) a+b ⇒ (+ a b) a+f[x] ⇒ (+ a (app f (prg x))) a-b ⇒ (- a b) a-b+c ⇒ (- a (+ b c)) a; ⇒ (seq a NIL) a b; ⇒ (seq (app a b) NIL) +b; ⇒ (seq (+ b) NIL) a;b;c ⇒ (seq a b c) a;;b ⇒ (seq a NIL b) a;b ⇒ (seq a b) a b ⇒ (app a b) a b c ⇒ (app a (app b c)) f//y ⇒ (app (fld (fld f)) y) f[;] ⇒ (app f (prg NIL NIL)) f[;y] ⇒ (app f (prg NIL y)) f[] ⇒ (app f (prg NIL)) f[()()] ⇒ (app f (prg (app (lst NIL) (lst NIL)))) f[(a)()] ⇒ (app f (prg (app a (lst NIL)))) f[()(a)] ⇒ (app f (prg (app (lst NIL) a))) f[x;;y] ⇒ (app f (prg x NIL y)) f[x;] ⇒ (app f (prg x NIL)) f[x;y] ⇒ (app f (prg x y)) f[x] ⇒ (app f (prg x)) x(+)/y ⇒ (app (fld +) x y) x(+/)//'y ⇒ (app (ech (fld (fld (fld +)))) x y) x(a f/)'y ⇒ (app (ech (app (fld f) a NIL)) x y) x(f)/y ⇒ (app (fld f) x y) x+/y ⇒ (app (fld +) x y) x/y ⇒ (app (fld x) y) x f//y ⇒ (app (fld (fld f)) x y) x f/y ⇒ (app (fld f) x y) x{f}/y ⇒ (app (fld (lam f)) x y) {()()} ⇒ (lam (app (lst NIL) (lst NIL))) {()} ⇒ (lam (lst NIL)) {(x)y} ⇒ (lam (app x y)) {[]()} ⇒ (lam (prg NIL) (lst NIL)) {[]a} ⇒ (lam (prg NIL) a) {[]a} ⇒ (lam (prg NIL) a) {[]} ⇒ (lam (prg NIL)) {[a];b} ⇒ (lam (prg a) NIL b) {[a]b} ⇒ (lam (prg a) b) {[a]} ⇒ (lam (prg a)) {a;b} ⇒ (lam a b) {a b} ⇒ (lam (app a b)) {f[x]} ⇒ (lam (app f (prg x))) {f}/y ⇒ (app (fld (lam f)) y) {x(y)} ⇒ (lam (app x y)) {a f[x]/b} ⇒ (lam (app (fld (app f (prg x))) a b)) {x/y} ⇒ (lam (app (fld x) y)) {x{y}} ⇒ (lam (app x (lam y))) {x} ⇒ (lam x) {x}y ⇒ (app (lam x) y) {{x}[y]} ⇒ (lam (app (lam x) (prg y))) {{}} ⇒ (lam (lam NIL)) {} ⇒ (lam NIL) """[1:-1].splitlines()[1:] red,end = '\033[91m','\033[0m' ok,total = 0,0 for i,o in (map(str.strip,a.split('⇒')) for a in x if not a.strip().startswith('#')): total += 1 c = ''#comment if '#' in o: o,c = o.split('#') try: o,x = o.strip(),parse(scan(i.strip()),0); ok += 1 except: print(f'Exception while parsing "{i}"'); continue if str(x)==o: continue wanted = f'{i} ⇒ {o}{red}{end}' actual = f'{"":<{len(i)}} {red}{x}{end}' m = max(len(actual),len(wanted)) print(f'{wanted:<{m}} ⌈expected⌉ {c}') print(f'{actual:<{m}} ⌊ {red}actual{end} ⌋','\n') def test_exception(scan,parse): x = """ a+: (a+:) ()) """[1:-1].splitlines() for i in map(str.strip,x): try: parse(scan(i)) raise SyntaxError(f"Should have raised SyntaxError, but didn't: {i}") except SyntaxError: continue def test_eval(scan,parse,evil): x = """ input ⇒ expected output (in s-expr form) 2 ⇒ 2:i 2.0 ⇒ 2.0:f 1,2 ⇒ [1, 2]:I 1,,2 ⇒ [1, 2]:I 1,,,2 ⇒ [1, [2]]:L ,1 2 ⇒ [[1, 2]]:L 1 2 ⇒ [1, 2]:I 1 2. ⇒ [1.0, 2.0]:F a:1 2 3 ⇒ [1, 2, 3]:I 4,a:1 2 3 ⇒ [4, 1, 2, 3]:I 4,a:1.0 2 3 ⇒ [4, 1.0, 2.0, 3.0]:L """[1:-1].splitlines()[1:] ok,total = 0,0 for i,o in (map(str.strip,a.split('⇒')) for a in x if not a.strip().startswith('#')): total += 1 c = '' if '#' in o: o,c = o.split('#') try: o,x = o.strip(),evil(parse(scan(i.strip()),0)) ok += 1 except Exception as e: print(f'Exception ({e}) evaluating "{i}"') continue if str(x)==o: continue print(f'{i} ⇒ {x} (actual)') print(f'{"expected:":>{len(i)}} {o}') # def test_all(scan,parse,evil): # print("test_expr:") # test_expr(scan,parse) # print("test_exception:") # test_exception(scan,parse) # print("test_eval:") # test_eval(scan,parse,evil)