Skip to content

Commit

Permalink
local imports and more types
Browse files Browse the repository at this point in the history
  • Loading branch information
hoosierEE committed Jul 24, 2024
1 parent 6b20d70 commit 7a8579d
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 44 deletions.
53 changes: 26 additions & 27 deletions README.org
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
* Element
Combining the most delightful parts of K with good ideas from functional and mainstream programming languages.
/A data-oriented language for parallel hardware./

- What: a close descendant of [[https://en.wikipedia.org/wiki/K_(programming_language)][K]] (and [[https://codeberg.org/anaseto/goal/src/branch/master][Goal]]) with implicit multi-core/GPU acceleration.
- Why: fun?
- How: Python prototype, then "for real" in CUDA/C++ (or perhaps [[https://ziglang.org/download/0.11.0/release-notes.html#GPGPU][Zig]] or [[https://pkg.odin-lang.org/vendor/OpenGL/][Odin]]?)
- Dream: a fast DSL for data-intensive kernels embedded in a distributed system environment like [[https://gleam.run/][Gleam]].
- what: syntax and semantics based on [[https://en.wikipedia.org/wiki/K_(programming_language)][K]] (and [[https://codeberg.org/anaseto/goal/src/branch/master][Goal]]) with implicit multi-core and GPU acceleration
- why: fun?
- how: first build a Python prototype, then implement in CUDA/C++ (or perhaps [[https://ziglang.org/download/0.11.0/release-notes.html#GPGPU][Zig]] or [[https://pkg.odin-lang.org/vendor/OpenGL/][Odin]]?)
- maybe one day: a fast DSL for data-intensive kernels embedded in a distributed system environment like [[https://gleam.run/][Gleam]]

keywords: "array-oriented" "interpreted" "functional" "automatic memory management"

** types
- base types - int, float, string, symbol
- builtin types - int, float, string, symbol
- compound types
- list-like
- tensor - same type, N dimensional
Expand Down Expand Up @@ -84,20 +86,18 @@ Planned features:
- short-circuiting =and= and =or= keywords also from [[https://codeberg.org/anaseto/goal/src/branch/master][goal]]
- =x:y= assign (immutable) variable
- =x::y= assign (mutable) variable
- Transitive mutability - parts of mutable structures are mutable, parts of immutable structures are immutable.
- No modified assignment operators. Use =a::a+1= instead of =a+:1=.
Meanwhile, verb-plus-colon still invokes the unary version of that verb, so =a-:b= is =a(-b)=.
- No partial assignment to containers. If you assign the name =a= with =a::1 2 3=, then =a[0]::99= is invalid. Use =@= (amend) instead, and re-assign the whole container: =a::@[a;0;99]=. To improve performance, the implementation is free to reuse the original memory for =a= instead of making a copy.
- Lists and function arguments evaluate left-to-right, top-to-bottom.
Meanwhile, verb-then-colon is still "force unary", so =a-:b= is =a(-b)=.
- In Element, =a;b= is always two separate expressions evaluated left to right regardless of context.
This is most noticeable when you have assignments in lists or function calls.
For example, =f[a+b;a:1;b:2]= or =(a+b;a:1;b:2)= are valid in K but not in Element.
In Element, =a;b= always parses as two separate expressions evaluated left to right regardless of being wrapped in any kind of parentheses.
Alternatives: use =a:1;b:2;(a+b;a;b)= or =2_(a:1;b:2;a+b;a;b)=.
# - Dictionary literals are a sequence of assignments enclosed in =[]= similar to [[https://kparc.io/k/][Shakti]]: =[a:2+q;b:5]= ⇔ =[`a:2;`b:5]= ⇔ =(`a;`b)!(2;5)= ⇔ =`a`b!2 5=
# - =[a:1;42]= is not a dict literal because =42= is not an assignment
# -

Aspirational features:
- module system: =require x=, =provide x=
- =\cd= etc. provided by REPL, not runtime
- REPL-specific:
- =\cd some/other/directory=
- =delete= function to forget a defined variable

* Install
Compile for GPU with NVIDIA's =nvcc= compiler:
Expand Down Expand Up @@ -126,13 +126,15 @@ Some [[https://github.com/doctest/doctest/tree/master/doc/markdown#reference][do
- [X] lex/scan/tokenize
- [X] parse
- [-] semantic analysis
- [ ] verbs
- [ ] rank polymorphic verbs
- [ ] iterators
- [ ] type checking
- [-] type inference
- [X] (int|float|string|symbol)
- [X] vec of (int|float|string|symbol)
- [X] primitive types (int|float|string|symbol)
- [X] vec
- [X] list
- [ ] expression
- [ ] lambda
- [ ] tensor
- [ ] dict
- [ ] table
Expand All @@ -143,18 +145,15 @@ Some [[https://github.com/doctest/doctest/tree/master/doc/markdown#reference][do
- [X] projection ⇒ lambda
- [ ] composition ⇒ lambda
- [ ] errors (mutable, rank, unused, ...)
- [-] codegen
- [X] tree-walk interpreter
- [-] code generation
- [ ] tree-walk interpreter
- [X] simple arithmetic =1+2=
- [X] array arithmetic =1 2+3 4=
- [ ] iterators =+/1 2 3=
- [ ] structural functions =3#"hi""world"=
- [-] hardware accelerated implementation
- [X] lex/scan/tokenize
- [ ] parse
- [ ] semantic analysis
- [ ] optimization
- [ ] codegen
- [ ] structural functions =4 3#!5=
- [ ] hardware accelerated implementation
- [ ] full test suite compatibility with prototype
- [ ] benchmarks showing it is faster
- [ ] stable release(s)
- [ ] pick a version numbering system (and stick to it)
- [ ] formal grammar
Expand Down
6 changes: 3 additions & 3 deletions prototype/Eval.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'''Eval.py - interpret a parsed expression'''
Expr = float|list|str
class Sym(str):pass
class Name(str):pass
type Sym = str
type Name = str
type Expr = float|list|str|Sym|Name

def ty1(x:str) -> type:
if x[0] in '`"': return (str,Sym)[x[0]=='`']
Expand Down
7 changes: 4 additions & 3 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,VERBM,WHITESPACE
from .Ast import Ast
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 Down Expand Up @@ -86,7 +86,8 @@ def loop(i=0) -> int|None:#return index of error-causing token (if any), else No
k = Ast(c,d.pop())#bind adverb to whatever
while n in ADVERB: k,i,n = Ast(n,k),i+1,nn(i)
if s:
if str(s[-1].name)[0] in VERB+OPAREN: s.append(Op(k,1))
debug('adverb')
if str(s[-1].name)[0] in ASSIGN+VERB+OPAREN: s.append(Op(k,1))
else: d.append(Ast(s.pop().name)); s.append(Op(k,2))
else: s.append(Op(k,1))
if s[-1].arity==2: pad(n)
Expand Down
2 changes: 1 addition & 1 deletion prototype/Scanner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import List,Tuple
from Builtin import BS,VERB,LF,WHITESPACE
from .Builtin import BS,VERB,LF,WHITESPACE
def Scan(expr:str)->List[str|Tuple[str]]:
'''
Tokenizes a string.
Expand Down
15 changes: 9 additions & 6 deletions prototype/Semantic.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from Ast import Ast
from Builtin import ASSIGN,VERB
from .Ast import Ast
from .Builtin import ASSIGN,VERB
from dataclasses import dataclass

type Sym = str
Expand All @@ -10,22 +10,25 @@ def ty(x:str) -> type:
if x[0] in '`"': return (str,Sym)[x[0]=='`']
if x.replace('.','').replace('-','').isnumeric(): return float if '.' in x else int
if x=='NIL': return type(None)
if x in ASSIGN+VERB: return Builtin
if x[0] in ASSIGN+VERB: return Builtin
return Name

@dataclass
class Val:
v:Ast
t:type
def __repr__(s): return f'{s.v}:{repr(s.t)[8:-2]}'
def __repr__(s):
r = repr(s.t)
st = r[8:-2] if '<' in r else r
return f'{s.v}:{st}'

def infer(a:Ast) -> Val:
'''infer types from literal expressions'''
match (a.node,a.children):
case ('vec',b): return Val(a,ty(b[0].node))
case ('{',p,b): return Ast(a.node,*map(infer,a.children))
case ('[',()): return Val(a.node,'NIL')
case (node,()): return Val(node,ty(node))
case (node,()): return Val(node,ty(node[0]))
case (node,children): return Ast(a.node,*map(infer,children))
case _: raise SyntaxError(f'unmatched: {a}')

Expand Down Expand Up @@ -56,5 +59,5 @@ def formalize(a:Ast) -> Ast:
return Ast(a.node, Ast('[',*(map(Ast,filter(str,xyz)))), *map(formalize,a.children))#insert (prg x y z)
return Ast(a.node, *map(formalize,a.children))

def analyze(a:Ast) -> Ast|Val:
def Sema(a:Ast) -> Ast|Val:
return infer(formalize(lam_from_prj(a)))
9 changes: 5 additions & 4 deletions prototype/Test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from Eval import *
from Parser import *
from Scanner import *
from Semantic import *
from .Eval import *
from .Parser import *
from .Scanner import *
from .Semantic import *
def test_expr(scan,parse):
x = """
input ⇒ expected output (in s-expr form)
Expand All @@ -16,6 +16,7 @@ def test_expr(scan,parse):
(-+:) ⇒ (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))
Expand Down

0 comments on commit 7a8579d

Please sign in to comment.