Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
adamsol committed Oct 30, 2020
1 parent 5f0efd0 commit d2f3219
Show file tree
Hide file tree
Showing 22 changed files with 1,870 additions and 125 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ else
LIB_PATH = lib/:lib/
endif

all: parser libs exe
all: parser libs exe docs

parser:
"$(MAKE)" parser -C src
Expand All @@ -18,7 +18,12 @@ libs:
exe:
"$(PYTHON)" -m PyInstaller --hidden-import=decorator --add-data "$(LIB_PATH)" pyxell.py --noconfirm

.PHONY: docs
docs:
"$(MAKE)" docs -C docs

clean:
"$(MAKE)" clean -C src
rm -f lib/*.ll lib/*.json
rm -rf build/ dist/
"$(MAKE)" clean -C docs
122 changes: 31 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,89 +4,24 @@ Pyxell
### Clean and easy-to-use multi-paradigm programming language with static typing. ###


Documentation
-------------

https://www.pyxell.org/docs/


Motivation
----------

The project aims to combine the best features of different programming languages,
Pyxell [_pixel_] aims to combine the best features of different programming languages,
pack them into a clean and consistent syntax,
and provide the execution speed of native machine code.

It draws mainly from Python, C++, C#, and Haskell,
and tries to avoid common design flaws that have been nicely described
trying to avoid common design flaws that have been nicely described
[in this blog post](https://eev.ee/blog/2016/12/01/lets-stop-copying-c/).


Examples
--------

Rational numbers:

```
print 1/10 + 5^-1 # 3/10
```

Range literals, for-loops, string interpolation:

```
a = ['A'..'Z']
for x, i in a, 0... by 5 do
print "a[{i}] = {x}"
```

Dynamic containers:

```
[Int] a = [1] # array (Python's list / C++'s vector)
a.push(2)
{Float} b = {3.0} # hash set
b.add(4.0)
{Char:String} c = {'5': "6"} # dictionary (hash map)
c['7'] = "8"
```

Generic functions, lambda expressions:

```
func fold<A,B>([A] a, A->B->B f, B r) B def
for x in a do
r = f(x, r)
return r
print fold([2, 3, 4], _*_, 1) # 24
-- There are built-in methods like this:
print [0..10 by 2].reduce(_+_) # 30
```

Generators, tuples, spread syntax:

```
fib = lambda* n def
if n <= 0 do
return
a, b = 0, 1
yield a
for _ in 2..n do
yield b
a, b = b, a+b
print [...fib(10)]
```

Classes, nullable types:

```
class C def
String? s: null
c = C()
print c.s?.length
print c.s ?? "---"
```


Features
--------

Expand Down Expand Up @@ -115,12 +50,14 @@ Features
To do:

* Exception handling
* Unicode
* Static class fields and methods
* Complex numbers
* Unicode support
* Module system
* Multiple inheritance
* Generic classes
* Operator overloading
* Multiple inheritance
* Concurrency
* Module system
* Asynchronous programming


Requirements
Expand All @@ -134,8 +71,10 @@ python -m pip install -r requirements.txt

* C++17 compiler: Clang 5+ or GCC 7+.

Note that generators are currently supported only in Clang, since they are based on C++'s coroutines
(GCC 10 also supports coroutines, but as of version 10.1 the implementation is buggy, so it is not yet supported by Pyxell).
Note that generators are currently available only with Clang, since they are based on C++'s coroutines.
Though GCC 10 also supports coroutines, as of version 10.2 the implementation is buggy
(see [here](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95591) or [here](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95823)),
so it is not yet supported by Pyxell.


Usage
Expand All @@ -145,28 +84,29 @@ Usage
python pyxell.py program.px
```

If the program is correct, `program.cpp` file and `program.exe` executable will be created in the same folder,
If the program is valid, `program.cpp` file and `program.exe` executable will be created in the same folder,
and it will be automatically executed (unless you add `-n` option).
Otherwise, errors will be displayed, pointing to the erroneous code location.

By default, `clang` command is used to compile the code.
You can pick a different compiler using `-c` option.

Use `-s` to skip the compilation step and obtain transpiled C++ code with all headers included,
ready for manual compilation (with -std=c++17 option, and with -fcoroutines-ts in the case of Clang).

The executable is not optimized by default.
You can set the optimization level with `-O` option, e.g. `-O2`.
This will make the program run faster, but also make the compilation slower.

Use `-s` to skip the compilation step and obtain transpiled C++ code with all headers included,
ready for manual compilation (with `-std=c++17` option, and with `-fcoroutines-ts` in the case of Clang).

To see all options, use `-h`.


PyInstaller
-----------

You can build a standalone application using `PyInstaller`. Install it using `pip`, then run `make exe`.
An executable `pyxell.exe` (not requiring Python to run) will be created in the `dist/pyxell` folder.
You can build a standalone compiler application using `PyInstaller`.
Install `PyInstaller` with `pip`, then run `make exe`.
An executable (not requiring Python to run) will be created in the `dist/pyxell` folder.


Development
Expand All @@ -180,19 +120,22 @@ then run `make parser`.
After changing the code of Pyxell libraries (`lib/*.px` files),
run `make libs` to rebuild them.

To build the documentation, go to the `docs` folder, run `npm install`, then `make`.
To start a documentation server locally, install `flask` and run `server.py` in the same folder.


Tests
-----

```
python test.py [-v]
python test.py
```

Tests are divided into good (supposed to compile and run properly) and bad (should throw compilation errors).

By default, the whole C++ code for correct tests is merged, so that only one file is compiled,
By default, the whole C++ code for valid tests is merged, so that only one file is compiled,
which is faster than compiling hundreds of files individually, even using multiple threads.
Total execution time should be around 30-60 seconds.
Total execution time (with default settings) should be around 30-60 seconds.

If, however, the script fails with an error like this: `too many sections` / `file too big`
(seen with GCC 7.2 on Windows), or there is another compilation error that is hard to decipher,
Expand All @@ -202,9 +145,6 @@ You can pass a path pattern to run only selected tests (e.g. `python test.py arr

To see all options, run the script with `-h`.

Tests serve currently also as a documentation of the language.
You can browse them to learn the syntax and semantics.


Alternatives
------------
Expand Down
2 changes: 2 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
package-lock.json
170 changes: 170 additions & 0 deletions docs/.vuepress/components/PyxellPlayground.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@

<template>
<div>
<VueCodemirror v-model="code" ref="code" :options="options" />
<label title="Standard input for your program.">
<input v-model="show_input" type="checkbox" />
Input
</label>
<label style="padding-left: 6px" title="Will make the compilation slower, but the program may run faster.">
<input v-model="optimization" type="checkbox" />
Optimizations
</label>
<div class="input" :style="{ 'max-height': show_input ? INPUT_HEIGHT : 0 }">
<VueCodemirror v-model="input" ref="input" :options="{ mode: null, theme: THEME }" />
</div>
<div style="text-align: right">
<button :disabled="running" class="run" @click="run">
<span v-if="running" class="spin">
&#x25e0;
</span>
<span v-else>
&#x25B6;
</span>
Run
</button>
</div>
<pre class="language-output" :style="{ color: error ? 'red' : 'inherit' }">{{ output }}</pre>
</div>
</template>

<script>
import axios from 'axios';
import VueCodemirror from 'vue-codemirror/src/codemirror.vue';
import { CodeMirror } from 'vue-codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/theme/dracula.css';
import 'codemirror/addon/mode/simple.js';
import syntax from '../utils/pyxell-syntax.js';
CodeMirror.defineSimpleMode('pyxell', {
start: [
{ token: 'comment', regex: /#.*/ },
{ token: 'comment', regex: /{#/, next: 'comment' },
{ token: 'variable', regex: /\bprint\b/ },
{ token: 'atom', regex: syntax.atom },
{ token: 'keyword', regex: syntax.keyword },
{ token: 'variable-2', regex: syntax.variable_name },
{ token: 'variable-3', regex: syntax.type_name },
{ token: 'number', regex: syntax.number },
{ token: 'string', regex: syntax.string },
],
comment: [
{ token: 'comment', regex: /.*?#}/, next: 'start' },
{ token: 'comment', regex: /.*/ },
],
});
export default {
components: { VueCodemirror },
data: () => ({
CODE_HEIGHT: '450px',
INPUT_HEIGHT: '120px',
THEME: 'dracula',
code: '',
input: '',
show_input: false,
optimization: false,
running: false,
error: false,
output: '',
}),
computed: {
options() {
return {
mode: 'pyxell',
theme: this.THEME,
lineNumbers: true,
indentUnit: 4,
extraKeys: {
'Tab': cm => {
if (cm.getMode().name === 'null') {
cm.execCommand('insertTab');
} else {
if (cm.somethingSelected()) {
cm.execCommand('indentMore');
} else {
cm.execCommand('insertSoftTab');
}
}
},
'Shift-Tab': cm => {
cm.execCommand('indentLess');
},
},
};
},
},
methods: {
async run() {
localStorage.setItem('code', this.code);
this.output = '';
this.running = true;
let response = await axios.post('/transpile/', {
code: this.code,
});
if (response.data.error) {
this.error = true;
this.output = response.data.error;
} else {
const params = {
'LanguageChoice': 27, // C++ (clang)
'Program': response.data.cpp_code,
'Input': this.input,
'CompilerArgs': '-std=c++17 -fcoroutines-ts -o a.out source_file.cpp' +
(this.optimization ? ' -O2' : ''),
};
const form_data = new FormData();
for (const [name, value] of Object.entries(params)) {
form_data.set(name, value);
}
response = await axios.post('https://rextester.com/rundotnet/api/', form_data);
this.error = !!response.data.Errors;
this.output = response.data.Errors || response.data.Result;
}
this.running = false;
},
},
created() {
this.code = localStorage.getItem('code') || '\nprint "Hello, world!"\n';
},
mounted() {
this.$refs.code.codemirror.setSize('auto', this.CODE_HEIGHT);
this.$refs.input.codemirror.setSize('auto', this.INPUT_HEIGHT);
},
};
</script>

<style lang="stylus">
.CodeMirror
border: 1px solid #eee
box-sizing: border-box
div.input
overflow: hidden
transition: max-height 0.4s
button.run
background-color: $accentColor
border: none
border-radius: 5px
color: white
font-size: 1.2em
padding: 5px 25px
&:not(:disabled)
cursor: pointer
.spin
animation: spin 1s linear infinite
display: inline-block
@keyframes spin
from
transform: rotate(0deg)
to
transform: rotate(360deg)
</style>
Loading

0 comments on commit d2f3219

Please sign in to comment.