Initial deeply busted Lilith state for LangJam

This commit is contained in:
Reid 'arrdem' McKenzie 2021-08-20 23:16:59 -06:00
parent 2b101bf02c
commit 43bbcda050
7 changed files with 270 additions and 0 deletions

9
projects/lilith/BUILD Normal file
View file

@ -0,0 +1,9 @@
py_project(
name = "lilith",
lib_deps = [
],
test_deps = [
py_requirement("hypothesis"),
]
)

81
projects/lilith/README.md Normal file
View file

@ -0,0 +1,81 @@
# Lilith
> The theme of the jam is "first-class comments".
```c
// foo bar baz
```
``` clojure
; text that the parser throws away
(def <name> <value>)
(def ^{:doc "foo bar baz"} <name> <value>)
```
``` python
"""modules have __doc__ as a property defined by the FIRST heredoc-string in the file"""
def foo(a, b):
"""Adds a and b.
>>> foo(1, 2)
3
"""
return a + b
```
``` clojure
(defn foo [a b]
"Adds a and b
>>> (foo 1 2)
=> 3
"
(+ a b))
```
- Object code
- .... Other media?
``` clojure
(defn foo [a b]
(!doc "")
(!doctest "")
(!test "")
(!impl
(+ a b)))
```
``` clojure
(defn foo [a b]
"---
doc: |
Adds a and b
---
doctest:
- in: (foo 1 2)
out: 3
"
)
```
``` org
#+TITLE: foo
* my bullet
#+BEGIN_SRC clojure
(defn foo [a b] (+ a b))
#+END_SRC
```
`org-babel` `org-babel-tagle`
``` clojure
(defn foo [] ..)
```
####################################################################################################

20
projects/lilith/setup.py Normal file
View file

@ -0,0 +1,20 @@
from setuptools import setup
setup(
name="arrdem.lilith",
# Package metadata
version="0.0.0",
license="MIT",
# Package setup
package_dir={"": "src/python"},
packages=[
"lilith",
],
install_requires=[
"lark",
],
test_requires=[
"pytest",
"hypothesis",
],
)

View file

@ -0,0 +1,47 @@
!defscope[designdoc]
!scope[designdoc]
!def[pitch]
!frag[lang: md]
# The Lilith Pitch
Code is more than .. just code for the compiler.
We write lots of artifacts related to our software
- Design document
- Formatted API listing
- Formatted book which is MORE than just the API / source listing
- A spec? OpenAPI example
- Doctests? / inline test cases
Theory - most of your "program" isn't code.
idea: the parser is going to IGNORE stuff by default.
Let's build an M-expression syntax with support for multiple co-equal languages and fragments/scopes with a meta-syntax allowing for references between them and consuming fragment-notation-defined blocks? (FIXME: better word?)
!def[sytnax]
!frag[lang: md]
\![] bang-brackets is a meta-syntactic directive used both by the lil tangler and the lil object language.
Programs consist of many fragments, which can reference each-other and from which executable framents are woven.
Fragments define interpretations and scopes.
Interpretations control sub-languages, the bang-bracket notation is more of a meta-language than a target language.
Interpretation is defined by the `lang:` key of a bang-bracket.
FIXME: how to define more langs?
FIXME: how do scopes get defined?
\!defscope[name: <>]
FIXME: we need bare words, we need strings
FIXME: We need the object language
!def[main]
!frag[lang: lil]
; is importing a bang-operation?
import[tagle]
print[tangle[pitch, syntax]]

View file

@ -0,0 +1,84 @@
"""
Variously poor parsing for Lilith.
"""
import typing as t
import re
import lark
class Block(t.NamedTuple):
tag: str
args: list
kwargs: list
body_lines: list
@property
def body(self):
return "\n".join(self.body_lines)
class TreeToTuples(lark.Transformer):
def kwargs(self, args):
d = {}
key, val = args[0:2]
if len(args) == 3:
d.update(args[2])
d[key.value] = val.value
return d
def args(self, args):
_args = [args[0].value]
if len(args) == 2:
_args = _args + args[1]
return _args
def header(self, parse_args):
print("Header", parse_args)
tag = None
args = None
kwargs = None
body = []
iargs = iter(parse_args[1])
tag = parse_args[0]
v = next(iargs, None)
if isinstance(v, list):
args = v
v = next(iargs, None)
if isinstance(v, dict):
kwargs = v
return Block(tag, args, kwargs, body)
block_grammar = lark.Lark("""
%import common.WORD
%import common.WS
%ignore WS
?start: header
args: WORD ("," args)?
kwargs: WORD ":" WORD ("," kwargs)?
arguments: args "," kwargs | args | kwargs
header: "!" WORD "[" arguments? "]"
""",
parser='lalr',
transformer=TreeToTuples())
def shotgun_parse(buff: str) -> t.List[object]:
def _parse():
block = None
for line in buff.splitlines():
if line.startswith("!"):
if block:
yield block
block = [line]
else:
block.append(line)
if block:
yield block
return list(_parse())

View file

@ -0,0 +1,3 @@
"""
Pytest fixtures.
"""

View file

@ -0,0 +1,26 @@
"""tests covering the Lilith parser."""
from lilith.parser import block_grammar, Block
import pytest
@pytest.mark.parametrize('example, result', [
('!def[syntax]',
Block('def', ['syntax'], None, [])),
('!frag[lang: md]',
Block('frag', None, {'lang': 'md'}, [])),
('!frag[foo, lang: md]',
Block('frag', ['foo'], {'lang': 'md'}, [])),
])
def test_parse_header(example, result):
assert block_grammar.parse(example) == result
(
"""!def[designdoc]
!frag[lang: md]
# Designdoc
A design document""",
None
)