Compare commits
20 Commits
rlp2core
...
named-core
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb3f73836c | ||
|
|
eeeac9cc85 | ||
|
|
4f39dd36f1 | ||
|
|
4c99e44c04 | ||
|
|
170e4e36ae | ||
|
|
d52a366c1b | ||
|
|
0025d33069 | ||
|
|
7c474cc064 | ||
|
|
fbef645746 | ||
|
|
c8199a9dd1 | ||
|
|
3d45e12676 | ||
|
|
22b5b47795 | ||
|
|
cefdf6ffae | ||
|
|
e3b18c8915 | ||
|
|
692d22afb9 | ||
|
|
c146e1c450 | ||
|
|
5a659d22dd | ||
|
|
1a881399ab | ||
|
|
257d02da87 | ||
|
|
f47f325e34 |
17
CHANGELOG.md
Normal file
17
CHANGELOG.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# unreleased
|
||||||
|
|
||||||
|
* New tag syntax:
|
||||||
|
```hs
|
||||||
|
case x of
|
||||||
|
{ 1 -> something
|
||||||
|
; 2 -> another
|
||||||
|
}
|
||||||
|
```
|
||||||
|
is now written as
|
||||||
|
```hs
|
||||||
|
case x of
|
||||||
|
{ <1> -> something
|
||||||
|
; <2> -> another
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
@@ -8,8 +8,8 @@ CABAL_BUILD = dist-newstyle/build/x86_64-osx/ghc-9.6.2/rlp-0.1.0.0/build
|
|||||||
|
|
||||||
all: parsers lexers
|
all: parsers lexers
|
||||||
|
|
||||||
parsers: $(CABAL_BUILD)/Rlp/Parse.hs
|
parsers: $(CABAL_BUILD)/Rlp/Parse.hs $(CABAL_BUILD)/Core/Parse.hs
|
||||||
lexers: $(CABAL_BUILD)/Rlp/Lex.hs
|
lexers: $(CABAL_BUILD)/Rlp/Lex.hs $(CABAL_BUILD)/Core/Lex.hs
|
||||||
|
|
||||||
$(CABAL_BUILD)/Rlp/Parse.hs: $(SRC)/Rlp/Parse.y
|
$(CABAL_BUILD)/Rlp/Parse.hs: $(SRC)/Rlp/Parse.y
|
||||||
$(HAPPY) $(HAPPY_OPTS) $< -o $@
|
$(HAPPY) $(HAPPY_OPTS) $< -o $@
|
||||||
@@ -17,3 +17,9 @@ $(CABAL_BUILD)/Rlp/Parse.hs: $(SRC)/Rlp/Parse.y
|
|||||||
$(CABAL_BUILD)/Rlp/Lex.hs: $(SRC)/Rlp/Lex.x
|
$(CABAL_BUILD)/Rlp/Lex.hs: $(SRC)/Rlp/Lex.x
|
||||||
$(ALEX) $(ALEX_OPTS) $< -o $@
|
$(ALEX) $(ALEX_OPTS) $< -o $@
|
||||||
|
|
||||||
|
$(CABAL_BUILD)/Core/Parse.hs: $(SRC)/Core/Parse.y
|
||||||
|
$(HAPPY) $(HAPPY_OPTS) $< -o $@
|
||||||
|
|
||||||
|
$(CABAL_BUILD)/Core/Lex.hs: $(SRC)/Core/Lex.x
|
||||||
|
$(ALEX) $(ALEX_OPTS) $< -o $@
|
||||||
|
|
||||||
|
|||||||
61
README.md
61
README.md
@@ -30,12 +30,12 @@ $ rlpc -ddump-opts t.hs
|
|||||||
|
|
||||||
### Potential Features
|
### Potential Features
|
||||||
Listed in order of importance.
|
Listed in order of importance.
|
||||||
- [ ] ADTs
|
- [x] ADTs
|
||||||
- [ ] First-class functions
|
- [x] First-class functions
|
||||||
- [ ] Higher-kinded types
|
- [ ] Higher-kinded types
|
||||||
- [ ] Typeclasses
|
- [ ] Typeclasses
|
||||||
- [ ] Parametric polymorphism
|
- [x] Parametric polymorphism
|
||||||
- [ ] Hindley-Milner type inference
|
- [x] Hindley-Milner type inference
|
||||||
- [ ] Newtype coercion
|
- [ ] Newtype coercion
|
||||||
- [ ] Parallelism
|
- [ ] Parallelism
|
||||||
|
|
||||||
@@ -66,32 +66,59 @@ Listed in order of importance.
|
|||||||
- [ ] TCO
|
- [ ] TCO
|
||||||
- [ ] DCE
|
- [ ] DCE
|
||||||
- [ ] Frontend
|
- [ ] Frontend
|
||||||
- [ ] High-level language
|
- [x] High-level language
|
||||||
- [ ] AST
|
- [x] AST
|
||||||
- [ ] Lexer
|
- [x] Lexer
|
||||||
- [ ] Parser
|
- [x] Parser
|
||||||
- [ ] Translation to the core language
|
- [ ] Translation to the core language
|
||||||
- [ ] Constraint solver
|
- [ ] Constraint solver
|
||||||
- [ ] `do`-notation
|
- [ ] `do`-notation
|
||||||
- [x] CLI
|
- [x] CLI
|
||||||
- [ ] Documentation
|
- [ ] Documentation
|
||||||
- [ ] State transition rules
|
- [x] State transition rules
|
||||||
- [ ] How does the evaluation model work?
|
- [ ] How does the evaluation model work?
|
||||||
|
- [ ] The Hindley-Milner type system
|
||||||
- [ ] CLI usage
|
- [ ] CLI usage
|
||||||
- [ ] Tail call optimisation
|
- [ ] Tail call optimisation
|
||||||
- [x] Parsing rlp
|
- [ ] Parsing rlp
|
||||||
- [ ] Tests
|
- [ ] Tests
|
||||||
- [x] Generic example programs
|
- [x] Generic example programs
|
||||||
- [ ] Parser
|
- [ ] Parser
|
||||||
|
|
||||||
### December Release Plan
|
### ~~December Release Plan~~
|
||||||
- [ ] Tests
|
- [x] Tests
|
||||||
- [ ] Core lexer
|
- [ ] Core lexer
|
||||||
- [ ] Core parser
|
- [ ] Core parser
|
||||||
- [ ] Evaluation model
|
- [x] Evaluation model
|
||||||
- [ ] Benchmarks
|
- [ ] Benchmarks
|
||||||
- [ ] Stable Core lexer
|
- [x] Stable Core lexer
|
||||||
- [ ] Stable Core parser
|
- [x] Stable Core parser
|
||||||
- [ ] Stable evaluation model
|
- [x] Stable evaluation model
|
||||||
- [ ] Garbage Collection
|
- [x] Garbage Collection
|
||||||
- [ ] Stable documentation for the evaluation model
|
- [ ] Stable documentation for the evaluation model
|
||||||
|
|
||||||
|
### January Release Plan
|
||||||
|
- [ ] Beta rl' to Core
|
||||||
|
- [ ] UX improvements
|
||||||
|
- [ ] Actual compiler errors -- no more unexceptional `error` calls
|
||||||
|
- [ ] Better CLI dump flags
|
||||||
|
- [ ] Annotate the AST with token positions for errors
|
||||||
|
|
||||||
|
### March Release Plan
|
||||||
|
- [ ] Tests
|
||||||
|
- [ ] rl' parser
|
||||||
|
- [ ] rl' lexer
|
||||||
|
|
||||||
|
### Indefinite Release Plan
|
||||||
|
|
||||||
|
This list is more concrete than the milestones, but likely further in the future
|
||||||
|
than the other release plans.
|
||||||
|
|
||||||
|
- [ ] Stable rl' to Core
|
||||||
|
- [ ] Core polish
|
||||||
|
- [ ] Better, stable parser
|
||||||
|
- [ ] Better, stable lexer
|
||||||
|
- [ ] Less hacky handling of named data
|
||||||
|
- [ ] Less hacky pragmas
|
||||||
|
- [ ] GM to LLVM
|
||||||
|
|
||||||
|
|||||||
@@ -112,5 +112,3 @@ The way around this is quite simple: simply offset the stack when w
|
|||||||
:end-before: -- << [ref/compileC]
|
:end-before: -- << [ref/compileC]
|
||||||
:caption: src/GM.hs
|
:caption: src/GM.hs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,21 @@ Lexing, Parsing, and Layouts
|
|||||||
============================
|
============================
|
||||||
|
|
||||||
The C-style languages of my previous experiences have all had quite trivial
|
The C-style languages of my previous experiences have all had quite trivial
|
||||||
lexical analysis stages, peaking in complexity when I streamed tokens lazily in
|
lexical analysis stages: you ignore all whitespace and point out the symbols you
|
||||||
C. The task of tokenising a C-style language is very simple in description: you
|
recognise. If you don't recognise something, check if it's a literal or an
|
||||||
ignore all whitespace and point out what you recognise. If you don't recognise
|
identifier. Should it be neither, return an error.
|
||||||
something, check if it's a literal or an identifier. Should it be neither,
|
|
||||||
return an error.
|
|
||||||
|
|
||||||
On paper, both lexing and parsing a Haskell-like language seem to pose a few
|
In contrast, both lexing and parsing a Haskell-like language poses a number of
|
||||||
greater challenges. Listed by ascending intimidation factor, some of the
|
greater challenges. Listed by ascending intimidation factor, some of the
|
||||||
potential roadblocks on my mind before making an attempt were:
|
potential roadblocks on my mind before making an attempt were:
|
||||||
|
|
||||||
|
* Context-sensitive keywords; Haskell allows for some words to be used as
|
||||||
|
identifiers in appropriate contexts, such as :code:`family`, :code:`role`,
|
||||||
|
:code:`as`. Reading a note_ found in `GHC's lexer`_, it appears that keywords
|
||||||
|
are only considered in bodies for which their use is relevant, e.g.
|
||||||
|
:code:`family` and :code:`role` in type declarations, :code:`as` after
|
||||||
|
:code:`case`; :code:`if`, :code:`then`, and :code:`else` in expressions, etc.
|
||||||
|
|
||||||
* Operators; Haskell has not only user-defined infix operators, but user-defined
|
* Operators; Haskell has not only user-defined infix operators, but user-defined
|
||||||
precedence levels and associativities. I recall using an algorithm that looked
|
precedence levels and associativities. I recall using an algorithm that looked
|
||||||
up infix, prefix, postfix, and even mixfix operators up in a global table to
|
up infix, prefix, postfix, and even mixfix operators up in a global table to
|
||||||
@@ -19,17 +24,9 @@ potential roadblocks on my mind before making an attempt were:
|
|||||||
stored in the table). I never modified the table at runtime, however this
|
stored in the table). I never modified the table at runtime, however this
|
||||||
could be a very nice solution for Haskell.
|
could be a very nice solution for Haskell.
|
||||||
|
|
||||||
* Context-sensitive keywords; Haskell allows for some words to be used as identifiers in
|
|
||||||
appropriate contexts, such as :code:`family`, :code:`role`, :code:`as`.
|
|
||||||
Reading a note_ found in `GHC's lexer`_,
|
|
||||||
it appears that keywords are only considered in bodies for which their use is
|
|
||||||
relevant, e.g. :code:`family` and :code:`role` in type declarations,
|
|
||||||
:code:`as` after :code:`case`; :code:`if`, :code:`then`, and :code:`else` in
|
|
||||||
expressions, etc.
|
|
||||||
|
|
||||||
* Whitespace sensitivity; While I was comfortable with the idea of a system
|
* Whitespace sensitivity; While I was comfortable with the idea of a system
|
||||||
similar to Python's INDENT/DEDENT tokens, Haskell seemed to use whitespace to
|
similar to Python's INDENT/DEDENT tokens, Haskell's layout system is based on
|
||||||
section code in a way that *felt* different.
|
alignment and is very generous with line-folding.
|
||||||
|
|
||||||
.. _note: https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/coding-style#2-using-notes
|
.. _note: https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/coding-style#2-using-notes
|
||||||
.. _GHC's lexer: https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Parser/Lexer.x#L1133
|
.. _GHC's lexer: https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Parser/Lexer.x#L1133
|
||||||
@@ -45,9 +42,9 @@ We will compare and contrast with Python's lexical analysis. Much to my dismay,
|
|||||||
Python uses newlines and indentation to separate statements and resolve scope
|
Python uses newlines and indentation to separate statements and resolve scope
|
||||||
instead of the traditional semicolons and braces found in C-style languages (we
|
instead of the traditional semicolons and braces found in C-style languages (we
|
||||||
may generally refer to these C-style languages as *explicitly-sectioned*).
|
may generally refer to these C-style languages as *explicitly-sectioned*).
|
||||||
Internally during tokenisation, when the Python lexer begins a new line, they
|
Internally during tokenisation, when the Python lexer encounters a new line, the
|
||||||
compare the indentation of the new line with that of the previous and apply the
|
indentation of the new line is compared with that of the previous and the
|
||||||
following rules:
|
following rules are applied:
|
||||||
|
|
||||||
1. If the new line has greater indentation than the previous, insert an INDENT
|
1. If the new line has greater indentation than the previous, insert an INDENT
|
||||||
token and push the new line's indentation level onto the indentation stack
|
token and push the new line's indentation level onto the indentation stack
|
||||||
@@ -60,44 +57,37 @@ following rules:
|
|||||||
3. If the indentation is equal, insert a NEWLINE token to terminate the previous
|
3. If the indentation is equal, insert a NEWLINE token to terminate the previous
|
||||||
line, and leave it at that!
|
line, and leave it at that!
|
||||||
|
|
||||||
Parsing Python with the INDENT, DEDENT, and NEWLINE tokens is identical to
|
On the parser's end, the INDENT, DEDENT, and NEWLINE tokens are identical to
|
||||||
parsing a language with braces and semicolons. This is a solution pretty in line
|
braces and semicolons. In developing our *layout* rules, we will follow in the
|
||||||
with Python's philosophy of the "one correct answer" (TODO: this needs a
|
pattern of translating the whitespace-sensitive source language to an explicitly
|
||||||
source). In developing our *layout* rules, we will follow in the pattern of
|
sectioned language.
|
||||||
translating the whitespace-sensitive source language to an explicitly sectioned
|
|
||||||
language.
|
|
||||||
|
|
||||||
But What About Haskell?
|
But What About Haskell?
|
||||||
***********************
|
***********************
|
||||||
|
|
||||||
We saw that Python, the most notable example of an implicitly sectioned
|
Parsing Haskell -- and thus rl' -- is only slightly more complex than Python,
|
||||||
language, is pretty simple to lex. Why then am I so afraid of Haskell's layouts?
|
but the design is certainly more sensitive.
|
||||||
To be frank, I'm far less scared after asking myself this -- however there are
|
|
||||||
certainly some new complexities that Python needn't concern. Haskell has
|
|
||||||
implicit line *continuation*: forms written over multiple lines; indentation
|
|
||||||
styles often seen in Haskell are somewhat esoteric compared to Python's
|
|
||||||
"s/[{};]//".
|
|
||||||
|
|
||||||
.. code-block:: haskell
|
.. code-block:: haskell
|
||||||
|
|
||||||
-- line continuation
|
-- line folds
|
||||||
something = this is a
|
something = this is a
|
||||||
single expression
|
single expression
|
||||||
|
|
||||||
-- an extremely common style found in haskell
|
-- an extremely common style found in haskell
|
||||||
data Python = Users
|
data Some = Data
|
||||||
{ are :: Crying
|
{ is :: Presented
|
||||||
, right :: About
|
, in :: This
|
||||||
, now :: Sorry
|
, silly :: Style
|
||||||
}
|
}
|
||||||
|
|
||||||
-- another formatting oddity
|
-- another style oddity
|
||||||
-- note that this is not a single
|
-- note that this is not a single
|
||||||
-- continued line! `look at`,
|
-- continued line! `look at`,
|
||||||
-- `this`, and `alignment` are all
|
-- `this odd`, and `alignment` are all
|
||||||
-- separate expressions!
|
-- discrete items!
|
||||||
anotherThing = do look at
|
anotherThing = do look at
|
||||||
this
|
this odd
|
||||||
alignment
|
alignment
|
||||||
|
|
||||||
But enough fear, lets actually think about implementation. Firstly, some
|
But enough fear, lets actually think about implementation. Firstly, some
|
||||||
@@ -233,3 +223,4 @@ References
|
|||||||
|
|
||||||
* `Haskell syntax reference
|
* `Haskell syntax reference
|
||||||
<https://www.haskell.org/onlinereport/haskell2010/haskellch10.html>`_
|
<https://www.haskell.org/onlinereport/haskell2010/haskellch10.html>`_
|
||||||
|
|
||||||
|
|||||||
5
doc/src/commentary/type-inference.rst
Normal file
5
doc/src/commentary/type-inference.rst
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Type Inference in rl'
|
||||||
|
=====================
|
||||||
|
|
||||||
|
rl' implements type inference via the Hindley-Milner type system.
|
||||||
|
|
||||||
17
doc/src/references/rlp-inference-rules.rst
Normal file
17
doc/src/references/rlp-inference-rules.rst
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
rl' Inference Rules
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. rubric::
|
||||||
|
[Var]
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{x : \tau \in \Gamma}
|
||||||
|
{\Gamma \vdash x : \tau}
|
||||||
|
|
||||||
|
.. rubric::
|
||||||
|
[App]
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{\Gamma \vdash f : \alpha \to \beta \qquad \Gamma \vdash x : \alpha}
|
||||||
|
{\Gamma \vdash f x : \beta}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
fac n = case (==#) n 0 of
|
fac n = case (==#) n 0 of
|
||||||
{ 1 -> 1
|
{ <1> -> 1
|
||||||
; 0 -> (*#) n (fac ((-#) n 1))
|
; <0> -> (*#) n (fac ((-#) n 1))
|
||||||
};
|
};
|
||||||
|
|
||||||
main = fac 3;
|
main = fac 3;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ nil = Pack{0 0};
|
|||||||
cons x y = Pack{1 2} x y;
|
cons x y = Pack{1 2} x y;
|
||||||
list = cons 1 (cons 2 (cons 3 nil));
|
list = cons 1 (cons 2 (cons 3 nil));
|
||||||
sum l = case l of
|
sum l = case l of
|
||||||
{ 0 -> 0
|
{ <0> -> 0
|
||||||
; 1 x xs -> (+#) x (sum xs)
|
; <1> x xs -> (+#) x (sum xs)
|
||||||
};
|
};
|
||||||
main = sum list;
|
main = sum list;
|
||||||
|
|
||||||
|
|||||||
105
programming-language-checklist
Normal file
105
programming-language-checklist
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
Programming Language Checklist
|
||||||
|
by Colin McMillen, Jason Reed, and Elly Fong-Jones, 2011-10-10.
|
||||||
|
|
||||||
|
You appear to be advocating a new:
|
||||||
|
[x] functional [ ] imperative [ ] object-oriented [ ] procedural [ ] stack-based
|
||||||
|
[ ] "multi-paradigm" [x] lazy [ ] eager [x] statically-typed [ ] dynamically-typed
|
||||||
|
[x] pure [ ] impure [ ] non-hygienic [ ] visual [x] beginner-friendly
|
||||||
|
[ ] non-programmer-friendly [ ] completely incomprehensible
|
||||||
|
programming language. Your language will not work. Here is why it will not work.
|
||||||
|
|
||||||
|
You appear to believe that:
|
||||||
|
[ ] Syntax is what makes programming difficult
|
||||||
|
[x] Garbage collection is free [x] Computers have infinite memory
|
||||||
|
[x] Nobody really needs:
|
||||||
|
[x] concurrency [x] a REPL [x] debugger support [x] IDE support [x] I/O
|
||||||
|
[x] to interact with code not written in your language
|
||||||
|
[ ] The entire world speaks 7-bit ASCII
|
||||||
|
[ ] Scaling up to large software projects will be easy
|
||||||
|
[ ] Convincing programmers to adopt a new language will be easy
|
||||||
|
[ ] Convincing programmers to adopt a language-specific IDE will be easy
|
||||||
|
[ ] Programmers love writing lots of boilerplate
|
||||||
|
[ ] Specifying behaviors as "undefined" means that programmers won't rely on them
|
||||||
|
[ ] "Spooky action at a distance" makes programming more fun
|
||||||
|
|
||||||
|
Unfortunately, your language (has/lacks):
|
||||||
|
[x] comprehensible syntax [ ] semicolons [x] significant whitespace [ ] macros
|
||||||
|
[ ] implicit type conversion [ ] explicit casting [x] type inference
|
||||||
|
[ ] goto [ ] exceptions [x] closures [x] tail recursion [ ] coroutines
|
||||||
|
[ ] reflection [ ] subtyping [ ] multiple inheritance [x] operator overloading
|
||||||
|
[x] algebraic datatypes [x] recursive types [x] polymorphic types
|
||||||
|
[ ] covariant array typing [x] monads [ ] dependent types
|
||||||
|
[x] infix operators [x] nested comments [ ] multi-line strings [ ] regexes
|
||||||
|
[ ] call-by-value [x] call-by-name [ ] call-by-reference [ ] call-cc
|
||||||
|
|
||||||
|
The following philosophical objections apply:
|
||||||
|
[ ] Programmers should not need to understand category theory to write "Hello, World!"
|
||||||
|
[ ] Programmers should not develop RSI from writing "Hello, World!"
|
||||||
|
[ ] The most significant program written in your language is its own compiler
|
||||||
|
[x] The most significant program written in your language isn't even its own compiler
|
||||||
|
[x] No language spec
|
||||||
|
[x] "The implementation is the spec"
|
||||||
|
[ ] The implementation is closed-source [ ] covered by patents [ ] not owned by you
|
||||||
|
[ ] Your type system is unsound [ ] Your language cannot be unambiguously parsed
|
||||||
|
[ ] a proof of same is attached
|
||||||
|
[ ] invoking this proof crashes the compiler
|
||||||
|
[x] The name of your language makes it impossible to find on Google
|
||||||
|
[x] Interpreted languages will never be as fast as C
|
||||||
|
[ ] Compiled languages will never be "extensible"
|
||||||
|
[ ] Writing a compiler that understands English is AI-complete
|
||||||
|
[ ] Your language relies on an optimization which has never been shown possible
|
||||||
|
[ ] There are less than 100 programmers on Earth smart enough to use your language
|
||||||
|
[ ] ____________________________ takes exponential time
|
||||||
|
[ ] ____________________________ is known to be undecidable
|
||||||
|
|
||||||
|
Your implementation has the following flaws:
|
||||||
|
[ ] CPUs do not work that way
|
||||||
|
[ ] RAM does not work that way
|
||||||
|
[ ] VMs do not work that way
|
||||||
|
[ ] Compilers do not work that way
|
||||||
|
[ ] Compilers cannot work that way
|
||||||
|
[ ] Shift-reduce conflicts in parsing seem to be resolved using rand()
|
||||||
|
[ ] You require the compiler to be present at runtime
|
||||||
|
[ ] You require the language runtime to be present at compile-time
|
||||||
|
[ ] Your compiler errors are completely inscrutable
|
||||||
|
[ ] Dangerous behavior is only a warning
|
||||||
|
[ ] The compiler crashes if you look at it funny
|
||||||
|
[x] The VM crashes if you look at it funny
|
||||||
|
[x] You don't seem to understand basic optimization techniques
|
||||||
|
[x] You don't seem to understand basic systems programming
|
||||||
|
[ ] You don't seem to understand pointers
|
||||||
|
[ ] You don't seem to understand functions
|
||||||
|
|
||||||
|
Additionally, your marketing has the following problems:
|
||||||
|
[x] Unsupported claims of increased productivity
|
||||||
|
[x] Unsupported claims of greater "ease of use"
|
||||||
|
[ ] Obviously rigged benchmarks
|
||||||
|
[ ] Graphics, simulation, or crypto benchmarks where your code just calls
|
||||||
|
handwritten assembly through your FFI
|
||||||
|
[ ] String-processing benchmarks where you just call PCRE
|
||||||
|
[ ] Matrix-math benchmarks where you just call BLAS
|
||||||
|
[x] Noone really believes that your language is faster than:
|
||||||
|
[x] assembly [x] C [x] FORTRAN [x] Java [x] Ruby [ ] Prolog
|
||||||
|
[ ] Rejection of orthodox programming-language theory without justification
|
||||||
|
[x] Rejection of orthodox systems programming without justification
|
||||||
|
[ ] Rejection of orthodox algorithmic theory without justification
|
||||||
|
[ ] Rejection of basic computer science without justification
|
||||||
|
|
||||||
|
Taking the wider ecosystem into account, I would like to note that:
|
||||||
|
[x] Your complex sample code would be one line in: examples/
|
||||||
|
[ ] We already have an unsafe imperative language
|
||||||
|
[ ] We already have a safe imperative OO language
|
||||||
|
[x] We already have a safe statically-typed eager functional language
|
||||||
|
[ ] You have reinvented Lisp but worse
|
||||||
|
[ ] You have reinvented Javascript but worse
|
||||||
|
[ ] You have reinvented Java but worse
|
||||||
|
[ ] You have reinvented C++ but worse
|
||||||
|
[ ] You have reinvented PHP but worse
|
||||||
|
[ ] You have reinvented PHP better, but that's still no justification
|
||||||
|
[ ] You have reinvented Brainfuck but non-ironically
|
||||||
|
|
||||||
|
In conclusion, this is what I think of you:
|
||||||
|
[ ] You have some interesting ideas, but this won't fly.
|
||||||
|
[x] This is a bad language, and you should feel bad for inventing it.
|
||||||
|
[ ] Programming in this language is an adequate punishment for inventing it.
|
||||||
|
|
||||||
@@ -73,6 +73,9 @@ library
|
|||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: GHC2021
|
default-language: GHC2021
|
||||||
|
|
||||||
|
default-extensions:
|
||||||
|
OverloadedStrings
|
||||||
|
|
||||||
executable rlpc
|
executable rlpc
|
||||||
import: warnings
|
import: warnings
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
|
|||||||
@@ -26,21 +26,23 @@ import Data.Function ((&))
|
|||||||
import GM
|
import GM
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
justLexSrc :: String -> Either RlpcError [CoreToken]
|
justLexSrc :: String -> Either [MsgEnvelope RlpcError] [CoreToken]
|
||||||
justLexSrc s = lexCoreR (T.pack s)
|
justLexSrc s = lexCoreR (T.pack s)
|
||||||
& fmap (map $ \ (Located _ _ _ t) -> t)
|
& fmap (map $ \ (Located _ _ _ t) -> t)
|
||||||
& rlpcToEither
|
& rlpcToEither
|
||||||
|
|
||||||
justParseSrc :: String -> Either RlpcError Program'
|
justParseSrc :: String -> Either [MsgEnvelope RlpcError] Program'
|
||||||
justParseSrc s = parse (T.pack s)
|
justParseSrc s = parse (T.pack s)
|
||||||
& rlpcToEither
|
& rlpcToEither
|
||||||
where parse = lexCoreR >=> parseCoreProgR
|
where parse = lexCoreR >=> parseCoreProgR
|
||||||
|
|
||||||
justTypeCheckSrc :: String -> Either RlpcError Program'
|
justTypeCheckSrc :: String -> Either [MsgEnvelope RlpcError] Program'
|
||||||
justTypeCheckSrc s = typechk (T.pack s)
|
justTypeCheckSrc s = typechk (T.pack s)
|
||||||
& rlpcToEither
|
& rlpcToEither
|
||||||
where typechk = lexCoreR >=> parseCoreProgR >=> checkCoreProgR
|
where typechk = lexCoreR >=> parseCoreProgR >=> checkCoreProgR
|
||||||
|
|
||||||
rlpcToEither :: RLPC e a -> Either e a
|
rlpcToEither :: RLPC a -> Either [MsgEnvelope RlpcError] a
|
||||||
rlpcToEither = evalRLPC def >>> fmap fst
|
rlpcToEither r = case evalRLPC def r of
|
||||||
|
(Just a, _) -> Right a
|
||||||
|
(Nothing, es) -> Left es
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ module Compiler.RLPC
|
|||||||
, RLPCT(..)
|
, RLPCT(..)
|
||||||
, RLPCIO
|
, RLPCIO
|
||||||
, RLPCOptions(RLPCOptions)
|
, RLPCOptions(RLPCOptions)
|
||||||
, RlpcError(..)
|
|
||||||
, IsRlpcError(..)
|
, IsRlpcError(..)
|
||||||
, rlpc
|
, RlpcError(..)
|
||||||
|
, MsgEnvelope(..)
|
||||||
, addFatal
|
, addFatal
|
||||||
, addWound
|
, addWound
|
||||||
, MonadErrorful
|
, MonadErrorful
|
||||||
@@ -27,9 +27,6 @@ module Compiler.RLPC
|
|||||||
, evalRLPCT
|
, evalRLPCT
|
||||||
, evalRLPCIO
|
, evalRLPCIO
|
||||||
, evalRLPC
|
, evalRLPC
|
||||||
, addRlpcWound
|
|
||||||
, addRlpcFatal
|
|
||||||
, liftRlpcErrs
|
|
||||||
, rlpcLogFile
|
, rlpcLogFile
|
||||||
, rlpcDebugOpts
|
, rlpcDebugOpts
|
||||||
, rlpcEvaluator
|
, rlpcEvaluator
|
||||||
@@ -40,6 +37,7 @@ module Compiler.RLPC
|
|||||||
, flagDDumpOpts
|
, flagDDumpOpts
|
||||||
, flagDDumpAST
|
, flagDDumpAST
|
||||||
, def
|
, def
|
||||||
|
, liftErrorful
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
@@ -51,6 +49,7 @@ import Control.Monad.Errorful
|
|||||||
import Compiler.RlpcError
|
import Compiler.RlpcError
|
||||||
import Data.Functor.Identity
|
import Data.Functor.Identity
|
||||||
import Data.Default.Class
|
import Data.Default.Class
|
||||||
|
import Data.Foldable
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import Data.Hashable (Hashable)
|
import Data.Hashable (Hashable)
|
||||||
import Data.HashSet (HashSet)
|
import Data.HashSet (HashSet)
|
||||||
@@ -58,48 +57,44 @@ import Data.HashSet qualified as S
|
|||||||
import Data.Coerce
|
import Data.Coerce
|
||||||
import Lens.Micro
|
import Lens.Micro
|
||||||
import Lens.Micro.TH
|
import Lens.Micro.TH
|
||||||
|
import System.Exit
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: fancy errors
|
newtype RLPCT m a = RLPCT {
|
||||||
newtype RLPCT e m a = RLPCT {
|
runRLPCT :: ReaderT RLPCOptions (ErrorfulT (MsgEnvelope RlpcError) m) a
|
||||||
runRLPCT :: ReaderT RLPCOptions (ErrorfulT e m) a
|
|
||||||
}
|
}
|
||||||
-- TODO: incorrect ussage of MonadReader. RLPC should have its own
|
deriving (Functor, Applicative, Monad)
|
||||||
-- environment access functions
|
|
||||||
deriving (Functor, Applicative, Monad, MonadReader RLPCOptions)
|
|
||||||
|
|
||||||
deriving instance (MonadIO m) => MonadIO (RLPCT e m)
|
type RLPC = RLPCT Identity
|
||||||
|
|
||||||
instance MonadTrans (RLPCT e) where
|
type RLPCIO = RLPCT IO
|
||||||
lift = RLPCT . lift . lift
|
|
||||||
|
|
||||||
instance (MonadState s m) => MonadState s (RLPCT e m) where
|
|
||||||
state = lift . state
|
|
||||||
|
|
||||||
type RLPC e = RLPCT e Identity
|
|
||||||
|
|
||||||
type RLPCIO e = RLPCT e IO
|
|
||||||
|
|
||||||
evalRLPCT :: RLPCOptions
|
|
||||||
-> RLPCT e m a
|
|
||||||
-> m (Either e (a, [e]))
|
|
||||||
evalRLPCT o = runRLPCT >>> flip runReaderT o >>> runErrorfulT
|
|
||||||
|
|
||||||
evalRLPC :: RLPCOptions
|
evalRLPC :: RLPCOptions
|
||||||
-> RLPC e a
|
-> RLPC a
|
||||||
-> Either e (a, [e])
|
-> (Maybe a, [MsgEnvelope RlpcError])
|
||||||
evalRLPC o m = coerce $ evalRLPCT o m
|
evalRLPC opt r = runRLPCT r
|
||||||
|
& flip runReaderT opt
|
||||||
|
& runErrorful
|
||||||
|
|
||||||
evalRLPCIO :: (Exception e)
|
evalRLPCT :: (Monad m)
|
||||||
=> RLPCOptions
|
=> RLPCOptions
|
||||||
-> RLPCIO e a
|
-> RLPCT m a
|
||||||
-> IO (a, [e])
|
-> m (Maybe a, [MsgEnvelope RlpcError])
|
||||||
evalRLPCIO o m = do
|
evalRLPCT = undefined
|
||||||
m' <- evalRLPCT o m
|
|
||||||
case m' of
|
evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a
|
||||||
-- TODO: errors
|
evalRLPCIO opt r = do
|
||||||
Left e -> throwIO e
|
(ma,es) <- evalRLPCT opt r
|
||||||
Right a -> pure a
|
putRlpcErrs es
|
||||||
|
case ma of
|
||||||
|
Just x -> pure x
|
||||||
|
Nothing -> die "Failed, no code compiled."
|
||||||
|
|
||||||
|
putRlpcErrs :: [MsgEnvelope RlpcError] -> IO ()
|
||||||
|
putRlpcErrs = traverse_ print
|
||||||
|
|
||||||
|
liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT (MsgEnvelope e) m a -> RLPCT m a
|
||||||
|
liftErrorful e = RLPCT $ lift (fmap liftRlpcError `mapErrorful` e)
|
||||||
|
|
||||||
data RLPCOptions = RLPCOptions
|
data RLPCOptions = RLPCOptions
|
||||||
{ _rlpcLogFile :: Maybe FilePath
|
{ _rlpcLogFile :: Maybe FilePath
|
||||||
@@ -113,32 +108,6 @@ data RLPCOptions = RLPCOptions
|
|||||||
data Evaluator = EvaluatorGM | EvaluatorTI
|
data Evaluator = EvaluatorGM | EvaluatorTI
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
data Severity = Error
|
|
||||||
| Warning
|
|
||||||
| Debug
|
|
||||||
deriving Show
|
|
||||||
|
|
||||||
-- temporary until we have a new doc building system
|
|
||||||
type ErrorDoc = String
|
|
||||||
|
|
||||||
instance (Monad m) => MonadErrorful e (RLPCT e m) where
|
|
||||||
addWound = RLPCT . lift . addWound
|
|
||||||
addFatal = RLPCT . lift . addFatal
|
|
||||||
|
|
||||||
liftRlpcErrs :: (IsRlpcError e, Monad m)
|
|
||||||
=> RLPCT e m a -> RLPCT RlpcError m a
|
|
||||||
liftRlpcErrs m = RLPCT . ReaderT $ \r ->
|
|
||||||
mapErrors liftRlpcErr $ runRLPCT >>> (`runReaderT` r) $ m
|
|
||||||
|
|
||||||
addRlpcWound :: (IsRlpcError e, Monad m) => e -> RLPCT RlpcError m ()
|
|
||||||
addRlpcWound = addWound . liftRlpcErr
|
|
||||||
|
|
||||||
addRlpcFatal :: (IsRlpcError e, Monad m) => e -> RLPCT RlpcError m ()
|
|
||||||
addRlpcFatal = addWound . liftRlpcErr
|
|
||||||
|
|
||||||
rlpc :: (Monad m) => ErrorfulT e m a -> RLPCT e m a
|
|
||||||
rlpc = RLPCT . ReaderT . const
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
instance Default RLPCOptions where
|
instance Default RLPCOptions where
|
||||||
|
|||||||
@@ -1,15 +1,70 @@
|
|||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
|
||||||
module Compiler.RlpcError
|
module Compiler.RlpcError
|
||||||
( RlpcError(..)
|
( IsRlpcError(..)
|
||||||
, IsRlpcError(..)
|
, MsgEnvelope(..)
|
||||||
|
, Severity(..)
|
||||||
|
, RlpcError(..)
|
||||||
|
, SrcSpan(..)
|
||||||
|
, msgSpan
|
||||||
|
, msgDiagnostic
|
||||||
|
, msgSeverity
|
||||||
|
, liftRlpcErrors
|
||||||
|
, errorMsg
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
import Control.Monad.Errorful
|
import Control.Monad.Errorful
|
||||||
|
import Data.Text (Text)
|
||||||
|
import Data.Text qualified as T
|
||||||
|
import GHC.Exts (IsString(..))
|
||||||
|
import Lens.Micro.Platform
|
||||||
|
import Lens.Micro.Platform.Internal
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
data RlpcError = RlpcErr String -- temp
|
data MsgEnvelope e = MsgEnvelope
|
||||||
|
{ _msgSpan :: SrcSpan
|
||||||
|
, _msgDiagnostic :: e
|
||||||
|
, _msgSeverity :: Severity
|
||||||
|
}
|
||||||
|
deriving (Functor, Show)
|
||||||
|
|
||||||
|
newtype RlpcError = Text [Text]
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
class IsRlpcError a where
|
instance IsString RlpcError where
|
||||||
liftRlpcErr :: a -> RlpcError
|
fromString = Text . pure . T.pack
|
||||||
|
|
||||||
|
class IsRlpcError e where
|
||||||
|
liftRlpcError :: e -> RlpcError
|
||||||
|
|
||||||
|
instance IsRlpcError RlpcError where
|
||||||
|
liftRlpcError = id
|
||||||
|
|
||||||
|
data Severity = SevWarning
|
||||||
|
| SevError
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
data SrcSpan = SrcSpan
|
||||||
|
!Int -- ^ Line
|
||||||
|
!Int -- ^ Column
|
||||||
|
!Int -- ^ Length
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
makeLenses ''MsgEnvelope
|
||||||
|
|
||||||
|
liftRlpcErrors :: (Functor m, IsRlpcError e)
|
||||||
|
=> ErrorfulT e m a
|
||||||
|
-> ErrorfulT RlpcError m a
|
||||||
|
liftRlpcErrors = mapErrorful liftRlpcError
|
||||||
|
|
||||||
|
instance (IsRlpcError e) => IsRlpcError (MsgEnvelope e) where
|
||||||
|
liftRlpcError msg = msg ^. msgDiagnostic & liftRlpcError
|
||||||
|
|
||||||
|
errorMsg :: SrcSpan -> e -> MsgEnvelope e
|
||||||
|
errorMsg s e = MsgEnvelope
|
||||||
|
{ _msgSpan = s
|
||||||
|
, _msgDiagnostic = e
|
||||||
|
, _msgSeverity = SevError
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +1,79 @@
|
|||||||
{-# LANGUAGE StandaloneDeriving #-}
|
{-# LANGUAGE StandaloneDeriving #-}
|
||||||
{-# LANGUAGE FunctionalDependencies #-}
|
{-# LANGUAGE FunctionalDependencies #-}
|
||||||
{-# LANGUAGE TupleSections, PatternSynonyms #-}
|
{-# LANGUAGE TupleSections, PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
module Control.Monad.Errorful
|
module Control.Monad.Errorful
|
||||||
( ErrorfulT
|
( ErrorfulT
|
||||||
, runErrorfulT
|
, runErrorfulT
|
||||||
, Errorful
|
, Errorful
|
||||||
, runErrorful
|
, runErrorful
|
||||||
, mapErrors
|
, mapErrorful
|
||||||
, MonadErrorful(..)
|
, MonadErrorful(..)
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
import Control.Monad.State.Strict
|
||||||
import Control.Monad.Trans
|
import Control.Monad.Trans
|
||||||
import Data.Functor.Identity
|
import Data.Functor.Identity
|
||||||
import Data.Coerce
|
import Data.Coerce
|
||||||
|
import Data.HashSet (HashSet)
|
||||||
|
import Data.HashSet qualified as H
|
||||||
import Lens.Micro
|
import Lens.Micro
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
newtype ErrorfulT e m a = ErrorfulT { runErrorfulT :: m (Either e (a, [e])) }
|
newtype ErrorfulT e m a = ErrorfulT { runErrorfulT :: m (Maybe a, [e]) }
|
||||||
|
|
||||||
type Errorful e = ErrorfulT e Identity
|
type Errorful e = ErrorfulT e Identity
|
||||||
|
|
||||||
pattern Errorful :: (Either e (a, [e])) -> Errorful e a
|
pattern Errorful :: (Maybe a, [e]) -> Errorful e a
|
||||||
pattern Errorful a = ErrorfulT (Identity a)
|
pattern Errorful a = ErrorfulT (Identity a)
|
||||||
|
|
||||||
runErrorful :: Errorful e a -> Either e (a, [e])
|
runErrorful :: Errorful e a -> (Maybe a, [e])
|
||||||
runErrorful m = coerce (runErrorfulT m)
|
runErrorful m = coerce (runErrorfulT m)
|
||||||
|
|
||||||
class (Applicative m) => MonadErrorful e m | m -> e where
|
class (Applicative m) => MonadErrorful e m | m -> e where
|
||||||
addWound :: e -> m ()
|
addWound :: e -> m ()
|
||||||
addFatal :: e -> m a
|
addFatal :: e -> m a
|
||||||
|
|
||||||
-- not sure if i want to add this yet...
|
|
||||||
-- catchWound :: m a -> (e -> m a) -> m a
|
|
||||||
|
|
||||||
instance (Applicative m) => MonadErrorful e (ErrorfulT e m) where
|
instance (Applicative m) => MonadErrorful e (ErrorfulT e m) where
|
||||||
addWound e = ErrorfulT $ pure . Right $ ((), [e])
|
addWound e = ErrorfulT $ pure (Just (), [e])
|
||||||
addFatal e = ErrorfulT $ pure . Left $ e
|
addFatal e = ErrorfulT $ pure (Nothing, [e])
|
||||||
|
|
||||||
instance MonadTrans (ErrorfulT e) where
|
instance MonadTrans (ErrorfulT e) where
|
||||||
lift m = ErrorfulT (Right . (,[]) <$> m)
|
lift m = ErrorfulT ((\x -> (Just x,[])) <$> m)
|
||||||
|
|
||||||
instance (MonadIO m) => MonadIO (ErrorfulT e m) where
|
instance (MonadIO m) => MonadIO (ErrorfulT e m) where
|
||||||
liftIO = lift . liftIO
|
liftIO = lift . liftIO
|
||||||
|
|
||||||
instance (Functor m) => Functor (ErrorfulT e m) where
|
instance (Functor m) => Functor (ErrorfulT e m) where
|
||||||
fmap f (ErrorfulT m) = ErrorfulT $ fmap (_1 %~ f) <$> m
|
fmap f (ErrorfulT m) = ErrorfulT (m & mapped . _1 . _Just %~ f)
|
||||||
|
|
||||||
instance (Applicative m) => Applicative (ErrorfulT e m) where
|
instance (Applicative m) => Applicative (ErrorfulT e m) where
|
||||||
pure a = ErrorfulT (pure . Right $ (a, []))
|
pure a = ErrorfulT . pure $ (Just a, [])
|
||||||
|
|
||||||
m <*> a = ErrorfulT (m' `apply` a')
|
ErrorfulT m <*> ErrorfulT n = ErrorfulT $ m `apply` n where
|
||||||
where
|
apply :: m (Maybe (a -> b), [e]) -> m (Maybe a, [e]) -> m (Maybe b, [e])
|
||||||
m' = runErrorfulT m
|
apply = liftA2 $ \ (mf,e1) (ma,e2) -> (mf <*> ma, e1 <> e2)
|
||||||
a' = runErrorfulT a
|
|
||||||
-- TODO: strict concatenation
|
|
||||||
apply = liftA2 $ liftA2 (\ (f,e1) (x,e2) -> (f x, e1 ++ e2))
|
|
||||||
|
|
||||||
instance (Monad m) => Monad (ErrorfulT e m) where
|
instance (Monad m) => Monad (ErrorfulT e m) where
|
||||||
ErrorfulT m >>= k = ErrorfulT $ do
|
ErrorfulT m >>= k = ErrorfulT $ do
|
||||||
m' <- m
|
(a,es) <- m
|
||||||
case m' of
|
case a of
|
||||||
Right (a,es) -> runErrorfulT (k a)
|
Just x -> runErrorfulT (k x)
|
||||||
Left e -> pure (Left e)
|
Nothing -> pure (Nothing, es)
|
||||||
|
|
||||||
mapErrors :: (Monad m) => (e -> e') -> ErrorfulT e m a -> ErrorfulT e' m a
|
mapErrorful :: (Functor m) => (e -> e') -> ErrorfulT e m a -> ErrorfulT e' m a
|
||||||
mapErrors f m = ErrorfulT $ do
|
mapErrorful f (ErrorfulT m) = ErrorfulT $
|
||||||
x <- runErrorfulT m
|
m & mapped . _2 . mapped %~ f
|
||||||
case x of
|
|
||||||
Left e -> pure . Left $ f e
|
-- when microlens-pro drops we can write this as
|
||||||
Right (a,es) -> pure . Right $ (a, f <$> es)
|
-- mapErrorful f = coerced . mapped . _2 . mappd %~ f
|
||||||
|
-- lol
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- daily dose of n^2 instances
|
||||||
|
|
||||||
|
instance (Monad m, MonadErrorful e m) => MonadErrorful e (StateT s m) where
|
||||||
|
addWound = undefined
|
||||||
|
addFatal = undefined
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,19 @@ Description : Core examples (may eventually be unit tests)
|
|||||||
-}
|
-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module Core.Examples
|
module Core.Examples where
|
||||||
( fac3
|
|
||||||
, sumList
|
|
||||||
, constDivZero
|
|
||||||
, idCase
|
|
||||||
) where
|
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
import Core.Syntax
|
import Core.Syntax
|
||||||
import Core.TH
|
import Core.TH
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- fac3 = undefined
|
||||||
|
-- sumList = undefined
|
||||||
|
-- constDivZero = undefined
|
||||||
|
-- idCase = undefined
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
letrecExample :: Program'
|
letrecExample :: Program'
|
||||||
letrecExample = [coreProg|
|
letrecExample = [coreProg|
|
||||||
pair x y f = f x y;
|
pair x y f = f x y;
|
||||||
@@ -140,8 +142,8 @@ simple1 = [coreProg|
|
|||||||
caseBool1 :: Program'
|
caseBool1 :: Program'
|
||||||
caseBool1 = [coreProg|
|
caseBool1 = [coreProg|
|
||||||
_if c x y = case c of
|
_if c x y = case c of
|
||||||
{ 1 -> x
|
{ <1> -> x
|
||||||
; 0 -> y
|
; <0> -> y
|
||||||
};
|
};
|
||||||
|
|
||||||
false = Pack{0 0};
|
false = Pack{0 0};
|
||||||
@@ -153,8 +155,8 @@ caseBool1 = [coreProg|
|
|||||||
fac3 :: Program'
|
fac3 :: Program'
|
||||||
fac3 = [coreProg|
|
fac3 = [coreProg|
|
||||||
fac n = case (==#) n 0 of
|
fac n = case (==#) n 0 of
|
||||||
{ 1 -> 1
|
{ <1> -> 1
|
||||||
; 0 -> (*#) n (fac ((-#) n 1))
|
; <0> -> (*#) n (fac ((-#) n 1))
|
||||||
};
|
};
|
||||||
|
|
||||||
main = fac 3;
|
main = fac 3;
|
||||||
@@ -168,8 +170,8 @@ sumList = [coreProg|
|
|||||||
cons x y = Pack{1 2} x y;
|
cons x y = Pack{1 2} x y;
|
||||||
list = cons 1 (cons 2 (cons 3 nil));
|
list = cons 1 (cons 2 (cons 3 nil));
|
||||||
sum l = case l of
|
sum l = case l of
|
||||||
{ 0 -> 0
|
{ <0> -> 0
|
||||||
; 1 x xs -> (+#) x (sum xs)
|
; <1> x xs -> (+#) x (sum xs)
|
||||||
};
|
};
|
||||||
main = sum list;
|
main = sum list;
|
||||||
|]
|
|]
|
||||||
@@ -185,10 +187,36 @@ idCase = [coreProg|
|
|||||||
id x = x;
|
id x = x;
|
||||||
|
|
||||||
main = id (case Pack{1 0} of
|
main = id (case Pack{1 0} of
|
||||||
{ 1 -> (+#) 2 3
|
{ <1> -> (+#) 2 3
|
||||||
})
|
})
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
-- NOTE: the GM primitive (==#) returns an untyped constructor with tag 1 for
|
||||||
|
-- true, and 0 for false. See: GM.boxBool
|
||||||
|
namedBoolCase :: Program'
|
||||||
|
namedBoolCase = [coreProg|
|
||||||
|
{-# PackData True 1 0 #-}
|
||||||
|
{-# PackData False 0 0 #-}
|
||||||
|
main = case (==#) 1 1 of
|
||||||
|
{ True -> 123
|
||||||
|
; False -> 456
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
namedConsCase :: Program'
|
||||||
|
namedConsCase = [coreProg|
|
||||||
|
{-# PackData Nil 0 0 #-}
|
||||||
|
{-# PackData Cons 1 2 #-}
|
||||||
|
Nil = Pack{0 0};
|
||||||
|
Cons = Pack{1 2};
|
||||||
|
foldr f z l = case l of
|
||||||
|
{ Nil -> z
|
||||||
|
; Cons x xs -> f x (foldr f z xs)
|
||||||
|
};
|
||||||
|
list = Cons 1 (Cons 2 (Cons 3 Nil));
|
||||||
|
main = foldr (+#) 0 list
|
||||||
|
|]
|
||||||
|
|
||||||
-- corePrelude :: Module Name
|
-- corePrelude :: Module Name
|
||||||
-- corePrelude = Module (Just ("Prelude", [])) $
|
-- corePrelude = Module (Just ("Prelude", [])) $
|
||||||
-- -- non-primitive defs
|
-- -- non-primitive defs
|
||||||
@@ -216,3 +244,4 @@ idCase = [coreProg|
|
|||||||
-- , ScDef "Cons" [] $ Con 2 2
|
-- , ScDef "Cons" [] $ Con 2 2
|
||||||
-- ]
|
-- ]
|
||||||
|
|
||||||
|
--}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ Module : Core.HindleyMilner
|
|||||||
Description : Hindley-Milner type system
|
Description : Hindley-Milner type system
|
||||||
-}
|
-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module Core.HindleyMilner
|
module Core.HindleyMilner
|
||||||
( Context'
|
( Context'
|
||||||
, infer
|
, infer
|
||||||
@@ -16,15 +17,17 @@ module Core.HindleyMilner
|
|||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
import Lens.Micro
|
import Lens.Micro
|
||||||
import Lens.Micro.Mtl
|
import Lens.Micro.Mtl
|
||||||
|
import Lens.Micro.Platform
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Data.HashMap.Strict qualified as H
|
import Data.HashMap.Strict qualified as H
|
||||||
import Data.Foldable (traverse_)
|
import Data.Foldable (traverse_)
|
||||||
import Compiler.RLPC
|
import Compiler.RLPC
|
||||||
import Control.Monad (foldM, void)
|
import Control.Monad (foldM, void, forM)
|
||||||
import Control.Monad.Errorful (Errorful, addFatal)
|
import Control.Monad.Errorful (Errorful, addFatal)
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
import Control.Monad.Utils (mapAccumLM)
|
import Control.Monad.Utils (mapAccumLM)
|
||||||
|
import Text.Printf
|
||||||
import Core.Syntax
|
import Core.Syntax
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -48,9 +51,23 @@ data TypeError
|
|||||||
| TyErrMissingTypeSig Name
|
| TyErrMissingTypeSig Name
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
|
|
||||||
-- TODO:
|
|
||||||
instance IsRlpcError TypeError where
|
instance IsRlpcError TypeError where
|
||||||
liftRlpcErr = RlpcErr . show
|
liftRlpcError = \case
|
||||||
|
-- todo: use anti-parser instead of show
|
||||||
|
TyErrCouldNotUnify t u -> Text
|
||||||
|
[ T.pack $ printf "Could not match type `%s` with `%s`."
|
||||||
|
(show t) (show u)
|
||||||
|
, "Expected: " <> tshow t
|
||||||
|
, "Got: " <> tshow u
|
||||||
|
]
|
||||||
|
TyErrUntypedVariable n -> Text
|
||||||
|
[ "Untyped (likely undefined) variable `" <> n <> "`"
|
||||||
|
]
|
||||||
|
TyErrRecursiveType t x -> Text
|
||||||
|
[ T.pack $ printf "recursive type error lol"
|
||||||
|
]
|
||||||
|
|
||||||
|
where tshow = T.pack . show
|
||||||
|
|
||||||
-- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may
|
-- | Synonym for @Errorful [TypeError]@. This means an @HMError@ action may
|
||||||
-- throw any number of fatal or nonfatal errors. Run with @runErrorful@.
|
-- throw any number of fatal or nonfatal errors. Run with @runErrorful@.
|
||||||
@@ -88,10 +105,10 @@ checkCoreProg p = scDefs
|
|||||||
where scname = sc ^. _lhs._1
|
where scname = sc ^. _lhs._1
|
||||||
|
|
||||||
-- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks.
|
-- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks.
|
||||||
checkCoreProgR :: Program' -> RLPC RlpcError Program'
|
checkCoreProgR :: Program' -> RLPC Program'
|
||||||
checkCoreProgR p = do
|
checkCoreProgR p = undefined
|
||||||
liftRlpcErrs . rlpc . checkCoreProg $ p
|
|
||||||
pure p
|
{-# WARNING checkCoreProgR "unimpl" #-}
|
||||||
|
|
||||||
-- | Infer the type of an expression under some context.
|
-- | Infer the type of an expression under some context.
|
||||||
--
|
--
|
||||||
@@ -140,7 +157,32 @@ gather = \g e -> runStateT (go g e) ([],0) <&> \ (t,(cs,_)) -> (t,cs) where
|
|||||||
Let NonRec bs e -> do
|
Let NonRec bs e -> do
|
||||||
g' <- buildLetContext g bs
|
g' <- buildLetContext g bs
|
||||||
go g' e
|
go g' e
|
||||||
-- TODO letrec, lambda, case
|
Let Rec bs e -> do
|
||||||
|
g' <- buildLetrecContext g bs
|
||||||
|
go g' e
|
||||||
|
Lam bs e -> case bs of
|
||||||
|
[x] -> do
|
||||||
|
tx <- uniqueVar
|
||||||
|
let g' = (x,tx) : g
|
||||||
|
te <- go g' e
|
||||||
|
pure (tx :-> te)
|
||||||
|
-- TODO lambda, case
|
||||||
|
|
||||||
|
buildLetrecContext :: Context' -> [Binding']
|
||||||
|
-> StateT ([Constraint], Int) HMError Context'
|
||||||
|
buildLetrecContext g bs = do
|
||||||
|
let f ag (k := _) = do
|
||||||
|
n <- uniqueVar
|
||||||
|
pure ((k,n) : ag)
|
||||||
|
rg <- foldM f g bs
|
||||||
|
let k ag (k := v) = do
|
||||||
|
t <- go rg v
|
||||||
|
pure ((k,t) : ag)
|
||||||
|
foldM k g bs
|
||||||
|
|
||||||
|
-- | augment a context with the inferred types of each binder. the returned
|
||||||
|
-- context is linearly accumulated, meaning that the context used to infer each binder
|
||||||
|
-- will include the inferred types of all previous binder
|
||||||
|
|
||||||
buildLetContext :: Context' -> [Binding']
|
buildLetContext :: Context' -> [Binding']
|
||||||
-> StateT ([Constraint], Int) HMError Context'
|
-> StateT ([Constraint], Int) HMError Context'
|
||||||
@@ -218,3 +260,20 @@ subst x t (TyVar y) | x == y = t
|
|||||||
subst x t (a :-> b) = subst x t a :-> subst x t b
|
subst x t (a :-> b) = subst x t a :-> subst x t b
|
||||||
subst _ _ e = e
|
subst _ _ e = e
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
demoContext :: Context'
|
||||||
|
demoContext =
|
||||||
|
[ ("fix", (TyVar "a" :-> TyVar "a") :-> TyVar "a")
|
||||||
|
, ("add", TyInt :-> TyInt :-> TyInt)
|
||||||
|
, ("==", TyInt :-> TyInt :-> TyCon "Bool")
|
||||||
|
, ("True", TyCon "Bool")
|
||||||
|
, ("False", TyCon "Bool")
|
||||||
|
]
|
||||||
|
|
||||||
|
pprintType :: Type -> String
|
||||||
|
pprintType (s :-> t) = "(" <> pprintType s <> " -> " <> pprintType t <> ")"
|
||||||
|
pprintType TyFun = "(->)"
|
||||||
|
pprintType (TyVar x) = x ^. unpacked
|
||||||
|
pprintType (TyCon t) = t ^. unpacked
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ $white_no_nl = $white # $nl
|
|||||||
|
|
||||||
@decimal = $digit+
|
@decimal = $digit+
|
||||||
|
|
||||||
|
@alttag = "<" $digit+ ">"
|
||||||
|
|
||||||
rlp :-
|
rlp :-
|
||||||
|
|
||||||
<0>
|
<0>
|
||||||
@@ -92,6 +94,8 @@ rlp :-
|
|||||||
"=" { constTok TokenEquals }
|
"=" { constTok TokenEquals }
|
||||||
"->" { constTok TokenArrow }
|
"->" { constTok TokenArrow }
|
||||||
|
|
||||||
|
@alttag { lexWith ( TokenAltTag . read @Int . T.unpack
|
||||||
|
. T.drop 1 . T.init ) }
|
||||||
@varname { lexWith TokenVarName }
|
@varname { lexWith TokenVarName }
|
||||||
@conname { lexWith TokenConName }
|
@conname { lexWith TokenConName }
|
||||||
@varsym { lexWith TokenVarSym }
|
@varsym { lexWith TokenVarSym }
|
||||||
@@ -135,6 +139,7 @@ data CoreToken = TokenLet
|
|||||||
| TokenConName Name
|
| TokenConName Name
|
||||||
| TokenVarSym Name
|
| TokenVarSym Name
|
||||||
| TokenConSym Name
|
| TokenConSym Name
|
||||||
|
| TokenAltTag Tag
|
||||||
| TokenEquals
|
| TokenEquals
|
||||||
| TokenLParen
|
| TokenLParen
|
||||||
| TokenRParen
|
| TokenRParen
|
||||||
@@ -167,24 +172,19 @@ lexWith :: (Text -> CoreToken) -> Lexer
|
|||||||
lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ T.take l s)
|
lexWith f (AlexPn _ y x,_,_,s) l = pure $ Located y x l (f $ T.take l s)
|
||||||
|
|
||||||
-- | The main lexer driver.
|
-- | The main lexer driver.
|
||||||
lexCore :: Text -> RLPC SrcError [Located CoreToken]
|
lexCore :: Text -> RLPC [Located CoreToken]
|
||||||
lexCore s = case m of
|
lexCore s = case m of
|
||||||
Left e -> addFatal err
|
Left e -> error "core lex error"
|
||||||
where err = SrcError
|
|
||||||
{ _errSpan = (0,0,0) -- TODO: location
|
|
||||||
, _errSeverity = Error
|
|
||||||
, _errDiagnostic = SrcErrLexical e
|
|
||||||
}
|
|
||||||
Right ts -> pure ts
|
Right ts -> pure ts
|
||||||
where
|
where
|
||||||
m = runAlex s lexStream
|
m = runAlex s lexStream
|
||||||
|
|
||||||
lexCoreR :: Text -> RLPC RlpcError [Located CoreToken]
|
lexCoreR :: Text -> RLPC [Located CoreToken]
|
||||||
lexCoreR = liftRlpcErrs . lexCore
|
lexCoreR = lexCore
|
||||||
|
|
||||||
-- | @lexCore@, but the tokens are stripped of location info. Useful for
|
-- | @lexCore@, but the tokens are stripped of location info. Useful for
|
||||||
-- debugging
|
-- debugging
|
||||||
lexCore' :: Text -> RLPC SrcError [CoreToken]
|
lexCore' :: Text -> RLPC [CoreToken]
|
||||||
lexCore' s = fmap f <$> lexCore s
|
lexCore' s = fmap f <$> lexCore s
|
||||||
where f (Located _ _ _ t) = t
|
where f (Located _ _ _ t) = t
|
||||||
|
|
||||||
@@ -201,11 +201,11 @@ data ParseError = ParErrLexical String
|
|||||||
|
|
||||||
-- TODO:
|
-- TODO:
|
||||||
instance IsRlpcError SrcError where
|
instance IsRlpcError SrcError where
|
||||||
liftRlpcErr = RlpcErr . show
|
liftRlpcError = Text . pure . T.pack . show
|
||||||
|
|
||||||
-- TODO:
|
-- TODO:
|
||||||
instance IsRlpcError ParseError where
|
instance IsRlpcError ParseError where
|
||||||
liftRlpcErr = RlpcErr . show
|
liftRlpcError = Text . pure . T.pack . show
|
||||||
|
|
||||||
alexEOF :: Alex (Located CoreToken)
|
alexEOF :: Alex (Located CoreToken)
|
||||||
alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) ->
|
alexEOF = Alex $ \ st@(AlexState { alex_pos = AlexPn _ y x }) ->
|
||||||
|
|||||||
@@ -3,14 +3,13 @@
|
|||||||
Module : Core.Parse
|
Module : Core.Parse
|
||||||
Description : Parser for the Core language
|
Description : Parser for the Core language
|
||||||
-}
|
-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings, ViewPatterns #-}
|
||||||
module Core.Parse
|
module Core.Parse
|
||||||
( parseCore
|
( parseCore
|
||||||
, parseCoreExpr
|
, parseCoreExpr
|
||||||
, parseCoreProg
|
, parseCoreProg
|
||||||
, parseCoreProgR
|
, parseCoreProgR
|
||||||
, module Core.Lex -- temp convenience
|
, module Core.Lex -- temp convenience
|
||||||
, parseTmp
|
|
||||||
, SrcError
|
, SrcError
|
||||||
, Module
|
, Module
|
||||||
)
|
)
|
||||||
@@ -24,7 +23,9 @@ import Compiler.RLPC
|
|||||||
import Lens.Micro
|
import Lens.Micro
|
||||||
import Data.Default.Class (def)
|
import Data.Default.Class (def)
|
||||||
import Data.Hashable (Hashable)
|
import Data.Hashable (Hashable)
|
||||||
|
import Data.List.Extra
|
||||||
import Data.Text.IO qualified as TIO
|
import Data.Text.IO qualified as TIO
|
||||||
|
import Data.Text (Text)
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Data.HashMap.Strict qualified as H
|
import Data.HashMap.Strict qualified as H
|
||||||
}
|
}
|
||||||
@@ -34,7 +35,7 @@ import Data.HashMap.Strict qualified as H
|
|||||||
%name parseCoreProg StandaloneProgram
|
%name parseCoreProg StandaloneProgram
|
||||||
%tokentype { Located CoreToken }
|
%tokentype { Located CoreToken }
|
||||||
%error { parseError }
|
%error { parseError }
|
||||||
%monad { RLPC SrcError }
|
%monad { RLPC } { happyBind } { happyPure }
|
||||||
|
|
||||||
%token
|
%token
|
||||||
let { Located _ _ _ TokenLet }
|
let { Located _ _ _ TokenLet }
|
||||||
@@ -50,6 +51,7 @@ import Data.HashMap.Strict qualified as H
|
|||||||
varsym { Located _ _ _ (TokenVarSym $$) }
|
varsym { Located _ _ _ (TokenVarSym $$) }
|
||||||
conname { Located _ _ _ (TokenConName $$) }
|
conname { Located _ _ _ (TokenConName $$) }
|
||||||
consym { Located _ _ _ (TokenConSym $$) }
|
consym { Located _ _ _ (TokenConSym $$) }
|
||||||
|
alttag { Located _ _ _ (TokenAltTag $$) }
|
||||||
word { Located _ _ _ (TokenWord $$) }
|
word { Located _ _ _ (TokenWord $$) }
|
||||||
'λ' { Located _ _ _ TokenLambda }
|
'λ' { Located _ _ _ TokenLambda }
|
||||||
'->' { Located _ _ _ TokenArrow }
|
'->' { Located _ _ _ TokenArrow }
|
||||||
@@ -83,6 +85,15 @@ Program : ScTypeSig ';' Program { insTypeSig $1 $3 }
|
|||||||
| ScTypeSig OptSemi { singletonTypeSig $1 }
|
| ScTypeSig OptSemi { singletonTypeSig $1 }
|
||||||
| ScDef ';' Program { insScDef $1 $3 }
|
| ScDef ';' Program { insScDef $1 $3 }
|
||||||
| ScDef OptSemi { singletonScDef $1 }
|
| ScDef OptSemi { singletonScDef $1 }
|
||||||
|
| TLPragma Program {% doTLPragma $1 $2 }
|
||||||
|
| TLPragma {% doTLPragma $1 mempty }
|
||||||
|
|
||||||
|
TLPragma :: { Pragma }
|
||||||
|
: '{-#' Words '#-}' { Pragma $2 }
|
||||||
|
|
||||||
|
Words :: { [Text] }
|
||||||
|
: Words word { $1 `snoc` $2 }
|
||||||
|
| word { [$1] }
|
||||||
|
|
||||||
OptSemi :: { () }
|
OptSemi :: { () }
|
||||||
OptSemi : ';' { () }
|
OptSemi : ';' { () }
|
||||||
@@ -95,10 +106,11 @@ ScDefs :: { [ScDef Name] }
|
|||||||
ScDefs : ScDef ';' ScDefs { $1 : $3 }
|
ScDefs : ScDef ';' ScDefs { $1 : $3 }
|
||||||
| ScDef ';' { [$1] }
|
| ScDef ';' { [$1] }
|
||||||
| ScDef { [$1] }
|
| ScDef { [$1] }
|
||||||
| {- epsilon -} { [] }
|
|
||||||
|
|
||||||
ScDef :: { ScDef Name }
|
ScDef :: { ScDef Name }
|
||||||
ScDef : Var ParList '=' Expr { ScDef $1 $2 $4 }
|
ScDef : Var ParList '=' Expr { ScDef $1 $2 $4 }
|
||||||
|
-- hack to allow constructors to be compiled into scs
|
||||||
|
| Con ParList '=' Expr { ScDef $1 $2 $4 }
|
||||||
|
|
||||||
Type :: { Type }
|
Type :: { Type }
|
||||||
Type : Type1 { $1 }
|
Type : Type1 { $1 }
|
||||||
@@ -148,22 +160,15 @@ Alters : Alter ';' Alters { $1 : $3 }
|
|||||||
| Alter { [$1] }
|
| Alter { [$1] }
|
||||||
|
|
||||||
Alter :: { Alter Name }
|
Alter :: { Alter Name }
|
||||||
Alter : litint ParList '->' Expr { Alter (AltData $1) $2 $4 }
|
Alter : alttag ParList '->' Expr { Alter (AltTag $1) $2 $4 }
|
||||||
|
| Con ParList '->' Expr { Alter (AltData $1) $2 $4 }
|
||||||
|
|
||||||
Expr1 :: { Expr Name }
|
Expr1 :: { Expr Name }
|
||||||
Expr1 : litint { Lit $ IntL $1 }
|
Expr1 : litint { Lit $ IntL $1 }
|
||||||
| Id { Var $1 }
|
| Id { Var $1 }
|
||||||
| PackCon { $1 }
|
| PackCon { $1 }
|
||||||
| ExprPragma { $1 }
|
|
||||||
| '(' Expr ')' { $2 }
|
| '(' Expr ')' { $2 }
|
||||||
|
|
||||||
ExprPragma :: { Expr Name }
|
|
||||||
ExprPragma : '{-#' Words '#-}' {% exprPragma $2 }
|
|
||||||
|
|
||||||
Words :: { [String] }
|
|
||||||
Words : word Words { T.unpack $1 : $2 }
|
|
||||||
| word { [T.unpack $1] }
|
|
||||||
|
|
||||||
PackCon :: { Expr Name }
|
PackCon :: { Expr Name }
|
||||||
PackCon : pack '{' litint litint '}' { Con $3 $4 }
|
PackCon : pack '{' litint litint '}' { Con $3 $4 }
|
||||||
|
|
||||||
@@ -189,34 +194,23 @@ Con : '(' consym ')' { $2 }
|
|||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
parseError :: [Located CoreToken] -> RLPC SrcError a
|
parseError :: [Located CoreToken] -> RLPC a
|
||||||
parseError (Located y x l _ : _) = addFatal err
|
parseError (Located y x l t : _) =
|
||||||
where err = SrcError
|
error $ show y <> ":" <> show x
|
||||||
{ _errSpan = (y,x,l)
|
<> ": parse error at token `" <> show t <> "'"
|
||||||
, _errSeverity = Error
|
|
||||||
, _errDiagnostic = SrcErrParse
|
|
||||||
}
|
|
||||||
|
|
||||||
parseTmp :: IO (Module Name)
|
{-# WARNING parseError "unimpl" #-}
|
||||||
parseTmp = do
|
|
||||||
s <- TIO.readFile "/tmp/t.hs"
|
|
||||||
case parse s of
|
|
||||||
Left e -> error (show e)
|
|
||||||
Right (ts,_) -> pure ts
|
|
||||||
where
|
|
||||||
parse = evalRLPC def . (lexCore >=> parseCore)
|
|
||||||
|
|
||||||
exprPragma :: [String] -> RLPC SrcError (Expr Name)
|
exprPragma :: [String] -> RLPC (Expr Name)
|
||||||
exprPragma ("AST" : e) = astPragma e
|
exprPragma ("AST" : e) = undefined
|
||||||
exprPragma _ = addFatal err
|
exprPragma _ = undefined
|
||||||
where err = SrcError
|
|
||||||
{ _errSpan = (0,0,0) -- TODO: span
|
|
||||||
, _errSeverity = Warning
|
|
||||||
, _errDiagnostic = SrcErrUnknownPragma "" -- TODO: missing pragma
|
|
||||||
}
|
|
||||||
|
|
||||||
astPragma :: [String] -> RLPC SrcError (Expr Name)
|
{-# WARNING exprPragma "unimpl" #-}
|
||||||
astPragma = pure . read . unwords
|
|
||||||
|
astPragma :: [String] -> RLPC (Expr Name)
|
||||||
|
astPragma _ = undefined
|
||||||
|
|
||||||
|
{-# WARNING astPragma "unimpl" #-}
|
||||||
|
|
||||||
insTypeSig :: (Hashable b) => (b, Type) -> Program b -> Program b
|
insTypeSig :: (Hashable b) => (b, Type) -> Program b -> Program b
|
||||||
insTypeSig ts = programTypeSigs %~ uncurry H.insert ts
|
insTypeSig ts = programTypeSigs %~ uncurry H.insert ts
|
||||||
@@ -230,8 +224,26 @@ insScDef sc = programScDefs %~ (sc:)
|
|||||||
singletonScDef :: (Hashable b) => ScDef b -> Program b
|
singletonScDef :: (Hashable b) => ScDef b -> Program b
|
||||||
singletonScDef sc = insScDef sc mempty
|
singletonScDef sc = insScDef sc mempty
|
||||||
|
|
||||||
parseCoreProgR :: [Located CoreToken] -> RLPC RlpcError Program'
|
parseCoreProgR :: [Located CoreToken] -> RLPC Program'
|
||||||
parseCoreProgR = liftRlpcErrs . parseCoreProg
|
parseCoreProgR = parseCoreProg
|
||||||
|
|
||||||
|
happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b
|
||||||
|
happyBind m k = m >>= k
|
||||||
|
|
||||||
|
happyPure :: a -> RLPC a
|
||||||
|
happyPure a = pure a
|
||||||
|
|
||||||
|
doTLPragma :: Pragma -> Program' -> RLPC Program'
|
||||||
|
-- TODO: warn unrecognised pragma
|
||||||
|
doTLPragma (Pragma []) p = pure p
|
||||||
|
|
||||||
|
doTLPragma (Pragma pr) p = case pr of
|
||||||
|
-- TODO: warn on overwrite
|
||||||
|
["PackData", n, readt -> t, readt -> a] ->
|
||||||
|
pure $ p & programDataTags . at n ?~ (t,a)
|
||||||
|
|
||||||
|
readt :: (Read a) => Text -> a
|
||||||
|
readt = read . T.unpack
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,14 @@ Description : Core ASTs and the like
|
|||||||
{-# LANGUAGE PatternSynonyms, OverloadedStrings #-}
|
{-# LANGUAGE PatternSynonyms, OverloadedStrings #-}
|
||||||
{-# LANGUAGE FunctionalDependencies #-}
|
{-# LANGUAGE FunctionalDependencies #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE DerivingStrategies, DerivingVia #-}
|
||||||
|
-- for recursion-schemes
|
||||||
|
{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable
|
||||||
|
, TemplateHaskell, TypeFamilies #-}
|
||||||
module Core.Syntax
|
module Core.Syntax
|
||||||
( Expr(..)
|
( Expr(..)
|
||||||
|
, ExprF(..)
|
||||||
|
, ExprF'(..)
|
||||||
, Type(..)
|
, Type(..)
|
||||||
, pattern TyInt
|
, pattern TyInt
|
||||||
, Lit(..)
|
, Lit(..)
|
||||||
@@ -24,9 +30,11 @@ module Core.Syntax
|
|||||||
, Module(..)
|
, Module(..)
|
||||||
, Program(..)
|
, Program(..)
|
||||||
, Program'
|
, Program'
|
||||||
|
, Pragma(..)
|
||||||
, unliftScDef
|
, unliftScDef
|
||||||
, programScDefs
|
, programScDefs
|
||||||
, programTypeSigs
|
, programTypeSigs
|
||||||
|
, programDataTags
|
||||||
, Expr'
|
, Expr'
|
||||||
, ScDef'
|
, ScDef'
|
||||||
, Alter'
|
, Alter'
|
||||||
@@ -40,11 +48,15 @@ import Data.Coerce
|
|||||||
import Data.Pretty
|
import Data.Pretty
|
||||||
import Data.List (intersperse)
|
import Data.List (intersperse)
|
||||||
import Data.Function ((&))
|
import Data.Function ((&))
|
||||||
|
import Data.Functor.Foldable
|
||||||
|
import Data.Functor.Foldable.TH (makeBaseFunctor)
|
||||||
import Data.String
|
import Data.String
|
||||||
|
import Data.HashMap.Strict (HashMap)
|
||||||
import Data.HashMap.Strict qualified as H
|
import Data.HashMap.Strict qualified as H
|
||||||
import Data.Hashable
|
import Data.Hashable
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Data.Char
|
import Data.Char
|
||||||
|
import GHC.Generics
|
||||||
-- Lift instances for the Core quasiquoters
|
-- Lift instances for the Core quasiquoters
|
||||||
import Language.Haskell.TH.Syntax (Lift)
|
import Language.Haskell.TH.Syntax (Lift)
|
||||||
import Lens.Micro.TH (makeLenses)
|
import Lens.Micro.TH (makeLenses)
|
||||||
@@ -99,11 +111,14 @@ data Alter b = Alter AltCon [b] (Expr b)
|
|||||||
|
|
||||||
deriving instance (Eq b) => Eq (Alter b)
|
deriving instance (Eq b) => Eq (Alter b)
|
||||||
|
|
||||||
|
newtype Pragma = Pragma [T.Text]
|
||||||
|
|
||||||
data Rec = Rec
|
data Rec = Rec
|
||||||
| NonRec
|
| NonRec
|
||||||
deriving (Show, Read, Eq, Lift)
|
deriving (Show, Read, Eq, Lift)
|
||||||
|
|
||||||
data AltCon = AltData Tag
|
data AltCon = AltData Name
|
||||||
|
| AltTag Tag
|
||||||
| AltLit Lit
|
| AltLit Lit
|
||||||
| Default
|
| Default
|
||||||
deriving (Show, Read, Eq, Lift)
|
deriving (Show, Read, Eq, Lift)
|
||||||
@@ -125,13 +140,20 @@ data Module b = Module (Maybe (Name, [Name])) (Program b)
|
|||||||
|
|
||||||
data Program b = Program
|
data Program b = Program
|
||||||
{ _programScDefs :: [ScDef b]
|
{ _programScDefs :: [ScDef b]
|
||||||
, _programTypeSigs :: H.HashMap b Type
|
, _programTypeSigs :: HashMap b Type
|
||||||
|
-- map constructors to their tag and arity
|
||||||
|
, _programDataTags :: HashMap b (Tag, Int)
|
||||||
}
|
}
|
||||||
deriving (Show, Lift)
|
deriving (Show, Lift, Generic)
|
||||||
|
deriving (Semigroup, Monoid)
|
||||||
|
via Generically (Program b)
|
||||||
|
|
||||||
makeLenses ''Program
|
makeLenses ''Program
|
||||||
|
makeBaseFunctor ''Expr
|
||||||
pure []
|
pure []
|
||||||
|
|
||||||
|
type ExprF' = ExprF Name
|
||||||
|
|
||||||
type Program' = Program Name
|
type Program' = Program Name
|
||||||
type Expr' = Expr Name
|
type Expr' = Expr Name
|
||||||
type ScDef' = ScDef Name
|
type ScDef' = ScDef Name
|
||||||
@@ -148,12 +170,6 @@ instance IsString Type where
|
|||||||
| otherwise = TyVar . fromString $ s
|
| otherwise = TyVar . fromString $ s
|
||||||
where (c:_) = s
|
where (c:_) = s
|
||||||
|
|
||||||
instance (Hashable b) => Semigroup (Program b) where
|
|
||||||
(<>) = undefined
|
|
||||||
|
|
||||||
instance (Hashable b) => Monoid (Program b) where
|
|
||||||
mempty = Program mempty mempty
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
class HasRHS s t a b | s -> a, t -> b, s b -> t, t a -> s where
|
class HasRHS s t a b | s -> a, t -> b, s b -> t, t a -> s where
|
||||||
@@ -187,3 +203,8 @@ instance HasLHS (ScDef b) (ScDef b) (b, [b]) (b, [b]) where
|
|||||||
(\ (ScDef n as _) -> (n,as))
|
(\ (ScDef n as _) -> (n,as))
|
||||||
(\ (ScDef _ _ e) (n',as') -> (ScDef n' as' e))
|
(\ (ScDef _ _ e) (n',as') -> (ScDef n' as' e))
|
||||||
|
|
||||||
|
instance HasLHS (Binding b) (Binding b) b b where
|
||||||
|
_lhs = lens
|
||||||
|
(\ (k := _) -> k)
|
||||||
|
(\ (_ := e) k' -> k' := e)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ module Core.TH
|
|||||||
( coreExpr
|
( coreExpr
|
||||||
, coreProg
|
, coreProg
|
||||||
, coreProgT
|
, coreProgT
|
||||||
, core
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
@@ -14,74 +13,38 @@ import Language.Haskell.TH
|
|||||||
import Language.Haskell.TH.Syntax hiding (Module)
|
import Language.Haskell.TH.Syntax hiding (Module)
|
||||||
import Language.Haskell.TH.Quote
|
import Language.Haskell.TH.Quote
|
||||||
import Control.Monad ((>=>))
|
import Control.Monad ((>=>))
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
import Control.Arrow ((>>>))
|
||||||
import Compiler.RLPC
|
import Compiler.RLPC
|
||||||
import Data.Default.Class (def)
|
import Data.Default.Class (def)
|
||||||
|
import Data.Text (Text)
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Core.Parse
|
import Core.Parse
|
||||||
import Core.Lex
|
import Core.Lex
|
||||||
|
import Core.Syntax
|
||||||
import Core.HindleyMilner (checkCoreProgR)
|
import Core.HindleyMilner (checkCoreProgR)
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: write in terms of a String -> QuasiQuoter
|
|
||||||
|
|
||||||
core :: QuasiQuoter
|
|
||||||
core = QuasiQuoter
|
|
||||||
{ quoteExp = qCore
|
|
||||||
, quotePat = error "core quasiquotes may only be used in expressions"
|
|
||||||
, quoteType = error "core quasiquotes may only be used in expressions"
|
|
||||||
, quoteDec = error "core quasiquotes may only be used in expressions"
|
|
||||||
}
|
|
||||||
|
|
||||||
coreProg :: QuasiQuoter
|
coreProg :: QuasiQuoter
|
||||||
coreProg = QuasiQuoter
|
coreProg = mkqq $ lexCoreR >=> parseCoreProgR
|
||||||
{ quoteExp = qCoreProg
|
|
||||||
, quotePat = error "core quasiquotes may only be used in expressions"
|
|
||||||
, quoteType = error "core quasiquotes may only be used in expressions"
|
|
||||||
, quoteDec = error "core quasiquotes may only be used in expressions"
|
|
||||||
}
|
|
||||||
|
|
||||||
coreExpr :: QuasiQuoter
|
coreExpr :: QuasiQuoter
|
||||||
coreExpr = QuasiQuoter
|
coreExpr = mkqq $ lexCoreR >=> parseCoreExpr
|
||||||
{ quoteExp = qCoreExpr
|
|
||||||
, quotePat = error "core quasiquotes may only be used in expressions"
|
|
||||||
, quoteType = error "core quasiquotes may only be used in expressions"
|
|
||||||
, quoteDec = error "core quasiquotes may only be used in expressions"
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | Type-checked @coreProg@
|
-- | Type-checked @coreProg@
|
||||||
coreProgT :: QuasiQuoter
|
coreProgT :: QuasiQuoter
|
||||||
coreProgT = QuasiQuoter
|
coreProgT = mkqq $ lexCoreR >=> parseCoreProgR >=> checkCoreProgR
|
||||||
{ quoteExp = qCoreProgT
|
|
||||||
|
mkqq :: (Lift a) => (Text -> RLPC a) -> QuasiQuoter
|
||||||
|
mkqq p = QuasiQuoter
|
||||||
|
{ quoteExp = mkq p
|
||||||
, quotePat = error "core quasiquotes may only be used in expressions"
|
, quotePat = error "core quasiquotes may only be used in expressions"
|
||||||
, quoteType = error "core quasiquotes may only be used in expressions"
|
, quoteType = error "core quasiquotes may only be used in expressions"
|
||||||
, quoteDec = error "core quasiquotes may only be used in expressions"
|
, quoteDec = error "core quasiquotes may only be used in expressions"
|
||||||
}
|
}
|
||||||
|
|
||||||
qCore :: String -> Q Exp
|
mkq :: (Lift a) => (Text -> RLPC a) -> String -> Q Exp
|
||||||
qCore s = case parse (T.pack s) of
|
mkq parse s = case evalRLPC def (parse $ T.pack s) of
|
||||||
Left e -> error (show e)
|
(Just a, _) -> lift a
|
||||||
Right (m,ts) -> lift m
|
(Nothing, _) -> error "todo: aaahhbbhjhbdjhabsjh"
|
||||||
where
|
|
||||||
parse = evalRLPC def . (lexCore >=> parseCore)
|
|
||||||
|
|
||||||
qCoreExpr :: String -> Q Exp
|
|
||||||
qCoreExpr s = case parseExpr (T.pack s) of
|
|
||||||
Left e -> error (show e)
|
|
||||||
Right (m,ts) -> lift m
|
|
||||||
where
|
|
||||||
parseExpr = evalRLPC def . (lexCore >=> parseCoreExpr)
|
|
||||||
|
|
||||||
qCoreProg :: String -> Q Exp
|
|
||||||
qCoreProg s = case parse (T.pack s) of
|
|
||||||
Left e -> error (show e)
|
|
||||||
Right (m,ts) -> lift m
|
|
||||||
where
|
|
||||||
parse = evalRLPC def . (lexCoreR >=> parseCoreProgR)
|
|
||||||
|
|
||||||
qCoreProgT :: String -> Q Exp
|
|
||||||
qCoreProgT s = case parse (T.pack s) of
|
|
||||||
Left e -> error (show e)
|
|
||||||
Right (m,_) -> lift m
|
|
||||||
where
|
|
||||||
parse = evalRLPC def . (lexCoreR >=> parseCoreProgR >=> checkCoreProgR)
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
-- for recursion schemes
|
|
||||||
{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
|
|
||||||
-- for recursion schemes
|
|
||||||
{-# LANGUAGE TemplateHaskell, TypeFamilies #-}
|
|
||||||
|
|
||||||
module Core.Utils
|
module Core.Utils
|
||||||
( bindersOf
|
( programRhss
|
||||||
, rhssOf
|
, programGlobals
|
||||||
, isAtomic
|
, isAtomic
|
||||||
-- , insertModule
|
-- , insertModule
|
||||||
, extractProgram
|
, extractProgram
|
||||||
, freeVariables
|
, freeVariables
|
||||||
, ExprF(..)
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
@@ -23,13 +17,11 @@ import Lens.Micro
|
|||||||
import GHC.Exts (IsList(..))
|
import GHC.Exts (IsList(..))
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
bindersOf :: (IsList l, Item l ~ b) => [Binding b] -> l
|
programGlobals :: Traversal' (Program b) b
|
||||||
bindersOf bs = fromList $ fmap f bs
|
programGlobals = programScDefs . each . _lhs . _1
|
||||||
where f (k := _) = k
|
|
||||||
|
|
||||||
rhssOf :: (IsList l, Item l ~ Expr b) => [Binding b] -> l
|
programRhss :: Traversal' (Program b) (Expr b)
|
||||||
rhssOf = fromList . fmap f
|
programRhss = programScDefs . each . _rhs
|
||||||
where f (_ := v) = v
|
|
||||||
|
|
||||||
isAtomic :: Expr b -> Bool
|
isAtomic :: Expr b -> Bool
|
||||||
isAtomic (Var _) = True
|
isAtomic (Var _) = True
|
||||||
@@ -47,8 +39,6 @@ extractProgram (Module _ p) = p
|
|||||||
|
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
makeBaseFunctor ''Expr
|
|
||||||
|
|
||||||
freeVariables :: Expr' -> Set Name
|
freeVariables :: Expr' -> Set Name
|
||||||
freeVariables = cata go
|
freeVariables = cata go
|
||||||
where
|
where
|
||||||
@@ -57,8 +47,8 @@ freeVariables = cata go
|
|||||||
-- TODO: collect free vars in rhss of bs
|
-- TODO: collect free vars in rhss of bs
|
||||||
go (LetF _ bs e) = (e `S.union` esFree) `S.difference` ns
|
go (LetF _ bs e) = (e `S.union` esFree) `S.difference` ns
|
||||||
where
|
where
|
||||||
es = rhssOf bs :: [Expr']
|
es = bs ^.. each . _rhs :: [Expr']
|
||||||
ns = bindersOf bs
|
ns = S.fromList $ bs ^.. each . _lhs
|
||||||
-- TODO: this feels a little wrong. maybe a different scheme is
|
-- TODO: this feels a little wrong. maybe a different scheme is
|
||||||
-- appropriate
|
-- appropriate
|
||||||
esFree = foldMap id $ freeVariables <$> es
|
esFree = foldMap id $ freeVariables <$> es
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE ImplicitParams #-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
module Core2Core
|
module Core2Core
|
||||||
( core2core
|
( core2core
|
||||||
@@ -15,11 +16,12 @@ import Data.Set (Set)
|
|||||||
import Data.Set qualified as S
|
import Data.Set qualified as S
|
||||||
import Data.List
|
import Data.List
|
||||||
import Control.Monad.Writer
|
import Control.Monad.Writer
|
||||||
import Control.Monad.State
|
import Control.Monad.State.Lazy
|
||||||
import Control.Arrow ((>>>))
|
import Control.Arrow ((>>>))
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
|
import Data.HashMap.Strict (HashMap)
|
||||||
import Numeric (showHex)
|
import Numeric (showHex)
|
||||||
import Lens.Micro
|
import Lens.Micro.Platform
|
||||||
import Core.Syntax
|
import Core.Syntax
|
||||||
import Core.Utils
|
import Core.Utils
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
@@ -28,22 +30,35 @@ core2core :: Program' -> Program'
|
|||||||
core2core p = undefined
|
core2core p = undefined
|
||||||
|
|
||||||
gmPrep :: Program' -> Program'
|
gmPrep :: Program' -> Program'
|
||||||
gmPrep p = p' & programScDefs %~ (<>caseScs)
|
gmPrep p = p & appFloater (floatNonStrictCases globals)
|
||||||
|
& tagData
|
||||||
where
|
where
|
||||||
rhss :: Applicative f => (Expr z -> f (Expr z)) -> Program z -> f (Program z)
|
|
||||||
rhss = programScDefs . each . _rhs
|
|
||||||
globals = p ^.. programScDefs . each . _lhs . _1
|
globals = p ^.. programScDefs . each . _lhs . _1
|
||||||
& S.fromList
|
& S.fromList
|
||||||
|
|
||||||
-- i kinda don't like that we're calling floatNonStrictCases twice tbh
|
tagData :: Program' -> Program'
|
||||||
p' = p & rhss %~ fst . runFloater . floatNonStrictCases globals
|
tagData p = let ?dt = p ^. programDataTags
|
||||||
caseScs = (p ^.. rhss)
|
in p & programRhss %~ cata go where
|
||||||
<&> snd . runFloater . floatNonStrictCases globals
|
go :: (?dt :: HashMap Name (Tag, Int)) => ExprF' Expr' -> Expr'
|
||||||
& mconcat
|
go (CaseF e as) = Case e (tagAlts <$> as)
|
||||||
|
go x = embed x
|
||||||
|
|
||||||
|
tagAlts :: (?dt :: HashMap Name (Tag, Int)) => Alter' -> Alter'
|
||||||
|
tagAlts (Alter (AltData c) bs e) = Alter (AltTag tag) bs e
|
||||||
|
where tag = case ?dt ^. at c of
|
||||||
|
Just (t,_) -> t
|
||||||
|
-- TODO: errorful
|
||||||
|
Nothing -> error $ "unknown constructor " <> show c
|
||||||
|
tagAlts x = x
|
||||||
|
|
||||||
-- | Auxilary type used in @floatNonSrictCases@
|
-- | Auxilary type used in @floatNonSrictCases@
|
||||||
type Floater = StateT [Name] (Writer [ScDef'])
|
type Floater = StateT [Name] (Writer [ScDef'])
|
||||||
|
|
||||||
|
appFloater :: (Expr' -> Floater Expr') -> Program' -> Program'
|
||||||
|
appFloater fl p = p & traverseOf programRhss fl
|
||||||
|
& runFloater
|
||||||
|
& \ (me,floats) -> me & programScDefs %~ (<>floats)
|
||||||
|
|
||||||
runFloater :: Floater a -> (a, [ScDef'])
|
runFloater :: Floater a -> (a, [ScDef'])
|
||||||
runFloater = flip evalStateT ns >>> runWriter
|
runFloater = flip evalStateT ns >>> runWriter
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -661,7 +661,8 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil
|
|||||||
compileC _ (Con t n) = [PushConstr t n]
|
compileC _ (Con t n) = [PushConstr t n]
|
||||||
|
|
||||||
compileC _ (Case _ _) =
|
compileC _ (Case _ _) =
|
||||||
error "case expressions may not appear in non-strict contexts :/"
|
error "GM compiler found a non-strict case expression, which should\
|
||||||
|
\ have been floated by Core2Core.gmPrep. This is a bug!"
|
||||||
|
|
||||||
compileC _ _ = error "yet to be implemented!"
|
compileC _ _ = error "yet to be implemented!"
|
||||||
|
|
||||||
@@ -724,12 +725,16 @@ buildInitialHeap (view programScDefs -> ss) = mapAccumL allocateSc mempty compil
|
|||||||
compileD g as = fmap (compileA g) as
|
compileD g as = fmap (compileA g) as
|
||||||
|
|
||||||
compileA :: Env -> Alter' -> (Tag, Code)
|
compileA :: Env -> Alter' -> (Tag, Code)
|
||||||
compileA g (Alter (AltData t) as e) = (t, [Split n] <> c <> [Slide n])
|
compileA g (Alter (AltTag t) as e) = (t, [Split n] <> c <> [Slide n])
|
||||||
where
|
where
|
||||||
n = length as
|
n = length as
|
||||||
binds = (NameKey <$> as) `zip` [0..]
|
binds = (NameKey <$> as) `zip` [0..]
|
||||||
g' = binds ++ argOffset n g
|
g' = binds ++ argOffset n g
|
||||||
c = compileE g' e
|
c = compileE g' e
|
||||||
|
compileA _ (Alter _ as e) = error "GM.compileA found an untagged\
|
||||||
|
\ constructor, which should have\
|
||||||
|
\ been handled by Core2Core.gmPrep.\
|
||||||
|
\ This is a bug!"
|
||||||
|
|
||||||
inlineOp1 :: Env -> Instr -> Expr' -> Code
|
inlineOp1 :: Env -> Instr -> Expr' -> Code
|
||||||
inlineOp1 g i a = compileE g a <> [i]
|
inlineOp1 g i a = compileE g a <> [i]
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ module Rlp.Lex
|
|||||||
, RlpToken(..)
|
, RlpToken(..)
|
||||||
, Located(..)
|
, Located(..)
|
||||||
, lexToken
|
, lexToken
|
||||||
|
, lexStream
|
||||||
, lexDebug
|
, lexDebug
|
||||||
, lexCont
|
, lexCont
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
import Codec.Binary.UTF8.String (encodeChar)
|
import Codec.Binary.UTF8.String (encodeChar)
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
|
import Control.Monad.Errorful
|
||||||
import Core.Syntax (Name)
|
import Core.Syntax (Name)
|
||||||
import Data.Functor.Identity
|
import Data.Functor.Identity
|
||||||
import Data.Char (digitToInt)
|
import Data.Char (digitToInt)
|
||||||
@@ -52,6 +54,7 @@ $asciisym = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:]
|
|||||||
|
|
||||||
@reservedname =
|
@reservedname =
|
||||||
case|data|do|import|in|let|letrec|module|of|where
|
case|data|do|import|in|let|letrec|module|of|where
|
||||||
|
|infixr|infixl|infix
|
||||||
|
|
||||||
@reservedop =
|
@reservedop =
|
||||||
"=" | \\ | "->" | "|"
|
"=" | \\ | "->" | "|"
|
||||||
@@ -123,6 +126,9 @@ lexReservedName = \case
|
|||||||
"of" -> TokenOf
|
"of" -> TokenOf
|
||||||
"let" -> TokenLet
|
"let" -> TokenLet
|
||||||
"in" -> TokenIn
|
"in" -> TokenIn
|
||||||
|
"infix" -> TokenInfix
|
||||||
|
"infixl" -> TokenInfixL
|
||||||
|
"infixr" -> TokenInfixR
|
||||||
|
|
||||||
lexReservedOp :: Text -> RlpToken
|
lexReservedOp :: Text -> RlpToken
|
||||||
lexReservedOp = \case
|
lexReservedOp = \case
|
||||||
@@ -203,13 +209,6 @@ alexEOF = do
|
|||||||
inp <- getInput
|
inp <- getInput
|
||||||
pure (Located undefined TokenEOF)
|
pure (Located undefined TokenEOF)
|
||||||
|
|
||||||
execP :: P a -> ParseState -> Maybe a
|
|
||||||
execP p st = runP p st & snd
|
|
||||||
|
|
||||||
execP' :: P a -> Text -> Maybe a
|
|
||||||
execP' p s = execP p st where
|
|
||||||
st = initParseState s
|
|
||||||
|
|
||||||
initParseState :: Text -> ParseState
|
initParseState :: Text -> ParseState
|
||||||
initParseState s = ParseState
|
initParseState s = ParseState
|
||||||
{ _psLayoutStack = []
|
{ _psLayoutStack = []
|
||||||
@@ -228,6 +227,10 @@ initAlexInput s = AlexInput
|
|||||||
, _aiPos = (1,1)
|
, _aiPos = (1,1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runP' :: P a -> Text -> (ParseState, [MsgEnvelope RlpParseError], Maybe a)
|
||||||
|
runP' p s = runP p st where
|
||||||
|
st = initParseState s
|
||||||
|
|
||||||
lexToken :: P (Located RlpToken)
|
lexToken :: P (Located RlpToken)
|
||||||
lexToken = do
|
lexToken = do
|
||||||
inp <- getInput
|
inp <- getInput
|
||||||
@@ -242,6 +245,7 @@ lexToken = do
|
|||||||
AlexToken inp' l act -> do
|
AlexToken inp' l act -> do
|
||||||
psInput .= inp'
|
psInput .= inp'
|
||||||
act inp l
|
act inp l
|
||||||
|
AlexError inp' -> addFatalHere 1 RlpParErrLexical
|
||||||
|
|
||||||
lexCont :: (Located RlpToken -> P a) -> P a
|
lexCont :: (Located RlpToken -> P a) -> P a
|
||||||
lexCont = (lexToken >>=)
|
lexCont = (lexToken >>=)
|
||||||
@@ -260,7 +264,7 @@ lexDebug k = do
|
|||||||
k t
|
k t
|
||||||
|
|
||||||
lexTest :: Text -> Maybe [RlpToken]
|
lexTest :: Text -> Maybe [RlpToken]
|
||||||
lexTest s = execP' lexStream s
|
lexTest s = runP' lexStream s ^. _3
|
||||||
|
|
||||||
indentLevel :: P Int
|
indentLevel :: P Int
|
||||||
indentLevel = do
|
indentLevel = do
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ module Rlp.Parse
|
|||||||
( parseRlpProg
|
( parseRlpProg
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
import Compiler.RlpcError
|
||||||
import Rlp.Lex
|
import Rlp.Lex
|
||||||
import Rlp.Syntax
|
import Rlp.Syntax
|
||||||
import Rlp.Parse.Types
|
import Rlp.Parse.Types
|
||||||
@@ -14,6 +15,7 @@ import Lens.Micro.Platform ()
|
|||||||
import Data.List.Extra
|
import Data.List.Extra
|
||||||
import Data.Fix
|
import Data.Fix
|
||||||
import Data.Functor.Const
|
import Data.Functor.Const
|
||||||
|
import Data.Text qualified as T
|
||||||
}
|
}
|
||||||
|
|
||||||
%name parseRlpProg StandaloneProgram
|
%name parseRlpProg StandaloneProgram
|
||||||
@@ -161,16 +163,19 @@ mkProgram ds = do
|
|||||||
pure $ RlpProgram (associate pt <$> ds)
|
pure $ RlpProgram (associate pt <$> ds)
|
||||||
|
|
||||||
parseError :: Located RlpToken -> P a
|
parseError :: Located RlpToken -> P a
|
||||||
parseError = error . show
|
parseError (Located ((l,c),s) t) = addFatal $
|
||||||
|
errorMsg (SrcSpan l c s) RlpParErrUnexpectedToken
|
||||||
|
|
||||||
mkInfixD :: Assoc -> Int -> Name -> P PartialDecl'
|
mkInfixD :: Assoc -> Int -> Name -> P PartialDecl'
|
||||||
mkInfixD a p n = do
|
mkInfixD a p n = do
|
||||||
let opl :: Lens' ParseState (Maybe OpInfo)
|
let opl :: Lens' ParseState (Maybe OpInfo)
|
||||||
opl = psOpTable . at n
|
opl = psOpTable . at n
|
||||||
opl <~ (use opl >>= \case
|
opl <~ (use opl >>= \case
|
||||||
-- TODO: non-fatal error
|
Just o -> addWoundHere l e >> pure (Just o) where
|
||||||
Just o -> pure (Just o)
|
e = RlpParErrDuplicateInfixD n
|
||||||
|
l = T.length n
|
||||||
Nothing -> pure (Just (a,p))
|
Nothing -> pure (Just (a,p))
|
||||||
)
|
)
|
||||||
pure $ InfixD a p n
|
pure $ InfixD a p n
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,47 @@
|
|||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-}
|
{-# LANGUAGE ImplicitParams, ViewPatterns, PatternSynonyms #-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
module Rlp.Parse.Types where
|
module Rlp.Parse.Types
|
||||||
|
( LexerAction
|
||||||
|
, MsgEnvelope(..)
|
||||||
|
, RlpcError(..)
|
||||||
|
, AlexInput(..)
|
||||||
|
, Position(..)
|
||||||
|
, RlpToken(..)
|
||||||
|
, P(..)
|
||||||
|
, ParseState(..)
|
||||||
|
, psLayoutStack
|
||||||
|
, psLexState
|
||||||
|
, psInput
|
||||||
|
, psOpTable
|
||||||
|
, Layout(..)
|
||||||
|
, Located(..)
|
||||||
|
, OpTable
|
||||||
|
, OpInfo
|
||||||
|
, RlpParseError(..)
|
||||||
|
, PartialDecl'
|
||||||
|
, Partial(..)
|
||||||
|
, pL, pR
|
||||||
|
, PartialE
|
||||||
|
, pattern WithInfo
|
||||||
|
, opInfoOrDef
|
||||||
|
, PartialExpr'
|
||||||
|
, aiPrevChar
|
||||||
|
, aiSource
|
||||||
|
, aiBytes
|
||||||
|
, aiPos
|
||||||
|
, addFatal
|
||||||
|
, addWound
|
||||||
|
, addFatalHere
|
||||||
|
, addWoundHere
|
||||||
|
)
|
||||||
|
where
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
import Core.Syntax (Name)
|
import Core.Syntax (Name)
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.State.Class
|
import Control.Monad.State.Strict
|
||||||
|
import Control.Monad.Errorful
|
||||||
|
import Compiler.RlpcError
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Fix
|
import Data.Fix
|
||||||
@@ -34,6 +70,12 @@ type Position =
|
|||||||
, Int -- column
|
, Int -- column
|
||||||
)
|
)
|
||||||
|
|
||||||
|
posLine :: Lens' Position Int
|
||||||
|
posLine = _1
|
||||||
|
|
||||||
|
posColumn :: Lens' Position Int
|
||||||
|
posColumn = _2
|
||||||
|
|
||||||
data RlpToken
|
data RlpToken
|
||||||
-- literals
|
-- literals
|
||||||
= TokenLitInt Int
|
= TokenLitInt Int
|
||||||
@@ -71,24 +113,34 @@ data RlpToken
|
|||||||
| TokenEOF
|
| TokenEOF
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
newtype P a = P { runP :: ParseState -> (ParseState, Maybe a) }
|
newtype P a = P {
|
||||||
|
runP :: ParseState
|
||||||
|
-> (ParseState, [MsgEnvelope RlpParseError], Maybe a)
|
||||||
|
}
|
||||||
deriving (Functor)
|
deriving (Functor)
|
||||||
|
|
||||||
instance Applicative P where
|
instance Applicative P where
|
||||||
pure a = P $ \st -> (st,Just a)
|
pure a = P $ \st -> (st, [], pure a)
|
||||||
liftA2 = liftM2
|
liftA2 = liftM2
|
||||||
|
|
||||||
instance Monad P where
|
instance Monad P where
|
||||||
p >>= k = P $ \st ->
|
p >>= k = P $ \st ->
|
||||||
let (st',a) = runP p st
|
let (st',es,ma) = runP p st
|
||||||
in case a of
|
in case ma of
|
||||||
Just x -> runP (k x) st'
|
Just a -> runP (k a) st'
|
||||||
Nothing -> (st', Nothing)
|
& _2 %~ (es<>)
|
||||||
|
Nothing -> (st',es,Nothing)
|
||||||
|
|
||||||
|
{-# INLINE (>>=) #-}
|
||||||
|
|
||||||
instance MonadState ParseState P where
|
instance MonadState ParseState P where
|
||||||
state f = P $ \st ->
|
state f = P $ \st ->
|
||||||
let (a,st') = f st
|
let (a,st') = f st
|
||||||
in (st', Just a)
|
in (st', [], Just a)
|
||||||
|
|
||||||
|
instance MonadErrorful (MsgEnvelope RlpParseError) P where
|
||||||
|
addWound e = P $ \st -> (st, [e], Just ())
|
||||||
|
addFatal e = P $ \st -> (st, [e], Nothing)
|
||||||
|
|
||||||
data ParseState = ParseState
|
data ParseState = ParseState
|
||||||
{ _psLayoutStack :: [Layout]
|
{ _psLayoutStack :: [Layout]
|
||||||
@@ -111,11 +163,14 @@ type OpInfo = (Assoc, Int)
|
|||||||
-- data WithLocation a = WithLocation [String] a
|
-- data WithLocation a = WithLocation [String] a
|
||||||
|
|
||||||
data RlpParseError = RlpParErrOutOfBoundsPrecedence Int
|
data RlpParseError = RlpParErrOutOfBoundsPrecedence Int
|
||||||
| RlpParErrDuplicateInfixD
|
| RlpParErrDuplicateInfixD Name
|
||||||
deriving (Eq, Ord, Show)
|
| RlpParErrLexical
|
||||||
|
| RlpParErrUnexpectedToken
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
instance IsRlpcError RlpParseError where
|
||||||
|
|
||||||
----------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- absolute psycho shit (partial ASTs)
|
-- absolute psycho shit (partial ASTs)
|
||||||
|
|
||||||
type PartialDecl' = Decl (Const PartialExpr') Name
|
type PartialDecl' = Decl (Const PartialExpr') Name
|
||||||
@@ -161,3 +216,27 @@ type PartialExpr' = Fix Partial
|
|||||||
makeLenses ''AlexInput
|
makeLenses ''AlexInput
|
||||||
makeLenses ''ParseState
|
makeLenses ''ParseState
|
||||||
|
|
||||||
|
addWoundHere :: Int -> RlpParseError -> P ()
|
||||||
|
addWoundHere l e = P $ \st ->
|
||||||
|
let e' = MsgEnvelope
|
||||||
|
{ _msgSpan = let pos = psInput . aiPos
|
||||||
|
in SrcSpan (st ^. pos . posLine)
|
||||||
|
(st ^. pos . posColumn)
|
||||||
|
l
|
||||||
|
, _msgDiagnostic = e
|
||||||
|
, _msgSeverity = SevError
|
||||||
|
}
|
||||||
|
in (st, [e'], Just ())
|
||||||
|
|
||||||
|
addFatalHere :: Int -> RlpParseError -> P a
|
||||||
|
addFatalHere l e = P $ \st ->
|
||||||
|
let e' = MsgEnvelope
|
||||||
|
{ _msgSpan = let pos = psInput . aiPos
|
||||||
|
in SrcSpan (st ^. pos . posLine)
|
||||||
|
(st ^. pos . posColumn)
|
||||||
|
l
|
||||||
|
, _msgDiagnostic = e
|
||||||
|
, _msgSeverity = SevError
|
||||||
|
}
|
||||||
|
in (st, [e'], Nothing)
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,25 @@ spec = do
|
|||||||
let e = [coreExpr|3|]
|
let e = [coreExpr|3|]
|
||||||
in check' [] (TyCon "Bool") e `shouldSatisfy` isLeft
|
in check' [] (TyCon "Bool") e `shouldSatisfy` isLeft
|
||||||
|
|
||||||
infer' :: Context' -> Expr' -> Either TypeError Type
|
it "should infer `fix ((+#) 1)` :: Int" $
|
||||||
infer' g e = fmap fst . runErrorful $ infer g e
|
let g = [ ("fix", ("a" :-> "a") :-> "a")
|
||||||
|
, ("+#", TyInt :-> TyInt :-> TyInt) ]
|
||||||
|
e = [coreExpr|fix ((+#) 1)|]
|
||||||
|
in infer' g e `shouldBe` Right TyInt
|
||||||
|
|
||||||
check' :: Context' -> Type -> Expr' -> Either TypeError ()
|
it "should infer mutually recursively defined lists" $
|
||||||
check' g t e = fmap fst . runErrorful $ check g t e
|
let g = [ ("cons", TyInt :-> TyCon "IntList" :-> TyCon "IntList") ]
|
||||||
|
e :: Expr'
|
||||||
|
e = [coreExpr|letrec { as = cons 1 bs; bs = cons 2 as } in as|]
|
||||||
|
in infer' g e `shouldBe` Right (TyCon "IntList")
|
||||||
|
|
||||||
|
infer' :: Context' -> Expr' -> Either [TypeError] Type
|
||||||
|
infer' g e = case runErrorful $ infer g e of
|
||||||
|
(Just t, _) -> Right t
|
||||||
|
(Nothing, es) -> Left es
|
||||||
|
|
||||||
|
check' :: Context' -> Type -> Expr' -> Either [TypeError] ()
|
||||||
|
check' g t e = case runErrorful $ check g t e of
|
||||||
|
(Just t, _) -> Right ()
|
||||||
|
(Nothing, es) -> Left es
|
||||||
|
|
||||||
|
|||||||
@@ -27,15 +27,22 @@ spec = do
|
|||||||
in coreRes `shouldBe` arithRes
|
in coreRes `shouldBe` arithRes
|
||||||
|
|
||||||
describe "test programs" $ do
|
describe "test programs" $ do
|
||||||
it "fac 3" $ do
|
it "fac 3" $
|
||||||
resultOf Ex.fac3 `shouldBe` Just (NNum 6)
|
resultOf Ex.fac3 `shouldBe` Just (NNum 6)
|
||||||
|
|
||||||
it "sum [1,2,3]" $ do
|
it "sum [1,2,3]" $
|
||||||
resultOf Ex.sumList `shouldBe` Just (NNum 6)
|
resultOf Ex.sumList `shouldBe` Just (NNum 6)
|
||||||
|
|
||||||
it "k 3 ((/#) 1 0)" $ do
|
it "k 3 ((/#) 1 0)" $
|
||||||
resultOf Ex.constDivZero `shouldBe` Just (NNum 3)
|
resultOf Ex.constDivZero `shouldBe` Just (NNum 3)
|
||||||
|
|
||||||
it "id (case ... of { ... })" $ do
|
it "id (case ... of { ... })" $
|
||||||
resultOf Ex.idCase `shouldBe` Just (NNum 5)
|
resultOf Ex.idCase `shouldBe` Just (NNum 5)
|
||||||
|
|
||||||
|
it "bool pattern matching with named constructors" $
|
||||||
|
resultOf Ex.namedBoolCase `shouldBe` Just (NNum 123)
|
||||||
|
|
||||||
|
it "list pattern matching with named constructors" $
|
||||||
|
resultOf Ex.namedConsCase `shouldBe` Just (NNum 6)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user