mirror of
https://github.com/HigherOrderCO/Kind1.git
synced 2024-10-26 16:38:23 +03:00
merge: branch 'master' of github.com:Kindelia/Kind
This commit is contained in:
commit
8986096d0b
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -742,6 +742,7 @@ name = "kind-target-kdl"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fxhash",
|
"fxhash",
|
||||||
|
"im-rc",
|
||||||
"kind-derive",
|
"kind-derive",
|
||||||
"kind-report",
|
"kind-report",
|
||||||
"kind-span",
|
"kind-span",
|
||||||
@ -781,7 +782,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kind2"
|
name = "kind2"
|
||||||
version = "0.3.6"
|
version = "0.3.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap 4.0.29",
|
"clap 4.0.29",
|
||||||
@ -793,8 +794,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kindelia_common"
|
name = "kindelia_common"
|
||||||
version = "0.1.5"
|
version = "0.1.7"
|
||||||
source = "git+https://github.com/developedby/Kindelia/?branch=kdl-lang-crate#ff2f75e319c167cbc9d19cbc35fbe0d9a510b56a"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8de1aea9d5b1e5bce50affa6c3d720f48a8bcf59bc8e53be68e6509740554cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec",
|
"bit-vec",
|
||||||
"hex",
|
"hex",
|
||||||
@ -807,12 +809,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kindelia_lang"
|
name = "kindelia_lang"
|
||||||
version = "0.1.0"
|
version = "0.1.7"
|
||||||
source = "git+https://github.com/developedby/Kindelia/?branch=kdl-lang-crate#ff2f75e319c167cbc9d19cbc35fbe0d9a510b56a"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4306d4e6a8215201432d0c0b0010ec6374dd31982a02adab41fa491c453f909f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"kindelia_common",
|
"kindelia_common",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-checker"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "Type checker for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -2,10 +2,11 @@
|
|||||||
//! a Expr of the kind-tree package.
|
//! a Expr of the kind-tree package.
|
||||||
|
|
||||||
use kind_span::{EncodedRange, Range};
|
use kind_span::{EncodedRange, Range};
|
||||||
use kind_tree::backend::Term;
|
|
||||||
use kind_tree::symbol::{Ident, QualifiedIdent};
|
use kind_tree::symbol::{Ident, QualifiedIdent};
|
||||||
use kind_tree::{desugared, Operator};
|
use kind_tree::{desugared, Operator};
|
||||||
|
|
||||||
|
use hvm::Term;
|
||||||
|
|
||||||
use crate::diagnostic::TypeDiagnostic;
|
use crate::diagnostic::TypeDiagnostic;
|
||||||
use desugared::Expr;
|
use desugared::Expr;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "kind2"
|
name = "kind2"
|
||||||
version = "0.3.6"
|
version = "0.3.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A pure functional functional language that uses the HVM."
|
description = "A pure functional functional language that uses the HVM."
|
||||||
repository = "https://github.com/Kindelia/Kind2"
|
repository = "https://github.com/Kindelia/Kind2"
|
||||||
|
94
crates/kind-cli/README.md
Normal file
94
crates/kind-cli/README.md
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
Kind2
|
||||||
|
=====
|
||||||
|
|
||||||
|
**Kind2** is a **functional programming language** and **proof assistant**.
|
||||||
|
|
||||||
|
It is a complete rewrite of [Kind1](https://github.com/kindelia/kind-legacy), based on
|
||||||
|
[HVM](https://github.com/kindelia/hvm), a **lazy**, **non-garbage-collected** and **massively parallel** virtual
|
||||||
|
machine. In [our benchmarks](https://github.com/kindelia/functional-benchmarks), its type-checker outperforms every
|
||||||
|
alternative proof assistant by a far margin, and its programs can offer exponential speedups over Haskell's GHC. Kind2
|
||||||
|
unleashes the [inherent parallelism of the Lambda
|
||||||
|
Calculus](https://github.com/VictorTaelin/Symmetric-Interaction-Calculus) to become the ultimate programming language of
|
||||||
|
the next century.
|
||||||
|
|
||||||
|
**Welcome to the inevitable parallel, functional future of computers!**
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
Pure functions are defined via equations, as in [Haskell](https://www.haskell.org/):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Applies a function to every element of a list
|
||||||
|
map <a> <b> (list: List a) (f: a -> b) : List b
|
||||||
|
map a b Nil f = Nil
|
||||||
|
map a b (Cons head tail) f = Cons (f head) (map tail f)
|
||||||
|
```
|
||||||
|
|
||||||
|
Side-effective programs are written via monads, resembling [Rust](https://www.rust-lang.org/) and [TypeScript](https://www.typescriptlang.org/):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Prints the double of every number up to a limit
|
||||||
|
Main : IO (Result () String) {
|
||||||
|
ask limit = IO.prompt "Enter limit:"
|
||||||
|
for x in (List.range limit) {
|
||||||
|
IO.print "{} * 2 = {}" x (Nat.double x)
|
||||||
|
}
|
||||||
|
return Ok ()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Theorems can be proved inductively, as in [Agda](https://wiki.portal.chalmers.se/agda/pmwiki.php) and [Idris](https://www.idris-lang.org/):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Black Friday Theorem. Proof that, for every Nat n: n * 2 / 2 == n.
|
||||||
|
black_friday_theorem (n: Nat) : Equal Nat (Nat.half (Nat.double n)) n
|
||||||
|
black_friday_theorem Nat.zero = Equal.refl
|
||||||
|
black_friday_theorem (Nat.succ n) = Equal.apply (x => Nat.succ x) (black_friday_theorem n)
|
||||||
|
```
|
||||||
|
|
||||||
|
For more examples, check the [Wikind](https://github.com/kindelia/wikind).
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
First, install [Rust](https://www.rust-lang.org/tools/install) first, then enter:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo install kind2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Warning:
|
||||||
|
New versions probably are not in `cargo`, so you can install the current version of kind2 by following these instructions:
|
||||||
|
|
||||||
|
1. Install Rust Nightly Toolchain
|
||||||
|
2. Clone the repository
|
||||||
|
3. `cargo install --path crates/kind-cli --force`
|
||||||
|
|
||||||
|
Then, use any of the commands below:
|
||||||
|
|
||||||
|
Command | Usage | Note
|
||||||
|
---------- | ------------------------- | --------------------------------------------------------------
|
||||||
|
Check | `kind2 check file.kind2` | Checks all definitions.
|
||||||
|
Eval | `kind2 eval file.kind2` | Runs using the type-checker's evaluator.
|
||||||
|
Run | `kind2 run file.kind2` | Runs using HVM's evaluator, on Rust-mode.
|
||||||
|
To-HVM | `kind2 to-hvm file.kind2` | Generates a [.hvm](https://github.com/kindelia/hvm) file. Can then be compiled to C.
|
||||||
|
To-KDL | `kind2 to-kdl file.kind2` | Generates a [.kdl](https://github.com/kindelia/kindelia) file. Can then be deployed to [Kindelia](https://github.com/kindelia/kindelia).
|
||||||
|
|
||||||
|
Executables can be generated via HVM:
|
||||||
|
|
||||||
|
```
|
||||||
|
kind2 to-hvm file.kind2
|
||||||
|
hvm compile file.hvm
|
||||||
|
clang -O2 file.c -o file
|
||||||
|
./file
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- If you need support related to Kind, email [support.kind@kindelia.org](mailto:support.kind@kindelia.org)
|
||||||
|
|
||||||
|
- For Feedbacks, email [kind@kindelia.org](mailto:kind@kindelia.org)
|
||||||
|
|
||||||
|
- To ask questions and join our community, check our [Discord Server](https://discord.gg/kindelia).
|
@ -3,6 +3,7 @@ name = "kind-derive"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "Derive generator the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -11,4 +12,4 @@ kind-span = { path = "../kind-span", version = "0.1.1" }
|
|||||||
kind-tree = { path = "../kind-tree", version = "0.1.1" }
|
kind-tree = { path = "../kind-tree", version = "0.1.1" }
|
||||||
kind-report = { path = "../kind-report", version = "0.1.1" }
|
kind-report = { path = "../kind-report", version = "0.1.1" }
|
||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
im-rc = "*"
|
im-rc = "15.1.0"
|
@ -3,6 +3,7 @@ name = "kind-driver"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "Driver for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -14,8 +15,8 @@ kind-report = { path = "../kind-report", version = "0.1.1" }
|
|||||||
kind-checker = { path = "../kind-checker", version = "0.1.1" }
|
kind-checker = { path = "../kind-checker", version = "0.1.1" }
|
||||||
kind-pass = { path = "../kind-pass", version = "0.1.1" }
|
kind-pass = { path = "../kind-pass", version = "0.1.1" }
|
||||||
|
|
||||||
kind-target-hvm = { path = "../kind-target-hvm" }
|
kind-target-hvm = { path = "../kind-target-hvm", version = "0.1.0" }
|
||||||
kind-target-kdl = { path = "../kind-target-kdl" }
|
kind-target-kdl = { path = "../kind-target-kdl", version = "0.1.0" }
|
||||||
|
|
||||||
hvm = "1.0.3"
|
hvm = "1.0.3"
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ use kind_pass::{desugar, erasure, inline::inline_book};
|
|||||||
use kind_report::report::FileCache;
|
use kind_report::report::FileCache;
|
||||||
use kind_span::SyntaxCtxIndex;
|
use kind_span::SyntaxCtxIndex;
|
||||||
|
|
||||||
use kind_tree::{backend, concrete, desugared, untyped};
|
use hvm::language::{syntax as backend};
|
||||||
|
use kind_tree::{concrete, desugared, untyped};
|
||||||
use resolution::ResolutionError;
|
use resolution::ResolutionError;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use std::{path::PathBuf};
|
use std::{path::PathBuf};
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-parser"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "Parser for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-pass"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "A lot of compiler passes for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -220,8 +220,8 @@ impl<'a> DesugarState<'a> {
|
|||||||
if let Some((_, name)) = arg.1 {
|
if let Some((_, name)) = arg.1 {
|
||||||
arguments.push(name)
|
arguments.push(name)
|
||||||
} else {
|
} else {
|
||||||
let id =
|
let mut id = Ident::generate(&format!("{}.{}", matcher.scrutinee.to_str(), arg.0));
|
||||||
Ident::generate(&format!("{}.{}", matcher.scrutinee.to_str(), arg.0));
|
id.range = case.constructor.range;
|
||||||
arguments.push(id);
|
arguments.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ pub fn inline_book(book: &mut untyped::Book) {
|
|||||||
|
|
||||||
for name in &to_remove {
|
for name in &to_remove {
|
||||||
book.entrs.remove(name);
|
book.entrs.remove(name);
|
||||||
|
book.names.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut state = InlineState { funs };
|
let mut state = InlineState { funs };
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-query"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "Query module for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-report"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "Report module for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-span"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "Describes locations for the Kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-target-hvm"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "HVM Code generator for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -12,4 +13,4 @@ kind-tree = { path = "../kind-tree", version = "0.1.1" }
|
|||||||
kind-report = { path = "../kind-report", version = "0.1.1" }
|
kind-report = { path = "../kind-report", version = "0.1.1" }
|
||||||
kind-derive = { path = "../kind-derive", version = "0.1.1" }
|
kind-derive = { path = "../kind-derive", version = "0.1.1" }
|
||||||
|
|
||||||
hvm = "1.0.3"
|
hvm = "1.0.3"
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use hvm::u60;
|
use hvm::u60;
|
||||||
|
|
||||||
use kind_tree::{
|
use kind_tree::untyped;
|
||||||
backend::{File, Rule, Term},
|
|
||||||
untyped,
|
use hvm::syntax::{File, Rule, Term};
|
||||||
};
|
|
||||||
|
|
||||||
pub fn compile_book(book: untyped::Book, trace: bool) -> File {
|
pub fn compile_book(book: untyped::Book, trace: bool) -> File {
|
||||||
let mut file = File {
|
let mut file = File {
|
||||||
|
@ -3,6 +3,7 @@ name = "kind-target-kdl"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
description = "KDL target for the kind compiler"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -12,7 +13,8 @@ kind-tree = { path = "../kind-tree", version = "0.1.1" }
|
|||||||
kind-report = { path = "../kind-report", version = "0.1.1" }
|
kind-report = { path = "../kind-report", version = "0.1.1" }
|
||||||
kind-derive = { path = "../kind-derive", version = "0.1.1" }
|
kind-derive = { path = "../kind-derive", version = "0.1.1" }
|
||||||
|
|
||||||
kindelia_lang = { git = "https://github.com/developedby/Kindelia/", branch = "kdl-lang-crate" }
|
kindelia_lang = "0.1.7"
|
||||||
linked-hash-map = "0.5.6"
|
linked-hash-map = "0.5.6"
|
||||||
tiny-keccak = "2.0.2"
|
tiny-keccak = "2.0.2"
|
||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
|
im-rc = "15.1.0"
|
||||||
|
@ -3,6 +3,7 @@ use std::{fmt::Display, sync::mpsc::Sender};
|
|||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use kind_report::data::Diagnostic;
|
use kind_report::data::Diagnostic;
|
||||||
use kind_tree::{symbol::QualifiedIdent, untyped};
|
use kind_tree::{symbol::QualifiedIdent, untyped};
|
||||||
|
use kindelia_lang::ast::Name;
|
||||||
use linked_hash_map::LinkedHashMap;
|
use linked_hash_map::LinkedHashMap;
|
||||||
use tiny_keccak::Hasher;
|
use tiny_keccak::Hasher;
|
||||||
|
|
||||||
@ -13,6 +14,31 @@ use crate::{diagnostic::KdlDiagnostic, GenericCompilationToHVMError};
|
|||||||
pub const KDL_NAME_LEN: usize = 12;
|
pub const KDL_NAME_LEN: usize = 12;
|
||||||
const U60_MAX: kdl::U120 = kdl::U120(0xFFFFFFFFFFFFFFF);
|
const U60_MAX: kdl::U120 = kdl::U120(0xFFFFFFFFFFFFFFF);
|
||||||
|
|
||||||
|
fn char_to_code(chr: char) -> Result<u128, String> {
|
||||||
|
let num = match chr {
|
||||||
|
'.' => 0,
|
||||||
|
'0'..='9' => 1 + chr as u128 - '0' as u128,
|
||||||
|
'A'..='Z' => 11 + chr as u128 - 'A' as u128,
|
||||||
|
'a'..='z' => 37 + chr as u128 - 'a' as u128,
|
||||||
|
'_' => 63,
|
||||||
|
_ => {
|
||||||
|
return Err(format!("Invalid Kindelia Name letter '{}'.", chr));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(num)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_str(name_txt: &str) -> Result<Name, String> {
|
||||||
|
let mut num: u128 = 0;
|
||||||
|
for (i, chr) in name_txt.chars().enumerate() {
|
||||||
|
if i >= Name::MAX_CHARS {
|
||||||
|
return Err("Too big".to_string())
|
||||||
|
}
|
||||||
|
num = (num << 6) + char_to_code(chr)?;
|
||||||
|
}
|
||||||
|
Ok(Name(num))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub ctrs: LinkedHashMap<String, kdl::Statement>,
|
pub ctrs: LinkedHashMap<String, kdl::Statement>,
|
||||||
@ -26,6 +52,8 @@ pub struct CompileCtx<'a> {
|
|||||||
kdl_states: Vec<String>,
|
kdl_states: Vec<String>,
|
||||||
book: &'a untyped::Book,
|
book: &'a untyped::Book,
|
||||||
|
|
||||||
|
kdl_used_names: im_rc::HashSet<String>,
|
||||||
|
|
||||||
sender: Sender<Box<dyn Diagnostic>>,
|
sender: Sender<Box<dyn Diagnostic>>,
|
||||||
failed: bool,
|
failed: bool,
|
||||||
}
|
}
|
||||||
@ -40,6 +68,7 @@ impl<'a> CompileCtx<'a> {
|
|||||||
},
|
},
|
||||||
kdl_names: Default::default(),
|
kdl_names: Default::default(),
|
||||||
kdl_states: Default::default(),
|
kdl_states: Default::default(),
|
||||||
|
kdl_used_names: Default::default(),
|
||||||
book,
|
book,
|
||||||
sender,
|
sender,
|
||||||
failed: false,
|
failed: false,
|
||||||
@ -108,10 +137,10 @@ pub fn compile_book(
|
|||||||
.map(|x| x.to_string())
|
.map(|x| x.to_string())
|
||||||
.unwrap_or_else(|| name_shortener(&entry.name, namespace).to_string());
|
.unwrap_or_else(|| name_shortener(&entry.name, namespace).to_string());
|
||||||
|
|
||||||
if let Ok(new_name) = kdl::Name::from_str(&new_name) {
|
if let Ok(new_name) = from_str(&new_name) {
|
||||||
ctx.kdl_names.insert(name.clone(), new_name);
|
ctx.kdl_names.insert(name.clone(), new_name);
|
||||||
} else {
|
} else {
|
||||||
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(entry.name.range)));
|
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(entry.name.to_string(), entry.name.range)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +177,80 @@ pub fn err_term() -> kdl::Term {
|
|||||||
pub fn compile_expr(ctx: &mut CompileCtx, expr: &untyped::Expr) -> kdl::Term {
|
pub fn compile_expr(ctx: &mut CompileCtx, expr: &untyped::Expr) -> kdl::Term {
|
||||||
use crate::untyped::ExprKind as From;
|
use crate::untyped::ExprKind as From;
|
||||||
use kdl::Term as To;
|
use kdl::Term as To;
|
||||||
|
|
||||||
match &expr.data {
|
match &expr.data {
|
||||||
|
From::Var { name } => {
|
||||||
|
let res_name = from_str(name.to_str());
|
||||||
|
ctx.kdl_used_names.remove(name.to_str());
|
||||||
|
if let Ok(name) = res_name {
|
||||||
|
To::Var { name }
|
||||||
|
} else {
|
||||||
|
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(name.to_string(), name.range)));
|
||||||
|
err_term()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
From::Lambda {
|
||||||
|
param,
|
||||||
|
body,
|
||||||
|
erased: _,
|
||||||
|
} => {
|
||||||
|
let name = from_str(param.to_str());
|
||||||
|
|
||||||
|
let not_used = ctx.kdl_used_names.contains(param.to_str());
|
||||||
|
|
||||||
|
ctx.kdl_used_names.insert(param.to_string());
|
||||||
|
|
||||||
|
let body = Box::new(compile_expr(ctx, body));
|
||||||
|
|
||||||
|
let not_used_now = ctx.kdl_used_names.contains(param.to_str());
|
||||||
|
let name = if not_used_now { Ok(from_str("").unwrap()) } else { name };
|
||||||
|
|
||||||
|
if not_used_now {
|
||||||
|
ctx.kdl_used_names.remove(param.to_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if not_used {
|
||||||
|
ctx.kdl_used_names.insert(param.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(name) = name {
|
||||||
|
To::Lam { name, body }
|
||||||
|
} else {
|
||||||
|
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(param.to_string(), param.range)));
|
||||||
|
err_term()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
From::Let { name: param, val, next } => {
|
||||||
|
let res_name = from_str(param.to_str());
|
||||||
|
|
||||||
|
let not_used = ctx.kdl_used_names.contains(param.to_str());
|
||||||
|
|
||||||
|
ctx.kdl_used_names.insert(param.to_string());
|
||||||
|
|
||||||
|
let expr = Box::new(compile_expr(ctx, next));
|
||||||
|
|
||||||
|
let not_used_now = ctx.kdl_used_names.contains(param.to_str());
|
||||||
|
|
||||||
|
let res_name = if not_used_now { Ok(from_str("").unwrap()) } else { res_name };
|
||||||
|
|
||||||
|
if not_used_now {
|
||||||
|
ctx.kdl_used_names.remove(param.to_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if not_used {
|
||||||
|
ctx.kdl_used_names.insert(param.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let argm = Box::new(compile_expr(ctx, &val));
|
||||||
|
|
||||||
|
if let Ok(name) = res_name {
|
||||||
|
let func = Box::new(To::Lam { name, body: expr });
|
||||||
|
To::App { func, argm }
|
||||||
|
} else {
|
||||||
|
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(param.to_string(), param.range)));
|
||||||
|
err_term()
|
||||||
|
}
|
||||||
|
}
|
||||||
From::App { fun, args } => {
|
From::App { fun, args } => {
|
||||||
let mut expr = compile_expr(ctx, fun);
|
let mut expr = compile_expr(ctx, fun);
|
||||||
for binding in args {
|
for binding in args {
|
||||||
@ -324,32 +426,6 @@ pub fn compile_expr(ctx: &mut CompileCtx, expr: &untyped::Expr) -> kdl::Term {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
From::Lambda {
|
|
||||||
param,
|
|
||||||
body,
|
|
||||||
erased: _,
|
|
||||||
} => {
|
|
||||||
let name = kdl::Name::from_str(param.to_str());
|
|
||||||
if let Ok(name) = name {
|
|
||||||
let body = Box::new(compile_expr(ctx, body));
|
|
||||||
To::Lam { name, body }
|
|
||||||
} else {
|
|
||||||
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(param.range)));
|
|
||||||
err_term()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
From::Let { name, val, next } => {
|
|
||||||
let res_name = kdl::Name::from_str(name.to_str());
|
|
||||||
if let Ok(name) = res_name {
|
|
||||||
let expr = Box::new(compile_expr(ctx, next));
|
|
||||||
let func = Box::new(To::Lam { name, body: expr });
|
|
||||||
let argm = Box::new(compile_expr(ctx, &val));
|
|
||||||
To::App { func, argm }
|
|
||||||
} else {
|
|
||||||
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(name.range)));
|
|
||||||
err_term()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
From::U60 { numb } => To::Num {
|
From::U60 { numb } => To::Num {
|
||||||
numb: kdl::U120(*numb as u128),
|
numb: kdl::U120(*numb as u128),
|
||||||
},
|
},
|
||||||
@ -357,15 +433,6 @@ pub fn compile_expr(ctx: &mut CompileCtx, expr: &untyped::Expr) -> kdl::Term {
|
|||||||
ctx.send_err(Box::new(KdlDiagnostic::FloatUsed(expr.range)));
|
ctx.send_err(Box::new(KdlDiagnostic::FloatUsed(expr.range)));
|
||||||
err_term()
|
err_term()
|
||||||
}
|
}
|
||||||
From::Var { name } => {
|
|
||||||
let res_name = kdl::Name::from_str(name.to_str());
|
|
||||||
if let Ok(name) = res_name {
|
|
||||||
To::Var { name }
|
|
||||||
} else {
|
|
||||||
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(name.range)));
|
|
||||||
err_term()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
From::Str { val } => {
|
From::Str { val } => {
|
||||||
let nil = kdl::Term::Ctr {
|
let nil = kdl::Term::Ctr {
|
||||||
name: *ctx.kdl_names.get("String.nil").unwrap(),
|
name: *ctx.kdl_names.get("String.nil").unwrap(),
|
||||||
@ -418,10 +485,10 @@ fn compile_common_function(ctx: &mut CompileCtx, entry: &untyped::Entry) {
|
|||||||
|
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
for (name, range, _strictness) in &entry.args {
|
for (name, range, _strictness) in &entry.args {
|
||||||
if let Ok(name) = kdl::Name::from_str(name) {
|
if let Ok(name) = from_str(name) {
|
||||||
args.push(name)
|
args.push(name)
|
||||||
} else {
|
} else {
|
||||||
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(*range)));
|
ctx.send_err(Box::new(KdlDiagnostic::InvalidVarName(name.to_string(), *range)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,8 +543,8 @@ fn compile_common_function(ctx: &mut CompileCtx, entry: &untyped::Entry) {
|
|||||||
|
|
||||||
fn compile_u120_new(ctx: &mut CompileCtx, entry: &untyped::Entry) {
|
fn compile_u120_new(ctx: &mut CompileCtx, entry: &untyped::Entry) {
|
||||||
// U120.new hi lo = (hi << 60) | lo
|
// U120.new hi lo = (hi << 60) | lo
|
||||||
let hi_name = kdl::Name::from_str("hi").unwrap();
|
let hi_name = from_str("hi").unwrap();
|
||||||
let lo_name = kdl::Name::from_str("lo").unwrap();
|
let lo_name = from_str("lo").unwrap();
|
||||||
let hi_var = kdl::Term::Var {
|
let hi_var = kdl::Term::Var {
|
||||||
name: hi_name.clone(),
|
name: hi_name.clone(),
|
||||||
};
|
};
|
||||||
@ -555,4 +622,4 @@ fn compile_oper(oper: &kind_tree::Operator) -> kdl::Oper {
|
|||||||
From::Xor => To::Xor,
|
From::Xor => To::Xor,
|
||||||
From::Or => To::Or,
|
From::Or => To::Or,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ use kind_report::data::{Color, Diagnostic, DiagnosticFrame, Marker, Severity};
|
|||||||
use kind_span::Range;
|
use kind_span::Range;
|
||||||
|
|
||||||
pub enum KdlDiagnostic {
|
pub enum KdlDiagnostic {
|
||||||
InvalidVarName(Range),
|
InvalidVarName(String, Range),
|
||||||
ShouldNotHaveArguments(Range),
|
ShouldNotHaveArguments(Range),
|
||||||
ShouldHaveOnlyOneRule(Range),
|
ShouldHaveOnlyOneRule(Range),
|
||||||
NoInitEntry(Range),
|
NoInitEntry(Range),
|
||||||
@ -12,7 +12,7 @@ pub enum KdlDiagnostic {
|
|||||||
impl Diagnostic for KdlDiagnostic {
|
impl Diagnostic for KdlDiagnostic {
|
||||||
fn get_syntax_ctx(&self) -> Option<kind_span::SyntaxCtxIndex> {
|
fn get_syntax_ctx(&self) -> Option<kind_span::SyntaxCtxIndex> {
|
||||||
match self {
|
match self {
|
||||||
KdlDiagnostic::InvalidVarName(range) => Some(range.ctx),
|
KdlDiagnostic::InvalidVarName(_, range) => Some(range.ctx),
|
||||||
KdlDiagnostic::ShouldNotHaveArguments(range) => Some(range.ctx),
|
KdlDiagnostic::ShouldNotHaveArguments(range) => Some(range.ctx),
|
||||||
KdlDiagnostic::ShouldHaveOnlyOneRule(range) => Some(range.ctx),
|
KdlDiagnostic::ShouldHaveOnlyOneRule(range) => Some(range.ctx),
|
||||||
KdlDiagnostic::NoInitEntry(range) => Some(range.ctx),
|
KdlDiagnostic::NoInitEntry(range) => Some(range.ctx),
|
||||||
@ -22,10 +22,10 @@ impl Diagnostic for KdlDiagnostic {
|
|||||||
|
|
||||||
fn to_diagnostic_frame(&self) -> kind_report::data::DiagnosticFrame {
|
fn to_diagnostic_frame(&self) -> kind_report::data::DiagnosticFrame {
|
||||||
match self {
|
match self {
|
||||||
KdlDiagnostic::InvalidVarName(range) => DiagnosticFrame {
|
KdlDiagnostic::InvalidVarName(s, range) => DiagnosticFrame {
|
||||||
code: 600,
|
code: 600,
|
||||||
severity: Severity::Error,
|
severity: Severity::Error,
|
||||||
title: "Invalid variable name for Kindelia.".to_string(),
|
title: format!("Invalid variable name '{s}' for Kindelia."),
|
||||||
subtitles: vec![],
|
subtitles: vec![],
|
||||||
hints: vec![],
|
hints: vec![],
|
||||||
positions: vec![Marker {
|
positions: vec![Marker {
|
||||||
@ -98,7 +98,7 @@ impl Diagnostic for KdlDiagnostic {
|
|||||||
fn get_severity(&self) -> Severity {
|
fn get_severity(&self) -> Severity {
|
||||||
use KdlDiagnostic::*;
|
use KdlDiagnostic::*;
|
||||||
match self {
|
match self {
|
||||||
InvalidVarName(_)
|
InvalidVarName(_, _)
|
||||||
| ShouldNotHaveArguments(_)
|
| ShouldNotHaveArguments(_)
|
||||||
| ShouldHaveOnlyOneRule(_)
|
| ShouldHaveOnlyOneRule(_)
|
||||||
| NoInitEntry(_)
|
| NoInitEntry(_)
|
||||||
|
@ -24,7 +24,7 @@ pub struct LinearizeCtx {
|
|||||||
|
|
||||||
impl LinearizeCtx {
|
impl LinearizeCtx {
|
||||||
fn create_name(&mut self) -> Name {
|
fn create_name(&mut self) -> Name {
|
||||||
let name = Name::from_str(&format!("x{}", self.name_count)).unwrap();
|
let name = Name::from_str_unsafe(&format!("x{}", self.name_count));
|
||||||
self.name_count += 1;
|
self.name_count += 1;
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ pub fn linearize_term(ctx: &mut LinearizeCtx, term: &Term, lhs: bool) -> Box<Ter
|
|||||||
.entry(*name)
|
.entry(*name)
|
||||||
.and_modify(|x| *x += 1)
|
.and_modify(|x| *x += 1)
|
||||||
.or_insert(1);
|
.or_insert(1);
|
||||||
let name = Name::from_str(&format!("{}.{}", name, used - 1)).unwrap(); // TODO: Think if this errs or not
|
let name = Name::from_str_unsafe(&format!("{}.{}", name, used - 1)); // TODO: Think if this errs or not
|
||||||
Term::Var { name }
|
Term::Var { name }
|
||||||
} else {
|
} else {
|
||||||
unreachable!("Unbound variable '{}' in kdl compilation", name.to_string());
|
unreachable!("Unbound variable '{}' in kdl compilation", name.to_string());
|
||||||
@ -182,8 +182,8 @@ pub fn linearize_term(ctx: &mut LinearizeCtx, term: &Term, lhs: bool) -> Box<Ter
|
|||||||
if let Some(x) = got_1 {
|
if let Some(x) = got_1 {
|
||||||
ctx.name_table.insert(*nam1, x);
|
ctx.name_table.insert(*nam1, x);
|
||||||
}
|
}
|
||||||
let nam0 = Name::from_str(&format!("{}{}", new_nam0, ".0")).unwrap();
|
let nam0 = Name::from_str_unsafe(&format!("{}{}", new_nam0, ".0"));
|
||||||
let nam1 = Name::from_str(&format!("{}{}", new_nam1, ".0")).unwrap();
|
let nam1 = Name::from_str_unsafe(&format!("{}{}", new_nam1, ".0"));
|
||||||
Term::Dup {
|
Term::Dup {
|
||||||
nam0,
|
nam0,
|
||||||
nam1,
|
nam1,
|
||||||
@ -274,7 +274,7 @@ pub fn dup_var(ctx: &mut LinearizeCtx, name: &Name, expr: Box<Term>, body: Box<T
|
|||||||
0 => body,
|
0 => body,
|
||||||
// if used once just make a let (lambda then app)
|
// if used once just make a let (lambda then app)
|
||||||
1 => {
|
1 => {
|
||||||
let name = Name::from_str(&format!("{}.0", name)).unwrap(); // TODO: handle err
|
let name = Name::from_str_unsafe(&format!("{}.0", name)); // TODO: handle err
|
||||||
let func = Box::new(Term::Lam { name, body });
|
let func = Box::new(Term::Lam { name, body });
|
||||||
let term = Term::App { func, argm: expr };
|
let term = Term::App { func, argm: expr };
|
||||||
Box::new(term)
|
Box::new(term)
|
||||||
@ -287,12 +287,12 @@ pub fn dup_var(ctx: &mut LinearizeCtx, name: &Name, expr: Box<Term>, body: Box<T
|
|||||||
// generate name for duplicated variables
|
// generate name for duplicated variables
|
||||||
for i in (aux_amount..(dup_times * 2)).rev() {
|
for i in (aux_amount..(dup_times * 2)).rev() {
|
||||||
let i = i - aux_amount; // moved to 0,1,..
|
let i = i - aux_amount; // moved to 0,1,..
|
||||||
let key = Name::from_str(&format!("{}.{}", name, i)).unwrap();
|
let key = Name::from_str_unsafe(&format!("{}.{}", name, i));
|
||||||
vars.push(key);
|
vars.push(key);
|
||||||
}
|
}
|
||||||
// generate name for aux variables
|
// generate name for aux variables
|
||||||
for i in (0..aux_amount).rev() {
|
for i in (0..aux_amount).rev() {
|
||||||
let key = Name::from_str(&format!("c.{}", i)).unwrap();
|
let key = Name::from_str_unsafe(&format!("c.{}", i));
|
||||||
vars.push(key);
|
vars.push(key);
|
||||||
}
|
}
|
||||||
// use aux variables to duplicate the variable
|
// use aux variables to duplicate the variable
|
||||||
@ -318,7 +318,7 @@ fn dup_var_go(idx: u64, dup_times: u64, body: Box<Term>, vars: &mut Vec<Name>) -
|
|||||||
} else {
|
} else {
|
||||||
let nam0 = vars.pop().unwrap();
|
let nam0 = vars.pop().unwrap();
|
||||||
let nam1 = vars.pop().unwrap();
|
let nam1 = vars.pop().unwrap();
|
||||||
let var_name = Name::from_str(&format!("c.{}", idx - 1)).unwrap();
|
let var_name = Name::from_str_unsafe(&format!("c.{}", idx - 1));
|
||||||
let expr = Box::new(Term::Var { name: var_name });
|
let expr = Box::new(Term::Var { name: var_name });
|
||||||
let dup = Term::Dup {
|
let dup = Term::Dup {
|
||||||
nam0,
|
nam0,
|
||||||
|
17
crates/kind-tests/suite/kdl/ISSUE-491-2.golden
Normal file
17
crates/kind-tests/suite/kdl/ISSUE-491-2.golden
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
ctr {String.nil}
|
||||||
|
ctr {Pair.new fst snd}
|
||||||
|
ctr {String.cons head tail}
|
||||||
|
|
||||||
|
fun (Test n) {
|
||||||
|
(Test ~) = (!@x1 (!@x1.0 (Pair.match x1.0 @x2 (!@x2.0 @~ (String.match x2.0 #1 @~ @~ #2) x2)) x1) {Pair.new {String.cons #84 {String.cons #101 {String.cons #115 {String.cons #116 {String.cons #101 {String.nil}}}}}} #0})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun (Pair.match scrutinee new_) {
|
||||||
|
(Pair.match {Pair.new x0 x1} x2) = (!@x2.0 (!@x1.0 (!@x0.0 (!(!x2.0 x0.0) x1.0) x0) x1) x2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun (String.match scrutinee nil_ cons_) {
|
||||||
|
(String.match {String.nil} x0 ~) = (!@x0.0 x0.0 x0)
|
||||||
|
(String.match {String.cons x0 x1} ~ x3) = (!@x3.0 (!@x1.0 (!@x0.0 (!(!x3.0 x0.0) x1.0) x0) x1) x3)
|
||||||
|
}
|
||||||
|
|
32
crates/kind-tests/suite/kdl/ISSUE-491-2.kind2
Normal file
32
crates/kind-tests/suite/kdl/ISSUE-491-2.kind2
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
Char : Type
|
||||||
|
Char = U60
|
||||||
|
|
||||||
|
#kdl_name = T2
|
||||||
|
#kdl_erase
|
||||||
|
#derive[match]
|
||||||
|
record Pair (a) (b) {
|
||||||
|
constructor new
|
||||||
|
fst : a
|
||||||
|
snd : b
|
||||||
|
}
|
||||||
|
|
||||||
|
#derive[match]
|
||||||
|
type String {
|
||||||
|
nil
|
||||||
|
cons (head: (Char)) (tail: (String))
|
||||||
|
}
|
||||||
|
|
||||||
|
#keep
|
||||||
|
Test (n: U60) : U60
|
||||||
|
Test n =
|
||||||
|
let state = Pair.new "Teste" 0
|
||||||
|
match Pair state {
|
||||||
|
new =>
|
||||||
|
match String state.fst {
|
||||||
|
nil =>
|
||||||
|
1
|
||||||
|
cons =>
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
16
crates/kind-tests/suite/kdl/ISSUE-491.golden
Normal file
16
crates/kind-tests/suite/kdl/ISSUE-491.golden
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
fun (C ) {
|
||||||
|
(C) = (!@~ (!@~ #2 #3) #2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun (B ) {
|
||||||
|
(B) = @~ @x1 (!@x1.0 x1.0 x1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun (A ) {
|
||||||
|
(A) = (!@~ @~ @x2 (!@x2.0 x2.0 x2) #2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun (D ) {
|
||||||
|
(D) = (!@~ #233 (!@~ #2 @~ #2))
|
||||||
|
}
|
||||||
|
|
23
crates/kind-tests/suite/kdl/ISSUE-491.kind2
Normal file
23
crates/kind-tests/suite/kdl/ISSUE-491.kind2
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#keep
|
||||||
|
A {
|
||||||
|
let xaaaaaaaaaaaaaaaaaaaaaa = 2
|
||||||
|
xaaaaaaaaaaaaaaaaaaaaaa => x => x
|
||||||
|
}
|
||||||
|
|
||||||
|
#keep
|
||||||
|
B {
|
||||||
|
xaaaaaaaaaaaaaaaaaaaaaa => x => x
|
||||||
|
}
|
||||||
|
|
||||||
|
#keep
|
||||||
|
C {
|
||||||
|
let aaaaaaaaaaaaaaaaaaaaaa = 2
|
||||||
|
let aaaaaaaaaaaaaaaaaaaaaa = 3
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
#keep
|
||||||
|
D {
|
||||||
|
let xxxxxxxxxxxx = ((xxxxxxxxxxxx => 2) (xxxxxxxxxxxx => 2))
|
||||||
|
233
|
||||||
|
}
|
@ -4,6 +4,7 @@ version = "0.1.1"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
|
description = "Syntatic trees for Kind compiler"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -24,7 +24,6 @@ pub mod symbol;
|
|||||||
|
|
||||||
use std::fmt::{Formatter, Display, Error};
|
use std::fmt::{Formatter, Display, Error};
|
||||||
|
|
||||||
pub use hvm::syntax as backend;
|
|
||||||
use symbol::Ident;
|
use symbol::Ident;
|
||||||
|
|
||||||
/// Attributes describes some compiler specific aspects
|
/// Attributes describes some compiler specific aspects
|
||||||
|
Loading…
Reference in New Issue
Block a user