Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
3effe65f01 | |||
221d85ebbe | |||
dc19df8811 | |||
b1f87428f5 | |||
87a6fbc642 | |||
e3ff1f259e | |||
d1c3ed3481 | |||
f789ed94fd |
@ -13,9 +13,6 @@ DESTINATION = 'tests/extracted'
|
|||||||
# Extension for extracted files:
|
# Extension for extracted files:
|
||||||
EXT = 'fos'
|
EXT = 'fos'
|
||||||
|
|
||||||
# Extension for desired input:
|
|
||||||
INP = 'in'
|
|
||||||
|
|
||||||
# Extension for expectations:
|
# Extension for expectations:
|
||||||
EXP = 'expect'
|
EXP = 'expect'
|
||||||
|
|
||||||
@ -37,11 +34,6 @@ for path in TEST_LIST:
|
|||||||
expath = destdir / f"{name}.{EXT}"
|
expath = destdir / f"{name}.{EXT}"
|
||||||
expath.write_text(example)
|
expath.write_text(example)
|
||||||
echo Wrote @(expath)
|
echo Wrote @(expath)
|
||||||
im = re.search(r'/\*\*\s+accepts.*?\n([\s\S]*?)\*\*/', details[em.end():])
|
|
||||||
if im:
|
|
||||||
ipath = destdir / f"{name}.{INP}"
|
|
||||||
ipath.write_text(im[1])
|
|
||||||
echo " ...and" @(ipath)
|
|
||||||
xm = re.search(r'/\*\*\s+writes.*?\n([\s\S]*?)\*\*/', details[em.end():])
|
xm = re.search(r'/\*\*\s+writes.*?\n([\s\S]*?)\*\*/', details[em.end():])
|
||||||
if xm:
|
if xm:
|
||||||
xpath = destdir / f"{name}.{EXP}"
|
xpath = destdir / f"{name}.{EXP}"
|
||||||
|
@ -9,14 +9,8 @@ diffed=0
|
|||||||
for dir in tests/extracted/*; do
|
for dir in tests/extracted/*; do
|
||||||
for file in $dir/*.$ext; do
|
for file in $dir/*.$ext; do
|
||||||
((total++))
|
((total++))
|
||||||
if [[ -f ${file%.*}.in ]]; then
|
$command $file > $file.out
|
||||||
cat ${file%.*}.in | $command $file > $file.out
|
if [[ $? -ne 0 ]]; then
|
||||||
result=$?
|
|
||||||
else
|
|
||||||
$command $file > $file.out
|
|
||||||
result=$?
|
|
||||||
fi
|
|
||||||
if [[ $result -ne 0 ]]; then
|
|
||||||
echo ERROR: $command $file failed.
|
echo ERROR: $command $file failed.
|
||||||
((failed++))
|
((failed++))
|
||||||
else
|
else
|
||||||
|
@ -9,7 +9,7 @@ plugins:
|
|||||||
- search
|
- search
|
||||||
- semiliterate:
|
- semiliterate:
|
||||||
ignore_folders: [target, lib]
|
ignore_folders: [target, lib]
|
||||||
exclude_extensions: ['.o', '.hi', '.cmi', '.cmo']
|
exclude_extensions: ['.o', '.hi']
|
||||||
extract_standard_markdown:
|
extract_standard_markdown:
|
||||||
terminate: <!-- /md -->
|
terminate: <!-- /md -->
|
||||||
theme:
|
theme:
|
||||||
|
@ -42,13 +42,10 @@ context-free syntax
|
|||||||
Ex.EscString = STRING
|
Ex.EscString = STRING
|
||||||
Ex.Stream = <stream>
|
Ex.Stream = <stream>
|
||||||
Ex.Sum = <<Ex> + <Ex>> {left}
|
Ex.Sum = <<Ex> + <Ex>> {left}
|
||||||
Ex.Concat = <<Ex> ++ <Ex>> {left}
|
|
||||||
Ex.Gets = [[Ex] << [Ex]] {left}
|
Ex.Gets = [[Ex] << [Ex]] {left}
|
||||||
Ex.DefGets = [<<< [Ex]]
|
Ex.DefGets = [<<< [Ex]]
|
||||||
Ex.To = [[Ex] >> [Ex]] {left}
|
Ex.To = [[Ex] >> [Ex]] {left}
|
||||||
Ex.DefTo = [[Ex] >>>]
|
Ex.DefTo = [[Ex] >>>]
|
||||||
Ex.Emits = <<Ex>!>
|
|
||||||
Ex.DefEmits = <!!>
|
|
||||||
|
|
||||||
Ex = <(<Ex>)> {bracket}
|
Ex = <(<Ex>)> {bracket}
|
||||||
|
|
||||||
@ -56,7 +53,7 @@ context-free priorities
|
|||||||
|
|
||||||
Ex.To
|
Ex.To
|
||||||
> Ex.DefTo
|
> Ex.DefTo
|
||||||
> {Ex.Sum Ex.Concat}
|
> Ex.Sum
|
||||||
> Ex.DefGets
|
> Ex.DefGets
|
||||||
> Ex.Gets,
|
> Ex.Gets,
|
||||||
|
|
||||||
|
@ -293,38 +293,4 @@ test emit_several_default [[
|
|||||||
>>>
|
>>>
|
||||||
]] parse succeeds
|
]] parse succeeds
|
||||||
/** writes
|
/** writes
|
||||||
3399677527121313**/
|
3399677527121313*/
|
||||||
|
|
||||||
/** md
|
|
||||||
### Streams are bidirectional
|
|
||||||
|
|
||||||
So far we have only sent items to a stream. But we can extract them from
|
|
||||||
streams as well, with the `!` postfix operator. `!!` all by itself abbreviates
|
|
||||||
`stream!`, i.e., extraction from the standard stream. For example,
|
|
||||||
|
|
||||||
```fostr
|
|
||||||
**/
|
|
||||||
|
|
||||||
/** md */ test custom_hw [[
|
|
||||||
<<< "What is your name?\n"
|
|
||||||
<<< 'Hello, ' ++ !!
|
|
||||||
]] /* **/
|
|
||||||
parse to TopLevel(Sequence([
|
|
||||||
DefGets(EscString("\"What is your name?\n\"")),
|
|
||||||
DefGets(Concat(LitString("'Hello, '"),DefEmits()))
|
|
||||||
]))
|
|
||||||
/** accepts
|
|
||||||
Kilroy
|
|
||||||
**/
|
|
||||||
/** writes
|
|
||||||
What is your name?
|
|
||||||
Hello, Kilroy
|
|
||||||
**/
|
|
||||||
|
|
||||||
/** md
|
|
||||||
```
|
|
||||||
|
|
||||||
queries users for their name and then writes a customized greeting. It also
|
|
||||||
illustrates the use of `++` for string concatenation, as opposed to `+` for
|
|
||||||
(numerical) addition.
|
|
||||||
**/
|
|
||||||
|
@ -17,7 +17,6 @@ rules
|
|||||||
|
|
||||||
defStream: DefGets(x) -> Gets(Stream(), x)
|
defStream: DefGets(x) -> Gets(Stream(), x)
|
||||||
defStream: DefTo(x) -> To(x, Stream())
|
defStream: DefTo(x) -> To(x, Stream())
|
||||||
defStream: DefEmits() -> Emits(Stream())
|
|
||||||
|
|
||||||
strategies
|
strategies
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ rules
|
|||||||
import System.IO
|
import System.IO
|
||||||
data IOStream = StdIO
|
data IOStream = StdIO
|
||||||
|
|
||||||
-- Danger: These currently assume the stream is StdIO
|
|
||||||
gets :: Show b => a -> b -> IO a
|
gets :: Show b => a -> b -> IO a
|
||||||
gets s d = do
|
gets s d = do
|
||||||
putStr(show d)
|
putStr(show d)
|
||||||
@ -34,10 +33,6 @@ rules
|
|||||||
putStr(d)
|
putStr(d)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
emit s = do
|
|
||||||
l <- getLine
|
|
||||||
return (l ++ "\n")
|
|
||||||
|
|
||||||
main = do
|
main = do
|
||||||
[<Preactions>()]return [val]]
|
[<Preactions>()]return [val]]
|
||||||
|
|
||||||
@ -46,7 +41,6 @@ rules
|
|||||||
hs: (_, LitString(x)) -> <haskLitString>x
|
hs: (_, LitString(x)) -> <haskLitString>x
|
||||||
hs: (_, EscString(x)) -> x
|
hs: (_, EscString(x)) -> x
|
||||||
hs: (_, Sum(x, y)) -> $[([x] + [y])]
|
hs: (_, Sum(x, y)) -> $[([x] + [y])]
|
||||||
hs: (_, Concat(x, y)) -> $[([x] ++ [y])]
|
|
||||||
|
|
||||||
hs: (Gets(_, xn), Gets(s, x)) -> v
|
hs: (Gets(_, xn), Gets(s, x)) -> v
|
||||||
with v := <newname>"_fostr_get"
|
with v := <newname>"_fostr_get"
|
||||||
@ -58,10 +52,6 @@ rules
|
|||||||
hs_gets: (s, xn, x ) -> $[[s] [<hs_getOp>xn] [x]]
|
hs_gets: (s, xn, x ) -> $[[s] [<hs_getOp>xn] [x]]
|
||||||
hs_getOp = get-type; (?STRING() < !"`getsStr`" + !"`gets`")
|
hs_getOp = get-type; (?STRING() < !"`getsStr`" + !"`gets`")
|
||||||
|
|
||||||
hs: (_, Emits(s)) -> v
|
|
||||||
with v := <newname>"_fostr_emitted"
|
|
||||||
; <add-preactions>[$[[v] <- emit [s]]]
|
|
||||||
|
|
||||||
hs: (_, Terminate(x)) -> $[[x];;]
|
hs: (_, Terminate(x)) -> $[[x];;]
|
||||||
hs: (_, Sequence(l)) -> <last>l
|
hs: (_, Sequence(l)) -> <last>l
|
||||||
/* One drawback of using paramorphism is we have to handle lists
|
/* One drawback of using paramorphism is we have to handle lists
|
||||||
|
@ -3,41 +3,24 @@ imports libstrategolib signatures/- util
|
|||||||
|
|
||||||
rules
|
rules
|
||||||
js: TopLevel(x) -> $[// Fostr preamble
|
js: TopLevel(x) -> $[// Fostr preamble
|
||||||
const _fostr_readline = require('readline');
|
|
||||||
const _fostr_events = require('events');
|
|
||||||
const _fostr_rl = _fostr_readline.createInterface({input: process.stdin});
|
|
||||||
const Stdio = {
|
const Stdio = {
|
||||||
gets: v => { process.stdout.write(String(v)); return Stdio; },
|
gets: v => { process.stdout.write(String(v)); return Stdio; },
|
||||||
emit: async () => {
|
|
||||||
const [line] = await _fostr_events.once(_fostr_rl, 'line');
|
|
||||||
return line + "\n"; }
|
|
||||||
}
|
}
|
||||||
function to(data, strm) {
|
function to(data, strm) {
|
||||||
strm.gets(data);
|
strm.gets(data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const _fostr_body = async () => {
|
|
||||||
// End of preamble
|
// End of preamble
|
||||||
|
|
||||||
[x]
|
[x]]
|
||||||
|
|
||||||
// Fostr coda
|
|
||||||
_fostr_rl.close()
|
|
||||||
}
|
|
||||||
_fostr_body();
|
|
||||||
]
|
|
||||||
with line := "[line]"
|
|
||||||
|
|
||||||
js: Stream() -> $[Stdio]
|
js: Stream() -> $[Stdio]
|
||||||
js: Int(x) -> x
|
js: Int(x) -> x
|
||||||
js: LitString(x) -> <javaLitString>x
|
js: LitString(x) -> <javaLitString>x
|
||||||
js: EscString(x) -> x
|
js: EscString(x) -> x
|
||||||
js: Sum(x, y) -> $[[x] + [y]]
|
js: Sum(x,y) -> $[[x] + [y]]
|
||||||
js: Concat(x, y) -> $[[x] + [y]]
|
|
||||||
js: Gets(x, y) -> $[[x].gets([y])]
|
js: Gets(x, y) -> $[[x].gets([y])]
|
||||||
js: To(x, y) -> $[to([x],[y])]
|
js: To(x, y) -> $[to([x],[y])]
|
||||||
js: Emits(x) -> $[(await [x].emit())]
|
|
||||||
js: Terminate(x) -> x
|
js: Terminate(x) -> x
|
||||||
js: Sequence(l) -> <join(|";\n")>l
|
js: Sequence(l) -> <join(|";\n")>l
|
||||||
|
|
||||||
|
@ -12,10 +12,9 @@ imports libstrategolib signatures/- util signature/TYPE analysis
|
|||||||
|
|
||||||
rules
|
rules
|
||||||
ml: (_, TopLevel(x)) -> $[(* fostr preamble *)
|
ml: (_, TopLevel(x)) -> $[(* fostr preamble *)
|
||||||
type stream = { getS: string -> stream; emitS: unit -> string }
|
type stream = { getS: string -> stream }
|
||||||
let rec stdio = {
|
let rec stdio = {
|
||||||
getS = (fun s -> print_string s; stdio);
|
getS = (fun s -> print_string s; stdio)
|
||||||
emitS = (fun () -> (read_line ()) ^ "\n");
|
|
||||||
};;
|
};;
|
||||||
(* End of preamble *)
|
(* End of preamble *)
|
||||||
|
|
||||||
@ -25,15 +24,11 @@ rules
|
|||||||
ml: (_, Int(x)) -> x
|
ml: (_, Int(x)) -> x
|
||||||
ml: (_, LitString(x)) -> $[{|[<un-single-quote>x]|}]
|
ml: (_, LitString(x)) -> $[{|[<un-single-quote>x]|}]
|
||||||
ml: (_, EscString(x)) -> x
|
ml: (_, EscString(x)) -> x
|
||||||
ml: (_, Sum(x, y)) -> $[[x] + [y]]
|
ml: (_, Sum(x,y)) -> $[[x] + [y]]
|
||||||
ml: (_, Concat(x, y)) -> $[[x] ^ [y]]
|
|
||||||
|
|
||||||
ml: (Gets(_,yn), Gets(x, y))
|
ml: (Gets(_,yn), Gets(x, y))
|
||||||
-> $[([x]).getS ([<ml_str>(yn,y)])]
|
-> $[([x]).getS ([<ml_str>(yn,y)])]
|
||||||
ml: (To(xn,_), To(x, y))
|
ml: (To(xn,_), To(x, y))
|
||||||
-> $[let _fto = ([x]) in (ignore (([y]).getS ([<ml_str>(xn,"_fto")])); _fto)]
|
-> $[let _fto = ([x]) in (ignore (([y]).getS ([<ml_str>(xn,"_fto")])); _fto)]
|
||||||
ml: (_, Emits(s)) -> $[[s].emitS ()]
|
|
||||||
|
|
||||||
ml: (_, Terminate(x)) -> x
|
ml: (_, Terminate(x)) -> x
|
||||||
ml: (_, Sequence(l)) -> <ml_seq>l
|
ml: (_, Sequence(l)) -> <ml_seq>l
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ rules
|
|||||||
def gets(self, v):
|
def gets(self, v):
|
||||||
print(v, file=sys.stdout, end='')
|
print(v, file=sys.stdout, end='')
|
||||||
return self
|
return self
|
||||||
def emit(self):
|
|
||||||
return input() + "\n" # Python inconsistently strips when using input
|
|
||||||
def to(data,strm):
|
def to(data,strm):
|
||||||
strm.gets(data)
|
strm.gets(data)
|
||||||
return data
|
return data
|
||||||
@ -23,10 +21,8 @@ rules
|
|||||||
py: LitString(x) -> $[r[x]]
|
py: LitString(x) -> $[r[x]]
|
||||||
py: EscString(x) -> x
|
py: EscString(x) -> x
|
||||||
py: Sum(x,y) -> $[[x] + [y]]
|
py: Sum(x,y) -> $[[x] + [y]]
|
||||||
py: Concat(x,y) -> $[[x] + [y]]
|
|
||||||
py: Gets(x, y) -> $[[x].gets([y])]
|
py: Gets(x, y) -> $[[x].gets([y])]
|
||||||
py: To(x, y) -> $[to([x],[y])]
|
py: To(x, y) -> $[to([x],[y])]
|
||||||
py: Emits(x) -> $[[x].emit()]
|
|
||||||
py: Terminate(x) -> $[[x];]
|
py: Terminate(x) -> $[[x];]
|
||||||
py: Sequence(l) -> <join(|"\n")>l
|
py: Sequence(l) -> <join(|"\n")>l
|
||||||
|
|
||||||
|
@ -222,13 +222,6 @@ This pattern lets us specify error messages.
|
|||||||
type_Ex(e2) == STREAM() | error $[Items may only be sent to Streams.]@e2.
|
type_Ex(e2) == STREAM() | error $[Items may only be sent to Streams.]@e2.
|
||||||
/* **/
|
/* **/
|
||||||
|
|
||||||
ty_Ex(Concat(e1, e2)) = STRING() :-
|
|
||||||
type_Ex(e1) == STRING() | error $[Expression [e1] not String in concat.]@e1,
|
|
||||||
type_Ex(e2) == STRING() | error $[Expression [e2] not String in concat.]@e2.
|
|
||||||
|
|
||||||
ty_Ex(Emits(e)) = STRING() :- // At the moment, only stream is stdio
|
|
||||||
type_Ex(e) == STREAM() | error $[Only Streams may emit items.]@e.
|
|
||||||
|
|
||||||
/** md
|
/** md
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user