hades-lang

所属分类:编程语言基础
开发工具:kotlin
文件大小:0KB
下载次数:0
上传日期:2023-11-13 16:18:38
上 传 者sh-1993
说明:  一种系统编程语言
(A systems programming language)

文件列表:
.editorconfig (20, 2023-11-21)
.idea/ (0, 2023-11-21)
.idea/codeStyles/ (0, 2023-11-21)
.idea/codeStyles/Project.xml (381, 2023-11-21)
.idea/codeStyles/codeStyleConfig.xml (144, 2023-11-21)
.idea/runConfigurations/ (0, 2023-11-21)
.idea/runConfigurations/HadesTestSuite.xml (859, 2023-11-21)
bdwgc/ (0, 2023-11-21)
bindings/ (0, 2023-11-21)
bindings/cjson.hds (1821, 2023-11-21)
bindings/gl.hds (19302, 2023-11-21)
bindings/glfw.hds (690, 2023-11-21)
build.gradle.kts (0, 2023-11-21)
build_all_distributions.sh (152, 2023-11-21)
build_libhdc.sh (259, 2023-11-21)
cJSON/ (0, 2023-11-21)
default.properties (66, 2023-11-21)
design/ (0, 2023-11-21)
design/ref.md (2757, 2023-11-21)
distribution_smoke_test.py (1044, 2023-11-21)
docs/ (0, 2023-11-21)
docs/index.md (592, 2023-11-21)
examples/ (0, 2023-11-21)
examples/gtk-hello-world/ (0, 2023-11-21)
examples/gtk-hello-world/Makefile (700, 2023-11-21)
examples/gtk-hello-world/gtk.hds (3981, 2023-11-21)
examples/gtk-hello-world/main.hds (1249, 2023-11-21)
examples/gui-app/ (0, 2023-11-21)
... ...

# Hades [![Build](https://github.com/dhruvrajvanshi/hades-lang/actions/workflows/ci.yml/badge.svg)](https://github.com/dhruvrajvanshi/hades-lang/actions/workflows/ci.yml) [![codecov](https://codecov.io/github/dhruvrajvanshi/hades-lang/branch/master/graph/badge.svg?token=Y3E81BS5OK)](https://codecov.io/github/dhruvrajvanshi/hades-lang) A systems level programming language that compiles to LLVM - [x] Easy interop with C - [x] Structs - [x] Generic types - [x] Extension Methods - [x] Closures - Pure stack allocated closures (i.e. can't be returned from functions and stored in structs right now) - Once we have proper destructor semantics, I'll implement heap allocated closures that get cleaned up according to their lifetime. - [ ] Named function arguments - [x] Traits - [x] Use after move checking: - Unlike Rust, move is explicit. Types can be made Move only by implementing a builtin NoCopy trait. - This is like C++ except the compiler prevents you from using a reference after moving it. - [ ] Rust style destructors using `Drop` trait (Not implemented) - [x] Associated trait types - [x] Algebraic data types (enums) - [x] Windows support - Editor integration - Syntax hilighting - [x] VSCode - [x] Intellij - [ ] Error highlighting - [ ] Autocompletion - [x] Debugger support: - Very basic support for gdb and lldb debug symbols is supported. This allows stepping through code using VS code. No local variables are shown yet. ## Intro Hades is a language that I as an application developer would want to use. Things that it focuses on - Ergonomics: Should not be too low level like Rust or C++. - Interop: Should be easy to bridge to other languages (currently, writing bindings for C is relatively easy). - Performance: Should still be able to control memory layout to write high performance/allocation free code when required. - Library oriented: I want the generic system to be like Swift. i.e. by default, generics should be compiled down to regular parameters so that libraries can be separately compiled. As an optimization, the compiler should monomorphize the generic calls if required. Hades doesn't currently work like this. As of now, everything is monomorphized, and there's no way to compile libraries. - Modern: Algebraic data types, first class closures, - IDE features: This is a stretch goal, but I'd like to have an LSP implementation. ## Getting started ### Prerequisites * Python 3 needs to be installed. * OpenJDK 11 or later needs to be installed (https://adoptopenjdk.net/ has Java builds for windows). On Linux, you can usually find `openjdk-11` builds in your package manager (`apt/dnf install openjdk-11`) ### Installation You can install the latest version of hades using this command ```sh curl https://raw.githubusercontent.com/dhruvrajvanshi/hades-lang/master/install.py | python3 - ``` On windows, you can run this in prowershell ```powershell # make sure you've installed python 3 beforehand (Invoke-webrequest -URI "https://raw.githubusercontent.com/dhruvrajvanshi/hades-lang/master/install.py").Content | python - ``` This will install the latest build from the master branch in ~/.hades/versions/latest/hades (%APPDATA%\hades on windows). Now, restarting your terminal should put `hades` command on your path. You can install specific releases by appending `---version ` to the commands, where `` can be replaced with any [tag version](https://github.com/dhruvrajvanshi/hades-lang/tags) from the releases page. `latest` tag is automatically built when something is pushed to master. ## Development The current compiler lives under the hadesboot directory (self hosting is a long term goal). Running the test suite is done using gradle. ``` ./gradlew test ``` Building the compiler ``` ./gradlew install ``` This installs the compiler executable in hadesboot/target directory. Check out examples directory makefiles to see how a typical hades binary is built. ## Editor support Basic syntax hilighting is supported ### IntelliJ 1. Git checkout this repo. 2. Go to `File > Settings > Editor > TextMate bundles` 3. Add a new bundle from directory `ide/vscode-hades`. You should now get basic syntax hilighting for .hds files. ### VS Code Plugin isn't published yet. It's in `ide/vscode-hades` Figure it out. Instructions to come in the future. ## Hello world ```scala extern def puts(*u8): Void = puts // by default, programs are linked with libc. This means you can declare pre-existing C functions as extern def main(): Void { puts(b"Hello world"); } ``` Local variables ```scala def main(): Void { val x: *Byte = b"Hello world"; // the type annotation can be omitted c.puts(x); } ``` ## Some bindings for a C library ![gtk bindings screenshot](images/screenshot.png) ## A bigger example ```scala // A struct has a packed layout like C struct Pair[A, B] { val first: A; val second: B; } def main(): Void { if true { val pair = Pair(1, b"text"); // Type arguments to Pair are inferred print_pair_second(pair); // function arguments are passed as value (a copy of pair is sent to print_pair val pair_ptr = &pair; // you can take address of local variables and pass them as pointers pair.print_second(); // this is an extension function call val mut_pair_ptr = &mut pair // taking a mutable pointer puts(mut_pair_ptr.second) // calling dot on a pointer dereferences it val second_field_ptr = &pair.second // we can get a field offset using &stuctval.field mut_pair_ptr.second = b"value" // dereferencing dot operator works for assignments as well } } def print_pair_second[T](pair: Pair[T, *Byte]): Void { c.puts(pair.second); } // extension methods can be defined for any type including types from // different libraries // some/nested_module.hds extension PairExtensions[T] for Pair[T, *Byte] { // `*this` means this extension takes its receiver by pointer // Use `*mut this` to treat receiver pointer as mutable // and `this` to take it as value def print_second(*this): Void { c.puts(this.second); // Unlike this.second on a pointer to a struct is equivalent to this->second in C } } // in another file // Importing a module brings extensions exported by that module // into scope. This isn't transitive i.e. extensions imported by // nested_module would not be available here. You have to separately // import those. import some.nested_module as nested_module; def main(): Void { val x = Pair(true, b"x"); // because extension method is declared as *this, // we have to take pointer to x to pass it to the method. (&x).print_second(); } ``` ## Traits Hades has a trait system similar to Rust. Traits allow us to define operations on generic type parameters. This has the advantage of better error messages than C++ while still being more powerful than simpler systems like Java interfaces. ```scala trait Printable[Self] { def print(self: Self): Void; } // Interfaces are implemented outside the type declaration // this means you can make builtin types implement new interfaces implementation Printable[Bool] { def print(self: Bool): Void { if *this { c.puts(b"true"); } else { c.puts(b"false"); } } } // Unlike C++, the body of this function can be checked independently // of call sites. No type errors on expanded templates :) // The where clause is a requirement on type T and a caller can only pass things that are Printable def print[T](value: T): Void where Printable[T] { Printable[T].print(value); } def main(): Void { print(true); print(10); // type error: Printable[Int] not found } ``` Implementations can have type parameters and where clauses, making it possible to implement traits for generic types based on other traits. ```scala struct Box[T] { val value: T; } // this declaration says that for all type Ts, Box[T] is printable if T is printable. // This makes it more powerful that Java/C# interfaces where it's not possible // to have an interface for Equality/Hashing and have generic containers conform // to them based on their type parameter. // Equality and Hashing, Stringification is baked into all objects in Java to get around this problem // but it doesn't solve it for custom interfaces. implementation[T] Printable[Box[T]] where Printable[T] { def print(self: Box[T]): Void { print(b"Box("); // implementation Box[*Byte] is omitted for berevity print(self); print(b")"); } } def f() { print(Box(true)); // works print(Box(b"hello")); // works print(Box(10)); // Type error because we haven't provided a Printable[Int] implementation } ``` Although traits directly can't define extension methods yet, (i.e. you have to call `Trait[Type].method(value)`, instead of `value.method()`, extension definitions can have where clauses, allowing you to wrap trait functions as extension methods. ```scala extension StringifiableExtensions[T] for T where Stringifiable[T] { def to_string(this): *Byte { return Stringifiable[T].print(this); } } def f[T](value: T): Void where Stringifiable[T] { // now you can call to_string as a method value.to_string(); } ``` Directly defining methods inside traits is being considered. ## Enum types Enum types (also known as algebraic data types) allow you to represent types that can be one of a finite set of cases. ```scala enum Optional[T] { Some(value: T); None; } /// This compiles down to the equivalent of this (the names are mangled so /// this isn't valid hades source code, but they are equivalent /// struct Optional[T] { /// val tag: u8 /// val payload: Union[Optional.Some[T], Optional.None] /// } /// struct Optional.Some[T] { /// val 0: T /// } /// const Optional.Some.tag : u8 = 0 /// struct Optional.None[T] {} /// const Optional.None.tag : u8 = 1 /// Optional.Some[u32](1) ~ Optional[u32](Optional.Some.tag, Optional.Some(1)) /// Optional.None[u32] ~ Optional[u32](Optional.None.tag) def main(): Void { // Enum types can be pattern matched on. // The cases are checked at compile time. If you // decide to add a new case, that will have to // be handled in existing match statements. val ten = match Optional.Some(10) { // notice the use of `val` keyword to disambiguate enum case names // from parameter binding patterns. // this is different from rust, where patterns can be qualified, // haskell, where data Cases have to start with uppercase (I think?) // and swift where constructor cases are prefixed with a `.` to distinguish // from bound patterns. // An explicit `val` keyword has an added advantage of being easily searchable. Some(val value) -> value, None -> 0 }; val zero = match Optional.None[Int] { Some(val value) -> value, None -> 0 }; } ``` Enums don't have to carry extra data. ``` // The underlying representation of an enum tag is // u8 (8 bit unsigned integer) enum Token { Identifier Number String } ``` This will be similar to a C style enum (except more type safe because you can't assign itegers to them) ## Closures Hades supports a limited form of closures that are allocated on the stack. This means that they can't be returned from functions or stored in structs. Once proper destruction and move semantics are implemented, this restriction can be lifted by heap allocated closures. ```scala def main(): Void { puts(apply(true, |value| if (value) b"true" else b"false")); // prints "true" // closures can have a block body // prints "Done" puts(apply(true, |value| { if value { return b"Done"; } else { return b"Not done"; } }); } def apply[T, U](arg: T, fn: (T) -> U): U { return fn(arg); } ``` ## Misc Check the suite directory for a few contrived examples used as an automated test suite. There's a gtk-hello-world which is a good representative program. Proper documentation coming in the future.

近期下载者

相关文件


收藏者