forked from glen/fostr
chore: Switch to this repository from predecessor
This commit is contained in:
parent
9ecfa63f58
commit
7b00b01856
63
.drone.yml
Normal file
63
.drone.yml
Normal file
@ -0,0 +1,63 @@
|
||||
---
|
||||
kind: pipeline
|
||||
name: examples
|
||||
steps:
|
||||
- name: build
|
||||
image: maven
|
||||
volumes:
|
||||
- name: lib
|
||||
path: /drone/lib
|
||||
- name: m2
|
||||
path: /root/.m2
|
||||
commands:
|
||||
- mvn -ntp verify
|
||||
- cd /drone/lib
|
||||
- git clone https://github.com/metaborg/spt.git
|
||||
- cd spt/org.metaborg.spt.cmd
|
||||
- mvn -ntp package
|
||||
- name: run_spt
|
||||
image: maven
|
||||
volumes:
|
||||
- name: lib
|
||||
path: /drone/lib
|
||||
- name: m2
|
||||
path: /root/.m2
|
||||
commands:
|
||||
- cd /drone/lib/spt/org.metaborg.meta.lang.spt
|
||||
- mvn -ntp verify
|
||||
- cd /drone/src
|
||||
- java -jar /drone/lib/spt/org.metaborg.spt.cmd/target/org.metaborg.spt.cmd* -l . -s /drone/lib/spt/org.metaborg.meta.lang.spt -t tests
|
||||
- mkdir -p lib
|
||||
- curl -o lib/sunshine.jar -L 'http://artifacts.metaborg.org/service/local/artifact/maven/redirect?r=snapshots&g=org.metaborg&a=org.metaborg.sunshine2&v=LATEST'
|
||||
- bin/fosgen tests/emit_sum.fos
|
||||
- name: extract_tests
|
||||
image: xonsh/xonsh
|
||||
commands:
|
||||
- xonsh bin/extract_tests.xsh
|
||||
- name: generate_tests
|
||||
image: maven
|
||||
volumes:
|
||||
- name: lib
|
||||
path: /drone/lib
|
||||
- name: m2
|
||||
path: /root/.m2
|
||||
commands:
|
||||
- bin/generate_test_code
|
||||
- name: python_tests
|
||||
image: python:slim
|
||||
commands:
|
||||
- bin/run_tests python py
|
||||
- name: javascript_tests
|
||||
image: node
|
||||
commands:
|
||||
- bin/run_tests node js
|
||||
- name: haskell_tests
|
||||
image: haskell
|
||||
commands:
|
||||
- bin/run_tests runghc hs
|
||||
|
||||
volumes:
|
||||
- name: lib
|
||||
temp: {}
|
||||
- name: m2
|
||||
temp: {}
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
/.cache
|
||||
/bin
|
||||
/lib
|
||||
/src-gen
|
||||
/target
|
||||
|
||||
@ -9,3 +9,10 @@
|
||||
/.factorypath
|
||||
|
||||
/.polyglot.metaborg.yaml
|
||||
|
||||
*.aterm
|
||||
/site
|
||||
tests/extracted/*
|
||||
tests/*.js
|
||||
tests/*.py
|
||||
tests/*.hs
|
||||
|
208
LICENSE
Normal file
208
LICENSE
Normal file
@ -0,0 +1,208 @@
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,
|
||||
AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution
|
||||
as defined by Sections 1 through 9 of this document.
|
||||
|
||||
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct
|
||||
or indirect, to cause the direction or management of such entity, whether
|
||||
by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
|
||||
of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions
|
||||
granted by this License.
|
||||
|
||||
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation
|
||||
or translation of a Source form, including but not limited to compiled object
|
||||
code, generated documentation, and conversions to other media types.
|
||||
|
||||
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form,
|
||||
made available under the License, as indicated by a copyright notice that
|
||||
is included in or attached to the work (an example is provided in the Appendix
|
||||
below).
|
||||
|
||||
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form,
|
||||
that is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative
|
||||
Works shall not include works that remain separable from, or merely link (or
|
||||
bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative
|
||||
Works thereof, that is intentionally submitted to Licensor for inclusion in
|
||||
the Work by the copyright owner or by an individual or Legal Entity authorized
|
||||
to submit on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication
|
||||
sent to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor
|
||||
for the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently incorporated
|
||||
within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this
|
||||
License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
|
||||
Derivative Works of, publicly display, publicly perform, sublicense, and distribute
|
||||
the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License,
|
||||
each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section) patent
|
||||
license to make, have made, use, offer to sell, sell, import, and otherwise
|
||||
transfer the Work, where such license applies only to those patent claims
|
||||
licensable by such Contributor that are necessarily infringed by their Contribution(s)
|
||||
alone or by combination of their Contribution(s) with the Work to which such
|
||||
Contribution(s) was submitted. If You institute patent litigation against
|
||||
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that the Work or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses granted to You
|
||||
under this License for that Work shall terminate as of the date such litigation
|
||||
is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or
|
||||
Derivative Works thereof in any medium, with or without modifications, and
|
||||
in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or Derivative Works a copy
|
||||
of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices stating that
|
||||
You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source
|
||||
form of the Work, excluding those notices that do not pertain to any part
|
||||
of the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its distribution,
|
||||
then any Derivative Works that You distribute must include a readable copy
|
||||
of the attribution notices contained within such NOTICE file, excluding those
|
||||
notices that do not pertain to any part of the Derivative Works, in at least
|
||||
one of the following places: within a NOTICE text file distributed as part
|
||||
of the Derivative Works; within the Source form or documentation, if provided
|
||||
along with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works
|
||||
that You distribute, alongside or as an addendum to the NOTICE text from the
|
||||
Work, provided that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction,
|
||||
or distribution of Your modifications, or for any such Derivative Works as
|
||||
a whole, provided Your use, reproduction, and distribution of the Work otherwise
|
||||
complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any
|
||||
Contribution intentionally submitted for inclusion in the Work by You to the
|
||||
Licensor shall be under the terms and conditions of this License, without
|
||||
any additional terms or conditions. Notwithstanding the above, nothing herein
|
||||
shall supersede or modify the terms of any separate license agreement you
|
||||
may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names,
|
||||
trademarks, service marks, or product names of the Licensor, except as required
|
||||
for reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to
|
||||
in writing, Licensor provides the Work (and each Contributor provides its
|
||||
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied, including, without limitation, any warranties
|
||||
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness
|
||||
of using or redistributing the Work and assume any risks associated with Your
|
||||
exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether
|
||||
in tort (including negligence), contract, or otherwise, unless required by
|
||||
applicable law (such as deliberate and grossly negligent acts) or agreed to
|
||||
in writing, shall any Contributor be liable to You for damages, including
|
||||
any direct, indirect, special, incidental, or consequential damages of any
|
||||
character arising as a result of this License or out of the use or inability
|
||||
to use the Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all other commercial
|
||||
damages or losses), even if such Contributor has been advised of the possibility
|
||||
of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work
|
||||
or Derivative Works thereof, You may choose to offer, and charge a fee for,
|
||||
acceptance of support, warranty, indemnity, or other liability obligations
|
||||
and/or rights consistent with this License. However, in accepting such obligations,
|
||||
You may act only on Your own behalf and on Your sole responsibility, not on
|
||||
behalf of any other Contributor, and only if You agree to indemnify, defend,
|
||||
and hold each Contributor harmless for any liability incurred by, or claims
|
||||
asserted against, such Contributor by reason of your accepting any such warranty
|
||||
or additional liability. END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "[]" replaced with your own identifying
|
||||
information. (Don't include the brackets!) The text should be enclosed in
|
||||
the appropriate comment syntax for the file format. We also recommend that
|
||||
a file or class name and description of purpose be included on the same "printed
|
||||
page" as the copyright notice for easier identification within third-party
|
||||
archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and
|
||||
|
||||
limitations under the License.
|
48
README.md
48
README.md
@ -1,18 +1,40 @@
|
||||
# fostr Language Specification
|
||||
# The fostr programming language
|
||||
|
||||
## Using Statix for multi-file analysis
|
||||
I don't really like to write code, but I do like the things that coding can
|
||||
build for me: accounting systems for non-profits I care about, spreadsheets
|
||||
that have a reasonable calculation language for cell contents, geometric
|
||||
visualizations that really help to understand three (and maybe even four!)
|
||||
dimensions.
|
||||
|
||||
By default the project is configured to analyze all files of your language in
|
||||
isolation -- single-file analysis. It is also possible to configure the project
|
||||
such that all files are analyzed together, and files can refer to each other --
|
||||
multi-file analysis.
|
||||
So I embarked on this project to see if I could produce as comfortable a
|
||||
language as possible to work in, given that I inevitably will be doing a
|
||||
bunch of coding. The language will be
|
||||
organized around (unary) ++f++unctions, (binary) ++o++perators, and
|
||||
(nullary) ++str++eams, hence the name "fostr".
|
||||
|
||||
To enable multi-file analysis, do the following:
|
||||
1. Uncomment the `(multifile)` option in `editor/Analysis.esv`
|
||||
2. Uncomment the multi-file definition, and comment the single-file version, of
|
||||
`editor-analyze` in `trans/analysis.str`.
|
||||
Other guiding principles:
|
||||
|
||||
NB. When working in an IDE such as Eclipse, it is necessary to _restart the IDE_
|
||||
after switching from single-file to multi-file analysis or vice versa. Failure to
|
||||
do so will result in exceptions during analysis.
|
||||
* Maximize signal to noise ratio in code, which means minimizing the number
|
||||
of symbols that have to be there just for the syntax; reducing punctuation;
|
||||
seeking brief syntax that is not too terse; etc.
|
||||
|
||||
* Since code is always structurally indented anyway, make use of that and
|
||||
don't repeat information that's in the whitespace. This principle meshes
|
||||
well with the previous one, and if whitespace significance is baked into
|
||||
the language design from the ground up, it can be kept both effective and
|
||||
natural.
|
||||
|
||||
* Code uses functions all the time. So needless to say, functions should be
|
||||
first-class entities that are exceptionally easy to create, pass around,
|
||||
etc.
|
||||
|
||||
* And true to the name, operators and streams should be just as easy to handle.
|
||||
|
||||
* Try to keep the constructs available as simple to reason about as possible,
|
||||
and practical to use. So side effects are OK, and it should be clear when
|
||||
they occur and in what order. And if possible, fostr will consist **only**
|
||||
of expressions, no other syntactic constructs. Everything has a value.
|
||||
|
||||
<!-- /md -->
|
||||
Like just about every other language, this documentation begins with a
|
||||
[whirlwind tour](http::/studioinfinity.org/fostr/basic).
|
||||
|
36
bin/extract_tests.xsh
Normal file
36
bin/extract_tests.xsh
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env xonsh
|
||||
|
||||
import re
|
||||
|
||||
#### Set Parameters
|
||||
# Should be a list of Path objects:
|
||||
TEST_LIST = pg`tests/*.spt`
|
||||
|
||||
# Should be the top-level directory for all extracted tests:
|
||||
# (there will be one subdirectory per item in TEST_LIST)
|
||||
DESTINATION = 'tests/extracted'
|
||||
|
||||
# Extension for extracted files:
|
||||
EXT = 'fos'
|
||||
|
||||
# Extension for expectations:
|
||||
EXP = 'expect'
|
||||
|
||||
for path in TEST_LIST:
|
||||
destdir = pf"{DESTINATION}/{path.stem}"
|
||||
mkdir -p @(destdir)
|
||||
contents = path.read_text()
|
||||
tests = re.split(r'test\s*(.+?)\s*\[\[.*?\n', contents)[1:]
|
||||
testit = iter(tests)
|
||||
for name, details in zip(testit, testit):
|
||||
em = re.search(r'\n\s*\]\]', details)
|
||||
if not em: continue
|
||||
example = details[:em.start()+1]
|
||||
expath = destdir / f"{name}.{EXT}"
|
||||
expath.write_text(example)
|
||||
echo Wrote @(expath)
|
||||
xm = re.search(r'/\*\*\s+writes.*?\n([\s\S]*?)\*\*/', details[em.end():])
|
||||
if xm:
|
||||
xpath = destdir / f"{name}.{EXP}"
|
||||
xpath.write_text(xm[1])
|
||||
echo " ...and" @(xpath)
|
71
bin/fosgen
Executable file
71
bin/fosgen
Executable file
@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
|
||||
##### Convenience:
|
||||
erro() { printf "%s\n" "$*" >&2; }
|
||||
|
||||
##### Set defaults:
|
||||
SUPPRESS_ERR=YES
|
||||
LANGUAGE=Python
|
||||
|
||||
##### Extract command line options:
|
||||
while [[ $1 = -* ]]
|
||||
do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
echo
|
||||
echo "Usage:"
|
||||
echo " fosgen [-d] [-l LANGUAGE] FILE"
|
||||
echo
|
||||
echo "Writes to standard output the code generated from the fostr"
|
||||
echo "program in FILE, targeting the specified LANGUAGE (which"
|
||||
echo "defaults to Python)."
|
||||
echo
|
||||
echo "The -d option writes diagnostic output to standard error."
|
||||
exit
|
||||
;;
|
||||
-d)
|
||||
SUPPRESS_ERR=''
|
||||
;;
|
||||
-l)
|
||||
shift
|
||||
LANGUAGE="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
##### Get positional arguments:
|
||||
PROGRAM=$1
|
||||
|
||||
##### Corral resources:
|
||||
BINDIR=$(dirname $BASH_SOURCE)
|
||||
SUNJAR="$BINDIR/../lib/sunshine.jar"
|
||||
PROJDIR="$BINDIR/.."
|
||||
|
||||
if [[ ! -f $SUNJAR ]]; then
|
||||
erro "Please download the Spoofax Sunshine jar to the lib directory."
|
||||
erro "Recommended command:"
|
||||
erro " curl -o lib/sunshine.jar -L 'http://artifacts.metaborg.org/service/local/artifact/maven/redirect?r=snapshots&g=org.metaborg&a=org.metaborg.sunshine2&v=LATEST'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! $MVN_REPO ]]; then
|
||||
MVN_REPO="$HOME/.m2/repository"
|
||||
fi
|
||||
if [[ ! -d $MVN_REPO ]]; then
|
||||
MVN_REPO="/root/.m2/repository"
|
||||
fi
|
||||
if [[ ! -d $MVN_REPO ]]; then
|
||||
erro "Cannot find your Maven repository. Please set environment variable"
|
||||
erro "MVN_REPO to its full path and re-run."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##### Perform the code generation:
|
||||
if [[ $SUPPRESS_ERR ]]
|
||||
then
|
||||
exec 2>/dev/null
|
||||
fi
|
||||
|
||||
java -jar $SUNJAR transform -p $PROJDIR -l $PROJDIR -l $MVN_REPO -n $LANGUAGE -i $PROGRAM
|
||||
exit $?
|
19
bin/generate_test_code
Executable file
19
bin/generate_test_code
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
failed=0
|
||||
|
||||
for dir in tests/extracted/*; do
|
||||
for file in $dir/*.fos; do
|
||||
for language in Python Javascript Haskell; do
|
||||
echo bin/fosgen -l ${language%.*} $file ...
|
||||
bin/fosgen -l $language $file
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo ' ... Failed.'
|
||||
((failed++))
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
echo "Code generation completed with $failed failures."
|
||||
exit $failed
|
33
bin/run_tests
Executable file
33
bin/run_tests
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
command=$1
|
||||
ext=$2
|
||||
total=0
|
||||
failed=0
|
||||
diffed=0
|
||||
|
||||
for dir in tests/extracted/*; do
|
||||
for file in $dir/*.$ext; do
|
||||
((total++))
|
||||
$command $file > $file.out
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo ERROR: $command $file failed.
|
||||
((failed++))
|
||||
else
|
||||
if [[ -f ${file%.*}.expect ]]; then
|
||||
echo ---- diff ${file%.*}.expect $file.out ----
|
||||
diff ${file%.*}.expect $file.out
|
||||
if [[ $? -ne 0 ]]; then
|
||||
((diffed++))
|
||||
fi
|
||||
echo -------------------------------
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo "Ran $total tests: $failed failures, $diffed runs differed."
|
||||
if [[ $failed -gt 0 ]] || [[ $diffed -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
16
docs/implementation.md
Normal file
16
docs/implementation.md
Normal file
@ -0,0 +1,16 @@
|
||||
## Using Statix for multi-file analysis
|
||||
|
||||
By default the project is configured to analyze all files of your language in
|
||||
isolation -- single-file analysis. It is also possible to configure the project
|
||||
such that all files are analyzed together, and files can refer to each other --
|
||||
multi-file analysis.
|
||||
|
||||
To enable multi-file analysis, do the following:
|
||||
1. Uncomment the `(multifile)` option in `editor/Analysis.esv`
|
||||
2. Uncomment the multi-file definition, and comment the single-file version, of
|
||||
`editor-analyze` in `trans/analysis.str`.
|
||||
|
||||
NB. When working in an IDE such as Eclipse, it is necessary to _restart the IDE_
|
||||
after switching from single-file to multi-file analysis or vice versa. Failure to
|
||||
do so will result in exceptions during analysis.
|
||||
|
@ -6,7 +6,7 @@ imports
|
||||
|
||||
language
|
||||
|
||||
// see README.md for details on how to switch to multi-file analysis
|
||||
// see docs/implementation.md for details on how to switch to multi-file analysis
|
||||
|
||||
observer : editor-analyze (constraint) // (multifile)
|
||||
|
||||
|
6
editor/Generation.esv
Normal file
6
editor/Generation.esv
Normal file
@ -0,0 +1,6 @@
|
||||
module Generation
|
||||
menus
|
||||
menu: "Generation" (openeditor)
|
||||
action: "Python" = to-python
|
||||
action: "Javascript" = to-javascript
|
||||
action: "Haskell" = to-haskell
|
@ -4,6 +4,7 @@ imports
|
||||
|
||||
Syntax
|
||||
Analysis
|
||||
Generation
|
||||
|
||||
language
|
||||
|
||||
|
@ -8,7 +8,7 @@ imports
|
||||
language
|
||||
|
||||
table : target/metaborg/sdf.tbl
|
||||
start symbols : Start
|
||||
start symbols : Ex
|
||||
|
||||
line comment : "//"
|
||||
block comment : "/*" * "*/"
|
||||
|
22
mkdocs.yml
Normal file
22
mkdocs.yml
Normal file
@ -0,0 +1,22 @@
|
||||
site_name: fostr language
|
||||
nav:
|
||||
- README.md
|
||||
- tests/basic.md
|
||||
- implementation.md
|
||||
|
||||
plugins:
|
||||
- search
|
||||
- semiliterate:
|
||||
ignore_folders: [target]
|
||||
exclude_extensions: ['.o', '.hi']
|
||||
extract_standard_markdown:
|
||||
terminate: <!-- /md -->
|
||||
theme:
|
||||
name: readthedocs
|
||||
markdown_extensions:
|
||||
- attr_list
|
||||
- markdown-del-ins
|
||||
- pymdownx.superfences
|
||||
- pymdownx.highlight:
|
||||
use_pygments: true
|
||||
- smarty
|
@ -6,12 +6,27 @@ imports
|
||||
|
||||
context-free start-symbols
|
||||
|
||||
Start
|
||||
Ex
|
||||
|
||||
context-free sorts
|
||||
|
||||
Start
|
||||
Ex
|
||||
|
||||
context-free syntax
|
||||
|
||||
Start.Empty = <>
|
||||
Ex.Int = INT
|
||||
Ex.Stdio = <stdio>
|
||||
Ex.Sum = {Ex "+"}+
|
||||
Ex.Receives = [[Ex] << [Ex]] {left}
|
||||
|
||||
context-free priorities
|
||||
|
||||
Ex.Sum
|
||||
> Ex.Receives,
|
||||
|
||||
// prevent cycle: no singletons
|
||||
Ex.Sum <0> .> {Ex "+"}+ = Ex,
|
||||
|
||||
// flat: no Sum immediately in Sum:
|
||||
{Ex "+"}+ = Ex <0> .> Ex.Sum,
|
||||
{Ex "+"}+ = {Ex "+"}+ "+" Ex <2> .> Ex.Sum
|
||||
|
74
tests/basic.spt
Normal file
74
tests/basic.spt
Normal file
@ -0,0 +1,74 @@
|
||||
module basic
|
||||
language fostr
|
||||
|
||||
/** md
|
||||
Title: A whirlwind tour of fostr
|
||||
|
||||
## Whirlwind tour
|
||||
|
||||
fostr is just in its infancy, so it's not yet even ready for
|
||||
Hello, World. The best we can offer now is this little snippet
|
||||
that writes the sum of the ASCII codes for 'H', 'W', and '!' to standard output:
|
||||
```fostr
|
||||
**/
|
||||
|
||||
/** md */ test emit_sum [[
|
||||
stdio << 72 + 87 + 33
|
||||
]]/* **/ parse to Receives(Stdio(), Sum([Int("72"), Int("87"), Int("33")]))
|
||||
/** writes
|
||||
192**/
|
||||
|
||||
/** md
|
||||
```
|
||||
|
||||
At the moment, there are only two ways to run a file containing fostr code
|
||||
(you can find the above in `tests/emit_sum.fos`). They both start by
|
||||
cloning this fostr project. Then, either:
|
||||
|
||||
1. Open the project in Eclipse and build it, visit your program file,
|
||||
generate code from it in your preferred target language (among
|
||||
the options available in the "Spoofax > Generate" menu), and execute the
|
||||
resulting code.
|
||||
|
||||
1. Use the `bin/fosgen` bash script to generate code in a target language,
|
||||
and execute the resulting code.
|
||||
|
||||
For example, this snippet generates the following Python:
|
||||
```python
|
||||
{! ../examples/emit_sum.py extract:
|
||||
start: 'Stdio\s='
|
||||
!}
|
||||
```
|
||||
(which writes "192" to standard output), or this non-idiomatic, inefficient, but
|
||||
working Javascript:
|
||||
```javascript
|
||||
{! ../examples/emit_sum.js extract:
|
||||
start: '^}'
|
||||
!}
|
||||
```
|
||||
In either case, there's also a preamble defining Stdio that's generated.
|
||||
(Haskell code generation is also currently supported.)
|
||||
|
||||
### Everything has a value
|
||||
|
||||
As mentioned in the [Introduction](../README.md), everything in a fostr
|
||||
program (including the entire program itself) is an expression and has
|
||||
a value. So what's the value of that expression above? Well, `stdio` is our
|
||||
first example of a stream, and for convenience, the value of a stream
|
||||
receiving an item is just the stream back again. The `<<` operator is also
|
||||
left-associative, so that way we can chain insertions into a stream:
|
||||
```fostr
|
||||
**/
|
||||
|
||||
/** md */ test emit_twice [[
|
||||
stdio << 72 + 87 + 33 << 291
|
||||
]]/* **/ parse to Receives(
|
||||
Receives(Stdio(), Sum([Int("72"), Int("87"), Int("33")])),
|
||||
Int("291"))
|
||||
/** writes
|
||||
192291**/
|
||||
|
||||
/** md
|
||||
```
|
||||
Running this program produces a nice palindromic output: "192291".
|
||||
**/
|
1
tests/emit_sum.fos
Normal file
1
tests/emit_sum.fos
Normal file
@ -0,0 +1 @@
|
||||
stdio << 72 + 87 + 33
|
@ -15,12 +15,12 @@ rules // Analysis
|
||||
// single-file analysis
|
||||
editor-analyze = stx-editor-analyze(pre-analyze, post-analyze|"statics", "programOk")
|
||||
|
||||
// see README.md for details on how to switch to multi-file analysis
|
||||
// see docs/implementation.md for details on how to switch to multi-file analysis
|
||||
// multi-file analysis
|
||||
// editor-analyze = stx-editor-analyze(pre-analyze, post-analyze|"statics", "projectOk", "fileOk")
|
||||
|
||||
pre-analyze = origin-track-forced(explicate-injections-fostr-Start)
|
||||
post-analyze = origin-track-forced(implicate-injections-fostr-Start)
|
||||
pre-analyze = origin-track-forced(explicate-injections-fostr-Ex)
|
||||
post-analyze = origin-track-forced(implicate-injections-fostr-Ex)
|
||||
|
||||
rules // Editor Services
|
||||
|
||||
|
@ -6,6 +6,9 @@ imports
|
||||
pp
|
||||
outline
|
||||
analysis
|
||||
haskell
|
||||
javascript
|
||||
python
|
||||
|
||||
rules // Debugging
|
||||
|
||||
|
41
trans/haskell.str
Normal file
41
trans/haskell.str
Normal file
@ -0,0 +1,41 @@
|
||||
module haskell
|
||||
imports libstrategolib signatures/-
|
||||
|
||||
signature
|
||||
constructors
|
||||
TopLevel: Ex -> Ex
|
||||
|
||||
rules
|
||||
hs: TopLevel(x) -> $[import System.IO
|
||||
data IOStream = StdIO
|
||||
|
||||
stdio :: IO IOStream
|
||||
stdio = return StdIO
|
||||
|
||||
receives :: Show b => IO a -> b -> IO a
|
||||
receives s d = do
|
||||
temp <- s
|
||||
putStr(show d)
|
||||
return temp
|
||||
|
||||
main = do
|
||||
[<hs>x]]
|
||||
|
||||
hs: Stdio() -> $[stdio]
|
||||
hs: Int(x) -> x
|
||||
hs: Sum(x) -> $[sum [<hs>x]]
|
||||
hs: Receives(x, y) -> $[[<hs>x] `receives` [<hs>y]]
|
||||
hs: [] -> $<[]>
|
||||
hs: [x | xs] -> $<[<<hs>x><<hstail>xs>]>
|
||||
|
||||
strategies
|
||||
// wrap expression in a toplevel and then apply code generation
|
||||
haskell = !TopLevel(<id>); hs
|
||||
|
||||
// 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
|
||||
to-haskell: (selected, _, _, path, project-path) -> (filename, result)
|
||||
with filename := <guarantee-extension(|"hs")> path
|
||||
; result := <haskell> selected
|
31
trans/javascript.str
Normal file
31
trans/javascript.str
Normal file
@ -0,0 +1,31 @@
|
||||
module javascript
|
||||
imports libstrategolib signatures/-
|
||||
|
||||
signature
|
||||
constructors
|
||||
TopLevel: Ex -> Ex
|
||||
|
||||
rules
|
||||
js: TopLevel(x) -> $[const Stdio = {
|
||||
receives: v => { process.stdout.write(String(v)); return Stdio; }
|
||||
}
|
||||
[<js>x]]
|
||||
|
||||
js: Stdio() -> $[Stdio]
|
||||
js: Int(x) -> x
|
||||
js: Sum(x) -> $[[<js>x].reduce((v,w) => v+w)]
|
||||
js: Receives(x, y) -> $[[<js>x].receives([<js>y])]
|
||||
js: [] -> $<[]>
|
||||
js: [x | xs] -> $<[<<js>x><<jstail>xs>]>
|
||||
|
||||
strategies
|
||||
// wrap expression in a toplevel and then apply code generation
|
||||
javascript = !TopLevel(<id>); js
|
||||
|
||||
// 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
|
||||
to-javascript: (selected, _, _, path, project-path) -> (filename, result)
|
||||
with filename := <guarantee-extension(|"js")> path
|
||||
; result := <javascript> selected
|
34
trans/python.str
Normal file
34
trans/python.str
Normal file
@ -0,0 +1,34 @@
|
||||
module python
|
||||
imports libstrategolib signatures/-
|
||||
|
||||
signature
|
||||
constructors
|
||||
TopLevel: Ex -> Ex
|
||||
|
||||
rules
|
||||
py: TopLevel(x) -> $[import sys
|
||||
class StdioC:
|
||||
def receives(self, v):
|
||||
print(v, file=sys.stdout, end='')
|
||||
return self
|
||||
Stdio = StdioC()
|
||||
[<py>x]]
|
||||
|
||||
py: Stdio() -> $[Stdio]
|
||||
py: Int(x) -> x
|
||||
py: Sum(x) -> $[sum([<py>x])]
|
||||
py: Receives(x, y) -> $[[<py>x].receives([<py>y])]
|
||||
py: [] -> $<[]>
|
||||
py: [x | xs] -> $<[<<py>x><<pytail>xs>]>
|
||||
|
||||
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
|
||||
pytail = foldr(!"", \ (x,y) -> $[, [<py>x][y]] \)
|
||||
|
||||
// Interface python code generation with editor services and file system
|
||||
to-python: (selected, _, _, path, project-path) -> (filename, result)
|
||||
with filename := <guarantee-extension(|"py")> path
|
||||
; result := <python> selected
|
@ -1,12 +1,15 @@
|
||||
module statics
|
||||
|
||||
// see README.md for details on how to switch to multi-file analysis
|
||||
imports signatures/fostr-sig
|
||||
|
||||
// see docs/implementation.md for details on how to switch to multi-file analysis
|
||||
|
||||
rules // single-file entry point
|
||||
|
||||
programOk : Start
|
||||
programOk : Ex
|
||||
|
||||
programOk(Empty()).
|
||||
programOk(Sum(_)).
|
||||
programOk(Receives(_,_)).
|
||||
|
||||
rules // multi-file entry point
|
||||
|
||||
@ -14,11 +17,6 @@ rules // multi-file entry point
|
||||
|
||||
projectOk(s).
|
||||
|
||||
fileOk : scope * Start
|
||||
fileOk : scope * Ex
|
||||
|
||||
fileOk(s, Empty()).
|
||||
|
||||
signature
|
||||
|
||||
sorts Start constructors
|
||||
Empty : Start
|
||||
fileOk(s, Receives(_,_)).
|
||||
|
Loading…
Reference in New Issue
Block a user