├── kirl_parser ├── .gitignore ├── Cargo.toml └── src │ ├── lib.rs │ ├── kirl_parser │ └── tests.rs │ └── kirl_tokenizer.rs ├── kirl_vm ├── src │ ├── lib.rs │ ├── vm.rs │ ├── bytecode.rs │ └── lir.rs └── Cargo.toml ├── examples ├── 0 │ └── hello.kirl ├── 1 │ ├── fib4.kirl │ ├── fib3.kirl │ ├── fib1.kirl │ └── fib2.kirl ├── 2 │ ├── main.kirl │ ├── subdir │ │ ├── sub3.kirl │ │ └── sub2.kirl │ └── sub1.kirl ├── 3 │ ├── valid.kirl │ └── error.kirl ├── 4 │ └── main.kirl ├── 5 │ └── main.kirl ├── 6 │ └── main.kirl ├── 7 │ └── main.kirl └── 8 │ ├── main1.kirl │ └── main2.kirl ├── kirl_common ├── src │ ├── lib.rs │ ├── interface.rs │ └── typing.rs └── Cargo.toml ├── kirl_common_macro ├── src │ ├── lib.rs │ └── kirl_function.rs └── Cargo.toml ├── .gitignore ├── Cargo.toml ├── kirl_semantic_analyzer ├── Cargo.toml └── src │ └── name_resolver.rs ├── kirl_engine ├── Cargo.toml └── src │ └── lib.rs ├── kirl_stdlib ├── Cargo.toml └── src │ └── lib.rs ├── README.md ├── kirl ├── Cargo.toml ├── src │ └── main.rs └── tests │ └── main.rs ├── README_EN.md └── LICENSE /kirl_parser/.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/.gitignore 3 | !/src 4 | !/Cargo.toml 5 | -------------------------------------------------------------------------------- /kirl_vm/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bytecode; 2 | pub mod lir; 3 | pub mod vm; 4 | -------------------------------------------------------------------------------- /examples/0/hello.kirl: -------------------------------------------------------------------------------- 1 | import std::io; 2 | 3 | "Hello, World!".io::println(); 4 | -------------------------------------------------------------------------------- /kirl_common/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod interface; 2 | pub mod typing; 3 | 4 | pub use dec; 5 | pub use once_cell; 6 | -------------------------------------------------------------------------------- /examples/2/main.kirl: -------------------------------------------------------------------------------- 1 | import std::io::println; 2 | import sub1::f; 3 | 4 | println("this is in main.kirl"); 5 | f(); 6 | -------------------------------------------------------------------------------- /examples/3/valid.kirl: -------------------------------------------------------------------------------- 1 | fn f(s: String) { 2 | "this is in function \"f\"".std::io::println(); 3 | } 4 | 5 | f("test"); 6 | -------------------------------------------------------------------------------- /examples/3/error.kirl: -------------------------------------------------------------------------------- 1 | fn f(s: String) { 2 | "this is in function \"f\"".std::io::println(); 3 | } 4 | 5 | f(0); // <- error! 6 | -------------------------------------------------------------------------------- /examples/2/subdir/sub3.kirl: -------------------------------------------------------------------------------- 1 | import std::io::println; 2 | 3 | fn f() { 4 | println("this is in function \"f\" in subdir/sub3.kirl"); 5 | } 6 | -------------------------------------------------------------------------------- /examples/2/subdir/sub2.kirl: -------------------------------------------------------------------------------- 1 | import std::io::println; 2 | 3 | fn f() { 4 | println("this is in function \"f\" in subdir/sub2.kirl"); 5 | sub3::f(); 6 | } 7 | -------------------------------------------------------------------------------- /examples/1/fib4.kirl: -------------------------------------------------------------------------------- 1 | import std::{io::println, num::{_add, _sub, _gt}}; 2 | 3 | fn fib(n: Number) -> Number |-> if n < 2 { n } else { fib(n - 1) + fib(n - 2) }; 4 | 5 | 20.fib().println(); 6 | -------------------------------------------------------------------------------- /examples/2/sub1.kirl: -------------------------------------------------------------------------------- 1 | import std::io::println; 2 | import subdir::sub2; 3 | 4 | fn f() { 5 | println("this is in function \"f\" in sub.kirl"); 6 | sub2::f(); 7 | } 8 | 9 | println("this is in sub.kirl"); 10 | -------------------------------------------------------------------------------- /examples/1/fib3.kirl: -------------------------------------------------------------------------------- 1 | import std::{io::println, num::{_add, _sub, _gt}}; 2 | 3 | fn fib(n: Number) -> Number { 4 | if n < 2 { 5 | n 6 | } else { 7 | fib(n - 1) + fib(n - 2) 8 | } 9 | } 10 | 11 | fib(20).println(); 12 | -------------------------------------------------------------------------------- /kirl_common_macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod kirl_function; 2 | 3 | use proc_macro::TokenStream; 4 | 5 | #[proc_macro_attribute] 6 | pub fn kirl_function(args: TokenStream, input: TokenStream) -> TokenStream { 7 | kirl_function::kirl_function_inner(args, input) 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/.gitignore 3 | !/kirl 4 | !/kirl_common 5 | !/kirl_common_macro 6 | !/kirl_engine 7 | !/kirl_vm 8 | !/kirl_parser 9 | !/kirl_semantic_analyzer 10 | !/kirl_stdlib 11 | !/examples 12 | !/Cargo.toml 13 | !/LICENSE 14 | !/README.md 15 | !/README_EN.md 16 | -------------------------------------------------------------------------------- /kirl_common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl_common" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | dec = "0.4.5" 10 | once_cell = "1.8.0" 11 | -------------------------------------------------------------------------------- /examples/1/fib1.kirl: -------------------------------------------------------------------------------- 1 | import std::{io::println, num::{_add, _sub, _gt}}; 2 | 3 | // n番目のフィボナッチ数を求める 4 | fn fib(n: Number) -> Number { 5 | if n < 2 { 6 | return n; 7 | } else { 8 | return fib(n - 1) + fib(n - 2); 9 | }; 10 | } 11 | 12 | println(fib(20)); 13 | -------------------------------------------------------------------------------- /examples/1/fib2.kirl: -------------------------------------------------------------------------------- 1 | import std::{io::println, num::{_add, _sub, _gt}}; 2 | 3 | /* 4 | n番目のフィボナッチ数を求める 5 | */ 6 | fn fib(n: Number) -> Number { 7 | return if n < 2 { 8 | n 9 | } else { 10 | fib(n - 1) + fib(n - 2) 11 | }; 12 | } 13 | 14 | println(fib(20)); 15 | -------------------------------------------------------------------------------- /examples/8/main1.kirl: -------------------------------------------------------------------------------- 1 | import std::io::{ print, println }; 2 | 3 | var condition = (); 4 | 5 | if var #{ value } = condition { 6 | "condition is #{ value: Number }\nvalue: ".print(); 7 | value.println(); 8 | } else { 9 | "condition is not #{ value: Number }".println(); 10 | }; 11 | -------------------------------------------------------------------------------- /examples/8/main2.kirl: -------------------------------------------------------------------------------- 1 | import std::io::{ print, println }; 2 | 3 | var condition = #{ value: 42 }; 4 | 5 | if var #{ value } = condition { 6 | "condition is #{ value: Number }\nvalue: ".print(); 7 | value.println(); 8 | } else { 9 | "condition is not #{ value: Number }".println(); 10 | }; 11 | -------------------------------------------------------------------------------- /examples/4/main.kirl: -------------------------------------------------------------------------------- 1 | import std::io::println; 2 | 3 | fn f(s: String) { 4 | "this is in function \"f\":(String)->()".println(); 5 | s.println(); 6 | } 7 | 8 | fn f(n: Number) { 9 | "this is in function \"f\":(Number)->()".println(); 10 | n.println(); 11 | } 12 | 13 | f("string"); 14 | f(256); 15 | -------------------------------------------------------------------------------- /examples/6/main.kirl: -------------------------------------------------------------------------------- 1 | import std::{io::println, num::_add}; 2 | 3 | fn get_value() -> #{ item1: Number, item2: String } |-> #{ item1: 1e+2 + 2e+1 + 8, item2: "test string" }; 4 | 5 | var value = get_value(); 6 | value.item1.println(); 7 | value.item2.println(); 8 | 9 | var #{ item1, item2: msg } = get_value(); 10 | item1.println(); 11 | msg.println(); 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "kirl", 4 | "kirl_common", 5 | "kirl_common_macro", 6 | "kirl_parser", 7 | "kirl_semantic_analyzer", 8 | "kirl_vm", 9 | "kirl_stdlib", 10 | "kirl_engine" 11 | ] 12 | 13 | [profile.dev] 14 | opt-level = 3 15 | 16 | [profile.dev.build-override] 17 | opt-level = 3 18 | 19 | [profile.release.build-override] 20 | opt-level = 3 21 | -------------------------------------------------------------------------------- /examples/5/main.kirl: -------------------------------------------------------------------------------- 1 | import std::{io::println, num::{_gt, _mul}}; 2 | 3 | var msg: String = "this is a string message"; 4 | 5 | msg.println(); 6 | 7 | msg = { 8 | var msg: Number = 0b_10_000_000_000; 9 | msg.println(); 10 | 11 | if msg > 0xff { 12 | var msg = "てすと用めっせーじ"; 13 | msg.println(); 14 | }; 15 | 16 | println(msg * 2); 17 | 18 | "this is a new string message" 19 | }; 20 | 21 | msg.println(); 22 | -------------------------------------------------------------------------------- /kirl_common_macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl_common_macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [lib] 9 | proc-macro = true 10 | 11 | [dependencies] 12 | kirl_common = { path = "../kirl_common" } 13 | syn = { version = "1.0.81", features = ["full", "extra-traits"] } 14 | quote = "1.0.10" 15 | proc-macro2 = "1.0.32" 16 | -------------------------------------------------------------------------------- /kirl_vm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl_vm" 3 | version = "0.1.0" 4 | authors = ["White-Green <43771790+White-Green@users.noreply.github.com>"] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | once_cell = "1.8.0" 11 | uuid = "0.8.2" 12 | anyhow = "1.0.43" 13 | kirl_semantic_analyzer = { path = "../kirl_semantic_analyzer" } 14 | kirl_common = { path = "../kirl_common" } 15 | -------------------------------------------------------------------------------- /kirl_semantic_analyzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl_semantic_analyzer" 3 | version = "0.1.0" 4 | authors = ["White-Green <43771790+White-Green@users.noreply.github.com>"] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | kirl_parser = { path = "../kirl_parser" } 11 | regex = "1.5.4" 12 | uuid = "0.8.2" 13 | take_mut = "0.2.2" 14 | kirl_common = { path = "../kirl_common" } 15 | -------------------------------------------------------------------------------- /kirl_engine/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl_engine" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | uuid = "0.8.2" 10 | anyhow = "1.0.43" 11 | kirl_parser = { path = "../kirl_parser" } 12 | kirl_semantic_analyzer = { path = "../kirl_semantic_analyzer" } 13 | kirl_vm = { path = "../kirl_vm" } 14 | kirl_stdlib = { path = "../kirl_stdlib" } 15 | kirl_common = { path = "../kirl_common" } 16 | -------------------------------------------------------------------------------- /kirl_stdlib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl_stdlib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | regex="1.5.4" 10 | uuid = { version = "0.8.2", features = ["v4"] } 11 | once_cell = "1.8.0" 12 | kirl_semantic_analyzer = { path = "../kirl_semantic_analyzer" } #TODO:このへん単一crateにまとめて外に出したいね 13 | kirl_common = { path = "../kirl_common" } 14 | kirl_common_macro = { path = "../kirl_common_macro" } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [English version is here](./README_EN.md) 2 | # kirl-lang 3 | 静的型付けされたスクリプト言語の実験的プロジェクト 4 | 5 | ## 実行環境 6 | [Rustツールチェイン](https://www.rust-lang.org) をインストールしてください 7 | 8 | ## インストール方法 9 | ```shell 10 | $ cargo install --git https://github.com/White-Green/kirl-lang 11 | ``` 12 | または 13 | ```shell 14 | $ git clone https://github.com/White-Green/kirl-lang 15 | $ cargo install kirl-lang/kirl 16 | ``` 17 | 18 | ## 実行 19 | 以下の内容のファイルを"hello.kirl"という名前で作成します 20 | ``` 21 | import std::io; 22 | 23 | "Hello, World!".io::println(); 24 | ``` 25 | その後、以下のコマンドで実行します 26 | ```shell 27 | $ kirl hello.kirl 28 | ``` 29 | -------------------------------------------------------------------------------- /kirl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [[test]] 9 | name = "e2e_test" 10 | path = "tests/main.rs" 11 | 12 | [dependencies] 13 | clap = "2.33.3" 14 | anyhow = "1.0.43" 15 | kirl_parser = { path = "../kirl_parser" } 16 | kirl_semantic_analyzer = { path = "../kirl_semantic_analyzer" } 17 | kirl_vm = { path = "../kirl_vm" } 18 | kirl_engine = { path = "../kirl_engine" } 19 | 20 | [dev-dependencies] 21 | tempfile = "3.2.0" 22 | assert_cmd = "2.0.2" 23 | predicates = "2.0.3" 24 | -------------------------------------------------------------------------------- /examples/7/main.kirl: -------------------------------------------------------------------------------- 1 | import std::io::println; 2 | 3 | fn tuple_function(tuple: (Number, String), ((num1, str1), num2, str2): ((Number, String), Number, String,)) -> (Number, String, (Number, String), Number, String,) { 4 | tuple.0th.println(); 5 | tuple. 1st.println(); 6 | num1.println(); 7 | str1.println(); 8 | num2.println(); 9 | str2.println(); 10 | (tuple.0th, tuple.1st, (num2, str2), num1, str1) 11 | } 12 | 13 | var (a, b, c, e, f) = tuple_function((1, "string_1", "expect_ignored"), ((2, "string_2"), 3, "string_3")); 14 | var (c, d) = c; 15 | a.println(); 16 | b.println(); 17 | c.println(); 18 | d.println(); 19 | e.println(); 20 | f.println(); 21 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | [日本語版はこちら](./README.md) 2 | 3 | # kirl-lang 4 | An experimental project for statically typed scripting language. 5 | 6 | ## required for running 7 | [Rust toolchain](https://www.rust-lang.org) for your computer 8 | 9 | ## install 10 | ```shell 11 | $ cargo install --git https://github.com/White-Green/kirl-lang 12 | ``` 13 | or 14 | ```shell 15 | $ git clone https://github.com/White-Green/kirl-lang 16 | $ cargo install kirl-lang/kirl 17 | ``` 18 | 19 | ## running 20 | create below file named "hello.kirl". 21 | ``` 22 | import std::io; 23 | 24 | "Hello, World!".io::println(); 25 | ``` 26 | and run this file by the below command. 27 | ```shell 28 | $ kirl hello.kirl 29 | ``` 30 | -------------------------------------------------------------------------------- /kirl/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::path::Path; 3 | 4 | use clap::{app_from_crate, crate_authors, crate_description, crate_name, crate_version, Arg}; 5 | 6 | use kirl_engine::{compile, KirlFileResolver}; 7 | use kirl_vm::vm::exec; 8 | 9 | struct OsFileResolver; 10 | 11 | impl KirlFileResolver for OsFileResolver { 12 | type ResolveError = std::io::Error; 13 | 14 | fn resolve_file_by_path(&mut self, path: impl AsRef) -> Result, Self::ResolveError> { 15 | std::fs::read_to_string(path).map(Cow::from) 16 | } 17 | } 18 | 19 | fn main() -> Result<(), String> { 20 | let matches = app_from_crate!().arg(Arg::with_name("entrypoint").help("kirl program file for entrypoint").takes_value(true).required(true)).get_matches(); 21 | let entrypoint = matches.value_of("entrypoint").unwrap(); 22 | match compile(&mut OsFileResolver, &entrypoint) { 23 | Ok(executable) => { 24 | exec(&executable); 25 | Ok(()) 26 | } 27 | Err(err) => Err(format!("{}", err)), 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 White-Green 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /kirl_parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kirl_parser" 3 | version = "0.1.0" 4 | authors = ["White-Green <43771790+White-Green@users.noreply.github.com>"] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | tokenizer = { git = "https://github.com/White-Green/Yet-Another-Rust-Parser", rev = "9b833ae43d4d6c032d25de48c6077ed16e0c5b85" } 11 | #tokenizer = { path = "../../Yet-Another-Rust-Parser/tokenizer" } 12 | tokenizer_generator = { git = "https://github.com/White-Green/Yet-Another-Rust-Parser", rev = "9b833ae43d4d6c032d25de48c6077ed16e0c5b85" } 13 | #tokenizer_generator = { path = "../../Yet-Another-Rust-Parser/tokenizer_generator" } 14 | parser = { git = "https://github.com/White-Green/Yet-Another-Rust-Parser", rev = "9b833ae43d4d6c032d25de48c6077ed16e0c5b85" } 15 | #parser = { path = "../../Yet-Another-Rust-Parser/parser" } 16 | parser_generator = { git = "https://github.com/White-Green/Yet-Another-Rust-Parser", rev = "9b833ae43d4d6c032d25de48c6077ed16e0c5b85" } 17 | #parser_generator = { path = "../../Yet-Another-Rust-Parser/parser_generator" } 18 | once_cell = "1.8.0" 19 | arrayvec = "0.7.1" 20 | kirl_common = { path = "../kirl_common" } 21 | -------------------------------------------------------------------------------- /kirl_parser/src/lib.rs: -------------------------------------------------------------------------------- 1 | use arrayvec::ArrayVec; 2 | use std::error::Error; 3 | use std::fmt::{Display, Formatter}; 4 | use std::ops::Range; 5 | 6 | use once_cell::unsync::OnceCell; 7 | use parser::{Parse, ParseError}; 8 | use tokenizer::Tokenize; 9 | 10 | use crate::kirl_parser::{get_parser, KirlTopLevelStatement, Parser, Symbol}; 11 | use crate::kirl_tokenizer::{get_tokenizer, TokenizeError, Tokenizer}; 12 | 13 | pub mod kirl_parser; 14 | pub mod kirl_tokenizer; 15 | 16 | #[derive(Clone, Default, Copy, Debug, PartialEq)] 17 | pub struct CharacterPosition { 18 | pub line: usize, 19 | pub column: usize, 20 | } 21 | 22 | impl CharacterPosition { 23 | pub fn zero() -> Self { 24 | Self::default() 25 | } 26 | 27 | pub fn new(line: usize, column: usize) -> Self { 28 | CharacterPosition { line, column } 29 | } 30 | 31 | pub fn next(self) -> Self { 32 | let CharacterPosition { line, column } = self; 33 | CharacterPosition { line, column: column + 1 } 34 | } 35 | 36 | pub fn next_line(self) -> Self { 37 | let CharacterPosition { line, .. } = self; 38 | CharacterPosition { line: line + 1, column: 0 } 39 | } 40 | } 41 | 42 | impl Display for CharacterPosition { 43 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 44 | let CharacterPosition { line, column } = self; 45 | write!(f, "Line:{},position:{}", line + 1, column) 46 | } 47 | } 48 | 49 | #[derive(Debug)] 50 | pub enum KirlParseError { 51 | TokenizeError(TokenizeError), 52 | ParseError(ParseError), 53 | } 54 | 55 | impl Display for KirlParseError { 56 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 57 | match self { 58 | KirlParseError::TokenizeError(e) => Display::fmt(e, f), 59 | KirlParseError::ParseError(e) => Display::fmt(e, f), 60 | } 61 | } 62 | } 63 | 64 | impl Error for KirlParseError { 65 | fn source(&self) -> Option<&(dyn Error + 'static)> { 66 | match self { 67 | KirlParseError::TokenizeError(e) => Some(e), 68 | KirlParseError::ParseError(e) => Some(e), 69 | } 70 | } 71 | } 72 | 73 | #[derive(Debug)] 74 | pub enum ParseErrorDetail { 75 | SyntaxErrorAt(Range), 76 | } 77 | 78 | impl Display for ParseErrorDetail { 79 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 80 | match self { 81 | ParseErrorDetail::SyntaxErrorAt(Range { start, end }) => { 82 | write!(f, "Syntax Error at {} - {}", start, end) 83 | } 84 | } 85 | } 86 | } 87 | 88 | impl Error for ParseErrorDetail {} 89 | 90 | pub struct KirlParser { 91 | tokenizer: Tokenizer, 92 | parser: Parser, 93 | } 94 | 95 | impl Default for KirlParser { 96 | fn default() -> Self { 97 | Self::new() 98 | } 99 | } 100 | 101 | impl KirlParser { 102 | pub fn new() -> Self { 103 | KirlParser { tokenizer: get_tokenizer(), parser: get_parser() } 104 | } 105 | 106 | pub fn parse(&self, input: &str) -> Result, KirlParseError> { 107 | let cell = OnceCell::new(); 108 | let parse_result = input 109 | .chars() 110 | .scan(CharacterPosition::zero(), |position, c| { 111 | let current_position = *position; 112 | *position = match c { 113 | '\n' => position.next_line(), 114 | _ => position.next(), 115 | }; 116 | Some((current_position, c)) 117 | }) 118 | .tokenize_with(&self.tokenizer, |(_, c)| *c) 119 | .flat_map(|token| match token { 120 | Ok(token) => token, 121 | Err(e) => { 122 | let _ = cell.set(e); 123 | ArrayVec::new() 124 | } 125 | }) 126 | .parse(&self.parser); 127 | cell.into_inner().map(KirlParseError::TokenizeError).map_or(Ok(()), Err).and_then(|_| match parse_result { 128 | Ok(Symbol::ValidKirlCode((_, code))) => Ok(code), 129 | Ok(_) => unreachable!("parserの仕様として、ValidKirlCodeに還元できないならErrになるのであんりーちゃぶる"), 130 | Err(e) => Err(KirlParseError::ParseError(e)), 131 | }) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /kirl/tests/main.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::assert::OutputAssertExt; 2 | use assert_cmd::prelude::CommandCargoExt; 3 | use predicates::prelude::predicate; 4 | use std::collections::{HashMap, VecDeque}; 5 | use std::fs; 6 | use std::process::Command; 7 | use tempfile::TempDir; 8 | 9 | #[derive(Debug)] 10 | enum FileMap { 11 | Directory(HashMap<&'static str, Self>), 12 | File(&'static [u8]), 13 | } 14 | 15 | impl From> for FileMap { 16 | fn from(map: HashMap<&'static str, FileMap>) -> Self { 17 | FileMap::Directory(map) 18 | } 19 | } 20 | 21 | impl From<&'static [u8]> for FileMap { 22 | fn from(value: &'static [u8]) -> Self { 23 | FileMap::File(value) 24 | } 25 | } 26 | 27 | impl From<&'static [u8; N]> for FileMap { 28 | fn from(value: &'static [u8; N]) -> Self { 29 | FileMap::File(value) 30 | } 31 | } 32 | 33 | macro_rules! insert_map { 34 | ($base:expr, $var:ident, $name:tt : {$($c:tt)*}, $($t:tt)*) => { 35 | $var.insert(stringify!($name), FileMap::from(create_map!(concat!($base, stringify!($name), "/"), $($c)*))); 36 | insert_map!($base, $var, $($t)*) 37 | }; 38 | ($base:expr, $var:ident, $name:tt, $($t:tt)*) => { 39 | $var.insert(concat!(stringify!($name), ".kirl"), FileMap::from(include_bytes!(concat!($base, stringify!($name), ".kirl")))); 40 | insert_map!($base, $var, $($t)*) 41 | }; 42 | ($base:expr, $var:ident, $name:tt : {$($c:tt)*}) => { 43 | $var.insert(stringify!($name), FileMap::from(create_map!(concat!($base, stringify!($name), "/"), $($c)*))); 44 | }; 45 | ($base:expr, $var:ident, $name:tt) => { 46 | $var.insert(concat!(stringify!($name), ".kirl"), FileMap::from(include_bytes!(concat!($base, stringify!($name), ".kirl")))); 47 | }; 48 | } 49 | 50 | macro_rules! create_map { 51 | ($base:expr, $($t:tt)*) => { 52 | { 53 | let mut map = HashMap::new(); 54 | insert_map!($base, map, $($t)*); 55 | map 56 | } 57 | }; 58 | } 59 | 60 | macro_rules! create_test_inner { 61 | ($name:ident, {$($map:tt)*}, $entry:expr, $out:expr, $cmd:ident, $($assert:tt)*) => { 62 | #[test] 63 | fn $name() -> anyhow::Result<()> { 64 | let files = create_map!("../../examples/", $($map)*); 65 | let temp_dir = TempDir::new()?; 66 | let temp_path = temp_dir.path(); 67 | let mut q = VecDeque::new(); 68 | q.push_back((temp_path.to_path_buf(), &files)); 69 | while let Some((path, files)) = q.pop_front() { 70 | for (name, files) in files { 71 | let child_path = path.join(name); 72 | match files { 73 | FileMap::Directory(body) => { 74 | fs::create_dir(&child_path)?; 75 | q.push_back((child_path, body)); 76 | } 77 | FileMap::File(body) => { 78 | fs::write(child_path, body)?; 79 | } 80 | } 81 | } 82 | } 83 | let mut $cmd = Command::cargo_bin("kirl")?; 84 | $cmd.arg(temp_path.join($entry)); 85 | $($assert)* 86 | Ok(()) 87 | } 88 | }; 89 | } 90 | 91 | macro_rules! create_test { 92 | (name: $name:ident; map: {$($map:tt)*}; entry: $entry:expr; out: $out:expr;) => { 93 | create_test_inner!($name, {$($map)*}, $entry, $out, cmd, cmd.assert() 94 | .success() 95 | .stdout(predicate::str::contains($out));); 96 | }; 97 | } 98 | 99 | macro_rules! create_failue_test { 100 | (name: $name:ident; map: {$($map:tt)*}; entry: $entry:expr; out: $out:expr;) => { 101 | create_test_inner!($name, {$($map)*}, $entry, $out, cmd, cmd.assert() 102 | .failure() 103 | .stderr(predicate::str::contains($out));); 104 | }; 105 | } 106 | 107 | create_test! { 108 | name: test_0; 109 | map: { 110 | 0: { 111 | hello 112 | } 113 | }; 114 | entry: "0/hello.kirl"; 115 | out: "Hello, World! 116 | "; 117 | } 118 | 119 | create_test! { 120 | name: test_1_1; 121 | map: { 122 | 1: { 123 | fib1 124 | } 125 | }; 126 | entry: "1/fib1.kirl"; 127 | out: "6765 128 | "; 129 | } 130 | 131 | create_test! { 132 | name: test_1_2; 133 | map: { 134 | 1: { 135 | fib2 136 | } 137 | }; 138 | entry: "1/fib2.kirl"; 139 | out: "6765 140 | "; 141 | } 142 | 143 | create_test! { 144 | name: test_1_3; 145 | map: { 146 | 1: { 147 | fib3 148 | } 149 | }; 150 | entry: "1/fib3.kirl"; 151 | out: "6765 152 | "; 153 | } 154 | 155 | create_test! { 156 | name: test_1_4; 157 | map: { 158 | 1: { 159 | fib4 160 | } 161 | }; 162 | entry: "1/fib4.kirl"; 163 | out: "6765 164 | "; 165 | } 166 | 167 | create_test! { 168 | name: test_2; 169 | map: { 170 | 2: { 171 | main, 172 | sub1, 173 | subdir: { 174 | sub2, 175 | sub3 176 | } 177 | } 178 | }; 179 | entry: "2/main.kirl"; 180 | out: "this is in main.kirl 181 | this is in function \"f\" in sub.kirl 182 | this is in function \"f\" in subdir/sub2.kirl 183 | this is in function \"f\" in subdir/sub3.kirl 184 | "; 185 | } 186 | 187 | create_test! { 188 | name: test_3_valid; 189 | map: { 190 | 3: { 191 | valid 192 | } 193 | }; 194 | entry: "3/valid.kirl"; 195 | out: "this is in function \"f\" 196 | "; 197 | } 198 | 199 | create_failue_test! { 200 | name: test_3_error; 201 | map: { 202 | 3: { 203 | error 204 | } 205 | }; 206 | entry: "3/error.kirl"; 207 | out: "Error: \"A named reference \\\"f\\\" at Line:5,position:0 - Line:5,position:1 is not found.\" 208 | "; 209 | } 210 | 211 | create_test! { 212 | name: test_4; 213 | map: { 214 | 4: { 215 | main 216 | } 217 | }; 218 | entry: "4/main.kirl"; 219 | out: "this is in function \"f\":(String)->() 220 | string 221 | this is in function \"f\":(Number)->() 222 | 256 223 | "; 224 | } 225 | 226 | create_test! { 227 | name: test_5; 228 | map: { 229 | 5: { 230 | main 231 | } 232 | }; 233 | entry: "5/main.kirl"; 234 | out: "this is a string message 235 | 1024 236 | てすと用めっせーじ 237 | 2048 238 | this is a new string message 239 | "; 240 | } 241 | 242 | create_test! { 243 | name: test_6; 244 | map: { 245 | 6: { 246 | main 247 | } 248 | }; 249 | entry: "6/main.kirl"; 250 | out: "128 251 | test string 252 | 128 253 | test string 254 | "; 255 | } 256 | 257 | create_test! { 258 | name: test_7; 259 | map: { 260 | 7: { 261 | main 262 | } 263 | }; 264 | entry: "7/main.kirl"; 265 | out: "1 266 | string_1 267 | 2 268 | string_2 269 | 3 270 | string_3 271 | 1 272 | string_1 273 | 3 274 | string_3 275 | 2 276 | string_2 277 | "; 278 | } 279 | 280 | create_test! { 281 | name: test_8_1; 282 | map: { 283 | 8: { 284 | main1 285 | } 286 | }; 287 | entry: "8/main1.kirl"; 288 | out: "condition is not #{ value: Number } 289 | "; 290 | } 291 | 292 | create_test! { 293 | name: test_8_2; 294 | map: { 295 | 8: { 296 | main2 297 | } 298 | }; 299 | entry: "8/main2.kirl"; 300 | out: "condition is #{ value: Number } 301 | value: 42 302 | "; 303 | } 304 | -------------------------------------------------------------------------------- /kirl_vm/src/vm.rs: -------------------------------------------------------------------------------- 1 | use kirl_common::interface::{InterchangeKirlVMValue, KirlVMValueLock}; 2 | use std::collections::HashMap; 3 | use std::sync::{Arc, RwLock}; 4 | 5 | use crate::bytecode::{KirlByteCodeOpcode, KirlVMExecutable}; 6 | 7 | fn unwrap(ptr: Arc>) -> T { 8 | Arc::try_unwrap(ptr).map(|rw| rw.into_inner().expect("")).unwrap_or_else(|ptr| ptr.read().expect("").clone()) 9 | } 10 | 11 | pub fn exec( 12 | KirlVMExecutable { 13 | bytecodes, 14 | entry_point, 15 | static_value_generators, 16 | rust_functions, 17 | function_pointers, 18 | member_names, 19 | types, 20 | }: &KirlVMExecutable, 21 | ) { 22 | let mut local_stack = Vec::new(); 23 | let mut global_stack: Vec> = Vec::new(); 24 | let mut global_stack_offset = 0usize; 25 | let mut global_stack_offset_stack = Vec::new(); 26 | let mut program_counter_stack = Vec::new(); 27 | let mut program_counter = *entry_point; 28 | let mut additional_operand = Vec::new(); 29 | loop { 30 | let instruction = bytecodes[program_counter]; 31 | match instruction.opcode() { 32 | KirlByteCodeOpcode::LoadStaticValue => { 33 | let operand = instruction.operand(); 34 | local_stack.push(static_value_generators[operand as usize]()); 35 | } 36 | KirlByteCodeOpcode::Load => { 37 | let operand = instruction.operand() as usize + global_stack_offset; 38 | local_stack.push(global_stack[operand].clone()); 39 | } 40 | KirlByteCodeOpcode::Store => { 41 | let operand = instruction.operand() as usize + global_stack_offset; 42 | if global_stack.len() <= operand { 43 | global_stack.resize_with(operand + 1, || Arc::new(RwLock::new(Vec::new().into_boxed_slice()))); 44 | } 45 | global_stack[operand] = local_stack.pop().expect(""); 46 | } 47 | KirlByteCodeOpcode::JumpIfTrue => { 48 | let condition = local_stack.pop().expect(""); 49 | let condition = bool::try_from_kirl_value(condition).expect(""); 50 | if *condition.read().expect("") { 51 | let operand = instruction.operand_signed(); 52 | program_counter = ((program_counter as isize) + (operand as isize)) as usize; 53 | continue; 54 | } 55 | } 56 | KirlByteCodeOpcode::JumpIfHasType => { 57 | let ty = &types[additional_operand.pop().expect("") as usize]; 58 | let condition = local_stack.last().expect(""); 59 | if condition.get_type().is_a(ty) { 60 | let operand = instruction.operand_signed(); 61 | program_counter = ((program_counter as isize) + (operand as isize)) as usize; 62 | continue; 63 | } 64 | } 65 | KirlByteCodeOpcode::Jump => { 66 | let operand = instruction.operand_signed(); 67 | program_counter = ((program_counter as isize) + (operand as isize)) as usize; 68 | continue; 69 | } 70 | KirlByteCodeOpcode::CallKirlFunction => { 71 | let operand = instruction.operand(); 72 | program_counter_stack.push(program_counter); 73 | program_counter = function_pointers[operand as usize]; 74 | global_stack_offset_stack.push(global_stack_offset); 75 | global_stack_offset = global_stack.len(); 76 | continue; 77 | } 78 | KirlByteCodeOpcode::CallRustFunction => { 79 | let operand = instruction.operand(); 80 | let mut function = rust_functions[operand as usize].lock().unwrap(); 81 | let argument_count = function.argument_count(); 82 | let mut arguments = Vec::with_capacity(argument_count); 83 | for _ in 0..argument_count { 84 | arguments.push(local_stack.pop().expect("")); 85 | } 86 | let ret = function.call(arguments).expect("TODO:組み込み関数が失敗した場合(ここ)の処理"); 87 | local_stack.push(ret); 88 | } 89 | KirlByteCodeOpcode::Return => { 90 | if program_counter_stack.is_empty() { 91 | return; 92 | } 93 | program_counter = program_counter_stack.pop().expect(""); 94 | global_stack_offset = global_stack_offset_stack.pop().expect(""); 95 | } 96 | KirlByteCodeOpcode::Nop => {} 97 | KirlByteCodeOpcode::AccessTupleItem => { 98 | let operand = instruction.operand(); 99 | let value = local_stack.pop().expect(""); 100 | let value = Box::<[Arc]>::try_from_kirl_value(value).expect(""); 101 | let value = value.read().expect(""); 102 | let value = Arc::clone(&value[operand as usize]); 103 | local_stack.push(value); 104 | } 105 | KirlByteCodeOpcode::AccessMember => { 106 | let operand = instruction.operand(); 107 | let value = local_stack.pop().expect(""); 108 | let value = HashMap::>::try_from_kirl_value(value).expect(""); 109 | let value = value.read().expect(""); 110 | let member = value.get(&member_names[operand as usize]).expect(""); 111 | local_stack.push(Arc::clone(member)); 112 | } 113 | KirlByteCodeOpcode::AssignTupleItem => { 114 | let operand = instruction.operand(); 115 | let value = local_stack.pop().expect(""); 116 | let dest = local_stack.pop().expect(""); 117 | let dest = Box::<[Arc]>::try_from_kirl_value(dest).expect(""); 118 | dest.write().expect("")[operand as usize] = value; 119 | } 120 | KirlByteCodeOpcode::AssignMember => { 121 | let operand = instruction.operand(); 122 | let value = local_stack.pop().expect(""); 123 | let dest = local_stack.pop().expect(""); 124 | let dest = HashMap::>::try_from_kirl_value(dest).expect(""); 125 | dest.write().expect("").insert(member_names[operand as usize].clone(), value); 126 | } 127 | KirlByteCodeOpcode::ConstructStruct => { 128 | let operand = instruction.operand(); 129 | let mut result = HashMap::with_capacity(operand as usize); 130 | for _ in 0..operand { 131 | let name = local_stack.pop().expect(""); 132 | let name = unwrap(String::try_from_kirl_value(name).expect("")); 133 | let value = local_stack.pop().expect(""); 134 | result.insert(name, value); 135 | } 136 | local_stack.push(Arc::new(RwLock::new(result))); 137 | } 138 | KirlByteCodeOpcode::ConstructTuple => { 139 | let operand = instruction.operand(); 140 | let mut result = Vec::with_capacity(operand as usize); 141 | for _ in 0..operand { 142 | result.push(local_stack.pop().expect("")); 143 | } 144 | local_stack.push(Arc::new(RwLock::new(result.into_boxed_slice()))); 145 | } 146 | KirlByteCodeOpcode::ConstructArray => { 147 | let operand = instruction.operand(); 148 | let mut result = Vec::with_capacity(operand as usize); 149 | for _ in 0..operand { 150 | result.push(local_stack.pop().expect("")); 151 | } 152 | local_stack.push(Arc::new(RwLock::new(result))); 153 | } 154 | KirlByteCodeOpcode::PushAdditionalOperand => { 155 | let operand = instruction.operand(); 156 | additional_operand.push(operand); 157 | } 158 | } 159 | program_counter += 1; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /kirl_common/src/interface.rs: -------------------------------------------------------------------------------- 1 | use crate::typing::{HIRType, LIRType}; 2 | use dec::Decimal128; 3 | use once_cell::sync::Lazy; 4 | use std::any::{Any, TypeId}; 5 | use std::borrow::Cow; 6 | use std::collections::HashMap; 7 | use std::error::Error; 8 | use std::fmt::Debug; 9 | use std::marker::PhantomData; 10 | use std::sync::{Arc, RwLock}; 11 | 12 | pub trait KirlRustFunction: Send + Sync { 13 | fn static_type() -> Cow<'static, HIRType> 14 | where 15 | Self: Sized; 16 | fn argument_count(&self) -> usize; 17 | fn call(&mut self, args: Vec>) -> Result, Box>; 18 | } 19 | 20 | pub struct FunctionWrapper(F, PhantomData<(Args, Result)>); 21 | 22 | macro_rules! count { 23 | ()=>{ 0 }; 24 | ($t:ident)=>{ 1 }; 25 | ($f:ident,$($t:ident),*)=>{ 1 + count!($($t),*) }; 26 | } 27 | 28 | macro_rules! tuple { 29 | ()=>{()}; 30 | ($($t:ident),+)=>{($($t),+,)}; 31 | } 32 | 33 | macro_rules! impl_fn { 34 | ($($t:ident),*)=>{ 35 | impl From for FunctionWrapper 36 | where F: FnMut($($t),*) -> R { 37 | fn from(function: F) -> Self { 38 | FunctionWrapper(function, PhantomData::default()) 39 | } 40 | } 41 | impl KirlRustFunction for FunctionWrapper, F> 42 | where F: FnMut($($t),*) -> Result, 43 | R: InterchangeKirlVMValue, 44 | E: std::error::Error + 'static, 45 | Self: Send + Sync, 46 | $($t: InterchangeKirlVMValue + Clone),* { 47 | fn static_type() -> Cow<'static, HIRType> { 48 | Cow::Owned(LIRType::Function { arguments: vec![$($t::static_type().into_owned()),*], result: Box::new(R::static_type().into_owned()) }.into()) 49 | } 50 | fn argument_count(&self) -> usize { count!($($t),*) } 51 | fn call(&mut self, args: Vec>) -> Result, Box> { 52 | #[allow(non_snake_case)] 53 | if let Ok([$($t),*]) = <[_;count!($($t),*)] as std::convert::TryFrom<_>>::try_from(args) { 54 | self.0($({ 55 | let value_ref = $t::try_from_kirl_value($t).unwrap_or_else(|value:Arc|panic!("expected type {:?} but found {:?}.", std::any::type_name::<$t>(), value.type_name())); 56 | Arc::try_unwrap(value_ref).map(|lock| lock.into_inner().expect("")).unwrap_or_else(|arc| arc.read().expect("").clone()) 57 | }),*).map(|result|result.into_kirl_value()).map_err(|err|Box::new(err) as Box) 58 | } else { unreachable!() } 59 | } 60 | } 61 | } 62 | } 63 | 64 | fn downcast(value: Arc) -> Result>, Arc> { 65 | let id = ::type_id(&*value); 66 | if id == TypeId::of::>() { 67 | unsafe { 68 | let raw = Arc::into_raw(value); 69 | Ok(Arc::from_raw(raw as *const RwLock)) 70 | } 71 | } else { 72 | Err(value) 73 | } 74 | } 75 | 76 | impl_fn!(); 77 | impl_fn!(A1); 78 | impl_fn!(A1, A2); 79 | impl_fn!(A1, A2, A3); 80 | impl_fn!(A1, A2, A3, A4); 81 | impl_fn!(A1, A2, A3, A4, A5); 82 | 83 | #[macro_export] 84 | macro_rules! get_type { 85 | (!)=>{ kirl_common::typing::LIRType::Unreachable }; 86 | (($($id:ident)::+ $(::<$($ty:tt),*>)?))=>{ $crate::typing::LIRType::Named{path:vec![$(std::string::String::from(stringify!($id))),+], generics_arguments: vec![$($(get_type!($ty)),*)?]} }; 87 | ((($($ty:tt),*)->($r:tt)))=>{ $crate::typing::LIRType::Function{arguments: vec![$(get_type!($ty)),*], result: Box::new(get_type!($r))} }; 88 | (())=>{ $crate::typing::LIRType::Tuple(Vec::new()) }; 89 | (($($ty:tt),*,))=>{ $crate::typing::LIRType::Tuple(vec![$(get_type!($ty)),*]) }; 90 | ([$ty:tt])=>{ $crate::typing::LIRType::Array(Box::new(get_type!($ty))) }; 91 | ((#{$($name:ident : $ty:tt),*$(,)?}))=>{ 92 | { 93 | let map = std::collections::BTreeMap::::new(); 94 | $( 95 | map.insert(std::string::String::from(stringify!($name)), get_type!($ty)).expect("duplicated name"); 96 | )* 97 | $crate::typing::LIRType::AnonymousStruct(map) 98 | } 99 | }; 100 | (($($ty:tt)|*|))=>{ $crate::typing::LIRType::Or(vec![get_type!($ty)]) }; 101 | } 102 | 103 | pub trait InterchangeKirlVMValue: Sized { 104 | fn static_type() -> Cow<'static, LIRType>; 105 | fn get_type(&self) -> Cow; 106 | fn into_kirl_value(self) -> Arc; 107 | fn try_from_kirl_value(value: Arc) -> Result>, Arc>; 108 | } 109 | 110 | impl InterchangeKirlVMValue for T { 111 | fn static_type() -> Cow<'static, LIRType> { 112 | Self::static_type() 113 | } 114 | 115 | fn get_type(&self) -> Cow { 116 | KirlVMValue::get_type(self) 117 | } 118 | 119 | fn into_kirl_value(self) -> Arc { 120 | Arc::new(RwLock::new(self)) 121 | } 122 | 123 | fn try_from_kirl_value(value: Arc) -> Result>, Arc> { 124 | downcast(value) 125 | } 126 | } 127 | 128 | pub trait KirlVMValue: Any + Debug + Send + Sync + 'static { 129 | fn static_type() -> Cow<'static, LIRType> 130 | where 131 | Self: Sized; 132 | fn get_type(&self) -> Cow; 133 | fn type_name(&self) -> &'static str { 134 | std::any::type_name::() 135 | } 136 | } 137 | 138 | mod private { 139 | use super::KirlVMValue; 140 | use std::sync::RwLock; 141 | 142 | pub trait KirlVMValueLockPrivate {} 143 | 144 | impl KirlVMValueLockPrivate for RwLock {} 145 | } 146 | 147 | pub trait KirlVMValueLock: private::KirlVMValueLockPrivate + Any + Debug + Send + Sync + 'static { 148 | fn get_type(&self) -> LIRType; 149 | fn type_name(&self) -> &'static str; 150 | } 151 | 152 | impl KirlVMValueLock for RwLock { 153 | fn get_type(&self) -> LIRType { 154 | self.read().unwrap().get_type().into_owned() 155 | } 156 | 157 | fn type_name(&self) -> &'static str { 158 | self.read().unwrap().type_name() 159 | } 160 | } 161 | 162 | impl KirlVMValue for String { 163 | fn static_type() -> Cow<'static, LIRType> { 164 | static TYPE: Lazy = Lazy::new(|| get_type!((String)).into_normalized()); 165 | Cow::Borrowed(&TYPE) 166 | } 167 | 168 | fn get_type(&self) -> Cow { 169 | ::static_type() 170 | } 171 | } 172 | 173 | impl KirlVMValue for Decimal128 { 174 | fn static_type() -> Cow<'static, LIRType> { 175 | static TYPE: Lazy = Lazy::new(|| get_type!((Number)).into_normalized()); 176 | Cow::Borrowed(&TYPE) 177 | } 178 | 179 | fn get_type(&self) -> Cow { 180 | ::static_type() 181 | } 182 | } 183 | 184 | impl InterchangeKirlVMValue for () { 185 | fn static_type() -> Cow<'static, LIRType> { 186 | static TYPE: Lazy = Lazy::new(|| get_type!(()).into_normalized()); 187 | Cow::Borrowed(&TYPE) 188 | } 189 | fn get_type(&self) -> Cow { 190 | Self::static_type() 191 | } 192 | fn into_kirl_value(self) -> Arc { 193 | let value = Vec::>::new().into_boxed_slice(); 194 | Arc::new(RwLock::new(value)) 195 | } 196 | fn try_from_kirl_value(value: Arc) -> Result>, Arc> { 197 | ]>>::try_from_kirl_value(value)?; 198 | Ok(Arc::new(RwLock::new(()))) 199 | } 200 | } 201 | 202 | impl KirlVMValue for LIRType { 203 | fn static_type() -> Cow<'static, LIRType> { 204 | static TYPE: Lazy = Lazy::new(|| get_type!((Type)).into_normalized()); 205 | Cow::Borrowed(&TYPE) 206 | } 207 | 208 | fn get_type(&self) -> Cow { 209 | ::static_type() 210 | } 211 | } 212 | 213 | impl KirlVMValue for bool { 214 | fn static_type() -> Cow<'static, LIRType> { 215 | static TYPE: Lazy = Lazy::new(|| get_type!((Bool)).into_normalized()); 216 | Cow::Borrowed(&TYPE) 217 | } 218 | 219 | fn get_type(&self) -> Cow { 220 | ::static_type() 221 | } 222 | } 223 | 224 | impl KirlVMValue for Vec> { 225 | fn static_type() -> Cow<'static, LIRType> 226 | where 227 | Self: Sized, 228 | { 229 | static TYPE: Lazy = Lazy::new(|| get_type!([()]).into_normalized()); 230 | Cow::Borrowed(&TYPE) 231 | } 232 | 233 | fn get_type(&self) -> Cow { 234 | Cow::Owned(LIRType::Array(Box::new(LIRType::Or(self.iter().map(|value| value.get_type()).collect()).into_normalized()))) 235 | } 236 | } 237 | 238 | impl KirlVMValue for Box<[Arc]> { 239 | fn static_type() -> Cow<'static, LIRType> 240 | where 241 | Self: Sized, 242 | { 243 | static TYPE: Lazy = Lazy::new(|| get_type!(()).into_normalized()); 244 | Cow::Borrowed(&TYPE) 245 | } 246 | 247 | fn get_type(&self) -> Cow { 248 | Cow::Owned(LIRType::Tuple(self.iter().map(|value| value.get_type()).collect())) 249 | } 250 | } 251 | 252 | impl KirlVMValue for HashMap> { 253 | fn static_type() -> Cow<'static, LIRType> 254 | where 255 | Self: Sized, 256 | { 257 | static TYPE: Lazy = Lazy::new(|| get_type!((#{})).into_normalized()); 258 | Cow::Borrowed(&TYPE) 259 | } 260 | 261 | fn get_type(&self) -> Cow { 262 | Cow::Owned(LIRType::AnonymousStruct(self.iter().map(|(key, value)| (key.clone(), value.get_type())).collect()).into_normalized()) 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /kirl_engine/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::collections::{HashMap, HashSet}; 3 | use std::error::Error; 4 | use std::fmt::{Debug, Display, Formatter}; 5 | use std::ops::Deref; 6 | use std::path::{Path, PathBuf}; 7 | 8 | use kirl_common::typing::HIRType; 9 | use uuid::Uuid; 10 | 11 | use kirl_parser::kirl_parser::Function; 12 | use kirl_parser::{KirlParseError, KirlParser}; 13 | use kirl_semantic_analyzer::name_resolver::{resolve_statements, statement_references, KirlNameResolver}; 14 | use kirl_semantic_analyzer::syntax_tree_to_hir::{analysis_function, analysis_statements, AnalysisStatementError, SearchPaths}; 15 | use kirl_semantic_analyzer::type_checker::{decision_type, used_functions, DecisionTypeError}; 16 | use kirl_semantic_analyzer::{collect_top_level_item_with_imports, HIRStatement, KirlTopLevelItems, WithImport}; 17 | use kirl_stdlib::get_stdlib; 18 | use kirl_vm::bytecode::KirlVMExecutable; 19 | use kirl_vm::lir::{hir_to_lir, LIRStatementList, LIRStatementListConvertError}; 20 | 21 | pub trait KirlFileResolver { 22 | type ResolveError: Error + Send + Sync + 'static; 23 | fn resolve_file_by_path(&mut self, path: impl AsRef) -> Result, Self::ResolveError>; 24 | } 25 | 26 | #[derive(Debug)] 27 | pub enum KirlCompileError { 28 | ParseError(KirlParseError), 29 | DecisionTypeError(DecisionTypeError), 30 | LIRConvertError(LIRStatementListConvertError), 31 | AnalysisError(AnalysisStatementError), 32 | FileResolveError(F), 33 | } 34 | 35 | impl From for KirlCompileError { 36 | fn from(e: KirlParseError) -> Self { 37 | KirlCompileError::ParseError(e) 38 | } 39 | } 40 | 41 | impl From for KirlCompileError { 42 | fn from(e: DecisionTypeError) -> Self { 43 | KirlCompileError::DecisionTypeError(e) 44 | } 45 | } 46 | 47 | impl From for KirlCompileError { 48 | fn from(e: LIRStatementListConvertError) -> Self { 49 | KirlCompileError::LIRConvertError(e) 50 | } 51 | } 52 | 53 | impl From for KirlCompileError { 54 | fn from(e: AnalysisStatementError) -> Self { 55 | KirlCompileError::AnalysisError(e) 56 | } 57 | } 58 | 59 | impl Display for KirlCompileError { 60 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 61 | match self { 62 | KirlCompileError::ParseError(e) => Display::fmt(e, f), 63 | KirlCompileError::DecisionTypeError(e) => Display::fmt(e, f), 64 | KirlCompileError::LIRConvertError(e) => Display::fmt(e, f), 65 | KirlCompileError::AnalysisError(e) => Display::fmt(e, f), 66 | KirlCompileError::FileResolveError(e) => Display::fmt(e, f), 67 | } 68 | } 69 | } 70 | 71 | impl Error for KirlCompileError { 72 | fn source(&self) -> Option<&(dyn Error + 'static)> { 73 | match self { 74 | KirlCompileError::ParseError(e) => Some(e), 75 | KirlCompileError::DecisionTypeError(e) => Some(e), 76 | KirlCompileError::LIRConvertError(e) => Some(e), 77 | KirlCompileError::AnalysisError(e) => Some(e), 78 | KirlCompileError::FileResolveError(e) => Some(e), 79 | } 80 | } 81 | } 82 | 83 | struct InFileResolver<'a> { 84 | function_types: &'a HashMap<(PathBuf, String), Vec<(Uuid, HIRType)>>, 85 | base_file_path: &'a Path, 86 | } 87 | 88 | impl<'a> KirlNameResolver for InFileResolver<'a> { 89 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 90 | let InFileResolver { function_types, base_file_path } = self; 91 | let key = match full_path { 92 | [] => unreachable!(), 93 | [name] => { 94 | let file_path = base_file_path.to_path_buf(); 95 | (file_path, name.clone()) 96 | } 97 | [path @ .., name] => { 98 | let mut file_path = base_file_path.to_path_buf(); 99 | file_path.pop(); 100 | file_path.extend(path); 101 | let file_path = file_path.with_extension("kirl"); 102 | (file_path, name.clone()) 103 | } 104 | }; 105 | function_types.get(&key).into_iter().flatten().map(|(id, ty)| (*id, ty.clone())).collect() 106 | } 107 | } 108 | 109 | fn resolve( 110 | parser: &KirlParser, 111 | hir: Vec>, 112 | hir_type: HIRType, 113 | hir_path: &impl AsRef, 114 | file_resolver: &mut F, 115 | parsed_files: &mut HashSet, 116 | mut static_resolver: &mut impl KirlNameResolver, 117 | function_types: &mut HashMap<(PathBuf, String), Vec<(Uuid, HIRType)>>, 118 | parsed_functions: &mut HashMap>>, 119 | loaded_functions: &mut HashMap, 120 | ) -> Result>, KirlCompileError> { 121 | let current_references = statement_references(&hir); 122 | for reference_path in current_references { 123 | match reference_path { 124 | [] => unreachable!(), 125 | [_] => {} 126 | [reference_file_path @ .., _] => { 127 | let mut file_path = hir_path.as_ref().to_path_buf(); 128 | file_path.pop(); 129 | file_path.extend(reference_file_path); 130 | let file_path = file_path.with_extension("kirl"); 131 | if !parsed_files.contains(&file_path) { 132 | let file = match file_resolver.resolve_file_by_path(&file_path) { 133 | Ok(file) => file, 134 | Err(_) => continue, 135 | }; 136 | let KirlTopLevelItems { functions, .. } = collect_top_level_item_with_imports(parser.parse(&file)?); 137 | for function in functions { 138 | add_parsed_function(function_types, parsed_functions, &file_path, function)?; 139 | } 140 | } 141 | } 142 | } 143 | } 144 | let loaded = resolve_statements(hir, &mut (InFileResolver { function_types, base_file_path: hir_path.as_ref() }, &mut static_resolver)); 145 | let (argument_types, return_type) = if let HIRType::Function { arguments, result } = &hir_type { (arguments.clone(), result.deref().clone()) } else { unreachable!() }; 146 | let loaded = decision_type(loaded, argument_types, return_type)?; 147 | let used_function_id = used_functions(&loaded); 148 | let next_resolve = function_types 149 | .iter() 150 | .flat_map(|((path, _), value)| { 151 | let mut result = Vec::new(); 152 | for (id, ty) in value { 153 | if used_function_id.contains(id) { 154 | if let Some(body) = parsed_functions.remove(id) { 155 | result.push((*id, body, ty.clone(), path.to_path_buf())); 156 | } 157 | } 158 | } 159 | result 160 | }) 161 | .collect::>(); 162 | for (id, statements, ty, path) in next_resolve { 163 | let argument_count = if let HIRType::Function { arguments, .. } = &ty { arguments.len() } else { unreachable!() }; 164 | let statements = resolve(parser, statements, ty, &path, file_resolver, parsed_files, static_resolver, function_types, parsed_functions, loaded_functions)?; 165 | loaded_functions.insert(id, hir_to_lir(statements, argument_count)?); 166 | } 167 | Ok(loaded) 168 | } 169 | 170 | fn add_parsed_function(function_types: &mut HashMap<(PathBuf, String), Vec<(Uuid, HIRType)>>, parsed_functions: &mut HashMap>>, file_path: &Path, function: WithImport) -> Result<(), KirlCompileError> { 171 | let function_name = function.item.name.clone(); 172 | let (function_body, argument, result) = analysis_function(function)?; 173 | let id = Uuid::new_v4(); 174 | function_types.entry((file_path.to_path_buf(), function_name)).or_default().push((id, HIRType::Function { arguments: argument, result: Box::new(result) })); 175 | parsed_functions.insert(id, function_body); 176 | Ok(()) 177 | } 178 | 179 | pub fn compile(file_resolver: &mut F, entry_point: impl AsRef) -> Result> { 180 | let stdlib = get_stdlib(); 181 | let mut resolver = HashMap::new(); 182 | resolver.insert("std".to_string(), stdlib); 183 | let parser = KirlParser::new(); 184 | let entry_point_body = file_resolver.resolve_file_by_path(&entry_point).map_err(KirlCompileError::FileResolveError)?; 185 | let syntax_tree = parser.parse(&entry_point_body)?; 186 | let KirlTopLevelItems { statements, functions, .. } = collect_top_level_item_with_imports(syntax_tree); 187 | let hir = analysis_statements(statements)?; 188 | let mut parsed_files = HashSet::new(); 189 | let mut function_types = HashMap::new(); 190 | let mut parsed_functions = HashMap::new(); 191 | let mut loaded_functions = HashMap::new(); 192 | for function in functions { 193 | add_parsed_function(&mut function_types, &mut parsed_functions, &entry_point.as_ref().to_path_buf(), function)?; 194 | } 195 | let hir = resolve( 196 | &parser, 197 | hir, 198 | HIRType::Function { 199 | arguments: Vec::new(), 200 | result: Box::new(HIRType::Or(vec![HIRType::Tuple(Vec::new()), HIRType::Named { path: vec!["Number".to_string()], generics_arguments: Vec::new() }])), 201 | }, 202 | &entry_point, 203 | file_resolver, 204 | &mut parsed_files, 205 | &mut resolver, 206 | &mut function_types, 207 | &mut parsed_functions, 208 | &mut loaded_functions, 209 | )?; 210 | let lir = hir_to_lir(hir, 0)?; 211 | loaded_functions.insert(Uuid::nil(), lir); 212 | Ok(KirlVMExecutable::new(loaded_functions.into_iter().map(|(id, code)| (id, code.0)), stdlib.static_values(), stdlib.functions(), Uuid::nil())) 213 | } 214 | -------------------------------------------------------------------------------- /kirl_vm/src/bytecode.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::convert::TryFrom; 3 | 4 | use std::fmt::Debug; 5 | 6 | use std::sync::{Arc, Mutex, RwLock}; 7 | 8 | use kirl_common::dec::{Context, Decimal128}; 9 | use kirl_common::typing::LIRType; 10 | 11 | use kirl_common::interface::{KirlRustFunction, KirlVMValueLock}; 12 | use uuid::Uuid; 13 | 14 | use crate::lir::{LIRInstruction, LIRStatement}; 15 | 16 | #[derive(Debug, Clone, Copy)] 17 | pub struct KirlByteCode(KirlByteCodeOpcode, [u8; 3]); 18 | 19 | #[derive(Debug, Clone, Copy)] 20 | pub enum KirlByteCodeOpcode { 21 | LoadStaticValue, 22 | Load, 23 | Store, 24 | JumpIfTrue, 25 | JumpIfHasType, 26 | Jump, 27 | CallKirlFunction, 28 | CallRustFunction, 29 | Return, 30 | Nop, 31 | AccessTupleItem, 32 | AccessMember, 33 | AssignTupleItem, 34 | AssignMember, 35 | ConstructStruct, 36 | ConstructTuple, 37 | ConstructArray, 38 | PushAdditionalOperand, 39 | } 40 | 41 | impl KirlByteCode { 42 | pub fn new(opcode: KirlByteCodeOpcode, operand: u32) -> Self { 43 | let [x1, x2, x3, x4] = operand.to_le_bytes(); 44 | assert!(x4 == 0xff || x4 == 0x00); 45 | KirlByteCode(opcode, [x1, x2, x3]) 46 | } 47 | 48 | pub fn without_operand(opcode: KirlByteCodeOpcode) -> Self { 49 | Self::new(opcode, 0) 50 | } 51 | 52 | pub fn new_signed(opcode: KirlByteCodeOpcode, operand: i32) -> Self { 53 | let operand = operand as u32; 54 | assert_eq!(((operand >> 24) ^ (operand >> 16)) & 0b1000_0000, 0); 55 | Self::new(opcode, operand) 56 | } 57 | 58 | pub fn opcode(self) -> KirlByteCodeOpcode { 59 | self.0 60 | } 61 | 62 | pub fn operand(self) -> u32 { 63 | let [x1, x2, x3] = self.1; 64 | u32::from_le_bytes([x1, x2, x3, 0]) 65 | } 66 | 67 | pub fn operand_signed(self) -> i32 { 68 | let [x1, x2, x3] = self.1; 69 | let x4 = if x3 & 0b1000_0000 == 0 { 0 } else { 0xff }; 70 | i32::from_le_bytes([x1, x2, x3, x4]) 71 | } 72 | } 73 | 74 | pub(crate) type StaticValueGenerator = Arc Arc>; 75 | 76 | pub struct KirlVMExecutable { 77 | pub(crate) bytecodes: Vec, 78 | pub(crate) entry_point: usize, 79 | pub(crate) static_value_generators: Vec, 80 | pub(crate) rust_functions: Vec>>, 81 | pub(crate) function_pointers: Vec, 82 | pub(crate) member_names: Vec, 83 | pub(crate) types: Vec, 84 | } 85 | 86 | impl KirlVMExecutable { 87 | pub fn new(functions: impl IntoIterator)>, static_value_generators: impl IntoIterator Arc>)>, rust_functions: impl IntoIterator>)>, main_function: Uuid) -> Self { 88 | let (mut static_value_generators, static_value_index): (Vec<_>, HashMap<_, _>) = static_value_generators.into_iter().enumerate().map(|(i, (id, generator))| (generator, (id, u32::try_from(i).unwrap()))).unzip(); 89 | let (rust_functions, rust_function_index): (Vec<_>, HashMap<_, _>) = rust_functions.into_iter().enumerate().map(|(i, (id, function))| (function, (id, u32::try_from(i).unwrap()))).unzip(); 90 | let mut bytecodes = Vec::new(); 91 | let mut function_pointers = HashMap::new(); 92 | let mut member_name_map = HashMap::new(); 93 | let mut type_map = HashMap::new(); 94 | let mut function_references = HashMap::new(); 95 | for (function_id, function_body) in functions { 96 | function_pointers.insert(function_id, bytecodes.len()); 97 | let (bytecode, function_reference) = lir_to_bytecode(function_body, &mut member_name_map, &mut type_map, &mut static_value_generators, &static_value_index, &rust_function_index); 98 | function_references.extend(function_reference.into_iter().map(|(index, id)| (index + bytecodes.len(), id))); 99 | bytecodes.extend(bytecode); 100 | } 101 | let (function_pointers, function_pointer_reference): (Vec<_>, HashMap<_, _>) = function_pointers.into_iter().enumerate().map(|(i, (id, pointer))| (pointer, (id, u32::try_from(i).unwrap()))).unzip(); 102 | for (index, function) in function_references { 103 | let function_pointer = function_pointer_reference[&function]; 104 | let opcode = bytecodes[index].0; 105 | bytecodes[index] = KirlByteCode::new(opcode, function_pointer); 106 | } 107 | let mut member_names = member_name_map.into_iter().collect::>(); 108 | member_names.sort_unstable_by_key(|(_, index)| *index); 109 | let member_names = member_names.into_iter().map(|(name, _)| name).collect(); 110 | let mut types = type_map.into_iter().collect::>(); 111 | types.sort_unstable_by_key(|(_, index)| *index); 112 | let types = types.into_iter().map(|(ty, _)| ty).collect(); 113 | KirlVMExecutable { 114 | bytecodes, 115 | entry_point: function_pointers[function_pointer_reference[&main_function] as usize], 116 | static_value_generators, 117 | rust_functions, 118 | function_pointers, 119 | member_names, 120 | types, 121 | } 122 | } 123 | } 124 | 125 | fn lir_to_bytecode(lir: impl IntoIterator, member_name_map: &mut HashMap, type_map: &mut HashMap, static_value_generators: &mut Vec, static_value_index: &HashMap, rust_function_index: &HashMap) -> (impl IntoIterator, impl IntoIterator) { 126 | let mut result = Vec::new(); 127 | let mut label_position_map = HashMap::new(); 128 | let mut position_label_map = HashMap::new(); 129 | let mut function_pointer_map = HashMap::new(); 130 | for LIRStatement { label, instruction } in lir { 131 | if instruction == LIRInstruction::Nop && label.is_none() { 132 | continue; 133 | } 134 | if let Some(label) = label { 135 | label_position_map.insert(label, result.len()); 136 | } 137 | match instruction { 138 | LIRInstruction::LoadImmediateString(value) => { 139 | result.push(KirlByteCode::new(KirlByteCodeOpcode::LoadStaticValue, static_value_generators.len() as u32)); 140 | let value = Arc::new(RwLock::new(value)) as Arc; 141 | static_value_generators.push(Arc::new(move || Arc::clone(&value))); 142 | } 143 | LIRInstruction::LoadImmediateNumber(value) => { 144 | result.push(KirlByteCode::new(KirlByteCodeOpcode::LoadStaticValue, static_value_generators.len() as u32)); 145 | let value = Context::::default().reduce(value); 146 | let value = Arc::new(RwLock::new(value)) as Arc; 147 | static_value_generators.push(Arc::new(move || Arc::clone(&value))); 148 | } 149 | LIRInstruction::LoadNamedValue(id) => result.push(KirlByteCode::new(KirlByteCodeOpcode::LoadStaticValue, *static_value_index.get(&id).expect("TODO:"))), 150 | LIRInstruction::Load(index) => { 151 | result.push(KirlByteCode::new(KirlByteCodeOpcode::Load, index as u32)); 152 | } 153 | LIRInstruction::Store(index) => { 154 | result.push(KirlByteCode::new(KirlByteCodeOpcode::Store, index as u32)); 155 | } 156 | LIRInstruction::JumpIfTrue(label) => { 157 | position_label_map.insert(result.len(), label); 158 | result.push(KirlByteCode::without_operand(KirlByteCodeOpcode::JumpIfTrue)); 159 | } 160 | LIRInstruction::JumpIfHasType(ty, label) => { 161 | let type_map_len = type_map.len() as u32; 162 | let type_index = *type_map.entry(ty.into_normalized()).or_insert(type_map_len); 163 | result.push(KirlByteCode::new(KirlByteCodeOpcode::PushAdditionalOperand, type_index)); 164 | position_label_map.insert(result.len(), label); 165 | result.push(KirlByteCode::without_operand(KirlByteCodeOpcode::JumpIfHasType)); 166 | } 167 | LIRInstruction::Jump(label) => { 168 | position_label_map.insert(result.len(), label); 169 | result.push(KirlByteCode::without_operand(KirlByteCodeOpcode::Jump)); 170 | } 171 | LIRInstruction::CallFunction(id) => match rust_function_index.get(&id) { 172 | None => { 173 | function_pointer_map.insert(result.len(), id); 174 | result.push(KirlByteCode::without_operand(KirlByteCodeOpcode::CallKirlFunction)); 175 | } 176 | Some(index) => { 177 | result.push(KirlByteCode::new(KirlByteCodeOpcode::CallRustFunction, *index)); 178 | } 179 | }, 180 | LIRInstruction::Return => { 181 | result.push(KirlByteCode::without_operand(KirlByteCodeOpcode::Return)); 182 | } 183 | LIRInstruction::Nop => { 184 | result.push(KirlByteCode::without_operand(KirlByteCodeOpcode::Nop)); 185 | } 186 | LIRInstruction::AccessTupleItem(index) => { 187 | result.push(KirlByteCode::new(KirlByteCodeOpcode::AccessTupleItem, index as u32)); 188 | } 189 | LIRInstruction::AccessMember(member) => { 190 | let member_name_map_len = member_name_map.len() as u32; 191 | let member = *member_name_map.entry(member).or_insert(member_name_map_len); 192 | result.push(KirlByteCode::new(KirlByteCodeOpcode::AccessMember, member)); 193 | } 194 | LIRInstruction::AssignTupleItem(index) => { 195 | result.push(KirlByteCode::new(KirlByteCodeOpcode::AssignTupleItem, index as u32)); 196 | } 197 | LIRInstruction::AssignMember(member) => { 198 | let member_name_map_len = member_name_map.len() as u32; 199 | let member = *member_name_map.entry(member).or_insert(member_name_map_len); 200 | result.push(KirlByteCode::new(KirlByteCodeOpcode::AssignMember, member)); 201 | } 202 | LIRInstruction::ConstructStruct(len) => { 203 | result.push(KirlByteCode::new(KirlByteCodeOpcode::ConstructStruct, u32::try_from(len).unwrap())); 204 | } 205 | LIRInstruction::ConstructTuple(len) => { 206 | result.push(KirlByteCode::new(KirlByteCodeOpcode::ConstructTuple, u32::try_from(len).unwrap())); 207 | } 208 | LIRInstruction::ConstructArray(len) => { 209 | result.push(KirlByteCode::new(KirlByteCodeOpcode::ConstructArray, u32::try_from(len).unwrap())); 210 | } 211 | } 212 | } 213 | for (position, label) in position_label_map { 214 | let target_position = label_position_map[&label] as isize; 215 | let diff = i32::try_from(target_position - position as isize).unwrap(); 216 | let opcode = result[position].0; 217 | result[position] = KirlByteCode::new_signed(opcode, diff); 218 | } 219 | (result, function_pointer_map) 220 | } 221 | -------------------------------------------------------------------------------- /kirl_semantic_analyzer/src/name_resolver.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{BTreeMap, HashMap}; 2 | 3 | use kirl_common::typing::HIRType; 4 | use uuid::Uuid; 5 | 6 | use crate::syntax_tree_to_hir::SearchPaths; 7 | use crate::{HIRExpression, HIRStatement, ReferenceAccess, Variable}; 8 | 9 | #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Default)] 10 | pub struct ResolvedItems(pub(crate) SearchPaths, pub(crate) Vec<(Vec, Uuid, HIRType)>); 11 | 12 | pub trait KirlNameResolver { 13 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)>; 14 | } 15 | 16 | impl KirlNameResolver for &mut R { 17 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 18 | (*self).resolve(full_path) 19 | } 20 | } 21 | 22 | impl KirlNameResolver for (R1,) 23 | where 24 | R1: KirlNameResolver, 25 | { 26 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 27 | let (r1,) = self; 28 | r1.resolve(full_path) 29 | } 30 | } 31 | 32 | impl KirlNameResolver for (R1, R2) 33 | where 34 | R1: KirlNameResolver, 35 | R2: KirlNameResolver, 36 | { 37 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 38 | let (r1, r2) = self; 39 | let mut result = r1.resolve(full_path); 40 | result.extend(r2.resolve(full_path)); 41 | result 42 | } 43 | } 44 | 45 | impl KirlNameResolver for (R1, R2, R3) 46 | where 47 | R1: KirlNameResolver, 48 | R2: KirlNameResolver, 49 | R3: KirlNameResolver, 50 | { 51 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 52 | let (r1, r2, r3) = self; 53 | let mut result = r1.resolve(full_path); 54 | result.extend(r2.resolve(full_path)); 55 | result.extend(r3.resolve(full_path)); 56 | result 57 | } 58 | } 59 | 60 | impl KirlNameResolver for (R1, R2, R3, R4) 61 | where 62 | R1: KirlNameResolver, 63 | R2: KirlNameResolver, 64 | R3: KirlNameResolver, 65 | R4: KirlNameResolver, 66 | { 67 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 68 | let (r1, r2, r3, r4) = self; 69 | let mut result = r1.resolve(full_path); 70 | result.extend(r2.resolve(full_path)); 71 | result.extend(r3.resolve(full_path)); 72 | result.extend(r4.resolve(full_path)); 73 | result 74 | } 75 | } 76 | 77 | impl KirlNameResolver for (R1, R2, R3, R4, R5) 78 | where 79 | R1: KirlNameResolver, 80 | R2: KirlNameResolver, 81 | R3: KirlNameResolver, 82 | R4: KirlNameResolver, 83 | R5: KirlNameResolver, 84 | { 85 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 86 | let (r1, r2, r3, r4, r5) = self; 87 | let mut result = r1.resolve(full_path); 88 | result.extend(r2.resolve(full_path)); 89 | result.extend(r3.resolve(full_path)); 90 | result.extend(r4.resolve(full_path)); 91 | result.extend(r5.resolve(full_path)); 92 | result 93 | } 94 | } 95 | 96 | impl KirlNameResolver for [R] { 97 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 98 | self.iter_mut().flat_map(|resolver| resolver.resolve(full_path)).collect() 99 | } 100 | } 101 | 102 | impl KirlNameResolver for HashMap { 103 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 104 | full_path.first().and_then(|key| self.get_mut(key)).map(|resolver| resolver.resolve(&full_path[1..])).unwrap_or_default() 105 | } 106 | } 107 | 108 | impl KirlNameResolver for BTreeMap { 109 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 110 | full_path.first().and_then(|key| self.get_mut(key)).map(|resolver| resolver.resolve(&full_path[1..])).unwrap_or_default() 111 | } 112 | } 113 | 114 | trait Resolvable { 115 | type ResolveResult; 116 | fn resolve(self, resolver: &mut impl KirlNameResolver) -> Self::ResolveResult; 117 | fn all_reference(&self) -> Vec<&[String]>; 118 | } 119 | 120 | impl Resolvable for Vec { 121 | type ResolveResult = Vec; 122 | fn resolve(self, resolver: &mut impl KirlNameResolver) -> Self::ResolveResult { 123 | self.into_iter().map(|v| v.resolve(resolver)).collect() 124 | } 125 | 126 | fn all_reference(&self) -> Vec<&[String]> { 127 | self.iter().flat_map(Resolvable::all_reference).collect() 128 | } 129 | } 130 | 131 | impl Resolvable for (T, U) { 132 | type ResolveResult = (T::ResolveResult, U::ResolveResult); 133 | fn resolve(self, resolver: &mut impl KirlNameResolver) -> Self::ResolveResult { 134 | let (t, u) = self; 135 | (t.resolve(resolver), u.resolve(resolver)) 136 | } 137 | 138 | fn all_reference(&self) -> Vec<&[String]> { 139 | let (t, u) = self; 140 | let mut result = t.all_reference(); 141 | result.extend(u.all_reference()); 142 | result 143 | } 144 | } 145 | 146 | impl Resolvable for Variable { 147 | type ResolveResult = Variable; 148 | fn resolve(self, resolver: &mut impl KirlNameResolver) -> Self::ResolveResult { 149 | match self { 150 | Variable::Named(range, types, paths) => { 151 | let reference = ResolvedItems(paths.clone(), paths.0.into_iter().flat_map(|path| [path.clone()].into_iter().cycle().zip(resolver.resolve(&path)).map(|(path, (id, ty))| (path, id, ty))).collect()); 152 | Variable::Named(range, types, reference) 153 | } 154 | Variable::Unnamed(id) => Variable::Unnamed(id), 155 | } 156 | } 157 | 158 | fn all_reference(&self) -> Vec<&[String]> { 159 | match self { 160 | Variable::Named(_, _, SearchPaths(paths)) => paths.iter().map(Vec::as_slice).collect(), 161 | Variable::Unnamed(_) => Vec::new(), 162 | } 163 | } 164 | } 165 | 166 | impl Resolvable for ReferenceAccess { 167 | type ResolveResult = ReferenceAccess; 168 | fn resolve(self, resolver: &mut impl KirlNameResolver) -> Self::ResolveResult { 169 | match self { 170 | ReferenceAccess::Variable(variable) => ReferenceAccess::Variable(variable.resolve(resolver)), 171 | ReferenceAccess::TupleItem(variable, index) => ReferenceAccess::TupleItem(variable.resolve(resolver), index), 172 | ReferenceAccess::Member(variable, member) => ReferenceAccess::Member(variable.resolve(resolver), member), 173 | } 174 | } 175 | 176 | fn all_reference(&self) -> Vec<&[String]> { 177 | match self { 178 | ReferenceAccess::Variable(variable) => variable.all_reference(), 179 | ReferenceAccess::TupleItem(variable, _) => variable.all_reference(), 180 | ReferenceAccess::Member(variable, _) => variable.all_reference(), 181 | } 182 | } 183 | } 184 | 185 | impl Resolvable for HIRExpression { 186 | type ResolveResult = HIRExpression; 187 | fn resolve(self, resolver: &mut impl KirlNameResolver) -> Self::ResolveResult { 188 | match self { 189 | HIRExpression::Immediate(value) => HIRExpression::Immediate(value), 190 | HIRExpression::CallFunction { function, arguments } => HIRExpression::CallFunction { 191 | function: function.resolve(resolver), 192 | arguments: arguments.resolve(resolver), 193 | }, 194 | HIRExpression::AccessVariable(variable) => HIRExpression::AccessVariable(variable.resolve(resolver)), 195 | HIRExpression::AccessTupleItem { variable, index } => HIRExpression::AccessTupleItem { variable: variable.resolve(resolver), index }, 196 | HIRExpression::AccessMember { variable, member } => HIRExpression::AccessMember { variable: variable.resolve(resolver), member }, 197 | HIRExpression::If { condition, then, other } => HIRExpression::If { 198 | condition: condition.resolve(resolver), 199 | then: then.resolve(resolver), 200 | other: other.resolve(resolver), 201 | }, 202 | HIRExpression::IfLet { condition_binding, pattern_type, condition, then, other } => HIRExpression::IfLet { 203 | condition_binding, 204 | pattern_type, 205 | condition: condition.resolve(resolver), 206 | then: then.resolve(resolver), 207 | other: other.resolve(resolver), 208 | }, 209 | HIRExpression::Loop(statements) => HIRExpression::Loop(statements.resolve(resolver)), 210 | HIRExpression::Assign { variable, value } => HIRExpression::Assign { variable: variable.resolve(resolver), value: value.resolve(resolver) }, 211 | HIRExpression::ConstructStruct(members) => HIRExpression::ConstructStruct(members.into_iter().map(|(k, v)| (k, v.resolve(resolver))).collect()), 212 | HIRExpression::ConstructTuple(members) => HIRExpression::ConstructTuple(members.resolve(resolver)), 213 | HIRExpression::ConstructArray(members) => HIRExpression::ConstructArray(members.resolve(resolver)), 214 | } 215 | } 216 | 217 | fn all_reference(&self) -> Vec<&[String]> { 218 | match self { 219 | HIRExpression::Immediate(_) => Vec::new(), 220 | HIRExpression::CallFunction { function, arguments } => { 221 | let mut result = function.all_reference(); 222 | result.extend(arguments.all_reference()); 223 | result 224 | } 225 | HIRExpression::AccessVariable(variable) => variable.all_reference(), 226 | HIRExpression::AccessTupleItem { variable, .. } => variable.all_reference(), 227 | HIRExpression::AccessMember { variable, .. } => variable.all_reference(), 228 | HIRExpression::If { condition, then, other } => { 229 | let mut result = condition.all_reference(); 230 | result.extend(then.all_reference()); 231 | result.extend(other.all_reference()); 232 | result 233 | } 234 | HIRExpression::IfLet { condition, then, other, .. } => { 235 | let mut result = condition.all_reference(); 236 | result.extend(then.all_reference()); 237 | result.extend(other.all_reference()); 238 | result 239 | } 240 | HIRExpression::Loop(statements) => statements.all_reference(), 241 | HIRExpression::Assign { variable, value } => { 242 | let mut result = variable.all_reference(); 243 | result.extend(value.all_reference()); 244 | result 245 | } 246 | HIRExpression::ConstructStruct(members) => members.values().flat_map(Resolvable::all_reference).collect(), 247 | HIRExpression::ConstructTuple(items) => items.all_reference(), 248 | HIRExpression::ConstructArray(items) => items.all_reference(), 249 | } 250 | } 251 | } 252 | 253 | impl Resolvable for HIRStatement { 254 | type ResolveResult = HIRStatement; 255 | fn resolve(self, resolver: &mut impl KirlNameResolver) -> Self::ResolveResult { 256 | match self { 257 | HIRStatement::Binding { variable_id, variable_type, expression } => HIRStatement::Binding { variable_id, variable_type, expression: expression.resolve(resolver) }, 258 | HIRStatement::Unreachable => HIRStatement::Unreachable, 259 | HIRStatement::Return(value) => HIRStatement::Return(value.resolve(resolver)), 260 | HIRStatement::Continue(label) => HIRStatement::Continue(label), 261 | HIRStatement::Break(label) => HIRStatement::Break(label), 262 | } 263 | } 264 | 265 | fn all_reference(&self) -> Vec<&[String]> { 266 | match self { 267 | HIRStatement::Binding { expression, .. } => expression.all_reference(), 268 | HIRStatement::Unreachable => Vec::new(), 269 | HIRStatement::Return(value) => value.all_reference(), 270 | HIRStatement::Continue(_) => Vec::new(), 271 | HIRStatement::Break(_) => Vec::new(), 272 | } 273 | } 274 | } 275 | 276 | pub fn resolve_statements(statements: Vec>, resolver: &mut impl KirlNameResolver) -> Vec> { 277 | statements.resolve(resolver) 278 | } 279 | 280 | pub fn statement_references(statements: &Vec>) -> Vec<&[String]> { 281 | statements.all_reference() 282 | } 283 | -------------------------------------------------------------------------------- /kirl_vm/src/lir.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | use std::error::Error; 3 | use std::fmt::{Display, Formatter}; 4 | 5 | use kirl_common::dec::Decimal128; 6 | use kirl_common::typing::{HIRType, LIRType, LIRTypeConvertError}; 7 | use uuid::Uuid; 8 | 9 | use kirl_semantic_analyzer::{HIRExpression, HIRStatement, Immediate, ReferenceAccess, Variable}; 10 | 11 | #[derive(Debug, Clone, PartialEq)] 12 | pub struct LIRStatementList(pub Vec); 13 | 14 | impl From> for LIRStatementList { 15 | fn from(value: Vec) -> Self { 16 | LIRStatementList(value) 17 | } 18 | } 19 | 20 | impl From for Vec { 21 | fn from(value: LIRStatementList) -> Self { 22 | value.0 23 | } 24 | } 25 | 26 | #[derive(Debug, Clone, PartialEq)] 27 | pub struct LIRStatement { 28 | pub(crate) label: Option, 29 | pub(crate) instruction: LIRInstruction, 30 | } 31 | 32 | impl From for LIRStatement { 33 | fn from(instruction: LIRInstruction) -> Self { 34 | LIRStatement { label: None, instruction } 35 | } 36 | } 37 | 38 | #[derive(Debug, Clone, PartialEq)] 39 | pub enum LIRInstruction { 40 | LoadImmediateString(String), 41 | LoadImmediateNumber(Decimal128), 42 | LoadNamedValue(Uuid), 43 | Load(usize), 44 | Store(usize), 45 | JumpIfTrue(String), 46 | JumpIfHasType(LIRType, String), 47 | Jump(String), 48 | CallFunction(Uuid), 49 | Return, 50 | Nop, 51 | AccessMember(String), 52 | AccessTupleItem(usize), 53 | AssignMember(String), 54 | AssignTupleItem(usize), 55 | ConstructStruct(usize), 56 | ConstructTuple(usize), 57 | ConstructArray(usize), 58 | } 59 | 60 | #[derive(Debug)] 61 | pub enum LIRStatementListConvertError { 62 | TypeConvertError(LIRTypeConvertError), 63 | UnexpectedBreak, 64 | UnexpectedContinue, 65 | } 66 | 67 | impl Display for LIRStatementListConvertError { 68 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 69 | match self { 70 | LIRStatementListConvertError::TypeConvertError(e) => e.fmt(f), 71 | LIRStatementListConvertError::UnexpectedBreak => write!(f, "Unexpected break."), 72 | LIRStatementListConvertError::UnexpectedContinue => write!(f, "Unexpected continue."), 73 | } 74 | } 75 | } 76 | 77 | impl Error for LIRStatementListConvertError { 78 | fn source(&self) -> Option<&(dyn Error + 'static)> { 79 | match self { 80 | LIRStatementListConvertError::TypeConvertError(e) => Some(e), 81 | LIRStatementListConvertError::UnexpectedBreak => None, 82 | LIRStatementListConvertError::UnexpectedContinue => None, 83 | } 84 | } 85 | } 86 | 87 | impl From for LIRStatementListConvertError { 88 | fn from(e: LIRTypeConvertError) -> Self { 89 | LIRStatementListConvertError::TypeConvertError(e) 90 | } 91 | } 92 | 93 | pub fn hir_to_lir(statements: Vec>, argument_count: usize) -> Result { 94 | fn convert_list(statements: impl IntoIterator>, result: &mut Vec, sequence: &mut usize, loop_labels: &mut Vec) -> Result<(), LIRStatementListConvertError> { 95 | fn convert(statement: HIRStatement<(Uuid, HIRType)>, result: &mut Vec, sequence: &mut usize, loop_labels: &mut Vec) -> Result<(), LIRStatementListConvertError> { 96 | fn push_variable(variable: Variable<(Uuid, HIRType)>, result: &mut Vec) { 97 | match variable { 98 | Variable::Named(_, _, (id, _)) => result.push(LIRInstruction::LoadNamedValue(id).into()), 99 | Variable::Unnamed(id) => result.push(LIRInstruction::Load(id).into()), 100 | } 101 | } 102 | match statement { 103 | HIRStatement::Binding { variable_id, expression, .. } => { 104 | match expression { 105 | HIRExpression::Immediate(value) => match value { 106 | Immediate::Number(value) => result.push(LIRInstruction::LoadImmediateNumber(value).into()), 107 | Immediate::String(value) => result.push(LIRInstruction::LoadImmediateString(value).into()), 108 | }, 109 | HIRExpression::CallFunction { function, arguments } => { 110 | let function = match function { 111 | Variable::Named(_, _, (id, _)) => id, 112 | Variable::Unnamed(_) => todo!(), 113 | }; 114 | for variable in arguments.into_iter().rev() { 115 | push_variable(variable, result); 116 | } 117 | result.push(LIRInstruction::CallFunction(function).into()); 118 | } 119 | HIRExpression::AccessVariable(variable) => { 120 | push_variable(variable, result); 121 | } 122 | HIRExpression::AccessTupleItem { variable, index } => { 123 | push_variable(variable, result); 124 | result.push(LIRInstruction::AccessTupleItem(index).into()); 125 | } 126 | HIRExpression::AccessMember { variable, member } => { 127 | push_variable(variable, result); 128 | result.push(LIRInstruction::AccessMember(member).into()); 129 | } 130 | HIRExpression::If { 131 | condition, 132 | then: (then_statements, then_result), 133 | other: (other_statements, other_result), 134 | } => { 135 | push_variable(condition, result); 136 | let then_label = format!("$if_then_{}", *sequence); 137 | let end_label = format!("$if_end_{}", *sequence); 138 | *sequence += 1; 139 | result.push(LIRInstruction::JumpIfTrue(then_label.clone()).into()); 140 | convert_list(other_statements, result, sequence, loop_labels)?; 141 | push_variable(other_result, result); 142 | result.push(LIRInstruction::Jump(end_label.clone()).into()); 143 | result.push(LIRStatement { label: Some(then_label), instruction: LIRInstruction::Nop }); 144 | convert_list(then_statements, result, sequence, loop_labels)?; 145 | push_variable(then_result, result); 146 | result.push(LIRStatement { label: Some(end_label), instruction: LIRInstruction::Nop }); 147 | } 148 | HIRExpression::IfLet { 149 | condition_binding, 150 | pattern_type, 151 | condition, 152 | then: (then_statements, then_result), 153 | other: (other_statements, other_result), 154 | } => { 155 | push_variable(condition, result); 156 | let then_label = format!("$if_then_{}", *sequence); 157 | let end_label = format!("$if_end_{}", *sequence); 158 | *sequence += 1; 159 | result.push(LIRInstruction::JumpIfHasType(pattern_type.try_into()?, then_label.clone()).into()); 160 | convert_list(other_statements, result, sequence, loop_labels)?; 161 | push_variable(other_result, result); 162 | result.push(LIRInstruction::Jump(end_label.clone()).into()); 163 | result.push(LIRStatement { 164 | label: Some(then_label), 165 | instruction: LIRInstruction::Store(condition_binding), 166 | }); 167 | convert_list(then_statements, result, sequence, loop_labels)?; 168 | push_variable(then_result, result); 169 | result.push(LIRStatement { label: Some(end_label), instruction: LIRInstruction::Nop }); 170 | } 171 | HIRExpression::Loop(inner) => { 172 | let label = format!("$loop_anonymous_{}", *sequence); 173 | let label_begin = format!("{}_begin", label); 174 | let label_end = format!("{}_end", label); 175 | loop_labels.push(label); 176 | *sequence += 1; 177 | result.push(LIRStatement { label: Some(label_begin.clone()), instruction: LIRInstruction::Nop }); 178 | convert_list(inner, result, sequence, loop_labels)?; 179 | result.push(LIRInstruction::Jump(label_begin).into()); 180 | result.push(LIRStatement { label: Some(label_end), instruction: LIRInstruction::Nop }); 181 | } 182 | HIRExpression::Assign { variable, value } => { 183 | push_variable(value.clone(), result); 184 | match variable { 185 | ReferenceAccess::Variable(dest) => { 186 | push_variable(value, result); 187 | match dest { 188 | Variable::Named(_, _, _) => todo!(), 189 | Variable::Unnamed(dest) => result.push(LIRInstruction::Store(dest).into()), 190 | } 191 | } 192 | ReferenceAccess::TupleItem(dest_variable, dest_index) => { 193 | push_variable(dest_variable, result); 194 | push_variable(value, result); 195 | result.push(LIRInstruction::AssignTupleItem(dest_index).into()); 196 | } 197 | ReferenceAccess::Member(dest_variable, dest_member) => { 198 | push_variable(dest_variable, result); 199 | push_variable(value, result); 200 | result.push(LIRInstruction::AssignMember(dest_member).into()); 201 | } 202 | } 203 | } 204 | HIRExpression::ConstructStruct(members) => { 205 | let len = members.len(); 206 | for (member, value) in members { 207 | push_variable(value, result); 208 | result.push(LIRInstruction::LoadImmediateString(member).into()); 209 | } 210 | result.push(LIRInstruction::ConstructStruct(len).into()); 211 | } 212 | HIRExpression::ConstructTuple(items) => { 213 | let len = items.len(); 214 | for item in items.into_iter().rev() { 215 | push_variable(item, result); 216 | } 217 | result.push(LIRInstruction::ConstructTuple(len).into()); 218 | } 219 | HIRExpression::ConstructArray(items) => { 220 | let len = items.len(); 221 | for item in items.into_iter().rev() { 222 | push_variable(item, result); 223 | } 224 | result.push(LIRInstruction::ConstructArray(len).into()); 225 | } 226 | } 227 | result.push(LIRInstruction::Store(variable_id).into()); 228 | } 229 | HIRStatement::Unreachable => {} 230 | HIRStatement::Return(value) => { 231 | push_variable(value, result); 232 | result.push(LIRInstruction::Return.into()); 233 | } 234 | HIRStatement::Continue(label) => { 235 | if let Some(label) = label.as_ref().or_else(|| loop_labels.last()) { 236 | result.push(LIRInstruction::Jump(format!("{}_begin", label)).into()); 237 | } else { 238 | return Err(LIRStatementListConvertError::UnexpectedContinue); 239 | } 240 | } 241 | HIRStatement::Break(label) => { 242 | result.push(LIRInstruction::ConstructTuple(0).into()); //TODO:loop式とかで値を持ってbreakするときに変える 243 | if let Some(label) = label.as_ref().or_else(|| loop_labels.last()) { 244 | result.push(LIRInstruction::Jump(format!("{}_end", label)).into()); 245 | } else { 246 | return Err(LIRStatementListConvertError::UnexpectedBreak); 247 | } 248 | } 249 | } 250 | Ok(()) 251 | } 252 | for statement in statements { 253 | convert(statement, result, sequence, loop_labels)?; 254 | } 255 | Ok(()) 256 | } 257 | let mut result = Vec::new(); 258 | for i in 0..argument_count { 259 | result.push(LIRInstruction::Store(i).into()); 260 | } 261 | let mut loop_labels = Vec::new(); 262 | convert_list(statements, &mut result, &mut 0, &mut loop_labels)?; 263 | result.push(LIRInstruction::ConstructTuple(0).into()); 264 | result.push(LIRInstruction::Return.into()); 265 | Ok(result.into()) 266 | } 267 | -------------------------------------------------------------------------------- /kirl_parser/src/kirl_parser/tests.rs: -------------------------------------------------------------------------------- 1 | use parser::Parse; 2 | use tokenizer::Tokenize; 3 | 4 | use crate::kirl_parser::{get_parser, AnonymousStructType, Block, Condition, ConstructStruct, Expression, ExpressionItem, Function, If, KirlTopLevelStatement, LetBinding, NamedType, Path, Pattern, Statement, StatementItem, StructName, Symbol, Type}; 5 | use crate::kirl_tokenizer::get_tokenizer; 6 | use crate::{CharacterPosition, KirlParser}; 7 | use kirl_common::dec::Decimal128; 8 | 9 | #[test] 10 | fn test_parse() { 11 | KirlParser::new(); 12 | let tokenizer = get_tokenizer(); 13 | let parser = get_parser(); 14 | const CODE: &str = r#" 15 | import std::println; 16 | 17 | fn my_function(value_a: int)-> #{value_a: int, value_b: string} { 18 | if value_a > 100 { 19 | #{value_a, value_b: "big"} 20 | } else { 21 | var value_c: int = value_a * 2; 22 | #{value_a: value_c, value_b: "small" } 23 | } 24 | } 25 | 26 | fn my_function(self: #{value_a: int, value_b: (int | string) }){ 27 | if var value_b: int = self.value_b { 28 | println(value_b); 29 | } else { 30 | println("not integer"); 31 | } 32 | } 33 | 34 | fn my_function2(#{value_a: a, value_b }: #{value_a: int, value_b: (int, string,) }){ 35 | var (n, s) = value_b; 36 | var n = (n, s,).0th; 37 | (a + n).println(); 38 | } 39 | 40 | fn get_closure(ratio: int)->([int])->int |-> 41 | fn: i: [int] |-> i.sum() * ratio; 42 | 43 | fn to_string::(obj: #{number: int, value: T}) -> #{number: string, value: T} { 44 | var #{number, value} = obj; 45 | #{number: number.to_string(), value} 46 | } 47 | println("Hello, World!"); 48 | var #{value_a, value_b} = my_function(10); 49 | #{value_a, value_b}.my_function(); 50 | 51 | a:while true { 52 | if value_a > 10 { 53 | break a; 54 | } else { 55 | continue a; 56 | } 57 | } 58 | 59 | struct MyStruct:: { 60 | value_a: [T], 61 | value_b: string 62 | } 63 | 64 | std::test::new(); 65 | std::test::new(a); 66 | std::test::new(a,); 67 | std::test::new(a, b); 68 | std::test::new(a, b,); 69 | 70 | std::test::new(); 71 | std::test::new::<>(); 72 | std::test::new::(); 73 | std::test::new::(); 74 | std::test::new::(); 75 | std::test::new::(); 76 | 77 | a.std::test::new(); 78 | a.std::test::new(a); 79 | a.std::test::new(a,); 80 | a.std::test::new(a, b); 81 | a.std::test::new(a, b,); 82 | 83 | a.std::test::new(); 84 | a.std::test::new::<>(); 85 | a.std::test::new::(); 86 | a.std::test::new::(); 87 | a.std::test::new::(); 88 | a.std::test::new::(); 89 | 90 | a.(); 91 | a.(a); 92 | a.(a,); 93 | a.(a, b); 94 | a.(a, b,); 95 | 96 | "#; 97 | let parse = |code: &str| { 98 | code.chars() 99 | .scan(CharacterPosition::zero(), |position, c| { 100 | let current_position = *position; 101 | *position = match c { 102 | '\n' => position.next_line(), 103 | _ => position.next(), 104 | }; 105 | Some((current_position, c)) 106 | }) 107 | .tokenize_with(&tokenizer, |(_, c)| *c) 108 | .flat_map(|token| token.unwrap()) 109 | .parse(&parser) 110 | }; 111 | if let Err(err) = parse(CODE) { 112 | unreachable!("failed to parse {:?} by {:?}", CODE, err); 113 | } 114 | const CODE_1: &str = r#"fn my_function(value_a: int)-> #{value_a: int, value_b: string} { 115 | if value_a > 100 { 116 | #{value_a, value_b: "big"} 117 | } else { 118 | var value_c: int = value_a * 2; 119 | #{value_a: value_c, value_b: "small" } 120 | } 121 | }"#; 122 | assert_eq!( 123 | parse(CODE_1).unwrap(), 124 | Symbol::ValidKirlCode(( 125 | CharacterPosition::new(0, 0)..CharacterPosition::new(7, 1), 126 | vec![KirlTopLevelStatement::FunctionDefinition(( 127 | CharacterPosition::new(0, 0)..CharacterPosition::new(7, 1), 128 | Function { 129 | position: CharacterPosition::new(0, 0)..CharacterPosition::new(7, 1), 130 | name: "my_function".to_owned(), 131 | generics_arguments: vec![], 132 | arguments: vec![( 133 | Pattern::Variable("value_a".to_owned()), 134 | Type::NamedType(NamedType { 135 | position: CharacterPosition::new(0, 24)..CharacterPosition::new(0, 27), 136 | path: vec!["int".to_owned()], 137 | generics_arguments: vec![], 138 | }), 139 | ),], 140 | return_type: Type::AnonymousStruct(AnonymousStructType { 141 | position: CharacterPosition::new(0, 31)..CharacterPosition::new(0, 63), 142 | members: vec![ 143 | ( 144 | "value_a".to_owned(), 145 | Type::NamedType(NamedType { 146 | position: CharacterPosition::new(0, 42)..CharacterPosition::new(0, 45), 147 | path: vec!["int".to_owned()], 148 | generics_arguments: vec![], 149 | }), 150 | ), 151 | ( 152 | "value_b".to_owned(), 153 | Type::NamedType(NamedType { 154 | position: CharacterPosition::new(0, 56)..CharacterPosition::new(0, 62), 155 | path: vec!["string".to_owned()], 156 | generics_arguments: vec![], 157 | }), 158 | ), 159 | ], 160 | },), 161 | expression: Expression { 162 | position: CharacterPosition::new(0, 64)..CharacterPosition::new(7, 1), 163 | expression: ExpressionItem::Block(Block { 164 | position: CharacterPosition::new(0, 64)..CharacterPosition::new(7, 1), 165 | statements: vec![], 166 | last_expression: Some( 167 | Expression { 168 | position: CharacterPosition::new(1, 4)..CharacterPosition::new(6, 5), 169 | expression: ExpressionItem::If(If { 170 | position: CharacterPosition::new(1, 4)..CharacterPosition::new(6, 5), 171 | condition: Condition::BoolExpression(Expression { 172 | position: CharacterPosition::new(1, 7)..CharacterPosition::new(1, 20), 173 | expression: ExpressionItem::GreaterThan( 174 | Expression { 175 | position: CharacterPosition::new(1, 7)..CharacterPosition::new(1, 14), 176 | expression: ExpressionItem::AccessVariable( 177 | Path { 178 | position: CharacterPosition::new(1, 7)..CharacterPosition::new(1, 14), 179 | path: vec!["value_a".to_owned()], 180 | }, 181 | Vec::new() 182 | ), 183 | } 184 | .into(), 185 | Expression { 186 | position: CharacterPosition::new(1, 17)..CharacterPosition::new(1, 20), 187 | expression: ExpressionItem::NumberImmediate(Decimal128::from(100)), 188 | } 189 | .into(), 190 | ), 191 | }) 192 | .into(), 193 | then: Expression { 194 | position: CharacterPosition::new(1, 21)..CharacterPosition::new(3, 5), 195 | expression: ExpressionItem::Block(Block { 196 | position: CharacterPosition::new(1, 21)..CharacterPosition::new(3, 5), 197 | statements: vec![], 198 | last_expression: Some( 199 | Expression { 200 | position: CharacterPosition::new(2, 8)..CharacterPosition::new(2, 34), 201 | expression: ExpressionItem::ConstructStruct(ConstructStruct { 202 | name: StructName::Anonymous, 203 | items: vec![ 204 | ( 205 | "value_a".to_owned(), 206 | Expression { 207 | position: CharacterPosition::new(2, 10)..CharacterPosition::new(2, 17), 208 | expression: ExpressionItem::AccessVariable( 209 | Path { 210 | position: CharacterPosition::new(2, 10)..CharacterPosition::new(2, 17), 211 | path: vec!["value_a".to_owned()], 212 | }, 213 | Vec::new() 214 | ), 215 | }, 216 | ), 217 | ( 218 | "value_b".to_owned(), 219 | Expression { 220 | position: CharacterPosition::new(2, 28)..CharacterPosition::new(2, 33), 221 | expression: ExpressionItem::StringImmediate("big".to_owned()), 222 | }, 223 | ), 224 | ], 225 | }), 226 | } 227 | .into() 228 | ), 229 | }), 230 | } 231 | .into(), 232 | other: Some( 233 | Expression { 234 | position: CharacterPosition::new(3, 11)..CharacterPosition::new(6, 5), 235 | expression: ExpressionItem::Block(Block { 236 | position: CharacterPosition::new(3, 11)..CharacterPosition::new(6, 5), 237 | statements: vec![Statement { 238 | position: CharacterPosition::new(4, 8)..CharacterPosition::new(4, 39), 239 | statement: StatementItem::LetBinding(LetBinding { 240 | position: CharacterPosition::new(4, 8)..CharacterPosition::new(4, 38), 241 | pattern: Pattern::Variable("value_c".to_owned()), 242 | type_hint: Some(Type::NamedType(NamedType { 243 | position: CharacterPosition::new(4, 21)..CharacterPosition::new(4, 24), 244 | path: vec!["int".to_owned()], 245 | generics_arguments: vec![], 246 | })), 247 | expression: Box::new(Expression { 248 | position: CharacterPosition::new(4, 27)..CharacterPosition::new(4, 38), 249 | expression: ExpressionItem::Mul( 250 | Expression { 251 | position: CharacterPosition::new(4, 27)..CharacterPosition::new(4, 34), 252 | expression: ExpressionItem::AccessVariable( 253 | Path { 254 | position: CharacterPosition::new(4, 27)..CharacterPosition::new(4, 34), 255 | path: vec!["value_a".to_owned()], 256 | }, 257 | Vec::new() 258 | ), 259 | } 260 | .into(), 261 | Expression { 262 | position: CharacterPosition::new(4, 37)..CharacterPosition::new(4, 38), 263 | expression: ExpressionItem::NumberImmediate(Decimal128::from(2)), 264 | } 265 | .into(), 266 | ), 267 | }), 268 | }), 269 | },], 270 | last_expression: Some( 271 | Expression { 272 | position: CharacterPosition::new(5, 8)..CharacterPosition::new(5, 46), 273 | expression: ExpressionItem::ConstructStruct(ConstructStruct { 274 | name: StructName::Anonymous, 275 | items: vec![ 276 | ( 277 | "value_a".to_owned(), 278 | Expression { 279 | position: CharacterPosition::new(5, 19)..CharacterPosition::new(5, 26), 280 | expression: ExpressionItem::AccessVariable( 281 | Path { 282 | position: CharacterPosition::new(5, 19)..CharacterPosition::new(5, 26), 283 | path: vec!["value_c".to_owned()], 284 | }, 285 | Vec::new() 286 | ), 287 | }, 288 | ), 289 | ( 290 | "value_b".to_owned(), 291 | Expression { 292 | position: CharacterPosition::new(5, 37)..CharacterPosition::new(5, 44), 293 | expression: ExpressionItem::StringImmediate("small".to_owned()), 294 | }, 295 | ), 296 | ], 297 | }), 298 | } 299 | .into(), 300 | ), 301 | }), 302 | } 303 | .into() 304 | ), 305 | }), 306 | } 307 | .into() 308 | ), 309 | }), 310 | }, 311 | }, 312 | )),], 313 | )) 314 | ); 315 | } 316 | -------------------------------------------------------------------------------- /kirl_stdlib/src/lib.rs: -------------------------------------------------------------------------------- 1 | use kirl_common::dec::Decimal128; 2 | use kirl_common::interface::{FunctionWrapper, InterchangeKirlVMValue, KirlRustFunction, KirlVMValue, KirlVMValueLock}; 3 | use kirl_common::typing::{HIRType, LIRType}; 4 | use kirl_common::{dec, get_type}; 5 | use kirl_common_macro::kirl_function; 6 | use once_cell::sync::Lazy; 7 | use regex::Regex; 8 | use std::borrow::Cow; 9 | use std::collections::HashMap; 10 | use std::error::Error; 11 | use std::fmt::{Debug, Display, Formatter}; 12 | use std::io; 13 | use std::io::Read; 14 | use std::sync::{Arc, Mutex, RwLock}; 15 | use uuid::Uuid; 16 | 17 | use kirl_semantic_analyzer::name_resolver::KirlNameResolver; 18 | 19 | pub enum FunctionOrChildren { 20 | Function(Arc>, Uuid, HIRType), 21 | StaticValue(Arc Arc + Send + Sync>, Uuid, HIRType), 22 | Children(HashMap>), 23 | } 24 | 25 | impl Debug for FunctionOrChildren { 26 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 27 | match self { 28 | FunctionOrChildren::Function(_, id, ty) => write!(f, "{}: {:?}", id, ty), 29 | FunctionOrChildren::StaticValue(_, id, ty) => write!(f, "{}: {:?}", id, ty), 30 | FunctionOrChildren::Children(children) => write!(f, "{:?}", children), 31 | } 32 | } 33 | } 34 | 35 | impl FunctionOrChildren { 36 | fn from_function(f: F) -> Self { 37 | FunctionOrChildren::Function(Arc::new(Mutex::new(f)), Uuid::new_v4(), F::static_type().into_owned()) 38 | } 39 | 40 | fn static_value Value + Send + Sync, Value: KirlVMValue>(f: F) -> Self { 41 | FunctionOrChildren::StaticValue(Arc::new(move || Arc::new(RwLock::new(f()))), Uuid::new_v4(), Value::static_type().into_owned().into()) 42 | } 43 | } 44 | 45 | impl From>> for FunctionOrChildren { 46 | fn from(value: HashMap>) -> Self { 47 | FunctionOrChildren::Children(value) 48 | } 49 | } 50 | 51 | #[derive(Debug)] 52 | pub struct KirlStdLib(HashMap>); 53 | 54 | impl<'a> KirlNameResolver for &'a FunctionOrChildren { 55 | fn resolve(&mut self, full_path: &[String]) -> Vec<(uuid::Uuid, HIRType)> { 56 | match self { 57 | FunctionOrChildren::Function(_, id, ty) | FunctionOrChildren::StaticValue(_, id, ty) => { 58 | if full_path.is_empty() { 59 | vec![(*id, ty.clone())] 60 | } else { 61 | Vec::new() 62 | } 63 | } 64 | FunctionOrChildren::Children(children) => resolve_ref(children, full_path), 65 | } 66 | } 67 | } 68 | 69 | impl<'a> KirlNameResolver for &'a KirlStdLib { 70 | fn resolve(&mut self, full_path: &[String]) -> Vec<(Uuid, HIRType)> { 71 | resolve_ref(&self.0, full_path) 72 | } 73 | } 74 | 75 | fn resolve_ref(map: &HashMap>, full_path: &[String]) -> Vec<(uuid::Uuid, HIRType)> { 76 | full_path.first().and_then(|key| map.get(key)).into_iter().flatten().flat_map(|mut resolver| resolver.resolve(&full_path[1..])).collect() 77 | } 78 | 79 | struct KirlStdLibFunctions<'a> { 80 | functions: Vec<(Uuid, Arc>)>, 81 | maps: Vec<&'a HashMap>>, 82 | } 83 | 84 | impl<'a> Iterator for KirlStdLibFunctions<'a> { 85 | type Item = (Uuid, Arc>); 86 | 87 | fn next(&mut self) -> Option { 88 | let KirlStdLibFunctions { functions, maps } = self; 89 | loop { 90 | if let Some(function) = functions.pop() { 91 | break Some(function); 92 | } 93 | if let Some(map) = maps.pop() { 94 | for children in map.values().flatten() { 95 | match children { 96 | FunctionOrChildren::Function(function, id, _) => functions.push((*id, Arc::clone(function))), 97 | FunctionOrChildren::Children(children) => maps.push(children), 98 | FunctionOrChildren::StaticValue(_, _, _) => {} 99 | } 100 | } 101 | } else { 102 | break None; 103 | } 104 | } 105 | } 106 | } 107 | 108 | struct KirlStdLibStaticValues<'a> { 109 | values: Vec<(Uuid, Arc Arc>)>, 110 | maps: Vec<&'a HashMap>>, 111 | } 112 | 113 | impl<'a> Iterator for KirlStdLibStaticValues<'a> { 114 | type Item = (Uuid, Arc Arc>); 115 | 116 | fn next(&mut self) -> Option { 117 | let KirlStdLibStaticValues { values, maps } = self; 118 | loop { 119 | if let Some(function) = values.pop() { 120 | break Some(function); 121 | } 122 | if let Some(map) = maps.pop() { 123 | for children in map.values().flatten() { 124 | match children { 125 | FunctionOrChildren::StaticValue(value, id, _) => values.push((*id, Arc::clone(value) as Arc Arc>)), 126 | FunctionOrChildren::Children(children) => maps.push(children), 127 | FunctionOrChildren::Function(_, _, _) => {} 128 | } 129 | } 130 | } else { 131 | break None; 132 | } 133 | } 134 | } 135 | } 136 | 137 | impl KirlStdLib { 138 | pub fn functions(&self) -> impl IntoIterator>)> + '_ { 139 | KirlStdLibFunctions { functions: Vec::new(), maps: vec![&self.0] } 140 | } 141 | 142 | pub fn static_values(&self) -> impl IntoIterator Arc>)> + '_ { 143 | KirlStdLibStaticValues { values: Vec::new(), maps: vec![&self.0] } 144 | } 145 | } 146 | 147 | macro_rules! count { 148 | ()=>{ 0 }; 149 | ($t:ident)=>{ 1 }; 150 | ($f:ident,$($t:ident),*)=>{ 1 + count!($($t),*) }; 151 | } 152 | 153 | macro_rules! map { 154 | ($($name:ident : $value:expr),* $(,)?)=>{ 155 | { 156 | let mut result = std::collections::HashMap::>::with_capacity(count!($($name),*)); 157 | $( 158 | result.entry(std::string::String::from(stringify!($name))) 159 | .or_default() 160 | .push(($value).into()); 161 | )* 162 | result.shrink_to_fit(); 163 | result 164 | } 165 | } 166 | } 167 | 168 | #[derive(Debug)] 169 | struct NoneError; 170 | 171 | impl Display for NoneError { 172 | fn fmt(&self, _: &mut Formatter<'_>) -> std::fmt::Result { 173 | unreachable!("Errorを返すことが無い場合にNoneError型を使いましょう") 174 | } 175 | } 176 | 177 | impl Error for NoneError {} 178 | 179 | static STDLIB: Lazy = Lazy::new(|| { 180 | KirlStdLib(map! { 181 | io: map! { 182 | print: FunctionOrChildren::from_function({ 183 | #[kirl_function((String)->())] 184 | fn string_print(s: Arc>) { 185 | print!("{}", s.read().unwrap()); 186 | } 187 | string_print::new() 188 | }), 189 | print: FunctionOrChildren::from_function(FunctionWrapper::from(|s: Decimal128| Ok::<_, NoneError>(print!("{}", s.to_standard_notation_string())))), 190 | print: FunctionOrChildren::from_function(FunctionWrapper::from(|s: bool| Ok::<_, NoneError>(print!("{}", s)))), 191 | println: FunctionOrChildren::from_function({ 192 | #[kirl_function((String)->())] 193 | fn string_println(s: Arc>){ 194 | println!("{}", s.read().unwrap()); 195 | } 196 | string_println::new() 197 | }), 198 | println: FunctionOrChildren::from_function(FunctionWrapper::from(|s: Decimal128| Ok::<_, NoneError>(println!("{}", s.to_standard_notation_string())))), 199 | println: FunctionOrChildren::from_function(FunctionWrapper::from(|s: bool| Ok::<_, NoneError>(println!("{}", s)))), 200 | stdin: map! { 201 | read_line: FunctionOrChildren::from_function({ 202 | #[kirl_function(()->String)] 203 | fn stdin_read_line() -> Result { 204 | let mut result = String::new(); 205 | io::stdin().read_line(&mut result)?; 206 | Ok(result) 207 | } 208 | stdin_read_line::new() 209 | }), 210 | read_all: FunctionOrChildren::from_function({ 211 | #[kirl_function(()->String)] 212 | fn stdin_read_all() -> Result { 213 | let mut result = String::new(); 214 | io::stdin().read_to_string(&mut result)?; 215 | Ok(result) 216 | } 217 | stdin_read_all::new() 218 | }) , 219 | }, 220 | }, 221 | bool: map!{ 222 | _not: FunctionOrChildren::from_function(FunctionWrapper::from(|a: bool| Ok::<_, NoneError>(!a))), 223 | _or: FunctionOrChildren::from_function(FunctionWrapper::from(|a: bool, b: bool| Ok::<_, NoneError>(a | b))), 224 | _and: FunctionOrChildren::from_function(FunctionWrapper::from(|a: bool, b: bool| Ok::<_, NoneError>(a & b))), 225 | _xor: FunctionOrChildren::from_function(FunctionWrapper::from(|a: bool, b: bool| Ok::<_, NoneError>(a ^ b))), 226 | _eq: FunctionOrChildren::from_function(FunctionWrapper::from(|a: bool, b: bool| Ok::<_, NoneError>(a == b))), 227 | true: FunctionOrChildren::static_value(||true), 228 | false: FunctionOrChildren::static_value(||false), 229 | to_string: FunctionOrChildren::from_function(FunctionWrapper::from(|a: bool| Ok::<_, NoneError>(a.to_string()))), 230 | }, 231 | num: map! { 232 | _add: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128, b: Decimal128| Ok::<_, NoneError>(a + b))), 233 | _sub: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128, b: Decimal128| Ok::<_, NoneError>(a - b))), 234 | _mul: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128, b: Decimal128| Ok::<_, NoneError>(a * b))), 235 | _div: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128, b: Decimal128| Ok::<_, NoneError>(a / b))), 236 | _rem: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128, b: Decimal128| Ok::<_, NoneError>(a % b))), 237 | _eq: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128, b: Decimal128| Ok::<_, NoneError>(a == b))), 238 | _gt: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128, b: Decimal128| Ok::<_, NoneError>(a > b))), 239 | _neg: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128| Ok::<_, NoneError>(-a))), 240 | to_string: FunctionOrChildren::from_function(FunctionWrapper::from(|a: Decimal128| Ok::<_, NoneError>(a.to_standard_notation_string()))), 241 | }, 242 | string: map! { 243 | _eq: FunctionOrChildren::from_function({ 244 | #[kirl_function((String, String)->Bool)] 245 | fn str_eq(a: Arc>, b: Arc>) -> bool { 246 | str::eq(&**a.read().unwrap(), &**b.read().unwrap()) 247 | } 248 | str_eq::new() 249 | }), 250 | _gt: FunctionOrChildren::from_function({ 251 | #[kirl_function((String, String)->Bool)] 252 | fn str_gt(a: Arc>, b: Arc>) -> bool { 253 | str::gt(&**a.read().unwrap(), &**b.read().unwrap()) 254 | } 255 | str_gt::new() 256 | }), 257 | regex: map! { 258 | is_match: FunctionOrChildren::from_function({ 259 | #[kirl_function((String, String)->Bool)] 260 | fn is_match(input: Arc>, pattern: Arc>)->Result{ 261 | let regex = Regex::new(&pattern.read().unwrap())?; 262 | Ok(regex.is_match(&input.read().unwrap())) 263 | } 264 | is_match::new() 265 | }), 266 | replace: FunctionOrChildren::from_function({ 267 | #[kirl_function((String, String, String)->String)] 268 | fn replace(input: Arc>, pattern: Arc>, replace: Arc>)->Result{ 269 | let regex = Regex::new(&pattern.read().unwrap())?; 270 | Ok(regex.replace_all(&input.read().unwrap(), &**replace.read().unwrap()).into_owned()) 271 | } 272 | replace::new() 273 | }), 274 | }, 275 | }, 276 | collections: map! { 277 | list: map! { 278 | new: { 279 | #[kirl_function(for ()->[T] )] 280 | fn create_list() -> Vec> { 281 | Vec::new() 282 | } 283 | FunctionOrChildren::from_function(create_list::new()) 284 | }, 285 | fill: { 286 | #[kirl_function(for (T, Number)->[T] )] 287 | fn fill_list(item: Arc, count: Decimal128) -> Vec> { 288 | vec![item; usize::try_from(dec::Decimal::<15>::from(count)).unwrap()] 289 | } 290 | FunctionOrChildren::from_function(fill_list::new()) 291 | }, 292 | len: { 293 | #[kirl_function(for ([T])->Number )] 294 | fn list_length(list: Arc>>>) -> Decimal128 { 295 | (list.read().unwrap().len() as u64).into() 296 | } 297 | FunctionOrChildren::from_function(list_length::new()) 298 | }, 299 | push: { 300 | #[kirl_function(for ([T], T)->() )] 301 | fn list_push(list: Arc>>>, item: Arc) { 302 | list.write().unwrap().push(item); 303 | } 304 | FunctionOrChildren::from_function(list_push::new()) 305 | }, 306 | insert: { 307 | #[kirl_function(for ([T], Number, T)->() )] 308 | fn list_insert(list: Arc>>>, index: Decimal128, item: Arc) { 309 | list.write().unwrap().insert(usize::try_from(dec::Decimal::<15>::from(index)).unwrap(), item); 310 | } 311 | FunctionOrChildren::from_function(list_insert::new()) 312 | }, 313 | remove: { 314 | #[kirl_function(for ([T], Number)->() )] 315 | fn list_remove(list: Arc>>>, index: Decimal128) { 316 | list.write().unwrap().remove(usize::try_from(dec::Decimal::<15>::from(index)).unwrap()); 317 | } 318 | FunctionOrChildren::from_function(list_remove::new()) 319 | }, 320 | _get_item: { 321 | #[kirl_function(for ([T], Number)->T )] 322 | fn list_get_item(list: Arc>>>, index: Decimal128) -> Arc { 323 | Arc::clone(&list.read().unwrap()[usize::try_from(dec::Decimal::<15>::from(index)).unwrap()]) 324 | } 325 | FunctionOrChildren::from_function(list_get_item::new()) 326 | }, 327 | _set_item: { 328 | #[kirl_function(for ([T], Number, T)->())] 329 | fn list_set_item(list: Arc>>>, index: Decimal128, item: Arc) { 330 | list.write().unwrap()[usize::try_from(dec::Decimal::<15>::from(index)).unwrap()] = item; 331 | } 332 | FunctionOrChildren::from_function(list_set_item::new()) 333 | }, 334 | _iterator: { 335 | #[kirl_function(for ([T])->std::iter::Iterator::)] 336 | fn list_iterator(list: Vec>) -> IteratorWrapper { 337 | IteratorWrapper::new_kirl_value(list.into_iter(), get_type!((std::iter::Iterator::<(Number)>))) 338 | } 339 | FunctionOrChildren::from_function(list_iterator::new()) 340 | } 341 | }, 342 | }, 343 | iter: map! { 344 | range: { 345 | #[kirl_function((Number)->std::iter::Iterator::)] 346 | fn range(stop: Decimal128) -> IteratorWrapper { 347 | let step = Decimal128::from(1); 348 | let iter = std::iter::successors(Some(Decimal128::from(0)), move |&i| Some(i + step)).take_while(move |i| i < &stop); 349 | IteratorWrapper::new(iter, get_type!((std::iter::Iterator::<(Number)>))) 350 | } 351 | FunctionOrChildren::from_function(range::new()) 352 | }, 353 | range: { 354 | #[kirl_function((Number, Number)->std::iter::Iterator::)] 355 | fn range(start: Decimal128, stop: Decimal128) -> IteratorWrapper { 356 | let step = Decimal128::from(1); 357 | let iter = std::iter::successors(Some(start), move |&i| Some(i + step)).take_while(move |i| i < &stop); 358 | IteratorWrapper::new(iter, get_type!((std::iter::Iterator::<(Number)>))) 359 | } 360 | FunctionOrChildren::from_function(range::new()) 361 | }, 362 | range: { 363 | #[kirl_function((Number, Number, Number)->std::iter::Iterator::)] 364 | fn range(start: Decimal128, stop: Decimal128, step: Decimal128) -> IteratorWrapper { 365 | let iter = std::iter::successors(Some(start), move |&i| Some(i + step)).take_while(move |i| i < &stop); 366 | IteratorWrapper::new(iter, get_type!((std::iter::Iterator::<(Number)>))) 367 | } 368 | FunctionOrChildren::from_function(range::new()) 369 | }, 370 | _iterator: { 371 | #[kirl_function(for (std::iter::Iterator::)->std::iter::Iterator:: )] 372 | fn iterator_into_iterator(iter: Arc) -> Arc { 373 | iter 374 | } 375 | FunctionOrChildren::from_function(iterator_into_iterator::new()) 376 | }, 377 | _next: { 378 | #[kirl_function(for (std::iter::Iterator::)->(() | #{ value: T }))] 379 | fn iterator_into_iterator(iter: Arc>) -> Arc { 380 | match iter.write().unwrap().iter.next() { 381 | Some(value) => { 382 | let map = { 383 | let mut map = HashMap::new(); 384 | map.insert("value".to_string(), value); 385 | map 386 | }; 387 | map.into_kirl_value() 388 | }, 389 | None => ().into_kirl_value() 390 | } 391 | } 392 | FunctionOrChildren::from_function(iterator_into_iterator::new()) 393 | }, 394 | }, 395 | }) 396 | }); 397 | 398 | pub fn get_stdlib() -> &'static KirlStdLib { 399 | &*STDLIB 400 | } 401 | 402 | struct IteratorWrapper { 403 | iter: Box> + Send + Sync>, 404 | iter_type: LIRType, 405 | } 406 | 407 | impl Debug for IteratorWrapper { 408 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 409 | f.debug_struct("IteratorWrapper").field("iter", &"emitted").field("iter_type", &self.iter_type).finish() 410 | } 411 | } 412 | 413 | impl IteratorWrapper { 414 | fn new(iter: I, item_type: LIRType) -> Self 415 | where 416 | I::Item: InterchangeKirlVMValue, 417 | { 418 | let iter = Box::new(iter.map(InterchangeKirlVMValue::into_kirl_value)); 419 | let iter_type = LIRType::Named { 420 | path: vec!["std".to_string(), "iter".to_string(), "Iterator".to_string()], 421 | generics_arguments: vec![item_type], 422 | }; 423 | IteratorWrapper { iter, iter_type } 424 | } 425 | 426 | fn new_kirl_value> + Send + Sync + 'static>(iter: I, item_type: LIRType) -> Self { 427 | let iter = Box::new(iter); 428 | let iter_type = LIRType::Named { 429 | path: vec!["std".to_string(), "iter".to_string(), "Iterator".to_string()], 430 | generics_arguments: vec![item_type], 431 | }; 432 | IteratorWrapper { iter, iter_type } 433 | } 434 | } 435 | 436 | impl KirlVMValue for IteratorWrapper { 437 | fn static_type() -> Cow<'static, LIRType> 438 | where 439 | Self: Sized, 440 | { 441 | static TYPE: Lazy = Lazy::new(|| get_type!((std::iter::Iterator::<()>)).into_normalized()); 442 | Cow::Borrowed(&*TYPE) 443 | } 444 | 445 | fn get_type(&self) -> Cow { 446 | Cow::Borrowed(&self.iter_type) 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /kirl_common_macro/src/kirl_function.rs: -------------------------------------------------------------------------------- 1 | use kirl_common::typing::HIRType; 2 | use proc_macro::TokenStream; 3 | use proc_macro2::Span; 4 | use quote::quote; 5 | use std::collections::HashMap; 6 | use syn::parse::{Parse, ParseStream}; 7 | use syn::punctuated::Punctuated; 8 | use syn::{braced, bracketed, parenthesized, parse_macro_input, token, AngleBracketedGenericArguments, ConstParam, FnArg, GenericArgument, GenericParam, Generics, Ident, ItemFn, LifetimeDef, LitStr, PatType, Path, PathArguments, PathSegment, ReturnType, Signature, Token, TraitBound, Type, TypeParam, TypeParamBound, TypeParen, TypePath, TypeTraitObject}; 9 | 10 | #[derive(Debug)] 11 | struct TypeWithGenerics { 12 | _for: Option, 13 | _open: Option, 14 | items: Option>, 15 | _close: Option]>, 16 | ty: TypeSyntax, 17 | } 18 | 19 | impl TypeWithGenerics { 20 | fn expand_generics(self) -> HIRType { 21 | let TypeWithGenerics { items, ty, .. } = self; 22 | let ty: HIRType = ty.into(); 23 | if let Some(items) = items { 24 | let mut map = HashMap::::new(); 25 | for (i, item) in items.into_iter().enumerate() { 26 | map.insert(item.to_string(), i).ok_or(()).expect_err("duplicated type argument name"); 27 | } 28 | fn expand_generics_inner(ty: HIRType, map: &HashMap) -> HIRType { 29 | match ty { 30 | ty @ (HIRType::Infer | HIRType::Unreachable | HIRType::GenericsTypeArgument(_)) => ty, 31 | HIRType::Named { path, generics_arguments } => { 32 | if generics_arguments.is_empty() { 33 | if let [name] = path.as_slice() { 34 | if let Some(index) = map.get(name) { 35 | return HIRType::GenericsTypeArgument(*index); 36 | } 37 | } 38 | } 39 | HIRType::Named { 40 | path, 41 | generics_arguments: generics_arguments.into_iter().map(|ty| expand_generics_inner(ty, map)).collect(), 42 | } 43 | } 44 | HIRType::Tuple(items) => HIRType::Tuple(items.into_iter().map(|ty| expand_generics_inner(ty, map)).collect()), 45 | HIRType::Array(item) => HIRType::Array(Box::new(expand_generics_inner(*item, map))), 46 | HIRType::Function { arguments, result } => HIRType::Function { 47 | arguments: arguments.into_iter().map(|ty| expand_generics_inner(ty, map)).collect(), 48 | result: Box::new(expand_generics_inner(*result, map)), 49 | }, 50 | HIRType::AnonymousStruct(members) => HIRType::AnonymousStruct(members.into_iter().map(|(k, ty)| (k, expand_generics_inner(ty, map))).collect()), 51 | HIRType::Or(items) => HIRType::Or(items.into_iter().map(|ty| expand_generics_inner(ty, map)).collect()), 52 | } 53 | } 54 | expand_generics_inner(ty, &map) 55 | } else { 56 | ty 57 | } 58 | } 59 | } 60 | 61 | impl Parse for TypeWithGenerics { 62 | fn parse(input: ParseStream) -> syn::Result { 63 | let (_for, _open, items, _close) = if input.peek(Token![for]) { 64 | ( 65 | Some(input.parse()?), 66 | Some(input.parse()?), 67 | Some({ 68 | let mut items = Punctuated::new(); 69 | loop { 70 | if input.peek(Token![>]) { 71 | break items; 72 | } 73 | items.push_value(input.parse()?); 74 | if input.peek(Token![>]) { 75 | break items; 76 | } 77 | items.push_punct(input.parse()?); 78 | } 79 | }), 80 | Some(input.parse()?), 81 | ) 82 | } else { 83 | (None, None, None, None) 84 | }; 85 | Ok(TypeWithGenerics { _for, _open, items, _close, ty: input.parse()? }) 86 | } 87 | } 88 | 89 | #[derive(Debug)] 90 | struct StructItem { 91 | name: Ident, 92 | _colon: Token![:], 93 | ty: TypeSyntax, 94 | } 95 | 96 | impl Parse for StructItem { 97 | fn parse(input: ParseStream) -> syn::Result { 98 | Ok(StructItem { name: input.parse()?, _colon: input.parse()?, ty: input.parse()? }) 99 | } 100 | } 101 | 102 | #[derive(Debug)] 103 | enum TypeSyntax { 104 | Unreachable(Token![!]), 105 | Named { path: Punctuated, _open: Option, args: Option>, _close: Option]> }, 106 | Tuple { _paren: token::Paren, items: Punctuated }, 107 | Array { _bracket: token::Bracket, item: Box }, 108 | Function { _paren: token::Paren, args: Punctuated, _arrow: Token![->], result: Box }, 109 | AnonymousStruct { _sharp: Token![#], _brace: token::Brace, members: Punctuated }, 110 | Or { _paren: token::Paren, items: Punctuated }, 111 | } 112 | 113 | impl Parse for TypeSyntax { 114 | fn parse(input: ParseStream) -> syn::Result { 115 | if input.peek(Token![!]) { 116 | Ok(TypeSyntax::Unreachable(input.parse()?)) 117 | } else if input.peek(Ident) { 118 | let path = { 119 | let mut path = Punctuated::new(); 120 | loop { 121 | if !input.peek(Ident) { 122 | break path; 123 | } 124 | path.push_value(input.parse()?); 125 | if !input.peek(Token![::]) { 126 | break path; 127 | } 128 | path.push_punct(input.parse()?); 129 | } 130 | }; 131 | if input.peek(Token![<]) { 132 | let _open = input.parse()?; 133 | let mut args = Punctuated::new(); 134 | loop { 135 | if input.peek(Token![>]) { 136 | break Ok(TypeSyntax::Named { path, _open: Some(_open), args: Some(args), _close: Some(input.parse()?) }); 137 | } 138 | args.push_value(input.parse()?); 139 | if input.peek(Token![>]) { 140 | break Ok(TypeSyntax::Named { path, _open: Some(_open), args: Some(args), _close: Some(input.parse()?) }); 141 | } 142 | args.push_punct(input.parse()?); 143 | } 144 | } else { 145 | Ok(TypeSyntax::Named { path, _open: None, args: None, _close: None }) 146 | } 147 | } else if input.peek(token::Bracket) { 148 | let item; 149 | #[allow(clippy::eval_order_dependence)] 150 | Ok(TypeSyntax::Array { _bracket: bracketed!(item in input), item: Box::new(item.parse()?) }) 151 | } else if input.peek(Token![#]) { 152 | let members; 153 | #[allow(clippy::eval_order_dependence)] 154 | Ok(TypeSyntax::AnonymousStruct { 155 | _sharp: input.parse()?, 156 | _brace: braced!(members in input), 157 | members: members.parse_terminated(StructItem::parse)?, 158 | }) 159 | } else { 160 | let content; 161 | let paren: token::Paren = parenthesized!(content in input); 162 | let tuple = if content.is_empty() { 163 | Punctuated::::new() 164 | } else { 165 | let first: TypeSyntax = content.parse()?; 166 | if content.is_empty() || content.peek(Token![,]) { 167 | let mut tuple_items = Punctuated::::new(); 168 | tuple_items.push_value(first); 169 | loop { 170 | if content.is_empty() { 171 | break tuple_items; 172 | } 173 | tuple_items.push_punct(content.parse()?); 174 | if content.is_empty() { 175 | break tuple_items; 176 | } 177 | tuple_items.push_value(content.parse()?); 178 | } 179 | } else { 180 | let mut or_items = Punctuated::::new(); 181 | or_items.push_value(first); 182 | loop { 183 | if content.is_empty() { 184 | return Ok(TypeSyntax::Or { _paren: paren, items: or_items }); 185 | } 186 | or_items.push_punct(content.parse()?); 187 | if content.is_empty() { 188 | return Ok(TypeSyntax::Or { _paren: paren, items: or_items }); 189 | } 190 | or_items.push_value(content.parse()?); 191 | } 192 | } 193 | }; 194 | if input.peek(Token![->]) { 195 | Ok(TypeSyntax::Function { 196 | _paren: paren, 197 | args: tuple, 198 | _arrow: input.parse()?, 199 | result: Box::new(input.parse()?), 200 | }) 201 | } else { 202 | Ok(TypeSyntax::Tuple { _paren: paren, items: tuple }) 203 | } 204 | } 205 | } 206 | } 207 | 208 | impl From for HIRType { 209 | fn from(ty: TypeSyntax) -> Self { 210 | match ty { 211 | TypeSyntax::Unreachable(_) => HIRType::Unreachable, 212 | TypeSyntax::Named { path, args, .. } => { 213 | let path = path.iter().map(|ident| ident.to_string()).collect(); 214 | HIRType::Named { 215 | path, 216 | generics_arguments: args.into_iter().flatten().map(Into::into).collect(), 217 | } 218 | } 219 | TypeSyntax::Tuple { items, .. } => HIRType::Tuple(items.into_iter().map(Into::into).collect()), 220 | TypeSyntax::Array { item, .. } => HIRType::Array(Box::new((*item).into())), 221 | TypeSyntax::Function { args, result, .. } => HIRType::Function { 222 | arguments: args.into_iter().map(Into::into).collect(), 223 | result: Box::new((*result).into()), 224 | }, 225 | TypeSyntax::AnonymousStruct { members, .. } => HIRType::AnonymousStruct(members.into_iter().map(|StructItem { name, ty, .. }| (name.to_string(), ty.into())).collect()), 226 | TypeSyntax::Or { items, .. } => HIRType::Or(items.into_iter().map(Into::into).collect()), 227 | } 228 | } 229 | } 230 | 231 | fn quote_type(ty: &HIRType) -> proc_macro2::TokenStream { 232 | match ty { 233 | HIRType::Infer => quote! { kirl_common::typing::HIRType::Infer }, 234 | HIRType::Unreachable => quote! {kirl_common::typing::HIRType::Unreachable }, 235 | HIRType::GenericsTypeArgument(i) => quote! { kirl_common::typing::HIRType::GenericsTypeArgument(#i) }, 236 | HIRType::Named { path, generics_arguments } => { 237 | let path = path.iter().map(|s| syn::LitStr::new(s, Span::call_site())); 238 | let generics_arguments = generics_arguments.iter().map(|ty| quote_type(ty)); 239 | quote! { kirl_common::typing::HIRType::Named { path: vec![#(#path.to_string()),*], generics_arguments: vec![#(#generics_arguments),*] } } 240 | } 241 | HIRType::Tuple(items) => { 242 | let items = items.iter().map(|ty| quote_type(ty)); 243 | quote! { kirl_common::typing::HIRType::Tuple(vec![#(#items),*]) } 244 | } 245 | HIRType::Array(item) => { 246 | let item = quote_type(item); 247 | quote! { kirl_common::typing::HIRType::Array(Box::new(#item)) } 248 | } 249 | HIRType::Function { arguments, result } => { 250 | let arguments = arguments.iter().map(|ty| quote_type(ty)); 251 | let result = quote_type(result); 252 | quote! { kirl_common::typing::HIRType::Function { arguments: vec![#(#arguments),*], result: Box::new(#result) } } 253 | } 254 | HIRType::AnonymousStruct(members) => { 255 | let members = members.iter().map(|(k, v)| { 256 | let k = LitStr::new(k, Span::call_site()); 257 | let v = quote_type(v); 258 | quote! { (#k.to_string(), #v) } 259 | }); 260 | quote! { kirl_common::typing::HIRType::AnonymousStruct(std::collections::BTreeMap::from([#(#members),*])) } 261 | } 262 | HIRType::Or(items) => { 263 | let items = items.iter().map(|ty| quote_type(ty)); 264 | quote! { kirl_common::typing::HIRType::Or(vec![#(#items),*]) } 265 | } 266 | } 267 | } 268 | 269 | enum ParamType<'a> { 270 | NonCast, 271 | Cast(&'a Type), 272 | Owned(&'a Type), 273 | } 274 | 275 | fn unwrap_paren(ty: &Type) -> &Type { 276 | if let Type::Paren(TypeParen { elem, .. }) = ty { 277 | unwrap_paren(elem) 278 | } else { 279 | ty 280 | } 281 | } 282 | 283 | fn unwrap_result(ty: &Type) -> Option<(&Type, &Type)> { 284 | if let Type::Path(TypePath { path: Path { segments, .. }, .. }) = unwrap_paren(ty) { 285 | if segments.len() <= 3 && segments.iter().rev().zip(["std", "result", "Result"].iter().rev()).all(|(seg, name)| seg.ident == name) || segments.len() <= 2 && segments.iter().rev().zip(["std", "Result"].iter().rev()).all(|(seg, name)| seg.ident == name) { 286 | if segments.iter().rev().skip(1).any(|seg| !matches!(seg.arguments, PathArguments::None)) { 287 | return None; 288 | } 289 | if let Some(PathSegment { 290 | arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }), 291 | .. 292 | }) = segments.last() 293 | { 294 | if args.len() != 2 { 295 | return None; 296 | } 297 | if let (GenericArgument::Type(ty0), GenericArgument::Type(ty1)) = (&args[0], &args[1]) { 298 | Some((ty0, ty1)) 299 | } else { 300 | None 301 | } 302 | } else { 303 | None 304 | } 305 | } else { 306 | None 307 | } 308 | } else { 309 | None 310 | } 311 | } 312 | 313 | fn get_param_type(ty: &Type) -> ParamType { 314 | fn unwrap_type<'a>(ty: &'a Type, path: &[&str]) -> Option<&'a Type> { 315 | if let Type::Path(TypePath { path: Path { segments, .. }, .. }) = unwrap_paren(ty) { 316 | if segments.len() > path.len() { 317 | return None; 318 | } 319 | if segments.iter().rev().zip(path.iter().rev()).any(|(seg, name)| seg.ident != name) { 320 | return None; 321 | } 322 | if segments.iter().rev().skip(1).any(|seg| !matches!(seg.arguments, PathArguments::None)) { 323 | return None; 324 | } 325 | if let Some(PathSegment { 326 | arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }), 327 | .. 328 | }) = segments.last() 329 | { 330 | if args.len() != 1 { 331 | return None; 332 | } 333 | if let Some(GenericArgument::Type(ty)) = args.first() { 334 | Some(ty) 335 | } else { 336 | None 337 | } 338 | } else { 339 | None 340 | } 341 | } else { 342 | None 343 | } 344 | } 345 | fn is_a(ty: &TypeParamBound, path: &[&str]) -> bool { 346 | if let TypeParamBound::Trait(TraitBound { path: Path { segments, .. }, .. }) = ty { 347 | if segments.len() > path.len() { 348 | return false; 349 | } 350 | if segments.iter().rev().zip(path.iter().rev()).any(|(seg, name)| seg.ident != name) { 351 | return false; 352 | } 353 | if segments.iter().rev().any(|seg| !matches!(seg.arguments, PathArguments::None)) { 354 | return false; 355 | } 356 | true 357 | } else { 358 | false 359 | } 360 | } 361 | match unwrap_type(ty, &["std", "sync", "Arc"]).map(unwrap_paren) { 362 | Some(Type::TraitObject(TypeTraitObject { bounds, .. })) if bounds.iter().any(|tr| is_a(tr, &["kirl_common", "interface", "KirlVMValueLock"])) => ParamType::NonCast, 363 | Some(ty) => match unwrap_type(ty, &["std", "sync", "RwLock"]) { 364 | Some(ty) => ParamType::Cast(ty), 365 | None => ParamType::Owned(ty), 366 | }, 367 | None => ParamType::Owned(ty), 368 | } 369 | } 370 | 371 | pub(crate) fn kirl_function_inner(args: TokenStream, input: TokenStream) -> TokenStream { 372 | let ty = parse_macro_input!(args as TypeWithGenerics).expand_generics(); 373 | let input = parse_macro_input!(input as ItemFn); 374 | let ItemFn { 375 | vis, 376 | sig: Signature { 377 | ident: function_name, 378 | generics: Generics { params, where_clause, .. }, 379 | inputs, 380 | output, 381 | .. 382 | }, 383 | .. 384 | } = &input; 385 | let where_clause = match where_clause { 386 | None => quote! {}, 387 | Some(where_clause) => quote! { #where_clause }, 388 | }; 389 | if let HIRType::Function { arguments, .. } = &ty { 390 | assert_eq!(arguments.len(), inputs.len(), "count of argument is mismatched"); 391 | } else { 392 | panic!("type should be Function"); 393 | } 394 | let params_ref = params 395 | .iter() 396 | .map(|param| match param { 397 | GenericParam::Type(TypeParam { ident, .. }) => quote! { #ident }, 398 | GenericParam::Lifetime(LifetimeDef { lifetime, .. }) => quote! { #lifetime }, 399 | GenericParam::Const(ConstParam { ident, .. }) => quote! { #ident }, 400 | }) 401 | .collect::>(); 402 | let kirl_type = quote_type(&ty); 403 | let argument_count = inputs.len(); 404 | let arguments = inputs 405 | .iter() 406 | .map(|arg| match arg { 407 | FnArg::Receiver(_) => panic!("receiver argument is not supported"), 408 | FnArg::Typed(PatType { ty, .. }) => get_param_type(ty), 409 | }) 410 | .enumerate() 411 | .map(|(i, ty)| { 412 | let name = Ident::new(&format!("param{}", i), Span::call_site()); 413 | match ty { 414 | ParamType::NonCast => quote! { #name }, 415 | ParamType::Cast(ty) => quote! { <#ty as kirl_common::interface::InterchangeKirlVMValue>::try_from_kirl_value(#name).unwrap_or_else(|value|panic!("expected type {:?} but found {:?}.", std::any::type_name::<#ty>(), value.type_name())) }, 416 | ParamType::Owned(ty) => quote! { { 417 | let value = <#ty as kirl_common::interface::InterchangeKirlVMValue>::try_from_kirl_value(#name).unwrap_or_else(|value|panic!("expected type {:?} but found {:?}.", std::any::type_name::<#ty>(), value.type_name())); 418 | std::sync::Arc::try_unwrap(value).map(|lock| lock.into_inner().expect("")).unwrap_or_else(|arc| arc.read().expect("").clone()) 419 | } }, 420 | } 421 | }); 422 | let param_names = (0..argument_count).map(|i| Ident::new(&format!("param{}", i), Span::call_site())); 423 | let output_map = match output { 424 | ReturnType::Default => quote! { Ok(<() as kirl_common::interface::InterchangeKirlVMValue>::into_kirl_value(())) }, 425 | ReturnType::Type(_, ty) => { 426 | if let Some((ty_ok, _)) = unwrap_result(ty) { 427 | match get_param_type(ty_ok) { 428 | ParamType::NonCast => quote! { result.map_err(Into::into) }, 429 | ParamType::Cast(_) => quote! { result.map(|result| result as std::sync::Arc>).map_err(Into::into) }, 430 | ParamType::Owned(ty) => quote! { result.map(<#ty as kirl_common::interface::InterchangeKirlVMValue>::into_kirl_value).map_err(Into::into) }, 431 | } 432 | } else { 433 | match get_param_type(ty) { 434 | ParamType::NonCast => quote! { Ok(result) }, 435 | ParamType::Cast(_) => quote! { Ok(result as std::sync::Arc) }, 436 | ParamType::Owned(ty) => quote! { Ok(<#ty as kirl_common::interface::InterchangeKirlVMValue>::into_kirl_value(result)) }, 437 | } 438 | } 439 | } 440 | }; 441 | let result = quote! { 442 | #input 443 | #[allow(non_camel_case_types)] 444 | #vis struct #function_name<#params> #where_clause { phantom: std::marker::PhantomData<(#(#params_ref),*)> } 445 | impl<#params> Default for #function_name<#(#params_ref),*> #where_clause { 446 | fn default() -> Self { 447 | #function_name { phantom: Default::default() } 448 | } 449 | } 450 | impl<#params> #function_name<#(#params_ref),*> #where_clause { 451 | fn new() -> Self { 452 | #function_name { phantom: Default::default() } 453 | } 454 | } 455 | impl<#params> kirl_common::interface::KirlRustFunction for #function_name<#(#params_ref),*> #where_clause { 456 | fn static_type() -> std::borrow::Cow<'static, kirl_common::typing::HIRType> { 457 | static TYPE: kirl_common::once_cell::sync::Lazy = kirl_common::once_cell::sync::Lazy::new(|| #kirl_type); 458 | std::borrow::Cow::Borrowed(&*TYPE) 459 | } 460 | fn argument_count(&self) -> usize { 461 | #argument_count 462 | } 463 | fn call(&mut self, args: Vec>) -> Result, Box> { 464 | if let Ok([#(#param_names),*]) = <[std::sync::Arc; #argument_count]>::try_from(args) { 465 | let result = #function_name::<#(#params_ref),*>(#(#arguments),*); 466 | #output_map 467 | } else { 468 | unreachable!("invalid argument count in KirlRustFunction::call"); 469 | } 470 | } 471 | } 472 | }; 473 | result.into() 474 | } 475 | -------------------------------------------------------------------------------- /kirl_parser/src/kirl_tokenizer.rs: -------------------------------------------------------------------------------- 1 | use arrayvec::ArrayVec; 2 | use std::error::Error; 3 | use std::fmt::{Display, Formatter}; 4 | use std::ops::Range; 5 | use std::str::FromStr; 6 | 7 | use kirl_common::dec::{Decimal128, ParseDecimalError}; 8 | use parser::enum_index; 9 | use parser::enum_index_derive::*; 10 | use tokenizer::DFATokenizer; 11 | use tokenizer_generator::tokenizer; 12 | 13 | use crate::CharacterPosition; 14 | 15 | #[derive(Debug, PartialEq, EnumIndex)] 16 | pub enum Token { 17 | /// import 18 | Import(Range), 19 | /// fn 20 | Fn(Range), 21 | /// struct 22 | Struct(Range), 23 | /// let 24 | Let(Range), 25 | /// var 26 | Var(Range), 27 | /// if 28 | If(Range), 29 | /// else 30 | Else(Range), 31 | /// match 32 | Match(Range), 33 | /// for 34 | For(Range), 35 | /// in 36 | In(Range), 37 | /// while 38 | While(Range), 39 | /// return 40 | Return(Range), 41 | /// break 42 | Break(Range), 43 | /// continue 44 | Continue(Range), 45 | /// タプルのn番目にアクセスするみたいなの 46 | TupleIndex((Range, usize)), 47 | /// 変数とかの識別子 48 | Identifier((Range, String)), 49 | /// 文字列即値 50 | StringImmediate((Range, String)), 51 | /// 数値即値 52 | NumberImmediate((Range, Decimal128)), 53 | /// ! 54 | Not(Range), 55 | /// . 56 | Dot(Range), 57 | /// , 58 | Comma(Range), 59 | /// # 60 | Sharp(Range), 61 | /// :: 62 | DoubleColon(Range), 63 | /// : 64 | Colon(Range), 65 | /// ; 66 | Semicolon(Range), 67 | /// > 68 | GreaterThan(Range), 69 | /// < 70 | LessThan(Range), 71 | /// >= 72 | GreaterOrEqual(Range), 73 | /// <= 74 | LessOrEqual(Range), 75 | /// = 76 | Assign(Range), 77 | /// == 78 | Equals(Range), 79 | /// != 80 | NotEquals(Range), 81 | /// + 82 | Add(Range), 83 | /// - 84 | Sub(Range), 85 | /// * 86 | Mul(Range), 87 | /// / 88 | Div(Range), 89 | /// % 90 | Rem(Range), 91 | /// & 92 | And(Range), 93 | /// | 94 | Or(Range), 95 | /// ^ 96 | Xor(Range), 97 | /// ( 98 | RoundBracketOpen(Range), 99 | /// ) 100 | RoundBracketClose(Range), 101 | /// [ 102 | SquareBracketOpen(Range), 103 | /// ] 104 | SquareBracketClose(Range), 105 | /// { 106 | WaveBracketOpen(Range), 107 | /// } 108 | WaveBracketClose(Range), 109 | /// -> 110 | FunctionArrow(Range), 111 | /// |-> 112 | MapsTo(Range), 113 | /// => 114 | MatchArrow(Range), 115 | } 116 | 117 | impl Token { 118 | pub fn get_position(&self) -> &Range { 119 | match self { 120 | Token::Import(range) => range, 121 | Token::Fn(range) => range, 122 | Token::Struct(range) => range, 123 | Token::Let(range) => range, 124 | Token::Var(range) => range, 125 | Token::If(range) => range, 126 | Token::Else(range) => range, 127 | Token::Match(range) => range, 128 | Token::For(range) => range, 129 | Token::In(range) => range, 130 | Token::While(range) => range, 131 | Token::Return(range) => range, 132 | Token::Break(range) => range, 133 | Token::Continue(range) => range, 134 | Token::TupleIndex((range, _)) => range, 135 | Token::Identifier((range, _)) => range, 136 | Token::StringImmediate((range, _)) => range, 137 | Token::NumberImmediate((range, _)) => range, 138 | Token::Not(range) => range, 139 | Token::Dot(range) => range, 140 | Token::Comma(range) => range, 141 | Token::Sharp(range) => range, 142 | Token::DoubleColon(range) => range, 143 | Token::Colon(range) => range, 144 | Token::Semicolon(range) => range, 145 | Token::GreaterThan(range) => range, 146 | Token::LessThan(range) => range, 147 | Token::GreaterOrEqual(range) => range, 148 | Token::LessOrEqual(range) => range, 149 | Token::Assign(range) => range, 150 | Token::Equals(range) => range, 151 | Token::NotEquals(range) => range, 152 | Token::Add(range) => range, 153 | Token::Sub(range) => range, 154 | Token::Mul(range) => range, 155 | Token::Div(range) => range, 156 | Token::Rem(range) => range, 157 | Token::And(range) => range, 158 | Token::Or(range) => range, 159 | Token::Xor(range) => range, 160 | Token::RoundBracketOpen(range) => range, 161 | Token::RoundBracketClose(range) => range, 162 | Token::SquareBracketOpen(range) => range, 163 | Token::SquareBracketClose(range) => range, 164 | Token::WaveBracketOpen(range) => range, 165 | Token::WaveBracketClose(range) => range, 166 | Token::FunctionArrow(range) => range, 167 | Token::MapsTo(range) => range, 168 | Token::MatchArrow(range) => range, 169 | } 170 | } 171 | } 172 | 173 | #[derive(Debug, PartialEq)] 174 | pub enum TokenizeError { 175 | IntegerParseError { raw: String, position: Range }, 176 | DecimalParseError { raw: String, position: Range, error: ParseDecimalError }, 177 | StringParseError { raw: String, position: Range }, 178 | UnknownCharacter { character: char, position: CharacterPosition }, 179 | } 180 | 181 | impl Display for TokenizeError { 182 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 183 | std::fmt::Debug::fmt(self, f) 184 | } 185 | } 186 | 187 | impl Error for TokenizeError { 188 | fn source(&self) -> Option<&(dyn Error + 'static)> { 189 | match self { 190 | TokenizeError::DecimalParseError { error, .. } => Some(error), 191 | _ => None, 192 | } 193 | } 194 | } 195 | 196 | macro_rules! array { 197 | ($($e:expr),*) => { [$($e),*].into_iter().collect() } 198 | } 199 | 200 | pub type Tokenizer = DFATokenizer, TokenizeError>, (CharacterPosition, char)>; 201 | 202 | tokenizer! { 203 | pub fn get_tokenizer() -> DFATokenizer { 204 | character (CharacterPosition, char); 205 | token Result, TokenizeError>; 206 | "//.*": |_, _| Ok(array![]); 207 | "/\\*(\\*[^/]|[^\\*])*\\*/": |_, _| Ok(array![]); 208 | "\\s": |_, _| Ok(array![]); 209 | "import": |_, v| Ok(array![Token::Import(v.first().unwrap().0..v.last().unwrap().0.next())]); 210 | "fn": |_, v| Ok(array![Token::Fn(v.first().unwrap().0..v.last().unwrap().0.next())]); 211 | "struct": |_, v| Ok(array![Token::Struct(v.first().unwrap().0..v.last().unwrap().0.next())]); 212 | "let": |_, v| Ok(array![Token::Let(v.first().unwrap().0..v.last().unwrap().0.next())]); 213 | "var": |_, v| Ok(array![Token::Var(v.first().unwrap().0..v.last().unwrap().0.next())]); 214 | "if": |_, v| Ok(array![Token::If(v.first().unwrap().0..v.last().unwrap().0.next())]); 215 | "else": |_, v| Ok(array![Token::Else(v.first().unwrap().0..v.last().unwrap().0.next())]); 216 | "match": |_, v| Ok(array![Token::Match(v.first().unwrap().0..v.last().unwrap().0.next())]); 217 | "for": |_, v| Ok(array![Token::For(v.first().unwrap().0..v.last().unwrap().0.next())]); 218 | "in": |_, v| Ok(array![Token::In(v.first().unwrap().0..v.last().unwrap().0.next())]); 219 | "while": |_, v| Ok(array![Token::While(v.first().unwrap().0..v.last().unwrap().0.next())]); 220 | "return": |_, v| Ok(array![Token::Return(v.first().unwrap().0..v.last().unwrap().0.next())]); 221 | "break": |_, v| Ok(array![Token::Break(v.first().unwrap().0..v.last().unwrap().0.next())]); 222 | "continue": |_, v| Ok(array![Token::Continue(v.first().unwrap().0..v.last().unwrap().0.next())]); 223 | "\\.[0-9][1-9]*(th|st|nd|rd)": |s, v| Ok(array![Token::Dot(v.first().unwrap().0..v[1].0), Token::TupleIndex((v[1].0..v.last().unwrap().0.next(), parse_tuple_index(&s[1..])))]); 224 | "[0-9][1-9]*(th|st|nd|rd)": |s, v| Ok(array![Token::TupleIndex((v.first().unwrap().0..v.last().unwrap().0.next(), parse_tuple_index(s)))]); 225 | "[a-zA-Z_][a-zA-Z0-9_]*": |s, v| Ok(array![Token::Identifier((v.first().unwrap().0..v.last().unwrap().0.next(), s.to_string()))]); 226 | "\"(\\\\(\n|\r|\r\n|r|n|t|x[0-9a-fA-F]{2}|u\\{[0-9a-fA-F]{1,6}\\}|\\\\|\")|[^\\\\\"])*\"": |s, v| { 227 | parse_string_literal(s) 228 | .ok_or_else(|| TokenizeError::StringParseError { 229 | raw: s.to_string(), 230 | position: v.first().unwrap().0..v.last().unwrap().0.next(), 231 | }) 232 | .map(|s| array![Token::StringImmediate((v.first().unwrap().0..v.last().unwrap().0.next(), s))]) 233 | }; 234 | "0b[01_]*[01]|0o[0-7_]*[0-7]|0d[0-9_]*[0-9]|0x[0-9a-fA-F_]*[0-9a-fA-F]|[0-9]|[0-9][0-9_]*[0-9]": |s, v| Ok(array![Token::NumberImmediate((v.first().unwrap().0..v.last().unwrap().0.next(), parse_integer(s)))]); 235 | "([0-9][0-9_]*[0-9]|[0-9]|([0-9][0-9_]*)?\\.[0-9_]*[0-9])([eE][\\+\\-]?[0-9_]*[0-9])?": |s, v| { 236 | Decimal128::from_str(&s.replace("_", "")) 237 | .map(|f| array![Token::NumberImmediate((v.first().unwrap().0..v.last().unwrap().0.next(), f))]) 238 | .map_err( 239 | |e| TokenizeError::DecimalParseError { 240 | raw: s.to_string(), 241 | position: v.first().unwrap().0..v.last().unwrap().0.next(), 242 | error: e, 243 | }) 244 | }; 245 | "!": |_, v| Ok(array![Token::Not(v.first().unwrap().0..v.last().unwrap().0.next())]); 246 | "\\.": |_, v| Ok(array![Token::Dot(v.first().unwrap().0..v.last().unwrap().0.next())]); 247 | ",": |_, v| Ok(array![Token::Comma(v.first().unwrap().0..v.last().unwrap().0.next())]); 248 | "#": |_, v| Ok(array![Token::Sharp(v.first().unwrap().0..v.last().unwrap().0.next())]); 249 | "::": |_, v| Ok(array![Token::DoubleColon(v.first().unwrap().0..v.last().unwrap().0.next())]); 250 | ":": |_, v| Ok(array![Token::Colon(v.first().unwrap().0..v.last().unwrap().0.next())]); 251 | ";": |_, v| Ok(array![Token::Semicolon(v.first().unwrap().0..v.last().unwrap().0.next())]); 252 | ">": |_, v| Ok(array![Token::GreaterThan(v.first().unwrap().0..v.last().unwrap().0.next())]); 253 | "<": |_, v| Ok(array![Token::LessThan(v.first().unwrap().0..v.last().unwrap().0.next())]); 254 | ">=": |_, v| Ok(array![Token::GreaterOrEqual(v.first().unwrap().0..v.last().unwrap().0.next())]); 255 | "<=": |_, v| Ok(array![Token::LessOrEqual(v.first().unwrap().0..v.last().unwrap().0.next())]); 256 | "=": |_, v| Ok(array![Token::Assign(v.first().unwrap().0..v.last().unwrap().0.next())]); 257 | "==": |_, v| Ok(array![Token::Equals(v.first().unwrap().0..v.last().unwrap().0.next())]); 258 | "!=": |_, v| Ok(array![Token::NotEquals(v.first().unwrap().0..v.last().unwrap().0.next())]); 259 | "\\+": |_, v| Ok(array![Token::Add(v.first().unwrap().0..v.last().unwrap().0.next())]); 260 | "\\-": |_, v| Ok(array![Token::Sub(v.first().unwrap().0..v.last().unwrap().0.next())]); 261 | "\\*": |_, v| Ok(array![Token::Mul(v.first().unwrap().0..v.last().unwrap().0.next())]); 262 | "/": |_, v| Ok(array![Token::Div(v.first().unwrap().0..v.last().unwrap().0.next())]); 263 | "%": |_, v| Ok(array![Token::Rem(v.first().unwrap().0..v.last().unwrap().0.next())]); 264 | "&": |_, v| Ok(array![Token::And(v.first().unwrap().0..v.last().unwrap().0.next())]); 265 | "\\|": |_, v| Ok(array![Token::Or(v.first().unwrap().0..v.last().unwrap().0.next())]); 266 | "\\^": |_, v| Ok(array![Token::Xor(v.first().unwrap().0..v.last().unwrap().0.next())]); 267 | "\\(": |_, v| Ok(array![Token::RoundBracketOpen(v.first().unwrap().0..v.last().unwrap().0.next())]); 268 | "\\)": |_, v| Ok(array![Token::RoundBracketClose(v.first().unwrap().0..v.last().unwrap().0.next())]); 269 | "\\[": |_, v| Ok(array![Token::SquareBracketOpen(v.first().unwrap().0..v.last().unwrap().0.next())]); 270 | "\\]": |_, v| Ok(array![Token::SquareBracketClose(v.first().unwrap().0..v.last().unwrap().0.next())]); 271 | "\\{": |_, v| Ok(array![Token::WaveBracketOpen(v.first().unwrap().0..v.last().unwrap().0.next())]); 272 | "\\}": |_, v| Ok(array![Token::WaveBracketClose(v.first().unwrap().0..v.last().unwrap().0.next())]); 273 | "->": |_, v| Ok(array![Token::FunctionArrow(v.first().unwrap().0..v.last().unwrap().0.next())]); 274 | "\\|->": |_, v| Ok(array![Token::MapsTo(v.first().unwrap().0..v.last().unwrap().0.next())]); 275 | "=>": |_, v| Ok(array![Token::MatchArrow(v.first().unwrap().0..v.last().unwrap().0.next())]); 276 | ".|\n": |_, v| Err(TokenizeError::UnknownCharacter { character: v.first().unwrap().1, position: v.first().unwrap().0 }); 277 | } 278 | } 279 | 280 | fn parse_tuple_index(s: &str) -> usize { 281 | usize::from_str(&s[..s.len() - 2]).expect("正規表現でチェックしてるのであんりーちゃぶる(オーバーフローする場合があるが)") 282 | } 283 | 284 | fn parse_integer(s: &str) -> Decimal128 { 285 | let s = s.replace("_", ""); 286 | let (s, radix) = if let Some(s) = s.strip_prefix("0b") { 287 | (s, 2) 288 | } else if let Some(s) = s.strip_prefix("0o") { 289 | (s, 8) 290 | } else if let Some(s) = s.strip_prefix("0d") { 291 | (s, 10) 292 | } else if let Some(s) = s.strip_prefix("0x") { 293 | (s, 16) 294 | } else { 295 | (s.as_str(), 10) 296 | }; 297 | let dec_radix = Decimal128::from(radix); 298 | s.chars().fold(Decimal128::ZERO, |acc, c| acc * dec_radix + Decimal128::from(c.to_digit(radix as u32).expect("正規表現でチェックしてるのであんりーちゃぶる"))) 299 | } 300 | 301 | fn parse_string_literal(s: &str) -> Option { 302 | let mut iter = s[1..s.len() - 1].chars().peekable(); 303 | let mut result = String::with_capacity(s.len()); 304 | while let Some(c) = iter.next() { 305 | if c != '\\' { 306 | result.push(c); 307 | continue; 308 | } 309 | match iter.next() { 310 | Some('\n') => {} 311 | Some('\r') => { 312 | iter.next_if(|&c| c == '\n'); 313 | } 314 | Some('r') => result.push('\r'), 315 | Some('n') => result.push('\n'), 316 | Some('t') => result.push('\t'), 317 | Some('\\') => result.push('\\'), 318 | Some('\"') => result.push('\"'), 319 | Some('x') => { 320 | let c = iter.by_ref().take(2).fold(0, |acc, c| acc << 4 | c.to_digit(16).expect("事前にとーくないざの正規表現で確認してるのであんりーちゃぶる")); 321 | result.push(char::from_u32(c).expect("16進2桁なのであんりーちゃぶる")); 322 | } 323 | Some('u') => { 324 | let c = iter.by_ref().skip(1).take_while(|c| *c != '}').fold(0, |acc, c| acc << 4 | c.to_digit(16).expect("事前にとーくないざの正規表現で確認してるのであんりーちゃぶる")); 325 | result.push(char::from_u32(c)?); 326 | } 327 | _ => unreachable!("事前にとーくないざの正規表現で確認してるのであんりーちゃぶる"), 328 | } 329 | } 330 | result.shrink_to_fit(); 331 | Some(result) 332 | } 333 | 334 | #[cfg(test)] 335 | mod tests { 336 | use std::str::FromStr; 337 | 338 | use kirl_common::dec::Decimal128; 339 | use tokenizer::Tokenize; 340 | 341 | use crate::kirl_tokenizer::{get_tokenizer, CharacterPosition, Token}; 342 | 343 | #[test] 344 | fn test_tokenize() { 345 | let tokenizer = get_tokenizer(); 346 | let tokenize = |s: &str| { 347 | s.chars() 348 | .scan(CharacterPosition::zero(), |position, c| { 349 | let current_position = *position; 350 | *position = match c { 351 | '\n' => position.next_line(), 352 | _ => position.next(), 353 | }; 354 | Some((current_position, c)) 355 | }) 356 | .tokenize_with(&tokenizer, |(_, c)| *c) 357 | .collect::>() 358 | }; 359 | const TEXT: &str = "\ 360 | import fn 361 | struct let 362 | if else 363 | match for 364 | in while 365 | return :: 366 | : ; 367 | > < 368 | >= <= 369 | = == 370 | + - 371 | * / 372 | % & 373 | | ^ 374 | ( ).0th 375 | [ ].3rd 376 | { }. 5th 377 | -> => 378 | . # 379 | , != 380 | ! break 381 | continue // Comment test 382 | /* Comment 383 | test2 */ 384 | "; 385 | println!("{:?}", TEXT); 386 | let vec = tokenize(TEXT); 387 | println!("{:?}", vec); 388 | let new = CharacterPosition::new; 389 | assert_eq!( 390 | vec, 391 | vec![ 392 | Ok(array![Token::Import(new(0, 0)..new(0, 6))]), 393 | Ok(array![]), 394 | Ok(array![Token::Fn(new(0, 7)..new(0, 9))]), 395 | Ok(array![]), 396 | Ok(array![Token::Struct(new(1, 0)..new(1, 6))]), 397 | Ok(array![]), 398 | Ok(array![Token::Let(new(1, 7)..new(1, 10))]), 399 | Ok(array![]), 400 | Ok(array![Token::If(new(2, 0)..new(2, 2))]), 401 | Ok(array![]), 402 | Ok(array![Token::Else(new(2, 3)..new(2, 7))]), 403 | Ok(array![]), 404 | Ok(array![Token::Match(new(3, 0)..new(3, 5))]), 405 | Ok(array![]), 406 | Ok(array![Token::For(new(3, 6)..new(3, 9))]), 407 | Ok(array![]), 408 | Ok(array![Token::In(new(4, 0)..new(4, 2))]), 409 | Ok(array![]), 410 | Ok(array![Token::While(new(4, 3)..new(4, 8))]), 411 | Ok(array![]), 412 | Ok(array![Token::Return(new(5, 0)..new(5, 6))]), 413 | Ok(array![]), 414 | Ok(array![Token::DoubleColon(new(5, 7)..new(5, 9))]), 415 | Ok(array![]), 416 | Ok(array![Token::Colon(new(6, 0)..new(6, 1))]), 417 | Ok(array![]), 418 | Ok(array![Token::Semicolon(new(6, 2)..new(6, 3))]), 419 | Ok(array![]), 420 | Ok(array![Token::GreaterThan(new(7, 0)..new(7, 1))]), 421 | Ok(array![]), 422 | Ok(array![Token::LessThan(new(7, 2)..new(7, 3))]), 423 | Ok(array![]), 424 | Ok(array![Token::GreaterOrEqual(new(8, 0)..new(8, 2))]), 425 | Ok(array![]), 426 | Ok(array![Token::LessOrEqual(new(8, 3)..new(8, 5))]), 427 | Ok(array![]), 428 | Ok(array![Token::Assign(new(9, 0)..new(9, 1))]), 429 | Ok(array![]), 430 | Ok(array![Token::Equals(new(9, 2)..new(9, 4))]), 431 | Ok(array![]), 432 | Ok(array![Token::Add(new(10, 0)..new(10, 1))]), 433 | Ok(array![]), 434 | Ok(array![Token::Sub(new(10, 2)..new(10, 3))]), 435 | Ok(array![]), 436 | Ok(array![Token::Mul(new(11, 0)..new(11, 1))]), 437 | Ok(array![]), 438 | Ok(array![Token::Div(new(11, 2)..new(11, 3))]), 439 | Ok(array![]), 440 | Ok(array![Token::Rem(new(12, 0)..new(12, 1))]), 441 | Ok(array![]), 442 | Ok(array![Token::And(new(12, 2)..new(12, 3))]), 443 | Ok(array![]), 444 | Ok(array![Token::Or(new(13, 0)..new(13, 1))]), 445 | Ok(array![]), 446 | Ok(array![Token::Xor(new(13, 2)..new(13, 3))]), 447 | Ok(array![]), 448 | Ok(array![Token::RoundBracketOpen(new(14, 0)..new(14, 1))]), 449 | Ok(array![]), 450 | Ok(array![Token::RoundBracketClose(new(14, 2)..new(14, 3))]), 451 | Ok(array![Token::Dot(new(14, 3)..new(14, 4)), Token::TupleIndex((new(14, 4)..new(14, 7), 0))]), 452 | Ok(array![]), 453 | Ok(array![Token::SquareBracketOpen(new(15, 0)..new(15, 1))]), 454 | Ok(array![]), 455 | Ok(array![Token::SquareBracketClose(new(15, 2)..new(15, 3))]), 456 | Ok(array![Token::Dot(new(15, 3)..new(15, 4)), Token::TupleIndex((new(15, 4)..new(15, 7), 3))]), 457 | Ok(array![]), 458 | Ok(array![Token::WaveBracketOpen(new(16, 0)..new(16, 1))]), 459 | Ok(array![]), 460 | Ok(array![Token::WaveBracketClose(new(16, 2)..new(16, 3))]), 461 | Ok(array![Token::Dot(new(16, 3)..new(16, 4))]), 462 | Ok(array![]), 463 | Ok(array![Token::TupleIndex((new(16, 5)..new(16, 8), 5))]), 464 | Ok(array![]), 465 | Ok(array![Token::FunctionArrow(new(17, 0)..new(17, 2))]), 466 | Ok(array![]), 467 | Ok(array![Token::MatchArrow(new(17, 3)..new(17, 5))]), 468 | Ok(array![]), 469 | Ok(array![Token::Dot(new(18, 0)..new(18, 1))]), 470 | Ok(array![]), 471 | Ok(array![Token::Sharp(new(18, 2)..new(18, 3))]), 472 | Ok(array![]), 473 | Ok(array![Token::Comma(new(19, 0)..new(19, 1))]), 474 | Ok(array![]), 475 | Ok(array![Token::NotEquals(new(19, 2)..new(19, 4))]), 476 | Ok(array![]), 477 | Ok(array![Token::Not(new(20, 0)..new(20, 1))]), 478 | Ok(array![]), 479 | Ok(array![Token::Break(new(20, 2)..new(20, 7))]), 480 | Ok(array![]), 481 | Ok(array![Token::Continue(new(21, 0)..new(21, 8))]), 482 | Ok(array![]), 483 | Ok(array![]), 484 | Ok(array![]), 485 | Ok(array![]), 486 | Ok(array![]), 487 | ] 488 | ); 489 | assert_eq!(tokenize("a"), vec![Ok(array![Token::Identifier((new(0, 0)..new(0, 1), "a".to_string()))])]); 490 | assert_eq!(tokenize("abc_123"), vec![Ok(array![Token::Identifier((new(0, 0)..new(0, 7), "abc_123".to_string()))])]); 491 | assert_eq!(tokenize("_abc_123"), vec![Ok(array![Token::Identifier((new(0, 0)..new(0, 8), "_abc_123".to_string()))])]); 492 | assert_ne!(tokenize("0_abc_123"), vec![Ok(array![Token::Identifier((new(0, 0)..new(0, 9), "0_abc_123".to_string()))])]); 493 | 494 | assert_eq!(tokenize("\"\n\""), vec![Ok(array![Token::StringImmediate((new(0, 0)..new(1, 1), "\n".to_string()))])]); 495 | assert_eq!(tokenize("\"\\\n\""), vec![Ok(array![Token::StringImmediate((new(0, 0)..new(1, 1), "".to_string()))])]); 496 | assert_eq!(tokenize("\"\\\r\""), vec![Ok(array![Token::StringImmediate((new(0, 0)..new(0, 4), "".to_string()))])]); 497 | assert_eq!(tokenize("\"\\\r\n\""), vec![Ok(array![Token::StringImmediate((new(0, 0)..new(1, 1), "".to_string()))])]); 498 | assert_eq!(tokenize(r##""abcd1234_*`{}-^=~|<>?_,./""##), vec![Ok(array![Token::StringImmediate((new(0, 0)..new(0, 27), "abcd1234_*`{}-^=~|<>?_,./".to_string()))])]); 499 | assert_eq!(tokenize(r#""\\ \" \n \t \x41 \u{beef}""#), vec![Ok(array![Token::StringImmediate((new(0, 0)..new(0, 27), "\\ \" \n \t \x41 \u{beef}".to_string()))])]); 500 | 501 | assert_eq!(tokenize("0"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 1), Decimal128::from(0)))])]); 502 | assert_eq!(tokenize("0b0"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 3), Decimal128::from(0)))])]); 503 | assert_eq!(tokenize("0o0"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 3), Decimal128::from(0)))])]); 504 | assert_eq!(tokenize("0d0"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 3), Decimal128::from(0)))])]); 505 | assert_eq!(tokenize("0x0"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 3), Decimal128::from(0)))])]); 506 | assert_ne!(tokenize("_0"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 2), Decimal128::from(0)))])]); 507 | assert_eq!(tokenize("12"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 2), Decimal128::from(12)))])]); 508 | assert_eq!(tokenize("0b10"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 4), Decimal128::from(0b10)))])]); 509 | assert_eq!(tokenize("0o12"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 4), Decimal128::from(0o12)))])]); 510 | assert_eq!(tokenize("0d12"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 4), Decimal128::from(12)))])]); 511 | assert_eq!(tokenize("0x12"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 4), Decimal128::from(0x12)))])]); 512 | assert_eq!(tokenize("123"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 3), Decimal128::from(123)))])]); 513 | assert_eq!(tokenize("0b101"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 5), Decimal128::from(0b101)))])]); 514 | assert_eq!(tokenize("0o123"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 5), Decimal128::from(0o123)))])]); 515 | assert_eq!(tokenize("0d123"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 5), Decimal128::from(123)))])]); 516 | assert_eq!(tokenize("0x123"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 5), Decimal128::from(0x123)))])]); 517 | 518 | assert_eq!(tokenize(".0"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 2), Decimal128::from(0)))])]); 519 | assert_eq!(tokenize(".1e1"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 4), Decimal128::from_str(".1e1").unwrap()))])]); 520 | assert_eq!(tokenize(".1e+1"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 5), Decimal128::from_str(".1e+1").unwrap()))])]); 521 | assert_eq!(tokenize(".1e-1"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 5), Decimal128::from_str(".1e-1").unwrap()))])]); 522 | assert_eq!(tokenize("1E2"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 3), Decimal128::from_str("1E2").unwrap()))])]); 523 | assert_eq!(tokenize("1E400"), vec![Ok(array![Token::NumberImmediate((new(0, 0)..new(0, 5), Decimal128::from_str("1E400").unwrap()))])]); 524 | } 525 | } 526 | -------------------------------------------------------------------------------- /kirl_common/src/typing.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::collections::BTreeMap; 3 | use std::error::Error; 4 | use std::fmt::{Display, Formatter}; 5 | 6 | #[derive(Debug, PartialEq, Clone, Ord, PartialOrd, Eq)] 7 | pub enum HIRType { 8 | Infer, 9 | Unreachable, 10 | GenericsTypeArgument(usize), 11 | Named { path: Vec, generics_arguments: Vec }, 12 | Tuple(Vec), 13 | Array(Box), 14 | Function { arguments: Vec, result: Box }, 15 | AnonymousStruct(BTreeMap), 16 | Or(Vec), 17 | } 18 | 19 | impl HIRType { 20 | pub fn apply_generics_type_argument(&self, type_arguments: &[HIRType]) -> Option { 21 | match self { 22 | HIRType::Infer => HIRType::Infer, 23 | HIRType::Unreachable => HIRType::Unreachable, 24 | HIRType::GenericsTypeArgument(i) => type_arguments.get(*i)?.clone(), 25 | HIRType::Named { path, generics_arguments } => HIRType::Named { 26 | path: path.clone(), 27 | generics_arguments: { 28 | let mut types = Vec::with_capacity(generics_arguments.len()); 29 | for ty in generics_arguments { 30 | types.push(ty.apply_generics_type_argument(type_arguments)?); 31 | } 32 | types 33 | }, 34 | }, 35 | HIRType::Tuple(items) => HIRType::Tuple({ 36 | let mut types = Vec::with_capacity(items.len()); 37 | for ty in items { 38 | types.push(ty.apply_generics_type_argument(type_arguments)?); 39 | } 40 | types 41 | }), 42 | HIRType::Array(item) => HIRType::Array(Box::new(item.apply_generics_type_argument(type_arguments)?)), 43 | HIRType::Function { arguments, result } => HIRType::Function { 44 | arguments: { 45 | let mut types = Vec::with_capacity(arguments.len()); 46 | for ty in arguments { 47 | types.push(ty.apply_generics_type_argument(type_arguments)?); 48 | } 49 | types 50 | }, 51 | result: Box::new(result.apply_generics_type_argument(type_arguments)?), 52 | }, 53 | HIRType::AnonymousStruct(members) => HIRType::AnonymousStruct({ 54 | let mut result = BTreeMap::new(); 55 | for (key, ty) in members { 56 | result.insert(key.clone(), ty.apply_generics_type_argument(type_arguments)?); 57 | } 58 | result 59 | }), 60 | HIRType::Or(items) => HIRType::Or({ 61 | let mut types = Vec::with_capacity(items.len()); 62 | for ty in items { 63 | types.push(ty.apply_generics_type_argument(type_arguments)?); 64 | } 65 | types 66 | }), 67 | } 68 | .into() 69 | } 70 | 71 | pub fn is_a(&self, rhs: &Self) -> bool { 72 | match (self, rhs) { 73 | (HIRType::Infer, _) => true, 74 | (_, HIRType::Infer) => true, 75 | (HIRType::Unreachable, _) => true, 76 | (_, HIRType::Unreachable) => false, 77 | (HIRType::GenericsTypeArgument(i), HIRType::GenericsTypeArgument(j)) => j == i, 78 | (HIRType::Named { path: path1, generics_arguments: arg1 }, HIRType::Named { path: path2, generics_arguments: arg2 }) => path1 == path2 && arg1.len() == arg2.len() && arg1.iter().zip(arg2).all(|(ty1, ty2)| ty1.is_a(ty2)), 79 | (HIRType::Tuple(items1), HIRType::Tuple(items2)) => items1.len() >= items2.len() && items1.iter().zip(items2).all(|(ty1, ty2)| ty1.is_a(ty2)), 80 | (HIRType::Array(t1), HIRType::Array(t2)) => t1.is_a(t2), 81 | (HIRType::Function { arguments: arg1, result: res1 }, HIRType::Function { arguments: arg2, result: res2 }) => arg1.len() == arg2.len() && arg2.iter().zip(arg1).all(|(ty1, ty2)| ty1.is_a(ty2)) && res1.is_a(res2), 82 | (HIRType::AnonymousStruct(members1), HIRType::AnonymousStruct(members2)) => members2.iter().all(|(k, v2)| members1.get(k).map_or(false, |v1| v1.is_a(v2))), 83 | (HIRType::Or(items1), ty2) => items1.iter().all(|ty1| ty1.is_a(ty2)), 84 | (ty1, HIRType::Or(items2)) => items2.iter().any(|ty2| ty1.is_a(ty2)), 85 | _ => false, 86 | } 87 | } 88 | 89 | pub fn normalize(&mut self) { 90 | match self { 91 | HIRType::Tuple(items) => items.iter_mut().for_each(HIRType::normalize), 92 | HIRType::Array(item) => item.normalize(), 93 | HIRType::Function { arguments, result } => { 94 | arguments.iter_mut().for_each(HIRType::normalize); 95 | result.normalize(); 96 | } 97 | HIRType::AnonymousStruct(members) => members.values_mut().for_each(HIRType::normalize), 98 | HIRType::Or(items) => { 99 | items.iter_mut().for_each(HIRType::normalize); 100 | *items = items.drain(..).flat_map(|ty| if let HIRType::Or(items) = ty { items } else { vec![ty] }).collect(); 101 | items.sort(); 102 | items.dedup(); 103 | if items.len() > 1 { 104 | items.retain(|ty| ty != &HIRType::Unreachable); 105 | } 106 | if items.len() == 1 { 107 | *self = items.pop().unwrap(); 108 | } 109 | } 110 | _ => {} 111 | } 112 | } 113 | 114 | pub fn into_normalized(mut self) -> HIRType { 115 | self.normalize(); 116 | self 117 | } 118 | 119 | pub fn member_type(&self, member_name: &str) -> Option> { 120 | match self { 121 | HIRType::Infer => Some(Cow::Owned(HIRType::Infer)), 122 | HIRType::AnonymousStruct(members) => members.get(member_name).map(Cow::Borrowed), 123 | HIRType::Or(items) => { 124 | let mut result = Vec::with_capacity(items.len()); 125 | for ty in items.iter().map(|ty| ty.member_type(member_name)) { 126 | result.push(ty?.into_owned()); 127 | } 128 | Some(Cow::Owned(HIRType::Or(result))) 129 | } 130 | _ => None, 131 | } 132 | } 133 | 134 | pub fn tuple_item_type(&self, n: usize) -> Option> { 135 | match self { 136 | HIRType::Infer => Some(Cow::Owned(HIRType::Infer)), 137 | HIRType::Tuple(items) => items.get(n).map(Cow::Borrowed), 138 | HIRType::Or(items) => { 139 | let mut result = Vec::with_capacity(items.len()); 140 | for ty in items.iter().map(|ty| ty.tuple_item_type(n)) { 141 | result.push(ty?.into_owned()); 142 | } 143 | Some(Cow::Owned(HIRType::Or(result))) 144 | } 145 | _ => None, 146 | } 147 | } 148 | 149 | pub fn has_member(&self, member_name: &str) -> bool { 150 | match self { 151 | HIRType::Infer => true, 152 | HIRType::AnonymousStruct(members) => members.contains_key(member_name), 153 | HIRType::Or(items) => items.iter().all(|ty| ty.has_member(member_name)), 154 | _ => false, 155 | } 156 | } 157 | 158 | pub fn has_tuple_item(&self, n: usize) -> bool { 159 | match self { 160 | HIRType::Infer => true, 161 | HIRType::Tuple(items) => n < items.len(), 162 | HIRType::Or(items) => items.iter().all(|ty| ty.has_tuple_item(n)), 163 | _ => false, 164 | } 165 | } 166 | 167 | pub fn intersect_to(&self, rhs: &HIRType) -> HIRType { 168 | match (self, rhs) { 169 | (this, rhs) if this == rhs => this.clone(), 170 | (HIRType::Infer, rhs) => rhs.clone(), 171 | (this, HIRType::Infer) => this.clone(), 172 | (HIRType::Tuple(items1), HIRType::Tuple(items2)) if items1.len() <= items2.len() => { 173 | let mut types = Vec::with_capacity(items1.len()); 174 | for (ty1, ty2) in items1.iter().zip(items2) { 175 | types.push(ty1.intersect_to(ty2)); 176 | } 177 | HIRType::Tuple(types) 178 | } 179 | (HIRType::Array(t1), HIRType::Array(t2)) => HIRType::Array(Box::new(t1.intersect_to(t2))), 180 | (ty1 @ HIRType::AnonymousStruct(members1), HIRType::AnonymousStruct(members2)) => { 181 | let mut result_members = BTreeMap::new(); 182 | for (key, value) in members1 { 183 | if let Some(ty2) = members2.get(key) { 184 | result_members.insert(key.clone(), value.intersect_to(ty2)); 185 | } else { 186 | return ty1.clone(); 187 | } 188 | } 189 | HIRType::AnonymousStruct(result_members) 190 | } 191 | (HIRType::Or(items1), ty2) => { 192 | let mut types = Vec::with_capacity(items1.len()); 193 | for ty in items1 { 194 | types.push(ty.intersect_to(ty2)); 195 | } 196 | HIRType::Or(types) 197 | } 198 | (ty1 @ HIRType::Tuple(items1), HIRType::Or(types)) => { 199 | let types = types 200 | .iter() 201 | .filter_map(|ty| match ty { 202 | ty @ HIRType::Tuple(items2) if ty.is_a(ty1) => Some(items1.iter().zip(items2).map(|(ty1, ty2)| ty1.intersect_to(ty2)).collect::>()), 203 | _ => None, 204 | }) 205 | .fold(vec![Vec::new(); items1.len()], |mut acc, types| { 206 | acc.iter_mut().zip(types).for_each(|(acc, ty)| acc.push(ty)); 207 | acc 208 | }); 209 | let types = types.into_iter().map(HIRType::Or).collect(); 210 | HIRType::Tuple(types) 211 | } 212 | (HIRType::Array(t1), HIRType::Or(types)) => { 213 | let types = types 214 | .iter() 215 | .filter_map(|ty| match ty { 216 | HIRType::Array(ty) if ty.is_a(t1) => Some(t1.intersect_to(ty)), 217 | _ => None, 218 | }) 219 | .collect(); 220 | HIRType::Array(Box::new(HIRType::Or(types).into_normalized())) 221 | } 222 | (ty1 @ HIRType::AnonymousStruct(members1), HIRType::Or(types)) => { 223 | let members = types 224 | .iter() 225 | .filter_map(|ty| match ty { 226 | ty @ HIRType::AnonymousStruct(members2) if ty.is_a(ty1) => Some(members1.iter().map(|(key, ty1)| (key.clone(), ty1.intersect_to(members2.get(key).unwrap()))).collect::>()), 227 | _ => None, 228 | }) 229 | .fold(BTreeMap::new(), |mut acc, members| { 230 | for (key, ty) in members { 231 | acc.entry(key).or_insert_with(Vec::new).push(ty); 232 | } 233 | acc 234 | }); 235 | let members = members.into_iter().map(|(k, t)| (k, HIRType::Or(t).into_normalized())).collect::>(); 236 | HIRType::AnonymousStruct(members) 237 | } 238 | (ty1, _) => ty1.clone(), 239 | } 240 | } 241 | 242 | pub fn possibility_assignable_to(&self, target: &HIRType) -> bool { 243 | match (self, target) { 244 | (ty1, ty2) if ty1 == ty2 => true, 245 | (HIRType::Infer, _) | (_, HIRType::Infer) => true, 246 | (HIRType::GenericsTypeArgument(_), _) | (_, HIRType::GenericsTypeArgument(_)) => true, 247 | (HIRType::Tuple(items1), HIRType::Tuple(items2)) => items1.iter().zip(items2).all(|(ty1, ty2)| ty1.possibility_assignable_to(ty2)), 248 | (HIRType::Array(ty1), HIRType::Array(ty2)) => ty1.possibility_assignable_to(ty2), 249 | (HIRType::AnonymousStruct(members1), HIRType::AnonymousStruct(members2)) => !members2.iter().any(|(key, ty2)| members1.get(key).map(|ty1| !ty1.possibility_assignable_to(ty2)).unwrap_or_default()), 250 | (HIRType::Or(types), ty2) => types.iter().any(|ty1| ty1.possibility_assignable_to(ty2)), 251 | (ty1, HIRType::Or(types)) => types.iter().any(|ty2| ty1.possibility_assignable_to(ty2)), 252 | _ => false, 253 | } 254 | } 255 | 256 | pub fn infer_temporary(&self) -> HIRType { 257 | match self { 258 | HIRType::Infer => HIRType::Tuple(Vec::new()), 259 | ty @ (HIRType::Unreachable | HIRType::GenericsTypeArgument(_) | HIRType::Named { .. }) => ty.clone(), 260 | HIRType::Tuple(items) => HIRType::Tuple(items.iter().map(HIRType::infer_temporary).collect()), 261 | HIRType::Array(item) => HIRType::Array(Box::new(item.infer_temporary())), 262 | HIRType::Function { arguments, result } => HIRType::Function { 263 | arguments: arguments.iter().map(HIRType::infer_temporary).collect(), 264 | result: Box::new(result.infer_temporary()), 265 | }, 266 | HIRType::AnonymousStruct(members) => HIRType::AnonymousStruct(members.iter().map(|(k, ty)| (k.clone(), ty.infer_temporary())).collect()), 267 | HIRType::Or(items) => HIRType::Or(items.iter().map(HIRType::infer_temporary).collect()), 268 | } 269 | } 270 | } 271 | 272 | impl ToString for HIRType { 273 | fn to_string(&self) -> String { 274 | match self { 275 | HIRType::Infer => "$Infer".to_string(), 276 | HIRType::Unreachable => "!".to_string(), 277 | HIRType::GenericsTypeArgument(i) => format!("$T{}", i), 278 | HIRType::Named { path, generics_arguments } => { 279 | let generics_arguments = generics_arguments.iter().map(ToString::to_string).reduce(|a, b| format!("{}, {}", a, b)).map(|a| format!("::<{}>", a)).unwrap_or_default(); 280 | format!("{}{}", path.join("::"), generics_arguments) 281 | } 282 | HIRType::Tuple(items) => { 283 | let items = items.iter().map(ToString::to_string).reduce(|a, b| format!("{}, {}", a, b)).unwrap_or_default(); 284 | format!("({})", items) 285 | } 286 | HIRType::Array(item) => { 287 | format!("[{}]", item.to_string()) 288 | } 289 | HIRType::Function { arguments, result } => { 290 | let argument = arguments.iter().map(ToString::to_string).reduce(|a, b| format!("{}, {}", a, b)).unwrap_or_default(); 291 | format!("({})->{}", argument, result.to_string()) 292 | } 293 | HIRType::AnonymousStruct(members) => { 294 | let members = members.iter().map(|(name, ty)| format!("{}: {}", name, ToString::to_string(ty))).reduce(|a, b| format!("{}, {}", a, b)).unwrap_or_default(); 295 | format!("#{{{}}}", members) 296 | } 297 | HIRType::Or(items) => { 298 | let items = items.iter().map(ToString::to_string).reduce(|a, b| format!("{} | {}", a, b)).unwrap_or_default(); 299 | format!("({})", items) 300 | } 301 | } 302 | } 303 | } 304 | 305 | #[derive(Debug, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)] 306 | pub enum LIRType { 307 | Unreachable, 308 | Named { path: Vec, generics_arguments: Vec }, 309 | Tuple(Vec), 310 | Array(Box), 311 | Function { arguments: Vec, result: Box }, 312 | AnonymousStruct(BTreeMap), 313 | Or(Vec), 314 | } 315 | 316 | impl From for HIRType { 317 | fn from(value: LIRType) -> Self { 318 | match value { 319 | LIRType::Unreachable => HIRType::Unreachable, 320 | LIRType::Named { path, generics_arguments } => HIRType::Named { 321 | path, 322 | generics_arguments: generics_arguments.into_iter().map(Into::into).collect(), 323 | }, 324 | LIRType::Tuple(items) => HIRType::Tuple(items.into_iter().map(Into::into).collect()), 325 | LIRType::Array(item) => HIRType::Array(Box::new((*item).into())), 326 | LIRType::Function { arguments, result } => HIRType::Function { 327 | arguments: arguments.into_iter().map(Into::into).collect(), 328 | result: Box::new((*result).into()), 329 | }, 330 | LIRType::AnonymousStruct(items) => HIRType::AnonymousStruct(items.into_iter().map(|(k, v)| (k, v.into())).collect()), 331 | LIRType::Or(items) => HIRType::Or(items.into_iter().map(Into::into).collect()), 332 | } 333 | } 334 | } 335 | 336 | impl LIRType { 337 | pub fn is_a(&self, rhs: &Self) -> bool { 338 | match (self, rhs) { 339 | (LIRType::Unreachable, _) => true, 340 | (_, LIRType::Unreachable) => false, 341 | (LIRType::Named { path: path1, generics_arguments: arg1 }, LIRType::Named { path: path2, generics_arguments: arg2 }) => path1 == path2 && arg1.len() == arg2.len() && arg1.iter().zip(arg2).all(|(ty1, ty2)| ty1.is_a(ty2)), 342 | (LIRType::Tuple(items1), LIRType::Tuple(items2)) => items1.len() == items2.len() && items1.iter().zip(items2).all(|(ty1, ty2)| ty1.is_a(ty2)), 343 | (LIRType::Array(t1), LIRType::Array(t2)) => t1.is_a(t2), 344 | (LIRType::Function { arguments: arg1, result: res1 }, LIRType::Function { arguments: arg2, result: res2 }) => arg1.len() == arg2.len() && arg2.iter().zip(arg1).all(|(ty1, ty2)| ty1.is_a(ty2)) && res1.is_a(res2), 345 | (LIRType::AnonymousStruct(members1), LIRType::AnonymousStruct(members2)) => members2.iter().all(|(k, v2)| members1.get(k).map_or(false, |v1| v1.is_a(v2))), 346 | (LIRType::Or(items1), ty2) => items1.iter().all(|ty1| ty1.is_a(ty2)), 347 | (ty1, LIRType::Or(items2)) => items2.iter().any(|ty2| ty1.is_a(ty2)), 348 | _ => false, 349 | } 350 | } 351 | 352 | pub fn normalize(&mut self) { 353 | match self { 354 | LIRType::Tuple(items) => items.iter_mut().for_each(LIRType::normalize), 355 | LIRType::Array(item) => item.normalize(), 356 | LIRType::Function { arguments, result } => { 357 | arguments.iter_mut().for_each(LIRType::normalize); 358 | result.normalize(); 359 | } 360 | LIRType::AnonymousStruct(members) => members.values_mut().for_each(LIRType::normalize), 361 | LIRType::Or(items) => { 362 | items.iter_mut().for_each(LIRType::normalize); 363 | *items = items.drain(..).flat_map(|ty| if let LIRType::Or(items) = ty { items } else { vec![ty] }).collect(); 364 | items.sort(); 365 | items.dedup(); 366 | if items.len() > 1 { 367 | items.retain(|ty| ty != &LIRType::Unreachable); 368 | } 369 | if items.len() == 1 { 370 | *self = items.pop().unwrap(); 371 | } 372 | } 373 | _ => {} 374 | } 375 | } 376 | 377 | pub fn into_normalized(mut self) -> LIRType { 378 | self.normalize(); 379 | self 380 | } 381 | 382 | pub fn member_type(&self, member_name: &str) -> Option> { 383 | match self { 384 | LIRType::AnonymousStruct(members) => members.get(member_name).map(Cow::Borrowed), 385 | LIRType::Or(items) => { 386 | let mut result = Vec::with_capacity(items.len()); 387 | for ty in items.iter().map(|ty| ty.member_type(member_name)) { 388 | match ty { 389 | None => return None, 390 | Some(ty) => result.push(ty.into_owned()), 391 | } 392 | } 393 | Some(Cow::Owned(LIRType::Or(result))) 394 | } 395 | _ => None, 396 | } 397 | } 398 | 399 | pub fn has_member(&self, member_name: &str) -> bool { 400 | match self { 401 | LIRType::AnonymousStruct(members) => members.contains_key(member_name), 402 | LIRType::Or(items) => items.iter().all(|ty| ty.has_member(member_name)), 403 | _ => false, 404 | } 405 | } 406 | } 407 | 408 | #[derive(Debug)] 409 | pub enum LIRTypeConvertError { 410 | UnSupportedType(&'static str), 411 | } 412 | 413 | impl Display for LIRTypeConvertError { 414 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 415 | match self { 416 | LIRTypeConvertError::UnSupportedType(name) => write!(f, "HIR type {:?} is not supported.", name), 417 | } 418 | } 419 | } 420 | 421 | impl Error for LIRTypeConvertError {} 422 | 423 | impl TryFrom for LIRType { 424 | type Error = LIRTypeConvertError; 425 | fn try_from(mut ty: HIRType) -> Result { 426 | ty.normalize(); 427 | match ty { 428 | HIRType::Infer => Err(LIRTypeConvertError::UnSupportedType("Infer")), 429 | HIRType::Unreachable => Ok(LIRType::Unreachable), 430 | HIRType::GenericsTypeArgument(_) => Err(LIRTypeConvertError::UnSupportedType("GenericsTypeArgument")), 431 | HIRType::Named { path, generics_arguments } => { 432 | let mut result_generics_arguments = Vec::with_capacity(generics_arguments.len()); 433 | for hir_type in generics_arguments { 434 | result_generics_arguments.push(hir_type.try_into()?); 435 | } 436 | Ok(LIRType::Named { path, generics_arguments: result_generics_arguments }) 437 | } 438 | HIRType::Tuple(items) => { 439 | let mut result_items = Vec::with_capacity(items.len()); 440 | for hir_type in items { 441 | result_items.push(hir_type.try_into()?); 442 | } 443 | Ok(LIRType::Tuple(result_items)) 444 | } 445 | HIRType::Array(item) => Ok(LIRType::Array(Box::new((*item).try_into()?))), 446 | HIRType::Function { arguments, result } => { 447 | let mut result_arguments = Vec::with_capacity(arguments.len()); 448 | for hir_type in arguments { 449 | result_arguments.push(hir_type.try_into()?); 450 | } 451 | Ok(LIRType::Function { arguments: result_arguments, result: Box::new((*result).try_into()?) }) 452 | } 453 | HIRType::AnonymousStruct(members) => { 454 | let mut result_members = BTreeMap::new(); 455 | for (member, hir_type) in members { 456 | result_members.insert(member, hir_type.try_into()?); 457 | } 458 | Ok(LIRType::AnonymousStruct(result_members)) 459 | } 460 | HIRType::Or(items) => { 461 | if items.is_empty() { 462 | return Err(LIRTypeConvertError::UnSupportedType("Empty or-type")); 463 | } 464 | let mut result_items = Vec::with_capacity(items.len()); 465 | for hir_type in items { 466 | result_items.push(hir_type.try_into()?); 467 | } 468 | Ok(LIRType::Or(result_items)) 469 | } 470 | } 471 | } 472 | } 473 | 474 | #[cfg(test)] 475 | mod tests { 476 | use super::HIRType; 477 | use std::borrow::Cow; 478 | use std::collections::BTreeMap; 479 | 480 | #[test] 481 | fn test_type_is_a() { 482 | use HIRType::*; 483 | assert!(Infer.is_a(&Infer)); 484 | assert!(Infer.is_a(&Named { path: vec!["Number".to_string()], generics_arguments: vec![] })); 485 | assert!(Named { path: vec!["Number".to_string()], generics_arguments: vec![] }.is_a(&Infer)); 486 | 487 | assert!(Named { path: vec!["Number".to_string()], generics_arguments: vec![] }.is_a(&Named { path: vec!["Number".to_string()], generics_arguments: vec![] })); 488 | assert!(!Named { path: vec!["Number".to_string()], generics_arguments: vec![] }.is_a(&Named { path: vec!["String".to_string()], generics_arguments: vec![] })); 489 | 490 | assert!(Tuple(vec![]).is_a(&Tuple(vec![]))); 491 | assert!(Tuple(vec![Tuple(vec![]), Tuple(vec![])]).is_a(&Tuple(vec![Tuple(vec![]), Tuple(vec![])]))); 492 | assert!(Tuple(vec![Tuple(vec![]), Tuple(vec![])]).is_a(&Tuple(vec![Tuple(vec![])]))); 493 | assert!(!Tuple(vec![Tuple(vec![])]).is_a(&Tuple(vec![Tuple(vec![]), Tuple(vec![])]))); 494 | 495 | assert!(Array(Box::new(Tuple(vec![Tuple(vec![])]))).is_a(&Array(Box::new(Tuple(vec![]))))); 496 | assert!(!Array(Box::new(Tuple(vec![]))).is_a(&Array(Box::new(Tuple(vec![Tuple(vec![])]))))); 497 | 498 | assert!(Function { 499 | arguments: vec![Tuple(vec![])], 500 | result: Box::new(Tuple(vec![Tuple(vec![])])), 501 | } 502 | .is_a(&Function { 503 | arguments: vec![Tuple(vec![Tuple(vec![])])], 504 | result: Box::new(Tuple(vec![])), 505 | })); 506 | assert!(!Function { 507 | arguments: vec![Tuple(vec![]), Tuple(vec![])], 508 | result: Box::new(Tuple(vec![Tuple(vec![])])), 509 | } 510 | .is_a(&Function { 511 | arguments: vec![Tuple(vec![Tuple(vec![])])], 512 | result: Box::new(Tuple(vec![])), 513 | })); 514 | 515 | assert!(AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])])), ("b".to_string(), Tuple(vec![]))])).is_a(&AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![]))])))); 516 | assert!(!AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![]))])).is_a(&AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])])), ("b".to_string(), Tuple(vec![]))])))); 517 | 518 | assert!(Or(vec![Tuple(vec![Tuple(vec![])]), Tuple(vec![Tuple(vec![]), Tuple(vec![])])]).is_a(&Tuple(vec![Tuple(vec![])]))); 519 | assert!(Tuple(vec![Tuple(vec![]), Tuple(vec![])]).is_a(&Or(vec![Tuple(vec![Tuple(vec![]), Tuple(vec![])]), Tuple(vec![Tuple(vec![])])]))); 520 | assert!(Or(vec![Tuple(vec![]), Tuple(vec![Tuple(vec![])]), Tuple(vec![Tuple(vec![Tuple(vec![]), Tuple(vec![])])])]).is_a(&Or(vec![Tuple(vec![]), Tuple(vec![Tuple(vec![])])]))); 521 | } 522 | 523 | #[test] 524 | fn test_type_normalize() { 525 | use HIRType::*; 526 | assert_eq!(Or(vec![Tuple(vec![]), Tuple(vec![])]).into_normalized(), Tuple(vec![])); 527 | assert_eq!(Or(vec![Tuple(vec![]), Tuple(vec![Tuple(vec![])])]).into_normalized(), Or(vec![Tuple(vec![Tuple(vec![])]), Tuple(vec![])]).into_normalized()); 528 | } 529 | 530 | #[test] 531 | fn test_type_member_type() { 532 | use HIRType::*; 533 | assert_eq!(AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])])), ("b".to_string(), Tuple(vec![]))])).member_type("a").map(Cow::into_owned), Some(Tuple(vec![Tuple(vec![])]))); 534 | assert_eq!(AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])])), ("b".to_string(), Tuple(vec![]))])).member_type("b").map(Cow::into_owned), Some(Tuple(vec![]))); 535 | assert_eq!(Tuple(vec![]).member_type("a"), None); 536 | assert_eq!( 537 | Or(vec![AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])]))])), AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![]))]))]).member_type("a").map(Cow::into_owned).map(HIRType::into_normalized), 538 | Some(Or(vec![Tuple(vec![]), Tuple(vec![Tuple(vec![])])])) 539 | ); 540 | assert_eq!(Or(vec![AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])]))])), Tuple(vec![])]).member_type("a"), None); 541 | } 542 | 543 | #[test] 544 | fn test_type_tuple_item_type() { 545 | use HIRType::*; 546 | assert_eq!(Tuple(vec![Tuple(vec![])]).tuple_item_type(0).map(Cow::into_owned), Some(Tuple(vec![]))); 547 | assert_eq!(Tuple(vec![Tuple(vec![]), Tuple(vec![Tuple(vec![])])]).tuple_item_type(1).map(Cow::into_owned), Some(Tuple(vec![Tuple(vec![])]))); 548 | assert_eq!(Tuple(vec![Tuple(vec![])]).tuple_item_type(1), None); 549 | assert_eq!(Or(vec![Tuple(vec![Tuple(vec![Tuple(vec![])])]), Tuple(vec![Tuple(vec![])])]).tuple_item_type(0).map(Cow::into_owned).map(HIRType::into_normalized), Some(Or(vec![Tuple(vec![]), Tuple(vec![Tuple(vec![])])]))); 550 | assert_eq!(Or(vec![Tuple(vec![Tuple(vec![])]), Tuple(vec![])]).tuple_item_type(0), None); 551 | } 552 | 553 | #[test] 554 | fn test_type_has_member() { 555 | use HIRType::*; 556 | assert!(AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])])), ("b".to_string(), Tuple(vec![]))])).has_member("a")); 557 | assert!(AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])])), ("b".to_string(), Tuple(vec![]))])).has_member("b")); 558 | assert!(!Tuple(vec![]).has_member("a")); 559 | assert!(Or(vec![AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])]))])), AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![]))]))]).has_member("a")); 560 | assert!(!Or(vec![AnonymousStruct(BTreeMap::from([("a".to_string(), Tuple(vec![Tuple(vec![])]))])), Tuple(vec![])]).has_member("a")); 561 | } 562 | 563 | #[test] 564 | fn test_type_has_tuple_item() { 565 | use HIRType::*; 566 | assert!(Tuple(vec![Tuple(vec![])]).has_tuple_item(0)); 567 | assert!(Tuple(vec![Tuple(vec![]), Tuple(vec![Tuple(vec![])])]).has_tuple_item(1)); 568 | assert!(!Tuple(vec![Tuple(vec![])]).has_tuple_item(1)); 569 | assert!(Or(vec![Tuple(vec![Tuple(vec![Tuple(vec![])])]), Tuple(vec![Tuple(vec![])])]).has_tuple_item(0)); 570 | assert!(!Or(vec![Tuple(vec![Tuple(vec![])]), Tuple(vec![])]).has_tuple_item(0)); 571 | } 572 | 573 | #[test] 574 | fn test_type_intersect_to() { 575 | use HIRType::*; 576 | let tuple0 = Tuple(vec![]); 577 | let tuple1 = Tuple(vec![tuple0.clone()]); 578 | let tuple2 = Tuple(vec![tuple0.clone(), tuple0.clone()]); 579 | assert_eq!(Infer.intersect_to(&Named { path: vec!["Number".to_string()], generics_arguments: vec![] }), Named { path: vec!["Number".to_string()], generics_arguments: vec![] }); 580 | assert_eq!(tuple0.intersect_to(&Named { path: vec!["Number".to_string()], generics_arguments: vec![] }), tuple0); 581 | assert_eq!(Array(Box::new(Infer)).intersect_to(&Or(vec![Array(Box::new(tuple0.clone())), Array(Box::new(tuple1.clone())), tuple0.clone(), tuple1.clone()])), Array(Box::new(Or(vec![tuple0.clone(), tuple1.clone()])))); 582 | assert_eq!( 583 | Tuple(vec![Infer, Infer]).intersect_to(&Or(vec![Tuple(vec![tuple0.clone(), tuple0.clone()]), Tuple(vec![tuple1.clone(), tuple1.clone(), tuple2.clone()]), Tuple(vec![tuple2.clone()])])), 584 | Tuple(vec![Or(vec![tuple0.clone(), tuple1.clone()]), Or(vec![tuple0.clone(), tuple1.clone()])]) 585 | ); 586 | assert_eq!( 587 | AnonymousStruct(BTreeMap::from([("a".to_string(), Infer), ("b".to_string(), tuple0.clone())])).intersect_to(&Or(vec![ 588 | AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone()), ("b".to_string(), tuple1.clone())])), 589 | AnonymousStruct(BTreeMap::from([("a".to_string(), tuple1.clone()), ("b".to_string(), tuple0.clone())])), 590 | AnonymousStruct(BTreeMap::from([("b".to_string(), tuple1.clone())])), 591 | tuple0.clone(), 592 | ])), 593 | AnonymousStruct(BTreeMap::from([("a".to_string(), Or(vec![tuple0.clone(), tuple1.clone()])), ("b".to_string(), tuple0.clone())])) 594 | ); 595 | } 596 | 597 | #[test] 598 | fn test_type_possibility_assignable_to() { 599 | use HIRType::*; 600 | let tuple0 = Tuple(vec![]); 601 | let tuple1 = Tuple(vec![tuple0.clone()]); 602 | let tuple2 = Tuple(vec![tuple0.clone(), tuple0.clone()]); 603 | assert!(Infer.possibility_assignable_to(&Infer)); 604 | assert!(Infer.possibility_assignable_to(&tuple0)); 605 | assert!(tuple0.possibility_assignable_to(&Infer)); 606 | 607 | assert!(tuple0.possibility_assignable_to(&tuple1)); 608 | assert!(tuple1.possibility_assignable_to(&tuple2)); 609 | assert!(!tuple1.possibility_assignable_to(&Tuple(vec![Array(Box::new(tuple0.clone()))]))); 610 | 611 | assert!(Array(Box::new(tuple1.clone())).possibility_assignable_to(&Array(Box::new(tuple0.clone())))); 612 | assert!(Array(Box::new(tuple1.clone())).possibility_assignable_to(&Array(Box::new(tuple1.clone())))); 613 | assert!(Array(Box::new(tuple1.clone())).possibility_assignable_to(&Array(Box::new(tuple2.clone())))); 614 | 615 | assert!(tuple1.possibility_assignable_to(&Or(vec![tuple1.clone(), tuple2.clone()]))); 616 | assert!(Or(vec![tuple1.clone(), tuple2.clone()]).possibility_assignable_to(&tuple1)); 617 | assert!(tuple1.possibility_assignable_to(&Or(vec![tuple0.clone(), tuple2.clone()]))); 618 | assert!(Or(vec![tuple0.clone(), tuple2.clone()]).possibility_assignable_to(&tuple1)); 619 | 620 | assert!(AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone())])).possibility_assignable_to(&AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone()), ("b".to_string(), tuple0.clone())])))); 621 | assert!(!AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone())])).possibility_assignable_to(&AnonymousStruct(BTreeMap::from([("a".to_string(), Array(Box::new(tuple0.clone()))), ("b".to_string(), tuple0.clone())])))); 622 | assert!(AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone()), ("b".to_string(), tuple1.clone())])).possibility_assignable_to(&AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone()), ("b".to_string(), tuple0.clone())])))); 623 | assert!(AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone()), ("b".to_string(), tuple1.clone())])).possibility_assignable_to(&Or(vec![AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone()), ("b".to_string(), tuple0.clone())])), tuple0.clone()]))); 624 | assert!(tuple2.possibility_assignable_to(&Or(vec![AnonymousStruct(BTreeMap::from([("a".to_string(), tuple0.clone()), ("b".to_string(), tuple0.clone())])), tuple0.clone()]))); 625 | } 626 | } 627 | --------------------------------------------------------------------------------