feat: Implement enters operator >> (#8)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Also adds parenthesization of fostr expressions. Recasts code generation in terms of bottomup processing of a local strategy. Resolves #1. Co-authored-by: Glen Whitney <glen@studioinfinity.org> Reviewed-on: #8 Co-Authored-By: Glen Whitney <glen@nobody@nowhere.net> Co-Committed-By: Glen Whitney <glen@nobody@nowhere.net>
This commit is contained in:
parent
527f802793
commit
2e49065031
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,9 +10,12 @@
|
|||||||
|
|
||||||
/.polyglot.metaborg.yaml
|
/.polyglot.metaborg.yaml
|
||||||
|
|
||||||
|
.pydevproject
|
||||||
|
|
||||||
*.aterm
|
*.aterm
|
||||||
/site
|
/site
|
||||||
tests/extracted/*
|
tests/extracted/*
|
||||||
tests/*.js
|
tests/*.js
|
||||||
tests/*.py
|
tests/*.py
|
||||||
tests/*.hs
|
tests/*.hs
|
||||||
|
adhoc*
|
||||||
|
@ -18,10 +18,13 @@ context-free syntax
|
|||||||
Ex.Stdio = <stdio>
|
Ex.Stdio = <stdio>
|
||||||
Ex.Sum = {Ex "+"}+
|
Ex.Sum = {Ex "+"}+
|
||||||
Ex.Receives = [[Ex] << [Ex]] {left}
|
Ex.Receives = [[Ex] << [Ex]] {left}
|
||||||
|
Ex.Enters = [[Ex] >> [Ex]] {left}
|
||||||
|
Ex = <(<Ex>)> {bracket}
|
||||||
|
|
||||||
context-free priorities
|
context-free priorities
|
||||||
|
|
||||||
Ex.Sum
|
Ex.Enters
|
||||||
|
> Ex.Sum
|
||||||
> Ex.Receives,
|
> Ex.Receives,
|
||||||
|
|
||||||
// prevent cycle: no singletons
|
// prevent cycle: no singletons
|
||||||
|
@ -71,4 +71,37 @@ stdio << 72 + 87 + 33 << 291
|
|||||||
/** md
|
/** md
|
||||||
```
|
```
|
||||||
Running this program produces a nice palindromic output: "192291".
|
Running this program produces a nice palindromic output: "192291".
|
||||||
|
|
||||||
|
And because sometimes you want to emphasize the value and propagate that
|
||||||
|
instead of the stream, you can also write these expressions "the other way"
|
||||||
|
with `>>`; both forms return the first argument:
|
||||||
|
```fostr
|
||||||
|
**/
|
||||||
|
|
||||||
|
/** md */ test enters_twice [[
|
||||||
|
(7 + 8 >> stdio + 9) >> stdio
|
||||||
|
]]/* **/ parse to
|
||||||
|
Enters(Sum([Int("7"), Enters(Int("8"), Stdio()), Int("9")]), Stdio())
|
||||||
|
/** writes
|
||||||
|
824**/
|
||||||
|
|
||||||
|
/* Extra tests not in the tour */
|
||||||
|
|
||||||
|
test receive_enter [[
|
||||||
|
stdio << (7 + 8 >> stdio + 9)
|
||||||
|
]]/* **/ parse to
|
||||||
|
Receives(Stdio(), Sum([Int("7"), Enters(Int("8"), Stdio()), Int("9")]))
|
||||||
|
/** writes
|
||||||
|
824**/
|
||||||
|
|
||||||
|
test enter_receive [[
|
||||||
|
(7 + 8 >> stdio + 9) >> (stdio << 9 + 2)
|
||||||
|
]]/* **/ parse to
|
||||||
|
Enters(Sum([Int("7"),Enters(Int("8"),Stdio()),Int("9")]),
|
||||||
|
Receives(Stdio(),Sum([Int("9"),Int("2")])))
|
||||||
|
/** writes
|
||||||
|
81124**/
|
||||||
|
|
||||||
|
/** md
|
||||||
|
```
|
||||||
**/
|
**/
|
||||||
|
@ -1,12 +1,20 @@
|
|||||||
module haskell
|
module haskell
|
||||||
imports libstrategolib signatures/-
|
imports libstrategolib signatures/- util
|
||||||
|
|
||||||
signature
|
signature
|
||||||
constructors
|
constructors
|
||||||
TopLevel: Ex -> Ex
|
TopLevel: Ex -> Ex
|
||||||
|
|
||||||
rules
|
rules
|
||||||
hs: TopLevel(x) -> $[import System.IO
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hs: TopLevel((c,p)) -> $[import System.IO
|
||||||
data IOStream = StdIO
|
data IOStream = StdIO
|
||||||
|
|
||||||
stdio :: IO IOStream
|
stdio :: IO IOStream
|
||||||
@ -19,21 +27,23 @@ rules
|
|||||||
return temp
|
return temp
|
||||||
|
|
||||||
main = do
|
main = do
|
||||||
[<hs>x]]
|
[p]return [c]]
|
||||||
|
|
||||||
hs: Stdio() -> $[stdio]
|
hs: Stdio() -> ("stdio", "")
|
||||||
hs: Int(x) -> x
|
hs: Int(x) -> (x, "")
|
||||||
hs: Sum(x) -> $[sum [<hs>x]]
|
hs: Sum((c,p)) -> ($[sum [c]], p)
|
||||||
hs: Receives(x, y) -> $[[<hs>x] `receives` [<hs>y]]
|
hs: Receives((c, p), (d, s)) -> ($[[c] `receives` [d]], <conc-strings>(p,s))
|
||||||
hs: [] -> $<[]>
|
hs: Enters((c, p), (d, s)) -> <hsenter>(c,d,<conc-strings>(p,s),<newname>"fos")
|
||||||
hs: [x | xs] -> $<[<<hs>x><<hstail>xs>]>
|
|
||||||
|
hsenter: (x, s, p, v) -> (v, <concat-strings>[$[[p]let [v] = [x]], "\n",
|
||||||
|
$[[s] `receives` [v]], "\n"])
|
||||||
|
|
||||||
|
hslist: x -> (<map(Fst); join(|", "); brack>x, <map(Snd); concat-strings>x)
|
||||||
|
brack: x -> $<[<x>]>
|
||||||
|
|
||||||
strategies
|
strategies
|
||||||
// wrap expression in a toplevel and then apply code generation
|
// wrap expression in a toplevel and then apply code generation
|
||||||
haskell = !TopLevel(<id>); hs
|
haskell = !TopLevel(<id>); bottomup(try(hs <+ hslist))
|
||||||
|
|
||||||
// translate each element of a list, prepending each with ',', and concatenate
|
|
||||||
hstail = foldr(!"", \ (x,y) -> $<, <<hs>x><y>> \)
|
|
||||||
|
|
||||||
// Interface haskell code generation with editor services and file system
|
// Interface haskell code generation with editor services and file system
|
||||||
to-haskell: (selected, _, _, path, project-path) -> (filename, result)
|
to-haskell: (selected, _, _, path, project-path) -> (filename, result)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
module javascript
|
module javascript
|
||||||
imports libstrategolib signatures/-
|
imports libstrategolib signatures/- util
|
||||||
|
|
||||||
signature
|
signature
|
||||||
constructors
|
constructors
|
||||||
@ -7,23 +7,25 @@ signature
|
|||||||
|
|
||||||
rules
|
rules
|
||||||
js: TopLevel(x) -> $[const Stdio = {
|
js: TopLevel(x) -> $[const Stdio = {
|
||||||
receives: v => { process.stdout.write(String(v)); return Stdio; }
|
receives: v => { process.stdout.write(String(v)); return Stdio; },
|
||||||
}
|
}
|
||||||
[<js>x]]
|
function forwards(data, strm) {
|
||||||
|
strm.receives(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
[x]]
|
||||||
|
|
||||||
js: Stdio() -> $[Stdio]
|
js: Stdio() -> $[Stdio]
|
||||||
js: Int(x) -> x
|
js: Int(x) -> x
|
||||||
js: Sum(x) -> $[[<js>x].reduce((v,w) => v+w)]
|
js: Sum(x) -> $[[x].reduce((v,w) => v+w)]
|
||||||
js: Receives(x, y) -> $[[<js>x].receives([<js>y])]
|
js: Receives(x, y) -> $[[x].receives([y])]
|
||||||
js: [] -> $<[]>
|
js: Enters(x, y) -> $[forwards([x],[y])]
|
||||||
js: [x | xs] -> $<[<<js>x><<jstail>xs>]>
|
|
||||||
|
jslist: x -> $<[<<join(|", ")>x>]>
|
||||||
|
|
||||||
strategies
|
strategies
|
||||||
// wrap expression in a toplevel and then apply code generation
|
// wrap expression in a toplevel, then generate code from bottom up
|
||||||
javascript = !TopLevel(<id>); js
|
javascript = !TopLevel(<id>); bottomup(try(js <+ jslist))
|
||||||
|
|
||||||
// translate each element of a list, prepending each with ',', and concatenate
|
|
||||||
jstail = foldr(!"", \ (x,y) -> $<, <<js>x><y>> \)
|
|
||||||
|
|
||||||
// Interface javascript code generation with editor services and file system
|
// Interface javascript code generation with editor services and file system
|
||||||
to-javascript: (selected, _, _, path, project-path) -> (filename, result)
|
to-javascript: (selected, _, _, path, project-path) -> (filename, result)
|
||||||
|
@ -1,32 +1,35 @@
|
|||||||
module python
|
module python
|
||||||
imports libstrategolib signatures/-
|
imports libstrategolib signatures/- util
|
||||||
|
|
||||||
signature
|
signature
|
||||||
constructors
|
constructors
|
||||||
TopLevel: Ex -> Ex
|
TopLevel: Ex -> Ex
|
||||||
|
|
||||||
rules
|
rules
|
||||||
|
|
||||||
py: TopLevel(x) -> $[import sys
|
py: TopLevel(x) -> $[import sys
|
||||||
class StdioC:
|
class StdioC:
|
||||||
def receives(self, v):
|
def receives(self, v):
|
||||||
print(v, file=sys.stdout, end='')
|
print(v, file=sys.stdout, end='')
|
||||||
return self
|
return self
|
||||||
|
def forwards(data,strm):
|
||||||
|
strm.receives(data)
|
||||||
|
return data
|
||||||
Stdio = StdioC()
|
Stdio = StdioC()
|
||||||
[<py>x]]
|
[x]]
|
||||||
|
|
||||||
py: Stdio() -> $[Stdio]
|
py: Stdio() -> $[Stdio]
|
||||||
py: Int(x) -> x
|
py: Int(x) -> x
|
||||||
py: Sum(x) -> $[sum([<py>x])]
|
py: Sum(x) -> $[sum([x])]
|
||||||
py: Receives(x, y) -> $[[<py>x].receives([<py>y])]
|
py: Receives(x, y) -> $[[x].receives([y])]
|
||||||
py: [] -> $<[]>
|
py: Enters(x, y) -> $[forwards([x],[y])]
|
||||||
py: [x | xs] -> $<[<<py>x><<pytail>xs>]>
|
|
||||||
|
pylist: x -> $<[<<join(|", ")>x>]>
|
||||||
|
|
||||||
strategies
|
strategies
|
||||||
// wrap expression in a toplevel and then apply code generation
|
|
||||||
python = !TopLevel(<id>); py
|
|
||||||
|
|
||||||
// translate each element of a list, prepending each with ',', and concatenate
|
// wrap with a toplevel, then generate code from the bottom up
|
||||||
pytail = foldr(!"", \ (x,y) -> $[, [<py>x][y]] \)
|
python = !TopLevel(<id>); bottomup(try(py <+ pylist))
|
||||||
|
|
||||||
// Interface python code generation with editor services and file system
|
// Interface python code generation with editor services and file system
|
||||||
to-python: (selected, _, _, path, project-path) -> (filename, result)
|
to-python: (selected, _, _, path, project-path) -> (filename, result)
|
||||||
|
@ -10,6 +10,7 @@ rules // single-file entry point
|
|||||||
|
|
||||||
programOk(Sum(_)).
|
programOk(Sum(_)).
|
||||||
programOk(Receives(_,_)).
|
programOk(Receives(_,_)).
|
||||||
|
programOk(Enters(_,_)).
|
||||||
|
|
||||||
rules // multi-file entry point
|
rules // multi-file entry point
|
||||||
|
|
||||||
|
9
trans/util.str
Normal file
9
trans/util.str
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module util
|
||||||
|
imports libstrategolib
|
||||||
|
|
||||||
|
rules
|
||||||
|
join(|infix) : [] -> ""
|
||||||
|
join(|infix) : [x | xs] -> $[[x][<prejoin(|infix)>xs]]
|
||||||
|
|
||||||
|
prejoin(|infix) : [] -> ""
|
||||||
|
prejoin(|infix) : [x | xs] -> $[[infix][x][<prejoin(|infix)>xs]]
|
Loading…
Reference in New Issue
Block a user