녹균 분석기에서 배운 것
19359 단어 rustcompileropensourcevscode
rust analyzer 및 목표:
Rust-analyzer는 Rust를 작성할 때 개발자의 체험을 개선하는 도구이다.이것은 다른 코드 편집기와 협력하여 코드를 작성하는 데 도움을 줍니다.rust analyzer가 제공하는 기능 예시: 보완, goto 정의, 코드를 더 익숙한 코드로 재구성하는 데 도움, 특징을 해결하는 데 도움...Rust는 이미 같은 도구RLS를 가지고 있지만 Rust survey 2018 이후 Rust 팀은 서로 다른 도전을 발견했고 IDE 체험을 개선하는 것이 그 일부분이다.RLS의 불안정성과 부정확성을 지적했다.따라서 Rust 팀은 IDE 컴파일러를 처음부터 다시 작성하고 정확성, 성능, 안정성을 갖춘 최상의 구조를 발견하기 위해 rls-2.0 라는 새 작업 그룹을 만들기로 결정했다.그들은 RLS 코드 라이브러리를 검사한 후에 완벽한 IDE의 장기적인 지원을 실현하는 좋은 기초가 아니기 때문에 처음부터 다시 쓰기로 결정했다.Rust analyzer는 RLS와는 구조가 다르지만 언어 서버 프로토콜을 유지합니다.
언어 서버 프로토콜에 대한 정보:
언어 서버 프로토콜(LSP)은 도구(클라이언트, 일반적으로 코드 편집기)와 언어 스마트 공급자(서버) 사이에서 사용되며, 자동으로 완성, 정의로 이동, 모든 인용 찾기 등의 기능을 도구에 통합시킨다.LSP는 프로그래밍 언어 분석기를 정의하는 데 사용되는 Microsoft에서 만든 공통 언어입니다.LSP 생태계는 현재 매우 빠르게 발전하고 있다. 예를 들어 최근 Golang(이미 큰 도구 생태계가 있음)은 LSP 모델로 전환하고 그들의 새로운 도구인 GoPLS로 처음부터 다시 쓰기로 결정했다.LSP를 사용하는 주요 원인 중 하나는 코드 편집기의 특성을 생성하기 위해 하나의 코드 라이브러리에만 주목하는 것이다.사실상, 이 해결 방안을 사용하면, 우리는 단지 하나의 엔진과 여러 개의 클라이언트만이 다른 편집기에 사용된다.
나의 공헌은 무엇입니까?
평소와 같이 저는 일상생활에서 사용하는 프로젝트에 기여하고 제 공헌의 영향을 느끼며 용례와 프로젝트 자체를 이해하려고 합니다.저는 매일 VSCode에서 Rust analyzer를 사용합니다. 제가 Rust 코드를 작성할 때 문제가 발생했습니다.문제는 녹균 분석기가 제시한 가양성이다.간단히 설명해 드릴게요.Rust에서 이 문법
#[cfg(feature = "myfeaturename")]
을 사용하여 조건 컴파일을 사용하고 #[cfg(not(feature = "myfeaturename"))]
을 사용합니다. 이것은 기능 "myfeaturename"가 비활성화되면 이 부분을 컴파일하지 않는다는 것을 의미합니다.다음은 코드 예제입니다.struct MyStruct {
my_val: usize,
#[cfg(feature = "foo")]
bar: bool,
}
impl MyStruct {
#[cfg(feature = "foo")]
pub(crate) fn new(my_val: usize, bar: bool) -> Self {
Self { my_val, bar }
}
#[cfg(not(feature = "foo"))]
pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
Self { my_val } // Error here to tell me the "bar" field was missing
}
}
이 필드는 기능bar
이 활성화된 경우에만 활성화됩니다.그리고 제 두 번째 방법foo
에서는 기능new
이 활성화되지 않기 때문에 foo
필드가 없는 구조만 만들 수 있습니다.녹균 분석기가 잘못했어요.이때 나는 이것이 기회가 될 수 있다고 결정하여 이 프로젝트에 도움이 되고 새로운 것을 많이 배웠다.자동완성과 보조를 개선하기 위해 다른pull 요청도 했습니다.예를 들어, 가능한 경우 완료에 대한 예선을 추가했습니다.feature attributes
나는 이런 코드를 작성하는 데 익숙하지 않다. 원본 코드를 해석하고 추상적인 문법 트리를 만들며 원본 코드에서 오류를 찾는 것이다.나는 컴파일러에 관한 문법과 어휘 선택을 많이 배웠다.거시적인 측면에서 볼 때 모든 내부 기계와 그 작업 원리.저는 이 점을 여러분과 공유해서 여러분의 작업 원리와 프로젝트의 전체 상황을 이해하는 데 도움을 줄 가치가 있다고 생각합니다.면책 성명: 나는 내가 이 문제를 어떻게 해결했는지 설명하지 않을 것이다. 이곳의 목표는 내가rust analyzer 코드 라이브러리에서 배운 것을 설명하는 것이다.
소스 코드에서 조수로:
Rust Analyzer(RA)가 소스 코드를 해석할 때 사용하는 정책을 자세히 살펴보고 Rust 코드를 작성하는 데 도움을 드리겠습니다.이것은 판자 상자 실체에서 파일의 원본 코드에 대한 단일 표현식입니다.RA에서 개발자는 파일 시스템을 처리하지 않기로 결정했기 때문에 몇 가지 이유로 a 를 사용하기로 결정했다.그들은 분석 과정에서 어떠한 IO 조작도 하고 싶지 않으며, 라 코드 라이브러리에서 파일 경로를 사용하는 것도 주로 성능을 고려하고 싶지 않다.따라서 모든 원본 파일은 파일 경로가 아니라 생성된 식별자에 의해 표시됩니다.
소스 코드를 분석하는 단계를 확인하면 다음과 같은 간단한 요약이 나와 있습니다.
Memoized thanks to Salsa crate
+----------------------------------------------+
+--------------------+ +------------------+ +--------------------+ +-----------------------------+
| | | | | | | |
| | | | | | | |
| | | Abstract | | High Level | | Computations on HIR types |
| Source code +-------> Syntax +------> Intermediate +------> to give feedbacks to |
| | | Tree | | Representation | | your code editor |
| | | | | | | |
| | | (AST) | | (HIR) | | |
+--------------------+ +------------------+ +--------------------+ +-----------------------------+
+----------------------------------------------->
Using Rowan crate
여기에는 판자 상자virtual file system에서 생성된 추상적 문법 트리(AST)에 몇 가지 규범이 있습니다.AST 손실이 적기 때문에 모든 공백, 주석, 괄호 등이 보존되어 있습니다...나쁜 문법을 파괴하지 마라. 이것은 잘못된 부분을 제외한 모든 AST를 생성한다는 것을 의미한다.문법 오류가 발견되면 멈추지 않습니다. 이것은 코드 편집기에서 편집할 때 뚜렷한 것 같지만 컴파일링에 사용되는 기본 AST에 대한 요구가 높지 않습니다.트리는 완전히 유형화되지 않았으며, 실제로 서로 다른 유형의 노드는 단지 bar
필드일 뿐, 이것은 하나의 매거이며, 다음은 3행 코드를 위한 AST 생성의 예이다.fn foo() { // here is a comment
1 + 1
}
SOURCE_FILE@[0; 14269)
FN_DEF@[0; 43)
FN_KW@[0; 2) "fn"
WHITESPACE@[2; 3) " "
NAME@[3; 6)
IDENT@[3; 6) "foo"
PARAM_LIST@[6; 8)
L_PAREN@[6; 7) "("
R_PAREN@[7; 8) ")"
WHITESPACE@[8; 9) " "
BLOCK_EXPR@[9; 43)
BLOCK@[9; 43)
L_CURLY@[9; 10) "{"
WHITESPACE@[10; 11) " "
COMMENT@[11; 31) "// here is a comment"
WHITESPACE@[31; 36) "\n "
BIN_EXPR@[36; 41)
LITERAL@[36; 37)
INT_NUMBER@[36; 37) "1"
WHITESPACE@[37; 38) " "
PLUS@[38; 39) "+"
WHITESPACE@[39; 40) " "
LITERAL@[40; 41)
INT_NUMBER@[40; 41) "1"
WHITESPACE@[41; 42) "\n"
R_CURLY@[42; 43) "}"
----------------------------------------------------------
// format is like: KIND@[start_offset; end_offset) "value"
문법 트리는 디자인에 아무런 의미 정보도 없다.문법 트리에 포함된 정보량은 표시된 원본 텍스트와 완전히 같습니다.따라서 그 위에서 데이터를 계산하기 어렵고rust analyzer는 실제적으로 AST 데이터를 원래대로 조작하지 않았다.반대로 트리를 녹슨 구체적인 유형으로 낮추어 더 많은 의미 정보를 추가합니다. 예를 들어 "이것은 어떤 유형입니까?""이 이름이 무슨 뜻이야"등등.첫 번째 단계는 원본 AST 노드(로드 지연)를 중심으로 간단한 패키지를 만들어서 이 낮은 유형을 원본 유형에 쉽게 비추도록 하는 것입니다.이 첫 번째 단계를 실현하려면 원시 AST 노드가 필요합니다. "kind"값을 검사해서 어떤 종류의 노드인지 알고 강제 변환을 통해 정확한 유형을 만들어야 합니다.참고로 이 새로운 유형은 다른 링크 방법을 포함하는 패키지이기 때문에 코드젠에서 생성됩니다.'낮추기'의 마지막 단계는 이러한 유형
kind
을 더욱 구체적인 녹슨 유형(ast::*
으로 바꾸어 더 좋은 방법(생성이 아니라)으로 상호작용을 하도록 하는 것이다.이 단계에서, 우리는 이른바'고급 중간 표시'(HIR) 를 가지게 되었다. 이것은 우리가 녹 유형을 사용하고 컴파일러에 우호적일 수 있도록 한다.다음은 함수 정의의 예입니다.// Example of an autogenerated ast::* type (1st step of lowering)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FnDef {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for FnDef {
fn can_cast(kind: SyntaxKind) -> bool { kind == FN_DEF }
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Self { syntax })
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
// Example of hir::* type (2nd step of lowering)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Function {
pub(crate) id: FunctionId, // We will see after where this identifier comes from
}
impl Function {
// more usable functions to interact with in the RA codebase
pub fn params(self, db: &dyn HirDatabase) -> Vec<TypeRef> {
db.function_data(self.id).params.clone()
}
// ...
}
나문 salsa를 사용하여 캐시 및 증가분 계산:
마지막에 말 안 할 수가 없어요.
최적화되지 않으면 CPU와 시간이 많이 걸릴 수 있습니다.이러한 최적화의 주요 사상은 일종의'수요에 따라'컴파일러를 가지고 있다는 것이다.사실상 이 모든 새로운 유형
hir::*
은 데이터베이스에서 작업한다.이 신기한 소스는
라는 판자 상자로 일부 RUSC 팀원들이 개발했다.모든 노드에 대해 우리는 확정적인 식별자를 가지고 데이터베이스를 빌려 나중에 이 노드를 찾을 수 있다.salsa의 작업 방식은 하나의 조회를 사용하는 것입니다. 이 조회는 노드의 순수한 함수를 만들고 저장하기 위해 파라미터를 얻을 뿐입니다.RA 코드 라이브러리에서 특정 요소에 접근해야 할 때마다 요소 id(예를 들어 함수 id:
hir::*
를 사용하여 "salsa 데이터베이스"에서 이 함수/조회를 호출할 수 있습니다.원소 id는 Salsa에서 생성된 식별자(0이 아닌 기호 정수를 고려)로 주로 서로 다른 함수의 입력 매개 변수로 사용됩니다. 데이터 자체의 상세한 정보가 필요하지 않을 때 복잡한 데이터 구조가 아닌 간단한 식별자를 사용하는 것이 좋습니다.Salsa and rust analyzer에서는 struct FunctionId(salsa::InternId)
이라고 불리지만 게임 개발에서 자주 사용하는 interning
모델과는 거리가 멀지 않다.녹병 분석기의 거의 모든 고급 기능은 매개 변수 중의 데이터베이스로 조회한다.Salsa 카트리지는 변경될 때마다 트리의 모든 부분을 다시 계산하지 않기 때문에 증량 계산을 할 수 있습니다.만약 Salsa로 의존항 조회를 잘 관리한다면, 되돌아오는 요소가 이전과 같다면, 나무에서 더 멀리 가지 못할 것이다.이것은 회로가 끊어져서 변경할 때마다 모든 트리를 다시 계산하지 않습니다.사르사는 어떤 일이 바뀌었는지 알기 위해 수정된 내부 기록을 보류하고 변화가 일어났는지 파악했다.사실 변경이 발생하면 수정이 추가됩니다. 샐사가 의존하는 조회를 알고 있기 때문에 수정 번호를 교체하고 검사하면 충분합니다.이것은 매우 간단한 예이다. 영감은 니콜라스 마사키(Nikolas Matsakis)"Salsa"의 저서로 사르사 춤의 행위를 설명하는 데 쓰인다.
db.set_source_text("a.rs", "fn main() {}") // I set a source file a.rs
db.set_source_text("b.rs", "fn main() {}") // I set a source file b.rs
// this function is use to generate AST for the entire codebase
db.whole_program_ast() // will execute (never invoked before):
// - db.manifest() // Read the source file previously set as input
// - db.ast("a.rs") // A query/function to create the ast from the source file a.rs
// - db.ast("b.rs") // A query/function to create the ast from the source file b.rs
db.set_source_text("a.rs", "fn main() { }") // here I mock a change in my a.rs file, I added a whitespace
db.whole_program_ast() // can we reuse the result?
// - iterate over the deps list:
// - manifest(): this has not changed (checked with a revision number)
// - ast(a.rs):
// - "have you changed since the last revision"?
// - look at its own input, determine they have changed
// - re-execute and produce a new ast
// - compare the old and new ast -- see that they are the same
// - "no, I have not changed"
// - ast(b.rs)
// - no input has changed since last revision
// - therefore still valid
// - the value is still value, so we just recomputed 1 step instead of 2 in this case
이것은rust analyzer의 작업 원리에 대한 개술일 뿐 이미 진행된 최적화에 대한 관심은 없다.이제 코드 편집기에서 Rust 코드를 작성하고 RA의 피드백을 받았을 때 숨겨진 내용을 알 수 있습니다.rust analyzer의 내부 구조에 대해서는 아직 할 말이 많지만, 이것은 한 문장에 진정으로 넣을 수 없다.아마도 우리는 미래의 블로그 글에서 더욱 구체적인 부분을 발굴할 것이다.이것은 아마도 아름다운 여행일 것이다.공구서류
an article
https://ferrous-systems.com/blog/rust-analyzer-2019/
https://langserver.org/
https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/syntax.md
https://docs.microsoft.com/en-ie/archive/blogs/ericlippert/persistence-facades-and-roslyns-red-green-trees
https://gist.github.com/nikomatsakis/5b119a71465549b61743e8739a369b5e
https://joshleeb.com/posts/rust-ecs-thoughts/
https://github.com/nikomatsakis/salsa-rfcs/blob/02e38d7b164f66a45b1797589feb7fe3ee6b564f/RFC0002-Intern-Queries.md
Reference
이 문제에 관하여(녹균 분석기에서 배운 것), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/bnjjj/what-i-learned-contributing-to-rust-analyzer-4c7e텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)