从零开始的语义分析器(0): 语言模型

2023-2-18 15:29| 发布者: wanhu| 查看: 92| 评论: 1

摘要: 打开一个项目, 这个项目里有各种各样的文件, 那么首先要做的就是区分每一个文件属于什么语言.一方面一个语言可能对应很多种文件, 另一方面一个文件后缀也不能直接用于判定语言.那么我们要给一个新语言注册哪些信息呢 ...

打开一个项目, 这个项目里有各种各样的文件, 那么首先要做的就是区分每一个文件属于什么语言.

一方面一个语言可能对应很多种文件, 另一方面一个文件后缀也不能直接用于判定语言.

那么我们要给一个新语言注册哪些信息呢?

  • name/id

唯一标识符, 禁止冲突

  • display_id

给人看的识别符号, 用于多语言国际化, 所有加 display 的默认是本地化的 id.

  • 用户配置

最高优先级, jetbrain 里是这玩意儿



vscode 里用 files.associations 标记(Workspace 级)

  • file_mime

高优先级, 查多媒体类型, 属于比较标准化的方法, 网络环境也适用.

  • file_name

高优先级, 宣称某个名称该语言所有, 很多为 unix 设计的格式没法区分 extension.

  • file_extension

低优先级, 宣称某种后缀归该语言所有.

  • case_sensitive

后缀名搞到现在, 确实挺复杂的, 小写 *.c 表示 c 语言, 大写 *.C 表示 c++.

注意只是 windows 不区分大小写, 不是说 ntfs 读不出大小写.

VSCode 不区分这两者, 且宣称这是 feature 而不是 bug.

  • parent

亲代, 语言怎么还有亲代呢?

语言当然有亲代, 比如 json 之于 json5, js 之于 jsx, xml 之于 html.

语言可以从亲代那里继承各种定义, 比如颜色定义, 节点类型之类的.

注意 LanguageInstance 是惰性加载的, 子代找定义, 有可能亲代没加载, 那么子代可以通知亲代初始化.


那核心结构体就这样

#[derive(Clone, Debug)]
pub struct LanguageInstance {
pub id: LanguageID,
pub debug_name: &'static str,
pub display_name: String,
pub parent: Option<LanguageID>,
pub case_insensitive: bool,
pub file_names: Vec<String>,
pub file_extensions: Vec<String>,
pub file_mimes: Vec<Mime>,
}
pub struct LanguageFileResolver {
user_edit: DashMap<String, LanguageID>,
}

注意, 用户能自己添加删除 file_pattern, 所以你得记录用户的修改事件, 然后根据插件加载的语言, 合成真正的 resolver.

另外我们的文件可能在远端, 所以我们使用 url 来标记文件路径.

还有一种情况是 url 是 data 编码的, 此时需要判定 MIME

impl LanguageFileResolver {
// normal url
pub fn check_file_name(&self, languages: &LanguageRegistry, file_url: &Url) -> PsiResult<LanguageID> {
// last part of url
let file_name = match file_url.path_segments().and_then(|mut s| s.last()) {
Some(s) => s,
None => Err(PsiError::runtime_error(format!("File name of `{}` not valid", file_url)))?,
};
for language in languages.get_all_languages() {
for support_name in language.file_names.iter() {
if language.case_insensitive {
if file_name.eq_ignore_ascii_case(support_name) {
return Ok(language.id);
}
}
else {
if file_name.eq(support_name) {
return Ok(language.id);
}
}
}
}
for get_all_language in languages.get_all_languages() {
for file_extension in get_all_language.file_extensions.iter() {
if file_name.ends_with(file_extension) {
return Ok(get_all_language.id);
}
}
}
Err(PsiError::runtime_error(format!("File `{}` does not match any language registered", file_url)))
}
// "data:text/plain,HelloWorld"
pub fn check_file_mime(&self, languages: &LanguageRegistry, mime: &Mime) -> PsiResult<LanguageID> {
for language in languages.get_all_languages() {
for file_mime in language.file_mimes.iter() {
if file_mime == mime {
return Ok(language.id);
}
}
}
Err(PsiError::runtime_error(format!("Mime type `{}` does not match any language registered", mime)))
}
}

代码同步于


路过

雷人

握手

鲜花

鸡蛋
版权声明:免责声明:文章信息来源于网络以及网友投稿,本网站只负责对文章进行整理、排版、编辑,是出于传递 更多信息之目的, 并不意味着赞同其观点或证实其内容的真实性,如本站文章和转稿涉及版权等问题,请作者在及时联系本站,我们会尽快处理。
已有 1 人参与

会员评论

相关分类

 万奢网手机版

官网微博:万奢网服务平台

今日头条二维码 1 微信公众号二维码 1 抖音小程序二维码 1
上海万湖珠宝贸易有限公司 地址:上海市宝山区共和新路4727号新陆国际大厦1003-1007室 网站经营许可证 备案号:沪ICP备11005343号-12012-2019
万奢网主要专注于手表回收,二手名表回收/销售业务,可免费鉴定(手表真假),评估手表回收价格,正规手表回收公司,宝山实体店,支持全国范围上门回收手表
返回顶部