├── .gitattributes ├── .github ├── FUNDING.yml ├── SECURITY.md ├── renovate.json └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── README.md ├── assets └── fonts │ ├── NotoSans-license.txt │ ├── NotoSansMonoCJKjp-Regular.otf │ ├── iosevka-fixed-extended.ttf │ └── iosevka-license.md ├── configs ├── crates.txt ├── deny.toml └── theme.ron ├── crates ├── adapters │ ├── dworkspace-firestore │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── dworkspace-in-memory │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── apps │ ├── desk-x │ │ ├── Cargo.toml │ │ ├── public │ │ │ └── index.html │ │ └── src │ │ │ ├── about.rs │ │ │ ├── main.rs │ │ │ ├── panels.rs │ │ │ ├── theme.rs │ │ │ └── windows.rs │ ├── deskc-cli │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── deskc-language-server │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── components │ ├── desk-command │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── cursor.rs │ │ │ ├── lib.rs │ │ │ └── terminal.rs │ ├── desk-physics │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── drag_state.rs │ │ │ ├── follow.rs │ │ │ ├── lib.rs │ │ │ └── shape.rs │ ├── desk-plugin │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── lib.rs │ │ │ └── system_labels.rs │ ├── desk-theme │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── colorscheme.rs │ │ │ └── lib.rs │ ├── desk-window │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── ctx.rs │ │ │ ├── lib.rs │ │ │ ├── widget.rs │ │ │ └── window.rs │ ├── deskc-ast │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── dson.rs │ │ │ ├── expr.rs │ │ │ ├── lib.rs │ │ │ ├── meta.rs │ │ │ ├── parser.rs │ │ │ ├── remove_span.rs │ │ │ ├── ty.rs │ │ │ └── visitor.rs │ ├── deskc-errors │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── lib.rs │ │ │ ├── mirgen.rs │ │ │ ├── syntax.rs │ │ │ ├── textual_diagnostics.rs │ │ │ └── typeinfer.rs │ ├── deskc-hir │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── expr.rs │ │ │ ├── lib.rs │ │ │ ├── list_ids.rs │ │ │ ├── meta.rs │ │ │ ├── ty.rs │ │ │ └── visitor.rs │ ├── deskc-ids │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── deskc-mir │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── block.rs │ │ │ ├── lib.rs │ │ │ ├── mir.rs │ │ │ ├── scope.rs │ │ │ ├── stmt.rs │ │ │ └── var.rs │ ├── deskc-type │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── conclusion.rs │ │ │ ├── conversions.rs │ │ │ └── lib.rs │ ├── deskvm-dprocess │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── dprocess │ │ │ ├── id.rs │ │ │ ├── links.rs │ │ │ ├── mod.rs │ │ │ ├── monitors.rs │ │ │ ├── new.rs │ │ │ ├── read_locks.rs │ │ │ ├── receive_message.rs │ │ │ ├── reduce.rs │ │ │ ├── reset.rs │ │ │ ├── status.rs │ │ │ ├── update_processor_attachment.rs │ │ │ └── write_locks.rs │ │ │ ├── dprocess_info.rs │ │ │ ├── dprocess_manifest.rs │ │ │ ├── effect_handler.rs │ │ │ ├── exit_status.rs │ │ │ ├── flags.rs │ │ │ ├── interpreter.rs │ │ │ ├── interpreter_builder.rs │ │ │ ├── interpreter_output.rs │ │ │ ├── lib.rs │ │ │ ├── metas.rs │ │ │ ├── migration_logic.rs │ │ │ ├── name_registry.rs │ │ │ ├── processing_kind.rs │ │ │ ├── processor.rs │ │ │ ├── processor_attachment.rs │ │ │ ├── scheduler.rs │ │ │ ├── status.rs │ │ │ ├── status_update.rs │ │ │ ├── timer.rs │ │ │ ├── value.rs │ │ │ └── vm_ref │ │ │ ├── get_dprocess.rs │ │ │ ├── get_processor.rs │ │ │ ├── mod.rs │ │ │ ├── notify_status.rs │ │ │ ├── pubsub.rs │ │ │ ├── read_locks.rs │ │ │ ├── register.rs │ │ │ ├── spawn.rs │ │ │ └── write_locks.rs │ ├── dson │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── dworkspace-codebase │ │ ├── Cargo.toml │ │ └── src │ │ ├── code.rs │ │ ├── content.rs │ │ ├── event.rs │ │ ├── flat_node.rs │ │ ├── lib.rs │ │ ├── node.rs │ │ ├── patch │ │ ├── diff_match_patch.rs │ │ └── mod.rs │ │ ├── projection.rs │ │ ├── rules.rs │ │ └── user.rs ├── libs │ ├── deskc-macros │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── serde-dson │ │ ├── Cargo.toml │ │ └── src │ │ ├── de.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ └── ser.rs ├── plugins │ ├── desk-editor │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── compile.rs │ │ │ ├── editor_state.rs │ │ │ ├── editor_widget.rs │ │ │ ├── lib.rs │ │ │ └── runtime.rs │ ├── desk-egui │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── desk-firebase-auth │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── desk-guide │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── desk-playground │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── desk-rapier2d │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── follow_system.rs │ │ │ └── lib.rs │ ├── desk-terminal │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── desk-touchpanel │ │ ├── Cargo.toml │ │ └── src │ │ ├── cursor_systems.rs │ │ ├── drag_system.rs │ │ └── lib.rs ├── systems │ ├── deskc-fmt │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── deskc-hirgen │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── error.rs │ │ │ ├── gen_effect_expr.rs │ │ │ └── lib.rs │ ├── deskc-mirgen │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── block_proto.rs │ │ │ ├── lib.rs │ │ │ ├── mir_proto.rs │ │ │ └── scope_proto.rs │ ├── deskc-syntax-minimalist │ │ ├── Cargo.toml │ │ ├── build.rs │ │ └── src │ │ │ ├── .gitignore │ │ │ ├── conversions.rs │ │ │ ├── grammar.par │ │ │ ├── grammar.rs │ │ │ ├── lib.rs │ │ │ └── span_storage.rs │ ├── deskc-typeinfer │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── cast_strategies.rs │ │ │ ├── ctx │ │ │ ├── apply.rs │ │ │ ├── check.rs │ │ │ ├── from_hir_type.rs │ │ │ ├── instantiate_subtype.rs │ │ │ ├── instantiate_supertype.rs │ │ │ ├── into_type.rs │ │ │ ├── mod.rs │ │ │ ├── subtype.rs │ │ │ ├── synth.rs │ │ │ ├── with_effects.rs │ │ │ └── with_type.rs │ │ │ ├── internal_type │ │ │ ├── effect_expr.rs │ │ │ └── mod.rs │ │ │ ├── lib.rs │ │ │ ├── mappings.rs │ │ │ ├── mono_type.rs │ │ │ ├── occurs_in.rs │ │ │ ├── partial_ord_max.rs │ │ │ ├── polymorphic_function.rs │ │ │ ├── similarity.rs │ │ │ ├── substitute.rs │ │ │ ├── substitute_from_ctx.rs │ │ │ ├── utils.rs │ │ │ └── well_formed.rs │ ├── deskc │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── card.rs │ │ │ ├── error.rs │ │ │ ├── hir_result.rs │ │ │ ├── lib.rs │ │ │ ├── parse_source_code.rs │ │ │ └── query_result.rs │ ├── deskvm-miri │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── const_stmt.rs │ │ │ ├── eval_cfg.rs │ │ │ ├── eval_cfg │ │ │ └── cast.rs │ │ │ ├── interpreter_builder.rs │ │ │ ├── lib.rs │ │ │ ├── operators │ │ │ ├── cmp.rs │ │ │ ├── helpers.rs │ │ │ ├── int.rs │ │ │ └── mod.rs │ │ │ └── value.rs │ ├── deskvm │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── desk_vm │ │ │ ├── dprocesses.rs │ │ │ ├── mod.rs │ │ │ ├── processors.rs │ │ │ ├── read_locks.rs │ │ │ ├── reduce.rs │ │ │ ├── run_migration_logic.rs │ │ │ └── status_updates.rs │ │ │ ├── lib.rs │ │ │ ├── migration_logic.rs │ │ │ └── scheduler.rs │ └── dworkspace │ │ ├── Cargo.toml │ │ └── src │ │ ├── audit │ │ ├── assertion.rs │ │ ├── execute_assertion.rs │ │ ├── extract_assertion.rs │ │ └── mod.rs │ │ ├── descendants.rs │ │ ├── error.rs │ │ ├── history.rs │ │ ├── lib.rs │ │ ├── loop_detector.rs │ │ ├── nodes.rs │ │ ├── nodes │ │ ├── ast.rs │ │ └── node.rs │ │ ├── prelude.rs │ │ ├── query_error.rs │ │ ├── references.rs │ │ ├── repository.rs │ │ └── state.rs └── tests │ └── deskc-test │ ├── Cargo.toml │ ├── cases │ ├── .gitignore │ ├── 001_literal.dson │ ├── 002_addition.dson │ ├── 003_match.dson │ ├── 004_let_function.dson │ ├── 005_division_by_zero.dson │ ├── 006_continuation.dson │ ├── 007_fibonacci.dson │ └── 008_cards.dson │ └── src │ ├── lib.rs │ └── test_case.rs ├── docs ├── CONTRIBUTING.md ├── CREDITS.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── blog │ ├── 0001-introduce-desk.md │ └── 0002-algebraic-effects.md ├── decisions │ ├── adr-template.md │ └── dkernel │ │ └── 0001-we-dont-need-files-and-directories.md └── language │ ├── README.md │ ├── formal-definition.md │ └── introduction.md └── tools ├── build-and-serve.sh ├── build-wasm.sh ├── check-ci.sh ├── deploy-wasm.sh ├── diff-crates.sh ├── list-crates.sh └── publish-crates.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | # Explicitly declare text files you want to always be normalized and converted 4 | # to native line endings on checkout. 5 | *.rs text eol=lf 6 | *.toml text eol=lf 7 | # Denote all files that are truly binary and should not be modified. 8 | *.png binary 9 | *.jpg binary 10 | *.ttf filter=lfs diff=lfs merge=lfs -text 11 | *.woff2 filter=lfs diff=lfs merge=lfs -text 12 | *.otf filter=lfs diff=lfs merge=lfs -text 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ryo33 2 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 0.0.0 | :white_check_mark: | 8 | | < 0.0.0 | :x: | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | Email me at ryo12redstone@gmail.com (Ryo Hirayama) 13 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":timezone(Asia/Tokyo)" 6 | ], 7 | "schedule": ["before 5am on monday"], 8 | "addLabels": [ 9 | "dependencies" 10 | ], 11 | "packageRules": [ 12 | { 13 | "matchDepTypes": ["devDependencies"], 14 | "groupName": "dev dependencies", 15 | "rangeStrategy": "update-lockfile" 16 | }, 17 | { 18 | "matchDepTypes": ["dependencies", "workspace.dependencies", "build-dependencies"], 19 | "matchUpdateTypes": ["minor", "patch"], 20 | "groupName": "non-major dependencies" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - '**/*.rs' 8 | 9 | env: 10 | CARGO_INCREMENTAL: 0 11 | RUST_BACKTRACE: short 12 | RUSTFLAGS: "-D warnings" 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | # for alsa and udev 18 | - run: sudo apt-get update 19 | - run: sudo apt-get install --no-install-recommends libasound2-dev libudev-dev -y 20 | 21 | - uses: actions/checkout@v3 22 | with: 23 | lfs: true 24 | 25 | - uses: actions-rs/toolchain@v1 26 | with: 27 | profile: minimal 28 | toolchain: stable 29 | default: true 30 | components: rustfmt, clippy 31 | 32 | - uses: Swatinem/rust-cache@v2 33 | 34 | - run: tools/check-ci.sh --no-cargo-deny 35 | 36 | - uses: EmbarkStudios/cargo-deny-action@v1 37 | with: 38 | arguments: --all-features 39 | command-arguments: --config configs/deny.toml 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore all but allows all directories 2 | * 3 | !*/ 4 | 5 | # ignore directories 6 | /target 7 | /node_modules 8 | 9 | # rust files 10 | !/crates/**/*.rs 11 | !/crates/**/Cargo.* 12 | 13 | # other files 14 | !/.github/**/*.yml 15 | !/.github/**/*.json 16 | !/docs/**/*.md 17 | !/configs/**/*.toml 18 | !/configs/**/*.ron 19 | !/tools/**/*.sh 20 | !/assets/fonts/*.ttf 21 | !/assets/fonts/*.otf 22 | !/assets/**/*license* 23 | 24 | 25 | # desk-x 26 | !/crates/apps/desk-x/public/index.html 27 | 28 | # specific files 29 | !/.gitattributes 30 | !/README.md 31 | !/LICENSE.md 32 | !/docs/LICENSE-* 33 | !/configs/crates.txt 34 | 35 | # global allow 36 | !.gitignore 37 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "crates/libs/*", 5 | "crates/apps/*", 6 | "crates/plugins/*", 7 | "crates/systems/*", 8 | "crates/components/*", 9 | "crates/adapters/*", 10 | "crates/tests/*", 11 | ] 12 | # wait for rapier2d supports bevy 0.9 13 | exclude = [ 14 | "crates/plugins/desk-rapier2d", 15 | ] 16 | 17 | # for smaller build size 18 | [profile.release] 19 | lto = "thin" 20 | 21 | # for parol 22 | [profile.dev.build-override] 23 | opt-level = 3 24 | [profile.release.build-override] 25 | opt-level = 3 26 | 27 | [workspace.dependencies] 28 | parking_lot = "0.12" 29 | thiserror = "1.0" 30 | uuid = "1.3" 31 | bevy = "0.10" 32 | egui = "0.22" 33 | bevy_math = "0.10" 34 | bevy_ecs = "0.10" 35 | once_cell = "1.18" 36 | maybe-owned = "0.3.4" 37 | egui_cable = "0.5" 38 | ron = "0.8" 39 | 40 | deskc = { path = "crates/systems/deskc", version = "0.0.0" } 41 | deskc-ids = { path = "crates/components/deskc-ids", version = "0.0.0" } 42 | deskc-type = { path = "crates/components/deskc-type", version = "0.0.0" } 43 | deskc-macros = { path = "crates/libs/deskc-macros", version = "0.0.0" } 44 | deskc-ast = { path = "crates/components/deskc-ast", version = "0.0.0" } 45 | desk-plugin = { path = "crates/components/desk-plugin", version = "0.0.0" } 46 | desk-window = { path = "crates/components/desk-window", version = "0.0.0" } 47 | desk-theme = { path = "crates/components/desk-theme", version = "0.0.0" } 48 | dworkspace = { path = "crates/systems/dworkspace", version = "0.0.0" } 49 | dson = { path = "crates/components/dson", version = "0.0.0" } 50 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | desk is dual-licensed under either 2 | 3 | - MIT License (docs/LICENSE-MIT or http://opensource.org/licenses/MIT) 4 | - Apache License, Version 2.0 (docs/LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) 5 | 6 | at your option. 7 | 8 | Copyright 2022 Ryo Hirayama 9 | -------------------------------------------------------------------------------- /assets/fonts/NotoSansMonoCJKjp-Regular.otf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:4d01725be822d144cf9a56ade981e6fb920cd7a610b8fc24cc601a920beea5b9 3 | size 16424156 4 | -------------------------------------------------------------------------------- /assets/fonts/iosevka-fixed-extended.ttf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:9bd2ccff0a7e27b5ec2a7d1cb21440c4d0981729a6bcefcb59cf22c494a985a0 3 | size 4916492 4 | -------------------------------------------------------------------------------- /configs/crates.txt: -------------------------------------------------------------------------------- 1 | # if crate A depends on crate B, B must come before A in this list 2 | 3 | # deskc components 4 | deskc-ids 5 | deskc-type 6 | deskc-ast 7 | deskc-hir 8 | deskc-mir 9 | deskc-errors 10 | 11 | # deskc systems 12 | deskc-syntax-minimalist 13 | deskc-hirgen 14 | deskc-typeinfer 15 | deskc-mirgen 16 | deskc-fmt 17 | deskc 18 | 19 | # deskc libs 20 | deskc-macros 21 | 22 | # deskc apps 23 | deskc-cli 24 | deskc-language-server 25 | 26 | # dson 27 | dson 28 | serde-dson 29 | 30 | # workspace components 31 | dworkspace-codebase 32 | 33 | # workspace systems 34 | dworkspace 35 | 36 | # workspace adapters 37 | dworkspace-firestore 38 | dworkspace-in-memory 39 | 40 | # deskvm components 41 | deskvm-dprocess 42 | 43 | # deskvm systems 44 | deskvm-miri 45 | deskvm 46 | 47 | # desk components 48 | desk-theme 49 | desk-physics 50 | desk-system-ordering 51 | desk-command 52 | desk-terminal 53 | desk-window 54 | 55 | # desk plugins 56 | desk-egui 57 | desk-rapier2d 58 | desk-touchpanel 59 | desk-guide 60 | desk-editor 61 | desk-firebase-auth 62 | 63 | # desk apps 64 | desk-x 65 | -------------------------------------------------------------------------------- /configs/deny.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | db-path = "~/.cargo/advisory-db" 3 | db-urls = ["https://github.com/rustsec/advisory-db"] 4 | vulnerability = "deny" 5 | unmaintained = "allow" 6 | yanked = "deny" 7 | notice = "deny" 8 | ignore = [] 9 | 10 | [licenses] 11 | unlicensed = "deny" 12 | copyleft = "deny" 13 | allow = [ 14 | "MIT", 15 | "MIT-0", 16 | "Apache-2.0", 17 | "BSD-3-Clause", 18 | "ISC", 19 | "Zlib", 20 | "0BSD", 21 | "BSD-2-Clause", 22 | "CC0-1.0", 23 | "BSL-1.0", 24 | ] 25 | exceptions = [ 26 | { name = "unicode-ident", allow = ["Unicode-DFS-2016"] }, 27 | { name = "epaint", allow = [ "LicenseRef-UFL-1.0", "OFL-1.1" ] }, 28 | ] 29 | default = "deny" 30 | 31 | [[licenses.clarify]] 32 | name = "stretch" 33 | expression = "MIT" 34 | license-files = [] 35 | 36 | [bans] 37 | multiple-versions = "allow" 38 | # This should be "deny" but for parol 39 | wildcards = "warn" 40 | highlight = "all" 41 | skip = [] 42 | 43 | [sources] 44 | unknown-registry = "deny" 45 | unknown-git = "deny" 46 | allow-registry = ["https://github.com/rust-lang/crates.io-index"] 47 | allow-git = [ 48 | "https://github.com/jsinger67/parol.git", 49 | "https://github.com/ryo33/bart.git", 50 | ] 51 | -------------------------------------------------------------------------------- /crates/adapters/dworkspace-firestore/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dworkspace-firestore" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | -------------------------------------------------------------------------------- /crates/adapters/dworkspace-firestore/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | let result = 2 + 2; 6 | assert_eq!(result, 4); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /crates/adapters/dworkspace-in-memory/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dworkspace-in-memory" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | dworkspace = { workspace = true } 15 | dworkspace-codebase = { package = "dworkspace-codebase", path = "../../components/dworkspace-codebase", version = "0.0.0" } 16 | -------------------------------------------------------------------------------- /crates/adapters/dworkspace-in-memory/src/lib.rs: -------------------------------------------------------------------------------- 1 | use dworkspace::{prelude::UserId, repository::Repository}; 2 | use dworkspace_codebase::event::Event; 3 | 4 | #[derive(Debug)] 5 | pub struct InMemoryRepository { 6 | pub user_id: UserId, 7 | pub entries: Vec, 8 | } 9 | 10 | impl InMemoryRepository { 11 | pub fn new(user_id: UserId) -> Self { 12 | Self { 13 | user_id, 14 | entries: Vec::new(), 15 | } 16 | } 17 | } 18 | 19 | impl Repository for InMemoryRepository { 20 | fn poll(&mut self) -> Vec { 21 | self.entries.drain(..).collect() 22 | } 23 | 24 | fn commit(&mut self, event: Event) { 25 | self.entries.push(event); 26 | } 27 | 28 | fn user_id(&self) -> UserId { 29 | self.user_id 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/apps/desk-x/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-x" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [features] 12 | inspector = ["bevy-inspector-egui"] 13 | 14 | [dependencies] 15 | egui-plugin = { path = "../../plugins/desk-egui", version = "0.0.0", package = "desk-egui" } 16 | # wait for rapier2d supports bevy 0.9 17 | # rapier2d-plugin = { path = "../../plugins/desk-rapier2d", version = "0.0.0", package = "desk-rapier2d" } 18 | touchpanel-plugin = { path = "../../plugins/desk-touchpanel", version = "0.0.0", package = "desk-touchpanel" } 19 | editor-plugin = { path = "../../plugins/desk-editor", version = "0.0.0", package = "desk-editor" } 20 | terminal-plugin = { path = "../../plugins/desk-terminal", version = "0.0.0", package = "desk-terminal" } 21 | playground-plugin = { path = "../../plugins/desk-playground", version = "0.0.0", package = "desk-playground" } 22 | 23 | desk-theme = { workspace = true } 24 | desk-window = { workspace = true } 25 | desk-plugin = { workspace = true } 26 | dworkspace = { workspace = true } 27 | dworkspace-in-memory = { package = "dworkspace-in-memory", path = "../../adapters/dworkspace-in-memory", version = "0.0.0" } 28 | dworkspace-codebase = { package = "dworkspace-codebase", path = "../../components/dworkspace-codebase", version = "0.0.0" } 29 | deskc-ids = { package = "deskc-ids", path = "../../components/deskc-ids", version = "0.0.0" } 30 | 31 | bevy = { workspace = true } 32 | bevy-inspector-egui = { version = "0.18", optional = true } 33 | console_error_panic_hook = "0.1" 34 | web-sys = "0.3" 35 | egui = { workspace = true } 36 | once_cell = { workspace = true } 37 | ron = { workspace = true } 38 | -------------------------------------------------------------------------------- /crates/apps/desk-x/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /crates/apps/desk-x/src/about.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use desk_plugin::DeskSystem; 3 | use dworkspace::Workspace; 4 | 5 | use desk_window::{ 6 | ctx::Ctx, 7 | widget::{Widget, WidgetId}, 8 | window::{DefaultWindow, Window}, 9 | }; 10 | use egui::special_emojis::GITHUB; 11 | 12 | #[derive(Component)] 13 | pub struct About; 14 | 15 | pub struct AboutPlugin; 16 | 17 | impl Plugin for AboutPlugin { 18 | fn build(&self, app: &mut App) { 19 | app.add_system(about.label(DeskSystem::UpdateWidget)); 20 | } 21 | } 22 | 23 | fn about(mut window: Query<(&mut Window, &Workspace), With>) { 24 | if let Ok((mut window, _kernel)) = window.get_single_mut() { 25 | window.add_widget(WidgetId::new(), AboutWidget); 26 | } 27 | } 28 | 29 | struct AboutWidget; 30 | 31 | impl Widget for AboutWidget { 32 | fn render(&mut self, ctx: &mut Ctx) { 33 | egui::Window::new("About").show(&ctx.backend(), |ui| { 34 | ui.hyperlink_to( 35 | format!("{} Hihaheho/Desk", GITHUB), 36 | "https://github.com/Hihaheho/Desk", 37 | ); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /crates/apps/desk-x/src/main.rs: -------------------------------------------------------------------------------- 1 | mod about; 2 | mod panels; 3 | mod theme; 4 | mod windows; 5 | 6 | use std::time::Duration; 7 | 8 | use about::AboutPlugin; 9 | use bevy::{ 10 | diagnostic::FrameTimeDiagnosticsPlugin, 11 | prelude::*, 12 | winit::{UpdateMode, WinitSettings}, 13 | }; 14 | 15 | #[cfg(feature = "inspector")] 16 | use bevy_inspector_egui::WorldInspectorPlugin; 17 | use editor_plugin::EditorPlugin; 18 | use egui_plugin::EguiPlugin; 19 | use panels::PanelsPlugin; 20 | use playground_plugin::PlaygroundPlugin; 21 | // use rapier2d_plugin::PhysicsPlugin; 22 | use terminal_plugin::TerminalPlugin; 23 | use touchpanel_plugin::TouchpanelPlugin; 24 | use windows::WindowsPlugin; 25 | 26 | fn main() { 27 | #[cfg(target_arch = "wasm32")] 28 | console_error_panic_hook::set_once(); 29 | 30 | let mut app = App::new(); 31 | 32 | app.add_plugins(DefaultPlugins) 33 | .add_plugin(EguiPlugin) 34 | // .add_plugin(PhysicsPlugin) 35 | .add_plugin(TouchpanelPlugin) 36 | .add_plugin(EditorPlugin) 37 | .add_plugin(TerminalPlugin) 38 | .add_plugin(WindowsPlugin) 39 | .add_plugin(AboutPlugin) 40 | .add_plugin(PanelsPlugin) 41 | .add_plugin(PlaygroundPlugin) 42 | .add_plugin(FrameTimeDiagnosticsPlugin) 43 | .insert_resource(ClearColor::default()) 44 | .insert_resource(WinitSettings { 45 | focused_mode: UpdateMode::ReactiveLowPower { 46 | max_wait: Duration::from_millis(1000), 47 | }, 48 | unfocused_mode: UpdateMode::ReactiveLowPower { 49 | max_wait: Duration::from_millis(2000), 50 | }, 51 | ..Default::default() 52 | }) 53 | .insert_resource(Msaa { samples: 4 }) 54 | .add_startup_system(setup_cameras); 55 | 56 | #[cfg(target_arch = "wasm32")] 57 | app.add_system(resize); 58 | 59 | #[cfg(feature = "inspector")] 60 | app.add_plugin(WorldInspectorPlugin::new()); 61 | 62 | app.run(); 63 | } 64 | 65 | fn setup_cameras(mut commands: Commands) { 66 | commands.spawn(Camera3dBundle::default()); 67 | } 68 | 69 | #[cfg(target_arch = "wasm32")] 70 | fn resize(mut windows: ResMut) { 71 | let js_window = web_sys::window().unwrap(); 72 | let window = windows.get_primary_mut().unwrap(); 73 | window.set_resolution( 74 | js_window.inner_width().unwrap().as_f64().unwrap() as f32, 75 | js_window.inner_height().unwrap().as_f64().unwrap() as f32, 76 | ); 77 | } 78 | -------------------------------------------------------------------------------- /crates/apps/desk-x/src/theme.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use desk_theme::Theme; 3 | 4 | pub struct ThemePlugin; 5 | 6 | impl Plugin for ThemePlugin { 7 | fn build(&self, app: &mut App) { 8 | app.register_type::() 9 | .add_startup_system(add_theme) 10 | .add_system(theme_changed); 11 | } 12 | } 13 | 14 | fn add_theme(mut commands: Commands) { 15 | commands.spawn(ron::from_str::(include_str!("../../../../configs/theme.ron")).unwrap()); 16 | } 17 | 18 | fn theme_changed( 19 | mut clear_coler: ResMut, 20 | mut theme: Query<&mut Theme, Changed>, 21 | ) { 22 | if let Ok(theme) = theme.get_single() { 23 | #[cfg(not(target_arch = "wasm32"))] 24 | { 25 | let theme_ron = ron::ser::to_string_pretty(theme, Default::default()).unwrap(); 26 | std::fs::write("configs/theme.ron", theme_ron).unwrap(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/apps/desk-x/src/windows.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | 3 | use desk_window::window::{DefaultWindow, Window}; 4 | use dworkspace::{ 5 | prelude::{EventId, EventPayload}, 6 | Workspace, 7 | }; 8 | use dworkspace_codebase::{event::Event, user::UserId}; 9 | use dworkspace_in_memory::InMemoryRepository; 10 | 11 | pub struct WindowsPlugin; 12 | 13 | impl Plugin for WindowsPlugin { 14 | fn build(&self, app: &mut App) { 15 | app.add_startup_system(setup); 16 | } 17 | } 18 | 19 | pub fn setup(mut commands: Commands) { 20 | let user_id = UserId::new(); 21 | let mut kernel = Workspace::new(InMemoryRepository::new(user_id)); 22 | kernel.commit(Event { 23 | id: EventId::new(), 24 | user_id, 25 | payload: EventPayload::AddOwner { user_id }, 26 | }); 27 | commands.spawn((DefaultWindow, Window::::default(), kernel)); 28 | } 29 | -------------------------------------------------------------------------------- /crates/apps/deskc-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-cli" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | -------------------------------------------------------------------------------- /crates/apps/deskc-cli/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /crates/apps/deskc-language-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-language-server" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | -------------------------------------------------------------------------------- /crates/apps/deskc-language-server/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /crates/components/desk-command/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-command" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | 15 | bevy_math = { workspace = true } 16 | bevy_ecs = { workspace = true } 17 | -------------------------------------------------------------------------------- /crates/components/desk-command/src/cursor.rs: -------------------------------------------------------------------------------- 1 | use bevy_ecs::prelude::Component; 2 | 3 | #[derive(Component)] 4 | pub struct Cursor; 5 | -------------------------------------------------------------------------------- /crates/components/desk-command/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod cursor; 2 | pub mod terminal; 3 | -------------------------------------------------------------------------------- /crates/components/desk-command/src/terminal.rs: -------------------------------------------------------------------------------- 1 | use bevy_ecs::prelude::Component; 2 | 3 | #[derive(Component, Debug, Default)] 4 | pub struct Terminal {} 5 | -------------------------------------------------------------------------------- /crates/components/desk-physics/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-physics" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | bevy_math = { workspace = true } 15 | bevy_ecs = { workspace = true } 16 | -------------------------------------------------------------------------------- /crates/components/desk-physics/src/drag_state.rs: -------------------------------------------------------------------------------- 1 | use bevy_ecs::prelude::Component; 2 | 3 | #[derive(Default, Component, Clone, Debug, PartialEq, Eq)] 4 | pub enum DragState { 5 | Dragging, 6 | #[default] 7 | NotDragging, 8 | } 9 | -------------------------------------------------------------------------------- /crates/components/desk-physics/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod drag_state; 2 | mod follow; 3 | pub mod shape; 4 | use std::ops::Add; 5 | 6 | use bevy_ecs::prelude::Component; 7 | use bevy_math::Vec2; 8 | 9 | pub use drag_state::*; 10 | pub use follow::*; 11 | 12 | #[derive(Component, Clone, Debug, PartialEq, Eq, Hash)] 13 | pub struct PhysicalObject; 14 | 15 | #[derive(Component, Clone, Debug, PartialEq, Default)] 16 | pub struct Velocity(pub Vec2); 17 | 18 | impl From for Velocity { 19 | fn from(velocity: Vec2) -> Self { 20 | Velocity(velocity) 21 | } 22 | } 23 | 24 | impl Add for &Velocity { 25 | type Output = Velocity; 26 | 27 | fn add(self, rhs: Vec2) -> Self::Output { 28 | (self.0 + rhs).into() 29 | } 30 | } 31 | 32 | impl Add for &Velocity { 33 | type Output = Velocity; 34 | 35 | fn add(self, rhs: Velocity) -> Self::Output { 36 | (self.0 + rhs.0).into() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /crates/components/desk-physics/src/shape.rs: -------------------------------------------------------------------------------- 1 | use bevy_ecs::prelude::Component; 2 | 3 | #[derive(Default, Component, Clone, Debug, PartialEq)] 4 | #[non_exhaustive] 5 | pub enum Shape { 6 | #[default] 7 | Blank, 8 | Rect { 9 | width: f32, 10 | height: f32, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /crates/components/desk-plugin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-plugin" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | bevy_ecs = { workspace = true } 15 | -------------------------------------------------------------------------------- /crates/components/desk-plugin/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::type_complexity)] 2 | 3 | mod system_labels; 4 | 5 | pub use system_labels::*; 6 | -------------------------------------------------------------------------------- /crates/components/desk-plugin/src/system_labels.rs: -------------------------------------------------------------------------------- 1 | use bevy_ecs::schedule::SystemLabel; 2 | 3 | #[derive(SystemLabel, Clone)] 4 | pub enum DeskSystem { 5 | UpdateWidget, 6 | RenderWidget, 7 | ProcessKernel, 8 | PrePhysics, 9 | } 10 | 11 | #[derive(SystemLabel, Clone)] 12 | pub enum ShellSystem { 13 | Add, 14 | UpdateComponent, 15 | UpdateWidget, 16 | Render, 17 | HandleEvents, 18 | } 19 | -------------------------------------------------------------------------------- /crates/components/desk-theme/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-theme" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | bevy = { workspace = true } 15 | serde = "1.0" 16 | -------------------------------------------------------------------------------- /crates/components/desk-theme/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod colorscheme; 2 | 3 | use bevy::prelude::*; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | #[derive(Component, Reflect, Default, Serialize, Deserialize)] 7 | #[reflect(Component)] 8 | pub struct Theme { 9 | /// hoverred interactive widget 10 | pub hovered: Widget, 11 | /// opened combo box 12 | pub open: Widget, 13 | /// non-interactive widget 14 | pub noninteractive: Widget, 15 | /// inactive widget 16 | pub inactive: Widget, 17 | /// active widget 18 | pub active: Widget, 19 | pub window_background: Color, 20 | pub window_corner_radius: f32, 21 | pub window_shadow: Shadow, 22 | pub extreme_background: Color, 23 | pub background: Color, 24 | } 25 | 26 | #[derive(Reflect, Serialize, Deserialize, Clone, Copy)] 27 | pub struct Stroke { 28 | pub color: Color, 29 | pub size: f32, 30 | } 31 | 32 | impl Default for Stroke { 33 | fn default() -> Self { 34 | Self { 35 | color: Color::BLACK, 36 | size: 1.0, 37 | } 38 | } 39 | } 40 | 41 | #[derive(Clone, Copy, Reflect, Default, Serialize, Deserialize)] 42 | pub struct Shadow { 43 | pub color: Color, 44 | pub extrusion: f32, 45 | } 46 | 47 | #[derive(Reflect, Default, Serialize, Deserialize)] 48 | pub struct Widget { 49 | pub background: Color, 50 | pub border: Stroke, 51 | pub stroke: Stroke, 52 | } 53 | 54 | #[derive(Reflect, Serialize, Deserialize, Clone)] 55 | pub struct EditorStyle { 56 | // How many spaces for each indentation level 57 | pub indent_width: u8, 58 | pub indent_guide: IndentGuide, 59 | pub line_spacing: f32, 60 | pub line_number: bool, 61 | pub cursor_background: Color, 62 | pub cursor_child_background: Color, 63 | pub selected_background: Color, 64 | pub hovered_background: Color, 65 | pub cursor_word_outline: Stroke, 66 | } 67 | 68 | impl Default for EditorStyle { 69 | fn default() -> Self { 70 | Self { 71 | indent_width: 2, 72 | indent_guide: Default::default(), 73 | line_spacing: 0.2, 74 | line_number: true, 75 | cursor_background: Color::rgb_u8(0xEF, 0xAF, 0xE8), 76 | cursor_child_background: Color::rgb_u8(0xFF, 0xDF, 0xF8), 77 | selected_background: Color::rgb_u8(0xD8, 0xA0, 0xE0), 78 | hovered_background: Color::rgb_u8(0xD0, 0xD0, 0xD0), 79 | cursor_word_outline: Stroke { 80 | size: 2.0, 81 | color: Color::rgb_u8(0x10, 0x10, 0x50), 82 | }, 83 | } 84 | } 85 | } 86 | 87 | #[derive(Reflect, Serialize, Deserialize, Clone)] 88 | pub enum IndentGuide { 89 | None, 90 | SingleColorLine { size: f32 }, 91 | } 92 | 93 | impl Default for IndentGuide { 94 | fn default() -> Self { 95 | Self::SingleColorLine { size: 0.2 } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /crates/components/desk-window/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-window" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | dworkspace-codebase = { package = "dworkspace-codebase", version = "0.0.0", path = "../dworkspace-codebase" } 13 | deskc-ids = { package = "deskc-ids", version = "0.0.0", path = "../deskc-ids" } 14 | # FIXME: component depends system 15 | dworkspace = { workspace = true } 16 | 17 | bevy_ecs = { workspace = true } 18 | bevy_math = { workspace = true } 19 | uuid = { workspace = true} 20 | -------------------------------------------------------------------------------- /crates/components/desk-window/src/ctx.rs: -------------------------------------------------------------------------------- 1 | use bevy_math::Vec2; 2 | use dworkspace::Workspace; 3 | use dworkspace_codebase::event::Event; 4 | 5 | pub struct Ctx<'a, Backend> { 6 | pub events: Vec, 7 | pub workspace: &'a mut Workspace, 8 | backend: Backend, 9 | pub offset: &'a mut Vec2, 10 | } 11 | 12 | impl<'a, T: Clone> Ctx<'a, T> { 13 | pub fn new(workspace: &'a mut Workspace, backend: T, offset: &'a mut Vec2) -> Ctx<'a, T> { 14 | Self { 15 | events: Vec::new(), 16 | workspace, 17 | backend, 18 | offset, 19 | } 20 | } 21 | 22 | pub fn add_event(&mut self, event: Event) { 23 | self.events.push(event); 24 | } 25 | 26 | pub fn backend(&self) -> T { 27 | self.backend.clone() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/components/desk-window/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod ctx; 2 | pub mod widget; 3 | pub mod window; 4 | -------------------------------------------------------------------------------- /crates/components/desk-window/src/widget.rs: -------------------------------------------------------------------------------- 1 | use crate::ctx::Ctx; 2 | use uuid::Uuid; 3 | 4 | pub trait Widget { 5 | fn render(&mut self, ctx: &mut Ctx<'_, T>); 6 | } 7 | 8 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] 9 | pub struct WidgetId(pub Uuid); 10 | 11 | impl WidgetId { 12 | pub fn new() -> Self { 13 | Self(Uuid::new_v4()) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /crates/components/desk-window/src/window.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use bevy_ecs::prelude::Component; 4 | use bevy_math::Vec2; 5 | use uuid::Uuid; 6 | 7 | use crate::widget::{Widget, WidgetId}; 8 | 9 | #[derive(Component)] 10 | pub struct DefaultWindow; 11 | 12 | #[derive(Component, Default)] 13 | pub struct Window { 14 | pub offset: Vec2, 15 | widgets: HashMap + Send + Sync + 'static>>, 16 | } 17 | 18 | #[derive(Component, Clone, Debug, PartialEq, Eq, Hash)] 19 | pub struct WindowId(pub Uuid); 20 | 21 | impl Window { 22 | pub fn drain_widgets(&mut self) -> Vec + Send + Sync + 'static>> { 23 | self.widgets.drain().map(|(_, widget)| widget).collect() 24 | } 25 | 26 | pub fn add_widget + Send + Sync + 'static>( 27 | &mut self, 28 | widget_id: WidgetId, 29 | widget: W, 30 | ) { 31 | self.widgets.insert(widget_id, Box::new(widget)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/components/deskc-ast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-ast" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ids = { path = "../deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | dson = { path = "../dson", version = "0.0.0", package = "dson" } 16 | 17 | thiserror = { workspace = true } 18 | downcast-rs = "1.2" 19 | -------------------------------------------------------------------------------- /crates/components/deskc-ast/src/expr.rs: -------------------------------------------------------------------------------- 1 | use dson::Dson; 2 | use ids::CardId; 3 | pub use ids::LinkName; 4 | 5 | use crate::{ 6 | meta::WithMeta, 7 | ty::{Effect, Type}, 8 | }; 9 | 10 | #[derive(Clone, Debug, PartialEq)] 11 | pub enum Literal { 12 | String(String), 13 | Integer(i64), 14 | // b must be unsigned to avoid ambiguity. 15 | Rational(i64, u64), 16 | Real(f64), 17 | } 18 | 19 | // Literal::Real should not be NaN 20 | impl Eq for Literal {} 21 | 22 | #[derive(Clone, Debug, PartialEq, Eq)] 23 | pub struct Handler { 24 | pub effect: WithMeta, 25 | pub handler: WithMeta, 26 | } 27 | 28 | #[derive(Clone, Debug, PartialEq, Eq)] 29 | pub enum Expr { 30 | Literal(Literal), 31 | Do { 32 | stmt: Box>, 33 | expr: Box>, 34 | }, 35 | Let { 36 | definition: Box>, 37 | body: Box>, 38 | }, 39 | Perform { 40 | input: Box>, 41 | output: WithMeta, 42 | }, 43 | Continue { 44 | input: Box>, 45 | output: WithMeta, 46 | }, 47 | Handle { 48 | expr: Box>, 49 | handlers: Vec>, 50 | }, 51 | Apply { 52 | function: WithMeta, 53 | link_name: LinkName, 54 | arguments: Vec>, 55 | }, 56 | Product(Vec>), 57 | Match { 58 | of: Box>, 59 | cases: Vec>, 60 | }, 61 | Typed { 62 | ty: WithMeta, 63 | item: Box>, 64 | }, 65 | Hole, 66 | Function { 67 | parameter: WithMeta, 68 | body: Box>, 69 | }, 70 | Vector(Vec>), 71 | Map(Vec>), 72 | Attributed { 73 | attr: Dson, 74 | item: Box>, 75 | }, 76 | /// Declare ident is a brand of the item. 77 | DeclareBrand { 78 | brand: String, 79 | item: Box>, 80 | }, 81 | Label { 82 | label: String, 83 | item: Box>, 84 | }, 85 | NewType { 86 | ident: String, 87 | ty: WithMeta, 88 | expr: Box>, 89 | }, 90 | Card { 91 | id: CardId, 92 | item: Box>, 93 | next: Box>, 94 | }, 95 | } 96 | 97 | #[derive(Clone, Debug, PartialEq, Eq)] 98 | pub struct MatchCase { 99 | pub ty: WithMeta, 100 | pub expr: WithMeta, 101 | } 102 | 103 | #[derive(Clone, Debug, PartialEq, Eq)] 104 | pub struct MapElem { 105 | pub key: WithMeta, 106 | pub value: WithMeta, 107 | } 108 | -------------------------------------------------------------------------------- /crates/components/deskc-ast/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod dson; 2 | pub mod expr; 3 | pub mod meta; 4 | pub mod remove_span; 5 | pub mod ty; 6 | pub mod visitor; 7 | pub mod parser; 8 | -------------------------------------------------------------------------------- /crates/components/deskc-ast/src/meta.rs: -------------------------------------------------------------------------------- 1 | use ids::NodeId; 2 | 3 | pub type Span = std::ops::Range; 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq)] 6 | pub struct WithMeta { 7 | pub meta: Meta, 8 | pub value: T, 9 | } 10 | 11 | #[derive(Clone, Debug, PartialEq, Eq, Default)] 12 | pub struct Meta { 13 | pub id: NodeId, 14 | pub comments: Comments, 15 | } 16 | 17 | #[derive(Clone, Debug, PartialEq, Eq)] 18 | pub enum Comment { 19 | Line(String), 20 | Block(String), 21 | } 22 | 23 | #[derive(Clone, Debug, PartialEq, Eq, Default)] 24 | pub struct Comments { 25 | pub before: Vec, 26 | pub after: Option, 27 | } 28 | 29 | // This is intended to be used in tests. 30 | pub fn dummy_meta(value: T) -> WithMeta { 31 | WithMeta { 32 | meta: Meta::default(), 33 | value, 34 | } 35 | } 36 | 37 | impl Meta { 38 | pub fn new_no_comments() -> Self { 39 | Self { 40 | id: NodeId::new(), 41 | comments: Default::default(), 42 | } 43 | } 44 | } 45 | 46 | impl From for Meta { 47 | fn from(id: NodeId) -> Self { 48 | Self { 49 | id, 50 | comments: Default::default(), 51 | } 52 | } 53 | } 54 | 55 | impl From> for Comments { 56 | fn from(comments: Vec) -> Self { 57 | Self { 58 | before: comments, 59 | after: None, 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/components/deskc-ast/src/parser.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use downcast_rs::{impl_downcast, DowncastSync}; 4 | use ids::NodeId; 5 | 6 | use crate::{ 7 | expr::Expr, 8 | meta::{Span, WithMeta}, 9 | }; 10 | 11 | pub trait Parser { 12 | type Error; 13 | 14 | fn parse(input: &str) -> Result; 15 | } 16 | 17 | #[derive(Debug, Eq, Clone)] 18 | pub struct ParseResult { 19 | pub expr: Arc>, 20 | pub span_storage: Arc>, 21 | } 22 | 23 | impl PartialEq for ParseResult { 24 | fn eq(&self, other: &Self) -> bool { 25 | self.expr == other.expr && self.span_storage == other.span_storage 26 | } 27 | } 28 | 29 | impl ParseResult { 30 | pub fn new(expr: Arc>, span_storage: T) -> Self { 31 | Self { 32 | expr, 33 | span_storage: Arc::new(Box::new(span_storage)), 34 | } 35 | } 36 | } 37 | 38 | pub trait SpanStorage: std::fmt::Debug + DowncastSync + Sync + Send { 39 | fn calculate_span(&self, id: &NodeId) -> Option; 40 | /// Use `deskc_ast::parser::dyn_eq` for implementation. 41 | fn dyn_eq(&self, other: &dyn SpanStorage) -> bool; 42 | } 43 | 44 | impl_downcast!(sync SpanStorage); 45 | 46 | impl PartialEq for dyn SpanStorage { 47 | fn eq(&self, other: &Self) -> bool { 48 | self.dyn_eq(other) 49 | } 50 | } 51 | 52 | impl Eq for dyn SpanStorage {} 53 | 54 | #[derive(Debug, PartialEq, Eq)] 55 | pub struct DummySpanStorage; 56 | impl SpanStorage for DummySpanStorage { 57 | fn calculate_span(&self, _id: &ids::NodeId) -> Option { 58 | None 59 | } 60 | fn dyn_eq(&self, other: &dyn SpanStorage) -> bool { 61 | dyn_eq(self, other) 62 | } 63 | } 64 | 65 | pub fn dyn_eq(a: &T, b: &dyn SpanStorage) -> bool { 66 | b.downcast_ref::().map_or(false, |b| a == b) 67 | } 68 | -------------------------------------------------------------------------------- /crates/components/deskc-ast/src/remove_span.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | expr::Expr, 3 | meta::{Meta, WithMeta}, 4 | ty::{Effect, Function, Type}, 5 | visitor::{ExprVisitorMut, TypeVisitorMut}, 6 | }; 7 | 8 | // A helper function for testing to remove span information from AST. 9 | pub fn replace_node_id_to_default(expr: &mut WithMeta) { 10 | struct RemoveSpan; 11 | impl ExprVisitorMut for RemoveSpan { 12 | fn visit_meta(&mut self, meta: &mut Meta) { 13 | meta.id = Default::default(); 14 | } 15 | fn visit_type(&mut self, ty: &mut WithMeta) { 16 | replace_node_id_to_default_ty(ty); 17 | } 18 | } 19 | RemoveSpan.visit_expr(expr) 20 | } 21 | 22 | // A helper function for testing to remove span information from AST. 23 | pub fn replace_node_id_to_default_ty(ty: &mut WithMeta) { 24 | struct RemoveSpanTy; 25 | impl TypeVisitorMut for RemoveSpanTy { 26 | fn visit_type(&mut self, ty: &mut WithMeta) { 27 | ty.meta.id = Default::default(); 28 | self.super_visit_type(ty); 29 | } 30 | fn visit_effect(&mut self, effect: &mut WithMeta) { 31 | effect.meta.id = Default::default(); 32 | self.visit_type(&mut effect.value.input); 33 | self.visit_type(&mut effect.value.output); 34 | } 35 | fn visit_trait(&mut self, types: &mut [WithMeta]) { 36 | for ty in types { 37 | ty.meta.id = Default::default(); 38 | self.visit_type(&mut ty.value.parameter); 39 | self.visit_type(&mut ty.value.body); 40 | } 41 | } 42 | fn visit_effect_expr(&mut self, item: &mut WithMeta) { 43 | item.meta.id = Default::default(); 44 | self.super_visit_effect_expr(item); 45 | } 46 | } 47 | RemoveSpanTy.visit_type(ty) 48 | } 49 | -------------------------------------------------------------------------------- /crates/components/deskc-ast/src/ty.rs: -------------------------------------------------------------------------------- 1 | use dson::Dson; 2 | 3 | use crate::meta::WithMeta; 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq)] 6 | pub struct Effect { 7 | pub input: WithMeta, 8 | pub output: WithMeta, 9 | } 10 | 11 | #[derive(Clone, Debug, PartialEq, Eq)] 12 | pub enum Type { 13 | Labeled { 14 | brand: String, 15 | item: Box>, 16 | }, 17 | Real, 18 | Rational, 19 | Integer, 20 | String, 21 | Effectful { 22 | ty: Box>, 23 | effects: WithMeta, 24 | }, 25 | Infer, 26 | Product(Vec>), 27 | Sum(Vec>), 28 | Function(Box), 29 | Vector(Box>), 30 | Map { 31 | key: Box>, 32 | value: Box>, 33 | }, 34 | Let { 35 | variable: String, 36 | definition: Box>, 37 | body: Box>, 38 | }, 39 | Variable(String), 40 | Attributed { 41 | attr: Dson, 42 | ty: Box>, 43 | }, 44 | Forall { 45 | variable: String, 46 | bound: Option>>, 47 | body: Box>, 48 | }, 49 | Exists { 50 | variable: String, 51 | bound: Option>>, 52 | body: Box>, 53 | }, 54 | } 55 | 56 | #[derive(Clone, Debug, PartialEq, Eq)] 57 | pub struct Function { 58 | pub parameter: WithMeta, 59 | pub body: WithMeta, 60 | } 61 | 62 | #[derive(Clone, Debug, PartialEq, Eq)] 63 | pub enum EffectExpr { 64 | Effects(Vec>), 65 | Add(Vec>), 66 | Sub { 67 | minuend: Box>, 68 | subtrahend: Box>, 69 | }, 70 | Apply { 71 | function: Box>, 72 | arguments: Vec>, 73 | }, 74 | } 75 | -------------------------------------------------------------------------------- /crates/components/deskc-errors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-errors" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ty = { path = "../deskc-type", version = "0.0.0", package = "deskc-type" } 15 | hir = { path = "../../components/deskc-hir", version = "0.0.0", package = "deskc-hir" } 16 | ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 17 | 18 | thiserror = { workspace = true } 19 | -------------------------------------------------------------------------------- /crates/components/deskc-errors/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod mirgen; 2 | pub mod syntax; 3 | pub mod textual_diagnostics; 4 | pub mod typeinfer; 5 | -------------------------------------------------------------------------------- /crates/components/deskc-errors/src/mirgen.rs: -------------------------------------------------------------------------------- 1 | use hir::meta::Meta; 2 | use thiserror::Error; 3 | use ty::Type; 4 | 5 | use crate::textual_diagnostics::{Report, TextualDiagnostics}; 6 | 7 | #[derive(Debug, Clone, Error)] 8 | pub enum GenMirError { 9 | #[error("invalid function call {ty:?} with {arguments:?}")] 10 | InvalidFunctionCall { 11 | expr: Meta, 12 | ty: Type, 13 | arguments: Vec, 14 | }, 15 | #[error("type not found {for_expr:?}")] 16 | TypeNotFound { for_expr: Meta }, 17 | #[error("function inferred as non-function {for_expr:?}")] 18 | FunctionInferredAsNonFunction { for_expr: hir::meta::Meta }, 19 | #[error("effectful inferred as non-effectful {for_expr:?}")] 20 | EffectfulInferredAsNonEffectful { for_expr: hir::meta::Meta }, 21 | } 22 | 23 | impl From<&GenMirError> for TextualDiagnostics { 24 | fn from(error: &GenMirError) -> TextualDiagnostics { 25 | match error { 26 | GenMirError::InvalidFunctionCall { 27 | expr, 28 | ty: _, 29 | arguments: _, 30 | } => TextualDiagnostics { 31 | title: "MIR generation error".into(), 32 | reports: vec![Report { 33 | span: todo!(), 34 | text: format!("{error}"), 35 | }], 36 | }, 37 | GenMirError::TypeNotFound { for_expr: meta } => TextualDiagnostics { 38 | title: "MIR generation error".into(), 39 | reports: vec![Report { 40 | span: todo!(), 41 | text: format!("{error}"), 42 | }], 43 | }, 44 | GenMirError::FunctionInferredAsNonFunction { for_expr: meta } => TextualDiagnostics { 45 | title: "MIR generation error".into(), 46 | reports: vec![Report { 47 | span: todo!(), 48 | text: format!("{error}"), 49 | }], 50 | }, 51 | GenMirError::EffectfulInferredAsNonEffectful { for_expr: meta } => TextualDiagnostics { 52 | title: "MIR generation error".into(), 53 | reports: vec![Report { 54 | span: todo!(), 55 | text: format!("{error}"), 56 | }], 57 | }, 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /crates/components/deskc-errors/src/syntax.rs: -------------------------------------------------------------------------------- 1 | use crate::textual_diagnostics::TextualDiagnostics; 2 | use thiserror::Error; 3 | 4 | #[derive(Error, Debug)] 5 | pub enum SyntaxError { 6 | #[error("other error {0}")] 7 | Other(String), 8 | } 9 | 10 | impl From<&SyntaxError> for TextualDiagnostics { 11 | fn from(value: &SyntaxError) -> Self { 12 | match value { 13 | SyntaxError::Other(string) => TextualDiagnostics { 14 | title: string.clone(), 15 | reports: vec![], 16 | }, 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /crates/components/deskc-errors/src/textual_diagnostics.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Range; 2 | 3 | pub struct TextualDiagnostics { 4 | pub title: String, 5 | pub reports: Vec, 6 | } 7 | 8 | pub struct Report { 9 | pub text: String, 10 | pub span: Range, 11 | } 12 | -------------------------------------------------------------------------------- /crates/components/deskc-errors/src/typeinfer.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | 3 | use hir::{expr::Expr, meta::Meta}; 4 | use thiserror::Error; 5 | use ty::{Effect, Type}; 6 | 7 | use crate::textual_diagnostics::{Report, TextualDiagnostics}; 8 | 9 | #[derive(Debug, PartialEq, Eq)] 10 | pub struct ExprTypeError { 11 | pub meta: Meta, 12 | pub error: TypeError, 13 | } 14 | 15 | impl Display for ExprTypeError { 16 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 17 | write!(f, "{:?} {}", self.meta, self.error) 18 | } 19 | } 20 | 21 | impl std::error::Error for ExprTypeError { 22 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 23 | Some(&self.error) 24 | } 25 | } 26 | 27 | #[derive(Debug, PartialEq, Eq)] 28 | pub enum TypeOrString { 29 | Type(Type), 30 | String(String), 31 | } 32 | 33 | #[derive(Error, Debug, PartialEq, Eq)] 34 | pub enum TypeError { 35 | #[error("not applicable {expr:?} {ty:?}")] 36 | NotApplicable { expr: Box, ty: TypeOrString }, 37 | #[error("not subtype {sub:?} {ty:?}")] 38 | NotSubtype { sub: TypeOrString, ty: TypeOrString }, 39 | #[error("circular existential {id:?} {ty:?}")] 40 | CircularExistential { id: usize, ty: TypeOrString }, 41 | #[error("not instantiable subtype {ty:?}")] 42 | NotInstantiableSubtype { ty: TypeOrString }, 43 | #[error("not instantiable supertype {ty:?}")] 44 | NotInstantiableSupertype { ty: TypeOrString }, 45 | #[error("variable not typed {id}")] 46 | VariableNotTyped { id: usize }, 47 | #[error("unknown effect handled: {effect:?}")] 48 | UnknownEffectHandled { effect: Effect }, 49 | #[error("continue out of handle")] 50 | ContinueOutOfHandle, 51 | #[error("existential not instansiated {id}")] 52 | ExistentialNotInstansiated { id: usize }, 53 | #[error("not inferred {id:?}")] 54 | NotInferred { id: ids::NodeId }, 55 | #[error("ambiguous subtype {sub:?} {ty:?}")] 56 | AmbiguousSubtype { sub: TypeOrString, ty: TypeOrString }, 57 | #[error("sum subtype {sub_ty:?} has unsufficent elements to supertype {super_ty:?}")] 58 | SumInsufficentElements { 59 | sub_ty: Vec, 60 | super_ty: Vec, 61 | }, 62 | #[error("product supertype {super_ty:?} has unsufficent elements to subtype {sub_ty:?}")] 63 | ProductInsufficentElements { 64 | sub_ty: Vec, 65 | super_ty: Vec, 66 | }, 67 | } 68 | 69 | impl From<&ExprTypeError> for TextualDiagnostics { 70 | fn from(error: &ExprTypeError) -> TextualDiagnostics { 71 | TextualDiagnostics { 72 | title: "Typeinfer error".into(), 73 | reports: vec![Report { 74 | span: todo!(), 75 | text: format!("{:?}", error.error), 76 | }], 77 | } 78 | } 79 | } 80 | 81 | impl From for TypeOrString { 82 | fn from(ty: Type) -> Self { 83 | Self::Type(ty) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /crates/components/deskc-hir/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-hir" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ids = { path = "../deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | dson = { path = "../dson", version = "0.0.0", package = "dson" } 16 | -------------------------------------------------------------------------------- /crates/components/deskc-hir/src/expr.rs: -------------------------------------------------------------------------------- 1 | use dson::Dson; 2 | pub use ids::LinkName; 3 | 4 | use crate::{ 5 | meta::WithMeta, 6 | ty::{Effect, Type}, 7 | }; 8 | 9 | #[derive(Clone, Debug, PartialEq)] 10 | pub enum Literal { 11 | String(String), 12 | Integer(i64), 13 | // b must be unsigned to avoid ambiguity. 14 | Rational(i64, u64), 15 | Real(f64), 16 | } 17 | 18 | // Literal::Real should not be NaN 19 | impl Eq for Literal {} 20 | 21 | #[derive(Clone, Debug, PartialEq, Eq)] 22 | pub struct Handler { 23 | pub effect: Effect, 24 | pub handler: WithMeta, 25 | } 26 | 27 | #[derive(Clone, Debug, PartialEq, Eq)] 28 | pub enum Expr { 29 | Literal(Literal), 30 | Do { 31 | stmt: Box>, 32 | expr: Box>, 33 | }, 34 | Let { 35 | definition: Box>, 36 | expr: Box>, 37 | }, 38 | Perform { 39 | input: Box>, 40 | output: WithMeta, 41 | }, 42 | Continue { 43 | input: Box>, 44 | output: WithMeta, 45 | }, 46 | Handle { 47 | handlers: Vec>, 48 | expr: Box>, 49 | }, 50 | Apply { 51 | function: WithMeta, 52 | link_name: LinkName, 53 | arguments: Vec>, 54 | }, 55 | Product(Vec>), 56 | Match { 57 | of: Box>, 58 | cases: Vec>, 59 | }, 60 | Typed { 61 | ty: WithMeta, 62 | item: Box>, 63 | }, 64 | Function { 65 | parameter: WithMeta, 66 | body: Box>, 67 | }, 68 | Vector(Vec>), 69 | Map(Vec>), 70 | Label { 71 | label: String, 72 | item: Box>, 73 | }, 74 | Brand { 75 | brand: String, 76 | item: Box>, 77 | }, 78 | } 79 | 80 | #[derive(Clone, Debug, PartialEq, Eq)] 81 | pub struct MatchCase { 82 | pub ty: WithMeta, 83 | pub expr: WithMeta, 84 | } 85 | 86 | #[derive(Clone, Debug, PartialEq, Eq)] 87 | pub struct MapElem { 88 | pub key: WithMeta, 89 | pub value: WithMeta, 90 | } 91 | -------------------------------------------------------------------------------- /crates/components/deskc-hir/src/lib.rs: -------------------------------------------------------------------------------- 1 | use expr::Expr; 2 | use ids::CardId; 3 | use meta::WithMeta; 4 | 5 | pub mod expr; 6 | mod list_ids; 7 | pub mod meta; 8 | pub mod ty; 9 | pub mod visitor; 10 | 11 | #[derive(Debug, Clone, PartialEq, Eq)] 12 | pub struct Cards { 13 | pub cards: Vec, 14 | pub file: WithMeta, 15 | } 16 | 17 | #[derive(Debug, Clone, PartialEq, Eq)] 18 | pub struct Card { 19 | pub id: CardId, 20 | pub hir: WithMeta, 21 | } 22 | -------------------------------------------------------------------------------- /crates/components/deskc-hir/src/list_ids.rs: -------------------------------------------------------------------------------- 1 | use ids::NodeId; 2 | 3 | use crate::{ 4 | expr::Expr, 5 | meta::WithMeta, 6 | visitor::{HirVisitor, TypeVisitor}, 7 | }; 8 | 9 | impl WithMeta { 10 | pub fn get_expr_ids(&self) -> impl Iterator { 11 | struct ExprIds { 12 | ids: Vec, 13 | } 14 | impl HirVisitor for ExprIds { 15 | fn visit_expr(&mut self, expr: &WithMeta) { 16 | self.ids.push(expr.meta.id.clone()); 17 | self.super_visit_expr(expr); 18 | } 19 | fn visit_type(&mut self, ty: &WithMeta) { 20 | TypeVisitor::visit_type(self, ty); 21 | } 22 | } 23 | impl TypeVisitor for ExprIds { 24 | fn visit_type(&mut self, ty: &WithMeta) { 25 | self.ids.push(ty.meta.id.clone()); 26 | self.super_visit_type(ty); 27 | } 28 | } 29 | let mut ids = ExprIds { ids: Vec::new() }; 30 | ids.visit_expr(self); 31 | ids.ids.into_iter() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/components/deskc-hir/src/meta.rs: -------------------------------------------------------------------------------- 1 | use dson::Dson; 2 | use ids::NodeId; 3 | 4 | #[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] 5 | pub struct Meta { 6 | pub id: NodeId, 7 | pub attrs: Vec, 8 | } 9 | 10 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 11 | pub struct WithMeta { 12 | pub meta: Meta, 13 | pub value: T, 14 | } 15 | 16 | // This is intended to be used in tests. 17 | pub fn dummy_meta(value: T) -> WithMeta { 18 | WithMeta { 19 | meta: Meta::default(), 20 | value, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /crates/components/deskc-hir/src/ty.rs: -------------------------------------------------------------------------------- 1 | use dson::Dson; 2 | 3 | use crate::meta::WithMeta; 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 6 | pub struct Handler { 7 | pub input: WithMeta, 8 | pub output: WithMeta, 9 | } 10 | 11 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 12 | pub struct Effect { 13 | pub input: WithMeta, 14 | pub output: WithMeta, 15 | } 16 | 17 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 18 | pub enum Type { 19 | Real, 20 | Rational, 21 | Integer, 22 | String, 23 | Effectful { 24 | ty: Box>, 25 | effects: WithMeta, 26 | }, 27 | Infer, 28 | Product(Vec>), 29 | Sum(Vec>), 30 | Function(Box), 31 | Vector(Box>), 32 | Map { 33 | key: Box>, 34 | value: Box>, 35 | }, 36 | Let { 37 | variable: String, 38 | // definition: Box>, 39 | body: Box>, 40 | definition: Box>, 41 | }, 42 | Variable(String), 43 | Brand { 44 | brand: String, 45 | item: Box>, 46 | }, 47 | // just label brand 48 | Label { 49 | label: String, 50 | item: Box>, 51 | }, 52 | Forall { 53 | variable: String, 54 | bound: Option>>, 55 | body: Box>, 56 | }, 57 | Exists { 58 | variable: String, 59 | bound: Option>>, 60 | body: Box>, 61 | }, 62 | } 63 | 64 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 65 | pub struct Function { 66 | pub parameter: WithMeta, 67 | pub body: WithMeta, 68 | } 69 | 70 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 71 | pub enum EffectExpr { 72 | Effects(Vec>), 73 | Add(Vec>), 74 | Sub { 75 | minuend: Box>, 76 | subtrahend: Box>, 77 | }, 78 | Apply { 79 | function: Box>, 80 | arguments: Vec>, 81 | }, 82 | } 83 | -------------------------------------------------------------------------------- /crates/components/deskc-ids/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-ids" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | uuid = { version = "1.3", features = ["v4", "serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | -------------------------------------------------------------------------------- /crates/components/deskc-ids/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use uuid::Uuid; 3 | 4 | #[derive(Clone, Copy, Debug, PartialEq, Hash, Eq, Serialize, Deserialize)] 5 | pub enum LinkName { 6 | None, 7 | Version(Uuid), 8 | Card(Uuid), 9 | } 10 | 11 | impl Default for LinkName { 12 | fn default() -> Self { 13 | LinkName::None 14 | } 15 | } 16 | 17 | #[derive(Clone, Debug, PartialEq, Hash, Eq, Serialize, Deserialize)] 18 | pub struct LinkId { 19 | pub ty: Type, 20 | pub name: LinkName, 21 | } 22 | 23 | #[derive( 24 | Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize, 25 | )] 26 | pub struct FileId(pub Uuid); 27 | 28 | #[derive( 29 | Clone, Copy, Debug, PartialEq, Hash, Eq, PartialOrd, Ord, Default, Serialize, Deserialize, 30 | )] 31 | pub struct CardId(pub Uuid); 32 | 33 | #[derive( 34 | Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize, 35 | )] 36 | pub struct NodeId(pub Uuid); 37 | 38 | impl NodeId { 39 | pub fn new() -> Self { 40 | NodeId(Uuid::new_v4()) 41 | } 42 | } 43 | 44 | impl CardId { 45 | pub fn new() -> Self { 46 | CardId(Uuid::new_v4()) 47 | } 48 | } 49 | 50 | impl FileId { 51 | pub fn new() -> Self { 52 | FileId(Uuid::new_v4()) 53 | } 54 | } 55 | 56 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] 57 | pub enum Entrypoint { 58 | Card { file_id: FileId, card_id: CardId }, 59 | File(FileId), 60 | } 61 | 62 | impl Entrypoint { 63 | pub fn file_id(&self) -> &FileId { 64 | match self { 65 | Entrypoint::Card { file_id, .. } => file_id, 66 | Entrypoint::File(file_id) => file_id, 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /crates/components/deskc-mir/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-mir" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | ty = { path = "../deskc-type", version = "0.0.0", package = "deskc-type" } 13 | ids = { path = "../deskc-ids", version = "0.0.0", package = "deskc-ids" } 14 | serde = { version = "1.0", features = ["derive"] } 15 | -------------------------------------------------------------------------------- /crates/components/deskc-mir/src/block.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use ty::Type; 3 | 4 | use crate::stmt::{Stmt, StmtBind, Terminator}; 5 | 6 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 7 | pub struct BasicBlock { 8 | pub stmts: Vec>, 9 | pub terminator: Terminator, 10 | } 11 | 12 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] 13 | pub struct BlockId(pub usize); 14 | -------------------------------------------------------------------------------- /crates/components/deskc-mir/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod block; 2 | pub mod mir; 3 | pub mod scope; 4 | pub mod stmt; 5 | pub mod var; 6 | -------------------------------------------------------------------------------- /crates/components/deskc-mir/src/mir.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use ty::Type; 3 | 4 | use crate::{block::BasicBlock, scope::Scope, stmt::LinkId, var::Vars}; 5 | 6 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 7 | pub struct ControlFlowGraph { 8 | // function parameter 9 | pub parameter: Option, 10 | // implicit parameters that captured from outer scope. 11 | pub captured: Vec, 12 | pub output: Type, 13 | // first N items in vars are arguments. 14 | pub vars: Vars, 15 | pub scopes: Vec, 16 | pub blocks: Vec, 17 | pub links: Vec, 18 | } 19 | 20 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] 21 | pub struct ControlFlowGraphId(pub usize); 22 | 23 | #[derive(Clone, Debug, PartialEq, Eq)] 24 | /// Mir -> CFGs -> Blocks -> Stmts 25 | pub struct Mir { 26 | pub entrypoint: ControlFlowGraphId, 27 | pub cfgs: Vec, 28 | } 29 | 30 | impl ControlFlowGraph { 31 | pub fn get_type(&self) -> &Type { 32 | &self.output 33 | } 34 | } 35 | 36 | impl Mir { 37 | pub fn captured(&self) -> &[Type] { 38 | &self.cfgs[self.entrypoint.0].captured 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /crates/components/deskc-mir/src/scope.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] 4 | pub struct ScopeId(pub usize); 5 | 6 | #[derive(Clone, Debug, PartialEq, Default, Eq, Serialize, Deserialize)] 7 | pub struct Scope { 8 | pub super_scope: Option, 9 | } 10 | -------------------------------------------------------------------------------- /crates/components/deskc-mir/src/stmt.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use ids::LinkName; 4 | use serde::{Deserialize, Serialize}; 5 | use ty::{Effect, Type}; 6 | 7 | use crate::{block::BlockId, mir::ControlFlowGraphId, var::VarId}; 8 | 9 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 10 | pub struct StmtBind { 11 | pub var: VarId, 12 | pub stmt: T, 13 | } 14 | 15 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 16 | pub enum Stmt { 17 | Const(Const), 18 | Product(Vec), 19 | Vector(Vec), 20 | Map(Vec), 21 | Fn(Closure), 22 | Perform(VarId), 23 | MatchResult(VarId), 24 | Apply { 25 | function: VarId, 26 | arguments: Vec, 27 | }, 28 | /// Used when cast is required such as `* A, B` to `A` or `A` to `+ A, B`. 29 | /// An implementation of MIR generator may generate redundant `Cast` stmt. 30 | Cast(VarId), 31 | Parameter, 32 | Recursion, 33 | Link(LinkName), 34 | } 35 | 36 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 37 | pub struct MapElem { 38 | pub key: VarId, 39 | pub value: VarId, 40 | } 41 | 42 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 43 | pub struct Closure { 44 | pub mir: ControlFlowGraphId, 45 | /// Caputerd variables 46 | pub captured: Vec, 47 | /// Used to create an effectful expression 48 | pub handlers: HashMap, 49 | } 50 | 51 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 52 | pub enum Const { 53 | Int(i64), 54 | // b must be unsigned to avoid ambiguity. 55 | Rational(i64, u64), 56 | Real(f64), 57 | String(String), 58 | } 59 | 60 | // Const::Real should not be NaN 61 | impl Eq for Const {} 62 | 63 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 64 | pub enum Op { 65 | Add, 66 | Sub, 67 | Mul, 68 | Div, 69 | Rem, 70 | Mod, 71 | Pow, 72 | Eq, 73 | Neq, 74 | Lt, 75 | Le, 76 | Gt, 77 | Ge, 78 | Not, 79 | Neg, 80 | Pos, 81 | Shl, 82 | Shr, 83 | BitAnd, 84 | BitOr, 85 | BitXor, 86 | BitNot, 87 | } 88 | 89 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 90 | pub struct MatchCase { 91 | pub ty: T, 92 | pub next: BlockId, 93 | } 94 | 95 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 96 | pub enum Terminator { 97 | Return(VarId), 98 | Match { 99 | var: VarId, 100 | cases: Vec>, 101 | }, 102 | Goto(BlockId), 103 | } 104 | 105 | pub type LinkId = ids::LinkId; 106 | -------------------------------------------------------------------------------- /crates/components/deskc-mir/src/var.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use ty::Type; 3 | 4 | use crate::scope::ScopeId; 5 | 6 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] 7 | pub struct VarId(pub usize); 8 | 9 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 10 | pub struct Var { 11 | pub ty: T, 12 | pub scope: ScopeId, 13 | } 14 | 15 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 16 | pub struct Vars(pub Vec>); 17 | 18 | impl Vars { 19 | pub fn get(&self, id: &VarId) -> &Var { 20 | &self.0[id.0] 21 | } 22 | 23 | pub fn get_mut(&mut self, id: &VarId) -> &mut Var { 24 | &mut self.0[id.0] 25 | } 26 | 27 | pub fn add_new_var(&mut self, scope: ScopeId, ty: T) -> VarId { 28 | let id = VarId(self.0.len()); 29 | self.0.push(Var { ty, scope }); 30 | id 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/components/deskc-type/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-type" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | ids = { path = "../deskc-ids", version = "0.0.0", package = "deskc-ids" } 13 | dson = { path = "../dson", version = "0.0.0", package = "dson" } 14 | serde = { version = "1.0", features = ["derive"] } 15 | -------------------------------------------------------------------------------- /crates/components/deskc-type/src/conclusion.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use ids::NodeId; 4 | 5 | use crate::Type; 6 | 7 | #[derive(Clone, Debug, PartialEq, Eq, Default)] 8 | pub struct TypeConclusions { 9 | pub types: HashMap, 10 | pub cast_strategies: HashMap, 11 | } 12 | 13 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 14 | pub struct TypeToType { 15 | pub from: Type, 16 | pub to: Type, 17 | } 18 | 19 | #[derive(Clone, Debug, PartialEq, Eq)] 20 | pub enum CastStrategy { 21 | ProductToProduct(HashMap), 22 | SumToSum(HashMap), 23 | ProductToInner(Type), 24 | InnerToSum(Type), 25 | } 26 | 27 | impl TypeConclusions { 28 | pub fn get_type(&self, id: &NodeId) -> Option<&Type> { 29 | self.types.get(id) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/components/deskc-type/src/conversions.rs: -------------------------------------------------------------------------------- 1 | use dson::Dson; 2 | 3 | pub trait DsonTypeDeduction { 4 | fn deduct_type(&self) -> crate::Type; 5 | } 6 | 7 | impl DsonTypeDeduction for Dson { 8 | fn deduct_type(&self) -> crate::Type { 9 | match self { 10 | Dson::Literal(literal) => match literal { 11 | dson::Literal::String(_) => crate::Type::String, 12 | dson::Literal::Integer(_) => crate::Type::Integer, 13 | dson::Literal::Rational(_, _) => crate::Type::Rational, 14 | dson::Literal::Real(_) => crate::Type::Real, 15 | }, 16 | Dson::Product(dsons) => todo!(), 17 | Dson::Vector(dsons) => todo!(), 18 | Dson::Map(elems) => todo!(), 19 | Dson::Attributed { attr, expr } => todo!(), 20 | Dson::Labeled { label, expr } => todo!(), 21 | Dson::Typed { ty, expr } => todo!(), 22 | Dson::Comment { text, expr } => todo!(), 23 | } 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use dson::Real; 30 | 31 | use super::*; 32 | 33 | #[test] 34 | fn test_dson_type_string() { 35 | let dson = Dson::Literal(dson::Literal::String("hello".to_string())); 36 | assert_eq!(dson.deduct_type(), crate::Type::String); 37 | } 38 | 39 | #[test] 40 | fn test_dson_type_integer() { 41 | let dson = Dson::Literal(dson::Literal::Integer(42)); 42 | assert_eq!(dson.deduct_type(), crate::Type::Integer); 43 | } 44 | 45 | #[test] 46 | fn test_dson_type_rational() { 47 | let dson = Dson::Literal(dson::Literal::Rational(1, 2)); 48 | assert_eq!(dson.deduct_type(), crate::Type::Rational); 49 | } 50 | 51 | #[test] 52 | fn test_dson_type_real() { 53 | let dson = Dson::Literal(dson::Literal::Real(Real(3.14))); 54 | assert_eq!(dson.deduct_type(), crate::Type::Real); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskvm-dprocess" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 15 | 16 | anyhow = "1.0" 17 | uuid = { version = "1.3", features = ["v4"] } 18 | parking_lot = { workspace = true } 19 | mry = "0.2.6" 20 | serde = { version = "1.0", features = ["derive"] } 21 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/id.rs: -------------------------------------------------------------------------------- 1 | use uuid::Uuid; 2 | 3 | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] 4 | pub struct DProcessId(pub Uuid); 5 | 6 | impl DProcessId { 7 | pub fn new() -> Self { 8 | Self(Uuid::new_v4()) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/mod.rs: -------------------------------------------------------------------------------- 1 | mod id; 2 | mod links; 3 | mod monitors; 4 | mod new; 5 | mod read_locks; 6 | mod receive_message; 7 | mod reduce; 8 | mod reset; 9 | mod status; 10 | mod update_processor_attachment; 11 | mod write_locks; 12 | 13 | pub use id::DProcessId; 14 | use std::collections::{HashMap, HashSet, VecDeque}; 15 | 16 | use parking_lot::RwLock; 17 | use ty::Type; 18 | 19 | use crate::{ 20 | effect_handler::EffectHandlers, flags::DProcessFlags, interpreter::Interpreter, metas::Metas, 21 | processor_attachment::ProcessorAttachment, status::DProcessStatus, timer::Timer, value::Value, 22 | }; 23 | 24 | /// A d-process owns a set of resources and can be scheduled on a processor. 25 | /// 26 | /// Heavily inspired by the C struct of Erlang process. 27 | #[derive(Debug)] 28 | // RwLock members are not public to prevent deadlocks. 29 | // Don't reorder members to keep the same order as in the lock methods. 30 | pub struct DProcess { 31 | pub id: DProcessId, 32 | /// An interpreter. 33 | interpreter: RwLock>, 34 | /// Metadatas mainly used by the scheduler. 35 | metas: RwLock, 36 | /// Effect handlers for this d-process. 37 | effect_handlers: RwLock, 38 | /// The status of this d-process. 39 | status: RwLock, 40 | /// Received messages. 41 | mailbox: RwLock>>, 42 | /// Which processor is this d-process attached to. 43 | processor_attachment: RwLock, 44 | /// A key-value store for this d-process. 45 | kv: RwLock>, 46 | /// This d-process's flags. 47 | flags: RwLock, 48 | /// Attached timers with the name of the counter used for the label of the event. 49 | timers: RwLock>, 50 | /// A set of d-process ids that are monitoring this d-process. 51 | monitors: RwLock>, 52 | links: RwLock>, 53 | } 54 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/monitors.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use ty::Type; 4 | 5 | use crate::{ 6 | status::{DProcessStatus, LinkExit}, 7 | value::Value, 8 | }; 9 | 10 | use super::{DProcess, DProcessId}; 11 | 12 | impl DProcess { 13 | pub fn add_monitor(&self, monitor: &DProcess) { 14 | match &*self.read_status() { 15 | DProcessStatus::Returned(value) => { 16 | monitor.notify_down(DownMessage { 17 | from: self.id.clone(), 18 | payload: DownPayload::Returned(value.clone()), 19 | }); 20 | } 21 | DProcessStatus::Crashed(_) => { 22 | monitor.notify_down(DownMessage { 23 | from: self.id.clone(), 24 | payload: DownPayload::Crashed, 25 | }); 26 | } 27 | DProcessStatus::Halted { ty, reason } => { 28 | monitor.notify_down(DownMessage { 29 | from: self.id.clone(), 30 | payload: DownPayload::Halted { 31 | ty: ty.clone(), 32 | reason: reason.clone(), 33 | }, 34 | }); 35 | } 36 | _ => { 37 | let mut monitors = self.lock_monitors(); 38 | monitors.insert(monitor.id.clone()); 39 | } 40 | } 41 | } 42 | 43 | pub fn remove_monitor(&self, monitor: &DProcessId) { 44 | let mut monitors = self.lock_monitors(); 45 | monitors.remove(monitor); 46 | } 47 | 48 | pub fn notify_down(&self, _message: DownMessage) { 49 | todo!() 50 | } 51 | } 52 | 53 | #[derive(Debug, Clone)] 54 | pub struct DownMessage { 55 | pub from: DProcessId, 56 | pub payload: DownPayload, 57 | } 58 | 59 | #[derive(Debug, Clone)] 60 | pub enum DownPayload { 61 | Returned(Arc), 62 | Crashed, 63 | Halted { ty: Arc, reason: Arc }, 64 | NotFound, 65 | LinkExit(LinkExit), 66 | } 67 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/new.rs: -------------------------------------------------------------------------------- 1 | use parking_lot::RwLock; 2 | 3 | use crate::dprocess_manifest::DProcessManifest; 4 | 5 | use super::{DProcess, DProcessId}; 6 | 7 | impl DProcess { 8 | pub fn new(manifest: &DProcessManifest) -> Self { 9 | Self { 10 | id: DProcessId::new(), 11 | interpreter: RwLock::new(manifest.interpreter_builder.build()), 12 | metas: RwLock::new(manifest.metas.clone()), 13 | effect_handlers: RwLock::new(manifest.effect_handlers.clone()), 14 | status: Default::default(), 15 | mailbox: Default::default(), 16 | processor_attachment: Default::default(), 17 | kv: Default::default(), 18 | flags: Default::default(), 19 | timers: Default::default(), 20 | monitors: Default::default(), 21 | links: Default::default(), 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/read_locks.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{HashMap, HashSet, VecDeque}, 3 | ops::Deref, 4 | }; 5 | 6 | use ty::Type; 7 | 8 | use crate::{ 9 | effect_handler::EffectHandlers, flags::DProcessFlags, interpreter::Interpreter, metas::Metas, 10 | processor_attachment::ProcessorAttachment, status::DProcessStatus, timer::Timer, value::Value, 11 | }; 12 | 13 | use super::{DProcess, DProcessId}; 14 | 15 | /// Read locks. 16 | impl DProcess { 17 | /// Locks the interpreter for reading. 18 | pub fn read_interpreter(&self) -> impl Deref> + '_ { 19 | self.interpreter.read() 20 | } 21 | 22 | /// Locks the metas for reading. 23 | pub fn read_metas(&self) -> impl Deref + '_ { 24 | self.metas.read() 25 | } 26 | 27 | /// Locks the effect handlers for reading. 28 | pub fn read_effect_handlers(&self) -> impl Deref + '_ { 29 | self.effect_handlers.read() 30 | } 31 | 32 | /// Locks the status for reading. 33 | pub fn read_status(&self) -> impl Deref + '_ { 34 | self.status.read() 35 | } 36 | 37 | /// Locks the mailbox for reading. 38 | pub fn read_mailbox(&self) -> impl Deref>> + '_ { 39 | self.mailbox.read() 40 | } 41 | 42 | /// Locks the processor attachment for reading. 43 | pub fn read_processor_attachment(&self) -> impl Deref + '_ { 44 | self.processor_attachment.read() 45 | } 46 | 47 | /// Locks the kv for reading. 48 | pub fn read_kv(&self) -> impl Deref> + '_ { 49 | self.kv.read() 50 | } 51 | 52 | /// Locks the flags for reading. 53 | pub fn read_flags(&self) -> impl Deref + '_ { 54 | self.flags.read() 55 | } 56 | 57 | /// Locks the timers for reading. 58 | pub fn read_timers(&self) -> impl Deref> + '_ { 59 | self.timers.read() 60 | } 61 | 62 | /// Locks the monitors for reading. 63 | pub fn read_monitors(&self) -> impl Deref> + '_ { 64 | self.monitors.read() 65 | } 66 | 67 | /// Locks the links for reading. 68 | pub fn read_links(&self) -> impl Deref> + '_ { 69 | self.links.read() 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/receive_message.rs: -------------------------------------------------------------------------------- 1 | use ty::Type; 2 | 3 | use crate::{status::DProcessStatus, value::Value, vm_ref::VmRef}; 4 | 5 | use super::DProcess; 6 | 7 | impl DProcess { 8 | pub fn receive_message(&self, vm: VmRef, ty: Type, value: Value) { 9 | let (mut interpreter, mut status, mut mailbox) = self.lock_interpreter_status_mailbox(); 10 | if let DProcessStatus::WaitingForMessage(waiting_for) = &*status { 11 | if **waiting_for == ty { 12 | interpreter.effect_output(value); 13 | self.update_status(vm, &mut status, DProcessStatus::Running); 14 | return; 15 | } 16 | } 17 | mailbox.entry(ty).or_default().push_back(value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/reset.rs: -------------------------------------------------------------------------------- 1 | use crate::{interpreter_builder::InterpreterBuilder, status::DProcessStatus, vm_ref::VmRef}; 2 | 3 | use super::DProcess; 4 | 5 | impl DProcess { 6 | /// Replaces the current interpreter with new one. 7 | /// 8 | /// Reset is preferred over loop because it's hot-reloading. 9 | pub fn reset(&self, vm: VmRef, interpreter_builder: Box) { 10 | let (mut interpreter, mut status) = self.lock_interpreter_and_status(); 11 | *interpreter = interpreter_builder.build(); 12 | self.update_status(vm, &mut status, DProcessStatus::Running); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/status.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | status::{DProcessStatus, LinkExit}, 3 | vm_ref::VmRef, 4 | }; 5 | 6 | use super::{ 7 | monitors::{DownMessage, DownPayload}, 8 | DProcess, 9 | }; 10 | 11 | impl DProcess { 12 | // Don't lock the status in this method to prevent invalid status. 13 | /// Pass the lock of status 14 | pub fn update_status(&self, vm: VmRef, locked: &mut DProcessStatus, status: DProcessStatus) { 15 | *locked = status; 16 | let notify_to_monitors = |payload: DownPayload| { 17 | self.read_monitors() 18 | .iter() 19 | .filter_map(|id| vm.get_dprocess(id)) 20 | .for_each(|monitor| { 21 | monitor.notify_down(DownMessage { 22 | from: self.id.clone(), 23 | payload: payload.clone(), 24 | }); 25 | }); 26 | }; 27 | let notify_to_links = |link_exit: LinkExit| { 28 | self.read_links() 29 | .iter() 30 | .filter_map(|id| vm.get_dprocess(id)) 31 | .for_each(|link| { 32 | link.update_status( 33 | vm, 34 | &mut link.lock_status(), 35 | DProcessStatus::HaltedByLink(link_exit.clone()), 36 | ); 37 | }); 38 | }; 39 | match locked { 40 | DProcessStatus::Returned(value) => { 41 | notify_to_monitors(DownPayload::Returned(value.clone())); 42 | } 43 | DProcessStatus::Halted { ty, reason } => { 44 | notify_to_monitors(DownPayload::Halted { 45 | ty: ty.clone(), 46 | reason: reason.clone(), 47 | }); 48 | notify_to_links(LinkExit::Halted { 49 | dprocess_id: self.id.clone(), 50 | ty: ty.clone(), 51 | reason: reason.clone(), 52 | }); 53 | } 54 | DProcessStatus::Crashed(err) => { 55 | notify_to_monitors(DownPayload::Crashed); 56 | notify_to_links(LinkExit::Crashed { 57 | dprocess_id: self.id.clone(), 58 | error: err.clone(), 59 | }); 60 | } 61 | DProcessStatus::HaltedByLink(link_exit) => { 62 | notify_to_monitors(DownPayload::LinkExit(link_exit.clone())); 63 | notify_to_links(link_exit.clone()); 64 | } 65 | _ => {} 66 | } 67 | // Important! notify to VM's migration logic. 68 | vm.notify_status(self, locked); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/update_processor_attachment.rs: -------------------------------------------------------------------------------- 1 | use crate::processor_attachment::ProcessorAttachment; 2 | 3 | use super::DProcess; 4 | 5 | impl DProcess { 6 | pub fn update_processor_attachment(&self, new_processor_attachment: ProcessorAttachment) { 7 | *self.processor_attachment.write() = new_processor_attachment; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess/write_locks.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{HashMap, HashSet, VecDeque}, 3 | ops::DerefMut, 4 | }; 5 | 6 | use ty::Type; 7 | 8 | use crate::{ 9 | flags::DProcessFlags, interpreter::Interpreter, status::DProcessStatus, timer::Timer, 10 | value::Value, 11 | }; 12 | 13 | use super::{DProcess, DProcessId}; 14 | 15 | // These must be private to prevent deadlocks. 16 | impl DProcess { 17 | pub(crate) fn lock_interpreter_and_status( 18 | &self, 19 | ) -> ( 20 | impl DerefMut> + '_, 21 | impl DerefMut + '_, 22 | ) { 23 | // This order must be the same as DProcess's definition to avoid deadlock. 24 | (self.interpreter.write(), self.status.write()) 25 | } 26 | 27 | pub(crate) fn lock_interpreter_status_mailbox( 28 | &self, 29 | ) -> ( 30 | impl DerefMut> + '_, 31 | impl DerefMut + '_, 32 | impl DerefMut>> + '_, 33 | ) { 34 | // This order must be the same as DProcess's definition to avoid deadlock. 35 | ( 36 | self.interpreter.write(), 37 | self.status.write(), 38 | self.mailbox.write(), 39 | ) 40 | } 41 | 42 | pub(crate) fn lock_interpreter(&self) -> impl DerefMut> + '_ { 43 | self.interpreter.write() 44 | } 45 | 46 | pub(crate) fn lock_status(&self) -> impl DerefMut + '_ { 47 | self.status.write() 48 | } 49 | 50 | pub(crate) fn lock_mailbox( 51 | &self, 52 | ) -> impl DerefMut>> + '_ { 53 | self.mailbox.write() 54 | } 55 | 56 | pub(crate) fn lock_kv(&self) -> impl DerefMut> + '_ { 57 | self.kv.write() 58 | } 59 | 60 | pub(crate) fn lock_flags(&self) -> impl DerefMut + '_ { 61 | self.flags.write() 62 | } 63 | 64 | pub(crate) fn lock_timers(&self) -> impl DerefMut> + '_ { 65 | self.timers.write() 66 | } 67 | 68 | pub(crate) fn lock_monitors(&self) -> impl DerefMut> + '_ { 69 | self.monitors.write() 70 | } 71 | 72 | pub(crate) fn lock_links(&self) -> impl DerefMut> + '_ { 73 | self.links.write() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess_info.rs: -------------------------------------------------------------------------------- 1 | use crate::dprocess::{DProcess, DProcessId}; 2 | 3 | // This must be private to prevent write locks. 4 | pub struct DProcessInfo<'a> { 5 | reference: &'a DProcess, 6 | } 7 | 8 | impl<'a> DProcessInfo<'a> { 9 | pub fn new(reference: &'a DProcess) -> Self { 10 | Self { reference } 11 | } 12 | 13 | pub fn id(&self) -> &DProcessId { 14 | &self.reference.id 15 | } 16 | 17 | // TODO Add read_* methods. 18 | } 19 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/dprocess_manifest.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::{ 4 | effect_handler::EffectHandlers, interpreter_builder::InterpreterBuilder, metas::Metas, 5 | }; 6 | 7 | #[derive(Debug, Clone)] 8 | pub struct DProcessManifest { 9 | pub interpreter_builder: Arc, 10 | pub effect_handlers: EffectHandlers, 11 | pub metas: Metas, 12 | } 13 | 14 | impl DProcessManifest { 15 | pub fn new( 16 | interpreter_builder: impl InterpreterBuilder + 'static, 17 | effect_handlers: EffectHandlers, 18 | metas: Metas, 19 | ) -> Self { 20 | Self { 21 | interpreter_builder: Arc::new(interpreter_builder), 22 | effect_handlers, 23 | metas, 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/flags.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, PartialEq, Eq, Default)] 2 | /// Inspired on Erlang's ones. 3 | pub struct DProcessFlags { 4 | priority: Priority, 5 | } 6 | 7 | #[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] 8 | pub enum Priority { 9 | /// The process might be not scheduled. 10 | Min, 11 | /// Low priority than default. 12 | Low, 13 | /// Normal priority. 14 | #[default] 15 | Default, 16 | /// High priority than default. 17 | High, 18 | /// The process should be scheduled always. 19 | Max, 20 | /// A priority for internal use. It has same priority as `Max` or has higher priority than `Max`. 21 | InternalMax, 22 | } 23 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/interpreter_builder.rs: -------------------------------------------------------------------------------- 1 | use crate::interpreter::Interpreter; 2 | 3 | pub trait InterpreterBuilder: std::fmt::Debug { 4 | fn build(&self) -> Box; 5 | } 6 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/interpreter_output.rs: -------------------------------------------------------------------------------- 1 | use ty::Effect; 2 | 3 | use crate::value::Value; 4 | 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub enum InterpreterOutput { 7 | Returned(Value), 8 | Performed { input: Value, effect: Effect }, 9 | Running, 10 | } 11 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod dprocess; 2 | pub mod dprocess_info; 3 | pub mod dprocess_manifest; 4 | pub mod effect_handler; 5 | pub mod exit_status; 6 | pub mod flags; 7 | pub mod interpreter; 8 | pub mod interpreter_builder; 9 | pub mod interpreter_output; 10 | pub mod metas; 11 | pub mod migration_logic; 12 | pub mod name_registry; 13 | pub mod processing_kind; 14 | pub mod processor; 15 | pub mod processor_attachment; 16 | pub mod scheduler; 17 | pub mod status; 18 | pub mod status_update; 19 | pub mod timer; 20 | pub mod value; 21 | pub mod vm_ref; 22 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/metas.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | any::{Any, TypeId}, 3 | collections::HashMap, 4 | sync::Arc, 5 | }; 6 | 7 | #[derive(Debug, Default, Clone)] 8 | /// This is used in Process and Processor for storing any kind of data especially for scheduling. 9 | pub struct Metas { 10 | metas: HashMap>, 11 | } 12 | 13 | impl Metas { 14 | pub fn new() -> Self { 15 | Self::default() 16 | } 17 | 18 | pub fn insert(&mut self, value: T) { 19 | self.metas.insert(TypeId::of::(), Arc::new(value)); 20 | } 21 | 22 | pub fn get(&self) -> Option<&T> { 23 | self.metas 24 | .get(&TypeId::of::()) 25 | .and_then(|boxed| boxed.downcast_ref::()) 26 | } 27 | 28 | pub fn remove(&mut self) { 29 | self.metas.remove(&TypeId::of::()); 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use super::*; 36 | 37 | #[test] 38 | fn test_metas() { 39 | let mut metas = Metas::new(); 40 | metas.insert(1); 41 | metas.insert(2); 42 | metas.insert(3); 43 | assert_eq!(metas.get::(), Some(&3)); 44 | metas.remove::(); 45 | assert_eq!(metas.get::(), None); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/migration_logic.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | dprocess::DProcessId, processor::ProcessorName, processor_attachment::ProcessorAttachment, 3 | status_update::StatusUpdate, vm_ref::VmRef, 4 | }; 5 | 6 | // TODO: This name should be more descriptive. 7 | /// This trait implements how VM attaches a process to a processor. 8 | /// 9 | /// Influenced by the Migration Logic of Erlang VM's scheduler. 10 | /// Implementation never fails. 11 | pub trait MigrationLogic: std::fmt::Debug { 12 | /// DeskVM completely respects the suggestions. 13 | fn suggest_migration(&mut self, vm: VmRef) -> Vec; 14 | 15 | /// DeskVM calls this method when a new d-process is created. 16 | fn notify_new_dprocess(&mut self, dprocess_id: &DProcessId); 17 | 18 | /// DeskVM calls this method when a d-process is deleted. 19 | fn notify_deleted_dprocess(&mut self, dprocess_id: &DProcessId); 20 | 21 | /// DeskVM calls this method when a status of a d-process is updated. 22 | /// 23 | /// DeskVM does not calls this method for d-process creation. 24 | fn notify_status(&mut self, status_update: &StatusUpdate); 25 | 26 | /// DeskVM calls this method when a new processor is created. 27 | fn notify_new_processor(&mut self, processor_name: &ProcessorName); 28 | 29 | /// DeskVM calls this method when a processor is deleted. 30 | fn notify_deleted_processor(&mut self, processor_name: &ProcessorName); 31 | } 32 | 33 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 34 | pub struct MigrateSuggestion { 35 | pub process_id: DProcessId, 36 | pub to: ProcessorAttachment, 37 | } 38 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/name_registry.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::dprocess::DProcessId; 4 | 5 | #[derive(Debug, Clone, PartialEq, Eq, Default)] 6 | pub struct NameRegistry { 7 | pub names: HashMap, 8 | } 9 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/processing_kind.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 2 | pub enum ProcessingKind { 3 | /// Current processing mainly uses GPU. 4 | GPU, 5 | /// Current processing mainly uses CPU. 6 | CPU, 7 | /// Current processing mainly uses IO. 8 | IO, 9 | } 10 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/processor.rs: -------------------------------------------------------------------------------- 1 | use parking_lot::RwLock; 2 | 3 | use crate::{metas::Metas, scheduler::Scheduler}; 4 | 5 | #[derive(Debug)] 6 | pub struct Processor { 7 | pub name: String, 8 | /// Metadatas mainly used by the scheduler and migration logic. 9 | pub metas: RwLock, 10 | } 11 | 12 | #[derive(Debug)] 13 | pub struct ProcessorWithScheduler { 14 | pub processor: Processor, 15 | pub scheduler: RwLock>, 16 | } 17 | 18 | #[derive(Debug)] 19 | pub struct ProcessorManifest { 20 | pub name: ProcessorName, 21 | pub metas: Metas, 22 | pub scheduler: Box, 23 | } 24 | 25 | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] 26 | pub struct ProcessorName(pub String); 27 | 28 | impl ProcessorWithScheduler { 29 | pub fn new(manifest: ProcessorManifest) -> Self { 30 | Self { 31 | processor: Processor { 32 | name: manifest.name.0, 33 | metas: RwLock::new(manifest.metas), 34 | }, 35 | scheduler: RwLock::new(manifest.scheduler), 36 | } 37 | } 38 | } 39 | 40 | impl ProcessorManifest { 41 | pub fn new(name: ProcessorName, scheduler: impl Scheduler + 'static, metas: Metas) -> Self { 42 | Self { 43 | name, 44 | metas, 45 | scheduler: Box::new(scheduler), 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/processor_attachment.rs: -------------------------------------------------------------------------------- 1 | use crate::processor::ProcessorName; 2 | 3 | #[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] 4 | pub enum ProcessorAttachment { 5 | Attached(ProcessorName), 6 | #[default] 7 | Detached, 8 | } 9 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/scheduler.rs: -------------------------------------------------------------------------------- 1 | use std::{sync::Arc, time::Duration}; 2 | 3 | use crate::{ 4 | dprocess::{DProcess, DProcessId}, 5 | processor::Processor, 6 | status_update::StatusUpdate, 7 | vm_ref::VmRef, 8 | }; 9 | 10 | pub trait Scheduler: std::fmt::Debug { 11 | /// Execute attached processes. 12 | /// 13 | /// A scheduler never fails. 14 | /// Implementation should not exceed the given duration. 15 | /// Implementation can return an output earlier even if it remains codes to run. 16 | fn reduce(&mut self, vm: VmRef, processor: &Processor, target_duration: &Duration); 17 | 18 | fn attach(&mut self, dprocess: Arc); 19 | 20 | fn detach(&mut self, process_id: &DProcessId); 21 | 22 | /// DeskVM calls this method when a status of a process is updated. 23 | fn notify_status(&mut self, status_update: &StatusUpdate); 24 | } 25 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/status.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use ty::{Effect, Type}; 4 | 5 | use crate::{dprocess::DProcessId, value::Value}; 6 | 7 | #[derive(Default, Debug, Clone, PartialEq, Eq)] 8 | /// A status of process. 9 | /// 10 | /// It's cheap to clone. 11 | pub enum DProcessStatus { 12 | #[default] 13 | Running, 14 | Deferred { 15 | effect: Arc, 16 | input: Arc, 17 | }, 18 | WaitingForMessage(Arc), 19 | Returned(Arc), 20 | Halted { 21 | ty: Arc, 22 | reason: Arc, 23 | }, 24 | Crashed(CrashError), 25 | HaltedByLink(LinkExit), 26 | } 27 | 28 | #[derive(Debug, Clone, PartialEq, Eq)] 29 | pub enum LinkExit { 30 | Halted { 31 | dprocess_id: DProcessId, 32 | ty: Arc, 33 | reason: Arc, 34 | }, 35 | Crashed { 36 | dprocess_id: DProcessId, 37 | error: CrashError, 38 | }, 39 | NotFound(DProcessId), 40 | } 41 | 42 | #[derive(Debug, Clone)] 43 | pub struct CrashError(pub Arc); 44 | 45 | impl PartialEq for CrashError { 46 | fn eq(&self, other: &Self) -> bool { 47 | self.0.to_string() == other.0.to_string() 48 | } 49 | } 50 | 51 | impl Eq for CrashError {} 52 | 53 | impl From for CrashError { 54 | fn from(error: anyhow::Error) -> Self { 55 | Self(Arc::new(error)) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/status_update.rs: -------------------------------------------------------------------------------- 1 | use crate::{dprocess::DProcessId, status::DProcessStatus}; 2 | 3 | #[derive(Debug, Clone, PartialEq, Eq)] 4 | pub struct StatusUpdate { 5 | pub dprocess_id: DProcessId, 6 | pub status: DProcessStatus, 7 | } 8 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/value.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use ty::Type; 5 | 6 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 7 | /// Sendable value between processes. 8 | /// 9 | /// Closure is not sendable in the following reasons: 10 | /// - DeskVM can have many types of interpreters, so it's hard to have a common closure format. 11 | /// - Desk promotes data-oriented programming, so sending closures are not used as much as in other languages. 12 | pub enum Value { 13 | /// It's actually a empty product. 14 | Unit, 15 | Number(Number), 16 | String(String), 17 | Product(HashMap), 18 | Variant { 19 | ty: Type, 20 | value: Box, 21 | }, 22 | Vector(Vec), 23 | TraitObject { 24 | ty: Type, 25 | value: Box, 26 | }, 27 | } 28 | 29 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 30 | pub enum Number { 31 | Integer(i64), 32 | Real(f64), 33 | // b must be unsigned to avoid ambiguity. 34 | Rational(i64, u64), 35 | } 36 | 37 | // A float of should not be NaN. 38 | impl Eq for Number {} 39 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/get_dprocess.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::dprocess::{DProcess, DProcessId}; 4 | 5 | use super::VmRef; 6 | 7 | impl<'a> VmRef<'a> { 8 | pub fn get_dprocess(&self, dprocess_id: &DProcessId) -> Option> { 9 | self.read_dprocesses().get(dprocess_id).cloned() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/get_processor.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::processor::{ProcessorName, ProcessorWithScheduler}; 4 | 5 | use super::VmRef; 6 | 7 | impl<'a> VmRef<'a> { 8 | pub fn get_processor( 9 | &self, 10 | processor_name: &ProcessorName, 11 | ) -> Option> { 12 | self.read_processors().get(processor_name).cloned() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/mod.rs: -------------------------------------------------------------------------------- 1 | mod get_dprocess; 2 | mod get_processor; 3 | mod notify_status; 4 | mod pubsub; 5 | mod read_locks; 6 | mod register; 7 | mod spawn; 8 | mod write_locks; 9 | 10 | use std::{ 11 | collections::{BTreeMap, HashMap}, 12 | sync::Arc, 13 | }; 14 | 15 | use parking_lot::RwLock; 16 | 17 | use crate::{ 18 | dprocess::{DProcess, DProcessId}, 19 | migration_logic::MigrationLogic, 20 | name_registry::NameRegistry, 21 | processor::{ProcessorName, ProcessorWithScheduler}, 22 | status_update::StatusUpdate, 23 | }; 24 | 25 | #[derive(Clone, Copy)] 26 | // Fields must be private to prevent deadlocks. 27 | pub struct VmRef<'a> { 28 | dprocesses: &'a RwLock>>, 29 | processors: &'a RwLock>>, 30 | name_registry: &'a RwLock, 31 | migration_logic: &'a RwLock>, 32 | status_update: &'a RwLock>, 33 | } 34 | 35 | impl<'a> VmRef<'a> { 36 | pub fn new( 37 | dprocesses: &'a RwLock>>, 38 | processors: &'a RwLock>>, 39 | name_registry: &'a RwLock, 40 | migration_logic: &'a RwLock>, 41 | status_update: &'a RwLock>, 42 | ) -> Self { 43 | Self { 44 | dprocesses, 45 | processors, 46 | name_registry, 47 | migration_logic, 48 | status_update, 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/notify_status.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | dprocess::DProcess, processor_attachment::ProcessorAttachment, status::DProcessStatus, 3 | status_update::StatusUpdate, 4 | }; 5 | 6 | use super::VmRef; 7 | 8 | impl<'a> VmRef<'a> { 9 | pub fn notify_status(&self, dprocess: &DProcess, status: &DProcessStatus) { 10 | let status_update = StatusUpdate { 11 | dprocess_id: dprocess.id.clone(), 12 | status: status.clone(), 13 | }; 14 | // Notify to migration logics 15 | self.lock_migration_logic().notify_status(&status_update); 16 | // Notify to the attached scheduler 17 | if let ProcessorAttachment::Attached(processor) = &*dprocess.read_processor_attachment() { 18 | if let Some(processor) = self.get_processor(processor) { 19 | processor.scheduler.write().notify_status(&status_update); 20 | } 21 | } 22 | // Push to the status queue 23 | self.lock_status_update().push(status_update); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/pubsub.rs: -------------------------------------------------------------------------------- 1 | use ty::Type; 2 | 3 | use crate::{dprocess::DProcessId, value::Value}; 4 | 5 | use super::VmRef; 6 | impl<'a> VmRef<'a> { 7 | pub fn subscribe(&self, _dprocess_id: DProcessId, _ty: Type) { 8 | todo!() 9 | } 10 | 11 | pub fn publish(&self, _ty: Type, _value: Value) { 12 | todo!() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/read_locks.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{BTreeMap, HashMap}, 3 | ops::Deref, 4 | sync::Arc, 5 | }; 6 | 7 | use crate::{ 8 | dprocess::{DProcess, DProcessId}, 9 | name_registry::NameRegistry, 10 | processor::{ProcessorName, ProcessorWithScheduler}, 11 | }; 12 | 13 | use super::VmRef; 14 | 15 | impl<'a> VmRef<'a> { 16 | pub fn read_dprocesses(&self) -> impl Deref>> + '_ { 17 | self.dprocesses.read() 18 | } 19 | 20 | pub fn read_processors( 21 | &self, 22 | ) -> impl Deref>> + '_ { 23 | self.processors.read() 24 | } 25 | 26 | pub fn read_name_registry(&self) -> impl Deref + '_ { 27 | self.name_registry.read() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/register.rs: -------------------------------------------------------------------------------- 1 | use crate::dprocess::DProcessId; 2 | 3 | use super::VmRef; 4 | 5 | impl<'a> VmRef<'a> { 6 | pub fn register(&self, _name: String, _dprocess_id: DProcessId) { 7 | todo!() 8 | } 9 | 10 | pub fn unregister(&self, _name: String) { 11 | todo!() 12 | } 13 | 14 | pub fn whereis(&self, _name: String) -> Option { 15 | todo!() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/spawn.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::{dprocess::DProcess, dprocess_manifest::DProcessManifest}; 4 | 5 | use super::VmRef; 6 | 7 | impl<'a> VmRef<'a> { 8 | pub fn spawn(&self, manifest: &DProcessManifest) { 9 | let dprocess = DProcess::new(manifest); 10 | let dprocess_id = dprocess.id.clone(); 11 | self.lock_migration_logic() 12 | .notify_new_dprocess(&dprocess_id); 13 | self.lock_dprocesses() 14 | .insert(dprocess_id, Arc::new(dprocess)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/components/deskvm-dprocess/src/vm_ref/write_locks.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, ops::DerefMut, sync::Arc}; 2 | 3 | use crate::{ 4 | dprocess::{DProcess, DProcessId}, 5 | migration_logic::MigrationLogic, 6 | status_update::StatusUpdate, 7 | }; 8 | 9 | use super::VmRef; 10 | 11 | // These must be private to prevent deadlocks. 12 | impl<'a> VmRef<'a> { 13 | pub(crate) fn lock_dprocesses( 14 | &self, 15 | ) -> impl DerefMut>> + '_ { 16 | self.dprocesses.write() 17 | } 18 | 19 | pub(crate) fn lock_migration_logic( 20 | &self, 21 | ) -> impl DerefMut> + '_ { 22 | self.migration_logic.write() 23 | } 24 | 25 | pub(crate) fn lock_status_update(&self) -> impl DerefMut> + '_ { 26 | self.status_update.write() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /crates/components/dson/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dson" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | serde = { version = "1.0", features = ["derive"] } 15 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dworkspace-codebase" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | deskc-ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | ty = { path = "../deskc-type", version = "0.0.0", package = "deskc-type" } 16 | ast = { path = "../deskc-ast", version = "0.0.0", package = "deskc-ast" } 17 | hir = { path = "../deskc-hir", version = "0.0.0", package = "deskc-hir" } 18 | dson = { workspace = true } 19 | 20 | uuid = { workspace = true} 21 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/code.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use ast::{expr::Expr, meta::WithMeta}; 4 | 5 | /// A unit of code in a codebase. 6 | /// 7 | /// Uses Arc for cheap cloning 8 | #[derive(Debug, Clone, PartialEq, Eq)] 9 | pub enum Code { 10 | SourceCode { 11 | syntax: SyntaxKind, 12 | source: Arc, 13 | }, 14 | Ast(Arc>), 15 | } 16 | 17 | // Some syntax are not supported yet. 18 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 19 | pub enum SyntaxKind { 20 | Minimalist, 21 | // TypeScriptLike, 22 | // OCamlLike, 23 | // RustLike, 24 | } 25 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/content.rs: -------------------------------------------------------------------------------- 1 | use deskc_ids::LinkName; 2 | 3 | use crate::code::SyntaxKind; 4 | 5 | #[derive(Clone, Debug, PartialEq)] 6 | pub enum Content { 7 | SourceCode { syntax: SyntaxKind, source: String }, 8 | String(String), 9 | Integer(i64), 10 | // b must be unsigned to avoid ambiguity. 11 | Rational(i64, u64), 12 | Real(f64), 13 | Apply { link_name: LinkName }, 14 | Do, 15 | Let, 16 | Perform, 17 | Continue, 18 | Handle, 19 | Product, 20 | Match, 21 | Typed, 22 | Hole, 23 | Function, 24 | Vector, 25 | Map, 26 | MapElem, 27 | Case, 28 | Handler, 29 | Effect, 30 | DeclareBrand { brand: String }, 31 | Label { label: String }, 32 | NewType { ident: String }, 33 | TyLabeled { brand: String }, 34 | TyMap, 35 | TyVector, 36 | TyProduct, 37 | Sum, 38 | TyLet { ident: String }, 39 | TyReal, 40 | TyRational, 41 | TyInteger, 42 | TyString, 43 | TyEffectful, 44 | Effects, 45 | EAdd, 46 | ESub, 47 | EApply, 48 | Infer, 49 | TyFunction, 50 | Variable { ident: String }, 51 | } 52 | 53 | // Content::Real should not be NaN 54 | impl Eq for Content {} 55 | 56 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 57 | pub enum ContentKind { 58 | SourceCode, 59 | String, 60 | Integer, 61 | Rational, 62 | Real, 63 | Apply, 64 | } 65 | 66 | impl Content { 67 | pub fn kind(&self) -> ContentKind { 68 | match self { 69 | Content::SourceCode { .. } => ContentKind::SourceCode, 70 | Content::String(_) => ContentKind::String, 71 | Content::Integer(_) => ContentKind::Integer, 72 | Content::Rational(_, _) => ContentKind::Rational, 73 | Content::Real(_) => ContentKind::Real, 74 | Content::Apply { .. } => ContentKind::Apply, 75 | _ => todo!(), 76 | } 77 | } 78 | } 79 | 80 | #[cfg(test)] 81 | mod tests { 82 | use super::*; 83 | 84 | #[test] 85 | fn test_content_kind() { 86 | assert_eq!( 87 | Content::SourceCode { 88 | syntax: SyntaxKind::Minimalist, 89 | source: String::new() 90 | } 91 | .kind(), 92 | ContentKind::SourceCode 93 | ); 94 | assert_eq!(Content::String(String::new()).kind(), ContentKind::String); 95 | assert_eq!(Content::Integer(0).kind(), ContentKind::Integer); 96 | assert_eq!(Content::Rational(0, 1).kind(), ContentKind::Rational); 97 | assert_eq!(Content::Real(0.0).kind(), ContentKind::Real); 98 | assert_eq!( 99 | Content::Apply { 100 | link_name: LinkName::None 101 | } 102 | .kind(), 103 | ContentKind::Apply 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/event.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | content::Content, 3 | patch::{AttributePatch, ContentPatch, OperandPatch}, 4 | rules::{NodeOperation, Rules, SpaceOperation}, 5 | user::UserId, 6 | }; 7 | use deskc_ids::NodeId; 8 | use uuid::Uuid; 9 | 10 | use crate::projection::Projection; 11 | 12 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] 13 | pub struct EventId(pub Uuid); 14 | 15 | impl EventId { 16 | pub fn new() -> Self { 17 | Self(Uuid::new_v4()) 18 | } 19 | } 20 | 21 | #[derive(Debug, Clone, PartialEq, Eq)] 22 | pub struct Event { 23 | pub id: EventId, 24 | pub user_id: UserId, 25 | pub payload: EventPayload, 26 | } 27 | 28 | #[derive(Debug, Clone, PartialEq, Eq)] 29 | pub enum EventPayload { 30 | AddOwner { 31 | user_id: UserId, 32 | }, 33 | RemoveOwner { 34 | user_id: UserId, 35 | }, 36 | UpdateSpaceRules { 37 | rules: Rules, 38 | }, 39 | CreateNode { 40 | node_id: NodeId, 41 | content: Content, 42 | }, 43 | RemoveNode { 44 | node_id: NodeId, 45 | }, 46 | PatchContent { 47 | node_id: NodeId, 48 | patch: ContentPatch, 49 | }, 50 | PatchOperand { 51 | node_id: NodeId, 52 | patch: OperandPatch, 53 | }, 54 | PatchAttribute { 55 | node_id: NodeId, 56 | patch: AttributePatch, 57 | }, 58 | UpdateNodeRules { 59 | node_id: NodeId, 60 | rules: Rules, 61 | }, 62 | UpdateOperandRules { 63 | node_id: NodeId, 64 | rules: Rules, 65 | }, 66 | AddSnapshot { 67 | /// current index of events 68 | /// if the index of this event is not index+1, this event must be 69 | index: usize, 70 | snapshot: Box, 71 | }, 72 | } 73 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod code; 2 | pub mod content; 3 | pub mod event; 4 | pub mod flat_node; 5 | pub mod node; 6 | pub mod patch; 7 | pub mod projection; 8 | pub mod rules; 9 | pub mod user; 10 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/node.rs: -------------------------------------------------------------------------------- 1 | use deskc_ids::NodeId; 2 | 3 | use crate::{content::Content, flat_node::Attributes}; 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq)] 6 | pub struct Node { 7 | pub id: NodeId, 8 | pub content: Content, 9 | pub operands: Vec, 10 | pub attributes: Attributes, 11 | } 12 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/patch/diff_match_patch.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, PartialEq, Eq)] 2 | pub enum Operation { 3 | Delete, 4 | Insert, 5 | Equal, 6 | } 7 | 8 | #[derive(Debug, Clone, PartialEq, Eq)] 9 | pub struct StringDiff { 10 | pub operation: Operation, 11 | pub text: String, 12 | } 13 | 14 | #[derive(Debug, Clone, PartialEq, Eq)] 15 | pub struct Patch { 16 | pub diffs: Vec, 17 | pub start1: i32, 18 | pub start2: i32, 19 | pub length1: i32, 20 | pub length2: i32, 21 | } 22 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/patch/mod.rs: -------------------------------------------------------------------------------- 1 | mod diff_match_patch; 2 | use deskc_ids::{LinkName, NodeId}; 3 | use dson::Dson; 4 | use ty::Type; 5 | 6 | use crate::{code::SyntaxKind, content::Content}; 7 | 8 | use self::diff_match_patch::Patch; 9 | 10 | #[derive(Debug, Clone, PartialEq)] 11 | pub enum ContentPatch { 12 | Replace(Content), 13 | ChangeSourceCodeSyntax { syntax: SyntaxKind, source: String }, 14 | PatchSourceCode(StringPatch), 15 | PatchString(StringPatch), 16 | UpdateInteger(u64), 17 | UpdateReal(f64), 18 | UpdateRational(u64, u64), 19 | UpdateApply { ty: Type, link_name: LinkName }, 20 | } 21 | 22 | #[derive(Debug, Clone, PartialEq, Eq)] 23 | pub enum StringPatch { 24 | Replace(String), 25 | DiffMatchPatch(Vec), 26 | } 27 | 28 | // ContentPatch::AddReal should not be NaN 29 | impl Eq for ContentPatch {} 30 | 31 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 32 | pub enum OperandPatch { 33 | Insert { 34 | position: OperandPosition, 35 | node_id: NodeId, 36 | }, 37 | Remove { 38 | node_id: NodeId, 39 | }, 40 | Move { 41 | node_id: NodeId, 42 | position: OperandPosition, 43 | }, 44 | } 45 | 46 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] 47 | pub enum OperandPosition { 48 | First, 49 | Last, 50 | Before(NodeId), 51 | After(NodeId), 52 | At(usize), 53 | } 54 | 55 | #[derive(Debug, Clone, PartialEq, Eq)] 56 | pub enum AttributePatch { 57 | Update { key: Type, value: Dson }, 58 | Remove { key: Type }, 59 | } 60 | -------------------------------------------------------------------------------- /crates/components/dworkspace-codebase/src/user.rs: -------------------------------------------------------------------------------- 1 | use uuid::Uuid; 2 | 3 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] 4 | pub struct UserId(pub Uuid); 5 | 6 | impl UserId { 7 | pub fn new() -> Self { 8 | Self(Uuid::new_v4()) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /crates/libs/deskc-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-macros" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [lib] 12 | proc-macro = true 13 | 14 | [dependencies] 15 | ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 16 | ast = { path = "../../components/deskc-ast", version = "0.0.0", package = "deskc-ast" } 17 | parser = { path = "../../systems/deskc-syntax-minimalist", version = "0.0.0", package = "deskc-syntax-minimalist" } 18 | dson = { path = "../../components/dson", version = "0.0.0", package = "dson" } 19 | deskc-ids = { workspace = true } 20 | 21 | quote = "1.0" 22 | proc-macro2 = "1.0" 23 | 24 | uuid = { workspace = true } 25 | -------------------------------------------------------------------------------- /crates/libs/serde-dson/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde-dson" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | dson = { path = "../../components/dson", version = "0.0.0", package = "dson" } 15 | serde = "1.0" 16 | thiserror = { workspace = true } 17 | 18 | [dev-dependencies] 19 | serde = { version = "1.0", features = ["derive"] } 20 | -------------------------------------------------------------------------------- /crates/libs/serde-dson/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use dson::Dson; 4 | use serde::{de, ser}; 5 | use thiserror::Error; 6 | 7 | pub type Result = std::result::Result; 8 | 9 | #[derive(Clone, Debug, PartialEq, Eq, Error)] 10 | pub enum Error { 11 | #[error("{0}")] 12 | Custom(String), 13 | #[error("expected a bool but got {got:?}")] 14 | ExpectedBool { got: Dson }, 15 | #[error("expected a unit but got {got:?}")] 16 | ExpectedUnit { got: Dson }, 17 | #[error("expected a product but got {got:?}")] 18 | ExpectedProduct { got: Dson }, 19 | #[error("expected a map but got {got:?}")] 20 | ExpectedMap { got: Dson }, 21 | #[error("expected a label but got {got:?}")] 22 | ExpectedLabel { got: Dson }, 23 | #[error("expected a string literal but got {got:?}")] 24 | ExpectedString { got: Dson }, 25 | #[error("label mismatch: expected {expected:?} but got {got:?}")] 26 | LabelMismatch { expected: String, got: String }, 27 | } 28 | 29 | impl ser::Error for Error { 30 | fn custom(msg: T) -> Self { 31 | Error::Custom(msg.to_string()) 32 | } 33 | } 34 | 35 | impl de::Error for Error { 36 | fn custom(msg: T) -> Self { 37 | Error::Custom(msg.to_string()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/libs/serde-dson/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod de; 2 | mod error; 3 | mod ser; 4 | 5 | pub use de::{from_dson, Deserializer}; 6 | pub use error::{Error, Result}; 7 | pub use ser::{to_dson, Serializer}; 8 | -------------------------------------------------------------------------------- /crates/plugins/desk-editor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-editor" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | dson = { workspace = true } 13 | desk-plugin = { workspace = true } 14 | desk-window = { workspace = true } 15 | desk-theme = { workspace = true } 16 | dworkspace = { workspace = true } 17 | dworkspace-codebase = { path = "../../components/dworkspace-codebase", version = "0.0.0", package = "dworkspace-codebase" } 18 | deskc-ids = { workspace = true } 19 | deskc-type = { workspace = true } 20 | deskc-macros = { workspace = true } 21 | 22 | bevy = { workspace = true } 23 | egui = { workspace = true } 24 | uuid = { workspace = true} 25 | once_cell = { workspace = true } 26 | maybe-owned = { workspace = true } 27 | -------------------------------------------------------------------------------- /crates/plugins/desk-editor/src/compile.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use deskc_ids::{CardId, NodeId}; 4 | use deskc_macros::ty; 5 | use dworkspace::prelude::*; 6 | use once_cell::sync::Lazy; 7 | 8 | pub struct Cards { 9 | pub cards: HashMap, 10 | } 11 | 12 | const CARD_ID_TYPE: Lazy = Lazy::new(|| ty!("@`desk-editor card-id` 'string")); 13 | 14 | impl State for Cards { 15 | fn handle_event(&mut self, _snapshot: &Projection, event: &Event) { 16 | match &event.payload { 17 | EventPayload::PatchAttribute { node_id: _, patch } => match patch { 18 | dworkspace_codebase::patch::AttributePatch::Update { key, value: _ } => { 19 | if *key == *CARD_ID_TYPE { 20 | // let card_id = CardId(); 21 | // self.cards.insert(card_id, node_id.clone()); 22 | } 23 | } 24 | dworkspace_codebase::patch::AttributePatch::Remove { key: _ } => todo!(), 25 | }, 26 | EventPayload::AddSnapshot { 27 | index: _, 28 | snapshot: _, 29 | } => {} 30 | EventPayload::RemoveNode { node_id: _ } => {} 31 | _ => {} 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /crates/plugins/desk-editor/src/editor_state.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{BTreeMap, BTreeSet}; 2 | 3 | use deskc_ids::NodeId; 4 | use dworkspace::{ 5 | prelude::{Event, EventPayload, OperandPatch, Projection}, 6 | state::State, 7 | }; 8 | use egui::Pos2; 9 | 10 | #[derive(Default)] 11 | pub struct NodeState { 12 | pub line_split: bool, 13 | pub editing_text: Option, 14 | } 15 | 16 | #[derive(Debug, Copy, PartialEq, Eq, Clone)] 17 | pub struct WordCursor { 18 | pub node_id: NodeId, 19 | pub offset: u16, 20 | } 21 | 22 | #[derive(Debug, Copy, PartialEq, Eq, Clone)] 23 | pub struct NextPos { 24 | pub pos: Pos2, 25 | pub search: WordSearch, 26 | } 27 | 28 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 29 | pub enum WordSearch { 30 | Forward, 31 | Backward, 32 | Nearest, 33 | } 34 | 35 | #[derive(Default)] 36 | pub struct EditorState { 37 | pub selected_nodes: BTreeSet, 38 | pub node_states: BTreeMap, 39 | /// Key is a top-level node. 40 | pub ephemeral_events: BTreeMap>, 41 | /// Relative to the top-left corner of the source code. 42 | pub word_cursor: Option, 43 | pub next_pos: Option, 44 | pub hovered_word: Option, 45 | } 46 | 47 | impl State for EditorState { 48 | fn handle_event(&mut self, _snapshot: &Projection, event: &Event) { 49 | match &event.payload { 50 | EventPayload::RemoveNode { node_id } => { 51 | self.selected_nodes.remove(node_id); 52 | self.node_states.remove(node_id); 53 | self.ephemeral_events.remove(node_id); 54 | } 55 | EventPayload::PatchOperand { 56 | node_id: _, 57 | patch: 58 | OperandPatch::Insert { 59 | node_id: operand, .. 60 | }, 61 | } => { 62 | // The operand is no longer top-level. 63 | self.ephemeral_events.remove(operand); 64 | } 65 | _ => {} 66 | } 67 | } 68 | } 69 | 70 | impl EditorState { 71 | pub fn node_mut(&mut self, node_id: NodeId) -> &mut NodeState { 72 | self.node_states.entry(node_id).or_default() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /crates/plugins/desk-editor/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod compile; 2 | mod editor_state; 3 | mod editor_widget; 4 | mod runtime; 5 | 6 | use bevy::prelude::*; 7 | use desk_plugin::DeskSystem; 8 | use desk_window::window::Window; 9 | use desk_window::{widget::WidgetId, window::DefaultWindow}; 10 | use dworkspace::Workspace; 11 | use editor_state::EditorState; 12 | use editor_widget::EditorWidget; 13 | 14 | pub struct EditorPlugin; 15 | 16 | impl Plugin for EditorPlugin { 17 | fn build(&self, app: &mut App) { 18 | app.add_system(setup.before(DeskSystem::UpdateWidget)) 19 | // move this to proper plugin 20 | .add_system( 21 | process_kernel 22 | .label(DeskSystem::ProcessKernel) 23 | .after(DeskSystem::RenderWidget), 24 | ) 25 | .add_system(compile_system) 26 | .add_system(editor.label(DeskSystem::UpdateWidget)); 27 | } 28 | } 29 | 30 | pub fn setup(mut kernel: Query<&mut Workspace, Added>) { 31 | for mut kernel in kernel.iter_mut() { 32 | kernel.add_state(EditorState::default()); 33 | } 34 | } 35 | 36 | pub fn process_kernel(mut kernel: Query<&mut Workspace>) { 37 | for mut kernel in kernel.iter_mut() { 38 | kernel.process(); 39 | } 40 | } 41 | 42 | pub fn compile_system(mut kernel: Query<&mut Workspace>) { 43 | for _kernel in kernel.iter_mut() {} 44 | } 45 | 46 | pub fn editor(mut window: Query<(&mut Window, &Workspace), With>) { 47 | if let Ok((mut window, kernel)) = window.get_single_mut() { 48 | for id in kernel.top_level_nodes() { 49 | window.add_widget( 50 | WidgetId::new(), 51 | EditorWidget { 52 | top_level_node_id: id.clone(), 53 | }, 54 | ); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /crates/plugins/desk-editor/src/runtime.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crates/plugins/desk-egui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-egui" 3 | version = "0.0.0" 4 | license = "(MIT OR Apache-2.0) AND OFL-1.1" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | desk-window = { workspace = true } 13 | desk-plugin = { workspace = true } 14 | desk-theme = { workspace = true } 15 | dworkspace = { workspace = true } 16 | 17 | bevy = { workspace = true } 18 | bevy_egui = "0.20" 19 | -------------------------------------------------------------------------------- /crates/plugins/desk-firebase-auth/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-firebase-auth" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | -------------------------------------------------------------------------------- /crates/plugins/desk-firebase-auth/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add(left: usize, right: usize) -> usize { 2 | left + right 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn it_works() { 11 | let result = add(2, 2); 12 | assert_eq!(result, 4); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /crates/plugins/desk-guide/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-guide" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | -------------------------------------------------------------------------------- /crates/plugins/desk-guide/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | let result = 2 + 2; 6 | assert_eq!(result, 4); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /crates/plugins/desk-playground/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-playground" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | bevy = { workspace = true } 15 | egui = { workspace = true } 16 | once_cell = { workspace = true } 17 | uuid = { workspace = true } 18 | 19 | dworkspace = { workspace = true } 20 | desk-window = { workspace = true } 21 | desk-plugin = { workspace = true } 22 | deskc-macros = { workspace = true } 23 | deskc-ast = { workspace = true } 24 | dson = { workspace = true } 25 | deskc-ids = { workspace = true } 26 | deskc-type = { workspace = true } 27 | -------------------------------------------------------------------------------- /crates/plugins/desk-rapier2d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-rapier2d" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | desk-plugin = { workspace = true } 15 | physics = { package = "desk-physics", path = "../../components/desk-physics", version = "0.0.0" } 16 | 17 | bevy = { workspace = true } 18 | bevy_rapier2d = { version = "0.21", features = ["wasm-bindgen", "debug-render"] } 19 | -------------------------------------------------------------------------------- /crates/plugins/desk-rapier2d/src/follow_system.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use bevy::prelude::*; 4 | use physics::{Follow, Velocity}; 5 | 6 | pub fn follow( 7 | follows: Query<&Follow>, 8 | transforms: Query<&Transform>, 9 | mut velocities: Query<(&mut Velocity, &Transform, &Follow)>, 10 | ) { 11 | let mut entities = Vec::new(); 12 | for follow in follows.iter() { 13 | entities.push(follow.target); 14 | } 15 | let mut vecs = HashMap::new(); 16 | for entity in entities { 17 | if let Ok(transform) = transforms.get(entity) { 18 | vecs.insert(entity, transform.translation.truncate()); 19 | } 20 | } 21 | for (mut velocity, transform, follow) in velocities.iter_mut() { 22 | if let Some(target) = vecs.get(&follow.target) { 23 | let vec = transform.translation.truncate(); 24 | *velocity = &*velocity + follow.parameters.follow_vector(&vec, target); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/plugins/desk-terminal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-terminal" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | desk-window = { workspace = true } 13 | dworkspace = { workspace = true } 14 | desk-plugin = { workspace = true } 15 | command = { package = "desk-command", path = "../../components/desk-command", version = "0.0.0" } 16 | dworkspace-codebase = { package = "dworkspace-codebase", path = "../../components/dworkspace-codebase", version = "0.0.0" } 17 | deskc-ids = { package = "deskc-ids", path = "../../components/deskc-ids", version = "0.0.0" } 18 | deskc-ty = { package = "deskc-type", path = "../../components/deskc-type", version = "0.0.0" } 19 | 20 | bevy = { workspace = true } 21 | egui = { workspace = true } 22 | -------------------------------------------------------------------------------- /crates/plugins/desk-terminal/src/lib.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | 3 | use desk_plugin::DeskSystem; 4 | use desk_window::{ 5 | ctx::Ctx, 6 | widget::{Widget, WidgetId}, 7 | window::{DefaultWindow, Window}, 8 | }; 9 | use dworkspace::Workspace; 10 | pub struct TerminalPlugin; 11 | 12 | impl Plugin for TerminalPlugin { 13 | fn build(&self, app: &mut App) { 14 | app.add_system(terminal.label(DeskSystem::UpdateWidget)); 15 | } 16 | } 17 | 18 | fn terminal(mut window: Query<(&mut Window, &Workspace), With>) { 19 | if let Ok((mut window, _kernel)) = window.get_single_mut() { 20 | window.add_widget(WidgetId::new(), TerminalWidget); 21 | } 22 | } 23 | 24 | struct TerminalWidget; 25 | 26 | impl Widget for TerminalWidget { 27 | fn render(&mut self, ctx: &mut Ctx) { 28 | egui::Window::new("Terminal").show(&ctx.backend(), |ui| { 29 | ui.label("Hello World"); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/plugins/desk-touchpanel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desk-touchpanel" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | desk-plugin = { workspace = true } 15 | physics = { package = "desk-physics", path = "../../components/desk-physics", version = "0.0.0" } 16 | command = { package = "desk-command", path = "../../components/desk-command", version = "0.0.0" } 17 | 18 | bevy = { workspace = true } 19 | -------------------------------------------------------------------------------- /crates/plugins/desk-touchpanel/src/cursor_systems.rs: -------------------------------------------------------------------------------- 1 | use bevy::{prelude::*, render::camera::Camera}; 2 | use command::cursor::Cursor; 3 | 4 | pub(crate) fn add_cursor(mut commands: Commands) { 5 | commands.spawn((Cursor, Transform::default())); 6 | } 7 | 8 | #[allow(clippy::type_complexity)] 9 | pub(crate) fn move_cursor( 10 | windows: Res, 11 | mut params: ParamSet<( 12 | Query<&Transform, With>, 13 | Query<&mut Transform, With>, 14 | )>, 15 | ) { 16 | if let Some((window, position)) = windows 17 | .get_primary() 18 | .and_then(|window| window.cursor_position().map(|pos| (window, pos))) 19 | { 20 | let camera = { 21 | if let Ok(camera) = params.p0().get_single() { 22 | *camera 23 | } else { 24 | return; 25 | } 26 | }; 27 | if let Ok(mut cursor) = params.p1().get_single_mut() { 28 | let position = translate_position(position, window, &camera); 29 | cursor.translation.x = position.x; 30 | cursor.translation.y = position.y; 31 | } 32 | } 33 | } 34 | 35 | fn translate_position(pos: Vec2, wnd: &Window, camera: &Transform) -> Vec2 { 36 | // get the size of the window 37 | let size = Vec2::new(wnd.width(), wnd.height()); 38 | 39 | // the default orthographic projection is in pixels from the center; 40 | // just undo the translation 41 | let p = pos - size / 2.0; 42 | 43 | // apply the camera transform 44 | (camera.compute_matrix() * p.extend(0.0).extend(1.0)) 45 | .truncate() 46 | .truncate() 47 | } 48 | -------------------------------------------------------------------------------- /crates/plugins/desk-touchpanel/src/drag_system.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use command::cursor::Cursor; 3 | use physics::{DragState, Follow, FollowParams}; 4 | 5 | pub fn toggle_follow_for_drag_state( 6 | mut commands: Commands, 7 | cursors: Query<(Entity, &Transform), With>, 8 | drags: Query<(Entity, &Transform, &DragState), Changed>, 9 | ) { 10 | let (cursor, cursor_vec) = if let Ok((entity, transform)) = cursors.get_single() { 11 | (entity, transform.translation.truncate()) 12 | } else { 13 | return; 14 | }; 15 | for (entity, transform, drag_state) in drags.iter() { 16 | match drag_state { 17 | DragState::Dragging => { 18 | let follow: Follow = Follow { 19 | target: cursor, 20 | parameters: FollowParams { 21 | position_offset: cursor_vec - transform.translation.truncate(), 22 | ignore_area_size: 5.0, 23 | velocity_coefficient: 10.0, 24 | velocity_power: 1.2, 25 | velocity_max: 2000.0, 26 | ..Default::default() 27 | }, 28 | }; 29 | commands.entity(entity).insert(follow); 30 | } 31 | DragState::NotDragging => { 32 | commands.entity(entity).remove::>(); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /crates/plugins/desk-touchpanel/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod cursor_systems; 2 | mod drag_system; 3 | 4 | use cursor_systems::{add_cursor, move_cursor}; 5 | use desk_plugin::{DeskSystem, ShellSystem}; 6 | use physics::Velocity; 7 | 8 | use bevy::prelude::*; 9 | 10 | pub struct TouchpanelPlugin; 11 | 12 | impl Plugin for TouchpanelPlugin { 13 | fn build(&self, app: &mut bevy::app::App) { 14 | app.add_startup_system(add_cursor) 15 | .add_system(move_cursor.before(DeskSystem::UpdateWidget)) 16 | .add_system( 17 | drag_system::toggle_follow_for_drag_state 18 | .after(ShellSystem::Render) 19 | .before(ShellSystem::HandleEvents), 20 | ) 21 | .add_system(reset_velocity.after(DeskSystem::PrePhysics)); 22 | } 23 | } 24 | 25 | fn reset_velocity(mut query: Query<&mut Velocity>) { 26 | for mut velocity in query.iter_mut() { 27 | velocity.0 = Vec2::ZERO; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/systems/deskc-fmt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-fmt" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | -------------------------------------------------------------------------------- /crates/systems/deskc-fmt/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crates/systems/deskc-hirgen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-hirgen" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | ast = { path = "../../components/deskc-ast", version = "0.0.0", package = "deskc-ast" } 16 | hir = { path = "../../components/deskc-hir", version = "0.0.0", package = "deskc-hir" } 17 | dson = { path = "../../components/dson", version = "0.0.0", package = "dson" } 18 | 19 | pretty_assertions = "1.3.0" 20 | thiserror = { workspace = true } 21 | 22 | [dev-dependencies] 23 | deskc = { path = "../deskc", version = "0.0.0", package = "deskc" } 24 | chumsky = "0.9.2" 25 | -------------------------------------------------------------------------------- /crates/systems/deskc-hirgen/src/error.rs: -------------------------------------------------------------------------------- 1 | use ids::{CardId, NodeId}; 2 | use thiserror::Error; 3 | 4 | #[derive(Clone, Debug, PartialEq, Eq, Error)] 5 | pub enum HirGenError { 6 | #[error("class expected")] 7 | ClassExpected { span: NodeId }, 8 | #[error("unexpected class")] 9 | UnexpectedClass { span: NodeId }, 10 | #[error("unknown type alias {alias} {span:?}")] 11 | UnknownTypeAlias { alias: String, span: NodeId }, 12 | #[error("unexpected card {card_id:?}")] 13 | UnexpectedCard { card_id: CardId }, 14 | } 15 | -------------------------------------------------------------------------------- /crates/systems/deskc-hirgen/src/gen_effect_expr.rs: -------------------------------------------------------------------------------- 1 | use ast::meta::WithMeta as AstWithMeta; 2 | use hir::{ 3 | meta::WithMeta, 4 | ty::{Effect, EffectExpr}, 5 | }; 6 | 7 | use crate::{error::HirGenError, HirGen}; 8 | 9 | impl HirGen { 10 | pub fn gen_effect_expr( 11 | &self, 12 | expr: &AstWithMeta, 13 | ) -> Result, HirGenError> { 14 | let AstWithMeta { value: expr, meta } = expr; 15 | self.push_meta(meta); 16 | let expr = match expr { 17 | ast::ty::EffectExpr::Effects(effects) => self.with_meta(EffectExpr::Effects( 18 | effects 19 | .iter() 20 | .map( 21 | |AstWithMeta { 22 | meta, 23 | value: effect, 24 | }| { 25 | self.push_meta(meta); 26 | Ok(self.with_meta(Effect { 27 | input: self.gen_type(&effect.input)?, 28 | output: self.gen_type(&effect.output)?, 29 | })) 30 | }, 31 | ) 32 | .collect::>()?, 33 | )), 34 | ast::ty::EffectExpr::Add(exprs) => self.with_meta(EffectExpr::Add( 35 | exprs 36 | .iter() 37 | .map(|e| self.gen_effect_expr(e)) 38 | .collect::>()?, 39 | )), 40 | ast::ty::EffectExpr::Sub { 41 | minuend, 42 | subtrahend, 43 | } => self.with_meta(EffectExpr::Sub { 44 | minuend: Box::new(self.gen_effect_expr(minuend)?), 45 | subtrahend: Box::new(self.gen_effect_expr(subtrahend)?), 46 | }), 47 | ast::ty::EffectExpr::Apply { 48 | function, 49 | arguments, 50 | } => self.with_meta(EffectExpr::Apply { 51 | function: Box::new(self.gen_type(function)?), 52 | arguments: arguments 53 | .iter() 54 | .map(|a| self.gen_type(a)) 55 | .collect::>()?, 56 | }), 57 | }; 58 | Ok(expr) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /crates/systems/deskc-mirgen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-mirgen" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | hir = { path = "../../components/deskc-hir", version = "0.0.0", package = "deskc-hir" } 16 | mir = { path = "../../components/deskc-mir", version = "0.0.0", package = "deskc-mir" } 17 | ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 18 | errors = { path = "../../components/deskc-errors", version = "0.0.0", package = "deskc-errors" } 19 | -------------------------------------------------------------------------------- /crates/systems/deskc-mirgen/src/block_proto.rs: -------------------------------------------------------------------------------- 1 | use mir::stmt::StmtBind; 2 | 3 | #[derive(Debug, Default)] 4 | pub struct BlockProto { 5 | pub stmts: Vec, 6 | } 7 | 8 | impl BlockProto { 9 | pub fn push_stmt_bind(&mut self, stmt_bind: StmtBind) { 10 | self.stmts.push(stmt_bind); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /crates/systems/deskc-mirgen/src/scope_proto.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use mir::{ 4 | scope::{Scope, ScopeId}, 5 | var::VarId, 6 | }; 7 | use ty::Type; 8 | 9 | #[derive(Debug, Default)] 10 | pub struct ScopeProto { 11 | pub super_id: Option, 12 | // Only used in mir generation 13 | pub named_vars: HashMap, 14 | } 15 | 16 | impl ScopeProto { 17 | pub fn into_scope(self) -> Scope { 18 | Scope { 19 | super_scope: self.super_id, 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /crates/systems/deskc-syntax-minimalist/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-syntax-minimalist" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | ast = { path = "../../components/deskc-ast", version = "0.0.0", package = "deskc-ast" } 16 | errors = { path = "../../components/deskc-errors", version = "0.0.0", package = "deskc-errors" } 17 | dson = { path = "../../components/dson", version = "0.0.0", package = "dson" } 18 | 19 | parol_runtime = { version = "0.16.0", features = ["auto_generation"] } 20 | anyhow = "1.0" 21 | thiserror = { workspace = true } 22 | uuid = { version = "1.3", features = ["v4"] } 23 | 24 | [build-dependencies] 25 | parol = { version = "0.21.5" } 26 | 27 | [dev-dependencies] 28 | env_logger = "0.10.0" 29 | pretty_assertions = "1.3.0" 30 | -------------------------------------------------------------------------------- /crates/systems/deskc-syntax-minimalist/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | parol::build::Builder::with_explicit_output_dir("src") 3 | .grammar_file("src/grammar.par") 4 | .expanded_grammar_output_file("grammar-exp.par") 5 | .parser_output_file("parser.rs") 6 | .actions_output_file("grammar_trait.rs") 7 | .enable_auto_generation() 8 | .range() 9 | .max_lookahead(1) 10 | .unwrap() 11 | .generate_parser() 12 | .unwrap(); 13 | println!("cargo:rerun-if-changed=build.rs"); 14 | } 15 | -------------------------------------------------------------------------------- /crates/systems/deskc-syntax-minimalist/src/.gitignore: -------------------------------------------------------------------------------- 1 | !grammar.par 2 | 3 | # generated files 4 | grammar_trait.rs 5 | parser.rs 6 | -------------------------------------------------------------------------------- /crates/systems/deskc-syntax-minimalist/src/grammar.rs: -------------------------------------------------------------------------------- 1 | use crate::grammar_trait::{ExprC, GrammarTrait}; 2 | use parol_runtime::Result; 3 | 4 | /// 5 | /// Data structure that implements the semantic actions for our grammar 6 | /// !Change this type as needed! 7 | /// 8 | #[derive(Debug, Default)] 9 | pub struct Grammar<'t> { 10 | pub expr: Option>, 11 | } 12 | 13 | impl Grammar<'_> { 14 | pub fn new() -> Self { 15 | Grammar::default() 16 | } 17 | } 18 | 19 | impl<'t> GrammarTrait<'t> for Grammar<'t> { 20 | // !Adjust your implementation as needed! 21 | 22 | /// Semantic action for non-terminal '{{grammar_name}}' 23 | fn expr_c(&mut self, arg: &ExprC<'t>) -> Result<()> { 24 | self.expr = Some(arg.clone()); 25 | Ok(()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/systems/deskc-syntax-minimalist/src/span_storage.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use ast::parser::{dyn_eq, SpanStorage}; 4 | 5 | #[derive(Debug, Default, PartialEq, Eq)] 6 | pub struct MinimalistSyntaxSpanStorage { 7 | spans: HashMap, 8 | } 9 | 10 | impl SpanStorage for MinimalistSyntaxSpanStorage { 11 | fn calculate_span(&self, id: &ids::NodeId) -> Option { 12 | self.spans.get(&id).map(|s| s.into()) 13 | } 14 | fn dyn_eq(&self, other: &dyn SpanStorage) -> bool { 15 | dyn_eq(self, other) 16 | } 17 | } 18 | 19 | impl From<(ids::NodeId, Option<&crate::grammar_trait::ExprC<'_>>)> for MinimalistSyntaxSpanStorage { 20 | fn from(value: (ids::NodeId, Option<&crate::grammar_trait::ExprC<'_>>)) -> Self { 21 | use crate::grammar_trait::Expr; 22 | use parol_runtime::lexer::rng::ToSpan; 23 | if let Some(expr) = value.1 { 24 | let mut spans = HashMap::new(); 25 | spans.insert( 26 | value.0, 27 | match &*expr.expr { 28 | Expr::ExprBeginExprCExprEnd(e) => ToSpan::span(e), 29 | Expr::Hole(e) => ToSpan::span(e), 30 | Expr::Do(e) => ToSpan::span(e), 31 | Expr::Cast(e) => ToSpan::span(e), 32 | Expr::Literal(e) => ToSpan::span(e), 33 | Expr::Let(e) => ToSpan::span(e), 34 | Expr::Perform(e) => ToSpan::span(e), 35 | Expr::Continue(e) => ToSpan::span(e), 36 | Expr::Handle(e) => ToSpan::span(e), 37 | Expr::Product(e) => ToSpan::span(e), 38 | Expr::Vector(e) => ToSpan::span(e), 39 | Expr::Map(e) => ToSpan::span(e), 40 | Expr::Attributed(e) => ToSpan::span(e), 41 | Expr::Match(e) => ToSpan::span(e), 42 | Expr::Function(e) => ToSpan::span(e), 43 | Expr::Apply(e) => ToSpan::span(e), 44 | Expr::Reference(e) => ToSpan::span(e), 45 | Expr::Forall(e) => ToSpan::span(e), 46 | Expr::Exists(e) => ToSpan::span(e), 47 | Expr::Labeled(e) => ToSpan::span(e), 48 | Expr::NewType(e) => ToSpan::span(e), 49 | Expr::Card(e) => ToSpan::span(e), 50 | Expr::Brand(e) => ToSpan::span(e), 51 | }, 52 | ); 53 | Self { spans } 54 | } else { 55 | Self::default() 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-typeinfer" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | hir = { path = "../../components/deskc-hir", version = "0.0.0", package = "deskc-hir" } 16 | ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 17 | errors = { path = "../../components/deskc-errors", version = "0.0.0", package = "deskc-errors" } 18 | 19 | thiserror = { workspace = true } 20 | itertools = "0.10" 21 | 22 | [dev-dependencies] 23 | deskc = { path = "../deskc", version = "0.0.0", package = "deskc" } 24 | dson = { workspace = true } 25 | 26 | chumsky = "0.9.2" 27 | ariadne = "0.2" 28 | pretty_assertions = "1.3.0" 29 | env_logger = "0.10.0" 30 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/cast_strategies.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::internal_type::Type; 4 | 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub enum CastStrategy { 7 | ProductToProduct(HashMap), 8 | SumToSum(HashMap), 9 | ProductToInner(Type), 10 | InnerToSum(Type), 11 | } 12 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/ctx/check.rs: -------------------------------------------------------------------------------- 1 | use errors::typeinfer::ExprTypeError; 2 | use hir::{ 3 | expr::{Expr, Literal}, 4 | meta::WithMeta, 5 | }; 6 | 7 | use crate::{ctx::Ctx, ctx::Log, internal_type::Type, to_expr_type_error}; 8 | 9 | use super::{with_effects::WithEffects, with_type::WithType}; 10 | 11 | impl Ctx { 12 | pub fn check( 13 | &self, 14 | expr: &WithMeta, 15 | ty: &Type, 16 | ) -> Result, ExprTypeError> { 17 | let scope = self.begin_scope(); 18 | let ctx = match (&expr.value, ty) { 19 | (Expr::Literal(Literal::Integer(_)), Type::Real) => self.clone(), 20 | (Expr::Literal(Literal::Real(_)), Type::Real) => self.clone(), 21 | (Expr::Literal(Literal::Rational(_, _)), Type::Real) => self.clone(), 22 | (Expr::Literal(Literal::String(_)), Type::String) => self.clone(), 23 | ( 24 | Expr::Function { 25 | parameter: _, 26 | body: _, 27 | }, 28 | Type::Function { 29 | parameter: _ty_parameter, 30 | body: _ty_body, 31 | }, 32 | ) => { 33 | todo!() 34 | } 35 | ( 36 | _, 37 | Type::ForAll { 38 | variable, 39 | bound, 40 | body, 41 | }, 42 | ) => self 43 | .add(Log::Variable(*variable)) 44 | .check(expr, body)? 45 | .recover_effects() 46 | .bound_check(&Type::Variable(*variable), bound) 47 | .map_err(|error| to_expr_type_error(expr, error))? 48 | .truncate_from(&Log::Variable(*variable)) 49 | .recover_effects(), 50 | (_, _) => { 51 | let WithType(ctx, synthed) = self.synth(expr)?.recover_effects(); 52 | ctx.subtype( 53 | &ctx.substitute_from_ctx(&synthed), 54 | &ctx.substitute_from_ctx(ty), 55 | ) 56 | .map_err(|error| to_expr_type_error(expr, error))? 57 | .ctx 58 | } 59 | }; 60 | let effects = ctx.end_scope(scope); 61 | ctx.store_type_and_effects( 62 | expr.meta.id.clone(), 63 | ctx.substitute_from_ctx(ty), 64 | effects.clone(), 65 | ); 66 | Ok(WithEffects(ctx, effects)) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/ctx/with_effects.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | ctx::{Ctx, Log}, 3 | internal_type::effect_expr::EffectExpr, 4 | }; 5 | 6 | use super::with_type::WithType; 7 | 8 | pub struct WithEffects(pub T, pub EffectExpr); 9 | 10 | impl WithEffects { 11 | pub fn recover_effects(self) -> Ctx { 12 | self.0.logs.borrow_mut().push(Log::Effect(self.1)); 13 | self.0 14 | } 15 | } 16 | 17 | impl WithEffects> { 18 | pub fn recover_effects(self) -> WithType { 19 | self.0 .0.logs.borrow_mut().push(Log::Effect(self.1)); 20 | self.0 .0.with_type(self.0 .1) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/ctx/with_type.rs: -------------------------------------------------------------------------------- 1 | use crate::internal_type::Type; 2 | 3 | use super::Ctx; 4 | 5 | pub struct WithType(pub Ctx, pub Type); 6 | 7 | impl WithType { 8 | pub fn ctx_do(self, f: impl FnOnce(&Ctx) -> Result) -> Result, E> { 9 | let WithType(ctx, ty) = self; 10 | Ok(WithType(f(&ctx)?, ty)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/mono_type.rs: -------------------------------------------------------------------------------- 1 | use ids::NodeId; 2 | 3 | use crate::{ 4 | ctx::Id, 5 | internal_type::{Type, TypeVisitor}, 6 | }; 7 | 8 | pub fn is_monotype(ty: &Type) -> bool { 9 | let mut monotype = MonoType { is_monotype: true }; 10 | monotype.visit(ty); 11 | monotype.is_monotype 12 | } 13 | 14 | pub(crate) struct MonoType { 15 | pub is_monotype: bool, 16 | } 17 | 18 | impl TypeVisitor for MonoType { 19 | fn visit_forall(&mut self, _variable: &Id, _bound: &Option>, _body: &Type) { 20 | self.is_monotype = false; 21 | } 22 | fn visit_infer(&mut self, _id: &NodeId) { 23 | // TODO: this is too conservative, but we may not have a way to know in here 24 | self.is_monotype = false; 25 | } 26 | fn visit(&mut self, ty: &Type) { 27 | // walk while monotype 28 | if self.is_monotype { 29 | self.visit_inner(ty) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/occurs_in.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | ctx::Id, 3 | internal_type::{Type, TypeVisitor}, 4 | }; 5 | 6 | // existential type is occurs in the type 7 | pub fn occurs_in(id: &Id, ty: &Type) -> bool { 8 | let mut occurs_in = OccursIn { 9 | id: *id, 10 | occurs_in: false, 11 | }; 12 | occurs_in.visit(ty); 13 | occurs_in.occurs_in 14 | } 15 | 16 | pub(crate) struct OccursIn { 17 | pub id: Id, 18 | pub occurs_in: bool, 19 | } 20 | 21 | impl TypeVisitor for OccursIn { 22 | fn visit_existential(&mut self, id: &Id) { 23 | if self.id == *id { 24 | self.occurs_in = true; 25 | } 26 | } 27 | fn visit(&mut self, ty: &Type) { 28 | // walk while not occurred 29 | if !self.occurs_in { 30 | self.visit_inner(ty) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/substitute.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | ctx::Id, 3 | internal_type::{Type, TypeVisitorMut}, 4 | }; 5 | 6 | pub fn substitute(to: &Type, id: &Id, by: &Type) -> Type { 7 | let mut substitute = Substitute { 8 | id: *id, 9 | ty: by.clone(), 10 | }; 11 | let mut to = to.clone(); 12 | substitute.visit(&mut to); 13 | to 14 | } 15 | 16 | pub(crate) struct Substitute { 17 | pub id: Id, 18 | pub ty: Type, 19 | } 20 | 21 | impl TypeVisitorMut for Substitute { 22 | fn visit(&mut self, ty: &mut Type) { 23 | match ty { 24 | Type::Existential(id) if *id == self.id => *ty = self.ty.clone(), 25 | Type::Variable(id) if *id == self.id => *ty = self.ty.clone(), 26 | ty => self.visit_inner(ty), 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/substitute_from_ctx.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | internal_type::{Type, TypeVisitorMut}, 3 | Ctx, 4 | }; 5 | 6 | pub(crate) struct SubstituteFromCtx<'a> { 7 | pub ctx: &'a Ctx, 8 | } 9 | 10 | impl<'a> TypeVisitorMut for SubstituteFromCtx<'a> { 11 | fn visit(&mut self, ty: &mut Type) { 12 | match ty { 13 | Type::Existential(id) => { 14 | if let Some(solved) = self.ctx.get_solved(id) { 15 | *ty = solved; 16 | } 17 | } 18 | Type::Variable(id) => { 19 | if let Ok(typed) = self.ctx.get_typed_var(id) { 20 | *ty = typed; 21 | } 22 | } 23 | Type::Infer(id) => { 24 | if let Some(typed) = self.ctx.inferred_types.borrow().get(id).cloned() { 25 | *ty = typed; 26 | } 27 | } 28 | ty => self.visit_inner(ty), 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | ctx::{Ctx, Id}, 3 | internal_type::Type, 4 | }; 5 | 6 | // TODO: use subtyping before concat or push the type. 7 | pub(crate) fn sum_all(_ctx: &Ctx, types: Vec) -> Type { 8 | let mut sum = types 9 | .into_iter() 10 | .map(|ty| match ty { 11 | Type::Sum(sum) => sum, 12 | other => vec![other], 13 | }) 14 | .reduce(|a, b| a.into_iter().chain(b).collect()) 15 | .unwrap_or_default(); 16 | 17 | sum.sort(); 18 | sum.dedup(); 19 | if sum.len() == 1 { 20 | sum.pop().unwrap() 21 | } else { 22 | Type::Sum(sum) 23 | } 24 | } 25 | 26 | #[derive(Clone, Debug, PartialEq, Eq, Default)] 27 | pub struct IdGen { 28 | pub next_id: Id, 29 | } 30 | 31 | impl IdGen { 32 | pub fn next_id(&mut self) -> Id { 33 | let id = self.next_id; 34 | self.next_id += 1; 35 | id 36 | } 37 | } 38 | 39 | #[derive(Clone, Debug, PartialEq, Eq, Default)] 40 | pub struct IdentGen { 41 | pub id_gen: IdGen, 42 | } 43 | 44 | impl IdentGen { 45 | pub fn next_ident(&mut self) -> String { 46 | let mut id = self.id_gen.next_id(); 47 | let atoz: Vec<_> = ('a'..='z').into_iter().collect(); 48 | let mut ret = String::new(); 49 | let index = id % 26; 50 | ret.push(atoz[index]); 51 | id /= 26; 52 | while id != 0 { 53 | let index = match id % 26 { 54 | // 0 == 'z' 55 | 0 => 25, 56 | // 1 == 'a' 57 | other => other - 1, 58 | }; 59 | ret.insert(0, atoz[index]); 60 | id /= 26; 61 | } 62 | ret 63 | } 64 | } 65 | 66 | #[cfg(test)] 67 | mod tests { 68 | use super::*; 69 | 70 | #[test] 71 | fn test_ident_gen() { 72 | let mut gen = IdentGen::default(); 73 | assert_eq!(gen.next_ident(), "a"); 74 | assert_eq!(gen.next_ident(), "b"); 75 | for _ in 0..26 - 4 { 76 | gen.next_ident(); 77 | } 78 | assert_eq!(gen.next_ident(), "y"); 79 | assert_eq!(gen.next_ident(), "z"); 80 | assert_eq!(gen.next_ident(), "aa"); 81 | assert_eq!(gen.next_ident(), "ab"); 82 | for _ in 0..26 - 4 { 83 | gen.next_ident(); 84 | } 85 | assert_eq!(gen.next_ident(), "ay"); 86 | assert_eq!(gen.next_ident(), "az"); 87 | assert_eq!(gen.next_ident(), "ba"); 88 | assert_eq!(gen.next_ident(), "bb"); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /crates/systems/deskc-typeinfer/src/well_formed.rs: -------------------------------------------------------------------------------- 1 | use ty::Id; 2 | 3 | use crate::{ 4 | ctx::Ctx, 5 | internal_type::{Type, TypeVisitor}, 6 | }; 7 | 8 | pub(crate) struct WellFormed<'a> { 9 | pub ctx: &'a Ctx, 10 | pub well_formed: bool, 11 | } 12 | 13 | impl<'a> TypeVisitor for WellFormed<'a> { 14 | fn visit_existential(&mut self, id: &Id) { 15 | self.well_formed = self.ctx.has_existential(id) || self.ctx.get_solved(id).is_some(); 16 | } 17 | 18 | fn visit_variable(&mut self, id: &Id) { 19 | self.well_formed = self.ctx.has_variable(id); 20 | } 21 | 22 | fn visit(&mut self, ty: &Type) { 23 | if self.well_formed { 24 | self.visit_inner(ty); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/systems/deskc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 15 | ast = { path = "../../components/deskc-ast", version = "0.0.0", package = "deskc-ast" } 16 | hir = { path = "../../components/deskc-hir", version = "0.0.0", package = "deskc-hir" } 17 | mir = { path = "../../components/deskc-mir", version = "0.0.0", package = "deskc-mir" } 18 | ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 19 | codebase = { path = "../../components/dworkspace-codebase", version = "0.0.0", package = "dworkspace-codebase" } 20 | minimalist = { path = "../deskc-syntax-minimalist", version = "0.0.0", package = "deskc-syntax-minimalist" } 21 | hirgen = { path = "../../systems/deskc-hirgen", version = "0.0.0", package = "deskc-hirgen" } 22 | typeinfer = { path = "../../systems/deskc-typeinfer", version = "0.0.0", package = "deskc-typeinfer" } 23 | mirgen = { path = "../../systems/deskc-mirgen", version = "0.0.0", package = "deskc-mirgen" } 24 | 25 | salsa = "0.16" 26 | uuid = { workspace = true} 27 | anyhow = "1.0" 28 | thiserror = { workspace = true } 29 | -------------------------------------------------------------------------------- /crates/systems/deskc/src/error.rs: -------------------------------------------------------------------------------- 1 | use ids::{CardId, FileId}; 2 | use thiserror::Error; 3 | 4 | #[derive(Error, Debug)] 5 | pub enum DeskcError { 6 | #[error("card not found: {card_id:?} in {file_id:?}")] 7 | CardNotFound { card_id: CardId, file_id: FileId }, 8 | } 9 | -------------------------------------------------------------------------------- /crates/systems/deskc/src/hir_result.rs: -------------------------------------------------------------------------------- 1 | use hir::Cards; 2 | 3 | #[derive(Debug, Clone, PartialEq, Eq)] 4 | pub struct CardsResult { 5 | pub cards: Cards, 6 | pub next_id: usize, 7 | } 8 | -------------------------------------------------------------------------------- /crates/systems/deskc/src/parse_source_code.rs: -------------------------------------------------------------------------------- 1 | use ast::parser::{ParseResult, Parser}; 2 | use codebase::code::SyntaxKind; 3 | 4 | pub fn parse_source_code(syntax: &SyntaxKind, source: &str) -> Result { 5 | match syntax { 6 | SyntaxKind::Minimalist => Ok(minimalist::MinimalistSyntaxParser::parse(source)?), 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /crates/systems/deskc/src/query_result.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | /// Cheap cloneable result. 4 | pub type QueryResult = Result, QueryError>; 5 | 6 | #[derive(Debug, Clone)] 7 | /// `Arc` 8 | pub struct QueryError(Arc); 9 | 10 | impl PartialEq for QueryError { 11 | fn eq(&self, _other: &Self) -> bool { 12 | // FIXME: this is not a good solution: we need Eq object safe 13 | // always returns false to occur recomputation always on error 14 | false 15 | } 16 | } 17 | impl Eq for QueryError {} 18 | 19 | impl> From for QueryError { 20 | fn from(error: T) -> Self { 21 | QueryError(Arc::new(error.into())) 22 | } 23 | } 24 | 25 | impl QueryError { 26 | pub fn downcast_ref( 27 | &self, 28 | ) -> Option<&T> { 29 | self.0.downcast_ref() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/systems/deskvm-miri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskvm-miri" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | [dependencies] 12 | mir = { path = "../../components/deskc-mir", version = "0.0.0", package = "deskc-mir" } 13 | deskc-type = { workspace = true } 14 | deskc-macros = { workspace = true } 15 | dprocess = { path = "../../components/deskvm-dprocess", version = "0.0.0", package = "deskvm-dprocess" } 16 | dson = { path = "../../components/dson", version = "0.0.0", package = "dson" } 17 | 18 | serde = { version = "1.0", features = ["derive"] } 19 | anyhow = "1.0" 20 | strum = { version = "0.24", features = ["derive"] } 21 | once_cell = { workspace = true } 22 | thiserror = { workspace = true } 23 | 24 | [dev-dependencies] 25 | hirgen = { path = "../../systems/deskc-hirgen", version = "0.0.0", package = "deskc-hirgen" } 26 | typeinfer = { path = "../../systems/deskc-typeinfer", version = "0.0.0", package = "deskc-typeinfer" } 27 | chumsky = "0.9.2" 28 | -------------------------------------------------------------------------------- /crates/systems/deskvm-miri/src/const_stmt.rs: -------------------------------------------------------------------------------- 1 | use mir::stmt::Const; 2 | 3 | use crate::value::Value; 4 | 5 | pub(crate) fn eval(value: &Const) -> Value { 6 | match value { 7 | Const::Int(value) => Value::Int(*value), 8 | Const::Rational(a, b) => Value::Rational(*a, *b), 9 | Const::Real(value) => Value::Real(*value), 10 | Const::String(value) => Value::String(value.clone()), 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /crates/systems/deskvm-miri/src/interpreter_builder.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, sync::Arc}; 2 | 3 | use deskc_type::{conclusion::TypeConclusions, Type}; 4 | use dprocess::{interpreter::Interpreter, interpreter_builder::InterpreterBuilder}; 5 | use mir::mir::Mir; 6 | use thiserror::Error; 7 | 8 | use crate::{eval_mir, value::Value}; 9 | 10 | #[derive(Error, Debug)] 11 | pub enum MiriBuilderCreationError { 12 | #[error("Parameter not found {0:?}")] 13 | ParameterNotFound(Type), 14 | } 15 | 16 | #[derive(Debug)] 17 | pub struct MiriBuilder { 18 | pub mir: Mir, 19 | pub parameters: HashMap, 20 | pub type_conclusion: Arc, 21 | } 22 | 23 | impl InterpreterBuilder for MiriBuilder { 24 | fn build(&self) -> Box { 25 | Box::new(eval_mir( 26 | self.mir.clone(), 27 | self.parameters.clone(), 28 | self.type_conclusion.clone(), 29 | )) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/systems/deskvm-miri/src/operators/helpers.rs: -------------------------------------------------------------------------------- 1 | use crate::value::Value; 2 | 3 | pub fn lr(value: &Value) -> (&Value, &Value) { 4 | let Value::Product(values) = value else { panic!("Expected product for integer operation")}; 5 | let vec: Vec<_> = values 6 | .iter() 7 | .map(|(key, value)| match key { 8 | deskc_type::Type::Label { label, item: _ } => { 9 | let left = label == "l"; 10 | (left, value) 11 | } 12 | _ => (false, value), 13 | }) 14 | .collect(); 15 | let l = vec 16 | .iter() 17 | .find(|(left, _)| *left) 18 | .expect("left operand of operator not found") 19 | .1; 20 | let r = vec 21 | .iter() 22 | .find(|(left, _)| !*left) 23 | .expect("right operand of operator not found") 24 | .1; 25 | (l, r) 26 | } 27 | -------------------------------------------------------------------------------- /crates/systems/deskvm-miri/src/operators/int.rs: -------------------------------------------------------------------------------- 1 | use deskc_macros::effect; 2 | 3 | use crate::value::{OperatorOutput, Value}; 4 | 5 | use super::helpers::lr; 6 | 7 | pub fn add(value: &Value) -> OperatorOutput { 8 | let (l, r) = int_lr(value); 9 | OperatorOutput::Return(Value::Int(l + r)) 10 | } 11 | 12 | pub fn sub(value: &Value) -> OperatorOutput { 13 | let (l, r) = int_lr(value); 14 | OperatorOutput::Return(Value::Int(l - r)) 15 | } 16 | 17 | pub fn mul(value: &Value) -> OperatorOutput { 18 | let (l, r) = int_lr(value); 19 | OperatorOutput::Return(Value::Int(l * r)) 20 | } 21 | 22 | pub fn div(value: &Value) -> OperatorOutput { 23 | let (l, r) = int_lr(value); 24 | if r == 0 { 25 | OperatorOutput::Perform { 26 | effect: effect!(r#"@`division by zero` 'integer ~> @quot 'integer"#), 27 | input: Value::Int(l), 28 | } 29 | } else { 30 | OperatorOutput::Return(Value::Int(l / r)) 31 | } 32 | } 33 | 34 | pub fn int_lr(value: &Value) -> (i64, i64) { 35 | let (l, r) = lr(value); 36 | let Value::Int(l) = l else { panic!("left operand of integer operator not an integer")}; 37 | let Value::Int(r) = r else { panic!("right operand of integer operator not an integer")}; 38 | (*l, *r) 39 | } 40 | -------------------------------------------------------------------------------- /crates/systems/deskvm-miri/src/operators/mod.rs: -------------------------------------------------------------------------------- 1 | mod cmp; 2 | mod helpers; 3 | mod int; 4 | 5 | use deskc_macros::ty; 6 | use std::collections::HashMap; 7 | use strum::IntoEnumIterator; 8 | 9 | use deskc_type::Type; 10 | use once_cell::sync::Lazy; 11 | 12 | use crate::value::{OperatorOutput, Value}; 13 | 14 | pub static OPERATORS: Lazy> = Lazy::new(|| { 15 | Operator::iter() 16 | .map(|operator| (operator.ty(), operator)) 17 | .collect() 18 | }); 19 | 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, strum::EnumIter)] 21 | pub enum Operator { 22 | IntAdd, 23 | IntSub, 24 | IntMul, 25 | IntDiv, 26 | Rem, 27 | RealEq, 28 | RealCmp, 29 | } 30 | 31 | impl Operator { 32 | pub fn ty(&self) -> Type { 33 | match self { 34 | Operator::IntAdd => { 35 | ty!(r#"\ *<@l 'integer, @r 'integer> -> @sum 'integer"#) 36 | } 37 | Operator::IntSub => { 38 | ty!(r#"\ *<@l 'integer, @r 'integer> -> @diff 'integer"#) 39 | } 40 | Operator::IntMul => { 41 | ty!(r#"\ *<@l 'integer, @r 'integer> -> @prod 'integer"#) 42 | } 43 | Operator::IntDiv => ty!(r#" 44 | \ *<@l 'integer, @r 'integer> -> ! { 45 | @`division by zero` 'integer ~> @quot 'integer 46 | } @quot 'integer 47 | "#), 48 | Operator::Rem => ty!(r#" 49 | \ *<@l 'integer, @r 'integer> -> ! { 50 | @`division by zero` 'integer ~> *<@quot 'integer, @rem 'integer> 51 | } *<@quot 'integer, @rem 'integer> 52 | "#), 53 | Operator::RealEq => { 54 | ty!(r#"\ *<@l 'real, @r 'real> -> +<@equal *<>, @unequal *<>>"#) 55 | } 56 | Operator::RealCmp => { 57 | ty!(r#"\ *<@l 'real, @r 'real> -> +<@less *<>, @equal *<>, @greater *<>>"#) 58 | } 59 | } 60 | } 61 | 62 | pub fn call(&self, value: &Value) -> OperatorOutput { 63 | match self { 64 | Operator::IntAdd => int::add(value), 65 | Operator::IntSub => int::sub(value), 66 | Operator::IntMul => int::mul(value), 67 | Operator::IntDiv => int::div(value), 68 | Operator::Rem => todo!(), 69 | Operator::RealEq => cmp::real_eq(value), 70 | Operator::RealCmp => cmp::real_cmp(value), 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /crates/systems/deskvm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskvm" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | dprocess = { path = "../../components/deskvm-dprocess", version = "0.0.0", package = "deskvm-dprocess" } 15 | ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 16 | 17 | anyhow = "1.0" 18 | parking_lot = { workspace = true } 19 | 20 | [dev-dependencies] 21 | uuid = { version = "1.3", features = ["v4"] } 22 | mir = { path = "../../components/deskc-mir", version = "0.0.0", package = "deskc-mir" } 23 | miri = { path = "../deskvm-miri", version = "0.0.0", package = "deskvm-miri" } 24 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/desk_vm/dprocesses.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use dprocess::{ 4 | dprocess::{DProcess, DProcessId}, 5 | dprocess_manifest::DProcessManifest, 6 | }; 7 | 8 | use super::DeskVm; 9 | 10 | impl DeskVm { 11 | pub fn spawn(&self, manifest: &DProcessManifest) -> DProcessId { 12 | let process = Arc::new(DProcess::new(manifest)); 13 | self.dprocesses 14 | .write() 15 | .insert(process.id.clone(), process.clone()); 16 | self.migration_logic 17 | .write() 18 | .notify_new_dprocess(&process.id); 19 | process.id.clone() 20 | } 21 | 22 | pub fn delete_dprocess(&self, id: &DProcessId) { 23 | if self.dprocesses.write().remove(id).is_some() { 24 | self.migration_logic.write().notify_deleted_dprocess(id); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/desk_vm/mod.rs: -------------------------------------------------------------------------------- 1 | mod dprocesses; 2 | mod processors; 3 | mod read_locks; 4 | mod reduce; 5 | mod run_migration_logic; 6 | mod status_updates; 7 | 8 | use std::{ 9 | collections::{BTreeMap, HashMap}, 10 | sync::Arc, 11 | }; 12 | 13 | use dprocess::{ 14 | dprocess::{DProcess, DProcessId}, 15 | migration_logic::MigrationLogic, 16 | name_registry::NameRegistry, 17 | processor::{ProcessorName, ProcessorWithScheduler}, 18 | status_update::StatusUpdate, 19 | vm_ref::VmRef, 20 | }; 21 | use parking_lot::RwLock; 22 | 23 | #[derive(Debug)] 24 | /// Influenced by Erlang VM but this is not tight-coupled with any interpreter of Desk-lang. 25 | /// 26 | /// It allows any interpreter or executable binaries to be managed as a d-process in DeskVM. 27 | /// For example, you can run a sandboxed DeskVM in a DeskVM (DeskVM on DeskVM). 28 | // Fields must be private to prevent deadlocks and invalid access. 29 | pub struct DeskVm { 30 | dprocesses: RwLock>>, 31 | processors: RwLock>>, 32 | migration_logic: RwLock>, 33 | name_registry: RwLock, 34 | status_updates: RwLock>, 35 | } 36 | 37 | impl DeskVm { 38 | pub fn new(migration_logic: impl MigrationLogic + 'static) -> Self { 39 | Self { 40 | dprocesses: Default::default(), 41 | processors: Default::default(), 42 | migration_logic: RwLock::new(Box::new(migration_logic)), 43 | name_registry: Default::default(), 44 | status_updates: Default::default(), 45 | } 46 | } 47 | 48 | pub fn vm_ref(&self) -> VmRef { 49 | VmRef::new( 50 | &self.dprocesses, 51 | &self.processors, 52 | &self.name_registry, 53 | &self.migration_logic, 54 | &self.status_updates, 55 | ) 56 | } 57 | } 58 | 59 | #[cfg(test)] 60 | mod tests { 61 | // TODO: Write tests. (It is hard to test because mry lacks features.) 62 | } 63 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/desk_vm/processors.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use dprocess::processor::{ProcessorManifest, ProcessorName, ProcessorWithScheduler}; 4 | 5 | use super::DeskVm; 6 | 7 | impl DeskVm { 8 | pub fn add_processor(&self, manifest: ProcessorManifest) { 9 | self.migration_logic 10 | .write() 11 | .notify_new_processor(&manifest.name); 12 | self.processors.write().insert( 13 | manifest.name.clone(), 14 | Arc::new(ProcessorWithScheduler::new(manifest)), 15 | ); 16 | } 17 | 18 | pub fn delete_processor(&self, name: &ProcessorName) { 19 | if self.processors.write().remove(name).is_some() { 20 | self.migration_logic.write().notify_deleted_processor(name); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/desk_vm/read_locks.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{BTreeMap, HashMap}, 3 | ops::Deref, 4 | sync::Arc, 5 | }; 6 | 7 | use dprocess::{ 8 | dprocess::{DProcess, DProcessId}, 9 | name_registry::NameRegistry, 10 | processor::{ProcessorName, ProcessorWithScheduler}, 11 | }; 12 | 13 | use super::DeskVm; 14 | 15 | impl DeskVm { 16 | pub fn read_dprocesses(&self) -> impl Deref>> + '_ { 17 | self.dprocesses.read() 18 | } 19 | 20 | pub fn read_processors( 21 | &self, 22 | ) -> impl Deref>> + '_ { 23 | self.processors.read() 24 | } 25 | 26 | pub fn read_name_registry(&self) -> impl Deref + '_ { 27 | self.name_registry.read() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/desk_vm/reduce.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use super::DeskVm; 4 | 5 | impl DeskVm { 6 | // VM never fails. 7 | /// An API for single-threaded platform such as the Web or realtime application like games. 8 | pub fn reduce(&mut self, target_duration: &Duration) { 9 | // This is a single threaded version. 10 | let divided_duration = *target_duration / self.processors.read().len() as u32; 11 | for pws in self.processors.read().values() { 12 | pws.scheduler 13 | .write() 14 | .reduce(self.vm_ref(), &pws.processor, ÷d_duration) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/desk_vm/run_migration_logic.rs: -------------------------------------------------------------------------------- 1 | use dprocess::{dprocess::DProcessId, processor_attachment::ProcessorAttachment}; 2 | 3 | use super::DeskVm; 4 | 5 | impl DeskVm { 6 | pub fn run_migration_logic(&self) { 7 | for suggestion in self 8 | .migration_logic 9 | .write() 10 | .suggest_migration(self.vm_ref()) 11 | { 12 | self.migrate(suggestion.process_id, suggestion.to); 13 | } 14 | } 15 | 16 | pub fn migrate(&self, process_id: DProcessId, to: ProcessorAttachment) { 17 | if let Some(process) = self.dprocesses.read().get(&process_id) { 18 | // Detach from current processor 19 | match &*process.read_processor_attachment() { 20 | ProcessorAttachment::Attached(processor_name) => { 21 | if let Some(processor) = self.processors.read().get(processor_name) { 22 | processor.scheduler.write().detach(&process.id); 23 | } 24 | } 25 | ProcessorAttachment::Detached => {} 26 | } 27 | // Attach to the new processor 28 | match &to { 29 | ProcessorAttachment::Attached(processor_name) => { 30 | if let Some(processor) = self.processors.read().get(processor_name) { 31 | processor.scheduler.write().attach(process.clone()); 32 | } 33 | } 34 | ProcessorAttachment::Detached => {} 35 | } 36 | process.update_processor_attachment(to); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/desk_vm/status_updates.rs: -------------------------------------------------------------------------------- 1 | use dprocess::status_update::StatusUpdate; 2 | 3 | use super::DeskVm; 4 | 5 | impl DeskVm { 6 | pub fn flush_status_updates(&self) -> Vec { 7 | self.status_updates.write().drain(..).collect() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod desk_vm; 2 | pub mod migration_logic; 3 | pub mod scheduler; 4 | -------------------------------------------------------------------------------- /crates/systems/deskvm/src/scheduler.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{HashMap, VecDeque}, 3 | sync::Arc, 4 | time::Duration, 5 | }; 6 | 7 | use dprocess::{ 8 | dprocess::{DProcess, DProcessId}, 9 | processor::Processor, 10 | scheduler::Scheduler, 11 | status::DProcessStatus, 12 | status_update::StatusUpdate, 13 | vm_ref::VmRef, 14 | }; 15 | 16 | #[derive(Debug, Default)] 17 | /// This is a scheduler that is supported officially. 18 | /// This should have the same capability as Erlang VM's one in the future. 19 | pub struct OfficialScheduler { 20 | run_queue: VecDeque>, 21 | process_status: HashMap, 22 | } 23 | 24 | impl Scheduler for OfficialScheduler { 25 | // An implementation for now. 26 | // This should reference the Erlang VM's scheduler. 27 | fn reduce(&mut self, vm: VmRef, _processor: &Processor, target_duration: &Duration) { 28 | let mut next_queue = VecDeque::new(); 29 | let mut running = vec![]; 30 | while let Some(dprocess) = self.run_queue.pop_front() { 31 | if let Some(status) = self.process_status.get(&dprocess.id) { 32 | // Push to next queue because process is attached. 33 | next_queue.push_back(dprocess.clone()); 34 | if *status == DProcessStatus::Running { 35 | running.push(dprocess); 36 | } 37 | } else { 38 | // Process is detached, so do not push to next queue. 39 | continue; 40 | } 41 | } 42 | let divided_duration = *target_duration / running.len() as u32; 43 | for dprocess in running { 44 | dprocess.reduce(vm, ÷d_duration); 45 | } 46 | self.run_queue = next_queue; 47 | } 48 | 49 | fn attach(&mut self, dprocess: Arc) { 50 | self.process_status 51 | .insert(dprocess.id.clone(), dprocess.read_status().clone()); 52 | self.run_queue.push_back(dprocess); 53 | } 54 | 55 | fn detach(&mut self, process_id: &DProcessId) { 56 | self.process_status.remove(process_id); 57 | } 58 | 59 | fn notify_status(&mut self, status_update: &StatusUpdate) { 60 | self.process_status 61 | .entry(status_update.dprocess_id.clone()) 62 | .and_modify(|e| *e = status_update.status.clone()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dworkspace" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | components = { path = "../../components/dworkspace-codebase", version = "0.0.0", package = "dworkspace-codebase" } 15 | deskc-ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 16 | deskc-ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 17 | deskc-ast = { path = "../../components/deskc-ast", version = "0.0.0", package = "deskc-ast" } 18 | deskc-hir = { path = "../../components/deskc-hir", version = "0.0.0", package = "deskc-hir" } 19 | deskc-hirgen = { path = "../deskc-hirgen", version = "0.0.0", package = "deskc-hirgen" } 20 | deskc-typeinfer = { path = "../deskc-typeinfer", version = "0.0.0", package = "deskc-typeinfer" } 21 | deskc = { path = "../deskc", version = "0.0.0", package = "deskc" } 22 | 23 | salsa = "0.16" 24 | serde = { version = "1.0", features = ["derive"] } 25 | thiserror = { workspace = true } 26 | bevy_ecs = { workspace = true } 27 | downcast-rs = "1.2.0" 28 | parking_lot = { workspace = true } 29 | anyhow = "1.0" 30 | 31 | [dev-dependencies] 32 | deskc-ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 33 | 34 | uuid = { version = "1.3", features = ["v4"] } 35 | mry = "0.2.6" 36 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/audit/assertion.rs: -------------------------------------------------------------------------------- 1 | use components::{ 2 | content::ContentKind, 3 | rules::{NodeOperation, SpaceOperation}, 4 | }; 5 | use deskc_ids::NodeId; 6 | 7 | use super::execute_assertion::AssertionError; 8 | 9 | #[derive(Debug, PartialEq)] 10 | pub enum Assertion { 11 | SpaceAllows(SpaceOperation), 12 | NodeAllows { 13 | node_id: NodeId, 14 | operation: NodeOperation, 15 | }, 16 | Owner, 17 | NoOwner, 18 | NodeExists(NodeId), 19 | NotReferenced(NodeId), 20 | NoOperandLoop { 21 | node_id: NodeId, 22 | operand_id: NodeId, 23 | }, 24 | OperandsHasSize { 25 | node_id: NodeId, 26 | size: usize, 27 | }, 28 | ContentKind { 29 | node_id: NodeId, 30 | kind: ContentKind, 31 | }, 32 | HasOperand { 33 | node_id: NodeId, 34 | operand_id: NodeId, 35 | }, 36 | All(Vec), 37 | Any(Vec), 38 | Contradiction(AssertionError), 39 | } 40 | 41 | impl Assertion { 42 | pub fn tautology() -> Self { 43 | Self::All(Vec::new()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug, PartialEq, Eq)] 4 | pub enum KernelError {} 5 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/history.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | use components::{ 4 | event::{Event, EventPayload}, 5 | projection::Projection, 6 | }; 7 | 8 | use crate::state::State; 9 | 10 | pub struct History { 11 | size: usize, 12 | undo_stack: VecDeque, 13 | } 14 | 15 | impl History { 16 | pub fn new(size: usize) -> Self { 17 | Self { 18 | size, 19 | undo_stack: VecDeque::new(), 20 | } 21 | } 22 | fn push(&mut self, payload: EventPayload) { 23 | self.undo_stack.push_back(payload); 24 | if self.undo_stack.len() > self.size { 25 | self.undo_stack.pop_front(); 26 | } 27 | } 28 | pub fn is_empty(&self) -> bool { 29 | self.undo_stack.is_empty() 30 | } 31 | pub fn undo_all(&mut self) -> Vec { 32 | self.undo_stack.drain(..).collect() 33 | } 34 | } 35 | 36 | impl State for History { 37 | fn handle_event(&mut self, projection: &Projection, event: &Event) { 38 | match &event.payload { 39 | EventPayload::AddOwner { user_id } => {} 40 | EventPayload::RemoveOwner { user_id } => {} 41 | EventPayload::UpdateSpaceRules { rules } => {} 42 | EventPayload::CreateNode { node_id, content } => {} 43 | EventPayload::RemoveNode { node_id } => {} 44 | EventPayload::PatchContent { node_id, patch } => {} 45 | EventPayload::PatchOperand { node_id, patch } => {} 46 | EventPayload::PatchAttribute { node_id, patch } => {} 47 | EventPayload::UpdateNodeRules { node_id, rules } => {} 48 | EventPayload::UpdateOperandRules { node_id, rules } => {} 49 | EventPayload::AddSnapshot { index, snapshot } => {} 50 | } 51 | } 52 | } 53 | 54 | #[cfg(test)] 55 | mod tests { 56 | use components::{event::EventId, user::UserId}; 57 | 58 | use super::*; 59 | 60 | fn e(payload: EventPayload) -> Event { 61 | Event { 62 | id: EventId::new(), 63 | user_id: UserId::new(), 64 | payload, 65 | } 66 | } 67 | 68 | #[test] 69 | fn test_history() { 70 | let mut history = History::new(10); 71 | let mut projection = Projection::default(); 72 | let user_id = UserId::new(); 73 | let event = e(EventPayload::AddOwner { user_id }); 74 | history.handle_event(&projection, &event); 75 | // assert_eq!(history.undo_stack, [ 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/nodes/node.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use components::node::Node; 4 | use deskc_ids::NodeId; 5 | 6 | use super::NodeQueries; 7 | 8 | pub(super) fn node(db: &dyn NodeQueries, id: NodeId) -> Arc { 9 | let flat_node = db.flat_node(id.clone()); 10 | Arc::new(Node { 11 | id, 12 | content: flat_node.content.clone(), 13 | operands: flat_node 14 | .operands 15 | .iter() 16 | .map(|child_id| db.node(child_id.clone()).as_ref().clone()) 17 | .collect(), 18 | attributes: flat_node.attributes.clone(), 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/prelude.rs: -------------------------------------------------------------------------------- 1 | pub use crate::state::State; 2 | pub use crate::Workspace; 3 | pub use components::content::Content; 4 | pub use components::event::{Event, EventId, EventPayload}; 5 | pub use components::flat_node::{Attributes, FlatNode, Operands}; 6 | pub use components::patch::{AttributePatch, ContentPatch, OperandPatch, OperandPosition}; 7 | pub use components::projection::Projection; 8 | pub use components::rules::{NodeOperation, SpaceOperation}; 9 | pub use components::user::UserId; 10 | pub use deskc_ast::expr::Expr; 11 | pub use deskc_ty::Type; 12 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/query_error.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | #[derive(Debug, Clone)] 4 | /// `Arc` 5 | pub struct QueryError(pub Arc); 6 | 7 | impl PartialEq for QueryError { 8 | fn eq(&self, _other: &Self) -> bool { 9 | // FIXME: this is not a good solution: we need Eq object safe 10 | // always returns false to occur recomputation always on error 11 | false 12 | } 13 | } 14 | impl Eq for QueryError {} 15 | 16 | impl> From for QueryError { 17 | fn from(error: T) -> Self { 18 | QueryError(Arc::new(error.into())) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/repository.rs: -------------------------------------------------------------------------------- 1 | use components::{event::Event, user::UserId}; 2 | 3 | pub trait Repository { 4 | fn poll(&mut self) -> Vec; 5 | fn commit(&mut self, event: Event); 6 | fn user_id(&self) -> UserId; 7 | } 8 | 9 | #[cfg(test)] 10 | #[mry::mry] 11 | #[derive(Default)] 12 | pub struct TestRepository {} 13 | 14 | #[cfg(test)] 15 | #[mry::mry] 16 | impl Repository for TestRepository { 17 | fn poll(&mut self) -> Vec { 18 | panic!() 19 | } 20 | fn commit(&mut self, log: Event) { 21 | panic!() 22 | } 23 | fn user_id(&self) -> UserId { 24 | panic!() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/systems/dworkspace/src/state.rs: -------------------------------------------------------------------------------- 1 | use components::{event::Event, projection::Projection}; 2 | use downcast_rs::{impl_downcast, Downcast}; 3 | 4 | pub trait State: Downcast { 5 | fn handle_event(&mut self, projection: &Projection, event: &Event); 6 | } 7 | 8 | impl_downcast!(State); 9 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deskc-test" 3 | version = "0.0.0" 4 | license = "MIT OR Apache-2.0" 5 | description = "The application platform for your cyberpunk desk" 6 | homepage = "https://github.com/Hihaheho/Desk" 7 | repository = "https://github.com/Hihaheho/Desk" 8 | readme = "../../../README.md" 9 | edition = "2021" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | deskc = { path = "../../systems/deskc", version = "0.0.0", package = "deskc" } 15 | miri = { path = "../../systems/deskvm-miri", version = "0.0.0", package = "deskvm-miri" } 16 | dprocess = { path = "../../components/deskvm-dprocess", version = "0.0.0", package = "deskvm-dprocess" } 17 | ids = { path = "../../components/deskc-ids", version = "0.0.0", package = "deskc-ids" } 18 | ast = { path = "../../components/deskc-ast", version = "0.0.0", package = "deskc-ast" } 19 | hir = { path = "../../components/deskc-hir", version = "0.0.0", package = "deskc-hir" } 20 | dson = { path = "../../components/dson", version = "0.0.0", package = "dson" } 21 | ty = { path = "../../components/deskc-type", version = "0.0.0", package = "deskc-type" } 22 | errors = { path = "../../components/deskc-errors", version = "0.0.0", package = "deskc-errors" } 23 | serde-dson = { path = "../../libs/serde-dson", version = "0.0.0" } 24 | chumsky = "0.8.0" 25 | pretty_assertions = "1.0.0" 26 | serde = { version = "1.0", features = ["derive"] } 27 | ariadne = "0.1.5" 28 | anyhow = "1.0" 29 | env_logger = "0.10.0" 30 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/.gitignore: -------------------------------------------------------------------------------- 1 | !/*.dson 2 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/001_literal.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-000000000000", 5 | @content " 6 | 1 7 | " 8 | > 9 | ], 10 | @assertions *< 11 | @runs [ 12 | *< 13 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-000000000000", 14 | @result @Success @Number @Integer 1 15 | > 16 | ] 17 | > 18 | > 19 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/002_addition.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 5 | @content ‹ 6 | ^ \ *<@l 'integer, @r 'integer> -> @sum 'integer (*<@l 1, @r 2>) 7 | › 8 | > 9 | ], 10 | @assertions *< 11 | @runs [ 12 | *< 13 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 14 | @result @Success @Number @Integer 3 15 | > 16 | ] 17 | > 18 | > 19 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/003_match.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 5 | @content ‹ 6 | $ #1 @false *<>; 7 | #2 8 | 'match & @false *<> '{ 9 | @true *<> => 1, 10 | @false *<> => 2 11 | }' 12 | › 13 | > 14 | ], 15 | @assertions *< 16 | @typed [*< 17 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca" 18 | @typings { 19 | 1 => @Label *< 20 | @label @Literal @String "false", 21 | @item @Product [] 22 | >, 23 | 2 => @Integer *<> 24 | } 25 | >] 26 | @runs [ 27 | *< 28 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 29 | @result @Success @Number @Integer 2 30 | > 31 | ] 32 | > 33 | > 34 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/004_let_function.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-000000000000", 5 | @content ‹ 6 | $ #1 \ 'integer -> 7 | ^\ *<@l 'integer, @r 'integer> -> @sum 'integer (*<@l 1, @r #2 &'integer>); 8 | ^ \ 'integer -> @sum 'integer (2) 9 | › 10 | > 11 | ], 12 | @assertions *< 13 | @typed [*< 14 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-000000000000" 15 | @typings { 16 | 1 => @Function *< 17 | @parameter @Integer *<>, 18 | @body @Label *< 19 | @label @Literal @String "sum", 20 | @item @Integer *<> 21 | > 22 | >, 23 | 2 => @Integer *<>, 24 | } 25 | >] 26 | @runs [ 27 | *< 28 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-000000000000", 29 | @result @Success @Number @Integer 3 30 | > 31 | ] 32 | > 33 | > 34 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/005_division_by_zero.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 5 | @content ‹ 6 | 'type add \ *<@l 'integer, @r 'integer> -> @sum 'integer; 7 | 'type div \ *<@l 'integer, @r 'integer> -> 8 | ! { @`division by zero` 'integer ~> @quot 'integer } @quot 'integer; 9 | #1 'handle #2 <'integer> ^ div *<@l 3, @r 0> '{ 10 | @`division by zero` 'integer ~> @quot 'integer => 11 | <'integer> ^add *<@l & @`division by zero` 'integer, 1> 12 | }' 13 | › 14 | > 15 | ], 16 | @assertions *< 17 | @typed [*< 18 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca" 19 | @typings { 20 | 1 => @Integer *<>, 21 | 2 => @Effectful *< 22 | @ty @Integer *<>, 23 | @effects @Effects [ 24 | *< 25 | @input @Label *< 26 | @label @Literal @String "division by zero", 27 | @item @Integer *<> 28 | >, 29 | @output @Label *< 30 | @label @Literal @String "quot", 31 | @item @Integer *<> 32 | > 33 | > 34 | ] 35 | > 36 | } 37 | >] 38 | @runs [ 39 | *< 40 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 41 | @result @Success @Number @Integer 4 42 | > 43 | ] 44 | > 45 | > 46 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/006_continuation.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 5 | @content ‹ 6 | 'type add \ *<@l 'integer, @r 'integer> -> @sum 'integer; 7 | 'handle '( 8 | $ ! "a" ~> 'integer; 9 | <'integer> ^add *<@l &'integer, @r &'integer> 10 | )' '{ 11 | 'string ~> 'integer => 12 | <'integer> ^add *< 13 | @l ! 1 ~> 'integer, 14 | @r ! 2 ~> 'integer, 15 | > 16 | }' 17 | › 18 | > 19 | ], 20 | @assertions *< 21 | @runs [ 22 | *< 23 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 24 | @result @Success @Number @Integer 6 25 | > 26 | ] 27 | > 28 | > 29 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/007_fibonacci.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 5 | @content ‹ 6 | ~~ type aliases 7 | 'type add \ *<@l 'integer, @r 'integer> -> @sum 'integer; 8 | 'type sub \ *<@l 'integer, @r 'integer> -> @diff 'integer; 9 | 'type eq \ *<@l 'real, @r 'real> -> +<@equal *<>, @unequal *<>>; 10 | 'type fib \ 'integer -> 'integer; 11 | 12 | ~~ let fib 13 | $ \ 'integer -> 'match ^eq *<@l &'integer, @r 0> '{ 14 | ~~ if number == 0) 15 | @equal *<> => 0 16 | ~~ if number != 0 17 | @unequal *<> => 'match ^eq *<@l &'integer, @r 1> '{ 18 | @equal *<> => 1 19 | @unequal *<> => 20 | ~~ adds fib(number - 1) and fib(number - 2) 21 | <'integer> ^add *< 22 | @l ^fib ^sub *<@l &'integer, @r 1> 23 | @r ^fib ^sub *<@l &'integer, @r 2> 24 | > 25 | }' 26 | }'; 27 | ^fib(7) 28 | › 29 | > 30 | ], 31 | @assertions *< 32 | @runs [ 33 | *< 34 | @entrypoint @File @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 35 | @result @Success @Number @Integer 13 36 | > 37 | ] 38 | > 39 | > 40 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/cases/008_cards.dson: -------------------------------------------------------------------------------- 1 | *< 2 | @files [ 3 | *< 4 | @id @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 5 | @content ‹ 6 | 'type add \ *<@l 'integer, @r 'integer> -> @sum 'integer; 7 | 'type sub \ *<@l 'integer, @r 'integer> -> @diff 'integer; 8 | 'type cmp \ *<@self 'real, @other 'real> -> +<@greater *<>, @less *<>, @equal *<>>; 9 | 10 | 'card 9883b420-f7be-468d-95f6-43884d885a33 11 | ^ 'card 9883b420-f7be-468d-95f6-aaaaaaaaaaaa \'integer -> 'integer (10); 12 | 'card 9883b420-f7be-468d-95f6-aaaaaaaaaaaa 13 | \ 'integer -> <'integer> ^add *< 14 | @l &'integer, 15 | 'match ^cmp *<@self &'integer, 3> '{ 16 | +< @greater *<>, @equal *<>> => 17 | ^ 'card 9883b420-f7be-468d-95f6-bbbbbbbbbbbb \ 'integer -> 'integer (&'integer) 18 | @less *<> => 19 | 0 20 | }' 21 | >; 22 | 'card 9883b420-f7be-468d-95f6-bbbbbbbbbbbb 23 | \ 'integer -> 24 | ^ 'card 9883b420-f7be-468d-95f6-cccccccccccc \ 'integer -> 'integer ( 25 | ^sub *<@minuend &'integer, 1> 26 | ); 27 | 'card 9883b420-f7be-468d-95f6-cccccccccccc 28 | \ 'integer -> 29 | ^ 'card 9883b420-f7be-468d-95f6-aaaaaaaaaaaa \ 'integer -> 'integer ( 30 | ^sub *<@minuend &'integer, 2> 31 | ); 32 | ? 33 | › 34 | > 35 | ], 36 | @assertions *< 37 | @runs [ 38 | *< 39 | @entrypoint @Card *< 40 | @file_id @FileId "7f9fc3e0-8b6e-4e7f-9e62-8b80b75d43ca", 41 | @card_id @CardId "9883b420-f7be-468d-95f6-43884d885a33" 42 | > 43 | @result @Success @Number @Integer 22 44 | > 45 | ] 46 | > 47 | > 48 | -------------------------------------------------------------------------------- /crates/tests/deskc-test/src/test_case.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use dprocess::value::Value; 4 | use ids::{Entrypoint, FileId}; 5 | use serde::{Deserialize, Serialize}; 6 | use ty::Type; 7 | 8 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 9 | pub struct TestCase { 10 | pub files: Vec, 11 | pub assertions: Assertions, 12 | } 13 | 14 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 15 | pub struct File { 16 | pub id: FileId, 17 | pub content: String, 18 | } 19 | 20 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 21 | pub struct Assertions { 22 | pub runs: Option>, 23 | pub typed: Option>, 24 | } 25 | 26 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 27 | pub struct Run { 28 | pub entrypoint: Entrypoint, 29 | pub result: RunResult, 30 | } 31 | 32 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 33 | pub enum RunResult { 34 | Success(Value), 35 | } 36 | 37 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 38 | pub struct Typed { 39 | pub entrypoint: Entrypoint, 40 | pub typings: HashMap, 41 | } 42 | -------------------------------------------------------------------------------- /docs/CREDITS.md: -------------------------------------------------------------------------------- 1 | # Desk Credits 2 | 3 | ## Desk Programming Language 4 | 5 | Influenced by: 6 | 7 | - [Lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)) for; 8 | - minimalism syntax and semantics 9 | - functional programming 10 | - 🚧 meta programming 11 | - [TypeScript](https://www.typescriptlang.org) for structural subtyping 12 | - [Haskell](https://www.haskell.org) for; 13 | - 🚧 type class 14 | - distinguished effectful function 15 | - [Koka](http://koka-lang.org/) for algebraic effects 16 | - [Unison](https://www.unison-lang.org) for content-addressable implementation 17 | - [Flix](https://flix.dev) for 🚧 embedded logic programming 18 | - [Rust](https://www.rust-lang.org) for; 19 | - 🚧 trait 20 | - 🚧 zero-cost abstraction 21 | - 🚧 linear type 22 | 23 | ## Desk Kernel 24 | 25 | Powered by: 26 | 27 | - [Salsa](https://salsa-rs.netlify.app) for incremental computation 28 | 29 | ## Desk X 30 | 31 | Powered by: 32 | 33 | - [Bevy Engine](https://bevyengine.org/) for parallel ECS 34 | - [egui](https://www.egui.rs/) for UI rendering 35 | -------------------------------------------------------------------------------- /docs/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /docs/decisions/dkernel/0001-we-dont-need-files-and-directories.md: -------------------------------------------------------------------------------- 1 | --- 2 | status: accepted 3 | date: 2022-11-06 4 | deciders: Ryo Hirayama 5 | --- 6 | # We don't need files and directories 7 | 8 | ## Context and Problem Statement 9 | 10 | Desk Kernel needs a kind of file system to manage them. 11 | The system is used for permission control. 12 | 13 | ## Decision Drivers 14 | 15 | * Is it minimalistic? 16 | * Is it easy to use? 17 | * Is it intuitive? 18 | 19 | ## Considered Options 20 | 21 | * We have files and directories 22 | * We have files 23 | * We have no files and directories 24 | 25 | ## Decision Outcome 26 | 27 | Chosen option: "We don't have files and directories", because it's minimalistic and easy to use. 28 | To have a kind of file system, each AST Node can have a hierarchy. 29 | We call it "the hierarchy system". 30 | 31 | ## Pros and Cons of the Options 32 | 33 | ### We have files and directories 34 | 35 | * Good, because it likes a computer's file system. 36 | * Bad, because it's hard for users that are not familiar with computers. 37 | 38 | ### We have files 39 | 40 | A file can be like a directory. 41 | 42 | * Good, because it's sophisticated. 43 | 44 | ### We don't have files and directories 45 | 46 | Each AST Node is like a file or a directory. 47 | 48 | * Good, because it's minimalistic and next state-of-art. 49 | * Good, because it has intuitive permission control. 50 | * Bad, because it's not intuitive for now. 51 | 52 | ## More Information 53 | 54 | - [this article](https://fkohlgrueber.github.io/blog/tree-structure-of-file-systems/) considers current file systems' problems, and says "I would seriously consider using this simple and general node-based structure and drop the separation between files and folders.". 55 | - Unity's hierarchy system is like our system. There is no file and directory, and each GameObject is like a file or a directory. 56 | -------------------------------------------------------------------------------- /docs/language/README.md: -------------------------------------------------------------------------------- 1 | # Desk Programming Language 2 | 3 | Note: 🚧 means "under development". 4 | 5 | ## Guides and Documentations 6 | 7 | - [Introduction of Desk-lang](/docs/language/introduction.md) 8 | 9 | ## Advanced Resources 10 | 11 | - [Desk Programming Language Formal Defintion](/docs/language/formal-definition.md) 12 | -------------------------------------------------------------------------------- /docs/language/formal-definition.md: -------------------------------------------------------------------------------- 1 | # Desk Programming Language Formal Definition 2 | 3 | ## Syntax 4 | $$ 5 | \begin{aligned} 6 | t ::=\ & \\& t_{ctx} \ t_{ty}\ t_{arg1},\ldots \\ 7 | \mid\ & \Pi t_{ctx} \ t_{fam}\ (t_{fam}\ \text{has at least one}\ \\&\ t_{ctx}\ \text{t)} \\ 8 | \mid\ & \Sigma t_{ctx} \ t_{fam}\ (t_{fam}\ \text{has at least one}\ \\&\ t_{ctx}\ \text{t)} \\ 9 | \mid\ & \\{ t_1,\ldots \\} \\ 10 | \mid\ & t_{term}:\ t_{ty} \\ 11 | \mid\ & \text{let}\ t_{ident}\ =\ t_{def}\ \text{in}\ t_e \\ 12 | \mid\ & \text{branch}\ t\ \text{begin}\ t_{ty1} \rightarrow t_{case1},\ldots\ \text{end} \\ 13 | \mid\ & \text{!} \ t_i \sim> t_o \\ 14 | \mid\ & \text{handle}\ t\ \text{begin}\ t_{i1} \sim> t_{o1} \rightarrow t_{h1},\ldots\ \text{end} \\ 15 | \mid\ & \text{@}\ t\ \mid\ \text{@@}\ t \\ 16 | \mid\ & \\# t_{attr}\ t \\ 17 | \\ 18 | program ::=\ & \cdot \mid\ program\ t_{alias} = t_{of} \mid\ program\ t \\ 19 | \\ 20 | \Gamma ::=\ & \cdot \mid\ \Gamma\ t 21 | \\ 22 | {\huge \varepsilon} ::=\ & \cdot \mid\ {\huge \varepsilon}\ t \\ 23 | \end{aligned} 24 | $$ 25 | -------------------------------------------------------------------------------- /tools/build-and-serve.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # fail fast 4 | set -euo pipefail 5 | shopt -s inherit_errexit 6 | 7 | tools/build-wasm.sh 8 | 9 | # cargo install basic-http-server 10 | basic-http-server -a 0.0.0.0:4000 crates/apps/desk-x/public 11 | -------------------------------------------------------------------------------- /tools/build-wasm.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # fail fast 4 | set -euo pipefail 5 | shopt -s inherit_errexit 6 | 7 | cargo build --bin desk-x --target wasm32-unknown-unknown --release 8 | wasm-bindgen --out-dir crates/apps/desk-x/public --target web target/wasm32-unknown-unknown/release/desk-x.wasm 9 | -------------------------------------------------------------------------------- /tools/check-ci.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # fail fast 4 | set -eo pipefail 5 | shopt -s inherit_errexit 6 | 7 | for OPT in "$@" 8 | do 9 | case $OPT in 10 | --no-cargo-deny) 11 | NO_CARGO_DENY=1 12 | ;; 13 | esac 14 | done 15 | 16 | tools/diff-crates.sh 17 | [[ -z ${NO_CARGO_DENY} ]] && cargo deny check --config configs/deny.toml 18 | cargo fmt --all -- --check 19 | cargo clippy --all-targets --all-features -- -D warnings -W clippy::all -W clippy::dbg_macro 20 | cargo check --tests --all-features 21 | cargo test --no-run --locked --all-features 22 | cargo test --all-features 23 | -------------------------------------------------------------------------------- /tools/deploy-wasm.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # fail fast 4 | set -euo pipefail 5 | shopt -s inherit_errexit 6 | 7 | tools/build-wasm.sh 8 | cat < firebase.json 9 | { 10 | "hosting": { 11 | "public": "crates/apps/desk-x/public" 12 | } 13 | } 14 | EOF 15 | firebase --project hihaheho-e58a7 deploy --only hosting 16 | rm firebase.json 17 | -------------------------------------------------------------------------------- /tools/diff-crates.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | diff <(grep name -r crates/*/*/Cargo.toml | awk '{print $3}' | sed 's/"//g' | grep -v test | sort) <(tools/list-crates.sh | sort) 4 | exit $? 5 | -------------------------------------------------------------------------------- /tools/list-crates.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | cat configs/crates.txt | grep -v "^#" | sed 's/^!//' | awk NF 4 | -------------------------------------------------------------------------------- /tools/publish-crates.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # fail fast 4 | set -euo pipefail 5 | shopt -s inherit_errexit 6 | 7 | VERSION=0.0.0 8 | 9 | skip_until=${1:-""} 10 | skip="yes" 11 | if [ -z $skip_until ]; then 12 | skip="no" 13 | fi 14 | 15 | tools/list-crates.sh | while read crate; do 16 | if [ $skip = "yes" ]; then 17 | if [ $crate = $skip_until ]; then 18 | skip="no" 19 | else 20 | continue 21 | fi 22 | fi 23 | if cargo search ${crate} | grep --quiet "${crate} = \"${VERSION}\""; then 24 | echo "Skipping ${crate} because it is already published" 25 | sleep 5 26 | else 27 | echo "Publishing ${crate}" 28 | cargo publish -p ${crate} --no-verify 29 | sleep 20 30 | fi 31 | done 32 | --------------------------------------------------------------------------------