From 804a00902a2ad6fea172378caa235acf701d0a0a Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Tue, 16 Feb 2021 09:46:12 -0800 Subject: [PATCH] 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). --- README.md | 3 +- syntax/fostr.sdf3 | 4 +-- tests/basic.spt | 6 ++-- trans/haskell.str | 74 ++++++++++++++++++++++++++++++-------------- trans/javascript.str | 6 ++-- trans/python.str | 2 +- 6 files changed, 62 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 91e1605..0df4cba 100644 --- a/README.md +++ b/README.md @@ -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"). diff --git a/syntax/fostr.sdf3 b/syntax/fostr.sdf3 index 7805b3f..4dc4569 100644 --- a/syntax/fostr.sdf3 +++ b/syntax/fostr.sdf3 @@ -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.Int = INT - Ex.LitString = <''> + Ex.LitString = STRING_LITERAL Ex.Stream = Ex.Sum = < + > {left} Ex.Gets = [[Ex] << [Ex]] {left} diff --git a/tests/basic.spt b/tests/basic.spt index 075a4c3..e1cadf9 100644 --- a/tests/basic.spt +++ b/tests/basic.spt @@ -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 diff --git a/trans/haskell.str b/trans/haskell.str index 63c969e..a22fe36 100644 --- a/trans/haskell.str +++ b/trans/haskell.str @@ -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 () 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]] + [()]return [val]] - hs: Stream() -> ("StdIO", "") - hs: Int(x) -> (x, "") - hs: LitString(x) - -> ($["[x]"], "") - hs: Sum( (c, p), (d, q)) -> ($[([c] + [d])], (p,q)) + hs: (_, Stream()) -> "StdIO" + hs: (_, Int(x)) -> x + hs: (_, LitString(x)) -> x + hs: (_, Sum(x, y)) -> $[([x] + [y])] - hs: Gets((c, p), (d, q)) -> (c,d,(p,q),"fosgt") - hsget: (s, x, p, v) -> (v, [p, $[[v] <- [s] `gets` [x]], - "\n"]) + hs: (Gets(_, xn), Gets(s, x)) -> v + with v := "_fostr_get" + ; [$[[v] <- [(s, xn, x)]]] + hs: (To(xn, _), To(x, s)) -> v + with v := "_fostr_to" + ; [$[let [v] = [x]], (s, xn, v)] - hs: To( (c, p), (d, q)) -> (c,d,(p,q),"fosto") - hsto: (x, s, p, v) -> (v, [p, $[let [v] = [x]], "\n", - $[[s] `gets` [v]], "\n"]) + hs_gets: (s, xn, x ) -> $[[s] [xn] [x]] + hs_getOp = get-type; (?STRING() < !"`getsStr`" + !"`gets`") - hs: Terminate((c,p)) -> ($[[c];;], p) - hs: Sequence(l) -> (l, l) + hs: (_, Terminate(x)) -> $[[x];;] + hs: (_, Sequence(l)) -> l + /* One drawback of using paramorphism is at the very leaves we have + to undouble the tuple: + */ + hs: (x, x) -> x where 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 := ((), ) + ; rules(Preactions: () -> newp) // Interface haskell code generation with editor services and file system to-haskell: (selected, _, _, path, project-path) -> (filename, result) diff --git a/trans/javascript.str b/trans/javascript.str index d0d97fe..645cc63 100644 --- a/trans/javascript.str +++ b/trans/javascript.str @@ -13,7 +13,7 @@ rules js: Stream() -> $[Stdio] js: Int(x) -> x - js: LitString(x) -> $['[x]'] + js: LitString(x) -> 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)) diff --git a/trans/python.str b/trans/python.str index d745cee..7aa4e06 100644 --- a/trans/python.str +++ b/trans/python.str @@ -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])]