Skip to content

Commit

Permalink
about to simplify
Browse files Browse the repository at this point in the history
  • Loading branch information
hoosierEE committed May 10, 2024
1 parent 97764d0 commit a3f2e03
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 34 deletions.
2 changes: 2 additions & 0 deletions prototype/Builtin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
ADVERB = "'","/","\\"
ANDOR = "and","or"
ASSIGN = ":","::"
BS = "\\"
CPAREN = ')','}',']'
ENDEXP = '',';','\n'
LF = "\n"
OPAREN = '(','{','['
VERB = tuple("~!@#$%^&*-_=+|,.<>?")
VERBM = tuple(x+':' for x in VERB)
WHITESPACE = " ","\t"
41 changes: 22 additions & 19 deletions prototype/Eval.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
# TODO: simplify (prototype only)
# get rid of integers
# don't save type info; instead compute it on-demand
# use plain Python values instead of Val class
from Ast import Ast
from Builtin import ASSIGN,VERB
from Semantic import lift_prj,formalize
class Sym(str):pass
class Name(str):pass
#Vectors; strand/list notation, or construct with ops:
#1 2 3 ⇒ [1, 2, 3]⊂I
#1 2.0 ⇒ [1.0, 2.0]⊂F
#(1.0;2.0) ⇒ [1.0, 2.0]⊂F
#1,2 ⇒ [1, 2]⊂I
#List types
#any type, any shape ("ab";1)⊂L
#1 type, any shape (1;2;3)⊂LI (0;((1;2);3);4)⊂LI
#tensor (1 type, defined shape): ((1;2;3);(4;5;6))⊂I(2;3)
#Dict types
#generic {a:1;b:("hi";"world")}⊂D
#unitype {a:1;b:(2;3)}⊂DI {a:1.0;b:(2.0;3.0)}⊂DF
#table {a:(1;2);b:(3;4)}⊂TI
Ty = dict(zip((str,Sym,Name,int,float,dict,list),'csnifDL'))
Yt = {b:a for a,b in Ty.items()}
class Val:
Expand Down Expand Up @@ -48,16 +39,29 @@ def v1(op:str,val:Val):

def v2val(op:str,a:Val,b:Val) -> Val:
match (op,a.t,b.t):
#TODO: handle numeric types better, 'min' is brittle
case ['-','f'|'i','f'|'i']: return Val(min(a.t,b.t),a.v-b.v)
case ['-','f'|'i','F'|'I']: return Val(min(a.t,b.t).upper(),[a.v-x for x in b.v])
case ['-','F'|'I','f'|'i']: return Val(min(a.t,b.t).upper(),[x-b.v for x in a.v])
case ['-','F'|'I','F'|'I']: return Val(min(a.t,b.t).upper(),[x-y for x,y in zip(a.v,b.v)])
case [',','f'|'i','f'|'i']: return Val(min(a.t,b.t).upper(),[a.v,b.v])
case [',','F'|'I','f'|'i']: return Val(min(a.t,b.t).upper(),[*a.v,b.v])
case [',','f'|'i','F'|'I']: return Val(min(a.t,b.t).upper(),[a.v,*b.v])

# case [',','f'|'i','f'|'i']: return Val(min(a.t,b.t).upper(),[a.v,b.v])
# case [',','F'|'I','f'|'i']: return Val(min(a.t,b.t),[*a.v,b.v])
# case [',','f'|'i','F'|'I']: return Val(min(a.t,b.t),[a.v,*b.v])
case [',',t,u] if t==u and t.islower(): return Val(t.upper(),[a.v,b.v])
case [',',t,u] if t==u and t.isupper(): return Val(t,[*a.v,*b.v])
case [',',t,u] if t.isupper() and u.islower(): return Val('L',[*a.v,b.v])
case [',',t,u] if t.islower() and u.isupper(): return Val('L',[*a.v,b.v])
case [',',t,u]: return Val('L',[*a.v,*b.v])

# case [',',t,u]:
# if hasattr(a.v,'__len__') and hasattr(b.v,'__len__'): return Val('L',[*a.v,*b.v])
# if hasattr(a.v,'__len__'): return Val('L',[*a.v,b.v])
# if hasattr(b.v,'__len__'): return Val('L',[a.v,*b.v])
# return Val(min(t,u),[a.v,b.v])
case ['@','L','i']: return Val(Ty[type(r:=a.v[b.v])],r)#TODO: outdex
case ['@',t,'i'] if t.isupper(): return Val(Ty[type(r:=a.v[b.v])],r)#TODO: outdex
case _: raise RuntimeError('nyi')
case _: raise RuntimeError(f'nyi: {op} {a} {b}')

def v2(op:str,a,b):
if type(a)==type(b)==Val: return v2val(op,a,b)
Expand All @@ -66,8 +70,7 @@ def v2(op:str,a,b):
def evl(x:Ast,e=None) -> Val:
e = e or {}
x = formalize(lift_prj(x))
print(x)
return Eval(e,formalize(lift_prj(x)))
return Eval(e,x)

def Eval(e,x) -> Val:
if type(x)==Val: return x
Expand Down
20 changes: 12 additions & 8 deletions prototype/Parser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from Ast import Ast
from Builtin import ADVERB,ASSIGN,CPAREN,ENDEXP,LF,OPAREN,VERB,WHITESPACE
from Builtin import ADVERB,ASSIGN,CPAREN,ENDEXP,LF,OPAREN,VERB,VERBM,WHITESPACE
import collections as C
NIL = Ast('NIL')
Op = C.namedtuple('Op','name arity')
Expand All @@ -8,6 +8,9 @@ def _Parse(t:list,verbose:int)->Ast:
if not t: return
z,b,s,d = len(t),[],[],[]
noun = lambda x:type(x)==tuple or type(x)==str and x.replace('.','').replace('-','').isalnum()
# def noun(x:str) -> bool:
# return type(x)==tuple or type(x)==str and x.replace('.','').replace('-','').isalnum()

def debug(*args):#optional logging
if verbose<1: return
R = lambda x:'LF' if x==LF else str(x)
Expand All @@ -27,7 +30,8 @@ def rt(x,arity):#(r)educe (t)op of stack based on x's arity
if x in ENDEXP:
if len(k)>1 and k[1].node==x: k = [k[0],*k[1].children]
elif len(k)>0 and k[0].node==x: k = [*k[0].children,*k[1:]]
if noun(x): d.append(Ast('app',Ast(x),*k))
# if x in ANDOR: d.append(Ast(x,*k))
if noun(x): d.append(Ast('app',Ast(x),*k))
elif type(x)==Ast and k: d.append(Ast('app',x,*k))
else: d.append(Ast(x,*k))
debug('rt',x,k)
Expand Down Expand Up @@ -62,9 +66,9 @@ def loop(i=0) -> int|None:#return error token index or None
else: break
elif c in ADVERB: x = s.pop(); s.append(Op(Ast(c,Ast(x.name)),x.arity)); x.arity==2 and pad(n)
elif noun(c) or c[0] in '`"': d.append(Ast(c)); break
elif c[0] in VERB and n in CPAREN+ENDEXP:
elif c in VERB+VERBM and n in CPAREN+ENDEXP:
d.append(Ast(c)) if s and s[-1].name in OPAREN else rq(Ast('prj',Ast(c))); break
elif c[0] in VERB and n in ADVERB: d.append(Ast(c)); break
elif c in VERB+VERBM and n in ADVERB: d.append(Ast(c)); break
else: s.append(Op(c,1))

while True:#binary
Expand All @@ -91,10 +95,10 @@ def loop(i=0) -> int|None:#return error token index or None
elif c in ASSIGN:
if n in CPAREN+ENDEXP: rq(Ast('prj',Ast(c),d.pop())); continue
else: s.append(Op(c,2))
elif c[0] in VERB:
if c.endswith(':'):
if n in CPAREN+ENDEXP: raise SyntaxError(err(i,"can't project a prefix op"))
else: s.append(Op(c,1)); break
elif c in VERBM:
if n in CPAREN+ENDEXP: raise SyntaxError(err(i,"can't project a prefix op"))
else: s.append(Op(c,1)); break
elif c in VERB:
if n in CPAREN+ENDEXP: rq(Ast('prj',Ast(c),d.pop())); continue
else: s.append(Op(c,2))
else:
Expand Down
38 changes: 31 additions & 7 deletions prototype/Unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def test_expr(scan,parse):
+(-) ⇒ (+ -)
a:b ⇒ (: a b)
(a:)2 ⇒ (app (prj : a) 2)
a+: ⇒ None
(-+:) ⇒ (cmp - (prj +:))
-+: ⇒ (cmp - (prj +:))
a::b ⇒ (:: a b)
Expand Down Expand Up @@ -151,10 +150,22 @@ def test_expr(scan,parse):
m = max(len(actual),len(wanted))
print(f'{wanted:<{m}} ⌈expected⌉ {c}')
print(f'{actual:<{m}}{red}actual{end} ⌋','\n')
print(f'{ok} of {total} passed')


def test_eval(scan,parse,_eval):
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
Expand All @@ -166,16 +177,29 @@ def test_eval(scan,parse,_eval):
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]:L
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(),_eval(parse(scan(i.strip()),0)); ok += 1
except: print(f'Exception evaluating "{i}"'); continue
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('expected:',o)
print(f'{"expected:":>{len(i)}} {o}')


def test(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)

0 comments on commit a3f2e03

Please sign in to comment.