forked from glen/fostr
feat: Type-dependent Haskell code generation
Caveat: type is still not being assigned for the Sequence() constructor. Also fixes the parsing of literal strings (whitespace just after the opening quote was being ignored, and was ambiguous just before the opening quote).
This commit is contained in:
parent
5cd75b8177
commit
804a00902a
@ -11,7 +11,8 @@ language as possible to work in, given that I inevitably will be doing a
|
||||
bunch of coding. The language will be centrally organized around the
|
||||
concept of "streams" (somewhat in the spirit of
|
||||
[streem](https://github.com/matz/streem) and/or
|
||||
[Orc](http://orc.csres.utexas.edu/index.shtml)). In fact all higher-type
|
||||
[Orc](http://orc.csres.utexas.edu/index.shtml), or to a lesser extent,
|
||||
[Sisal-is](https://github.com/parsifal-47/sisal-is)). In fact all higher-type
|
||||
entities will be cast in terms of streams, or in slogan form, "++f++unctions
|
||||
and (binary) ++o++perators are ++str++eams" (hence the name "fostr").
|
||||
|
||||
|
@ -14,7 +14,7 @@ lexical sorts
|
||||
|
||||
lexical syntax
|
||||
|
||||
STRING_LITERAL = ~[\']*
|
||||
STRING_LITERAL = "'"~[\']*"'"
|
||||
|
||||
context-free sorts
|
||||
|
||||
@ -38,7 +38,7 @@ context-free syntax
|
||||
TermEx.Terminate = <<Ex>;>
|
||||
|
||||
Ex.Int = INT
|
||||
Ex.LitString = <'<STRING_LITERAL>'>
|
||||
Ex.LitString = STRING_LITERAL
|
||||
Ex.Stream = <stream>
|
||||
Ex.Sum = <<Ex> + <Ex>> {left}
|
||||
Ex.Gets = [[Ex] << [Ex]] {left}
|
||||
|
@ -1,15 +1,15 @@
|
||||
module basic
|
||||
language fostr
|
||||
|
||||
|
||||
test hw1_type [[
|
||||
[[stream]] << [['Hello, world!']]
|
||||
[[stream]] << [['Hello, world! ']] << [[3+2]] << ' times.'
|
||||
]]
|
||||
run get-type on #1 to STREAM()
|
||||
run get-type on #2 to STRING()
|
||||
run get-type on #3 to INT()
|
||||
run get-type to STREAM()
|
||||
/** writes
|
||||
Hello, world!**/
|
||||
Hello, world! 5 times.**/
|
||||
|
||||
/** md
|
||||
Title: A whirlwind tour of fostr
|
||||
|
@ -1,15 +1,25 @@
|
||||
module haskell
|
||||
imports libstrategolib signatures/- util
|
||||
imports libstrategolib signatures/- util analysis
|
||||
rules
|
||||
/* Approach: Generate code from the bottom up.
|
||||
At every node, we create a pair of the implementation and
|
||||
necessary preamble of IO actions.
|
||||
We concatenate preambles as we go up.
|
||||
Finally, at the toplevel we emit the preamble before returning the
|
||||
final value.
|
||||
/* Approach:
|
||||
A) We will define a local transformation taking a term with value strings
|
||||
at each child to a value string for the node.
|
||||
B) We will append IO actions needed to set up for the value progressively
|
||||
to a Preactions rule (mapping () to the list of actions). There will
|
||||
be a utility `add-preaction` to append a new clause to value of this
|
||||
rule.
|
||||
C) We will use bottomup-para to traverse the full AST with the
|
||||
transformation from A so that we have access to the original expression
|
||||
(and get get the Statix-associated type when we need to).
|
||||
Hence the transformation in (A) must actually take a pair of
|
||||
an (original) term and a term with value strings at each child,
|
||||
and be certain to return a value string.
|
||||
|
||||
Finally, at the toplevel we emit the result of <Preactions>() before
|
||||
returning the final value.
|
||||
*/
|
||||
|
||||
hs: TopLevel((c,p)) -> $[import System.IO
|
||||
hs: (_, TopLevel(val)) -> $[import System.IO
|
||||
data IOStream = StdIO
|
||||
|
||||
gets :: Show b => a -> b -> IO a
|
||||
@ -17,25 +27,35 @@ rules
|
||||
putStr(show d)
|
||||
return s
|
||||
|
||||
getsStr :: a -> String -> IO a
|
||||
getsStr s d = do
|
||||
putStr(d)
|
||||
return s
|
||||
|
||||
main = do
|
||||
[p]return [c]]
|
||||
[<Preactions>()]return [val]]
|
||||
|
||||
hs: Stream() -> ("StdIO", "")
|
||||
hs: Int(x) -> (x, "")
|
||||
hs: LitString(x)
|
||||
-> ($["[<string-as-chars(escape-chars(HaskellEscape))>x]"], "")
|
||||
hs: Sum( (c, p), (d, q)) -> ($[([c] + [d])], <conc-strings>(p,q))
|
||||
hs: (_, Stream()) -> "StdIO"
|
||||
hs: (_, Int(x)) -> x
|
||||
hs: (_, LitString(x)) -> <haskLitString>x
|
||||
hs: (_, Sum(x, y)) -> $[([x] + [y])]
|
||||
|
||||
hs: Gets((c, p), (d, q)) -> <hsget>(c,d,<conc-strings>(p,q),<newname>"fosgt")
|
||||
hsget: (s, x, p, v) -> (v, <concat-strings>[p, $[[v] <- [s] `gets` [x]],
|
||||
"\n"])
|
||||
hs: (Gets(_, xn), Gets(s, x)) -> v
|
||||
with v := <newname>"_fostr_get"
|
||||
; <add-preactions>[$[[v] <- [<hs_gets>(s, xn, x)]]]
|
||||
hs: (To(xn, _), To(x, s)) -> v
|
||||
with v := <newname>"_fostr_to"
|
||||
; <add-preactions>[$[let [v] = [x]], <hs_gets>(s, xn, v)]
|
||||
|
||||
hs: To( (c, p), (d, q)) -> <hsto>(c,d,<conc-strings>(p,q),<newname>"fosto")
|
||||
hsto: (x, s, p, v) -> (v, <concat-strings>[p, $[let [v] = [x]], "\n",
|
||||
$[[s] `gets` [v]], "\n"])
|
||||
hs_gets: (s, xn, x ) -> $[[s] [<hs_getOp>xn] [x]]
|
||||
hs_getOp = get-type; (?STRING() < !"`getsStr`" + !"`gets`")
|
||||
|
||||
hs: Terminate((c,p)) -> ($[[c];;], p)
|
||||
hs: Sequence(l) -> (<last; Fst>l, <map(Snd); concat-strings>l)
|
||||
hs: (_, Terminate(x)) -> $[[x];;]
|
||||
hs: (_, Sequence(l)) -> <last>l
|
||||
/* One drawback of using paramorphism is at the very leaves we have
|
||||
to undouble the tuple:
|
||||
*/
|
||||
hs: (x, x) -> x where <is-string>x
|
||||
|
||||
/* Characters we need to escape in Haskell string constants */
|
||||
Hascape: ['\t' | cs ] -> ['\', 't' | cs ]
|
||||
@ -47,9 +67,15 @@ rules
|
||||
Hascape: [ 12 | cs ] -> ['\', 'f' | cs ] // Form feed
|
||||
|
||||
strategies
|
||||
HaskellEscape = Escape <+ Hascape
|
||||
haskLitString = un-single-quote
|
||||
; string-as-chars(escape-chars(Escape <+ Hascape))
|
||||
; double-quote
|
||||
|
||||
haskell = bottomup(try(hs))
|
||||
haskell = rules(Preactions: () -> ""); bottomup-para(try(hs))
|
||||
|
||||
/* See "Approach" at top of file */
|
||||
add-preactions = newp := <conc-strings>(<Preactions>(), <lines>)
|
||||
; rules(Preactions: () -> newp)
|
||||
|
||||
// Interface haskell code generation with editor services and file system
|
||||
to-haskell: (selected, _, _, path, project-path) -> (filename, result)
|
||||
|
@ -13,7 +13,7 @@ rules
|
||||
|
||||
js: Stream() -> $[Stdio]
|
||||
js: Int(x) -> x
|
||||
js: LitString(x) -> $['[<string-as-chars(escape-chars(JavaEscape))>x]']
|
||||
js: LitString(x) -> <javaLitString>x
|
||||
js: Sum(x,y) -> $[[x] + [y]]
|
||||
js: Gets(x, y) -> $[[x].gets([y])]
|
||||
js: To(x, y) -> $[to([x],[y])]
|
||||
@ -29,7 +29,9 @@ rules
|
||||
Jscape: [ 12 | cs ] -> ['\', 'f' | cs ] // Form feed
|
||||
|
||||
strategies
|
||||
JavaEscape = Escape <+ Jscape
|
||||
javaLitString = un-single-quote
|
||||
; string-as-chars(escape-chars(Escape <+ Jscape))
|
||||
; single-quote
|
||||
|
||||
javascript = bottomup(try(js))
|
||||
|
||||
|
@ -15,7 +15,7 @@ rules
|
||||
|
||||
py: Stream() -> $[Stdio]
|
||||
py: Int(x) -> x
|
||||
py: LitString(x) -> $[r'[x]']
|
||||
py: LitString(x) -> $[r[x]]
|
||||
py: Sum(x,y) -> $[[x] + [y]]
|
||||
py: Gets(x, y) -> $[[x].gets([y])]
|
||||
py: To(x, y) -> $[to([x],[y])]
|
||||
|
Loading…
Reference in New Issue
Block a user