The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .clog.toml
├── .github
    └── workflows
    │   ├── release.yml
    │   └── rust.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.lock
├── Cargo.toml
├── Cross.toml
├── LICENSE
├── README.md
├── appveyor.yml
├── base
    ├── Cargo.toml
    ├── src
    │   ├── ast.rs
    │   ├── error.rs
    │   ├── fixed.rs
    │   ├── fnv.rs
    │   ├── kind.rs
    │   ├── lib.rs
    │   ├── macros.rs
    │   ├── merge.rs
    │   ├── metadata.rs
    │   ├── pos.rs
    │   ├── resolve.rs
    │   ├── scoped_map.rs
    │   ├── serialization.rs
    │   ├── source.rs
    │   ├── symbol.rs
    │   └── types
    │   │   ├── flags.rs
    │   │   ├── mod.rs
    │   │   └── pretty_print.rs
    └── tests
    │   ├── compile-fail
    │       ├── arena-1.rs
    │       └── arena-2.rs
    │   ├── compiletest.rs
    │   └── types.rs
├── benches
    ├── check.rs
    ├── function_call.rs
    └── precompiled.rs
├── book
    ├── .gitignore
    ├── book.toml
    └── src
    │   ├── SUMMARY.md
    │   ├── anatomy-of-a-gluon-program.md
    │   ├── dissecting-hello-world.md
    │   ├── embedding-api.md
    │   ├── extending-the-guessing-game-with-effects.md
    │   ├── getting-started.md
    │   ├── marshalling-types.md
    │   ├── metadata.md
    │   ├── modules.md
    │   ├── standard-types-and-functions.md
    │   ├── syntax-and-semantics.md
    │   └── using-the-repl.md
├── build.rs
├── c-api
    ├── Cargo.toml
    └── src
    │   └── lib.rs
├── check
    ├── Cargo.toml
    ├── src
    │   ├── implicits.rs
    │   ├── kindcheck.rs
    │   ├── lib.rs
    │   ├── metadata.rs
    │   ├── recursion_check.rs
    │   ├── rename.rs
    │   ├── substitution.rs
    │   ├── typ.rs
    │   ├── typecheck.rs
    │   ├── typecheck
    │   │   ├── error.rs
    │   │   ├── generalize.rs
    │   │   └── mod_type.rs
    │   ├── unify.rs
    │   └── unify_type.rs
    └── tests
    │   ├── effect.rs
    │   ├── error_recovery.rs
    │   ├── fail.rs
    │   ├── forall.rs
    │   ├── gadt.rs
    │   ├── implicits.rs
    │   ├── metadata.rs
    │   ├── pass.rs
    │   ├── recursive.rs
    │   ├── row_polymorphism.rs
    │   ├── snapshots
    │       ├── fail__alias_mismatch.snap
    │       ├── fail__multiple_extra_parameters_error.snap
    │       ├── fail__no_inference_variable_in_error.snap
    │       ├── fail__unable_to_resolve_implicit_error_message.snap
    │       └── fail__unification_error_with_empty_record_displays_good_error_message.snap
    │   ├── stack_overflow.rs
    │   ├── support
    │       └── mod.rs
    │   └── type_projection.rs
├── codegen
    ├── Cargo.toml
    ├── src
    │   ├── arena_clone.rs
    │   ├── ast_clone.rs
    │   ├── attr.rs
    │   ├── functor.rs
    │   ├── getable.rs
    │   ├── lib.rs
    │   ├── pushable.rs
    │   ├── shared.rs
    │   ├── trace.rs
    │   ├── userdata.rs
    │   └── vm_type.rs
    └── tests
    │   ├── derive_getable.rs
    │   ├── derive_pushable.rs
    │   ├── derive_userdata.rs
    │   ├── derive_vm_type.rs
    │   ├── full.rs
    │   └── init
    │       └── mod.rs
├── completion
    ├── Cargo.toml
    ├── src
    │   └── lib.rs
    └── tests
    │   ├── completion.rs
    │   ├── metadata.rs
    │   ├── signature_help.rs
    │   ├── suggest.rs
    │   └── support
    │       └── mod.rs
├── doc
    ├── Cargo.toml
    ├── build.rs
    ├── src
    │   ├── doc
    │   │   ├── module.html
    │   │   └── style.css
    │   ├── lib.rs
    │   └── main.rs
    └── tests
    │   └── doc.rs
├── examples
    ├── 24.glu
    ├── 24.rs
    ├── fib.rs
    ├── http
    │   ├── main.rs
    │   └── server.glu
    ├── lisp
    │   ├── lisp.glu
    │   ├── main.rs
    │   ├── parser.glu
    │   └── types.glu
    └── marshalling.rs
├── format
    ├── Cargo.toml
    ├── src
    │   ├── lib.rs
    │   └── pretty_print.rs
    └── tests
    │   ├── pretty_print.rs
    │   └── std.rs
├── parser
    ├── Cargo.toml
    ├── benches
    │   └── parser.rs
    ├── build.rs
    ├── src
    │   ├── grammar.lalrpop
    │   ├── infix.rs
    │   ├── layout.rs
    │   ├── lib.rs
    │   ├── str_suffix.rs
    │   └── token.rs
    └── tests
    │   ├── attributes.rs
    │   ├── basic.rs
    │   ├── error_handling.rs
    │   ├── indentation.rs
    │   ├── stack_overflow.rs
    │   ├── support
    │       └── mod.rs
    │   └── types.rs
├── repl
    ├── Cargo.toml
    ├── build.rs
    ├── src
    │   ├── main.rs
    │   ├── repl.glu
    │   └── repl.rs
    └── tests
    │   ├── basic.rs
    │   ├── print.glu
    │   └── rexpect.rs
├── scripts
    ├── before_deploy.sh
    ├── ci.sh
    ├── install.sh
    ├── install_cross.sh
    ├── install_mdbook.sh
    ├── install_sccache.sh
    ├── publish.sh
    ├── release.sh
    ├── sync_publish.sh
    └── version.sh
├── src
    ├── compiler_pipeline.rs
    ├── import.rs
    ├── lib.rs
    ├── lift_io.rs
    ├── query.rs
    ├── std_lib.rs
    └── std_lib
    │   ├── env.rs
    │   ├── http.rs
    │   ├── io.rs
    │   ├── process.rs
    │   ├── random.rs
    │   └── regex.rs
├── std
    ├── alternative.glu
    ├── applicative.glu
    ├── array.glu
    ├── assert.glu
    ├── bool.glu
    ├── byte.glu
    ├── category.glu
    ├── channel.glu
    ├── char.glu
    ├── cmp.glu
    ├── debug.glu
    ├── disposable.glu
    ├── effect.glu
    ├── effect
    │   ├── alt.glu
    │   ├── error.glu
    │   ├── io.glu
    │   ├── io
    │   │   ├── read.glu
    │   │   └── write.glu
    │   ├── lift.glu
    │   ├── reader.glu
    │   ├── reference.glu
    │   ├── st.glu
    │   ├── st
    │   │   └── string.glu
    │   ├── state.glu
    │   └── writer.glu
    ├── env.glu
    ├── float.glu
    ├── foldable.glu
    ├── fs.glu
    ├── function.glu
    ├── functor.glu
    ├── group.glu
    ├── http.glu
    ├── http
    │   └── types.glu
    ├── identity.glu
    ├── int.glu
    ├── io.glu
    ├── io
    │   ├── base.glu
    │   ├── read.glu
    │   └── write.glu
    ├── json.glu
    ├── json
    │   ├── de.glu
    │   └── ser.glu
    ├── lazy.glu
    ├── lazyt.glu
    ├── list.glu
    ├── map.glu
    ├── monad.glu
    ├── monoid.glu
    ├── num.glu
    ├── option.glu
    ├── parser.glu
    ├── path.glu
    ├── path
    │   └── types.glu
    ├── prelude.glu
    ├── process.glu
    ├── random.glu
    ├── reference.glu
    ├── regex.glu
    ├── regex
    │   └── types.glu
    ├── result.glu
    ├── semigroup.glu
    ├── show.glu
    ├── state.glu
    ├── statet.glu
    ├── stream.glu
    ├── string.glu
    ├── test.glu
    ├── thread.glu
    ├── transformer.glu
    ├── traversable.glu
    ├── types.glu
    ├── unit.glu
    └── writer.glu
├── tests
    ├── api.rs
    ├── array.rs
    ├── compile-fail
    │   ├── get-reference.rs
    │   ├── getable-reference-str.rs
    │   ├── getable-reference.rs
    │   ├── run_expr_str_ref.rs
    │   └── store-ref.rs
    ├── compiletest.rs
    ├── de.rs
    ├── debug.rs
    ├── error.rs
    ├── fail.rs
    ├── fail
    │   ├── cyclic_dependency.glu
    │   ├── deps
    │   │   └── cyclic_dependency2.glu
    │   └── unwrap.glu
    ├── inline.rs
    ├── io.rs
    ├── limits.rs
    ├── main.rs
    ├── metadata.rs
    ├── optimize
    │   ├── cmp.glu
    │   ├── inline_num.glu
    │   ├── inline_through_module.glu
    │   └── inline_through_module2.glu
    ├── parallel.rs
    ├── pass
    │   ├── alternative.glu
    │   ├── arithmetic.glu
    │   ├── buffered_io.glu
    │   ├── channel.glu
    │   ├── char.glu
    │   ├── deep_clone_userdata.glu
    │   ├── derive.glu
    │   ├── io.glu
    │   ├── json
    │   │   ├── de.glu
    │   │   └── ser.glu
    │   ├── lazy.glu
    │   ├── lazyt.glu
    │   ├── lisp.glu
    │   ├── list.glu
    │   ├── map.glu
    │   ├── match_literal.glu
    │   ├── parser.glu
    │   ├── path.glu
    │   ├── reference.glu
    │   ├── regex.glu
    │   ├── state.glu
    │   ├── statet.glu
    │   ├── stream.glu
    │   ├── string.glu
    │   ├── thread.glu
    │   ├── unwrap.glu
    │   └── writer.glu
    ├── pattern_match.rs
    ├── row_polymorphism.rs
    ├── safety.rs
    ├── serialization.rs
    ├── skeptic-template.md
    ├── skeptic-tests.rs
    ├── snapshots
    │   └── ui__macro_error_with_line_column_info.snap
    ├── stack_overflow.rs
    ├── support
    │   └── mod.rs
    ├── tutorial.rs
    ├── ui.rs
    ├── unrelated_type_error.glu
    └── vm.rs
└── vm
    ├── Cargo.toml
    ├── build.rs
    └── src
        ├── api
            ├── de.rs
            ├── function.rs
            ├── json.rs
            ├── mac.rs
            ├── mod.rs
            ├── opaque.rs
            ├── record.rs
            ├── scoped.rs
            ├── ser.rs
            └── typ.rs
        ├── array.rs
        ├── channel.rs
        ├── compiler.rs
        ├── core
            ├── costs.rs
            ├── dead_code.rs
            ├── grammar.lalrpop
            ├── interpreter.rs
            ├── mod.rs
            ├── optimize.rs
            ├── pretty.rs
            └── purity.rs
        ├── debug.rs
        ├── derive
            ├── deserialize.rs
            ├── eq.rs
            ├── mod.rs
            ├── serialize.rs
            └── show.rs
        ├── dynamic.rs
        ├── gc.rs
        ├── gc
            └── mutex.rs
        ├── interner.rs
        ├── lazy.rs
        ├── lib.rs
        ├── macros.rs
        ├── primitives.rs
        ├── reference.rs
        ├── serialization.rs
        ├── source_map.rs
        ├── stack.rs
        ├── thread.rs
        ├── types.rs
        ├── value.rs
        └── vm.rs


/.clog.toml:
--------------------------------------------------------------------------------
1 | [clog]
2 | repository = "https://github.com/gluon-lang/gluon"
3 | 
4 | changelog = "CHANGELOG.md"
5 | 
6 | from-latest-tag = true
7 | 


--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
 1 | name: release
 2 | on:
 3 |   push:
 4 |     tags:
 5 |       - '*'
 6 | jobs:
 7 |   release:
 8 |     runs-on: ubuntu-latest
 9 |     - name: release
10 |       uses: actions/create-release@v1
11 |       id: create_release
12 |       with:
13 |         draft: false
14 |         prerelease: false
15 |         release_name: ${{ steps.version.outputs.version }}
16 |         tag_name: ${{ github.ref }}
17 |         body_path: CHANGELOG.md
18 |       env:
19 |         GITHUB_TOKEN: ${{ github.token }}
20 |     # Only run deployment on git tags
21 |     - CURRENT_TAG=`git describe --exact-match --abbrev=0 --tags || true`
22 |     - >
23 |         if [[ $CURRENT_TAG != "" ]]; then
24 |             export GIT_HASH=$(git rev-parse HEAD)
25 |             sh scripts/before_deploy.sh
26 |         fi
27 | 


--------------------------------------------------------------------------------
/.github/workflows/rust.yml:
--------------------------------------------------------------------------------
 1 | name: ci
 2 | on:
 3 |   pull_request:
 4 |   push:
 5 |     branches:
 6 |     - master
 7 | jobs:
 8 |   test:
 9 |     name: test
10 |     runs-on: ubuntu-latest
11 |     strategy:
12 |       matrix:
13 |         rust: [stable, nightly]
14 |     env:
15 |       CRATE_NAME: gluon
16 |       CARGO_INCREMENTAL: 0 # Incremental compilation is slower and bloats the cache
17 |       RUST_BACKTRACE: 1
18 |       # RUSTC_WRAPPER: sccache
19 |       SCCACHE_CACHE_SIZE: 500M
20 |     steps:
21 |     - name: Checkout repository
22 |       uses: actions/checkout@v2
23 |     - name: Use cache
24 |       uses: actions/cache@v2
25 |       with:
26 |         path: |
27 |           ~/bin
28 |         key: ${{ runner.os }}-${{ matrix.rust }}
29 |     - name: Install Rust
30 |       uses: hecrj/setup-rust-action@v1
31 |       with:
32 |         rust-version: ${{ matrix.rust }}
33 |     - uses: Swatinem/rust-cache@v2
34 |     - run: echo "$HOME/bin" >> $GITHUB_PATH
35 |     - run: mkdir -p $HOME/bin
36 |     - name: Setup tools
37 |       if: steps.cache.outputs.cache-hit != 'true'
38 |       run: |
39 |           # ./scripts/install_sccache.sh $TARGET
40 |           source ~/.cargo/env || true
41 |           ./scripts/install_mdbook.sh $TARGET
42 |     - name: Run tests
43 |       run: |
44 |           if [ ! -z $DISABLE_TESTS ]; then
45 |               return
46 |           elif [[ -z ${WASM+set} ]]; then
47 |               mdbook build book
48 |               ./scripts/ci.sh
49 |               if ! git diff-index HEAD --; then
50 |                   echo "Detected changes in the source after running tests"
51 |                   exit 1
52 |               fi
53 |           else
54 |               rustup target add wasm32-unknown-unknown
55 |               cargo check --target wasm32-unknown-unknown -p gluon_c-api
56 |           fi
57 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | 
 2 | *.swp
 3 | *.swo
 4 | # rustfmt backup files
 5 | *.bk
 6 | *.bak
 7 | *.rs.fmt
 8 | 
 9 | *.bak
10 | 
11 | target
12 | 
13 | .vscode
14 | 


--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
 1 | # Contributing to Gluon
 2 | 
 3 | ## Filing bug reports
 4 | 
 5 | It does not matter if you found a soundness issue in typechecker or found the documentation confusing. Either way filing an issue to the [issue tracker][] is extremely helpful.
 6 | 
 7 | [issue tracker]:https://github.com/gluon-lang/gluon/issues
 8 | 
 9 | ## Finding something to work on
10 | 
11 | A good place to start is to look at the issues marked as [beginner][]. These are issues that should be possible to work on without knowledge on the inner workings of Gluon.
12 | 
13 | If you find something that looks interesting, please leave a comment on the issue. That way, you can get assistance quicker and there is no risk of duplicating work.
14 | 
15 | [beginner]:https://github.com/gluon-lang/gluon/labels/Beginner
16 | 
17 | ## Building
18 | 
19 | Gluon can build with version 1.9.0 of Rust or later but we recommend version 1.11.0 or later to avoid some very long compile times for the `gluon_parser` crate.
20 | 
21 | ## Testing
22 | 
23 | To build and run all(*) tests for Gluon you can call `cargo test --features test --all`. Instead of `--all` you can pass the `-p <crate name>` and `--test <test module>` flags to compile a specific crate and/or test module. For instance, `cargo test --features test -p gluon_parser --test basic` to run the tests in [parsers/tests/basic.rs](https://github.com/gluon-lang/gluon/blob/master/parser/tests/basic.rs).
24 | 
25 | (*) You can see what Github actions actually builds and tests in [scripts/ci.sh](https://github.com/gluon-lang/gluon/blob/master/scripts/ci.sh). Most of the time you should not need to worry about these additional tests and can just rely on CI running them.
26 | 
27 | ## Pull requests
28 | 
29 | Once you have made some changes, you will need to file a pull request to get your changes merged into the main repository. If the code is still a work in progress, it can still be a good idea to submit a PR. That will let other contributors see your progress and provide assistance (you may prefix the PR message with [WIP] to make it explicit that the PR is incomplete).
30 | 
31 | You may see that some of the [commits][] follow the [commit message convention of Angular][]. Following this convention is optional but if you enjoy using it, feel free to do so!
32 | 
33 | [commits]:https://github.com/gluon-lang/gluon/commit/9b36d699c63e482969239ed9f84779f7cd1ad2f3
34 | [commit message convention of Angular]:https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format
35 | 
36 | ## Releases
37 | 
38 | Releases are done by running `./scripts/release.sh <patch|minor|major> <new-version>` on a branch and making a PR. After the PR is merged and has passed CI `git push --tags` will make CI publish the new version.
39 | 


--------------------------------------------------------------------------------
/Cross.toml:
--------------------------------------------------------------------------------
1 | [build.env]
2 | passthrough = [
3 |     "RUST_BACKTRACE",
4 |     "RUST_LOG",
5 |     "GIT_HASH",
6 | ]
7 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2015 Markus Westerlind
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 | 
23 | 


--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
 1 | environment:
 2 |   global:
 3 |     # This will be used as part of the zipfile name
 4 |     PROJECT_NAME: gluon
 5 |     # By default schannel checks revocation of certificates unlike some other SSL
 6 |     # backends, but we've historically had problems on CI where a revocation
 7 |     # server goes down presumably. See rust-lang/#43333 for more info
 8 |     CARGO_HTTP_CHECK_REVOKE: false
 9 |   matrix:
10 |     - TARGET: x86_64-pc-windows-msvc
11 |       CHANNEL: nightly
12 | 
13 | # Install Rust and Cargo
14 | # (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
15 | install:
16 |   - curl -sSf -o rustup-init.exe https://win.rustup.rs
17 |   - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
18 |   - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
19 |   - rustc -Vv
20 |   - cargo -V
21 | 
22 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents
23 | # the "directory does not contain a project or solution file" error.
24 | # source: https://github.com/starkat99/appveyor-rust/blob/master/appveyor.yml#L113
25 | build: false
26 | 
27 | # Equivalent to Travis' `script` phase
28 | # TODO modify this phase as you see fit
29 | test_script:
30 |   - cargo test --features test --all
31 |   - cargo check --all --no-default-features
32 |   - cargo build --release -p gluon_repl
33 | 
34 | before_deploy:
35 |   # Generate artifacts for release
36 |   - cargo build --release -p gluon_repl
37 |   - mkdir staging
38 |   # TODO update this part to copy the artifacts that make sense for your project
39 |   - copy target\release\gluon.exe staging
40 |   - cd staging
41 |     # release zipfile will look like 'rust-everywhere-v1.2.3-x86_64-pc-windows-msvc'
42 |   - 7z a ..\%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip *
43 |   - appveyor PushArtifact ..\%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip
44 | 
45 | deploy:
46 |   description: 'Windows release'
47 |   artifact: target\release\gluon.exe
48 |   # TODO Regenerate this auth_token for your project, this one won't work for you. Here's how:
49 |   # - Go to 'https://github.com/settings/tokens/new' and generate a Token with only the
50 |   # `public_repo` scope enabled
51 |   # - Then go to 'https://ci.appveyor.com/tools/encrypt' and enter the newly generated token.
52 |   # - Enter the "encrypted value" below
53 |   auth_token:
54 |     secure: 0fkZyK+5fQgQVFWFTVCFwrZJDp8aAaMJorsgNZd8YF0aasbd7hWC8EUVCL5YSNuc
55 |   provider: GitHub
56 |   # deploy when a new tag is pushed and only on the nightly channel
57 |   on:
58 |     # channel to use to produce the release artifacts
59 |     CHANNEL: nightly
60 |     appveyor_repo_tag: true
61 | 
62 | branches:
63 |   only:
64 |     - master
65 |     # IMPORTANT Regex to match tags. Required, or appveyor may not trigger deploys when a new tag
66 |     # is pushed. This regex matches semantic versions like v1.2.3-rc4+2016.02.22
67 |     - /^v\d+\.\d+\.\d+.*$/
68 | 


--------------------------------------------------------------------------------
/base/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_base"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | 
 9 | description = "Basic type definitions and functions for the gluon programming language"
10 | 
11 | homepage = "https://gluon-lang.org"
12 | repository = "https://github.com/gluon-lang/gluon"
13 | documentation = "https://docs.rs/gluon"
14 | 
15 | [dependencies]
16 | bitflags = "1.3.2"
17 | hashbrown = "0.11.2"
18 | log = "0.4.20"
19 | quick-error = "2.0.1"
20 | fnv = "1.0.7"
21 | pretty = "0.10.0"
22 | smallvec = "1.11.0"
23 | collect-mac = "0.1.0"
24 | anymap = { version = "0.12.1", optional = true }
25 | itertools = "0.10.5"
26 | ordered-float = "2.10.0"
27 | codespan = "0.11.1"
28 | codespan-reporting = "0.11.1"
29 | either = "1.9.0"
30 | vec_map = "0.8.2"
31 | typed-arena = "2.0.2"
32 | 
33 | gluon_codegen = { version = "0.18.2", path = "../codegen" } # GLUON
34 | 
35 | serde = { version = "1.0.188", features = ["rc"], optional = true }
36 | serde_state = { version = "0.4.8", features = ["rc"], optional = true }
37 | serde_derive = { version = "1.0.188", optional = true }
38 | serde_derive_state = { version = "0.4.10", optional = true }
39 | 
40 | # Crates used in testing
41 | compiletest_rs = { version = "0.7.1", optional = true }
42 | 
43 | [dev-dependencies]
44 | env_logger = "0.9.3"
45 | pretty_assertions = "1.4.0"
46 | 
47 | [features]
48 | serialization = ["serde", "serde_state", "serde_derive", "serde_derive_state", "anymap"]
49 | nightly = ["compiletest_rs"]
50 | 


--------------------------------------------------------------------------------
/base/src/fnv.rs:
--------------------------------------------------------------------------------
 1 | extern crate fnv;
 2 | 
 3 | use std::collections::{HashMap, HashSet};
 4 | use std::hash::BuildHasherDefault;
 5 | 
 6 | pub use self::fnv::FnvHasher;
 7 | 
 8 | /// Non-crypto `HashMap` using Fnv Hasher
 9 | ///
10 | /// The default hashing implementation in `std::collections` uses `SipHasher`
11 | /// since gluon doesn't need the cryptographic guarantee provided by `SipHasher`,
12 | /// we've opted for the faster fnv hash.
13 | pub type FnvMap<K, V> = HashMap<K, V, BuildHasherDefault<FnvHasher>>;
14 | 
15 | /// Non-crypto `HashSet` using Fnv Hasher
16 | ///
17 | /// The default hashing implementation in `std::collections` uses `SipHasher`
18 | /// since gluon doesn't need the cryptographic guarantee provided by `SipHasher`,
19 | /// we've opted for the faster fnv hash.
20 | pub type FnvSet<K> = HashSet<K, BuildHasherDefault<FnvHasher>>;
21 | 


--------------------------------------------------------------------------------
/base/src/macros.rs:
--------------------------------------------------------------------------------
 1 | #[macro_export]
 2 | macro_rules! ice {
 3 |     () => ({
 4 |         panic!("ICE: Please report an issue at https://github.com/gluon-lang/gluon/issues")
 5 |     });
 6 |     ($msg:expr) => ({
 7 |         panic!(concat!($msg, ". Please report an issue at https://github.com/gluon-lang/gluon/issues"))
 8 |     });
 9 |     ($fmt:expr, $($arg:tt)+) => ({
10 |         panic!(concat!($fmt, ". Please report an issue at https://github.com/gluon-lang/gluon/issues"), $($arg)+)
11 |     });
12 | }
13 | 


--------------------------------------------------------------------------------
/base/tests/compile-fail/arena-1.rs:
--------------------------------------------------------------------------------
 1 | extern crate gluon_base;
 2 | 
 3 | use gluon_base::{
 4 |     ast::{Arena, Expr, RootExpr},
 5 |     mk_ast_arena, pos,
 6 | };
 7 | 
 8 | fn main() {
 9 |     mk_ast_arena!(arena1);
10 |     mk_ast_arena!(arena2);
11 |     //~^ `tag` does not live long enough [E0597]
12 | 
13 |     let arena1_expr = arena1.alloc(pos::spanned(
14 |         Default::default(),
15 |         Expr::<String>::Error(None),
16 |     ));
17 | 
18 |     RootExpr::new(arena2, arena1_expr);
19 | }
20 | 


--------------------------------------------------------------------------------
/base/tests/compile-fail/arena-2.rs:
--------------------------------------------------------------------------------
 1 | extern crate gluon_base;
 2 | 
 3 | use gluon_base::{
 4 |     ast::{Arena, Expr, RootExpr},
 5 |     mk_ast_arena, pos,
 6 | };
 7 | 
 8 | fn main() {
 9 |     mk_ast_arena!(arena1);
10 |     mk_ast_arena!(arena2);
11 |     //~^ `tag` does not live long enough [E0597]
12 | 
13 |     let arena2_expr = arena2.alloc(pos::spanned(
14 |         //~^ `arena2` does not live long enough [E0597]
15 |         Default::default(),
16 |         Expr::<String>::Error(None),
17 |     ));
18 | 
19 |     // Should fail
20 |     RootExpr::new(arena1, arena2_expr);
21 | }
22 | 


--------------------------------------------------------------------------------
/base/tests/compiletest.rs:
--------------------------------------------------------------------------------
 1 | #![cfg(feature = "nightly")]
 2 | extern crate compiletest_rs as compiletest;
 3 | extern crate env_logger;
 4 | 
 5 | use std::fs;
 6 | use std::path::{Path, PathBuf};
 7 | 
 8 | fn lib_dir(out_dir: &Path, lib_name: &str) -> PathBuf {
 9 |     // Just loading gluon through -L dir does not work as we compile gluon with different sets of
10 |     // flags which gives ambiguity errors.
11 |     // Instead retrieve the latest compiled gluon library which should usually be the correct one
12 |     let mut gluon_rlibs: Vec<_> = fs::read_dir(out_dir.join("deps"))
13 |         .unwrap()
14 |         .filter_map(|entry| {
15 |             let entry = entry.expect("dir entry");
16 |             if entry
17 |                 .path()
18 |                 .to_str()
19 |                 .map_or(false, |name| name.contains(lib_name))
20 |             {
21 |                 Some(entry)
22 |             } else {
23 |                 None
24 |             }
25 |         })
26 |         .collect();
27 |     gluon_rlibs.sort_by(|l, r| {
28 |         l.metadata()
29 |             .unwrap()
30 |             .modified()
31 |             .unwrap()
32 |             .cmp(&r.metadata().unwrap().modified().unwrap())
33 |     });
34 |     gluon_rlibs.last().expect("libgluon not found").path()
35 | }
36 | 
37 | fn run_mode(mode: &'static str) {
38 |     // Retrieve the path where library dependencies are output
39 |     let out_dir = PathBuf::from("../target/debug");
40 |     let gluon_base_rlib = lib_dir(&out_dir, "libgluon_base-");
41 | 
42 |     let mut config = compiletest::Config::default();
43 |     let cfg_mode = mode.parse().ok().expect("Invalid mode");
44 | 
45 |     config.verbose = true;
46 |     config.mode = cfg_mode;
47 |     config.src_base = PathBuf::from(format!("tests/{}", mode));
48 |     config.target_rustcflags = Some(format!(
49 |         "-L {}/deps --extern gluon_base={}",
50 |         out_dir.display(),
51 |         gluon_base_rlib.display(),
52 |     ));
53 |     println!("{}", config.target_rustcflags.as_ref().unwrap());
54 |     compiletest::run_tests(&config);
55 | }
56 | 
57 | #[test]
58 | fn compile_test() {
59 |     let _ = env_logger::try_init();
60 |     run_mode("compile-fail");
61 | }
62 | 


--------------------------------------------------------------------------------
/benches/precompiled.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate criterion;
 3 | 
 4 | use std::{fs::File, io::Read};
 5 | 
 6 | use criterion::{Bencher, Criterion};
 7 | 
 8 | use gluon::{compiler_pipeline::compile_to, new_vm, ThreadExt};
 9 | 
10 | fn precompiled_prelude(b: &mut Bencher) {
11 |     let thread = new_vm();
12 |     let prelude = {
13 |         let mut out = String::new();
14 |         File::open("std/prelude.glu")
15 |             .unwrap()
16 |             .read_to_string(&mut out)
17 |             .unwrap();
18 |         out
19 |     };
20 |     let mut serialized_prelude = Vec::new();
21 |     {
22 |         let mut serializer = serde_json::Serializer::new(&mut serialized_prelude);
23 |         futures::executor::block_on(compile_to(
24 |             &prelude[..],
25 |             &mut thread.module_compiler(&mut thread.get_database()),
26 |             &thread,
27 |             "std.prelude",
28 |             &prelude,
29 |             None,
30 |             &mut serializer,
31 |         ))
32 |         .unwrap()
33 |     }
34 |     b.iter(|| {
35 |         use gluon::compiler_pipeline::{Executable, Precompiled};
36 | 
37 |         let mut deserializer = serde_json::Deserializer::from_slice(&serialized_prelude);
38 |         futures::executor::block_on(Precompiled(&mut deserializer).run_expr(
39 |             &mut thread.module_compiler(&mut thread.get_database()),
40 |             &*thread,
41 |             "std.prelude",
42 |             "",
43 |             (),
44 |         ))
45 |         .unwrap()
46 |     })
47 | }
48 | 
49 | fn source_prelude(b: &mut Bencher) {
50 |     let mut prelude_source = String::new();
51 |     File::open("std/prelude.glu")
52 |         .and_then(|mut f| f.read_to_string(&mut prelude_source))
53 |         .unwrap();
54 |     let thread = new_vm();
55 | 
56 |     b.iter(|| {
57 |         use gluon::compiler_pipeline::Executable;
58 |         futures::executor::block_on(prelude_source.run_expr(
59 |             &mut thread.module_compiler(&mut thread.get_database()),
60 |             &*thread,
61 |             "std.prelude",
62 |             &prelude_source,
63 |             None,
64 |         ))
65 |         .unwrap()
66 |     })
67 | }
68 | 
69 | fn precompiled_benchmark(c: &mut Criterion) {
70 |     c.bench_function("source std/prelude", source_prelude);
71 |     c.bench_function("precompiled std/prelude", precompiled_prelude);
72 | }
73 | 
74 | criterion_group!(precompiled, precompiled_benchmark);
75 | criterion_main!(precompiled);
76 | 


--------------------------------------------------------------------------------
/book/.gitignore:
--------------------------------------------------------------------------------
1 | book
2 | 


--------------------------------------------------------------------------------
/book/book.toml:
--------------------------------------------------------------------------------
1 | [book]
2 | title = "Gluon Documentation"
3 | description = "Gluon is a static, type inferred and embeddable language written in Rust"
4 | authors = ["Markus Westerlind"]
5 | multilingual = false
6 | src = "src"
7 | 


--------------------------------------------------------------------------------
/book/src/SUMMARY.md:
--------------------------------------------------------------------------------
 1 | # Summary
 2 | 
 3 | - [Getting started](./getting-started.md)
 4 | 
 5 |     - [Dissecting Hello World](./dissecting-hello-world.md)
 6 | 
 7 |     - [Using the REPL](./using-the-repl.md)
 8 | 
 9 |     - [Anatomy of a gluon program](./anatomy-of-a-gluon-program.md)
10 | 
11 |     - [Extending the guessing game with extensible effects](./extending-the-guessing-game-with-effects.md)
12 | 
13 | - [Syntax and semantics](./syntax-and-semantics.md)
14 | 
15 | - [Metadata](./metadata.md)
16 | 
17 | - [Modules](./modules.md)
18 | 
19 | - [Embedding API](./embedding-api.md)
20 | 
21 |     - [Marshalling types](./marshalling-types.md)
22 | 
23 | - [Standard types and functions](./standard-types-and-functions.md)
24 | 


--------------------------------------------------------------------------------
/book/src/dissecting-hello-world.md:
--------------------------------------------------------------------------------
 1 | # Dissecting Hello World
 2 | 
 3 | ```gluon
 4 | let io = import! std.io
 5 | io.println "Hello world!"
 6 | ```
 7 | 
 8 | There are a number of things going on in the hello world example so lets break them down one step at a time.
 9 | 
10 | ```gluon
11 | let
12 | ```
13 | 
14 | Gluon uses the keyword `let` to bind values for later use.
15 | 
16 | ```gluon
17 | import! std.io
18 | ```
19 | 
20 | `import!` is a builtin macro which loads the contents of another module. In the example we use it to get access to the standard library's `io` module. Since it appeared on the right side of `let io =` we thus bound the `std.io` module to the `io` binding.
21 | 
22 | ```
23 | io.println
24 | ```
25 | 
26 | Here we access the `println` function from the `io` module we bound earlier which is a function that lets us write strings to stdout.
27 | 
28 | ```gluon
29 | "Hello world!"
30 | ```
31 | 
32 | Finally we create a string literal which gets passed to `println` to get printed.
33 | 


--------------------------------------------------------------------------------
/book/src/getting-started.md:
--------------------------------------------------------------------------------
 1 | # Getting started
 2 | 
 3 | To get started with gluon we must first have a way to compile and run Gluon programs. The fastest way to get that is to download one of the pre-built binaries for Linux, Windows, OSX or FreeBSD from https://github.com/gluon-lang/gluon/releases. Alternatively, if you have a Rust compiler and Cargo installed you may install it with `cargo install gluon_repl`.
 4 | 
 5 | Once installed you can verify that it works by saving the following program into a file named `hello_world.glu` and then compile and run it with `gluon hello_world.glu`.
 6 | 
 7 | ```gluon
 8 | let io = import! std.io
 9 | io.println "Hello world!"
10 | ```
11 | 
12 | If everything works the program should have printed `Hello world!` to your terminal.
13 | 


--------------------------------------------------------------------------------
/book/src/modules.md:
--------------------------------------------------------------------------------
 1 | # Modules
 2 | 
 3 | ## Importing modules
 4 | 
 5 | As is often the case, it is convenient to separate code into multiple files which can later be imported and used from multiple other files. To do this, we can use the `import!` macro which takes a single string literal as argument and loads and compiles that file at compile time before the importing module is compiled.
 6 | 
 7 | For example, say that we need the `assert` function from the `test` module which can be found at `std/test.glu`. We might write something like this:
 8 | 
 9 | ```f#,rust
10 | let { assert } = import! std.test
11 | assert (1 == 1)
12 | ```
13 | 
14 | ## Writing modules
15 | 
16 | Importing standard modules is all well and good but it is also necessary to write your own once a program starts getting too big for a single file. As it turns out, if you have been following along so far, you already know everything about writing a module! Creating and loading a module in gluon entails creating a file containing an expression which is then loaded and evaluated using `import!`. `import!` is then just the value of the evaluated expression.
17 | 
18 | ```f#
19 | // module.glu
20 | type Named a = { name: String, value: a }
21 | let twice f x = f (f x)
22 | { twice, Named }
23 | 
24 | //main.glu
25 | let { twice, Named }  = import! "module.glu"
26 | let addTwice = twice (\x -> x + 1)
27 | let namedFloat : Named Float = { name = "pi", value = 3.14 }
28 | addTwice 10
29 | ```
30 | 
31 | Though modules are most commonly a record, this does not have to be the case. If you wanted, you could write a module returning any other value as well.
32 | 
33 | ```f#
34 | // pi.glu
35 | 3.14
36 | 
37 | //main.glu
38 | let pi  = import! "pi.glu"
39 | 2 * pi * 10
40 | ```
41 | 
42 | 


--------------------------------------------------------------------------------
/book/src/standard-types-and-functions.md:
--------------------------------------------------------------------------------
 1 | # Standard types and functions
 2 | 
 3 | The API documentation for the standard library can be found [here][std-docs]. Some of the modules
 4 | are only available if Gluon is compiled with the required features:
 5 | 
 6 | - `std.regex` requires the `regex` feature (enabled by default)
 7 | - `std.random` requires the `rand` feature (enabled by default)
 8 | - All `std.json.*` modules require the `serialization` feature
 9 | 
10 | TODO
11 | 
12 | ### Prelude
13 | 
14 | When compiling an expression, the compiler automatically inserts a small prelude before the expression itself, which gives automatic access to basic operators such as `+`, `-`, etc as well as types such as `Option` and `Result`.
15 | 
16 | ### Threads and channels
17 | 
18 | Gluon has support for cooperative threading and communication between them through the `Thread` and `Sender`/`Receiver` types.
19 | 
20 | ### Strings
21 | 
22 | `String` is a built-in data type. The module `std.string` provides the infix operatoin `++`, concatenating two strings. The operation `show` converts the Int to a printable String.
23 | ```
24 | let io @ { ? } = import! std.io
25 | let string @ { len } = import! std.string
26 | let { show }  = import! std.show
27 | let message : String = "Hello" ++ " " ++ "World" ++ "!"
28 | let prompt s = "<" ++ show (len s) ++ "> "
29 | io.println ( (prompt message) ++ message )
30 | ```
31 | The output will be
32 | ```
33 | <12> Hello World!
34 | ```
35 | 
36 | The following API doc for the module [`std.string`](https://gluon-lang.org/doc/crates_io/std/std/string.html) is a list of all string operations.
37 | ```
38 | 
39 | TODO
40 | 
41 | [std-docs]: http://gluon-lang.org/doc/nightly/std/index.html
42 | 


--------------------------------------------------------------------------------
/book/src/using-the-repl.md:
--------------------------------------------------------------------------------
 1 | # Using the REPL
 2 | 
 3 | Though it is possible to continue running any programs by saving it to a file and running it with `gluon my_script.glu` there is an easier way to go about it when you want to experiment quickly with small programs. By running `gluon -i`, gluon starts in "interactive" mode, giving you a REPL where you may evaluate expressions and inspect their results. Try evaluating some simple arithmetic expressions to see that it works.
 4 | 
 5 | ```
 6 | > 1 + 2
 7 | 3
 8 | > 100 * 3 + 4
 9 | 304
10 | > 3.14 * 10.0
11 | 31.400000000000002
12 | ```
13 | 
14 | Evaluating only a single expression can get quite unwieldy so if we want to break something up into multiple steps we can use `let` to give a name to an expression.
15 | 
16 | ```
17 | > let pi_2 = 3.14 * 2.0
18 | 6.28
19 | > pi_2 * 3.0
20 | 18.84
21 | ```
22 | 
23 | These are the basic parts of the REPL and if you want to you can try writing hello world again by using the features above.
24 | 
25 | If you still have the `hello_world.glu` file around there is another way to run it from inside the REPL by using the special `:script` (`:s`) command.
26 | 
27 | ```
28 | > :s hello_world.glu
29 | Hello World!
30 | ```
31 | 
32 | There are a few other of these special commands as well and you can find them all with `:help` (`:h`).
33 | 
34 | 
35 | ```
36 | > :type 1
37 | Int
38 | > :info std.io.println
39 | std.io.println: String -> IO ()
40 | > :kind std.option.Option
41 | Type -> Type
42 | ```
43 | 
44 | Finally you may quit the REPL using the `:quit` (`:q`) command or using `<CTRL-D>`.
45 | 


--------------------------------------------------------------------------------
/c-api/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_c-api"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus Westerlind <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | 
 9 | description = "C-api for gluon, a static, type inferred programming language for application embedding"
10 | 
11 | homepage = "https://gluon-lang.org"
12 | repository = "https://github.com/gluon-lang/gluon"
13 | documentation = "https://docs.rs/gluon"
14 | 
15 | [lib]
16 | crate-type = ["cdylib"]
17 | 
18 | [dependencies]
19 | gluon = { version = "0.18.2", path = ".." } # GLUON
20 | futures = "0.3.28"
21 | 
22 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
23 | libc = "0.2.147"
24 | 
25 | [features]
26 | test = ["gluon/test"]
27 | nightly = ["gluon/nightly"]
28 | 


--------------------------------------------------------------------------------
/check/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_check"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | 
 9 | description = "The typechecker for the gluon programming language"
10 | 
11 | homepage = "https://gluon-lang.org"
12 | repository = "https://github.com/gluon-lang/gluon"
13 | documentation = "https://docs.rs/gluon"
14 | 
15 | [dependencies]
16 | collect-mac = "0.1.0"
17 | ena = "0.14.2"
18 | log = "0.4.20"
19 | itertools = "0.10.5"
20 | pretty = "0.10.0"
21 | smallvec = "1.11.0"
22 | rpds = "0.10.0"
23 | quick-error = "2.0.1"
24 | 
25 | codespan = "0.11.1"
26 | codespan-reporting = "0.11.1"
27 | 
28 | strsim = "0.10.0"
29 | 
30 | gluon_base = { path = "../base", version = "0.18.2" } # GLUON
31 | gluon_codegen = { path = "../codegen", version = "0.18.2" } # GLUON
32 | 
33 | [dev-dependencies]
34 | env_logger = "0.9.3"
35 | insta = "1.31.0"
36 | 
37 | gluon_parser = { path = "../parser", version = "0.18.2" } # GLUON
38 | gluon_format = { path = "../format", version = ">=0.9" }
39 | 
40 | collect-mac = "0.1.0"
41 | difference = "2.0.0"
42 | pretty_assertions = "1.4.0"
43 | 
44 | 


--------------------------------------------------------------------------------
/check/src/typ.rs:
--------------------------------------------------------------------------------
 1 | pub use crate::base::types::{ArcType as RcType, Flags, TypeExt, TypePtr};
 2 | 
 3 | #[cfg(test)]
 4 | mod tests {
 5 |     use super::*;
 6 | 
 7 |     use crate::base::{
 8 |         symbol::Symbol,
 9 |         types::{Generic, Type},
10 |     };
11 | 
12 |     #[test]
13 |     fn flags() {
14 |         let gen = Type::<_, RcType>::generic(Generic::new(Symbol::from("a"), Default::default()));
15 |         assert_eq!(gen.flags(), Flags::HAS_GENERICS);
16 |         assert_eq!(
17 |             Type::function(vec![gen.clone()], gen.clone()).flags(),
18 |             Flags::HAS_GENERICS
19 |         );
20 |     }
21 | }
22 | 


--------------------------------------------------------------------------------
/check/src/typecheck/mod_type.rs:
--------------------------------------------------------------------------------
  1 | use std::{fmt, ops};
  2 | 
  3 | use base::types::ArcType;
  4 | 
  5 | #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  6 | pub enum TypeModifier {
  7 |     Wobbly,
  8 |     Rigid,
  9 | }
 10 | 
 11 | impl Default for TypeModifier {
 12 |     fn default() -> Self {
 13 |         TypeModifier::Wobbly
 14 |     }
 15 | }
 16 | 
 17 | impl ops::BitOr for TypeModifier {
 18 |     type Output = Self;
 19 | 
 20 |     fn bitor(mut self, typ: Self) -> Self {
 21 |         self |= typ;
 22 |         self
 23 |     }
 24 | }
 25 | impl ops::BitOrAssign for TypeModifier {
 26 |     fn bitor_assign(&mut self, typ: Self) {
 27 |         match (*self, typ) {
 28 |             (TypeModifier::Rigid, TypeModifier::Rigid) => (),
 29 |             _ => *self = TypeModifier::Wobbly,
 30 |         }
 31 |     }
 32 | }
 33 | 
 34 | pub type ModTypeRef<'a> = ModType<&'a ArcType>;
 35 | 
 36 | #[derive(Clone, Copy, Debug)]
 37 | pub struct ModType<T = ArcType> {
 38 |     pub modifier: TypeModifier,
 39 |     pub concrete: T,
 40 | }
 41 | 
 42 | impl<T> fmt::Display for ModType<T>
 43 | where
 44 |     T: fmt::Display,
 45 | {
 46 |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 47 |         self.concrete.fmt(f)
 48 |     }
 49 | }
 50 | 
 51 | impl<T> ops::Deref for ModType<T> {
 52 |     type Target = T;
 53 | 
 54 |     fn deref(&self) -> &Self::Target {
 55 |         &self.concrete
 56 |     }
 57 | }
 58 | 
 59 | impl<T> ops::DerefMut for ModType<T> {
 60 |     fn deref_mut(&mut self) -> &mut Self::Target {
 61 |         &mut self.concrete
 62 |     }
 63 | }
 64 | 
 65 | impl<T> ops::BitOrAssign for ModType<T> {
 66 |     fn bitor_assign(&mut self, typ: Self) {
 67 |         self.modifier |= typ.modifier;
 68 |         self.concrete = typ.concrete;
 69 |     }
 70 | }
 71 | 
 72 | impl<T> ModType<T> {
 73 |     pub fn new(modifier: TypeModifier, typ: T) -> Self {
 74 |         ModType {
 75 |             modifier,
 76 |             concrete: typ,
 77 |         }
 78 |     }
 79 | 
 80 |     pub fn rigid(typ: T) -> Self {
 81 |         Self::new(TypeModifier::Rigid, typ)
 82 |     }
 83 | 
 84 |     pub fn wobbly(typ: T) -> Self {
 85 |         Self::new(TypeModifier::Wobbly, typ)
 86 |     }
 87 | 
 88 |     pub fn as_ref(&self) -> ModType<&T> {
 89 |         ModType::new(self.modifier, &self.concrete)
 90 |     }
 91 | }
 92 | 
 93 | impl<'a, T> ModType<&'a T>
 94 | where
 95 |     T: Clone,
 96 | {
 97 |     pub fn to_owned(&self) -> ModType<T> {
 98 |         ModType::new(self.modifier, self.concrete.clone())
 99 |     }
100 | }
101 | 


--------------------------------------------------------------------------------
/check/tests/error_recovery.rs:
--------------------------------------------------------------------------------
 1 | extern crate gluon_base as base;
 2 | 
 3 | mod support;
 4 | 
 5 | use crate::support::*;
 6 | 
 7 | use crate::base::ast::Typed;
 8 | 
 9 | #[test]
10 | fn partial_let() {
11 |     let src = r#"
12 | /// Alias of `or`
13 | #[infix(left, 3)]
14 | let (<|>) : () = ()
15 | let a
16 | {
17 |     (<|>)
18 | }
19 |         "#;
20 |     let (expr, result) = typecheck_partial_expr(src);
21 |     assert_req!(result.map(|t| t.to_string()), Ok("{ (<|>) : () }"));
22 |     assert_eq!(
23 |         expr.env_type_of(&MockEnv::new()).to_string(),
24 |         "{ (<|>) : () }"
25 |     );
26 | }
27 | 


--------------------------------------------------------------------------------
/check/tests/snapshots/fail__alias_mismatch.snap:
--------------------------------------------------------------------------------
 1 | ---
 2 | source: check/tests/fail.rs
 3 | expression: "&*format!(\"{}\", result . unwrap_err()).replace(\"\\t\", \"        \")"
 4 | ---
 5 | error: Expected the following types to be equal
 6 | Expected: test.A
 7 | Found: test.B
 8 | 1 errors were found during unification:
 9 | Row labels do not match.
10 |     Expected: A
11 |     Found: B
12 |   ┌─ test:5:11
13 |   │
14 | 5 │ eq (A 0) (B 0.0)
15 |   │           ^^^^^
16 | 
17 | 
18 | 


--------------------------------------------------------------------------------
/check/tests/snapshots/fail__multiple_extra_parameters_error.snap:
--------------------------------------------------------------------------------
 1 | ---
 2 | source: check/tests/fail.rs
 3 | expression: "&*format!(\"{}\", result . unwrap_err()).replace(\"\\t\", \"        \")"
 4 | ---
 5 | error: Expected the following types to be equal
 6 | Expected: Int -> Float -> a
 7 | Found: String
 8 | 1 errors were found during unification:
 9 | Types do not match:
10 |     Expected: Int -> Float -> a
11 |     Found: String
12 |   ┌─ test:3:7
13 |   │
14 | 3 │ id "" 1 1.0
15 |   │       ----- Attempted to call function with 3 arguments but its type only has 1
16 | 
17 | 
18 | 


--------------------------------------------------------------------------------
/check/tests/snapshots/fail__no_inference_variable_in_error.snap:
--------------------------------------------------------------------------------
 1 | ---
 2 | source: check/tests/fail.rs
 3 | expression: "&*format!(\"{}\", result . unwrap_err()).replace(\"\\t\", \"        \")"
 4 | ---
 5 | error: Expected the following types to be equal
 6 | Expected: Int -> a
 7 | Found: ()
 8 | 1 errors were found during unification:
 9 | Types do not match:
10 |     Expected: Int -> a
11 |     Found: ()
12 |   ┌─ test:2:4
13 |   │
14 | 2 │ () 1
15 |   │    - Attempted to call a non-function value
16 | 
17 | 
18 | 


--------------------------------------------------------------------------------
/check/tests/snapshots/fail__unable_to_resolve_implicit_error_message.snap:
--------------------------------------------------------------------------------
 1 | ---
 2 | source: check/tests/fail.rs
 3 | expression: "&*format!(\"{}\", result . unwrap_err()).replace(\"\\t\", \"        \")"
 4 | ---
 5 | error: Implicit parameter with type `test.Eq Int` could not be resolved.
 6 |    ┌─ test:11:3
 7 |    │
 8 | 11 │ f (Test (Test 1))
 9 |    │   ---------------
10 |    │   │
11 |    │   Required because of an implicit parameter of `[test.Eq Int] -> test.Eq (test.Test Int)`
12 |    │   Required because of an implicit parameter of `[test.Eq (test.Test Int)] -> test.Eq (test.Test (test.Test Int))`
13 | 
14 | 
15 | 


--------------------------------------------------------------------------------
/check/tests/snapshots/fail__unification_error_with_empty_record_displays_good_error_message.snap:
--------------------------------------------------------------------------------
 1 | ---
 2 | source: check/tests/fail.rs
 3 | expression: "&*format!(\"{}\", result . unwrap_err()).replace(\"\\t\", \"        \")"
 4 | ---
 5 | error: Expected the following types to be equal
 6 | Expected: ()
 7 | Found: { x : Int }
 8 | 1 errors were found during unification:
 9 | The type `()` lacks the following fields: x
10 |   ┌─ test:4:7
11 |   │
12 | 4 │ f { } { x = 1 }
13 |   │       ^^^^^^^^^
14 | 
15 | 
16 | 


--------------------------------------------------------------------------------
/codegen/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_codegen"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus <marwes91@gmail.com>"]
 5 | 
 6 | edition = "2018"
 7 | 
 8 | license = "MIT"
 9 | 
10 | description = "Code generation macros for the gluon programming language"
11 | 
12 | repository = "https://github.com/gluon-lang/gluon"
13 | documentation = "https://docs.rs/gluon"
14 | 
15 | [lib]
16 | proc-macro = true
17 | 
18 | [dependencies]
19 | syn = { version = "1.0.109", features = ["extra-traits"] }
20 | quote = "1.0.33"
21 | proc-macro2 = "1.0.66"
22 | 
23 | [dev-dependencies]
24 | env_logger = "0.9.3"
25 | serde = "1.0.188"
26 | serde_derive = "1.0.188"
27 | gluon = { version = ">=0.8.0", path = "..", features = ["serialization"] }
28 | gluon_vm = { version = ">=0.8.0", path = "../vm" }
29 | 


--------------------------------------------------------------------------------
/codegen/src/userdata.rs:
--------------------------------------------------------------------------------
 1 | use proc_macro2::{Ident, Span, TokenStream};
 2 | use syn::{self, Data, DeriveInput, Generics};
 3 | 
 4 | use crate::{
 5 |     attr::{Container, CrateName},
 6 |     shared::{map_lifetimes, map_type_params, split_for_impl},
 7 | };
 8 | 
 9 | pub fn derive(input: TokenStream) -> TokenStream {
10 |     let derive_input = syn::parse2(input).expect("Input is checked by rustc");
11 | 
12 |     let container = Container::from_ast(&derive_input);
13 | 
14 |     let DeriveInput {
15 |         ident,
16 |         data,
17 |         generics,
18 |         ..
19 |     } = derive_input;
20 | 
21 |     let tokens = match data {
22 |         Data::Struct(_) | Data::Enum(_) => gen_impl(&container, ident, generics),
23 |         Data::Union(_) => panic!("Unions are not supported"),
24 |     };
25 | 
26 |     tokens.into()
27 | }
28 | 
29 | fn gen_impl(container: &Container, ident: Ident, generics: Generics) -> TokenStream {
30 |     let trait_bounds = &map_type_params(&generics, |ty| {
31 |         quote! { #ty: 'static + ::std::fmt::Debug + _gluon_gc::Trace + Sync + Send }
32 |     });
33 | 
34 |     let lifetime_bounds = &map_lifetimes(&generics, |lifetime| quote! { #lifetime: 'static });
35 | 
36 |     let (impl_generics, ty_generics, where_clause) = split_for_impl(&generics, &[], &[]);
37 | 
38 |     let gluon = match container.crate_name {
39 |         CrateName::Some(ref ident) => quote! {
40 |             use #ident::api as _gluon_api;
41 |             use #ident::gc as _gluon_gc;
42 |             use #ident::Result as _gluon_Result;
43 |         },
44 |         CrateName::GluonVm => quote! {
45 |             use crate::api as _gluon_api;
46 |             use crate::thread as _gluon_gc;
47 |             use crate::Result as _gluon_Result;
48 |         },
49 |         CrateName::None => quote! {
50 |             use gluon::vm::api as _gluon_api;
51 |             use gluon::vm::gc as _gluon_gc;
52 |             use gluon::vm::Result as _gluon_Result;
53 |         },
54 |     };
55 | 
56 |     let dummy_const = Ident::new(&format!("_IMPL_USERDATA_FOR_{}", ident), Span::call_site());
57 | 
58 |     let deep_clone = if container.clone {
59 |         quote! {
60 |             fn deep_clone<'gc>(
61 |                 &self,
62 |                 deep_cloner: &'gc mut _gluon_api::Cloner
63 |             ) -> _gluon_Result<_gluon_gc::GcRef<'gc, Box<dyn _gluon_api::Userdata>>> {
64 |                 let data: Box<dyn _gluon_api::Userdata> = Box::new(self.clone());
65 |                 deep_cloner.gc().alloc(_gluon_gc::Move(data))
66 |             }
67 |         }
68 |     } else {
69 |         quote! {}
70 |     };
71 | 
72 |     quote! {
73 |         #[allow(non_upper_case_globals)]
74 |         const #dummy_const: () = {
75 |             #gluon
76 | 
77 |             #[automatically_derived]
78 |             #[allow(unused_attributes, unused_variables)]
79 |             impl #impl_generics _gluon_api::Userdata for #ident #ty_generics
80 |             #where_clause #(#trait_bounds,)* #(#lifetime_bounds),*
81 |             {
82 |                 #deep_clone
83 |             }
84 |         };
85 |     }
86 | }
87 | 


--------------------------------------------------------------------------------
/codegen/tests/derive_userdata.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate gluon_codegen;
 3 | extern crate gluon;
 4 | #[macro_use]
 5 | extern crate gluon_vm;
 6 | 
 7 | mod init;
 8 | 
 9 | use std::sync::Arc;
10 | 
11 | use gluon::{
12 |     import,
13 |     vm::{self, ExternModule},
14 |     Thread, ThreadExt,
15 | };
16 | 
17 | use init::new_vm;
18 | 
19 | #[derive(Userdata, Trace, Debug, VmType)]
20 | #[gluon(vm_type = "WindowHandle")]
21 | struct WindowHandle {
22 |     id: Arc<u64>,
23 |     metadata: Arc<str>,
24 | }
25 | 
26 | fn load_mod(vm: &Thread) -> vm::Result<ExternModule> {
27 |     vm.register_type::<WindowHandle>("WindowHandle", &[])?;
28 | 
29 |     let module = record! {
30 |         create_hwnd => primitive!(2, create_hwnd),
31 |         id => primitive!(1, id),
32 |         metadata => primitive!(1, metadata),
33 |     };
34 | 
35 |     ExternModule::new(vm, module)
36 | }
37 | 
38 | fn create_hwnd(id: u64, metadata: String) -> WindowHandle {
39 |     WindowHandle {
40 |         id: Arc::new(id),
41 |         metadata: Arc::from(metadata),
42 |     }
43 | }
44 | 
45 | fn id(hwnd: &WindowHandle) -> u64 {
46 |     *hwnd.id
47 | }
48 | 
49 | fn metadata(hwnd: &WindowHandle) -> String {
50 |     String::from(&*hwnd.metadata)
51 | }
52 | 
53 | #[test]
54 | fn userdata() {
55 |     let vm = new_vm();
56 | 
57 |     import::add_extern_module(&vm, "hwnd", load_mod);
58 | 
59 |     let script = r#"
60 |         let { assert } = import! std.test
61 |         let { create_hwnd, id, metadata } = import! hwnd
62 | 
63 |         let hwnd = create_hwnd 0 "Window1"
64 | 
65 |         let _ = assert (id hwnd == 0)
66 |         assert (metadata hwnd == "Window1")
67 |     "#;
68 | 
69 |     if let Err(why) = vm.run_expr::<()>("test", script) {
70 |         panic!("{}", why);
71 |     }
72 | }
73 | 
74 | #[derive(Userdata, Trace, Debug, VmType)]
75 | #[gluon(vm_type = "Empty")]
76 | struct Empty;
77 | 


--------------------------------------------------------------------------------
/codegen/tests/derive_vm_type.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate gluon_codegen;
 3 | extern crate gluon;
 4 | 
 5 | mod init;
 6 | 
 7 | use gluon::vm::api;
 8 | use gluon::{base::types::Type, vm::api::VmType};
 9 | #[macro_use]
10 | extern crate serde_derive;
11 | use init::new_vm;
12 | 
13 | #[derive(VmType)]
14 | #[allow(unused)]
15 | struct Struct {
16 |     string: String,
17 |     number: u32,
18 |     vec: Vec<f64>,
19 | }
20 | 
21 | #[test]
22 | fn struct_() {
23 |     let vm = new_vm();
24 | 
25 |     assert_eq!(
26 |         Struct::make_type(&vm).to_string(),
27 |         "{ string : String, number : Int, vec : Array Float }"
28 |     );
29 | }
30 | 
31 | #[derive(VmType, Serialize, Deserialize)]
32 | #[allow(unused)]
33 | enum Enum {
34 |     One,
35 |     Two(u32),
36 |     Three { id: String },
37 | }
38 | 
39 | #[test]
40 | fn enum_() {
41 |     let vm = new_vm();
42 | 
43 |     let src = api::typ::make_source::<Enum>(&vm).unwrap();
44 |     println!("Enum Types:\n{}", src);
45 | 
46 |     assert_eq!(
47 |         Enum::make_type(&vm).to_string(),
48 |         "| One\n| Two Int\n| Three { id : String }"
49 |     );
50 | }
51 | 
52 | #[derive(VmType)]
53 | #[allow(unused)]
54 | struct NewtypeInner(Struct);
55 | 
56 | #[test]
57 | fn newtype_inner() {
58 |     let vm = new_vm();
59 | 
60 |     assert_eq!(
61 |         NewtypeInner::make_type(&vm).to_string(),
62 |         Struct::make_type(&vm).to_string(),
63 |     );
64 | }
65 | 
66 | #[derive(VmType)]
67 | #[gluon(newtype)]
68 | #[allow(unused)]
69 | struct Newtype(Struct);
70 | 
71 | #[test]
72 | fn newtype() {
73 |     let vm = new_vm();
74 | 
75 |     match &*Newtype::make_type(&vm) {
76 |         Type::Alias(alias) => {
77 |             assert_eq!(alias.name.declared_name(), "Newtype");
78 |             assert_eq!(
79 |                 alias.unresolved_type().to_string(),
80 |                 Struct::make_type(&vm).to_string()
81 |             );
82 |         }
83 |         _ => panic!(),
84 |     }
85 | }
86 | 


--------------------------------------------------------------------------------
/codegen/tests/full.rs:
--------------------------------------------------------------------------------
  1 | extern crate gluon;
  2 | #[macro_use]
  3 | extern crate gluon_codegen;
  4 | #[macro_use]
  5 | extern crate gluon_vm;
  6 | 
  7 | mod init;
  8 | 
  9 | use gluon::{
 10 |     import,
 11 |     vm::{self, ExternModule},
 12 |     Thread, ThreadExt,
 13 | };
 14 | use init::new_vm;
 15 | 
 16 | #[derive(Debug, PartialEq, Getable, Pushable, VmType)]
 17 | struct Struct {
 18 |     string: String,
 19 |     number: u32,
 20 |     vec: Vec<f64>,
 21 | }
 22 | 
 23 | fn load_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
 24 |     let module = record! {
 25 |         new_struct => primitive!(1, new_struct),
 26 |     };
 27 | 
 28 |     ExternModule::new(vm, module)
 29 | }
 30 | 
 31 | fn new_struct(_: ()) -> Struct {
 32 |     Struct {
 33 |         string: "hello".to_owned(),
 34 |         number: 1,
 35 |         vec: vec![1.0, 2.0, 3.0],
 36 |     }
 37 | }
 38 | 
 39 | #[test]
 40 | fn normal_struct() {
 41 |     let vm = new_vm();
 42 |     import::add_extern_module(&vm, "functions", load_struct_mod);
 43 | 
 44 |     let script = r#"
 45 |         let { new_struct } = import! functions
 46 |         
 47 |         new_struct ()
 48 |     "#;
 49 | 
 50 |     let (s, _) = vm
 51 |         .run_expr::<Struct>("test", script)
 52 |         .unwrap_or_else(|why| panic!("{}", why));
 53 | 
 54 |     assert_eq!(
 55 |         s,
 56 |         Struct {
 57 |             string: "hello".into(),
 58 |             number: 1,
 59 |             vec: vec![1.0, 2.0, 3.0],
 60 |         }
 61 |     );
 62 | }
 63 | 
 64 | #[derive(Debug, PartialEq, VmType, Pushable, Getable)]
 65 | struct Newtype(pub Struct);
 66 | 
 67 | fn load_newtype_mod(vm: &Thread) -> vm::Result<ExternModule> {
 68 |     let module = record! {
 69 |         newtype_id => primitive!(1, newtype_id),
 70 |     };
 71 | 
 72 |     ExternModule::new(vm, module)
 73 | }
 74 | 
 75 | fn newtype_id(val: Newtype) -> Newtype {
 76 |     val
 77 | }
 78 | 
 79 | #[test]
 80 | fn newtype() {
 81 |     let vm = new_vm();
 82 |     import::add_extern_module(&vm, "functions", load_newtype_mod);
 83 | 
 84 |     // newtypes should map to the inner type
 85 |     let script = r#"
 86 |         let { newtype_id } = import! functions
 87 | 
 88 |         newtype_id { string = "test", number = 42, vec = [1.0, 1.0, 2.0, 3.0, 5.0] }
 89 |     "#;
 90 | 
 91 |     let (s, _) = vm
 92 |         .run_expr::<Newtype>("test", script)
 93 |         .unwrap_or_else(|why| panic!("{}", why));
 94 | 
 95 |     assert_eq!(
 96 |         s,
 97 |         Newtype(Struct {
 98 |             string: "test".into(),
 99 |             number: 42,
100 |             vec: vec![1.0, 1.0, 2.0, 3.0, 5.0],
101 |         })
102 |     );
103 | }
104 | 


--------------------------------------------------------------------------------
/codegen/tests/init/mod.rs:
--------------------------------------------------------------------------------
 1 | use gluon::{self, import::Import, RootedThread};
 2 | 
 3 | pub fn new_vm() -> RootedThread {
 4 |     if ::std::env::var("GLUON_PATH").is_err() {
 5 |         ::std::env::set_var("GLUON_PATH", "..");
 6 |     }
 7 | 
 8 |     let vm = gluon::new_vm();
 9 |     let import = vm.get_macros().get("import");
10 |     import
11 |         .as_ref()
12 |         .and_then(|import| import.downcast_ref::<Import>())
13 |         .expect("Import macro")
14 |         .add_path("..");
15 | 
16 |     vm
17 | }
18 | 


--------------------------------------------------------------------------------
/completion/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_completion"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | 
 9 | description = "Auto-completion for the gluon programming language"
10 | 
11 | repository = "https://github.com/gluon-lang/gluon"
12 | documentation = "https://docs.rs/gluon"
13 | 
14 | [dependencies]
15 | either = "1.9.0"
16 | itertools = "0.10.5"
17 | walkdir = "2.3.3"
18 | codespan = "0.11.1"
19 | 
20 | gluon_base = { path = "../base", version = "0.18.2" } # GLUON
21 | 
22 | [dev-dependencies]
23 | collect-mac = "0.1.0"
24 | env_logger = "0.9.3"
25 | pretty_assertions = "1.4.0"
26 | quick-error = "2.0.1"
27 | 
28 | gluon_check = { path = "../check", version = "0.18.2" } # GLUON
29 | gluon_parser = { path = "../parser", version = "0.18.2" } # GLUON
30 | 


--------------------------------------------------------------------------------
/completion/tests/signature_help.rs:
--------------------------------------------------------------------------------
  1 | #[macro_use]
  2 | extern crate collect_mac;
  3 | extern crate env_logger;
  4 | 
  5 | extern crate gluon_base as base;
  6 | extern crate gluon_check as check;
  7 | extern crate gluon_completion as completion;
  8 | extern crate gluon_parser as parser;
  9 | 
 10 | mod support;
 11 | 
 12 | use crate::support::*;
 13 | 
 14 | use crate::base::types::Type;
 15 | 
 16 | use crate::completion::SignatureHelp;
 17 | 
 18 | fn signature_help(expr_str: &str, row: usize, column: usize) -> Option<SignatureHelp> {
 19 |     let offset = loc(expr_str, row, column);
 20 |     let (expr, _result) = support::typecheck_partial_expr(expr_str);
 21 |     let expr = expr.expr();
 22 |     completion::signature_help(&support::MockEnv::new(), expr.span, &expr, offset)
 23 | }
 24 | 
 25 | #[test]
 26 | fn just_identifier() {
 27 |     let _ = env_logger::try_init();
 28 | 
 29 |     let result = signature_help(
 30 |         r#"
 31 | let test x y : Int -> String -> Int = x
 32 | test //
 33 | "#,
 34 |         2,
 35 |         5,
 36 |     );
 37 |     let expected = Some(SignatureHelp {
 38 |         name: "test".to_string(),
 39 |         typ: Type::function(vec![typ("Int"), typ("String")], typ("Int")),
 40 |         index: Some(0),
 41 |     });
 42 | 
 43 |     assert_eq!(result, expected);
 44 | }
 45 | 
 46 | #[test]
 47 | fn on_function() {
 48 |     let _ = env_logger::try_init();
 49 | 
 50 |     let result = signature_help(
 51 |         r#"
 52 | let test x y : Int -> String -> Int = x
 53 | test 123//
 54 | "#,
 55 |         2,
 56 |         3,
 57 |     );
 58 |     let expected = Some(SignatureHelp {
 59 |         name: "test".to_string(),
 60 |         typ: Type::function(vec![typ("Int"), typ("String")], typ("Int")),
 61 |         index: None,
 62 |     });
 63 | 
 64 |     assert_eq!(result, expected);
 65 | }
 66 | 
 67 | #[test]
 68 | fn after_first_argument() {
 69 |     let _ = env_logger::try_init();
 70 | 
 71 |     let result = signature_help(
 72 |         r#"
 73 | let test x y : Int -> String -> Int = x
 74 | test 123 //
 75 | "#,
 76 |         2,
 77 |         9,
 78 |     );
 79 |     let expected = Some(SignatureHelp {
 80 |         name: "test".to_string(),
 81 |         typ: Type::function(vec![typ("Int"), typ("String")], typ("Int")),
 82 |         index: Some(1),
 83 |     });
 84 | 
 85 |     assert_eq!(result, expected);
 86 | }
 87 | 
 88 | #[test]
 89 | fn inside_argument() {
 90 |     let _ = env_logger::try_init();
 91 | 
 92 |     let result = signature_help(
 93 |         r#"
 94 | let test x y : Int -> String -> Int = x
 95 | test { x = "" }
 96 | "#,
 97 |         2,
 98 |         13,
 99 |     );
100 |     let expected = Some(SignatureHelp {
101 |         name: "".to_string(),
102 |         typ: typ("String"),
103 |         index: None,
104 |     });
105 | 
106 |     assert_eq!(result, expected);
107 | }
108 | 


--------------------------------------------------------------------------------
/doc/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_doc"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus Westerlind <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | 
 9 | description = "The documentation generator for the gluon programming language"
10 | 
11 | repository = "https://github.com/gluon-lang/gluon"
12 | documentation = "https://docs.rs/gluon"
13 | 
14 | [dependencies]
15 | clap = "2.34.0"
16 | env_logger = "0.9.3"
17 | anyhow = "1.0.75"
18 | futures = "0.3.28"
19 | handlebars = "4.3.7"
20 | itertools = "0.10.5"
21 | lazy_static = "1.4.0"
22 | log = "0.4.20"
23 | opener = "0.5.2"
24 | pretty = "0.10.0"
25 | pulldown-cmark = "0.8.0"
26 | rayon = "1.7.0"
27 | regex = "1.9.4"
28 | structopt = "0.3.26"
29 | walkdir = "2.3.3"
30 | 
31 | serde = "1.0.188"
32 | serde_derive = "1.0.188"
33 | serde_json = "1.0.105"
34 | 
35 | gluon = { version = "0.18.2", default-features = false, path = ".." } # GLUON
36 | completion = { package = "gluon_completion", version = "0.18.2", path = "../completion" } # GLUON
37 | 
38 | 
39 | [dev-dependencies]
40 | cargo-deadlinks = "0.8.1"
41 | 


--------------------------------------------------------------------------------
/doc/build.rs:
--------------------------------------------------------------------------------
 1 | use std::env;
 2 | use std::path::Path;
 3 | use std::process::Command;
 4 | 
 5 | fn main() {
 6 |     if env::var("GIT_HASH").is_err() {
 7 |         let output = Command::new("git")
 8 |             .args(&["rev-parse", "HEAD"])
 9 |             .output()
10 |             .unwrap();
11 |         let git_hash = String::from_utf8(output.stdout).unwrap();
12 |         println!("cargo:rustc-env=GIT_HASH={}", git_hash);
13 |     }
14 |     let git_edit_msg = "../.git/COMMIT_EDITMSG";
15 |     if Path::new(git_edit_msg).exists() {
16 |         // This is the closest thing to making sure we rebuild this every time a new commit is made
17 |         println!("cargo:rerun-if-changed={}", git_edit_msg);
18 |     }
19 | }
20 | 


--------------------------------------------------------------------------------
/doc/src/doc/style.css:
--------------------------------------------------------------------------------
1 | .anchor {
2 |     color: inherit;
3 |     text-decoration: inherit;
4 | }
5 | 


--------------------------------------------------------------------------------
/doc/src/main.rs:
--------------------------------------------------------------------------------
 1 | extern crate env_logger;
 2 | extern crate opener;
 3 | extern crate rayon;
 4 | extern crate structopt;
 5 | 
 6 | extern crate gluon;
 7 | extern crate gluon_doc;
 8 | 
 9 | use std::path::Path;
10 | 
11 | use structopt::StructOpt;
12 | 
13 | fn main() {
14 |     if let Err(err) = main_() {
15 |         eprintln!("{}", err);
16 |     }
17 | }
18 | 
19 | fn main_() -> Result<(), anyhow::Error> {
20 |     env_logger::init();
21 | 
22 |     let opt = gluon_doc::Opt::from_args();
23 | 
24 |     if let Some(jobs) = opt.jobs {
25 |         rayon::ThreadPoolBuilder::new()
26 |             .num_threads(jobs)
27 |             .build_global()?;
28 |     }
29 | 
30 |     gluon_doc::generate(&gluon_doc::Options::from(&opt), &gluon::new_vm())?;
31 | 
32 |     if opt.open {
33 |         let path = Path::new(&opt.output)
34 |             .join(&opt.input)
35 |             .with_extension("html");
36 |         eprintln!("Opening {}", path.display());
37 |         opener::open(path)?;
38 |     }
39 | 
40 |     Ok(())
41 | }
42 | 


--------------------------------------------------------------------------------
/doc/tests/doc.rs:
--------------------------------------------------------------------------------
 1 | use std::{fs, path::Path};
 2 | 
 3 | use {itertools::Itertools, rayon::prelude::*};
 4 | 
 5 | use gluon_doc as doc;
 6 | 
 7 | use gluon::{check::metadata::metadata, RootedThread, ThreadExt};
 8 | 
 9 | fn new_vm() -> RootedThread {
10 |     ::gluon::VmBuilder::new()
11 |         .import_paths(Some(vec!["..".into()]))
12 |         .build()
13 | }
14 | 
15 | fn doc_check(module: &str, expected: doc::Record) {
16 |     let vm = new_vm();
17 |     let (expr, typ) = vm.typecheck_str("basic", module, None).unwrap();
18 |     let (meta, _) = metadata(&vm.get_env(), &expr.expr());
19 | 
20 |     let out = doc::record(
21 |         "basic",
22 |         &typ,
23 |         &Default::default(),
24 |         &<() as gluon::base::source::Source>::new(""),
25 |         &meta,
26 |     );
27 |     assert_eq!(out, expected,);
28 | }
29 | 
30 | #[test]
31 | fn basic() {
32 |     let module = r#"
33 | /// This is the test function
34 | let test x = x
35 | { test }
36 | "#;
37 |     doc_check(
38 |         module,
39 |         doc::Record {
40 |             types: Vec::new(),
41 |             values: vec![doc::Field {
42 |                 name: "test".to_string(),
43 |                 args: vec![doc::Argument {
44 |                     implicit: false,
45 |                     name: "x".to_string(),
46 |                 }],
47 |                 typ: handlebars::html_escape("forall a . a -> a"),
48 |                 attributes: "".to_string(),
49 |                 comment: "This is the test function".to_string(),
50 |                 definition_line: None,
51 |             }],
52 |         },
53 |     );
54 | }
55 | 
56 | #[test]
57 | fn doc_hidden() {
58 |     let module = r#"
59 | #[doc(hidden)]
60 | type Test = Int
61 | #[doc(hidden)]
62 | let test x = x
63 | { Test, test }
64 | "#;
65 |     doc_check(
66 |         module,
67 |         doc::Record {
68 |             types: Vec::new(),
69 |             values: vec![],
70 |         },
71 |     );
72 | }
73 | 
74 | #[test]
75 | fn check_links() {
76 |     let _ = env_logger::try_init();
77 | 
78 |     let out = Path::new("../target/doc_test");
79 |     if out.exists() {
80 |         fs::remove_dir_all(out).unwrap_or_else(|err| panic!("{}", err));
81 |     }
82 |     doc::generate_for_path(&new_vm(), "../std", out).unwrap_or_else(|err| panic!("{}", err));
83 | 
84 |     let out = fs::canonicalize(out).unwrap();
85 |     let errors = cargo_deadlinks::unavailable_urls(
86 |         &out,
87 |         &cargo_deadlinks::CheckContext {
88 |             check_http: cargo_deadlinks::HttpCheck::Enabled,
89 |             ..Default::default()
90 |         },
91 |     )
92 |     .collect::<Vec<_>>();
93 | 
94 |     assert!(errors.is_empty(), "{}", errors.iter().format("\n"));
95 | }
96 | 


--------------------------------------------------------------------------------
/examples/24.rs:
--------------------------------------------------------------------------------
 1 | #![cfg(feature = "rand")]
 2 | 
 3 | use std::{fs::File, io::Read};
 4 | 
 5 | use gluon::{vm::api::IO, ThreadExt};
 6 | 
 7 | fn main() {
 8 |     env_logger::init();
 9 | 
10 |     if let Err(err) = main_() {
11 |         eprintln!("{}", err);
12 |         std::process::exit(1);
13 |     }
14 | }
15 | 
16 | fn main_() -> Result<(), Box<dyn std::error::Error>> {
17 |     let thread = gluon::new_vm();
18 |     thread.get_database_mut().run_io(true);
19 | 
20 |     let mut source = String::new();
21 |     let mut file = File::open("examples/24.glu")?;
22 |     file.read_to_string(&mut source)?;
23 | 
24 |     thread.run_expr::<IO<()>>("24", &source)?;
25 |     Ok(())
26 | }
27 | 


--------------------------------------------------------------------------------
/examples/fib.rs:
--------------------------------------------------------------------------------
 1 | use gluon::{new_vm, vm::api::FunctionRef, ThreadExt};
 2 | 
 3 | fn fib(n: u64) -> u64 {
 4 |     if n <= 1 {
 5 |         1
 6 |     } else {
 7 |         fib(n - 1) + fib(n - 2)
 8 |     }
 9 | }
10 | 
11 | fn main() {
12 |     const N: u64 = 46;
13 |     if std::env::args().nth(1).as_ref().map(|s| &s[..]) == Some("rust") {
14 |         println!("{}", fib(N));
15 |     } else {
16 |         let vm = new_vm();
17 |         let text = r#"
18 |             let fib n =
19 |                 if n #Int< 2
20 |                 then 1
21 |                 else fib (n #Int- 1) #Int+ fib (n #Int- 2)
22 |             fib
23 |             "#;
24 |         vm.load_script("fib", text)
25 |             .unwrap_or_else(|err| panic!("{}", err));
26 |         let mut fib: FunctionRef<fn(u64) -> u64> =
27 |             vm.get_global("fib").unwrap_or_else(|err| panic!("{}", err));
28 |         let result = fib.call(N).unwrap_or_else(|err| panic!("{}", err));
29 |         println!("{}", result);
30 |     }
31 | }
32 | 


--------------------------------------------------------------------------------
/examples/lisp/main.rs:
--------------------------------------------------------------------------------
 1 | extern crate env_logger;
 2 | 
 3 | extern crate gluon;
 4 | #[macro_use]
 5 | extern crate gluon_codegen;
 6 | 
 7 | use std::io::{self, BufRead};
 8 | 
 9 | use gluon::{
10 |     new_vm,
11 |     vm::api::{FunctionRef, OpaqueValue},
12 |     RootedThread, ThreadExt,
13 | };
14 | 
15 | #[derive(VmType)]
16 | #[gluon(vm_type = "examples.lisp.lisp.Expr")]
17 | struct ExprMarker;
18 | type Expr = OpaqueValue<RootedThread, ExprMarker>;
19 | 
20 | #[derive(VmType)]
21 | #[gluon(vm_type = "examples.lisp.lisp.LispState")]
22 | struct LispStateMarker;
23 | type LispState = OpaqueValue<RootedThread, LispStateMarker>;
24 | 
25 | fn main() {
26 |     if let Err(err) = main_() {
27 |         eprintln!("{}", err);
28 |     }
29 | }
30 | 
31 | fn main_() -> gluon::Result<()> {
32 |     env_logger::init();
33 | 
34 |     let thread = new_vm();
35 |     thread.load_file("examples/lisp/lisp.glu")?;
36 | 
37 |     let mut eval: FunctionRef<fn(String, LispState) -> Result<(Expr, LispState), String>> =
38 |         thread.get_global("examples.lisp.lisp.eval_env_string")?;
39 | 
40 |     let mut show: FunctionRef<fn(Expr) -> String> =
41 |         thread.get_global("examples.lisp.lisp.show.show")?;
42 | 
43 |     let mut env: LispState = thread.get_global("examples.lisp.lisp.default_env")?;
44 | 
45 |     let stdin = io::stdin();
46 |     for line in stdin.lock().lines() {
47 |         let line = line?;
48 |         match eval.call(line, env.clone())? {
49 |             Ok((msg, new_env)) => {
50 |                 println!("{}", show.call(msg.clone())?);
51 |                 env = new_env;
52 |             }
53 |             Err(err) => {
54 |                 eprintln!("{}", err);
55 |             }
56 |         }
57 |     }
58 |     Ok(())
59 | }
60 | 
61 | #[cfg(test)]
62 | mod tests {
63 |     use super::*;
64 | 
65 |     use gluon::Error;
66 | 
67 |     fn eval_lisp(expr: &str) -> Result<String, Error> {
68 |         let thread = new_vm();
69 |         thread.load_file("examples/lisp/lisp.glu")?;
70 | 
71 |         let mut eval: FunctionRef<fn(String, LispState) -> Result<(Expr, LispState), String>> =
72 |             thread.get_global("examples.lisp.lisp.eval_env_string")?;
73 | 
74 |         let mut show: FunctionRef<fn(Expr) -> String> =
75 |             thread.get_global("examples.lisp.lisp.show.show")?;
76 | 
77 |         let env: LispState = thread.get_global("examples.lisp.lisp.default_env")?;
78 | 
79 |         let (msg, _) = eval.call(expr.to_string(), env.clone())??;
80 |         Ok(show.call(msg.clone())?)
81 |     }
82 | 
83 |     #[test]
84 |     fn basic() {
85 |         assert_eq!(eval_lisp("(+ 1 2 3)").unwrap(), "6");
86 |     }
87 | }
88 | 


--------------------------------------------------------------------------------
/examples/lisp/parser.glu:
--------------------------------------------------------------------------------
 1 | let prelude = import! std.prelude
 2 | let { Expr } = import! "examples/lisp/types.glu"
 3 | let char = import! std.char
 4 | let { List } = import! std.list
 5 | let { Result } = import! std.result
 6 | let string = import! std.string
 7 | let float = import! std.float
 8 | let int = import! std.int
 9 | 
10 | let {
11 |     Parser,
12 |     fail,
13 |     between,
14 |     lazy_parser,
15 |     many,
16 |     one_of,
17 |     satisfy,
18 |     spaces,
19 |     token,
20 |     recognize,
21 |     take1,
22 |     skip_many,
23 |     skip_many1,
24 |     ?
25 | } =
26 |     import! std.parser
27 | 
28 | let { (<>) } = import! std.prelude
29 | 
30 | let { Applicative, (<*), (*>), map2, wrap } = import! std.applicative
31 | let { map } = import! std.functor
32 | let { (<|>) } = import! std.alternative
33 | let { flat_map } = import! std.monad
34 | 
35 | let atom : Parser Expr =
36 |     let symbol = one_of "!#$%&|*+-/:<=>?@^_~"
37 |     let alpha = satisfy char.is_alphabetic
38 |     let alpha_num = satisfy char.is_alphanumeric
39 |     map (\x -> Atom x) (recognize ((alpha <|> symbol) *> skip_many (alpha_num <|> symbol)))
40 | 
41 | let parse_parser p f msg : Parser a -> (String -> Result () b) -> String -> Parser b =
42 |     do s = recognize p
43 |     match f s with
44 |     | Ok i -> wrap i
45 |     | Err _ -> fail ("Expected " <> msg)
46 | 
47 | let int_parser : Parser Expr =
48 |     map
49 |         (\i -> Int i)
50 |         (parse_parser (skip_many1 (satisfy char.is_numeric)) int.parse "integer")
51 | 
52 | let float_parser : Parser Expr =
53 |     let number = skip_many1 (satisfy char.is_numeric)
54 |     map (\f -> Float f) (parse_parser (number *> token '.' *> number) float.parse "float")
55 | 
56 | rec
57 | let list _ : () -> Parser Expr =
58 |     let e = expr ()
59 |     between (token '(') (token ')') (spaces *> map (\x -> List x) (many e))
60 | let expr _ : () -> Parser Expr = (atom <|> float_parser <|> int_parser <|> lazy_parser list) <* spaces
61 | in
62 | 
63 | {
64 |     expr = spaces *> lazy_parser expr,
65 | }
66 | 


--------------------------------------------------------------------------------
/examples/lisp/types.glu:
--------------------------------------------------------------------------------
 1 | let { List } = import! std.list
 2 | let { Map } = import! std.map
 3 | let { Option } = import! std.option
 4 | let { Result } = import! std.result
 5 | 
 6 | let { Eff } = import! std.effect
 7 | let { State } = import! std.effect.state
 8 | let { Error } = import! std.effect.error
 9 | 
10 | rec
11 | type Expr =
12 |     | Atom String
13 |     | Int Int
14 |     | Float Float
15 |     | List (List Expr)
16 |     | Function Function
17 |     | Primitive (forall r . List Expr -> Eff (LispEffect r) Expr)
18 | type Function = {
19 |     params : List String,
20 |     vararg : Option String,
21 |     body : List Expr,
22 |     closure : Map String Expr
23 | }
24 | type LispState = Map String Expr
25 | type LispEffect r a = [| error : Error String, state : State LispState | r |] a
26 | in
27 | 
28 | { Expr, Function, LispState, LispEffect }
29 | 


--------------------------------------------------------------------------------
/format/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_format"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | 
 9 | description = "Code formatting for the gluon programming language"
10 | 
11 | repository = "https://github.com/gluon-lang/gluon"
12 | documentation = "https://docs.rs/gluon"
13 | 
14 | [dependencies]
15 | log = "0.4.20"
16 | pretty = "0.10.0"
17 | itertools = "0.10.5"
18 | codespan = "0.11.1"
19 | 
20 | gluon_base = { path = "../base", version = "0.18.2" } # GLUON
21 | 
22 | [dev-dependencies]
23 | difference = "2.0.0"
24 | env_logger = "0.9.3"
25 | expect-test = "1.4.1"
26 | futures = "0.3.28"
27 | pretty_assertions = "1.4.0"
28 | tokio = { version = "1.32.0", features = ["macros"] }
29 | walkdir = "2.3.3"
30 | 
31 | gluon_base = { path = "../base", version = "0.18.2" } # GLUON
32 | gluon = { path = "..", version = ">=0.9" }
33 | 
34 | tensile = { version = "0.7", features = ["tokio"] }
35 | 
36 | [features]
37 | test = []
38 | 
39 | [[test]]
40 | name = "std"
41 | harness = false
42 | 


--------------------------------------------------------------------------------
/format/src/lib.rs:
--------------------------------------------------------------------------------
 1 | //! Code formatter.
 2 | #![doc(html_root_url = "https://docs.rs/gluon_formatter/0.18.2")] // # GLUON
 3 | 
 4 | extern crate codespan;
 5 | #[macro_use]
 6 | extern crate gluon_base as base;
 7 | extern crate itertools;
 8 | extern crate pretty;
 9 | 
10 | use base::{ast::SpannedExpr, source::Source, symbol::Symbol};
11 | 
12 | mod pretty_print;
13 | 
14 | pub fn pretty_expr(input: &dyn Source, expr: &SpannedExpr<Symbol>) -> String {
15 |     Formatter::default().pretty_expr(input, expr)
16 | }
17 | 
18 | #[derive(Default, Debug, Clone)]
19 | pub struct Formatter {
20 |     /// Prints the source code after macro expansion
21 |     ///
22 |     /// NOTE: This is only provided for debug purposes and is likely to have have bugs
23 |     pub expanded: bool,
24 | }
25 | 
26 | impl Formatter {
27 |     pub fn pretty_expr(&self, source: &dyn Source, expr: &SpannedExpr<Symbol>) -> String {
28 |         let input = source.src();
29 |         let newline = match input.find(|c: char| c == '\n' || c == '\r') {
30 |             Some(i) => {
31 |                 if input[i..].starts_with("\r\n") {
32 |                     "\r\n"
33 |                 } else if input[i..].starts_with("\r") {
34 |                     "\r"
35 |                 } else {
36 |                     "\n"
37 |                 }
38 |             }
39 |             None => "\n",
40 |         };
41 | 
42 |         let arena = pretty::Arena::<()>::new();
43 |         let printer = pretty_print::Printer::new(&arena, source, self.clone());
44 |         printer.format(100, newline, &expr)
45 |     }
46 | }
47 | 


--------------------------------------------------------------------------------
/parser/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_parser"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | 
 9 | description = "The parser for the gluon programming language"
10 | 
11 | homepage = "https://gluon-lang.org"
12 | repository = "https://github.com/gluon-lang/gluon"
13 | documentation = "https://docs.rs/gluon"
14 | 
15 | build = "build.rs"
16 | 
17 | [dependencies]
18 | collect-mac = "0.1.0"
19 | itertools = "0.10.5"
20 | quick-error = "2.0.1"
21 | lalrpop-util = "0.19.12"
22 | log = "0.4.20"
23 | gluon_base = { path = "../base", version = "0.18.2" } # GLUON
24 | ordered-float = "2.10.0"
25 | codespan = "0.11.1"
26 | codespan-reporting = "0.11.1"
27 | 
28 | [dev-dependencies]
29 | criterion = "0.3.6"
30 | env_logger = "0.9.3"
31 | difference = "2.0.0"
32 | pretty_assertions = "1.4.0"
33 | 
34 | [build-dependencies]
35 | lalrpop = "0.19.12"
36 | 
37 | [[bench]]
38 | name = "parser"
39 | harness = false
40 | 


--------------------------------------------------------------------------------
/parser/benches/parser.rs:
--------------------------------------------------------------------------------
 1 | extern crate gluon_base as base;
 2 | extern crate gluon_parser as parser;
 3 | 
 4 | use std::fs;
 5 | 
 6 | use criterion::{criterion_group, criterion_main, Bencher, Criterion};
 7 | 
 8 | use crate::base::{
 9 |     ast, mk_ast_arena,
10 |     symbol::{SymbolModule, Symbols},
11 |     types::TypeCache,
12 | };
13 | 
14 | fn parse_file(b: &mut Bencher, file: &str) {
15 |     let text = fs::read_to_string(file).unwrap();
16 | 
17 |     b.iter(|| {
18 |         let mut symbols = Symbols::new();
19 |         let mut symbols = SymbolModule::new("".into(), &mut symbols);
20 |         mk_ast_arena!(arena);
21 |         let expr = parser::parse_expr(arena.borrow(), &mut symbols, &TypeCache::default(), &text)
22 |             .unwrap_or_else(|err| panic!("{:?}", err));
23 |         let expr = arena.alloc(expr);
24 |         ast::RootExpr::new(arena.clone(), expr)
25 |     })
26 | }
27 | 
28 | fn parse_benchmark(c: &mut Criterion) {
29 |     c.bench_function("std/prelude", |b| parse_file(b, "../std/prelude.glu"));
30 |     c.bench_function("examples/lisp", |b| {
31 |         parse_file(b, "../examples/lisp/lisp.glu")
32 |     });
33 |     c.bench_function("examples/http", |b| {
34 |         parse_file(b, "../examples/http/server.glu")
35 |     });
36 | }
37 | 
38 | criterion_group!(parser, parse_benchmark);
39 | criterion_main!(parser);
40 | 


--------------------------------------------------------------------------------
/parser/build.rs:
--------------------------------------------------------------------------------
 1 | extern crate lalrpop;
 2 | 
 3 | fn main() {
 4 |     lalrpop::Configuration::new()
 5 |         .use_cargo_dir_conventions()
 6 |         .process_file("src/grammar.lalrpop")
 7 |         .unwrap();
 8 | 
 9 |     println!("cargo:rerun-if-changed=src/grammar.lalrpop");
10 | }
11 | 


--------------------------------------------------------------------------------
/parser/tests/attributes.rs:
--------------------------------------------------------------------------------
 1 | extern crate env_logger;
 2 | extern crate gluon_base as base;
 3 | extern crate gluon_parser as parser;
 4 | 
 5 | #[macro_use]
 6 | mod support;
 7 | 
 8 | use crate::support::*;
 9 | 
10 | #[test]
11 | fn any_tokens() {
12 |     let _ = ::env_logger::try_init();
13 |     let text = r#"
14 | #[test(ident "string" 42 = 'a' + )]
15 | let (+) x y = error ""
16 | { }
17 | "#;
18 |     parse_clear_span!(text);
19 | }
20 | 
21 | #[test]
22 | fn bindings() {
23 |     let _ = ::env_logger::try_init();
24 |     let text = r#"
25 | #[infix(left, 6)]
26 | let (+) x y = error ""
27 | #[implicit]
28 | type Test = Int
29 | 
30 | {
31 |     #[abc()]
32 |     Test,
33 |     #[test]
34 |     t = \_ -> True
35 | }
36 | "#;
37 |     parse_clear_span!(text);
38 | }
39 | 


--------------------------------------------------------------------------------
/parser/tests/types.rs:
--------------------------------------------------------------------------------
 1 | extern crate gluon_base as base;
 2 | extern crate gluon_parser as parser;
 3 | 
 4 | use crate::base::{ast::Expr, mk_ast_arena, types::TypeContext};
 5 | use crate::support::{clear_span, parse, typ};
 6 | 
 7 | mod support;
 8 | 
 9 | #[test]
10 | fn function_type() {
11 |     let _ = env_logger::try_init();
12 | 
13 |     let input = "let _ : Int -> Float -> String = 1 in 1";
14 |     let expr = parse(input).unwrap_or_else(|err| panic!("{}", err.1));
15 |     mk_ast_arena!(arena);
16 |     let mut arena = (*arena).borrow();
17 |     match clear_span(expr).expr().value {
18 |         Expr::LetBindings(ref bindings, _) => {
19 |             assert_eq!(
20 |                 bindings[0].typ,
21 |                 Some(arena.function(
22 |                     vec![typ(arena, "Int"), typ(arena, "Float")],
23 |                     typ(arena, "String"),
24 |                 ),)
25 |             );
26 |         }
27 |         _ => panic!("Expected let"),
28 |     }
29 | }
30 | 


--------------------------------------------------------------------------------
/repl/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_repl"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus Westerlind <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | 
 7 | license = "MIT"
 8 | description = "REPL for gluon. A static, type inferred programming language for application embedding"
 9 | 
10 | homepage = "https://gluon-lang.org"
11 | repository = "https://github.com/gluon-lang/gluon"
12 | documentation = "https://docs.rs/gluon"
13 | 
14 | [[bin]]
15 | name = "gluon"
16 | path = "src/main.rs"
17 | doc = false
18 | 
19 | [dependencies]
20 | gluon = { version = "0.18.2", path = "..", features = ["serialization"] } # GLUON
21 | gluon_vm = { version = "0.18.2", path = "../vm", features = ["serialization"] } # GLUON
22 | gluon_completion = { path = "../completion", version = "0.18.2" } # GLUON
23 | gluon_codegen = { path = "../codegen", version = "0.18.2" } # GLUON
24 | gluon_format = { version = "0.18.2", path = "../format" } # GLUON
25 | gluon_doc = { version = "0.18.2", path = "../doc" } # GLUON
26 | 
27 | app_dirs = { package = "app_dirs2", version = "2.5.5" }
28 | anyhow = "1.0.75"
29 | futures = "0.3.28"
30 | tokio = { version = "1.32.0", features = ["rt-multi-thread", "macros", "signal"] }
31 | clap = "2.34.0"
32 | structopt = "0.3.26"
33 | log = "0.4.20"
34 | env_logger = { version = "0.9.3", optional = true }
35 | lazy_static = "1.4.0"
36 | rustyline = "=6.0.0"
37 | walkdir = "2.3.3"
38 | codespan = "0.11.1"
39 | codespan-reporting = "0.11.1"
40 | quick-error = "2.0.1"
41 | 
42 | serde = "1.0.188"
43 | serde_derive = "1.0.188"
44 | 
45 | [target.'cfg(not(windows))'.dependencies]
46 | ansi_term = "0.12.1"
47 | 
48 | [dev-dependencies]
49 | pretty_assertions = "1.4.0"
50 | tokio = "1.32.0"
51 | 
52 | [target.'cfg(unix)'.dev-dependencies]
53 | rexpect = "0.4.0"
54 | 
55 | [features]
56 | default = ["env_logger"]
57 | test = []
58 | 
59 | 


--------------------------------------------------------------------------------
/repl/build.rs:
--------------------------------------------------------------------------------
 1 | use std::env;
 2 | use std::path::Path;
 3 | use std::process::Command;
 4 | 
 5 | fn main() {
 6 |     if env::var("GIT_HASH").is_err() {
 7 |         let output = Command::new("git")
 8 |             .args(&["rev-parse", "HEAD"])
 9 |             .output()
10 |             .unwrap();
11 |         let git_hash = String::from_utf8(output.stdout).unwrap();
12 |         println!("cargo:rustc-env=GIT_HASH={}", git_hash);
13 |     }
14 | 
15 |     let edit_msg = Path::new("../.git/COMMIT_EDITMSG");
16 |     if edit_msg.exists() {
17 |         // This is the closest thing to making sure we rebuild this every time a new commit is made
18 |         println!("cargo:rerun-if-changed={}", edit_msg.display());
19 |     }
20 | }
21 | 


--------------------------------------------------------------------------------
/repl/tests/basic.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate pretty_assertions;
 3 | 
 4 | use std::env;
 5 | use std::path::Path;
 6 | use std::process::{Command, Stdio};
 7 | 
 8 | #[test]
 9 | fn issue_365_run_io_from_command_line() {
10 |     if ::std::env::var("GLUON_PATH").is_err() {
11 |         ::std::env::set_var("GLUON_PATH", "..");
12 |     }
13 | 
14 |     let path = env::args().next().unwrap();
15 |     let gluon_path = Path::new(&path[..])
16 |         .parent()
17 |         .and_then(|p| p.parent())
18 |         .expect("folder")
19 |         .join("gluon");
20 |     let output = Command::new(&*gluon_path)
21 |         .stdin(Stdio::piped())
22 |         .stdout(Stdio::piped())
23 |         .stderr(Stdio::piped())
24 |         .arg("tests/print.glu")
25 |         .output()
26 |         .unwrap_or_else(|err| panic!("{}\nWhen opening `{}`", err, gluon_path.display()));
27 | 
28 |     let stderr = String::from_utf8_lossy(&output.stderr);
29 |     if stderr != "" {
30 |         panic!("{}", stderr);
31 |     }
32 |     assert_eq!(String::from_utf8_lossy(&output.stdout), "123\n");
33 | }
34 | 


--------------------------------------------------------------------------------
/repl/tests/print.glu:
--------------------------------------------------------------------------------
1 | let io = import! std.io
2 | io.println "123"
3 | 


--------------------------------------------------------------------------------
/scripts/before_deploy.sh:
--------------------------------------------------------------------------------
 1 | # This script takes care of building your crate and packaging it for release
 2 | 
 3 | set -ex
 4 | 
 5 | main() {
 6 |     local src=$(pwd) \
 7 |           stage=
 8 | 
 9 |     case $TRAVIS_OS_NAME in
10 |         linux)
11 |             stage=$(mktemp -d)
12 |             ;;
13 |         osx)
14 |             stage=$(mktemp -d -t tmp)
15 |             ;;
16 |     esac
17 | 
18 |     test -f Cargo.lock || cargo generate-lockfile
19 | 
20 |     cross build -p gluon_repl --target $TARGET --release
21 | 
22 |     # Copy the files that are needed in the distribution
23 |     if [ -f target/$TARGET/release/gluon ]; then
24 |         cp target/$TARGET/release/gluon $stage/
25 |     elif [ -f target/$TARGET/release/gluon.exe ]; then
26 |         cp target/$TARGET/release/gluon.exe $stage/
27 |     else
28 |         echo "Could not find gluon executable"
29 |         exit 1
30 |     fi
31 |     mkdir $stage/std
32 |     cp -r std/* $stage/std/
33 | 
34 |     cd $stage
35 |     tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
36 |     cd $src
37 | 
38 |     rm -rf $stage
39 | 
40 |     mv $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz target/
41 | }
42 | 
43 | main
44 | 


--------------------------------------------------------------------------------
/scripts/ci.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | set -ex
 3 | 
 4 | export RUST_BACKTRACE=1
 5 | 
 6 | declare -a PROJECTS=(
 7 |     gluon_codegen
 8 |     gluon_base
 9 |     gluon_parser
10 |     gluon_check
11 |     gluon_completion
12 |     gluon_vm
13 |     gluon_format
14 |     gluon
15 |     gluon_c-api
16 |     gluon_doc
17 |     gluon_repl
18 | )
19 | 
20 | if [ -z $NO_NORMAL_TEST ]; then
21 |     cargo test --features "test" --all "$@"
22 |     cargo test --features "test" --all --bins "$@"
23 |     cargo test --features "test" --all --examples "$@"
24 |     cargo test --features "test" --all --benches "$@"
25 |     cargo test --features "test" -p gluon_parser --benches "$@"
26 |     echo "" | cargo run --features "test" --example 24
27 |     cargo run --features "test" --example marshalling
28 | 
29 |     echo "TRAVIS_RUST_VERSION=$TRAVIS_RUST_VERSION"
30 |     (echo $TRAVIS_RUST_VERSION | grep nightly) && cargo test --features "test nightly" -p gluon --test compiletest "$@"
31 | 
32 |     # Check each crate individually so that features from one do not affect another which would break publish
33 |     for PROJECT in "${PROJECTS[@]}"
34 |     do
35 |         cargo check --package "${PROJECT}" --no-default-features "$@"
36 |     done
37 | fi
38 | 


--------------------------------------------------------------------------------
/scripts/install_cross.sh:
--------------------------------------------------------------------------------
 1 | set -ex
 2 | 
 3 | main() {
 4 |     local target=x86_64-unknown-linux-musl
 5 |     # https://github.com/cross-rs/cross/releases/download/v0.2.5/cross-x86_64-unknown-linux-musl.tar.gz
 6 |     # This fetches latest stable release
 7 |     local tag=$(git ls-remote --tags --refs --exit-code https://github.com/cross-rs/cross \
 8 |                        | cut -d/ -f3 \
 9 |                        | grep -E '^v[0.1.0-9.]+
#39; \
10 |                        | sort --version-sort \
11 |                        | tail -n1)
12 |     sh ./scripts/install.sh -- \
13 |         --force \
14 |         --git cross-rs/cross \
15 |         --tag $tag \
16 |         --target $target
17 | }
18 | 
19 | main
20 | 


--------------------------------------------------------------------------------
/scripts/install_mdbook.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | set -ex
 4 | 
 5 | 
 6 | if [[ $1 == *"apple"* ]]; then
 7 |     exit 0
 8 | else
 9 |     TARGET='x86_64-unknown-linux-musl'
10 | fi
11 | 
12 | MDBOOK_VERSION="mdbook-v0.2.1-${TARGET}"
13 | curl -L "https://github.com/rust-lang-nursery/mdBook/releases/download/v0.2.1/$MDBOOK_VERSION.tar.gz" | tar -xvz
14 | chmod +x ./mdbook
15 | mv ./mdbook $HOME/bin/
16 | 


--------------------------------------------------------------------------------
/scripts/install_sccache.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | set -ex
 4 | 
 5 | # https://stackoverflow.com/a/34676160/2489366
 6 | # the directory of the script
 7 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 8 | 
 9 | # the temp directory used, within $DIR
10 | # omit the -p parameter to create a temporal directory in the default location
11 | WORK_DIR=`mktemp -d "$DIR.XXXXXXXX"`
12 | 
13 | # check if tmp dir was created
14 | if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then
15 |   echo "Could not create temp dir"
16 |   exit 1
17 | fi
18 | 
19 | # deletes the temp directory
20 | function cleanup {
21 |   rm -rf "$WORK_DIR"
22 |   echo "Deleted temp working directory $WORK_DIR"
23 | }
24 | 
25 | # register the cleanup function to be called on the EXIT signal
26 | trap cleanup EXIT
27 | 
28 | # Sample links
29 | # https://github.com/mozilla/sccache/releases/download/v0.5.4/sccache-dist-v0.5.4-x86_64-unknown-linux-musl.tar.gz
30 | # https://github.com/mozilla/sccache/releases/download/v0.5.4/sccache-v0.5.4-aarch64-apple-darwin.tar.gz
31 | 
32 | VERSION="v0.4.2"
33 | 
34 | if [[ $1 == *"apple"* ]]; then
35 |     TARGET=$1
36 |     SCCACHE_VERSION="sccache-${VERSION}-aarch64-${TARGET}-darwin"
37 | else
38 |     TARGET='x86_64-unknown-linux-musl'
39 |     SCCACHE_VERSION="sccache-dist-${VERSION}-${TARGET}"
40 | fi
41 | 
42 | pushd ${WORK_DIR}
43 | 
44 | curl -L "https://github.com/mozilla/sccache/releases/download/${VERSION}/$SCCACHE_VERSION.tar.gz" | tar -xvz
45 | mv $SCCACHE_VERSION/sccache* ./sccache
46 | # it is sccache-dist on linux and sccache on mac
47 | chmod +x ./sccache
48 | mv ./sccache $HOME/bin/
49 | 
50 | popd
51 | 


--------------------------------------------------------------------------------
/scripts/publish.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | set -ex
 3 | 
 4 | VERSION=$(echo $1 | sed 's/v//')
 5 | shift
 6 | 
 7 | function retry {
 8 |     for i in {0..10}; do
 9 |         $@
10 |         if [ $? -eq 0 ]; then
11 |             exit 0
12 |         fi
13 |         sleep 3
14 |     done
15 |     exit 1
16 | }
17 | 
18 | 
19 | declare -a PROJECTS=(
20 |     gluon_codegen
21 |     gluon_base
22 |     gluon_parser
23 |     gluon_check
24 |     gluon_completion
25 |     gluon_vm
26 |     gluon_format
27 |     gluon
28 |     gluon_c-api
29 |     gluon_doc
30 |     gluon_repl
31 | )
32 | 
33 | for PROJECT in "${PROJECTS[@]}"
34 | do
35 |     PROJECT_PATH=$(echo "$PROJECT" | sed 's/gluon_//' | sed 's/gluon/./')
36 | 
37 |     if ! (./scripts/sync_publish.sh "$(pwd)/${PROJECT_PATH}" -f "$@"); then
38 |         echo "Failed to publish $PROJECT_PATH"
39 |         exit 1
40 |     fi
41 | done
42 | 


--------------------------------------------------------------------------------
/scripts/release.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | set -ex
 3 | 
 4 | LEVEL=$1
 5 | VERSION=$2
 6 | if [ -z "$LEVEL" ]; then
 7 |     echo "Expected patch, minor or major"
 8 |     exit 1
 9 | fi
10 | 
11 | clog --$LEVEL
12 | if [[ -z $(head -1 CHANGELOG.md | grep $VERSION) ]]; then
13 |     git checkout CHANGELOG.md
14 |     echo "Wrong version specified"
15 |     exit 1
16 | fi
17 | 
18 | git add CHANGELOG.md
19 | 
20 | ./scripts/version.sh $VERSION
21 | 


--------------------------------------------------------------------------------
/scripts/sync_publish.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | # Usage: sync_publish /path/to/crate -f
 4 | #
 5 | # Publish a crate and wait for it to become available.
 6 | #
 7 | # https://gist.github.com/Riateche/a1c500fe760a2b9190beb0a7134db82d
 8 | 
 9 | set -e
10 | set -o pipefail
11 | 
12 | TMP_DIR=/tmp/test1
13 | 
14 | DIR="$1"
15 | FORCE="$2"
16 | shift
17 | shift
18 | 
19 | NAME=$(grep '^name' "$DIR/Cargo.toml" | head -n 1 | sed 's/name = "\([^"]*\)"/\1/')
20 | cd "$DIR"
21 | 
22 | VERSION=$(cargo metadata --format-version 1 2>/dev/null | jq -r '.packages[] | select(.name=="'$NAME'").version')
23 | 
24 | rm -rf "$TMP_DIR"
25 | cargo new "$TMP_DIR" > /dev/null 2>&1
26 | cd "$TMP_DIR"
27 | if cargo add "$NAME@$VERSION" > /dev/null 2>&1; then
28 |     echo "$NAME=$VERSION already exists, skipping."
29 |     exit 0
30 | fi
31 | 
32 | echo "Publishing $NAME=$VERSION"
33 | if [ "$FORCE" != "-f" ]; then
34 |     echo "This is a dry run. Run with -f to publish."
35 |     exit 0
36 | fi
37 | 
38 | cd "$DIR"
39 | cargo publish $@
40 | 
41 | cd "$TMP_DIR"
42 | while ! cargo add "$NAME@$VERSION" > /dev/null 2>&1; do
43 |     echo "Waiting for crate to be published..."
44 |     sleep 1
45 | done
46 | 


--------------------------------------------------------------------------------
/scripts/version.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | # Modified from https://github.com/nikomatsakis/lalrpop/blob/master/version.sh
 3 | #
 4 | # A script to bump the version number on all Cargo.toml files etc in
 5 | # an atomic fashion.
 6 | 
 7 | set -e
 8 | 
 9 | if [ "$1" == "" ]; then
10 |     echo "Usage: version.sh <new-version-number>"
11 |     exit 1
12 | fi
13 | 
14 | VERSION=$(
15 |     ls **/Cargo.toml | \
16 |         xargs grep "# GLUON" | \
17 |         perl -p -e 's/.*version = "([0-9.]+)"[^#]+# GLUON/$1/' |
18 |         sort |
19 |         uniq)
20 | 
21 | if [ $(echo $VERSION | wc -w) != 1 ]; then
22 |     echo "Error: inconsistent versions detected across Cargo.toml files!"
23 |     echo "$VERSION"
24 |     exit 1
25 | fi
26 | 
27 | echo "Found consistent version $VERSION"
28 | 
29 | perl -p -i -e 's/version *= *"[0-9.]+"([^#]+)# GLUON/version = "'$1'"$1# GLUON/' \
30 |      $(ls **/Cargo.toml Cargo.toml)
31 | 
32 | perl -p -i -e 's/^gluon *= *"[0-9.]+"/gluon = "'$1'"/' \
33 |      README.md
34 | 
35 | perl -p -i -e 's/[0-9][0-9.]+([^#]+)# GLUON/'$1'$1# GLUON/' \
36 |      $(ls **/src/lib.rs src/lib.rs)
37 | 
38 | # Update Cargo.lock
39 | cargo fetch
40 | 
41 | git add .
42 | CHANGES=$(git diff  HEAD --unified=0 CHANGELOG.md | tail +6 | sed -e 's/^\+//')
43 | git commit -m "Version ${1}"
#39;\n\n'"${CHANGES}"
44 | git tag "v${1}"
45 | 


--------------------------------------------------------------------------------
/src/std_lib.rs:
--------------------------------------------------------------------------------
 1 | pub mod env;
 2 | #[cfg(feature = "http")]
 3 | pub mod http;
 4 | pub mod io;
 5 | pub mod process;
 6 | #[cfg(all(feature = "random", not(target_arch = "wasm32")))]
 7 | pub mod random;
 8 | #[cfg(feature = "regex")]
 9 | pub mod regex;
10 | 


--------------------------------------------------------------------------------
/src/std_lib/process.rs:
--------------------------------------------------------------------------------
 1 | use crate::real_std::process::Command;
 2 | use crate::vm::{api::IO, thread::Thread, ExternModule, Result};
 3 | 
 4 | #[derive(Getable, VmType)]
 5 | #[gluon(crate_name = "::vm")]
 6 | struct CreateProcess<'a> {
 7 |     command: &'a str,
 8 |     args: Vec<&'a str>,
 9 |     env: Option<Vec<(&'a str, &'a str)>>,
10 |     current_dir: Option<&'a str>,
11 | }
12 | 
13 | fn execute(create: CreateProcess) -> IO<Option<i32>> {
14 |     let mut command = Command::new(create.command);
15 |     for arg in &create.args {
16 |         command.arg(arg);
17 |     }
18 |     match create.env {
19 |         Some(env) => {
20 |             command.env_clear();
21 |             for (key, value) in &env {
22 |                 command.env(key, value);
23 |             }
24 |         }
25 |         None => (),
26 |     }
27 |     if let Some(current_dir) = create.current_dir {
28 |         command.current_dir(current_dir);
29 |     }
30 |     IO::from(command.status().map(|status| status.code()))
31 | }
32 | 
33 | mod std {
34 |     pub mod process {
35 |         pub use crate::std_lib::process as prim;
36 |     }
37 | }
38 | 
39 | pub fn load(vm: &Thread) -> Result<ExternModule> {
40 |     ExternModule::new(
41 |         vm,
42 |         record! {
43 |             execute => primitive!(1, std::process::prim::execute)
44 |         },
45 |     )
46 | }
47 | 


--------------------------------------------------------------------------------
/src/std_lib/random.rs:
--------------------------------------------------------------------------------
 1 | //! Module containing bindings to the `rand` library.
 2 | 
 3 | extern crate rand;
 4 | extern crate rand_xorshift;
 5 | 
 6 | use self::rand::{Rng, SeedableRng};
 7 | 
 8 | use crate::vm::{
 9 |     self,
10 |     api::{RuntimeResult, IO},
11 |     thread::Thread,
12 |     types::VmInt,
13 |     ExternModule,
14 | };
15 | 
16 | #[derive(Clone, Debug, Userdata, Trace, VmType)]
17 | #[gluon(vm_type = "std.random.XorShiftRng")]
18 | #[gluon_userdata(clone)]
19 | #[gluon(crate_name = "::vm")]
20 | #[gluon_trace(skip)]
21 | struct XorShiftRng(self::rand_xorshift::XorShiftRng);
22 | 
23 | field_decl! { value, gen }
24 | 
25 | fn next_int(_: ()) -> IO<VmInt> {
26 |     IO::Value(rand::thread_rng().gen())
27 | }
28 | 
29 | fn next_float(_: ()) -> IO<f64> {
30 |     IO::Value(rand::thread_rng().gen())
31 | }
32 | 
33 | fn gen_int_range(low: VmInt, high: VmInt) -> IO<VmInt> {
34 |     IO::Value(rand::thread_rng().gen_range(low..high))
35 | }
36 | 
37 | type RngNext<G> = record_type! {
38 |     value => VmInt,
39 |     gen => G
40 | };
41 | 
42 | fn xor_shift_new(seed: &[u8]) -> RuntimeResult<XorShiftRng, String> {
43 |     if seed.len() == 16 {
44 |         let seed = unsafe { *(seed.as_ptr() as *const [u8; 16]) };
45 |         RuntimeResult::Return(XorShiftRng(self::rand_xorshift::XorShiftRng::from_seed(
46 |             seed,
47 |         )))
48 |     } else {
49 |         RuntimeResult::Panic("Expected xorshift seed to have 16 elements".to_string())
50 |     }
51 | }
52 | 
53 | fn xor_shift_next(gen: &XorShiftRng) -> RngNext<XorShiftRng> {
54 |     let mut gen = gen.clone();
55 |     record_no_decl! {
56 |         value => gen.0.gen(),
57 |         gen => gen
58 |     }
59 | }
60 | 
61 | mod std {
62 |     pub mod random {
63 |         pub use crate::std_lib::random as prim;
64 |     }
65 | }
66 | 
67 | pub fn load(vm: &Thread) -> vm::Result<ExternModule> {
68 |     vm.register_type::<XorShiftRng>("std.random.XorShiftRng", &[])?;
69 | 
70 |     ExternModule::new(
71 |         vm,
72 |         record! {
73 |             type std::random::XorShiftRng => XorShiftRng,
74 |             next_int => primitive!(1, std::random::prim::next_int),
75 |             next_float => primitive!(1, std::random::prim::next_float),
76 |             gen_int_range => primitive!(2, std::random::prim::gen_int_range),
77 |             xor_shift_new => primitive!(1, std::random::prim::xor_shift_new),
78 |             xor_shift_next => primitive!(1, std::random::prim::xor_shift_next)
79 |         },
80 |     )
81 | }
82 | 


--------------------------------------------------------------------------------
/src/std_lib/regex.rs:
--------------------------------------------------------------------------------
 1 | //! Module containing bindings to the `regex` library.
 2 | 
 3 | extern crate regex;
 4 | 
 5 | use crate::vm::{self, thread::Thread, ExternModule};
 6 | 
 7 | #[derive(Debug, Userdata, Trace, VmType)]
 8 | #[gluon(vm_type = "std.regex.Regex")]
 9 | #[gluon(crate_name = "vm")]
10 | #[gluon_trace(skip)]
11 | struct Regex(regex::Regex);
12 | 
13 | #[derive(Debug, Userdata, Trace, VmType)]
14 | #[gluon(vm_type = "std.regex.Error")]
15 | #[gluon(crate_name = "vm")]
16 | #[gluon_trace(skip)]
17 | struct Error(regex::Error);
18 | 
19 | fn new(re: &str) -> Result<Regex, Error> {
20 |     match regex::Regex::new(re) {
21 |         Ok(r) => Ok(Regex(r)),
22 |         Err(e) => Err(Error(e)),
23 |     }
24 | }
25 | 
26 | fn is_match(re: &Regex, text: &str) -> bool {
27 |     let &Regex(ref re) = re;
28 |     re.is_match(text)
29 | }
30 | 
31 | #[derive(Pushable, VmType)]
32 | #[gluon(vm_type = "std.regex.types.Match")]
33 | #[gluon(crate_name = "vm")]
34 | struct Match<'a> {
35 |     start: usize,
36 |     end: usize,
37 |     text: &'a str,
38 | }
39 | 
40 | impl<'a> Match<'a> {
41 |     fn new(m: regex::Match<'a>) -> Self {
42 |         Match {
43 |             start: m.start(),
44 |             end: m.end(),
45 |             text: m.as_str(),
46 |         }
47 |     }
48 | }
49 | 
50 | fn find<'a>(re: &Regex, text: &'a str) -> Option<Match<'a>> {
51 |     let &Regex(ref re) = re;
52 |     re.find(text).map(Match::new)
53 | }
54 | 
55 | fn captures<'a>(re: &Regex, text: &'a str) -> Option<Vec<Option<Match<'a>>>> {
56 |     let &Regex(ref re) = re;
57 |     re.captures(text)
58 |         .map(|c| (0..c.len()).map(move |i| c.get(i).map(Match::new)))
59 |         // FIXME Once rust stops ICEing .map(Collect::new)
60 |         .map(|i| i.collect())
61 | }
62 | 
63 | fn error_to_string(err: &Error) -> String {
64 |     let &Error(ref err) = err;
65 |     err.to_string()
66 | }
67 | 
68 | mod std {
69 |     pub mod regex {
70 |         pub use crate::std_lib::regex as prim;
71 |     }
72 | }
73 | 
74 | pub fn load(vm: &Thread) -> vm::Result<ExternModule> {
75 |     vm.register_type::<Regex>("std.regex.Regex", &[])?;
76 |     vm.register_type::<Error>("std.regex.Error", &[])?;
77 | 
78 |     ExternModule::new(
79 |         vm,
80 |         record! {
81 |             type Error => Error,
82 |             type Regex => Regex,
83 |             type Match => Match,
84 | 
85 |             new => primitive!(1, std::regex::prim::new),
86 |             is_match => primitive!(2, std::regex::prim::is_match),
87 |             find => primitive!(2, std::regex::prim::find),
88 |             // Workaround MIR bug in rustc
89 |             captures => primitive!(2, "std.regex.prim.captures", |x, y| std::regex::prim::captures(x, y)),
90 |             error_to_string => primitive!(1, std::regex::prim::error_to_string)
91 |         },
92 |     )
93 | }
94 | 


--------------------------------------------------------------------------------
/std/alternative.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Alternative` type
 3 | let { Applicative } = import! std.applicative
 4 | 
 5 | /// A monoid on applicative functors.
 6 | #[implicit]
 7 | type Alternative f = {
 8 |     applicative : Applicative f,
 9 |     /// The identify of `or`
10 |     empty : forall a . f a,
11 |     /// An associative binary operation.
12 |     ///
13 |     /// Evaluates to the first argument if it is not `empty`, otherwise evaluates to the second argument.
14 |     or : forall a . f a -> f a -> f a
15 | }
16 | 
17 | let empty ?alt : [Alternative f] -> f a = alt.empty
18 | 
19 | let or ?alt : [Alternative f] -> f a -> f a -> f a = alt.or
20 | 
21 | /// An associative binary operation. Alias of `or`.
22 | ///
23 | /// Evaluates to the first argument if it is not `empty`, otherwise evaluates to the second argument.
24 | #[infix(left, 3)]
25 | let (<|>) : [Alternative f] -> f a -> f a -> f a = or
26 | 
27 | {
28 |     Alternative,
29 |     empty,
30 |     or,
31 |     (<|>),
32 | }
33 | 


--------------------------------------------------------------------------------
/std/assert.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Assertion functions.
 3 | let { error } = import! std.prim
 4 | 
 5 | let assert_msg x s = if x then () else error s
 6 | let assert x = assert_msg x "Assertion failed"
 7 | 
 8 | {
 9 |     assert,
10 |     assert_msg,
11 | }
12 | 


--------------------------------------------------------------------------------
/std/bool.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! The boolean type.
 3 | 
 4 | let { Bool, Ordering } = import! std.types
 5 | let { Semigroup } = import! std.semigroup
 6 | let { Monoid } = import! std.monoid
 7 | let { Group } = import! std.group
 8 | let { Eq, Ord } = import! std.cmp
 9 | let { Show } = import! std.show
10 | let { id } = import! std.function
11 | 
12 | /// Boolean 'not'
13 | let not x : Bool -> Bool = if x then False else True
14 | 
15 | /// Boolean 'exclusive or'
16 | let xor x y : Bool -> Bool -> Bool = if x then not y else y
17 | 
18 | let conjunctive =
19 |     let semigroup : Semigroup Bool = {
20 |         append = \x y -> x && y,
21 |     }
22 | 
23 |     let monoid : Monoid Bool = {
24 |         semigroup = semigroup,
25 |         empty = True,
26 |     }
27 | 
28 |     { semigroup, monoid }
29 | 
30 | let disjunctive =
31 |     let semigroup : Semigroup Bool = {
32 |         append = \x y -> x || y,
33 |     }
34 | 
35 |     let monoid : Monoid Bool = {
36 |         semigroup = semigroup,
37 |         empty = False,
38 |     }
39 | 
40 |     { semigroup, monoid }
41 | 
42 | let exclusive =
43 |     let semigroup : Semigroup Bool = { append = xor }
44 | 
45 |     let monoid : Monoid Bool = {
46 |         semigroup = semigroup,
47 |         empty = False,
48 |     }
49 | 
50 |     let group : Group Bool = {
51 |         monoid = monoid,
52 |         inverse = id,
53 |     }
54 | 
55 |     { semigroup, monoid, group }
56 | 
57 | let eq : Eq Bool = {
58 |     (==) = \l r -> if l then r else not r,
59 | }
60 | 
61 | let ord : Ord Bool = {
62 |     eq = eq,
63 |     compare = \l r -> if l then if r then EQ else GT else LT,
64 | }
65 | 
66 | let show : Show Bool = {
67 |     show = \x -> if x then "True" else "False",
68 | }
69 | 
70 | {
71 |     Bool,
72 |     not,
73 |     xor,
74 |     conjunctive,
75 |     disjunctive,
76 |     exclusive,
77 |     eq,
78 |     ord,
79 |     show,
80 | }
81 | 


--------------------------------------------------------------------------------
/std/byte.glu:
--------------------------------------------------------------------------------
 1 | //! An 8-bit unsigned integer.
 2 | 
 3 | let { Semigroup, Monoid, Group, Eq, Ord, Ordering, Num, Show } = import! std.prelude
 4 | 
 5 | let additive =
 6 |     let semigroup : Semigroup Byte = {
 7 |         append = \x y -> x #Byte+ y,
 8 |     }
 9 | 
10 |     let monoid : Monoid Byte = {
11 |         semigroup = semigroup,
12 |         empty = 0b,
13 |     }
14 | 
15 |     let group : Group Byte = {
16 |         monoid = monoid,
17 |         inverse = \x -> 0b #Byte- x,
18 |     }
19 | 
20 |     { semigroup, monoid, group }
21 | 
22 | let multiplicative =
23 |     let semigroup : Semigroup Byte = {
24 |         append = \x y -> x #Byte* y,
25 |     }
26 | 
27 |     let monoid : Monoid Byte = {
28 |         semigroup = semigroup,
29 |         empty = 1b,
30 |     }
31 | 
32 |     { semigroup, monoid }
33 | 
34 | let eq : Eq Byte = {
35 |     (==) = \l r -> l #Byte== r,
36 | }
37 | 
38 | let ord : Ord Byte = {
39 |     eq = eq,
40 |     compare = \l r -> if l #Byte< r then LT else if l #Byte== r then EQ else GT,
41 | }
42 | 
43 | let num : Num Byte = {
44 |     ord = ord,
45 |     (+) = additive.semigroup.append,
46 |     (-) = \l r -> l #Byte- r,
47 |     (*) = multiplicative.semigroup.append,
48 |     (/) = \l r -> l #Byte/ r,
49 |     negate = additive.group.inverse,
50 | }
51 | 
52 | let show : Show Byte = {
53 |     show = (import! std.prim).show_byte,
54 | }
55 | 
56 | {
57 |     additive,
58 |     multiplicative,
59 |     eq,
60 |     ord,
61 |     num,
62 |     show,
63 |     ..
64 |     import! std.byte.prim
65 | }
66 | 


--------------------------------------------------------------------------------
/std/category.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Category` type
 3 | 
 4 | #[implicit]
 5 | type Category (cat : Type -> Type -> Type) = {
 6 |     id : forall a . cat a a,
 7 |     compose : forall a b c . cat b c -> cat a b -> cat a c
 8 | }
 9 | 
10 | let id ?cat : forall cat a . [Category cat] -> cat a a = cat.id
11 | let compose ?cat : forall a b c . [Category cat] -> cat b c -> cat a b -> cat a c = cat.compose
12 | 
13 | /// Right-to-left composition. Alias for `compose`.
14 | #[infix(right, 9)]
15 | let (<<) : forall a b c . [Category cat] -> cat b c -> cat a b -> cat a c = compose
16 | 
17 | /// Left-to-right composition. Alias for `compose`, but with the arguments flipped.
18 | #[infix(left, 9)]
19 | let (>>) f g : forall a b c . [Category cat] -> cat a b -> cat b c -> cat a c = compose g f
20 | 
21 | {
22 |     Category,
23 |     id,
24 |     compose,
25 | 
26 |     (<<),
27 |     (>>),
28 | }
29 | 


--------------------------------------------------------------------------------
/std/channel.glu:
--------------------------------------------------------------------------------
1 | //! Mpmc channels.
2 | 
3 | let prim = import! std.channel.prim
4 | 
5 | {
6 |     ..
7 |     prim
8 | }
9 | 


--------------------------------------------------------------------------------
/std/char.glu:
--------------------------------------------------------------------------------
 1 | //! A character type.
 2 | 
 3 | let { Eq, Ord, Ordering, Show } = import! std.prelude
 4 | 
 5 | let eq : Eq Char = { (==) = \l r -> l #Char== r }
 6 | 
 7 | let ord : Ord Char = {
 8 |     eq = eq,
 9 |     compare = \l r -> if l #Char< r then LT else if l #Char== r then EQ else GT,
10 | }
11 | 
12 | let show : Show Char = { show = (import! std.prim).show_char }
13 | 
14 | {
15 |     eq,
16 |     ord,
17 |     show,
18 |     ..
19 |     import! std.char.prim
20 | }
21 | 


--------------------------------------------------------------------------------
/std/cmp.glu:
--------------------------------------------------------------------------------
  1 | //@NO-IMPLICIT-PRELUDE
  2 | //! Functionality for ordering and comparison.
  3 | 
  4 | let { Bool, Ordering } = import! std.types
  5 | let { Semigroup } = import! std.semigroup
  6 | let { Monoid } = import! std.monoid
  7 | 
  8 | /// `Eq a` defines equality (==) on `a`
  9 | #[implicit]
 10 | type Eq a = {
 11 |     /// Tests whether the values are equal.
 12 |     (==) : a -> a -> Bool
 13 | }
 14 | 
 15 | #[infix(left, 4)]
 16 | let (==) ?eq : [Eq a] -> a -> a -> Bool = eq.(==)
 17 | 
 18 | /// Tests whether the values are not equal.
 19 | #[infix(left, 4)]
 20 | let (/=) ?eq l r : [Eq a] -> a -> a -> Bool = if (eq.(==) l r) then False else True
 21 | 
 22 | /// `Ord a` defines an ordering on `a`
 23 | #[implicit]
 24 | type Ord a = {
 25 |     eq : Eq a,
 26 |     /// Compares two values and returns wheter the first is less than, equal or greater than the second.
 27 |     compare : a -> a -> Ordering
 28 | }
 29 | 
 30 | let compare ?ord : [Ord a] -> a -> a -> Ordering = ord.compare
 31 | 
 32 | /// Returns whether `l` is less than or equal to `r`.
 33 | #[infix(left, 4)]
 34 | let (<=) l r : [Ord a] -> a -> a -> Bool =
 35 |     match compare l r with
 36 |     | LT -> True
 37 |     | EQ -> True
 38 |     | GT -> False
 39 | 
 40 | /// Returns whether `l` is less than `r`.
 41 | #[infix(left, 4)]
 42 | let (<) l r : [Ord a] -> a -> a -> Bool =
 43 |     match compare l r with
 44 |     | LT -> True
 45 |     | EQ -> False
 46 |     | GT -> False
 47 | 
 48 | /// Returns whether `l` is greater than `r`.
 49 | #[infix(left, 4)]
 50 | let (>) l r : [Ord a] -> a -> a -> Bool =
 51 |     match compare l r with
 52 |     | LT -> False
 53 |     | EQ -> False
 54 |     | GT -> True
 55 | 
 56 | /// Returns whether `l` is greater than or equal to `r`.
 57 | #[infix(left, 4)]
 58 | let (>=) l r : [Ord a] -> a -> a -> Bool =
 59 |     match compare l r with
 60 |     | LT -> False
 61 |     | EQ -> True
 62 |     | GT -> True
 63 | 
 64 | let min l r : [Ord a] -> a -> a -> a =
 65 |     if l <= r then l
 66 |     else r
 67 | 
 68 | let max l r : [Ord a] -> a -> a -> a =
 69 |     if r >= l then r
 70 |     else l
 71 | 
 72 | let semigroup : Semigroup Ordering = {
 73 |     append = \x y ->
 74 |         match x with
 75 |         | EQ -> y
 76 |         | _ -> x,
 77 | }
 78 | 
 79 | let monoid : Monoid Ordering = {
 80 |     semigroup,
 81 |     empty = EQ,
 82 | }
 83 | 
 84 | {
 85 |     Eq,
 86 |     (==),
 87 |     (/=),
 88 | 
 89 |     Bool,
 90 | 
 91 |     Ord,
 92 |     compare,
 93 |     (<),
 94 |     (<=),
 95 |     (>=),
 96 |     (>),
 97 |     min,
 98 |     max,
 99 | 
100 |     Ordering,
101 | 
102 |     semigroup,
103 | 
104 |     monoid,
105 | }
106 | 


--------------------------------------------------------------------------------
/std/debug.glu:
--------------------------------------------------------------------------------
1 | //! Debug library.
2 | 
3 | let prim = import! std.debug.prim
4 | 
5 | {
6 |     ..
7 |     prim
8 | }
9 | 


--------------------------------------------------------------------------------
/std/disposable.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! A `Disposable` abstracts over different kinds of resources.
 3 | 
 4 | let { IO, wrap, flat_map } = import! std.io.prim
 5 | let { Bool } = import! std.types
 6 | 
 7 | 
 8 | /// A resource that has to be released after use, for example a file handle or a
 9 | /// database connection.
10 | #[implicit]
11 | type Disposable a = {
12 |     /// Disposes of `a`, releasing the resources it manages. Calling this function
13 |     /// a second time (or more) has no effect.
14 |     dispose : a -> IO (),
15 |     /// Indicates if `a` has been disposed, meaning that `dispose` has been called
16 |     /// at least once.
17 |     is_disposed : a -> Bool
18 | }
19 | 
20 | let dispose ?disposable : [Disposable a] -> a -> IO () = disposable.dispose
21 | 
22 | let is_disposed ?disposable : [Disposable a] -> a -> Bool = disposable.is_disposed
23 | 
24 | /// Calls `action` with `disposable` and disposes `disposable` afterwards. Returns
25 | /// the result of `action`, unless disposing `disposable` fails.
26 | let using disposable action : forall r . [Disposable a] -> a -> (a -> IO r) -> IO r =
27 |     let result = action disposable
28 |     do _ = dispose disposable
29 |     result
30 | 
31 | 
32 | {
33 |     Disposable,
34 | 
35 |     dispose,
36 |     is_disposed,
37 |     using,
38 | }
39 | 


--------------------------------------------------------------------------------
/std/effect.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Composable effect types
 3 | let { error } = import! std.prim
 4 | let option = import! std.option
 5 | let { Result, ? } = import! std.result
 6 | let { (<<), (|>) } = import! std.function
 7 | let { (<>) } = import! std.semigroup
 8 | let monoid @ { Monoid } = import! std.monoid
 9 | 
10 | let { Functor, map } = import! std.functor
11 | let { Applicative, wrap } = import! std.applicative
12 | let { Monad } = import! std.monad
13 | 
14 | rec
15 | /// An effectful function `a -> b`
16 | type Arr r a b = a -> Eff r b
17 | 
18 | /// The `Eff` monad provides composable effect via a `Row` of effects (`r`) and produces a value of type `a`.
19 | type Eff r a =
20 |     | Pure a
21 |     | Impure : forall x . r x -> Arr r x a -> Eff r a
22 | in
23 | let compose f g : Arr r a b -> Arr r b c -> Arr r a c = \a ->
24 |     match f a with
25 |     | Pure b -> g b
26 |     | Impure r h -> Impure r (compose h g)
27 | 
28 | let wrap_eff x : a -> Eff r a = Pure x
29 | let flat_map_eff f m : (a -> Eff r b) -> Eff r a -> Eff r b =
30 |     match m with
31 |     | Pure x -> f x
32 |     | Impure row g -> Impure row (compose g f)
33 | 
34 | let functor : Functor (Eff r) = {
35 |     map = \f m -> flat_map_eff (\x -> wrap_eff (f x)) m,
36 | }
37 | 
38 | let applicative : Applicative (Eff r) = {
39 |     functor,
40 |     apply = \f g -> flat_map_eff (\f1 -> flat_map_eff (\g1 -> wrap_eff (f1 g1)) g) f,
41 |     wrap = wrap_eff,
42 | }
43 | 
44 | let monad : Monad (Eff r) = {
45 |     applicative,
46 |     flat_map = flat_map_eff,
47 | }
48 | 
49 | type OpenVariant r a = .. r
50 | #[doc(hidden)]
51 | let inject_rest x : forall e . OpenVariant r a -> [| | r |] a = convert_effect! x
52 | 
53 | /// Extracts the value of type `a` from an effectful computation. Can only be done once all other
54 | /// effects have been eliminated from the row (leaving `[| |]` as the empty effect). See each
55 | /// individual effects module on how to eliminate the effect.
56 | let run_pure eff : Eff [| |] a -> a =
57 |     match eff with
58 |     | Pure v -> v
59 |     | Impure _ _ -> error "Impossible: run_pure"
60 | 
61 | {
62 |     Eff,
63 |     Arr,
64 | 
65 |     functor,
66 |     applicative,
67 |     monad,
68 | 
69 |     run_pure,
70 | 
71 |     inject_rest,
72 | }
73 | 


--------------------------------------------------------------------------------
/std/effect/alt.glu:
--------------------------------------------------------------------------------
 1 | //! Implementation of the `Alt` effect
 2 | 
 3 | let { Eff, inject_rest, ? } = import! std.effect
 4 | let { map } = import! std.functor
 5 | let { wrap } = import! std.applicative
 6 | let { Alternative } = import! std.alternative
 7 | let { (<<), id } = import! std.function
 8 | 
 9 | /// The `Alt` effect lets `Eff` implement `Alternative`
10 | type Alt r a =
11 |     | Empty
12 |     .. r
13 | 
14 | let extract_alt x : forall s . [| alt : Alt | r |] a -> Alt r a = convert_variant! x
15 | 
16 | let send_alt f : Alt r a -> Eff [| alt : Alt | r |] a = Impure (convert_effect! alt f) Pure
17 | 
18 | let run_alt_inner transform fail eff_1 eff_2 : (a -> b)
19 |         -> (() -> Eff [| | s |] b)
20 |         -> Eff [| alt : Alt | r |] a
21 |         -> Eff [| alt : Alt | r |] a
22 |         -> Eff [| | s |] b
23 |     =
24 |     let loop next ve : (() -> Eff [| | s |] b) -> Eff [| alt : Alt | r |] a -> _ =
25 |         match ve with
26 |         | Pure value -> wrap (transform value)
27 |         | Impure e f ->
28 |             match extract_alt e with
29 |             | Empty ->
30 |                 next ()
31 |             | rest ->
32 |                 Impure (inject_rest rest) (loop next << f)
33 |     let loop_2 _ = loop fail eff_2
34 |     loop loop_2 eff_1
35 | 
36 | let empty : forall s . Eff [| alt : Alt | r |] s =
37 |     send_alt Empty
38 | 
39 | let alternative : Alternative (Eff [| alt : Alt | r |]) = {
40 |     applicative = (import! std.effect).applicative,
41 |     empty = empty,
42 |     or = \l r -> run_alt_inner id (\_ -> empty) l r,
43 | }
44 | 
45 | /// Eliminates the `Alt` effect returning `None` if the `Alt` effect is `empty`, otherwise returns `Some a` with the value
46 | ///
47 | /// ```
48 | /// let { assert_eq, ? } = import! std.test
49 | /// let alt @ { ? } = import! std.effect.alt
50 | /// let state = import! std.effect.state
51 | /// let { (*>) } = import! std.applicative
52 | /// let { empty } = import! std.alternative
53 | /// let { Eff, run_pure, ? } = import! std.effect
54 | ///
55 | /// let incr = state.modify (\x -> x + 1)
56 | ///
57 | /// seq assert_eq (run_pure (state.exec_state 0 (alt.run_alt incr incr))) (1)
58 | /// seq assert_eq (run_pure (state.exec_state 0 (alt.run_alt (incr *> incr) incr))) (2)
59 | /// seq assert_eq (run_pure (state.exec_state 0 (alt.run_alt (incr *> empty *> incr) incr))) (2)
60 | /// assert_eq (run_pure (state.exec_state 0 (alt.run_alt empty incr))) (1)
61 | ///
62 | /// ```
63 | let run_alt eff_1 eff_2 : Eff [| alt : Alt | r |] a
64 |         -> Eff [| alt : Alt | r |] a
65 |         -> Eff [| | r |] (Option a)
66 |     =
67 |     let fail _ = wrap None
68 |     run_alt_inner Some fail eff_1 eff_2
69 | 
70 | {
71 |     Alt,
72 | 
73 |     alternative,
74 | 
75 |     run_alt,
76 | }
77 | 


--------------------------------------------------------------------------------
/std/effect/error.glu:
--------------------------------------------------------------------------------
 1 | //! Implementation of the `Error` effect
 2 | 
 3 | let { Eff, inject_rest, ? } = import! std.effect
 4 | let { Result } = import! std.result
 5 | let { Option } = import! std.option
 6 | let { (<<) } = import! std.function
 7 | let { wrap } = import! std.applicative
 8 | 
 9 | /// The `Error` effects adds "exceptions" to the `Eff` monad
10 | type Error e r a =
11 |     | Error e
12 |     .. r
13 | 
14 | let send_error f : Error e r a -> Eff [| error : Error e | r |] a =
15 |     Impure (convert_effect! error f) Pure
16 | 
17 | let extract_error x : forall e . [| error : Error e | r |] a -> Error e r a = convert_variant! x
18 | 
19 | /// Throws the error `e`
20 | let throw e : e -> Eff [| error : Error e | r |] a = send_error (Error e)
21 | 
22 | /// Moves a `Result` into the `Eff` monad
23 | let ok_or_throw r : Result e t -> Eff [| error : Error e | r |] t =
24 |     match r with
25 |     | Ok t -> wrap t
26 |     | Err e -> throw e
27 | 
28 | let some_or_throw e o : e -> Option a -> Eff [| error : Error e | r |] a =
29 |     match o with
30 |     | Some x -> wrap x
31 |     | None -> throw e
32 | 
33 | /// Eliminates the `Error` effect and returns a `Result`
34 | let run_error eff : forall e . Eff [| error : Error e | r |] a -> Eff [| | r |] (Result e a) =
35 |     let loop ve : Eff [| error : Error e | r |] a -> Eff [| | r |] (Result e a) =
36 |         match ve with
37 |         | Pure v -> wrap (Ok v)
38 |         | Impure e f ->
39 |             match extract_error e with
40 |             | Error err ->
41 |                 wrap (Err err)
42 |             | rest ->
43 |                 Impure (inject_rest rest) (loop << f)
44 |     loop eff
45 | 
46 | /// Catches an "exception", allowing the effect to continue executing
47 | let catch eff handler : forall e .
48 |         Eff [| error : Error e | r |] a
49 |             -> (e -> Eff [| error : Error e | r |] a)
50 |             -> Eff [| error : Error e | r |] a
51 |     =
52 |     let loop ve : Eff [| error : Error e | r |] a -> Eff [| error : Error e | r |] a =
53 |         match ve with
54 |         | Pure v -> wrap v
55 |         | Impure e f ->
56 |             match extract_error e with
57 |             | Error err ->
58 |                 handler err
59 |             | rest ->
60 |                 Impure e (loop << f)
61 |     loop eff
62 | 
63 | 
64 | {
65 |     Error,
66 | 
67 |     catch,
68 |     throw,
69 |     ok_or_throw,
70 |     some_or_throw,
71 |     run_error,
72 | }
73 | 


--------------------------------------------------------------------------------
/std/effect/io.glu:
--------------------------------------------------------------------------------
1 | let { lift } = import! std.effect.lift
2 | lift_io! lift (import! std.io)
3 | 


--------------------------------------------------------------------------------
/std/effect/io/read.glu:
--------------------------------------------------------------------------------
1 | let { lift } = import! std.effect.lift
2 | let { Read } = import! std.io.read
3 | lift_io! lift (import! std.io.read)
4 | 


--------------------------------------------------------------------------------
/std/effect/io/write.glu:
--------------------------------------------------------------------------------
1 | let { lift } = import! std.effect.lift
2 | let { Write } = import! std.io.write
3 | lift_io! lift (import! std.io.write)
4 | 


--------------------------------------------------------------------------------
/std/effect/lift.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Lift` effect
 3 | let { error } = import! std.prim
 4 | let { Eff, inject_rest } = import! std.effect
 5 | let { wrap } = import! std.applicative
 6 | let { Monad, flat_map } = import! std.monad
 7 | let { (<<) } = import! std.function
 8 | 
 9 | /// The `Lift` effect allows a regular monad (usually `IO`) to be used in an `Eff` monad
10 | type Lift m r a =
11 |     | Lift (m a)
12 |     .. r
13 | 
14 | let send_lift f : Lift m r a -> Eff [| lift : Lift m | r |] a = Impure (convert_effect! lift f) Pure
15 | 
16 | let extract_state x : forall m . [| lift : Lift m | r |] a -> Lift m r a = convert_variant! x
17 | 
18 | /// "Lifts" a monadic action into the `Eff` monad. Since monads do not compose this can only be
19 | let lift m : m a -> Eff [| lift : Lift m | r |] a = send_lift (Lift m)
20 | 
21 | /// Eliminates the lifted monad `m`. Can only be used once all other effects have been eliminated
22 | let run_lift eff : [Monad m] -> Eff [| lift : Lift m |] a -> m a =
23 |     let loop ve : Eff [| lift : Lift m |] a -> m a =
24 |         match ve with
25 |         | Pure v -> wrap v
26 |         | Impure e f ->
27 |             match extract_state e with
28 |             | Lift m ->
29 |                 do a = m
30 |                 loop (f a)
31 |             | _ -> error "Impossible: Lift should always be the only remaining variant"
32 |     loop eff
33 | 
34 | {
35 |     Lift,
36 | 
37 |     lift,
38 |     run_lift,
39 | }
40 | 


--------------------------------------------------------------------------------
/std/effect/reader.glu:
--------------------------------------------------------------------------------
 1 | //! Implementation of the `Reader` effect
 2 | let { Eff, inject_rest, ? } = import! std.effect
 3 | let { map } = import! std.functor
 4 | let { wrap } = import! std.applicative
 5 | let { (<<) } = import! std.function
 6 | 
 7 | /// The `Reader` effects provides a shared, immutable environment for the effectful functions using it
 8 | type Reader s r a =
 9 |     | Ask : Reader s r s
10 |     .. r
11 | 
12 | let extract_reader x : forall s . [| reader : Reader s | r |] a -> Reader s r a = convert_variant! x
13 | 
14 | let send_reader f : Reader s r a -> Eff [| reader : Reader s | r |] a =
15 |     Impure (convert_effect! reader f) Pure
16 | 
17 | /// Retrieve the value from the environment
18 | let ask : forall s . Eff [| reader : Reader s | r |] s =
19 |     send_reader Ask
20 | 
21 | /// Retrieve the value from the environment while applying `f` to it
22 | let asks f : forall s . (s -> a) -> Eff [| reader : Reader s | r |] a =
23 |     map f ask
24 | 
25 | /// Runs a computation in a modified environment.
26 | let local f eff : forall s .
27 |         (s -> s) -> Eff [| reader : Reader s | r |] a -> Eff [| reader : Reader s | r |] a
28 |     =
29 |     do s = asks f
30 |     let s : s = s
31 |     // FIXME Remove after this does not affect inference
32 |     let loop ve : Eff [| reader : Reader s | r |] a -> Eff [| reader : Reader s | r |] a =
33 |         match ve with
34 |         | Pure value -> wrap value
35 |         | Impure e f ->
36 |             match extract_reader e with
37 |             | Ask ->
38 |                 loop (f s)
39 |             | rest ->
40 |                 Impure (inject_rest rest) (loop << f)
41 |     loop eff
42 | 
43 | /// Eliminates the `Reader` effect
44 | let run_reader s eff : forall s . s -> Eff [| reader : Reader s | r |] a -> Eff [| | r |] a =
45 |     let loop reader ve : s -> Eff [| reader : Reader s | r |] a -> Eff [| | r |] a =
46 |         match ve with
47 |         | Pure value -> wrap value
48 |         | Impure e f ->
49 |             match extract_reader e with
50 |             | Ask ->
51 |                 loop reader (f reader)
52 |             | rest ->
53 |                 Impure (inject_rest rest) (loop reader << f)
54 |     loop s eff
55 | {
56 |     Reader,
57 |     ask,
58 |     asks,
59 |     local,
60 |     run_reader,
61 | }
62 | 


--------------------------------------------------------------------------------
/std/effect/reference.glu:
--------------------------------------------------------------------------------
 1 | let { lift } = import! std.effect.lift
 2 | let m = lift_io! lift (import! std.reference)
 3 | 
 4 | #[infix(right, 9)]
 5 | let (<-) = m.(<-)
 6 | 
 7 | {
 8 |     (<-),
 9 |     ..
10 |     m
11 | }
12 | 


--------------------------------------------------------------------------------
/std/effect/st.glu:
--------------------------------------------------------------------------------
 1 | //! Implementation of the `st.State` effect
 2 | 
 3 | let { Eff, inject_rest, ? } = import! std.effect
 4 | let { map } = import! std.functor
 5 | let { wrap } = import! std.applicative
 6 | let { (<<) } = import! std.function
 7 | let reference @ { Reference, ref, load } = import! std.st.reference.prim
 8 | 
 9 | type STRef s a = Reference a
10 | 
11 | #[infix(right, 9)]
12 | let (<-) = reference.(<-)
13 | 
14 | /// The `State` effect enables the use of mutable state. By branding the state with `s` the mutable
15 | /// values are prevented from escaping the monad.
16 | type State s r a =
17 |     | Call : forall b . (() -> b) -> State s r b
18 |     .. r
19 | 
20 | #[inline(never)]
21 | let extract_state x : forall s . [| st : State s | r |] a -> State s r a = convert_variant! x
22 | 
23 | #[inline(never)]
24 | let send_state f : forall s . State s r a -> Eff [| st : State s | r |] a =
25 |     Impure (convert_effect! st f) Pure
26 | 
27 | let make_call = Call
28 | 
29 | /// Creates a new mutable reference that contains `a`.
30 | let new_ref a : forall s . a -> Eff [| st : State s | r |] (STRef s a) =
31 |     send_state (Call (\_ -> ref a))
32 | 
33 | /// Reads the values stored in the reference.
34 | let read_ref ref : forall s . STRef s a -> Eff [| st : State s | r |] a =
35 |     send_state (Call (\_ -> load ref))
36 | 
37 | /// Writes a new value into the reference.
38 | let write_ref a ref : forall s . a -> STRef s a -> Eff [| st : State s | r |] () =
39 |     send_state (Call (\_ -> ref <- a))
40 | 
41 | /// Eliminates the `State` effect
42 | let run_state eff : (forall s . Eff [| st : State s | r |] a) -> Eff [| | r |] a =
43 |     let loop ve : forall s . Eff [| st : State s | r |] a -> Eff [| | r |] a =
44 |         match ve with
45 |         | Pure value -> wrap value
46 |         | Impure e f ->
47 |             match extract_state e with
48 |             | Call g ->
49 |                 loop (f (g ()))
50 |             | rest ->
51 |                 Impure (inject_rest rest) (loop << f)
52 |     loop eff
53 | 
54 | 
55 | {
56 |     State,
57 |     STRef,
58 | 
59 |     send_state,
60 | 
61 |     new_ref,
62 |     read_ref,
63 |     write_ref,
64 |     run_state,
65 |     make_call,
66 | }
67 | 


--------------------------------------------------------------------------------
/std/effect/st/string.glu:
--------------------------------------------------------------------------------
 1 | let { Eff, ? } = import! std.effect
 2 | let { State, send_state, make_call } = import! std.effect.st
 3 | let prim @ { StringBuf } = import! std.effect.st.string.prim
 4 | 
 5 | let new : forall s . Eff [| st : State s | r |] (StringBuf s) =
 6 |     send_state (make_call prim.new)
 7 | 
 8 | let len buf : StringBuf s -> Eff [| st : State s | r |] Int =
 9 |     send_state (make_call (\_ -> prim.len buf))
10 | 
11 | let push_str buf str : StringBuf s -> String -> Eff [| st : State s | r |] () =
12 |     send_state (make_call (\_ -> prim.push_str buf str))
13 | 
14 | let slice buf start end : StringBuf s -> Int -> Int -> Eff [| st : State s | r |] String =
15 |     send_state (make_call (\_ -> prim.slice buf start end))
16 | 
17 | /// ```
18 | /// let { assert_eq, ? } = import! std.test
19 | /// let st = import! std.effect.st
20 | /// let string_buf = import! std.effect.st.string
21 | /// let { (*>) } = import! std.applicative
22 | /// let { Eff, run_pure, ? } = import! std.effect
23 | ///
24 | /// let action =
25 | ///     do buf = string_buf.new
26 | ///     seq string_buf.push_str buf "field:"
27 | ///     seq string_buf.push_str buf " "
28 | ///     seq string_buf.push_str buf "123"
29 | ///     string_buf.read buf
30 | /// assert_eq (run_pure (st.run_state action)) "field: 123"
31 | /// ```
32 | let read buf : StringBuf s -> Eff [| st : State s | r |] String =
33 |     do l = len buf
34 |     slice buf 0 l
35 | 
36 | {
37 |     StringBuf,
38 | 
39 |     new,
40 |     len,
41 |     push_str,
42 |     slice,
43 |     read,
44 | }
45 | 


--------------------------------------------------------------------------------
/std/effect/state.glu:
--------------------------------------------------------------------------------
 1 | //! Implementation of the `State` effect
 2 | 
 3 | let { Eff, inject_rest, ? } = import! std.effect
 4 | let { map } = import! std.functor
 5 | let { wrap } = import! std.applicative
 6 | let { (<<) } = import! std.function
 7 | 
 8 | /// The `State` effect provides an updatable state
 9 | type State s r a =
10 |     | Get : State s r s
11 |     | Put : s -> State s r ()
12 |     .. r
13 | 
14 | let extract_state x : forall s . [| state : State s | r |] a -> State s r a = convert_variant! x
15 | 
16 | let send_state f : State s r a -> Eff [| state : State s | r |] a =
17 |     Impure (convert_effect! state f) Pure
18 | 
19 | /// Retreive the current value.
20 | let get : forall s . Eff [| state : State s | r |] s =
21 |     send_state Get
22 | 
23 | /// Retreive the current value and applied `f` to it.
24 | let gets f : forall s . (s -> a) -> Eff [| state : State s | r |] a =
25 |     map f get
26 | 
27 | /// Store `s` as the new value of the state.
28 | let put s : s -> Eff [| state : State s | r |] () =
29 |     send_state (Put s)
30 | 
31 | /// Update the state by applying `f`.
32 | let modify f : (s -> s) -> Eff [| state : State s | r |] () =
33 |     do s = get
34 |     put (f s)
35 | 
36 | /// Eliminate the `State` effect and return the state and the computed value
37 | let run_state s eff : forall s .
38 |         s
39 |             -> Eff [| state : State s | r |] a
40 |             -> Eff [| | r |] { state : s, value : a }
41 |     =
42 |     let loop state ve : s
43 |             -> Eff [| state : State s | r |] a
44 |             -> Eff [| | r |] { state : s, value : a }
45 |         =
46 |         match ve with
47 |         | Pure value -> wrap { state, value }
48 |         | Impure e f ->
49 |             match extract_state e with
50 |             | Get ->
51 |                 loop state (f state)
52 |             | Put state ->
53 |                 loop state (f ())
54 |             | rest ->
55 |                 Impure (inject_rest rest) (loop state << f)
56 |     loop s eff
57 | 
58 | /// Eliminate the `State` effect and return the state
59 | let exec_state s eff : forall s . s -> Eff [| state : State s | r |] a -> Eff [| | r |] s =
60 |     map (\r -> r.state) (run_state s eff)
61 | 
62 | /// Eliminate the `State` effect and return the computed value
63 | let eval_state s eff : forall s . s -> Eff [| state : State s | r |] a -> Eff [| | r |] a =
64 |     map (\r -> r.value) (run_state s eff)
65 | 
66 | {
67 |     State,
68 | 
69 |     get,
70 |     gets,
71 |     put,
72 |     modify,
73 |     run_state,
74 |     exec_state,
75 |     eval_state,
76 | }
77 | 


--------------------------------------------------------------------------------
/std/effect/writer.glu:
--------------------------------------------------------------------------------
 1 | //! Implementation of the `Writer` effect
 2 | 
 3 | let { Eff, inject_rest, ? } = import! std.effect
 4 | let monoid @ { Monoid } = import! std.monoid
 5 | let { (<>) } = import! std.semigroup
 6 | let { wrap } = import! std.applicative
 7 | let { (<<) } = import! std.function
 8 | 
 9 | /// The `Writer` effect allows the computations to output values of type `s`
10 | type Writer s r a =
11 |     | Tell : s -> Writer s r ()
12 |     .. r
13 | 
14 | #[inline(never)]
15 | let extract_writer x : forall s . [| writer : Writer s | r |] a -> Writer s r a = convert_variant! x
16 | 
17 | #[inline(never)]
18 | let send_writer f : Writer s r a -> Eff [| writer : Writer s | r |] a =
19 |     Impure (convert_effect! writer f) Pure
20 | 
21 | /// Outputs `s`
22 | let tell s : forall s . s -> Eff [| writer : Writer s | r |] () =
23 |     send_writer (Tell s)
24 | 
25 | /// Eliminates `Writer`, returning the output and computed value. Each output through `tell` are
26 | /// joined via its `Monoid` instance
27 | let run_writer eff : forall s .
28 |         [Monoid s] -> Eff [| writer : Writer s | r |] a -> Eff [| | r |] { value : a, writer : s }
29 |     =
30 |     let loop writer ve : s -> Eff [| writer : Writer s | r |] a -> Eff [| | r |] _ =
31 |         match ve with
32 |         | Pure value -> wrap { value, writer }
33 |         | Impure e f ->
34 |             match extract_writer e with
35 |             | Tell w ->
36 |                 loop (writer <> w) (f ())
37 |             | rest ->
38 |                 Impure (inject_rest rest) (loop writer << f)
39 |     loop monoid.empty eff
40 | 
41 | {
42 |     Writer,
43 | 
44 |     tell,
45 |     run_writer,
46 | }
47 | 


--------------------------------------------------------------------------------
/std/env.glu:
--------------------------------------------------------------------------------
1 | //! Inspection and manipulation of the process's environment.
2 | 
3 | {
4 |     ..
5 |     import! std.env.prim
6 | }
7 | 


--------------------------------------------------------------------------------
/std/float.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! The 64-bit floating point type.
 3 | 
 4 | let { Semigroup, Monoid, Group, Eq, Ord, Ordering, Num, Show } = import! std.prelude
 5 | 
 6 | let additive =
 7 |     let semigroup : Semigroup Float = { append = \x y -> x #Float+ y }
 8 | 
 9 |     let monoid : Monoid Float = {
10 |         semigroup = semigroup,
11 |         empty = 0.0,
12 |     }
13 | 
14 |     let group : Group Float = {
15 |         monoid = monoid,
16 |         inverse = \x -> 0.0 #Float- x,
17 |     }
18 | 
19 |     { semigroup, monoid, group }
20 | 
21 | let multiplicative =
22 |     let semigroup : Semigroup Float = { append = \x y -> x #Float* y }
23 | 
24 |     let monoid : Monoid Float = {
25 |         semigroup = semigroup,
26 |         empty = 1.0,
27 |     }
28 | 
29 |     let group : Group Float = {
30 |         monoid = monoid,
31 |         inverse = \x -> 1.0 #Float/ x,
32 |     }
33 | 
34 |     { semigroup, monoid, group }
35 | 
36 | let eq : Eq Float = {
37 |     (==) = \l r -> l #Float== r,
38 | }
39 | 
40 | let ord : Ord Float = {
41 |     eq = eq,
42 |     compare = \l r -> if l #Float< r then LT else if l #Float== r then EQ else GT,
43 | }
44 | 
45 | let num : Num Float = {
46 |     ord = ord,
47 |     (+) = additive.semigroup.append,
48 |     (-) = \l r -> l #Float- r,
49 |     (*) = multiplicative.semigroup.append,
50 |     (/) = \l r -> l #Float/ r,
51 |     negate = additive.group.inverse,
52 | }
53 | 
54 | let show : Show Float = {
55 |     show = (import! std.prim).show_float,
56 | }
57 | 
58 | {
59 |     additive,
60 |     multiplicative,
61 |     eq,
62 |     ord,
63 |     num,
64 |     show,
65 |     ..
66 |     import! std.float.prim
67 | }
68 | 


--------------------------------------------------------------------------------
/std/foldable.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Foldable` type
 3 | 
 4 | let { Bool, Option } = import! std.types
 5 | let { Semigroup, append } = import! std.semigroup
 6 | let { Monoid, empty } = import! std.monoid
 7 | let { wrap } = import! std.applicative
 8 | let { Monad, flat_map } = import! std.monad
 9 | let { Eq, (==) } = import! std.cmp
10 | 
11 | /// Operations over a data structure that can be folded which means that a functions gets called on
12 | /// each element to reduce the structure to a single value (`Array`, `List` and `Map` are all `Foldable`)
13 | #[implicit]
14 | type Foldable (f : Type -> Type) = {
15 |     foldr : forall a b . (a -> b -> b) -> b -> f a -> b,
16 |     foldl : forall a b . (b -> a -> b) -> b -> f a -> b
17 | }
18 | 
19 | let foldr ?fold : forall a b . [Foldable f] -> (a -> b -> b) -> b -> f a -> b = fold.foldr
20 | let foldl ?fold : forall a b . [Foldable f] -> (b -> a -> b) -> b -> f a -> b = fold.foldl
21 | 
22 | let concat : [Foldable t] -> [Monoid m] -> t m -> m =
23 |     foldr append empty
24 | 
25 | let concat_map f : [Foldable t] -> [Monoid m] -> (a -> m) -> t a -> m =
26 |     foldr (\x -> append (f x)) empty
27 | 
28 | let fold_m ?fold ?monad f z : [Foldable t] -> [Monad m] -> (a -> b -> m a) -> a -> t b -> m a =
29 |     foldl (\acc y -> flat_map (\x -> f x y) acc) (wrap z)
30 | 
31 | let find ?fold pred : [Foldable t] -> (a -> Bool) -> t a -> Option a =
32 |     let go acc next =
33 |         match acc with
34 |         | None -> if pred next then Some next else None
35 |         | Some _ -> acc
36 | 
37 |     fold.foldl go None
38 | 
39 | let find_map ?fold pred : [Foldable t] -> (a -> Option b) -> t a -> Option b =
40 |     let go acc next =
41 |         match acc with
42 |         | None -> pred next
43 |         | Some _ -> acc
44 | 
45 |     fold.foldl go None
46 | 
47 | let all pred : [Foldable t] -> (a -> Bool) -> t a -> Bool =
48 |     foldl (\acc x -> acc && pred x) True
49 | 
50 | let any pred : [Foldable t] -> (a -> Bool) -> t a -> Bool =
51 |     foldl (\acc x -> acc || pred x) False
52 | 
53 | let elem x : [Foldable t] -> [Eq a] -> a -> t a -> Bool =
54 |     any ((==) x)
55 | 
56 | let count : [Foldable t] -> t a -> Int =
57 |     foldl (\acc _ -> acc #Int+ 1) 0
58 | 
59 | {
60 |     Foldable,
61 |     foldr,
62 |     foldl,
63 |     fold_m,
64 |     concat,
65 |     concat_map,
66 |     find,
67 |     find_map,
68 |     all,
69 |     any,
70 |     elem,
71 |     count,
72 | }
73 | 


--------------------------------------------------------------------------------
/std/fs.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Functions for working with the file system
 3 | 
 4 | let fs_prim = import! std.fs.prim
 5 | 
 6 | {
 7 |     ..
 8 |     fs_prim
 9 | }
10 | 
11 | 


--------------------------------------------------------------------------------
/std/function.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Conveniences for working with functions.
 3 | 
 4 | let { Semigroup } = import! std.semigroup
 5 | let { Monoid } = import! std.monoid
 6 | let { Category } = import! std.category
 7 | let { Functor } = import! std.functor
 8 | let { Monad } = import! std.monad
 9 | let { Applicative } = import! std.applicative
10 | 
11 | let semigroup s : Semigroup b -> Semigroup (a -> b) = {
12 |     append = \f g x -> s.append (f x) (g x),
13 | }
14 | 
15 | let monoid m : Monoid b -> Monoid (a -> b) = {
16 |     semigroup = semigroup m.semigroup,
17 |     empty = \_ -> m.empty,
18 | }
19 | 
20 | let category : Category (->) = {
21 |     id = \x -> x,
22 |     compose = \f g x -> f (g x),
23 | }
24 | 
25 | let functor : Functor ((->) a) = { map = category.compose }
26 | 
27 | let applicative : Applicative ((->) a) = {
28 |     functor = functor,
29 |     apply = \f g x -> f x (g x),
30 |     wrap = \x y -> x,
31 | }
32 | 
33 | let monad : Monad ((->) a) = {
34 |     applicative = applicative,
35 |     flat_map = \f m x -> f (m x) x,
36 | }
37 | 
38 | /// The identity function, where `id x == x`
39 | let id : a -> a = category.id
40 | 
41 | /// const `x` creates a function that always returns `x`
42 | let const : a -> b -> a = applicative.wrap
43 | 
44 | /// flip `f` creates a new function that takes its two arguments in reverse order
45 | let flip f x y : (a -> b -> c) -> b -> a -> c = f y x
46 | 
47 | /// Backward function application, where `f <| x == f x`
48 | #[infix(right, 0)]
49 | let (<|) f x : (a -> b) -> a -> b = f x
50 | 
51 | /// Forward function application, where `x |> f == f x`
52 | #[infix(left, 0)]
53 | let (|>) x f : a -> (a -> b) -> b = f x
54 | 
55 | /// Right-to-left function composition
56 | #[infix(right, 9)]
57 | let (<<) : (b -> c) -> (a -> b) -> a -> c = category.compose
58 | 
59 | /// Left-to-right function composition
60 | #[infix(left, 9)]
61 | let (>>) : (a -> b) -> (b -> c) -> a -> c = flip category.compose
62 | 
63 | {
64 |     semigroup,
65 |     monoid,
66 |     category,
67 |     functor,
68 |     applicative,
69 |     monad,
70 |     id,
71 |     const,
72 |     flip,
73 |     (<|),
74 |     (|>),
75 |     (<<),
76 |     (>>),
77 | }
78 | 


--------------------------------------------------------------------------------
/std/functor.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Functor` type
 3 | 
 4 | /// A `Functor` represents an action on a parameterized type which does not
 5 | /// change the structure with the mapped type.
 6 | ///
 7 | /// The following laws should hold:
 8 | ///
 9 | /// * `map id == id`
10 | /// * `map (f << g) == map f << map g`
11 | #[implicit]
12 | type Functor f = {
13 |     /// Apply the supplied function to the contents of `f a`, converting it to
14 |     /// an `f b`
15 |     ///
16 |     /// # Examples
17 |     ///
18 |     /// * `option.functor.map show_Int.show (Some 1) == Some "1"`
19 |     /// * `result.functor.map show_Int.show (Some 1) == Ok "1"`
20 |     /// * `list.functor.map show_Int.show (list.of [1, 2]) == list.of ["1", "2"]`
21 |     ///
22 |     /// # Note
23 |     ///
24 |     /// * Known as `fmap` in Haskell
25 |     map : forall a b . (a -> b) -> f a -> f b
26 | }
27 | 
28 | let map ?functor : [Functor f] -> (a -> b) -> f a -> f b = functor.map
29 | 
30 | { Functor, map }
31 | 


--------------------------------------------------------------------------------
/std/group.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Group` type
 3 | 
 4 | let { Monoid } = import! std.monoid
 5 | 
 6 | /// `Group a` represents an monoid an which has an inverse element. This means
 7 | /// the following additional laws must hold:
 8 | ///
 9 | /// * `forall x . append (inverse x) x = empty = append x (inverse x)`
10 | #[implicit]
11 | type Group a = {
12 |     monoid : Monoid a,
13 |     /// The inverse operation
14 |     inverse : a -> a
15 | }
16 | 
17 | {
18 |     Group,
19 | }
20 | 


--------------------------------------------------------------------------------
/std/http/types.glu:
--------------------------------------------------------------------------------
 1 | let { Body, ResponseBody, StatusCode, Method, Request, Response, Headers, HttpState, Uri } =
 2 |     import! std.http.prim_types
 3 | 
 4 | let { Eff } = import! std.effect
 5 | let { Error } = import! std.effect.error
 6 | let { Alt } = import! std.effect.alt
 7 | let { State } = import! std.effect.state
 8 | let { Lift } = import! std.effect.lift
 9 | 
10 | /// Type used by handlers to indicate why they could not process a request
11 | type Failure =
12 |     | DontProcess
13 |     | Error String
14 | 
15 | 
16 | type HttpEffect r a = [| alt : Alt, state : State HttpState, lift : Lift IO | r |] a
17 | 
18 | {
19 |     Method,
20 |     Failure,
21 |     Request,
22 |     StatusCode,
23 |     Headers,
24 |     Response,
25 |     ResponseBody,
26 |     HttpEffect,
27 |     HttpState,
28 |     Uri,
29 |     Body,
30 | }
31 | 


--------------------------------------------------------------------------------
/std/identity.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! The identity functor and monad.
 3 | 
 4 | let { Functor } = import! std.functor
 5 | let { Applicative } = import! std.applicative
 6 | let { Monad } = import! std.monad
 7 | 
 8 | type Identity a = a
 9 | 
10 | let functor : Functor Identity = {
11 |     map = \f m -> f m,
12 | }
13 | 
14 | let applicative : Applicative Identity = {
15 |     functor,
16 |     apply = \mf m -> mf m,
17 |     wrap = \value -> value,
18 | }
19 | 
20 | let monad : Monad Identity = {
21 |     applicative,
22 |     flat_map = \f m -> f m,
23 | }
24 | 
25 | { Identity, functor, applicative, monad }
26 | 


--------------------------------------------------------------------------------
/std/int.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! The signed 64-bit integer type.
 3 | 
 4 | let { Semigroup } = import! std.semigroup
 5 | let { Monoid } = import! std.monoid
 6 | let { Group } = import! std.group
 7 | let { Eq, Ord, Ordering } = import! std.cmp
 8 | let { Num } = import! std.num
 9 | let { Show } = import! std.show
10 | 
11 | let additive =
12 |     let semigroup : Semigroup Int = {
13 |         append = \x y -> x #Int+ y,
14 |     }
15 | 
16 |     let monoid : Monoid Int = {
17 |         semigroup = semigroup,
18 |         empty = 0,
19 |     }
20 | 
21 |     let group : Group Int = {
22 |         monoid = monoid,
23 |         inverse = \x -> 0 #Int- x,
24 |     }
25 | 
26 |     { semigroup, monoid, group }
27 | 
28 | let multiplicative =
29 |     let semigroup : Semigroup Int = {
30 |         append = \x y -> x #Int* y,
31 |     }
32 | 
33 |     let monoid : Monoid Int = {
34 |         semigroup = semigroup,
35 |         empty = 1,
36 |     }
37 | 
38 |     { semigroup, monoid }
39 | 
40 | let eq : Eq Int = {
41 |     (==) = \l r -> l #Int== r,
42 | }
43 | 
44 | let ord : Ord Int = {
45 |     eq = eq,
46 |     compare = \l r -> if l #Int< r then LT else if l #Int== r then EQ else GT,
47 | }
48 | 
49 | let num : Num Int = {
50 |     ord = ord,
51 |     (+) = additive.semigroup.append,
52 |     (-) = \l r -> l #Int- r,
53 |     (*) = multiplicative.semigroup.append,
54 |     (/) = \l r -> l #Int/ r,
55 |     negate = additive.group.inverse,
56 | }
57 | 
58 | let show : Show Int = {
59 |     show = (import! std.prim).show_int,
60 | }
61 | 
62 | {
63 |     additive,
64 |     multiplicative,
65 |     eq,
66 |     ord,
67 |     num,
68 |     show,
69 |     ..
70 |     import! std.int.prim
71 | }
72 | 


--------------------------------------------------------------------------------
/std/io.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Functions for working with I/O
 3 | 
 4 | let io_prim @ { IO, File } = import! std.io.prim
 5 | let { Read } = import! std.io.read
 6 | let { Write } = import! std.io.write
 7 | let { Disposable } = import! std.disposable
 8 | let { functor, applicative, monad } = import! std.io.base
 9 | 
10 | /// Opens the file at `path` in read-only mode. Fails if the file does not
11 | /// exist.
12 | let open_file path : String -> IO File =
13 |     let { OpenOptions } = io_prim
14 |     io_prim.open_file_with path [Read]
15 | 
16 | /// Opens a file in write-only mode. If the file already exists, it will be
17 | /// truncated. If the file does not exist, it will be created.
18 | let create_file path : String -> IO File =
19 |     let { OpenOptions } = io_prim
20 |     io_prim.open_file_with path [Create, Write, Truncate]
21 | 
22 | let read : Read File = {
23 |     read = io_prim.read_file,
24 |     read_to_end = io_prim.read_file_to_end,
25 | }
26 | 
27 | let write : Write File = {
28 |     write_slice = io_prim.write_slice_file,
29 |     flush = io_prim.flush_file,
30 | }
31 | 
32 | let disposable : Disposable File = {
33 |     dispose = io_prim.close_file,
34 |     is_disposed = io_prim.is_file_closed,
35 | }
36 | 
37 | {
38 |     open_file,
39 |     create_file,
40 | 
41 |     functor,
42 |     applicative,
43 |     monad,
44 |     read,
45 |     write,
46 |     disposable,
47 |     ..
48 |     io_prim
49 | }
50 | 


--------------------------------------------------------------------------------
/std/io/base.glu:
--------------------------------------------------------------------------------
 1 | let { Functor } = import! std.functor
 2 | let { Applicative } = import! std.applicative
 3 | let { Monad } = import! std.monad
 4 | 
 5 | let io_prim @ { IO } = import! std.io.prim
 6 | 
 7 | 
 8 | let functor : Functor IO = {
 9 |     map = \f -> io_prim.flat_map (\x -> io_prim.wrap (f x)),
10 | }
11 | 
12 | let applicative : Applicative IO =
13 |     let wrap = io_prim.wrap
14 |     let apply f x = io_prim.flat_map (\g -> io_prim.flat_map (\y -> wrap (g y)) x) f
15 | 
16 |     { functor, apply, wrap }
17 | 
18 | let monad : Monad IO = {
19 |     applicative = applicative,
20 |     flat_map = io_prim.flat_map,
21 | }
22 | 
23 | { IO, functor, applicative, monad }
24 | 


--------------------------------------------------------------------------------
/std/json.glu:
--------------------------------------------------------------------------------
 1 | //! A type representing a JSON value.
 2 | //!
 3 | //! _This module is only available if gluon is compiled with the `serialization` feature._
 4 | 
 5 | let { Map, ? } = import! std.map
 6 | let { ? } = import! std.array
 7 | 
 8 | type Value =
 9 |     | Null
10 |     | Bool Bool
11 |     | Int Int
12 |     | Float Float
13 |     | String String
14 |     | Array (Array Value)
15 |     | Object (Map String Value)
16 | 
17 | { Value }
18 | 


--------------------------------------------------------------------------------
/std/lazy.glu:
--------------------------------------------------------------------------------
 1 | //! Lazy values.
 2 | //!
 3 | //! A lazy value will only be evaluated once the `force` function is called on it.
 4 | //! The value returned by `force` is cached so any subsequence calls of `force` on the same value
 5 | //! will only return the cached value and not evaluate the lazy value again.
 6 | 
 7 | let prim = import! std.lazy.prim
 8 | 
 9 | {
10 |     ..
11 |     prim
12 | }
13 | 


--------------------------------------------------------------------------------
/std/lazyt.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Monad transformer version of `Lazy`
 3 | 
 4 | let { Applicative, apply, wrap } = import! std.applicative
 5 | let { (<<) } = import! std.function
 6 | let { Functor, map } = import! std.functor
 7 | let { Lazy, lazy, force } = import! std.lazy
 8 | let { Monad, flat_map } = import! std.monad
 9 | let { Transformer } = import! std.transformer
10 | 
11 | type LazyT m a = Lazy (m a)
12 | 
13 | let functor : [Functor m] -> Functor (LazyT m) =
14 |     let ltmap f ma = lazy (\_ -> map f (force ma))
15 | 
16 |     { map = ltmap }
17 | 
18 | let applicative : [Applicative m] -> Applicative (LazyT m) =
19 |     let ltwrap a = lazy (\_ -> wrap a)
20 |     let ltapply mf ma = lazy (\_ -> apply (force mf) (force ma))
21 | 
22 |     { functor, apply = ltapply, wrap = ltwrap }
23 | 
24 | let monad : [Monad m] -> Monad (LazyT m) =
25 |     let ltflat_map f ma = lazy (\_ -> flat_map (force << f) (force ma))
26 | 
27 |     { applicative, flat_map = ltflat_map }
28 | 
29 | let transformer : Transformer LazyT =
30 |     let wrap_monad ma : [Monad m] -> m a -> LazyT m a = lazy (\_ -> ma)
31 | 
32 |     { /* monad, */ wrap_monad }
33 | 
34 | let force_t : LazyT m a -> m a = force
35 | 
36 | {
37 |     LazyT,
38 | 
39 |     force_t,
40 | 
41 |     functor,
42 |     applicative,
43 |     monad,
44 |     transformer,
45 | }
46 | 


--------------------------------------------------------------------------------
/std/monad.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Monad` type
 3 | 
 4 | let { Bool } = import! std.types
 5 | let { Applicative, wrap } = import! std.applicative
 6 | 
 7 | /// A generalised interface for imperatively sequencing actions
 8 | #[implicit]
 9 | type Monad (m : Type -> Type) = {
10 |     applicative : Applicative m,
11 |     /// This can be seen as akin to sequential variable binding in an
12 |     /// imperative language. For example in Javascript:
13 |     ///
14 |     /// ```js
15 |     /// var x = call_fallible("hello");
16 |     /// do_something(x);
17 |     /// ```
18 |     ///
19 |     /// In gluon this would look like:
20 |     ///
21 |     /// ```gluon
22 |     /// result.monad.flat_map (\x -> do_something x) (call_fallible "hello")
23 |     /// ```
24 |     ///
25 |     /// Note that it is sometimes more ergonomic to use the `(>>=)` operator:
26 |     ///
27 |     /// ```gluon
28 |     /// let { (>>=) } = import! std.prelude
29 |     ///
30 |     /// call_fallible "hello" >>= (\x -> do_something x)
31 |     /// ```
32 |     ///
33 |     /// # Note
34 |     ///
35 |     /// * Known as `(=<<) or `flip (>>=)` in Haskell
36 |     /// * Known as `Option::and_then` and `Result::and_then` in Rust
37 |     flat_map : forall a b . (a -> m b) -> m a -> m b
38 | }
39 | 
40 | let flat_map ?m : [Monad m] -> (a -> m b) -> m a -> m b = m.flat_map
41 | 
42 | #[infix(right, 1)]
43 | let (=<<) : [Monad m] -> (a -> m b) -> m a -> m b = flat_map
44 | 
45 | #[infix(left, 1)]
46 | let (>>=) x f : [Monad m] -> m a -> (a -> m b) -> m b = flat_map f x
47 | 
48 | let join mm : [Monad m] -> m (m a) -> m a = mm >>= (\x -> x)
49 | 
50 | // Kleisli composition
51 | #[infix(right, 9)]
52 | let (<=<) g f x : [Monad m] -> (b -> m c) -> (a -> m b) -> a -> m c = g =<< f x
53 | 
54 | #[infix(left, 9)]
55 | let (>=>) f g x : [Monad m] -> (a -> m b) -> (b -> m c) -> a -> m c = f x >>= g
56 | 
57 | {
58 |     Monad,
59 |     flat_map,
60 |     (>>=),
61 |     (=<<),
62 |     join,
63 |     (<=<),
64 |     (>=>),
65 | }
66 | 


--------------------------------------------------------------------------------
/std/monoid.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Monoid` type
 3 | 
 4 | let { Semigroup } = import! std.semigroup
 5 | 
 6 | /// `Monoid a` represents an semigroup an which has an identity. This means
 7 | /// the following additional laws must hold:
 8 | ///
 9 | /// * `forall x . append x empty == x`
10 | /// * `forall x . append empty x == x`
11 | #[implicit]
12 | type Monoid a = {
13 |     semigroup : Semigroup a,
14 |     /// # Note
15 |     ///
16 |     /// * Known as `mempty` in Haskell
17 |     empty : a
18 | }
19 | 
20 | let empty ?m : [Monoid a] -> a = m.empty
21 | 
22 | {
23 |     Monoid,
24 |     empty,
25 | }
26 | 


--------------------------------------------------------------------------------
/std/num.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Operations on numbers.
 3 | 
 4 | let { Ord } = import! std.cmp
 5 | 
 6 | /// The basic operation on numbers.
 7 | /// Defined for both the primitive type `Int` and `Float`
 8 | #[implicit]
 9 | type Num a = {
10 |     ord : Ord a,
11 |     /// The addition operator
12 |     (+) : a -> a -> a,
13 |     /// The subtraction operator
14 |     (-) : a -> a -> a,
15 |     /// The multiplication operator
16 |     (*) : a -> a -> a,
17 |     /// The division operator
18 |     (/) : a -> a -> a,
19 |     /// The negation function
20 |     negate : a -> a
21 | }
22 | 
23 | #[infix(left, 6)]
24 | let (+) ?num : [Num a] -> a -> a -> a = num.(+)
25 | #[infix(left, 6)]
26 | let (-) ?num : [Num a] -> a -> a -> a = num.(-)
27 | #[infix(left, 7)]
28 | let (*) ?num : [Num a] -> a -> a -> a = num.(*)
29 | #[infix(left, 7)]
30 | let (/) ?num : [Num a] -> a -> a -> a = num.(/)
31 | 
32 | let negate ?num : [Num a] -> a -> a = num.negate
33 | 
34 | {
35 |     Num,
36 | 
37 |     (+),
38 |     (-),
39 |     (*),
40 |     (/),
41 |     negate,
42 | }
43 | 


--------------------------------------------------------------------------------
/std/path.glu:
--------------------------------------------------------------------------------
 1 | //! Functions operating on paths
 2 | 
 3 | let types @ { Component } = import! std.path.types
 4 | let _ = import! std.fs.prim
 5 | let prim = import! std.path.prim
 6 | {
 7 |     Component,
 8 |     eq_Component = types.eq_Component,
 9 |     show_Component = types.show_Component,
10 |     ..
11 |     prim
12 | }
13 | 


--------------------------------------------------------------------------------
/std/path/types.glu:
--------------------------------------------------------------------------------
 1 | 
 2 | #[derive(Show, Eq)]
 3 | type Component =
 4 |     | Prefix
 5 |     | RootDir
 6 |     | CurDir
 7 |     | ParentDir
 8 |     | Normal String
 9 | { Component, eq_Component, show_Component }
10 | 


--------------------------------------------------------------------------------
/std/prelude.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Definitions which gets implicit re-export in every file.
 3 | 
 4 | let { IO } = import! std.io.prim
 5 | let { Option } = import! std.types
 6 | let { Functor } = import! std.functor
 7 | let { Applicative, (*>), wrap } = import! std.applicative
 8 | let { Alternative } = import! std.alternative
 9 | let { Foldable } = import! std.foldable
10 | let { Monad } = import! std.monad
11 | let { Semigroup, append, (<>) } = import! std.semigroup
12 | let { Monoid, empty } = import! std.monoid
13 | let { Group } = import! std.group
14 | let { Eq, Ord, Bool, Ordering, (==), (/=), (<), (<=), (>=), (>) } = import! std.cmp
15 | let { Show, show } = import! std.show
16 | let { Category, id, compose } = import! std.category
17 | let { Num, (+), (-), (*), (/), negate } = import! std.num
18 | let { Bool, not } = import! std.bool
19 | let { Array } = import! std.array
20 | let { (++) } = import! std.string
21 | let { error } = import! std.prim
22 | let { flat_map } = import! std.monad
23 | let { (<|) } = import! std.function
24 | 
25 | {
26 |     IO,
27 | 
28 |     Ordering,
29 | 
30 |     Semigroup,
31 |     append,
32 |     (<>),
33 | 
34 |     Monoid,
35 |     empty,
36 | 
37 |     Group,
38 | 
39 |     Eq,
40 |     (==),
41 |     (/=),
42 | 
43 |     Ord,
44 |     (<),
45 |     (<=),
46 |     (>=),
47 |     (>),
48 | 
49 |     Category,
50 |     id,
51 |     compose,
52 | 
53 |     Functor,
54 |     Applicative,
55 |     Alternative,
56 |     Monad,
57 | 
58 |     Num,
59 |     (+),
60 |     (-),
61 |     (*),
62 |     (/),
63 |     negate,
64 | 
65 |     Show,
66 |     show,
67 | 
68 |     Option,
69 |     Bool,
70 | 
71 |     Array,
72 | 
73 |     (++),
74 | 
75 |     not,
76 | 
77 |     error,
78 | 
79 |     flat_map,
80 | 
81 |     (<|),
82 | }
83 | 


--------------------------------------------------------------------------------
/std/process.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Functions for working with external processes
 3 | 
 4 | let process_prim = import! std.process.prim
 5 | let { Option } = import! std.option
 6 | 
 7 | let proc command args = { command, args, env = None, current_dir = None }
 8 | 
 9 | {
10 |     proc,
11 |     ..
12 |     process_prim
13 | }
14 | 


--------------------------------------------------------------------------------
/std/random.glu:
--------------------------------------------------------------------------------
 1 | //! Basic random number generation
 2 | //!
 3 | //! _This module is only available if gluon is compiled with the `rand` feature._
 4 | 
 5 | let prim @ { XorShiftRng } = import! std.random.prim
 6 | 
 7 | type RandomGen g = { next : g -> { value : Int, gen : g } }
 8 | 
 9 | let xor_shift_rng =
10 |     let random_gen : RandomGen XorShiftRng = {
11 |         next = prim.xor_shift_next,
12 |     }
13 | 
14 |     {
15 |         new = prim.xor_shift_new,
16 |         random_gen,
17 |     }
18 | 
19 | {
20 |     RandomGen,
21 |     XorShiftRng,
22 | 
23 |     xor_shift_rng,
24 | 
25 |     thread_rng = {
26 |         next_int = prim.next_int,
27 |         next_float = prim.next_float,
28 |         gen_int_range = prim.gen_int_range,
29 |     },
30 | }
31 | 


--------------------------------------------------------------------------------
/std/reference.glu:
--------------------------------------------------------------------------------
 1 | //! A mutable reference type
 2 | 
 3 | let reference @ { Reference } = import! std.reference.prim
 4 | let { flat_map } = import! std.monad
 5 | 
 6 | let { IO, ? } = import! std.io.base
 7 | 
 8 | #[infix(right, 9)]
 9 | let (<-) = reference.(<-)
10 | 
11 | let modify r f : Reference a -> (a -> a) -> IO () =
12 |     do x = reference.load r
13 |     r <- f x
14 | {
15 |     Reference,
16 |     (<-),
17 |     modify,
18 |     ..
19 |     reference
20 | }
21 | 


--------------------------------------------------------------------------------
/std/regex.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Bindings for rust-lang/regex
 3 | 
 4 | let { Match, eq_Match, show_Match } = import! std.regex.types
 5 | let regex_prim @ { Regex, Error } = import! std.regex.prim
 6 | 
 7 | {
 8 |     Match,
 9 |     Regex,
10 |     Error,
11 | 
12 |     eq_Match,
13 |     show_Match,
14 |     ..
15 |     regex_prim
16 | }
17 | 
18 | 
19 | 


--------------------------------------------------------------------------------
/std/regex/types.glu:
--------------------------------------------------------------------------------
1 | 
2 | #[derive(Eq, Show)]
3 | type Match = { start : Int, end : Int, text : String }
4 | 
5 | { Match, eq_Match, show_Match }
6 | 


--------------------------------------------------------------------------------
/std/semigroup.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Applicative` type
 3 | 
 4 | /// `Semigroup a` represents an associative operation on `a`.
 5 | /// This means the following laws must hold:
 6 | ///
 7 | /// * `forall x . append x (append y z) == append (append x y) z`
 8 | #[implicit]
 9 | type Semigroup a = {
10 |     /// # Note
11 |     ///
12 |     /// * Known as `(<>)` or `mappend` in Haskell
13 |     append : a -> a -> a
14 | }
15 | 
16 | let append ?s : [Semigroup a] -> a -> a -> a = s.append
17 | #[infix(left, 4)]
18 | let (<>) : [Semigroup a] -> a -> a -> a = append
19 | 
20 | {
21 |     Semigroup,
22 |     append,
23 |     (<>),
24 | }
25 | 


--------------------------------------------------------------------------------
/std/show.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Value to string conversion.
 3 | 
 4 | /// `Show a` represents a conversion function from `a` to a readable string.
 5 | #[implicit]
 6 | type Show a = { show : a -> String }
 7 | 
 8 | /// Converts a value into a string.
 9 | /// ```
10 | /// let { ? } = import! std.effect
11 | /// let { assert_eq, ? } = import! std.test
12 | /// let list @ { ? } = import! std.list
13 | ///
14 | /// seq assert_eq (show 123) "123"
15 | /// seq assert_eq (show 3.14) "3.14"
16 | /// seq assert_eq (show "abc") "\"abc\""
17 | /// assert_eq (show (list.of [1, 2, 3])) "[1, 2, 3]"
18 | /// ```
19 | let show ?s : [Show a] -> a -> String = s.show
20 | 
21 | {
22 |     Show,
23 |     show,
24 | }
25 | 


--------------------------------------------------------------------------------
/std/state.glu:
--------------------------------------------------------------------------------
 1 | //! The state monad.
 2 | 
 3 | let { Applicative, Functor, Monad } = import! std.prelude
 4 | 
 5 | type State s a = s -> { value : a, state : s }
 6 | 
 7 | let functor : Functor (State s) =
 8 |     rec let map f m : (a -> b) -> State s a -> State s b = \state ->
 9 |         let { value, state } = m state
10 |         { value = f value, state = state }
11 | 
12 |     { map }
13 | 
14 | let applicative : Applicative (State s) =
15 |     rec let apply mf n : State s (a -> b) -> State s a -> State s b = \state ->
16 |         let { value, state } = mf state
17 |         functor.map value n state
18 |     in
19 |     let wrap value : a -> State s a = \state -> { value, state }
20 | 
21 |     { functor, apply, wrap }
22 | 
23 | let monad : Monad (State s) =
24 |     rec let flat_map f m : (a -> State s b) -> State s a -> State s b = \state ->
25 |         let { value, state } = m state
26 |         let m2 = f value
27 |         m2 state
28 | 
29 |     { applicative, flat_map }
30 | 
31 | let put value : s -> State s () = \state -> { value = (), state = value }
32 | 
33 | let get : State s s = \state -> { value = state, state }
34 | 
35 | let gets f : (s -> a) -> State s a = \state -> { value = f state, state }
36 | 
37 | let modify f : (s -> s) -> State s () = \state -> { value = (), state = f state }
38 | 
39 | let runState f state : State s a -> s -> { value : a, state : s } = f state
40 | 
41 | let evalState f state : State s a -> s -> a = (runState f state).value
42 | 
43 | let execState f state : State s a -> s -> s = (runState f state).state
44 | 
45 | { State, applicative, functor, monad, put, get, modify, runState, evalState, execState }
46 | 


--------------------------------------------------------------------------------
/std/string.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! A UTF-8 encoded string
 3 | 
 4 | let string_prim = import! std.string.prim
 5 | let prim = import! std.prim
 6 | let { Semigroup, (<>) } = import! std.semigroup
 7 | let { Monoid } = import! std.monoid
 8 | let { Show } = import! std.show
 9 | let { Eq, Ord, Ordering } = import! std.cmp
10 | let function = import! std.function
11 | 
12 | let semigroup : Semigroup String = { append = string_prim.append }
13 | 
14 | /// Appends two strings.
15 | ///
16 | /// Re-export of `semigroup.append`.
17 | #[infix(left, 4)]
18 | let (++) : String -> String -> String = (<>)
19 | 
20 | let monoid : Monoid String = { semigroup, empty = "" }
21 | 
22 | let eq : Eq String = { (==) = prim.string_eq }
23 | 
24 | let ord : Ord String = { eq, compare = prim.string_compare }
25 | 
26 | let show : Show String = { show = \s -> "\"" ++ s ++ "\"" }
27 | 
28 | {
29 |     eq,
30 |     ord,
31 |     show,
32 |     semigroup,
33 |     monoid,
34 |     (++),
35 |     ..
36 |     string_prim
37 | }
38 | 


--------------------------------------------------------------------------------
/std/thread.glu:
--------------------------------------------------------------------------------
1 | //! Green threading library.
2 | 
3 | let prim = import! std.thread.prim
4 | 
5 | {
6 |     ..
7 |     prim
8 | }
9 | 


--------------------------------------------------------------------------------
/std/transformer.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Utilities for writing `Monad` transformers
 3 | 
 4 | let { Monad } = import! std.prelude
 5 | 
 6 | #[implicit]
 7 | type Transformer t = { wrap_monad : forall a m . [Monad m] -> m a -> t m a }
 8 | 
 9 | let wrap_monad ?_ ?tr ma : [Monad m] -> [Transformer t] -> m a -> t m a =
10 |     tr.wrap_monad ma
11 | 
12 | { Transformer, wrap_monad }
13 | 


--------------------------------------------------------------------------------
/std/traversable.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Implementation of the `Traversable` type
 3 | 
 4 | let { Functor } = import! std.functor
 5 | let { Foldable } = import! std.foldable
 6 | let { Applicative } = import! std.applicative
 7 | 
 8 | #[implicit]
 9 | type Traversable t = {
10 |     functor : Functor t,
11 |     foldable : Foldable t,
12 |     traverse : forall a b m . Applicative m -> (a -> m b) -> t a -> m (t b)
13 | }
14 | 
15 | let traverse ?t ?a : forall a b m .
16 |         [Traversable t]
17 |             -> [Applicative m]
18 |             -> (a -> m b)
19 |             -> t a
20 |             -> m (t b)
21 |     =
22 |     t.traverse a
23 | 
24 | let sequence : [Traversable t] -> [Applicative m] -> t (m a) -> m (t a) =
25 |     traverse (\x -> x)
26 | 
27 | let for x f : [Traversable t] -> [Applicative m] -> t a -> (a -> m b) -> m (t b) =
28 |     traverse f x
29 | 
30 | 
31 | {
32 |     Traversable,
33 | 
34 |     traverse,
35 |     sequence,
36 |     for,
37 | }
38 | 


--------------------------------------------------------------------------------
/std/types.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Definition of standard types separate from the prelude to allow primitives to use them
 3 | 
 4 | /// `Bool` represents a value which can only be `True` or `False`
 5 | type Bool =
 6 |     | False
 7 |     | True
 8 | 
 9 | /// `Option` represents a value which may not exist.
10 | type Option a =
11 |     | None
12 |     | Some a
13 | 
14 | /// `Result` represents either success (`Ok`) or an error (`Err`)
15 | type Result e t =
16 |     | Err e
17 |     | Ok t
18 | 
19 | /// `Ordering` represents the result of comparing two values
20 | type Ordering =
21 |     | LT
22 |     | EQ
23 |     | GT
24 | 
25 | { Bool, Option, Result, Ordering }
26 | 


--------------------------------------------------------------------------------
/std/unit.glu:
--------------------------------------------------------------------------------
 1 | //! The unit type.
 2 | 
 3 | let { Eq, Ord, Ordering, Show } = import! std.prelude
 4 | let { const } = import! std.function
 5 | let { Bool } = import! std.bool
 6 | 
 7 | let eq : Eq () = { (==) = const (const True) }
 8 | 
 9 | let ord : Ord () = { eq = eq, compare = const (const EQ) }
10 | 
11 | let show : Show () = { show = const "()" }
12 | 
13 | {
14 |     eq,
15 |     ord,
16 |     show,
17 | }
18 | 


--------------------------------------------------------------------------------
/std/writer.glu:
--------------------------------------------------------------------------------
 1 | //! Implementation of the `Writer` type
 2 | 
 3 | let { Functor, map } = import! std.functor
 4 | let prelude @ { Applicative, Monad, Monoid, (<>) } = import! std.prelude
 5 | let { empty } = import! std.monoid
 6 | let { Identity } = import! std.identity
 7 | 
 8 | /// The writer Monad
 9 | type Writer w a = { value : a, writer : w }
10 | 
11 | let functor : [Monoid w] -> Functor (Writer w) = {
12 |     map = \f m -> { value = f m.value, writer = m.writer },
13 | }
14 | 
15 | let applicative : [Monoid w] -> Applicative (Writer w) = {
16 |     functor,
17 |     apply = \mf m -> { value = mf.value m.value, writer = mf.writer <> m.writer },
18 |     wrap = \value -> { value, writer = empty },
19 | }
20 | 
21 | let monad : [Monoid w] -> Monad (Writer w) = {
22 |     applicative,
23 |     flat_map = \f m ->
24 |         let { value, writer } = f m.value
25 |         { value, writer = m.writer <> writer },
26 | }
27 | 
28 | let tell w : w -> Writer w () = { value = (), writer = w }
29 | 
30 | { Writer, functor, applicative, monad, tell }
31 | 


--------------------------------------------------------------------------------
/tests/array.rs:
--------------------------------------------------------------------------------
  1 | extern crate env_logger;
  2 | 
  3 | extern crate gluon;
  4 | 
  5 | #[macro_use]
  6 | mod support;
  7 | 
  8 | test_expr! { array,
  9 | r#"
 10 | let array = import! std.array.prim
 11 | let arr = [1,2,3]
 12 | 
 13 | array.index arr 0 #Int== 1
 14 |     && array.len arr #Int== 3
 15 |     && array.len (array.append arr arr) #Int== array.len arr #Int* 2"#,
 16 | true
 17 | }
 18 | 
 19 | test_expr! { array_byte,
 20 | r#"
 21 | let array = import! std.array.prim
 22 | let arr = [1b,2b,3b]
 23 | 
 24 | let b = array.index arr 2 #Byte== 3b && array.len arr #Int== 3
 25 | let arr2 = array.append arr arr
 26 | b && array.len arr2 #Int== array.len arr #Int* 2
 27 |   && array.index arr2 1 #Byte== array.index arr2 4
 28 | "#,
 29 | true
 30 | }
 31 | 
 32 | test_expr! { array_float,
 33 | r#"
 34 | let array = import! std.array.prim
 35 | let arr = [1.0,2.0,3.0]
 36 | 
 37 | let b = array.index arr 2 #Float== 3.0 && array.len arr #Int== 3
 38 | let arr2 = array.append arr arr
 39 | b && array.len arr2 #Int== array.len arr #Int* 2
 40 |   && array.index arr2 1 #Float== array.index arr2 4
 41 | "#,
 42 | true
 43 | }
 44 | 
 45 | test_expr! { array_data,
 46 | r#"
 47 | let array = import! std.array.prim
 48 | let arr = [{x = 1, y = "a" }, { x = 2, y = "b" }]
 49 | 
 50 | let b = (array.index arr 1).x #Int== 2 && array.len arr #Int== 2
 51 | let arr2 = array.append arr arr
 52 | b && array.len arr2 #Int== array.len arr #Int* 2
 53 | "#,
 54 | true
 55 | }
 56 | 
 57 | test_expr! { array_array,
 58 | r#"
 59 | let array = import! std.array.prim
 60 | let arr = [[], [1], [2, 3]]
 61 | 
 62 | let b = array.len (array.index arr 1) #Int== 1 && array.len arr #Int== 3
 63 | let arr2 = array.append arr arr
 64 | b && array.len arr2 #Int== array.len arr #Int* 2
 65 | "#,
 66 | true
 67 | }
 68 | 
 69 | // Test that empty variants are handled correctly in arrays
 70 | test_expr! { array_empty_variant,
 71 | r#"
 72 | let array = import! std.array.prim
 73 | type Test = | Empty | Some Int
 74 | let arr = [Empty, Some 1]
 75 | match array.index arr 0 with
 76 | | Empty -> 0
 77 | | Some x -> x
 78 | "#,
 79 | 0i32
 80 | }
 81 | 
 82 | // Test that array append handles array types correctly
 83 | test_expr! { array_empty_append,
 84 | r#"
 85 | let array = import! std.array.prim
 86 | type Test = | Empty | Some Int
 87 | let arr = array.append [] [Empty, Some 1]
 88 | match array.index arr 0 with
 89 | | Empty -> 0
 90 | | Some x -> x
 91 | "#,
 92 | 0i32
 93 | }
 94 | 
 95 | test_expr! { array_load,
 96 | r#"
 97 | let array = import! std.array
 98 | 0
 99 | "#,
100 | 0i32
101 | }
102 | 
103 | test_expr! { array_fold,
104 | r#"
105 | let array = import! std.array
106 | array.foldable.foldl (\x y -> y.x) 0 [{ x = 4 }]
107 | "#,
108 | 4
109 | }
110 | 


--------------------------------------------------------------------------------
/tests/compile-fail/get-reference.rs:
--------------------------------------------------------------------------------
 1 | extern crate gluon;
 2 | use gluon::new_vm;
 3 | use gluon::vm::api::Getable;
 4 | use gluon::vm::internal::Value;
 5 | use gluon::vm::Variants;
 6 | 
 7 | #[cfg_attr(rustfmt, rustfmt_skip)]
 8 | fn main() {
 9 |     unsafe {
10 |         let vm = new_vm();
11 |         let value = Value::int(0);
12 |         let value = Variants::new(&value);
13 |         //~^ Error `value` does not live long enough
14 |         let _: &'static str = <&'static str>::from_value(&vm, value);
15 |     }
16 | }
17 | 


--------------------------------------------------------------------------------
/tests/compile-fail/getable-reference-str.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate gluon_vm;
 3 | extern crate gluon;
 4 | use gluon::{
 5 |     import::add_extern_module,
 6 |     new_vm,
 7 |     vm::{
 8 |         api::primitive_f,
 9 |         thread::{Status, Thread},
10 |         ExternModule,
11 |     },
12 | };
13 | 
14 | fn f(_: &'static str) {}
15 | 
16 | #[cfg_attr(rustfmt, rustfmt_skip)]
17 | fn main() {
18 |     let vm = new_vm();
19 |     add_extern_module(&vm, "test", |vm| {
20 |         ExternModule::new(vm, primitive!(1, f))
21 |         //~^ `thread` has lifetime `'thread` but it needs to satisfy a `'static` lifetime requirement
22 |     });
23 | }
24 | 


--------------------------------------------------------------------------------
/tests/compile-fail/getable-reference.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate gluon_vm;
 3 | extern crate gluon;
 4 | extern crate gluon_codegen;
 5 | 
 6 | use gluon::{
 7 |     import::add_extern_module,
 8 |     new_vm,
 9 |     vm::{
10 |         api::{primitive_f, Userdata, VmType},
11 |         gc::{Gc, Trace},
12 |         thread::{Status, Thread},
13 |         ExternModule,
14 |     },
15 | };
16 | 
17 | #[derive(Debug, gluon_codegen::Trace)]
18 | struct Test;
19 | 
20 | impl Userdata for Test {}
21 | 
22 | impl VmType for Test {
23 |     type Type = Test;
24 | }
25 | 
26 | fn f(_: &'static Test) {}
27 | 
28 | #[cfg_attr(rustfmt, rustfmt_skip)]
29 | fn main() {
30 |     let vm = new_vm();
31 |     add_extern_module(&vm, "test", |vm| {
32 |         ExternModule::new(vm, primitive!(1, f))
33 |         //~^ `thread` has lifetime `'thread` but it needs to satisfy a `'static` lifetime requirement
34 |     });
35 | }
36 | 


--------------------------------------------------------------------------------
/tests/compile-fail/run_expr_str_ref.rs:
--------------------------------------------------------------------------------
 1 | extern crate gluon;
 2 | 
 3 | use gluon::{new_vm, ThreadExt};
 4 | 
 5 | fn main() {
 6 |     let vm = new_vm();
 7 | 
 8 |     let _ = vm.run_expr::<&str>("", r#" "test" "#);
 9 |     //~^ the trait bound `for<'value> &str: Getable<'_, 'value>` is not satisfied [E0277]
10 | }
11 | 


--------------------------------------------------------------------------------
/tests/compile-fail/store-ref.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate gluon_vm;
 3 | extern crate gluon;
 4 | extern crate gluon_codegen;
 5 | 
 6 | use std::{fmt, sync::Mutex};
 7 | 
 8 | use gluon::{
 9 |     import::add_extern_module,
10 |     new_vm,
11 |     vm::{
12 |         api::{primitive_f, Userdata, VmType},
13 |         gc::Trace,
14 |         thread::{Status, Thread},
15 |         ExternModule,
16 |     },
17 | };
18 | 
19 | #[derive(gluon_codegen::Trace)]
20 | #[gluon_trace(skip)]
21 | struct Test<'vm>(Mutex<&'vm str>);
22 | 
23 | impl Userdata for Test<'static> {}
24 | 
25 | impl<'vm> fmt::Debug for Test<'vm> {
26 |     fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
27 |         Ok(())
28 |     }
29 | }
30 | 
31 | impl<'vm> VmType for Test<'vm> {
32 |     type Type = Test<'static>;
33 | }
34 | 
35 | fn f<'vm>(test: &'vm Test<'vm>, s: &'vm str) {
36 |     *test.0.lock().unwrap() = s;
37 | }
38 | 
39 | #[cfg_attr(rustfmt, rustfmt_skip)]
40 | fn main() {
41 |     let vm = new_vm();
42 |     add_extern_module(&vm, "test", |vm| {
43 |         ExternModule::new(vm, primitive!(2, f))
44 |         //~^ `thread` has lifetime `'thread` but it needs to satisfy a `'static` lifetime requirement
45 |     });
46 | }
47 | 


--------------------------------------------------------------------------------
/tests/compiletest.rs:
--------------------------------------------------------------------------------
 1 | #![cfg(feature = "nightly")]
 2 | extern crate compiletest_rs as compiletest;
 3 | extern crate env_logger;
 4 | 
 5 | use std::fs;
 6 | use std::path::{Path, PathBuf};
 7 | 
 8 | fn lib_dir(out_dir: &Path, lib_name: &str) -> PathBuf {
 9 |     // Just loading gluon through -L dir does not work as we compile gluon with different sets of
10 |     // flags which gives ambiguity errors.
11 |     // Instead retrieve the latest compiled gluon library which should usually be the correct one
12 |     let mut gluon_rlibs: Vec<_> = fs::read_dir(out_dir.join("deps"))
13 |         .unwrap()
14 |         .filter_map(|entry| {
15 |             let entry = entry.expect("dir entry");
16 |             if entry
17 |                 .path()
18 |                 .to_str()
19 |                 .map_or(false, |name| name.contains(lib_name))
20 |             {
21 |                 Some(entry)
22 |             } else {
23 |                 None
24 |             }
25 |         })
26 |         .collect();
27 |     gluon_rlibs.sort_by(|l, r| {
28 |         l.metadata()
29 |             .unwrap()
30 |             .modified()
31 |             .unwrap()
32 |             .cmp(&r.metadata().unwrap().modified().unwrap())
33 |     });
34 |     gluon_rlibs.last().expect("libgluon not found").path()
35 | }
36 | 
37 | fn run_mode(mode: &'static str) {
38 |     // Retrieve the path where library dependencies are output
39 |     let mut out_dir = PathBuf::from(env!("OUT_DIR"));
40 |     loop {
41 |         match out_dir.file_name() {
42 |             Some(name) => match name.to_str() {
43 |                 Some(name) if name == "debug" => break,
44 |                 _ => (),
45 |             },
46 |             None => break,
47 |         }
48 |         out_dir.pop();
49 |     }
50 |     let gluon_rlib = lib_dir(&out_dir, "libgluon-");
51 |     let gluon_vm_rlib = lib_dir(&out_dir, "libgluon_vm-");
52 | 
53 |     let mut config = compiletest::Config::default();
54 |     let cfg_mode = mode.parse().ok().expect("Invalid mode");
55 | 
56 |     config.verbose = true;
57 |     config.mode = cfg_mode;
58 |     config.src_base = PathBuf::from(format!("tests/{}", mode));
59 |     config.target_rustcflags = Some(format!(
60 |         "-L {}/deps --extern gluon={} --extern gluon_vm={}",
61 |         out_dir.display(),
62 |         gluon_rlib.display(),
63 |         gluon_vm_rlib.display()
64 |     ));
65 |     println!("{}", config.target_rustcflags.as_ref().unwrap());
66 |     compiletest::run_tests(&config);
67 | }
68 | 
69 | #[test]
70 | #[should_panic]
71 | fn compile_test() {
72 |     let _ = env_logger::try_init();
73 |     run_mode("compile-fail");
74 | }
75 | 


--------------------------------------------------------------------------------
/tests/fail.rs:
--------------------------------------------------------------------------------
1 | 

2 | 


--------------------------------------------------------------------------------
/tests/fail/cyclic_dependency.glu:
--------------------------------------------------------------------------------
1 | // ERROR Module 'tests.fail.cyclic_dependency' occurs in a cyclic dependency: `tests.fail.cyclic_dependency -> tests.fail.deps.cyclic_dependency2 -> tests.fail.cyclic_dependency`
2 | let c  = import! "tests/fail/deps/cyclic_dependency2.glu"
3 | in 1
4 | 


--------------------------------------------------------------------------------
/tests/fail/deps/cyclic_dependency2.glu:
--------------------------------------------------------------------------------
1 | let c  = import! "tests/fail/cyclic_dependency.glu"
2 | in 1
3 | 


--------------------------------------------------------------------------------
/tests/fail/unwrap.glu:
--------------------------------------------------------------------------------
1 | // ERROR Option was None
2 | let { Option, unwrap }  = import! std.option
3 | 
4 | unwrap None
5 | 


--------------------------------------------------------------------------------
/tests/limits.rs:
--------------------------------------------------------------------------------
 1 | mod support;
 2 | 
 3 | use gluon::{
 4 |     vm::{
 5 |         api::{Hole, OpaqueValue},
 6 |         thread::ThreadInternal,
 7 |         Error as VMError,
 8 |     },
 9 |     Error, Thread, ThreadExt,
10 | };
11 | 
12 | use crate::support::make_vm;
13 | 
14 | #[test]
15 | fn out_of_memory() {
16 |     let _ = ::env_logger::try_init();
17 | 
18 |     let vm = make_vm();
19 |     vm.set_memory_limit(10);
20 |     vm.get_database_mut().implicit_prelude(false);
21 | 
22 |     let expr = " [1, 2, 3, 4] ";
23 |     let result = vm.run_expr::<OpaqueValue<&Thread, Hole>>("example", expr);
24 | 
25 |     match result {
26 |         // FIXME This should just need to match on the explicit out of memory error
27 |         Err(Error::VM(VMError::OutOfMemory { limit: 10, .. })) => (),
28 |         Err(err) => panic!("Unexpected error `{:?}`", err),
29 |         Ok(_) => panic!("Expected an error"),
30 |     }
31 | }
32 | 
33 | #[test]
34 | fn stack_overflow() {
35 |     let _ = ::env_logger::try_init();
36 | 
37 |     let vm = make_vm();
38 |     vm.context().set_max_stack_size(3);
39 |     vm.get_database_mut().implicit_prelude(false);
40 | 
41 |     let expr = " [1, 2, 3, 4] ";
42 |     let result = vm.run_expr::<OpaqueValue<&Thread, Hole>>("example", expr);
43 | 
44 |     match result {
45 |         Err(Error::VM(VMError::StackOverflow(3))) => (),
46 |         Err(err) => panic!("Unexpected error `{:?}`", err),
47 |         Ok(_) => panic!("Expected an error"),
48 |     }
49 | }
50 | 


--------------------------------------------------------------------------------
/tests/metadata.rs:
--------------------------------------------------------------------------------
 1 | use gluon::{import::Import, vm::thread::RootedThread, ThreadExt};
 2 | 
 3 | fn make_vm() -> RootedThread {
 4 |     let vm = ::gluon::new_vm();
 5 |     let import = vm.get_macros().get("import");
 6 |     import
 7 |         .as_ref()
 8 |         .and_then(|import| import.downcast_ref::<Import>())
 9 |         .expect("Import macro")
10 |         .add_path("..");
11 |     vm
12 | }
13 | 
14 | #[test]
15 | fn metadata_from_other_module() {
16 |     let _ = ::env_logger::try_init();
17 |     let vm = make_vm();
18 |     let text = r#"
19 | let { List, of }  = import! std.list
20 | { List, of }
21 | "#;
22 |     vm.load_script("test", text)
23 |         .unwrap_or_else(|err| panic!("{}", err));
24 | 
25 |     let env = vm.get_env();
26 |     assert!(env.get_metadata("test.of").is_ok());
27 |     assert!(env.get_metadata("test.List").is_ok());
28 | }
29 | 


--------------------------------------------------------------------------------
/tests/optimize/cmp.glu:
--------------------------------------------------------------------------------
 1 | let { Option, Ordering, Bool } = import! std.types
 2 | 
 3 | #[infix(left, 4)]
 4 | let (=?) opt y : Option b -> b -> b =
 5 |     match opt with
 6 |     | Some x -> x
 7 |     | None -> y
 8 | 
 9 | let mk_ord builder =
10 |     #[infix(left, 4)]
11 |     let (<) l r = True
12 | 
13 |     {
14 |         (<) = builder.(<) =? (<),
15 |     }
16 | 
17 | { Option, mk_ord }
18 | 


--------------------------------------------------------------------------------
/tests/optimize/inline_num.glu:
--------------------------------------------------------------------------------
 1 | let additive =
 2 |     let semigroup = {
 3 |         append = \x y -> x #Int+ y
 4 |     }
 5 | 
 6 |     { semigroup }
 7 | 
 8 | 
 9 | {
10 |     (+) = additive.semigroup.append,
11 |     additive,
12 | }
13 | 


--------------------------------------------------------------------------------
/tests/optimize/inline_through_module.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | //! Definitions which gets implicit re-export in every file.
 3 | 
 4 | let { Num, (+), (-), (*), (/)  } = import! tests.optimize.inline_through_module2
 5 | 
 6 | {
 7 |     Num,
 8 |     (+), (-), (*), (/),
 9 | }
10 | 


--------------------------------------------------------------------------------
/tests/optimize/inline_through_module2.glu:
--------------------------------------------------------------------------------
 1 | //@NO-IMPLICIT-PRELUDE
 2 | 
 3 | #[implicit]
 4 | type Num a = {
 5 |     /// The addition operator
 6 |     (+) : a -> a -> a,
 7 |     /// The subtraction operator
 8 |     (-) : a -> a -> a,
 9 |     /// The multiplication operator
10 |     (*) : a -> a -> a,
11 |     /// The division operator
12 |     (/) : a -> a -> a,
13 | }
14 | 
15 | let num : Num Int = {
16 |     (+) = \l r -> l #Int+ r,
17 |     (-) = \l r -> l #Int- r,
18 |     (*) = \l r -> l #Int* r,
19 |     (/) = \l r -> l #Int/ r,
20 | }
21 | 
22 | 
23 | #[infix(left, 6)]
24 | let (+) ?num : [Num a] -> a -> a -> a = num.(+)
25 | #[infix(left, 6)]
26 | let (-) ?num : [Num a] -> a -> a -> a = num.(-)
27 | #[infix(left, 7)]
28 | let (*) ?num : [Num a] -> a -> a -> a = num.(*)
29 | #[infix(left, 7)]
30 | let (/) ?num : [Num a] -> a -> a -> a = num.(/)
31 | 
32 | {
33 |     Num,
34 | 
35 |     (+), (-), (*), (/),
36 | 
37 |     num,
38 | }
39 | 
40 | 


--------------------------------------------------------------------------------
/tests/parallel.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate gluon_vm;
 3 | 
 4 | use std::thread::spawn;
 5 | 
 6 | use gluon::{
 7 |     new_vm,
 8 |     vm::{
 9 |         api::{FunctionRef, OpaqueValue, IO},
10 |         channel::{ChannelRecord, Receiver, Sender},
11 |     },
12 |     Error, RootedThread, ThreadExt,
13 | };
14 | 
15 | #[test]
16 | fn parallel() {
17 |     let _ = env_logger::try_init();
18 | 
19 |     if let Err(err) = parallel_() {
20 |         assert!(false, "{}", err);
21 |     }
22 | }
23 | 
24 | fn parallel_() -> Result<(), Error> {
25 |     let vm = new_vm();
26 | 
27 |     vm.get_database_mut().run_io(true);
28 | 
29 |     vm.run_expr::<()>("<top>", " let _ = import! std.channel in () ")?;
30 | 
31 |     let (value, _) = vm.run_expr::<IO<_>>(
32 |         "<top>",
33 |         " let { channel } = import! std.channel in channel 0 ",
34 |     )?;
35 |     let record_p! { sender, receiver }: ChannelRecord<
36 |         OpaqueValue<RootedThread, Sender<i32>>,
37 |         OpaqueValue<RootedThread, Receiver<i32>>,
38 |     > = Result::from(value)?;
39 | 
40 |     let child = vm.new_thread()?;
41 |     let handle1 = spawn(move || -> Result<(), Error> {
42 |         let expr = r#"
43 |         let { ? } = import! std.io
44 |         let { wrap } = import! std.applicative
45 |         let { send } = import! std.channel
46 |         let f sender =
47 |             send sender 1
48 |             send sender 2
49 |             wrap ()
50 |         f
51 |         "#;
52 |         let mut f: FunctionRef<fn(OpaqueValue<RootedThread, Sender<i32>>) -> IO<()>> =
53 |             child.run_expr("<top>", expr)?.0;
54 |         Ok(f.call(sender)
55 |             .and_then(|io| Result::from(io).map_err(From::from))?)
56 |     });
57 | 
58 |     let child2 = vm.new_thread()?;
59 |     let handle2 = spawn(move || -> Result<(), Error> {
60 |         let expr = r#"
61 |         let { assert }  = import! std.test
62 |         let { wrap }  = import! std.applicative
63 |         let { ? } = import! std.io
64 |         let { Bool } = import! std.bool
65 |         let { Result }  = import! std.result
66 |         let { recv } = import! std.channel
67 | 
68 |         let f receiver =
69 |             do x = recv receiver
70 |             match x with
71 |             | Ok x -> wrap <| assert (x == 1)
72 |             | Err _ -> error "Fail 1"
73 | 
74 |             do x = recv receiver
75 |             match x with
76 |             | Ok x -> wrap <| assert (x == 2)
77 |             | Err _ -> error "Fail 2"
78 | 
79 |         f
80 |         "#;
81 |         let mut f: FunctionRef<fn(OpaqueValue<RootedThread, Receiver<i32>>) -> IO<()>> =
82 |             child2.run_expr("<top>", expr)?.0;
83 |         Ok(f.call(receiver)
84 |             .and_then(|io| Result::from(io).map_err(From::from))?)
85 |     });
86 | 
87 |     // Ensure that both threads stop without any panics (just dropping ignores panics)
88 |     handle1.join().unwrap()?;
89 |     handle2.join().unwrap()
90 | }
91 | 


--------------------------------------------------------------------------------
/tests/pass/alternative.glu:
--------------------------------------------------------------------------------
 1 | let { run, Test, TestCase, assert_eq, test, group, ? } = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let prelude @ { Alternative } = import! std.prelude
 4 | let { Applicative, (*>) } = import! std.applicative
 5 | let int = import! std.int
 6 | let list @ { ? }= import! std.list
 7 | let option = import! std.option
 8 | let { (<|>), or, empty } = import! std.alternative
 9 | 
10 | let test_alt ?alt show eq : [Alternative f] -> Show (f Int) -> Eq (f Int) -> _ =
11 |     let { wrap } = alt.applicative
12 | 
13 |     let assert = assert_eq ?show ?eq
14 | 
15 |     [
16 |         test "empty equal" <| \_ -> (assert empty empty),
17 |         test "or selects non-empty" <| \_ -> (assert (empty <|> wrap 1) (wrap 1)),
18 |         test "empty <|> empty == empty" <| \_ -> (assert (empty <|> empty) empty),
19 |         test "or selects non-empty 2" <| \_ -> (assert (empty <|> empty <|> wrap 10) (wrap 10))
20 |     ]
21 | 
22 | let tests: TestCase r () =
23 |     group "alternative" [
24 |         group "option" (test_alt option.show option.eq),
25 |         group "list" (test_alt list.show list.eq)
26 |     ]
27 | 
28 | tests
29 | 
30 | 


--------------------------------------------------------------------------------
/tests/pass/arithmetic.glu:
--------------------------------------------------------------------------------
 1 | let { run, Test, assert_eq, test, group, ? }  = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let prelude  = import! std.prelude
 4 | let { Applicative, (*>), ? } = import! std.applicative
 5 | let int = import! std.int
 6 | let float = import! std.float
 7 | let byte @ { ? } = import! std.byte
 8 | let { empty } = import! std.monoid
 9 | 
10 | let { ? } = import! std.effect
11 | 
12 | let byte_tests =
13 |     group "byte" [
14 |         test "arithmetic" <| \_ ->
15 |             assert_eq 2b 2b
16 |                 *> assert_eq 12b (10b + 2b)
17 |                 *> assert_eq 123b (50b * 2b + 9b * 3b - 4b),
18 |         test "from_int" <| \_ -> assert_eq (byte.from_int 2) 2b,
19 |         test "from_int_truncate" <| \_ -> assert_eq (byte.from_int 2000) 208b,
20 |     ]
21 | 
22 | let int_tests =
23 |     group "int" [
24 |         test "arithmetic" <| \_ ->
25 |             assert_eq 2 2
26 |                 *> assert_eq 12 (10 + 2)
27 |                 *> assert_eq 123 (50 * 2 + 9 * 3 - 4),
28 |         test "from_float" <| \_ -> assert_eq (int.from_float 2.0) 2,
29 |         test "from_float_truncate" <| \_ -> assert_eq (int.from_float 2.7) 2,
30 |         test "from_byte" <| \_ -> assert_eq (int.from_byte 2b) 2,
31 |         group "monoid" [
32 |             test "additive" <| \_ ->
33 |                 let { ? } = int.additive
34 |                 assert_eq 0 empty,
35 |             test "multiplicative" <| \_ ->
36 |                 let { ? } = int.multiplicative
37 |                 assert_eq 1 empty,
38 |         ]
39 |     ]
40 | 
41 | let float_tests =
42 |     group "float" [
43 |         test "float" <| \_ -> assert_eq 91.0 (50.0 * 2.0 - 3.0 * 3.0),
44 |         test "from_int" <| \_ -> assert_eq (float.from_int 2) 2.0,
45 |     ]
46 | 
47 | group "arithmetic" [byte_tests, int_tests, float_tests]
48 | 


--------------------------------------------------------------------------------
/tests/pass/channel.glu:
--------------------------------------------------------------------------------
 1 | let { TestEff, run, assert_eq, test, group, ? }  = import! std.test
 2 | let { lift } = import! std.effect.lift
 3 | let { (<|) } = import! std.function
 4 | let prelude  = import! std.prelude
 5 | let { Applicative, (*>), ? } = import! std.applicative
 6 | let int = import! std.int
 7 | let result @ { Result, ? } = import! std.result
 8 | let unit @ { ? } = import! std.unit
 9 | let { send, recv, channel } = import! std.channel
10 | 
11 | 
12 | let { ? } = import! std.effect
13 | 
14 | let assert_recv channel expect : [Eq a] -> [Show a] -> _ -> Result () a -> _ =
15 |     do x = lift <| recv channel
16 |     assert_eq x expect
17 | 
18 | test "channel" <| \_ ->
19 |     do { sender, receiver } = lift <| channel 0
20 |     seq lift <| send sender 0
21 |     seq lift <| send sender 1
22 |     seq lift <| send sender 2
23 |     seq assert_recv receiver (Ok 0)
24 |     seq assert_recv receiver (Ok 1)
25 |     assert_recv receiver (Ok 2)
26 | 


--------------------------------------------------------------------------------
/tests/pass/char.glu:
--------------------------------------------------------------------------------
 1 | let { run, Test, assert_eq, test, group, ? }  = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let prelude  = import! std.prelude
 4 | let { Applicative, (*>), ? } = import! std.applicative
 5 | let char @ { ? } = import! std.char
 6 | 
 7 | group "char" [
 8 |     test "from_int" <| \_ -> assert_eq (char.from_int 97) (Some 'a'),
 9 |     test "from_int_error" <| \_ -> assert_eq (char.from_int 0x110000) None,
10 |     test "to_int" <| \_ -> assert_eq (char.to_int 'a') 97,
11 | ]
12 | 


--------------------------------------------------------------------------------
/tests/pass/deep_clone_userdata.glu:
--------------------------------------------------------------------------------
 1 | let { run, assert, assert_eq, group, test, ? } = import! std.test
 2 | let { lift } = import! std.effect.lift
 3 | let { ? } = import! std.effect
 4 | let { (<|) } = import! std.function
 5 | let prelude = import! std.prelude
 6 | let { wrap, (*>) } = import! std.applicative
 7 | let { Result } = import! std.result
 8 | let { ref, load } = import! std.reference
 9 | let { lazy, force } = import! std.lazy
10 | let { channel, send, recv } = import! std.channel
11 | let { resume, spawn } = import! std.thread
12 | let { ? } = import! std.io
13 | 
14 | // Dummy test
15 | group "deep_clone_userdata" [
16 |     test "1" <| \_ ->
17 |         do { sender, receiver } = lift <| channel (lazy (\_ -> 0))
18 | 
19 |         do thread = lift <| spawn (
20 |                 seq send sender (lazy (\_ -> 1))
21 |                 let l = lazy (\_ -> 2)
22 |                 let _ = force l
23 |                 send sender l
24 |                 wrap ())
25 | 
26 |         lift <| resume thread
27 |         do x = lift <| recv receiver
28 |         match x with
29 |         | Ok x -> assert_eq (force x) 1
30 |         | Err e -> error "Receive 1 error"
31 |         do x = lift <| recv receiver
32 |         match x with
33 |         | Ok x -> assert_eq (force x) 2
34 |         | Err e -> error "Receive 2 error",
35 | 
36 |     test "2" <| \_ ->
37 |         do r = lift <| ref 0
38 |         do { sender, receiver } = lift <| channel r
39 | 
40 |         do thread = lift <| spawn (
41 |                 do r = ref 3
42 |                 send sender r
43 |                 wrap ())
44 | 
45 |         do r = lift <| resume thread
46 |         match r with
47 |         | Ok () -> wrap ()
48 |         | Err e -> error e
49 |         do r = lift <| recv receiver
50 |         match r with
51 |         | Ok x ->
52 |             do x = lift <| load x
53 |             assert_eq x 3
54 |         | Err e -> error "Receive 3 error"
55 | ]
56 | 


--------------------------------------------------------------------------------
/tests/pass/io.glu:
--------------------------------------------------------------------------------
 1 | let { TestEff, assert_eq, test, group, ? }  = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let { Applicative, (*>), ? } = import! std.applicative
 4 | let result = import! std.result
 5 | let string = import! std.string
 6 | let io = import! std.io
 7 | 
 8 | let { ? } = import! std.effect
 9 | let { lift } = import! std.effect.lift
10 | 
11 | group "io" [
12 |     test "read_file" <| \_ ->
13 |         let path = "tests/pass/io.glu"
14 |         do contents1 = lift <| io.read_file_to_string path
15 |         do contents2 = lift <| io.read_file_to_array path
16 |         assert_eq contents1 (result.unwrap_ok <| string.from_utf8 contents2)
17 | ]
18 | 


--------------------------------------------------------------------------------
/tests/pass/json/ser.glu:
--------------------------------------------------------------------------------
 1 | let { Serialize } = import! std.json.ser
 2 | 
 3 | #[derive(Show, Eq, Serialize)]
 4 | type Record = { x : Int }
 5 | 
 6 | #[derive(Show, Eq, Serialize)]
 7 | type Record2 = { x : Int, y : String }
 8 | 
 9 | #[derive(Show, Eq, Serialize)]
10 | type Variant = | MyInt Int | MyString String
11 | 
12 | #[derive(Show, Eq, Serialize)]
13 | type MyOption a = | MyNone | MySome a
14 | 
15 | let result @ { Result, ? } = import! std.result
16 | let ser @ { ValueSerializer, Serialize, ? } = import! std.json.ser
17 | let { Test, run, assert, assert_eq, test, group, ? }  = import! std.test
18 | let { Applicative, (*>) } = import! std.applicative
19 | let { map } = import! std.functor
20 | let { (<|) } = import! std.function
21 | let int = import! std.int
22 | let list @ { List, ? } = import! std.list
23 | let { ? } = import! std.array
24 | let { (<>) } = import! std.semigroup
25 | 
26 | group "json.ser" [
27 |     test "derive_record_1_field" <| \_ ->
28 |         assert_eq (ser.to_string { x = 1 }) (Ok r#"{"x":1}"#),
29 | 
30 |     test "derive_record_2_fields" <| \_ ->
31 |         assert_eq (ser.to_string { x = 1, y = "abc" }) (Ok r#"{"x":1,"y":"abc"}"#),
32 | 
33 |     test "variant_int" <| \_ ->
34 |         assert_eq (ser.to_string (MyInt 123)) (Ok r#"123"#),
35 | 
36 |     test "variant_string" <| \_ ->
37 |         assert_eq (ser.to_string (MyString "abc")) (Ok r#""abc""#),
38 | 
39 |     test "option_some" <| \_ ->
40 |         assert_eq (ser.to_string (MySome "abc")) (Ok r#""abc""#),
41 | 
42 |     test "option_none" <| \_ ->
43 |         let x: MyOption String = MyNone
44 |         assert_eq (ser.to_string x) (Ok r#"null"#),
45 | ]
46 | 
47 | 


--------------------------------------------------------------------------------
/tests/pass/lazy.glu:
--------------------------------------------------------------------------------
 1 | let { run, TestEff, assert_eq, test, ? } = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let prelude = import! std.prelude
 4 | let { Applicative, (*>), wrap } = import! std.applicative
 5 | let { lazy, force } = import! std.lazy
 6 | 
 7 | let { ? } = import! std.effect
 8 | 
 9 | let l = lazy (\_ -> 123 + 57)
10 | 
11 | let tests : TestEff r () =
12 |     assert_eq (force (lazy (\_ -> 2))) 2 *> wrap ()
13 |         *> assert_eq 180 (force l)
14 | 
15 | test "lazy" <| \_ -> tests
16 | 


--------------------------------------------------------------------------------
/tests/pass/lazyt.glu:
--------------------------------------------------------------------------------
 1 | let { (<|) } = import! std.function
 2 | let { Test, run, assert, assert_eq, test, group, ? } = import! std.test
 3 | let { LazyT, force_t, ? } = import! std.lazyt
 4 | let { Functor, map } = import! std.functor
 5 | let { Applicative, wrap, (*>) } = import! std.applicative
 6 | let { Monad, (>>=) } = import! std.monad
 7 | let { Transformer, wrap_monad } = import! std.transformer
 8 | let { Option, unwrap, ? } = import! std.option
 9 | let { (++), ? } = import! std.string
10 | let list @ { List, ? } = import! std.list
11 | 
12 | 
13 | let left_identity x f : [Eq a] -> [Show a] -> a -> (a -> LazyT Option a) -> _ = \_ ->
14 |     let mx : LazyT Option _ = wrap x
15 |     assert_eq (force_t (mx >>= f)) (force_t (f x))
16 | 
17 | let right_identity x : [Eq a] -> [Show a] -> a -> _ = \_ ->
18 |     let mx : LazyT Option _ = wrap x
19 |     assert_eq (force_t (mx >>= wrap)) (force_t mx)
20 | 
21 | let associativity mx f g : [Monad m] -> [Show (m a)] -> [Eq (m a)] -> m a -> _ -> _ -> _ = \_ ->
22 |     let mx : LazyT m _ = wrap_monad mx
23 |     assert_eq (force_t ((mx >>= f) >>= g)) (force_t (mx >>= (\x -> f x >>= g)))
24 | 
25 | group "lazyt" [
26 |     group "LazyT m is monadic" [
27 |         test "left identity" <| left_identity 324 (\x -> wrap <| x + 89),
28 |         test "right identity" <| right_identity "hello",
29 |         test "associativity" <| associativity (Some 5) (\x -> wrap (x+5)) (\x -> wrap (x*2)),
30 |     ],
31 |     let x = list.of [8,6,7,5,3,0,9]
32 |     let f = (*) 42
33 |     test "LazyT m is lazy" <| \_ -> assert_eq (map f x) (force_t <| map f <| wrap_monad x),
34 | ]
35 | 


--------------------------------------------------------------------------------
/tests/pass/list.glu:
--------------------------------------------------------------------------------
 1 | let { TestEff, assert_eq, test, ? }  = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let { Applicative, (*>), ? } = import! std.applicative
 4 | let list @ { List, ? } = import! std.list
 5 | 
 6 | let { ? } = import! std.effect
 7 | 
 8 | let empty_list : List Int =
 9 |     Nil
10 | 
11 | let test_list : TestEff r () =
12 |     assert_eq (list.of []) empty_list *>
13 |         assert_eq (list.of [10, 20, 30]) (Cons 10 (Cons 20 (Cons 30 Nil)))
14 | 
15 | test "list" <| \_ -> test_list
16 | 


--------------------------------------------------------------------------------
/tests/pass/map.glu:
--------------------------------------------------------------------------------
 1 | let prelude @ { Eq, Show } = import! std.prelude
 2 | let { (<|) } = import! std.function
 3 | let int = import! std.int
 4 | let option @ { Option } = import! std.option
 5 | let string = import! std.string
 6 | let { (<>) } = import! std.prelude
 7 | let { Test, run, assert, assert_eq, test, group, ? }  = import! std.test
 8 | let map @ { empty, singleton, find, insert, to_list, keys, values, ? } = import! std.map
 9 | let { Applicative, (*>) } = import! std.applicative
10 | let list @ { List, ? } = import! std.list
11 | 
12 | let { ? } = import! std.effect
13 | 
14 | let show_Entry : Show { key : String, value : Int } = {
15 |     show = \e -> e.key <> int.show.show e.value
16 | }
17 | 
18 | let eq_Entry : Eq { key : String, value : Int } = {
19 |     (==) = \l r -> l.key == r.key && l.value == r.value
20 | }
21 | 
22 | let basic_tests =
23 |     let test_map = singleton "test" 1 <> singleton "asd" 2 <> singleton "a" 3
24 | 
25 |     [
26 |         test "find" <| \_ -> (assert_eq (find "test" test_map) (Some 1)
27 |             *> assert_eq (find "asd" test_map) (Some 2)
28 |             *> assert_eq (find "b" test_map) None
29 |             *> assert_eq (find "test" (insert "test" 10 test_map)) (Some 10)
30 |             *> assert_eq (find "test" test_map) (Some 1)
31 |         ),
32 |         test "to_list" <| \_ -> (assert_eq (to_list test_map) (list.of [{ key = "a", value = 3 },
33 |                                                        { key = "asd", value = 2 },
34 |                                                        { key = "test", value = 1 }])),
35 |         test "keys" <| \_ -> (assert_eq (keys test_map) (list.of ["a", "asd", "test"])),
36 |         test "values" <| \_ -> (assert_eq (values test_map) (list.of [3, 2, 1])),
37 |         test "append" <| \_ -> (assert_eq (to_list (test_map <> empty)) (to_list test_map)),
38 |         test "append" <| \_ -> (assert_eq (to_list (empty <> test_map)) (to_list test_map)),
39 |     ]
40 | 
41 | let append_tests =
42 |     let test_map1 = singleton "a" 1 <> singleton "b" 2 <> singleton "c" 3
43 |     let test_map2 = singleton "+" 1 <> (singleton "-" 2 <> singleton "*" 3)
44 |     assert_eq (find "b" test_map1) (Some 2)
45 |         *> assert_eq (find "*" test_map2) (Some 3)
46 | 
47 | group "map" [group "basic" basic_tests, test "append" <| \_ -> append_tests]
48 | 
49 | 


--------------------------------------------------------------------------------
/tests/pass/match_literal.glu:
--------------------------------------------------------------------------------
 1 | let prelude = import! std.prelude
 2 | let { (<|) } = import! std.function
 3 | let { run, Test, assert_eq, test, group, ? } = import! std.test
 4 | let { (*>), ? } = import! std.applicative
 5 | 
 6 | let { ? } = import! std.effect
 7 | 
 8 | let ints input =
 9 |     match input with
10 |     | 0 -> 1
11 |     | 1 -> 2
12 |     | _ -> 3
13 | 
14 | let strings input =
15 |     match input with
16 |     | "A" -> 4
17 |     | "B" -> 5
18 |     | _ -> 6
19 | 
20 | type N = | A Int | B
21 | 
22 | let ns input =
23 |     match input with
24 |     | A 1 -> 7
25 |     | A 2 -> 8
26 |     | B -> 9
27 |     | _ -> 10
28 | 
29 | type R1 = { x: Int }
30 | 
31 | let r1 input =
32 |     match input with
33 |     | { x = 2 } -> 11
34 |     | { x = 3 } -> 12
35 |     | _ -> 13
36 | 
37 | type R2 = { x: Int, y: Int }
38 | 
39 | let r2 input =
40 |     match input with
41 |     | { x = 2, y = 3 } -> 14
42 |     | { x = 3, y = 4 } -> 15
43 |     | _ -> 16
44 | 
45 | type TestM = | TestM Int String
46 | 
47 | let test_m input =
48 |     match input with
49 |     | TestM 1 "hello" -> 20
50 |     | TestM _ "world" -> 21
51 |     | TestM 2 _ -> 22
52 |     | _ -> 23
53 | 
54 | let match_ns =
55 |     assert_eq (ns (A 1)) 7
56 |         *> assert_eq (ns (A 2)) 8
57 |         *> assert_eq (ns B) 9
58 |         *> assert_eq (ns (A 3)) 10
59 | 
60 | let match_ints =
61 |     assert_eq (ints 0) 1
62 |         *> assert_eq (ints 1) 2
63 |         *> assert_eq (ints 2) 3
64 |         *> assert_eq (ints 3) 3
65 | 
66 | let match_strings =
67 |     assert_eq (strings "A") 4
68 |         *> assert_eq (strings "B") 5
69 |         *> assert_eq (strings "") 6
70 | 
71 | let match_r1 =
72 |     assert_eq (r1 { x = 2 }) 11
73 |         *> assert_eq (r1 { x = 3 }) 12
74 |         *> assert_eq (r1 { x = 4 }) 13
75 | 
76 | let match_r2 =
77 |     assert_eq (r2 { x = 2, y = 3 }) 14
78 |         *> assert_eq (r2 { x = 3, y = 4 }) 15
79 |         *> assert_eq (r2 { x = 4, y = 4 }) 16
80 | 
81 | let match_test_m =
82 |     assert_eq (test_m (TestM 1 "hello")) 20
83 |         *> assert_eq (test_m (TestM 2 "world")) 21
84 |         *> assert_eq (test_m (TestM 2 "hello")) 22
85 |         *> assert_eq (test_m (TestM 3 "")) 23
86 | 
87 | group "match_literal" [test "match_ints" <| \_ -> match_ints, test "match_strings" <| \_ -> match_strings, test "match_ns" <| \_ -> match_ns, test "match_r1" <| \_ -> match_r1, test "match_r2" <| \_ -> match_r2, test "match_test_m" <| \_ -> match_test_m]
88 | 


--------------------------------------------------------------------------------
/tests/pass/parser.glu:
--------------------------------------------------------------------------------
 1 | let prelude = import! std.prelude
 2 | let { (<|) } = import! std.function
 3 | let result @ { Result, ? } = import! std.result
 4 | let { Test, run, assert_eq, test, group } = import! std.test
 5 | let { ? } = import! std.char
 6 | let { Parser, applicative, functor, alternative, monad, any, parse } = import! std.parser
 7 | let { Applicative, (*>), ? } = import! std.applicative
 8 | let { (<|>) } = import! std.alternative
 9 | 
10 | group "parser" [
11 |     test "any" <| \_ -> (assert_eq (parse any "abc") (Ok 'a'))
12 | ]
13 | 


--------------------------------------------------------------------------------
/tests/pass/path.glu:
--------------------------------------------------------------------------------
 1 | let { (<|) } = import! std.function
 2 | let { Test, run, assert, assert_eq, test, group, ? }  = import! std.test
 3 | let { ? } = import! std.array
 4 | 
 5 | let path @ { Component, ? } = import! std.path
 6 | 
 7 | group "path" [
 8 |     test "components" <| \_ -> assert_eq (path.components "../abc/.") [ParentDir, Normal "abc"],
 9 | ]
10 | 
11 | 


--------------------------------------------------------------------------------
/tests/pass/reference.glu:
--------------------------------------------------------------------------------
 1 | let { assert_eq, group, test } = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let { ? } = import! std.io
 4 | let int = import! std.int
 5 | let { Bool } = import! std.bool
 6 | let { Reference, ref, (<-), load } = import! std.effect.reference
 7 | let { ? } = import! std.effect
 8 | let { lift } = import! std.effect.lift
 9 | 
10 | let assert_eq_ref l r : [Show a] -> [Eq a] -> a -> Reference a -> _ =
11 |     do r = load r
12 |     assert_eq l r
13 | 
14 | // Dummy test
15 | group "reference" [
16 |     test "basic" <| \_ ->
17 |         do ri = ref 0
18 |         assert_eq_ref 0 ri
19 |         ri <- 2
20 |         assert_eq_ref 2 ri
21 |         assert_eq_ref 2 ri
22 |         ri <- 10
23 |         assert_eq_ref 10 ri
24 | ]
25 | 


--------------------------------------------------------------------------------
/tests/pass/regex.glu:
--------------------------------------------------------------------------------
 1 | let { run, Test, assert_eq, test, group, ? }  = import! std.test
 2 | let { Applicative, (*>) } = import! std.applicative
 3 | let { (<|), (|>) } = import! std.function
 4 | 
 5 | let { ? } = import! std.array
 6 | let { unwrap_ok, unwrap_err } = import! std.result
 7 | 
 8 | let regex @ { ? } = import! std.regex
 9 | 
10 | let match_a = regex.new "a" |> unwrap_ok
11 | group "regex" [
12 |     test "is_match_a" <| \_ ->
13 |         assert_eq (regex.is_match match_a "a") True,
14 |     test "is_not_match_a" <| \_ ->
15 |         assert_eq (regex.is_match match_a "b") False,
16 | 
17 |     test "is_match2" <| \_ ->
18 |         let match_hello = regex.new "hello, .*" |> unwrap_ok
19 |         assert_eq (regex.is_match match_hello "hello, world") True,
20 | 
21 |     test "compile error" <| \_ -> 
22 |         let msg = regex.new ")" |> unwrap_err |> regex.error_to_string
23 |         assert_eq msg "regex parse error:\n    )\n    ^\nerror: unopened group",
24 | 
25 |     test "captures" <| \_ -> 
26 |         let re = regex.new r#"[a-z]+(?:([0-9]+)|([A-Z]+))"# |> unwrap_ok
27 |         assert_eq
28 |             (regex.captures re "abc123")
29 |             (Some [Some { start = 0, end = 6, text = "abc123" }, Some { start = 3, end = 6, text = "123" }, None])
30 | 
31 | ]
32 | 


--------------------------------------------------------------------------------
/tests/pass/state.glu:
--------------------------------------------------------------------------------
 1 | let prelude = import! std.prelude
 2 | let { (<|) } = import! std.function
 3 | let { Test, run, assert, assert_eq, test, group, ? } = import! std.test
 4 | let int = import! std.int
 5 | let state @ { State, put, get, modify, runState, evalState, execState, ? } = import! std.state
 6 | let { Applicative, wrap, (*>), ? } = import! std.applicative
 7 | 
 8 | group "state" [
 9 |     test "modify execState" <| \_ -> (assert_eq (execState (modify (\x -> x + 2) *> modify (\x -> x * 4)) 0) 8),
10 |     test "modify evalState" <| \_ -> (assert_eq (evalState (modify (\x -> x + 2) *> get) 0) 2),
11 |     test "put get evalState" <| \_ -> (assert_eq (evalState (put "hello" *> get) "") "hello"),
12 |     test "put get runState" <| \_ -> (assert_eq (runState (put "hello" *> get) "").value "hello"),
13 | 
14 |     /* FIXME
15 |     test "record unpack runState" <| \_ ->
16 |         let m : State { x : Int } Int =
17 |             do { x } = get
18 |             wrap x
19 |         assert_eq (evalState m { x = 1 }) 1,
20 |     */
21 | ]
22 | 
23 | 


--------------------------------------------------------------------------------
/tests/pass/statet.glu:
--------------------------------------------------------------------------------
 1 | let { (<|) } = import! std.function
 2 | let { Test, run, assert, assert_eq, test, group, ? } = import! std.test
 3 | let { StateT, put, get, gets, modify, run_state_t, eval_state_t, exec_state_t, ? } = import! std.statet
 4 | let { wrap, (*>) } = import! std.applicative
 5 | let { Monad, (>>=) } = import! std.monad
 6 | let { Option, unwrap, ? } = import! std.option
 7 | let { (++), ? } = import! std.string
 8 | let list @ { List, ? } = import! std.list
 9 | let { Transformer, wrap_monad } = import! std.transformer
10 | 
11 | #[infix(right,7)]
12 | let (::) x xs = Cons x xs
13 | 
14 | let left_identity x f : [Eq a] -> [Show a] -> a -> (a -> StateT _ Option a) -> _ = \_ ->
15 |     let mx : StateT _ Option _ = wrap x
16 |     let s = ()
17 |     assert_eq (eval_state_t (mx >>= f) s) (eval_state_t (f x) s)
18 | 
19 | let right_identity x : [Eq a] -> [Show a] -> a -> _ = \_ ->
20 |     let mx : StateT _ Option _ = wrap x
21 |     let s = ()
22 |     assert_eq (eval_state_t (mx >>= wrap) s) (eval_state_t mx s)
23 | 
24 | let associativity ?mo mx f g : [Monad m] -> [Show (m a)] -> [Eq (m a)] -> m a -> _ -> _ -> _ = \_ ->
25 |     let mx : StateT _ m _ = wrap_monad mx
26 |     let s = ()
27 |     assert_eq (eval_state_t ((mx >>= f) >>= g) s) (eval_state_t (mx >>= (\x -> f x >>= g)) s)
28 | 
29 | group "statet" [
30 |     // should this be moved to std.monad?
31 |     group "StateT s m is monadic" [
32 |         test "left identity" <| left_identity 324 (\x -> wrap <| x + 89),
33 |         test "right identity" <| right_identity "hello",
34 |         test "associativity" <| associativity (Some 5) (\x -> wrap (x+5)) (\x -> wrap (x*2)),
35 |     ],
36 |     group "StateT s m has state effects" [
37 |         test "modify exec_state_t" <| \_ -> (assert_eq (exec_state_t (modify (\x -> x + 2) *> modify (\x -> x * 4)) 0) <| Some 8),
38 |         test "modify eval_state_t" <| \_ -> (assert_eq (eval_state_t (modify (\x -> x + 2) *> get) 0) <| Some 2),
39 |         test "put get eval_state_t" <| \_ -> (assert_eq (eval_state_t (put "hello" *> get) "") <| Some "hello"),
40 |         #[derive(Eq, Show)]
41 |         type StateOut s a = { value : a, state : s }
42 |         test "put get run_state_t" <| \_ -> (assert_eq (run_state_t (put "hello" *> get) "") <| Some {value = "hello", state = "hello"}),
43 |         test "gets eval_state_t" <| \_ -> (assert_eq (eval_state_t (gets <| (::) 1) (Cons 2 (Cons 3 Nil))) <| Some (1 :: 2 :: 3 :: Nil)),
44 |     ],
45 | ]
46 | 


--------------------------------------------------------------------------------
/tests/pass/stream.glu:
--------------------------------------------------------------------------------
 1 | let prelude = import! std.prelude
 2 | let { (<|) } = import! std.function
 3 | let { run, Test, assert_eq, test, group, ? } = import! std.test
 4 | let { Applicative, (*>) } = import! std.applicative
 5 | let int = import! std.int
 6 | let stream @ { Stream, ? } = import! std.stream
 7 | let list @ { List, ? } = import! std.list
 8 | let { Option } = import! std.option
 9 | let { foldl } = import! std.foldable
10 | 
11 | let s = stream.from (\i -> if i < 5 then Some i else None)
12 | 
13 | group "stream" [
14 |     test "fold" <| \_ -> (assert_eq (foldl (+) 0 s) 10),
15 |     test "from" <| \_ -> (assert_eq s (stream.of [0, 1, 2, 3, 4])),
16 |     test "map" <| \_ -> (assert_eq (stream.functor.map (\x -> x + x) s) (stream.of [0, 2, 4, 6, 8])),
17 |     test "zip_with" <| \_ -> (assert_eq (stream.zip_with (+) s s) (stream.of [0, 2, 4, 6, 8]))
18 | ]
19 | 


--------------------------------------------------------------------------------
/tests/pass/string.glu:
--------------------------------------------------------------------------------
 1 | let { run, Test, assert_eq, test, group ? } = import! std.test
 2 | let { (<|) } = import! std.function
 3 | let { Applicative, (*>), ? } = import! std.applicative
 4 | 
 5 | let string = import! std.string
 6 | let { Result, ? } = import! std.result
 7 | let { ? } = import! std.unit
 8 | 
 9 | let { ? } = import! std.effect
10 | 
11 | let slice_tests =
12 |     test "slice" <| \_ -> (assert_eq (string.slice "ab" 0 1) "a" *> assert_eq (string.slice "ab" 1 2) "b"
13 |         *> assert_eq (string.slice "abcd" 2 4) "cd")
14 | 
15 | let append_tests =
16 |     let { (<>) } = import! std.prelude
17 |     test "append" <| \_ -> (assert_eq ("ab" <> "cd") "abcd" *> assert_eq ("ab" <> "") "ab" *> assert_eq ("" <> "cd") "cd"
18 |         *> assert_eq ("" <> "") "")
19 | 
20 | let find_tests =
21 |     test "find" <| \_ -> (assert_eq (string.find "abcd1234" "ab") (Some 0)
22 |         *> assert_eq (string.find "abcd1234" "b") (Some 1)
23 |         *> assert_eq (string.find "abcd1234" "4") (Some 7)
24 |         *> assert_eq (string.find "abcd1234" "xyz") None
25 |         *> assert_eq (string.rfind "abcdabcd" "b") (Some 5)
26 |         *> assert_eq (string.rfind "abcdabcd" "d") (Some 7)
27 |         *> assert_eq (string.rfind "abcd1234" "xyz") None)
28 | 
29 | let starts_ends_tests =
30 |     test "starts_ends_tests" <| \_ -> (assert_eq (string.starts_with "abcd1234" "ab") True
31 |         *> assert_eq (string.starts_with "abcd1234" "b") False
32 |         *> assert_eq (string.ends_with "abcd1234" "1234") True
33 |         *> assert_eq (string.ends_with "abcd1234" "4") True
34 |         *> assert_eq (string.ends_with "abcd1234" "ab") False)
35 | 
36 | let trim_tests =
37 |     test "trim" <| \_ -> (assert_eq (string.trim "ab") "ab" *> assert_eq (string.trim " ab ") "ab"
38 |         *> assert_eq (string.trim "ab \t") "ab"
39 |         *> assert_eq (string.trim "\t ab") "ab"
40 |         *> assert_eq (string.trim_start " ab ") "ab "
41 |         *> assert_eq (string.trim_end " ab ") " ab")
42 | 
43 | let from_utf8_tests =
44 |     test "from_utf8_tests" <| \_ -> (assert_eq (string.from_utf8 []) (Ok "") *> assert_eq (string.from_utf8 [32b]) (Ok " ")
45 |         *> assert_eq (string.from_utf8 [195b, 165b, 195b, 164b, 195b, 182b]) (Ok "åäö")
46 |         *> assert_eq (string.from_utf8 [195b, 165b, 195b, 164b, 195b]) (Err ())
47 |         *> assert_eq (string.from_utf8 [195b, 165b, 195b, 195b, 182b]) (Err ()))
48 | 
49 | group "string" [append_tests, find_tests, starts_ends_tests, trim_tests, from_utf8_tests]
50 | 


--------------------------------------------------------------------------------
/tests/pass/thread.glu:
--------------------------------------------------------------------------------
 1 | let { run, assert_eq, test, ? }  = import! std.test
 2 | let { lift } = import! std.effect.lift
 3 | let { (<|) } = import! std.function
 4 | let prelude  = import! std.prelude
 5 | let { Bool } = import! std.bool
 6 | let int = import! std.int
 7 | let { ? } = import! std.io
 8 | let result @ { Result, ? } = import! std.result
 9 | let string = import! std.string
10 | let unit @ { ? } = import! std.unit
11 | let { Applicative, wrap, (*>) } = import! std.applicative
12 | let { flat_map } = import! std.monad
13 | let { send, recv, channel } = import! std.channel
14 | let { spawn, yield, resume } = import! std.thread
15 | 
16 | let { ? } = import! std.effect
17 | 
18 | let assert_any_err =
19 |     assert_eq ?(result.show ?string.show ?unit.show)
20 |               ?(result.eq ?{ (==) = \x y -> True } ?unit.eq)
21 | 
22 | 
23 | let assert_recv channel expect : [Eq a] -> [Show a] -> _ -> Result () a -> _ =
24 |     do x = lift <| recv channel
25 |     assert_eq x expect
26 | 
27 | test "thread" <| \_ ->
28 |     do { sender, receiver } = lift <| channel 0
29 |     do thread = lift <| spawn (
30 |             seq send sender 0
31 |             let _ = yield ()
32 |             seq send sender 1
33 |             wrap ()
34 |         )
35 |     seq lift <| resume thread
36 | 
37 |     seq assert_recv receiver (Ok 0)
38 | 
39 |     seq assert_recv receiver (Err ())
40 |     seq lift <| resume thread
41 |     seq assert_recv receiver (Ok 1)
42 | 
43 |     seq assert_recv receiver (Err ())
44 |     do x = lift <| resume thread
45 |     assert_any_err x (Err "Any error message here")
46 | 


--------------------------------------------------------------------------------
/tests/pass/unwrap.glu:
--------------------------------------------------------------------------------
 1 | let { (|>) } = import! std.function
 2 | let { (<|) } = import! std.function
 3 | let option @ { Option } = import! std.option
 4 | let result @ { Result } = import! std.result
 5 | let { assert_eq, test, group }  = import! std.test
 6 | 
 7 | group "unwrap" [
 8 |     test "one" <| \_ -> (
 9 |         let one = Some 1 |> option.unwrap
10 |         assert_eq one 1
11 |     ),
12 | 
13 |     test "two" <| \_ -> (
14 |         let two = Ok 2 |> result.unwrap_ok
15 |         assert_eq two 2
16 |     ),
17 | 
18 |     test "three" <| \_ -> (
19 |         let three = Err 3 |> result.unwrap_err
20 |         assert_eq three 3
21 |     )
22 | ]
23 | 


--------------------------------------------------------------------------------
/tests/pass/writer.glu:
--------------------------------------------------------------------------------
 1 | let prelude = import! std.prelude
 2 | let { (<|) } = import! std.function
 3 | let list @ { ? } = import! std.list
 4 | let { Writer, ? }  = import! std.writer
 5 | let { Test, run_raw, assert, assert_eq, test, ? }  = import! std.test
 6 | let { Applicative, (*>), ? } = import! std.applicative
 7 | let { count } = import! std.foldable
 8 | 
 9 | let { run_pure, ? } = import! std.effect
10 | 
11 | let failed_tests =
12 |     run_pure <| run_raw (
13 |         assert_eq 1 1
14 |             *> assert_eq 1 2
15 |             *> assert_eq 1 1
16 |             *> assert_eq 1.0 10.0
17 |     )
18 | 
19 | test "writer" <| \_ -> (assert_eq (count failed_tests) 2)
20 | 


--------------------------------------------------------------------------------
/tests/row_polymorphism.rs:
--------------------------------------------------------------------------------
 1 | use gluon::{
 2 |     vm::api::{FunctionRef, Hole, OpaqueValue},
 3 |     Thread, ThreadExt,
 4 | };
 5 | 
 6 | use crate::support::make_vm;
 7 | 
 8 | #[macro_use]
 9 | mod support;
10 | 
11 | test_expr! { polymorphic_field_access,
12 | r#"
13 | let f record = record.x
14 | f { y = 1, x = 123 }
15 | "#,
16 | 123
17 | }
18 | 
19 | test_expr! { polymorphic_record_unpack,
20 | r#"
21 | let f record =
22 |     let { x, y } = record
23 |     x #Int- y
24 | f { y = 1, z = 0, x = 123 }
25 | "#,
26 | 122
27 | }
28 | 
29 | #[test]
30 | fn polymorphic_record_access_from_child_thread() {
31 |     let _ = ::env_logger::try_init();
32 |     let vm = make_vm();
33 |     let child = vm.new_thread().unwrap();
34 | 
35 |     vm.run_expr::<OpaqueValue<&Thread, Hole>>("", "import! std.function")
36 |         .unwrap();
37 | 
38 |     let result = child.run_expr::<FunctionRef<fn(i32) -> i32>>(
39 |         "test",
40 |         r#"
41 |         let function = import! std.function
42 |         let f r = r.id in
43 |         f function
44 |         "#,
45 |     );
46 |     assert!(result.is_ok(), "{}", result.err().unwrap());
47 |     assert_eq!(result.unwrap().0.call(123), Ok(123));
48 | }
49 | 
50 | // FIXME Add this test back when order no longer matters for fields
51 | // test_expr! { prelude different_order_on_fields,
52 | // r#"
53 | // let x =
54 | // if False then
55 | // { x = 1, y = "a" }
56 | // else
57 | // { y = "b", x = 2 }
58 | // x.y
59 | // "#,
60 | // String::from("a")
61 | // }
62 | //
63 | 


--------------------------------------------------------------------------------
/tests/safety.rs:
--------------------------------------------------------------------------------
 1 | mod support;
 2 | 
 3 | use gluon::{
 4 |     vm::{
 5 |         api::{FunctionRef, OpaqueValue, IO},
 6 |         reference::Reference,
 7 |     },
 8 |     RootedThread, Thread, ThreadExt,
 9 | };
10 | 
11 | use crate::support::*;
12 | 
13 | fn verify_value_cloned(from: &Thread, to: &Thread) {
14 |     from.get_database_mut().run_io(true);
15 |     to.get_database_mut().run_io(true);
16 | 
17 |     from.run_expr::<()>("load", r#"let _ = import! std.reference in () "#)
18 |         .unwrap_or_else(|err| panic!("{}", err));
19 |     to.run_expr::<()>("load", r#"let _ = import! std.reference in () "#)
20 |         .unwrap_or_else(|err| panic!("{}", err));
21 | 
22 |     let expr = r#"
23 |         let { ref } = import! std.reference
24 |         ref 0
25 |         "#;
26 | 
27 |     let value: OpaqueValue<_, _> = from
28 |         .run_expr::<IO<OpaqueValue<RootedThread, Reference<i32>>>>("example", expr)
29 |         .and_then(|(io, _)| Result::from(io).map_err(From::from))
30 |         .unwrap_or_else(|err| panic!("{}", err));
31 | 
32 |     // Load the prelude
33 |     type Fn<'t> = FunctionRef<'t, fn(OpaqueValue<RootedThread, Reference<i32>>) -> IO<()>>;
34 |     let store_expr = r#"
35 |         let { (<-) } = import! std.reference
36 |         \r -> r <- 1
37 |         "#;
38 |     let (mut store_1, _) = to
39 |         .run_expr::<Fn>("store_1", store_expr)
40 |         .unwrap_or_else(|err| panic!("{}", err));
41 |     assert_eq!(store_1.call(value.clone()), Ok(IO::Value(())));
42 | 
43 |     let mut load: FunctionRef<fn(OpaqueValue<RootedThread, Reference<i32>>) -> IO<i32>> =
44 |         from.get_global("std.reference.load").unwrap();
45 |     assert_eq!(load.call(value), Ok(IO::Value(0)));
46 | }
47 | 
48 | #[test]
49 | fn cant_transfer_opaque_value_between_sibling_threads() {
50 |     let _ = ::env_logger::try_init();
51 |     //     vm
52 |     //  /     \
53 |     // vm1    vm2
54 |     // Passing a value directly from vm1 to vm2 requires the value to be cloned in its entirety
55 |     let vm = make_vm();
56 |     let vm1 = vm.new_thread().unwrap();
57 |     let vm2 = vm.new_thread().unwrap();
58 |     verify_value_cloned(&vm1, &vm2);
59 | }
60 | 
61 | #[test]
62 | fn cant_transfer_opaque_value_between_disjoint_threads() {
63 |     let _ = ::env_logger::try_init();
64 |     // vm1    vm2
65 |     // Passing a value directly from vm1 to vm2 requires the value to be cloned in its entirety
66 |     // since the vms do not share the same global vm
67 |     let vm1 = make_vm();
68 |     let vm2 = make_vm();
69 |     verify_value_cloned(&vm1, &vm2);
70 | }
71 | 


--------------------------------------------------------------------------------
/tests/skeptic-template.md:
--------------------------------------------------------------------------------
1 | 
2 | ```rust,skeptic-root-template
3 | extern crate env_logger;
4 | extern crate gluon;
5 | ```
6 | 


--------------------------------------------------------------------------------
/tests/skeptic-tests.rs:
--------------------------------------------------------------------------------
1 | #![cfg(feature = "little-skeptic")]
2 | include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));
3 | 


--------------------------------------------------------------------------------
/tests/snapshots/ui__macro_error_with_line_column_info.snap:
--------------------------------------------------------------------------------
 1 | ---
 2 | source: tests/ui.rs
 3 | expression: result.unwrap_err().emit_string().unwrap()
 4 | ---
 5 | error: Could not find module 'undefined'. Searched `.`.
 6 |   ┌─ test:1:1
 7 |   │
 8 | 1 │ import! undefined
 9 |   │ ^^^^^^^^^^^^^^^^^
10 | 
11 | 
12 | 


--------------------------------------------------------------------------------
/tests/tutorial.rs:
--------------------------------------------------------------------------------
 1 | #[macro_use]
 2 | extern crate gluon_vm;
 3 | 
 4 | use gluon::base::types::Type;
 5 | use gluon::import::{add_extern_module, Import};
 6 | use gluon::vm;
 7 | use gluon::vm::api::{FunctionRef, Hole, OpaqueValue};
 8 | use gluon::{RootedThread, Thread, ThreadExt};
 9 | 
10 | fn new_vm() -> RootedThread {
11 |     let vm = ::gluon::new_vm();
12 |     let import = vm.get_macros().get("import");
13 |     import
14 |         .as_ref()
15 |         .and_then(|import| import.downcast_ref::<Import>())
16 |         .expect("Import macro")
17 |         .add_path("..");
18 |     vm
19 | }
20 | 
21 | #[test]
22 | fn access_field_through_alias() {
23 |     let _ = ::env_logger::try_init();
24 |     let vm = new_vm();
25 |     vm.run_expr::<OpaqueValue<&Thread, Hole>>("example", r#" import! std.int "#)
26 |         .unwrap();
27 |     let mut add: FunctionRef<fn(i32, i32) -> i32> = vm
28 |         .get_global("std.int.num.(+)")
29 |         .unwrap_or_else(|err| panic!("{}", err));
30 |     let result = add.call(1, 2);
31 |     assert_eq!(result, Ok(3));
32 | }
33 | 
34 | #[test]
35 | fn call_rust_from_gluon() {
36 |     let _ = ::env_logger::try_init();
37 | 
38 |     fn factorial(x: i32) -> i32 {
39 |         if x <= 1 {
40 |             1
41 |         } else {
42 |             x * factorial(x - 1)
43 |         }
44 |     }
45 | 
46 |     fn load_factorial(vm: &Thread) -> vm::Result<vm::ExternModule> {
47 |         vm::ExternModule::new(vm, primitive!(1, factorial))
48 |     }
49 | 
50 |     let vm = new_vm();
51 | 
52 |     // Introduce a module that can be loaded with `import! factorial`
53 |     add_extern_module(&vm, "factorial", load_factorial);
54 | 
55 |     let expr = r#"
56 |         let factorial = import! factorial
57 |         factorial 5
58 |     "#;
59 | 
60 |     let (result, _) = vm.run_expr::<i32>("factorial", expr).unwrap();
61 | 
62 |     assert_eq!(result, 120);
63 | }
64 | 
65 | #[test]
66 | fn use_string_module() {
67 |     let _ = ::env_logger::try_init();
68 | 
69 |     let vm = new_vm();
70 |     let result = vm
71 |         .run_expr::<String>(
72 |             "example",
73 |             " let string  = import! \"std/string.glu\" in string.trim \"  \
74 |              Hello world  \t\" ",
75 |         )
76 |         .unwrap();
77 |     let expected = ("Hello world".to_string(), Type::string());
78 | 
79 |     assert_eq!(result, expected);
80 | }
81 | 


--------------------------------------------------------------------------------
/tests/ui.rs:
--------------------------------------------------------------------------------
1 | use gluon::{new_vm, ThreadExt};
2 | 
3 | #[test]
4 | fn macro_error_with_line_column_info() {
5 |     let thread = new_vm();
6 |     let result = thread.run_expr::<()>("test", "import! undefined");
7 |     insta::assert_snapshot!(result.unwrap_err().emit_string().unwrap());
8 | }
9 | 


--------------------------------------------------------------------------------
/tests/unrelated_type_error.glu:
--------------------------------------------------------------------------------
1 | let f x = x + 1
2 | "" + 1
3 | { f }
4 | 


--------------------------------------------------------------------------------
/vm/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "gluon_vm"
 3 | version = "0.18.2" # GLUON
 4 | authors = ["Markus <marwes91@gmail.com>"]
 5 | edition = "2018"
 6 | build = "build.rs"
 7 | 
 8 | license = "MIT"
 9 | 
10 | description = "The virtual machine for executing the gluon programming language"
11 | 
12 | homepage = "https://gluon-lang.org"
13 | repository = "https://github.com/gluon-lang/gluon"
14 | documentation = "https://docs.rs/gluon"
15 | 
16 | [dependencies]
17 | async-trait = "0.1.73"
18 | bitflags = "1.3.2"
19 | codespan = "0.11.1"
20 | codespan-reporting = "0.11.1"
21 | collect-mac = "0.1.0"
22 | downcast-rs = "1.2.0"
23 | difference = { version = "2.0.0", optional = true }
24 | crossbeam-utils = "0.8.16"
25 | frunk_core = "0.4.2"
26 | futures = { version = "0.3.28", features = ["compat", "async-await"] }
27 | itertools = "0.10.5"
28 | lalrpop-util = { version = "0.19.12", optional = true }
29 | log = "0.4.20"
30 | ordered-float = "2.10.0"
31 | parking_lot = "0.11.2"
32 | petgraph = "0.6.4"
33 | pretty = "0.10.0"
34 | quick-error = "2.0.1"
35 | regex = { version = "1.9.4", optional = true }
36 | smallvec = "1.11.0"
37 | slab = "0.4.9"
38 | typed-arena = "2.0.2"
39 | 
40 | serde = { version = "1.0.188", optional = true }
41 | serde_json = { version = "1.0.105", optional = true }
42 | serde_state = { version = "0.4.8", optional = true }
43 | serde_derive = { version = "1.0.188", optional = true }
44 | serde_derive_state = { version = "0.4.10", optional = true }
45 | 
46 | gluon_base = { path = "../base", version = "0.18.2" } # GLUON
47 | gluon_check = { path = "../check", version = "0.18.2" } # GLUON
48 | gluon_codegen = { path = "../codegen", version = "0.18.2" } # GLUON
49 | gluon_parser = { path = "../parser", version = "0.18.2", optional = true } # GLUON
50 | 
51 | [build-dependencies]
52 | lalrpop = { version = "0.19.12", features = ["lexer"], optional = true }
53 | 
54 | [dev-dependencies]
55 | difference = "2.0.0"
56 | env_logger = "0.9.3"
57 | pretty_assertions = "1.4.0"
58 | 
59 | # HACK Trick crates.io into letting letting this be published with a dependency on gluon
60 | # (which requires gluon_vm to be published)
61 | gluon = { path = "..", version = ">=0.9" }
62 | 
63 | lalrpop-util = "0.19.12"
64 | regex = "1.9.4"
65 | serde_json = "1.0.105"
66 | tokio = { version = "1.32.0", features = ["macros"] }
67 | 
68 | gluon_parser = { path = "../parser", version = "0.18.2" } # GLUON
69 | 
70 | [features]
71 | serialization = ["serde", "serde_state", "serde_derive", "serde_derive_state", "serde_json", "gluon_base/serialization", "codespan/serialization"]
72 | test = ["difference", "lalrpop", "lalrpop-util", "regex", "serialization", "gluon_parser"]
73 | docs_rs = ["serialization"]
74 | 
75 | [package.metadata.docs.rs]
76 | features = ["docs_rs"]
77 | 


--------------------------------------------------------------------------------
/vm/build.rs:
--------------------------------------------------------------------------------
 1 | #[cfg(feature = "test")]
 2 | mod build {
 3 |     extern crate lalrpop;
 4 | 
 5 |     pub fn main() {
 6 |         lalrpop::Configuration::new()
 7 |             .use_cargo_dir_conventions()
 8 |             .process_file("src/core/grammar.lalrpop")
 9 |             .unwrap();
10 | 
11 |         println!("cargo:rerun-if-changed=src/core/grammar.lalrpop");
12 |     }
13 | }
14 | 
15 | #[cfg(not(feature = "test"))]
16 | mod build {
17 |     pub fn main() {}
18 | }
19 | 
20 | fn main() {
21 |     build::main();
22 | }
23 | 


--------------------------------------------------------------------------------
/vm/src/debug.rs:
--------------------------------------------------------------------------------
 1 | use crate::{
 2 |     api::{generic::A, Generic, OpaqueRef},
 3 |     thread::Thread,
 4 |     value::ValueRepr,
 5 |     ExternModule, Result,
 6 | };
 7 | 
 8 | fn trace(a: Generic<A>) {
 9 |     println!("{:?}", a);
10 | }
11 | 
12 | fn show(a: Generic<A>) -> String {
13 |     format!("{:?}", a)
14 | }
15 | 
16 | fn tag(a: OpaqueRef<A>) -> Option<String> {
17 |     match a.get_value().get_repr() {
18 |         ValueRepr::Data(data) => data.poly_tag().map(|s| s.to_string()),
19 |         _ => None,
20 |     }
21 | }
22 | 
23 | mod std {
24 |     pub use crate::debug;
25 | }
26 | 
27 | pub fn load(vm: &Thread) -> Result<ExternModule> {
28 |     ExternModule::new(
29 |         vm,
30 |         record! {
31 |             trace => primitive!(1, std::debug::trace),
32 |             show => primitive!(1, std::debug::show),
33 |             tag => primitive!(1, std::debug::tag)
34 |         },
35 |     )
36 | }
37 | 


--------------------------------------------------------------------------------
/vm/src/dynamic.rs:
--------------------------------------------------------------------------------
 1 | use std::borrow::Cow;
 2 | 
 3 | use crate::base::resolve;
 4 | use crate::base::types::{ArcType, NullInterner, Type};
 5 | 
 6 | use crate::thread::{RootedValue, Thread, VmRoot, VmRootInternal};
 7 | 
 8 | #[derive(Debug)]
 9 | pub struct FieldIter<'a, T>
10 | where
11 |     T: VmRootInternal,
12 | {
13 |     value: &'a RootedValue<T>,
14 |     index: usize,
15 |     resolved_type: Cow<'a, ArcType>,
16 | }
17 | 
18 | impl<'a, T> Iterator for FieldIter<'a, T>
19 | where
20 |     T: VmRoot<'a>,
21 | {
22 |     type Item = (RootedValue<T>, ArcType);
23 | 
24 |     fn next(&mut self) -> Option<Self::Item> {
25 |         match **self.resolved_type {
26 |             Type::Record(ref row) => match **row {
27 |                 Type::ExtendRow { ref fields, .. } => {
28 |                     let index = self.index;
29 |                     self.index += 1;
30 |                     self.value
31 |                         .get(index)
32 |                         .map(|value| (value, fields[index].typ.clone()))
33 |                 }
34 |                 _ => None,
35 |             },
36 |             _ => None,
37 |         }
38 |     }
39 | }
40 | 
41 | pub fn field_iter<'vm, T>(
42 |     value: &'vm RootedValue<T>,
43 |     typ: &'vm ArcType,
44 |     thread: &Thread,
45 | ) -> FieldIter<'vm, T>
46 | where
47 |     T: VmRoot<'vm>,
48 | {
49 |     FieldIter {
50 |         value: value,
51 |         index: 0,
52 |         resolved_type: resolve::remove_aliases_cow(&thread.get_env(), &mut NullInterner, typ),
53 |     }
54 | }
55 | 


--------------------------------------------------------------------------------