mirror of
https://github.com/oxalica/nil.git
synced 2024-10-27 20:44:38 +03:00
Impl all literals lowering
This commit is contained in:
parent
d0132c886c
commit
431b3255ef
19
Cargo.lock
generated
19
Cargo.lock
generated
@ -137,12 +137,22 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"expect-test",
|
||||
"la-arena",
|
||||
"ordered-float",
|
||||
"rowan",
|
||||
"salsa",
|
||||
"smol_str",
|
||||
"syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.0"
|
||||
@ -155,6 +165,15 @@ version = "11.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96bcbab4bfea7a59c2c0fe47211a1ac4e3e96bea6eb446d704f310bc5c732ae2"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
|
@ -5,6 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
la-arena = "0.2.1"
|
||||
ordered-float = "3.0.0"
|
||||
rowan = "0.15.6"
|
||||
salsa = "0.17.0-pre.2"
|
||||
smol_str = "0.1.23"
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{AstPtr, Expr, ExprId, Literal, Module, ModuleSourceMap};
|
||||
use super::{AstPtr, Expr, ExprId, Literal, Module, ModuleSourceMap, Path, PathAnchor};
|
||||
use crate::source::{FileId, InFile};
|
||||
use rowan::ast::AstNode;
|
||||
use syntax::ast::{self, LiteralKind};
|
||||
@ -71,16 +71,61 @@ impl LowerCtx {
|
||||
fn lower_literal(&mut self, lit: ast::Literal) -> Option<Literal> {
|
||||
let kind = lit.kind()?;
|
||||
let tok = lit.token().unwrap();
|
||||
let text = tok.text();
|
||||
let mut text = tok.text();
|
||||
|
||||
fn normalize_path(path: &str) -> (usize, Box<str>) {
|
||||
let mut ret = String::new();
|
||||
let mut supers = 0usize;
|
||||
for seg in path.split('/').filter(|&seg| !seg.is_empty() && seg != ".") {
|
||||
if seg != ".." {
|
||||
if !ret.is_empty() {
|
||||
ret.push('/');
|
||||
}
|
||||
ret.push_str(seg);
|
||||
} else if ret.is_empty() {
|
||||
supers += 1;
|
||||
} else {
|
||||
let last_slash = ret.bytes().rposition(|c| c != b'/').unwrap_or(0);
|
||||
ret.truncate(last_slash);
|
||||
}
|
||||
}
|
||||
(supers, ret.into())
|
||||
}
|
||||
|
||||
Some(match kind {
|
||||
LiteralKind::Int => Literal::Int(text.parse::<i64>().ok()?),
|
||||
LiteralKind::Float => todo!(),
|
||||
LiteralKind::Float => Literal::Float(text.parse::<f64>().unwrap().into()),
|
||||
LiteralKind::Uri => Literal::String(text.into()),
|
||||
LiteralKind::RelativePath => todo!(),
|
||||
LiteralKind::AbsolutePath => todo!(),
|
||||
LiteralKind::HomePath => todo!(),
|
||||
LiteralKind::SearchPath => todo!(),
|
||||
LiteralKind::RelativePath
|
||||
| LiteralKind::AbsolutePath
|
||||
| LiteralKind::HomePath
|
||||
| LiteralKind::SearchPath => {
|
||||
let anchor = match kind {
|
||||
LiteralKind::RelativePath => PathAnchor::Relative(self.file_id),
|
||||
LiteralKind::AbsolutePath => PathAnchor::Absolute,
|
||||
LiteralKind::HomePath => {
|
||||
text = &text[2..]; // Strip "~/".
|
||||
PathAnchor::Home
|
||||
}
|
||||
LiteralKind::SearchPath => {
|
||||
text = &text[1..text.len() - 1]; // Strip '<' and '>'.
|
||||
let (search_name, path) = text.split_once('/').unwrap();
|
||||
text = path;
|
||||
PathAnchor::Search(search_name.into())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (mut supers, raw_segments) = normalize_path(text);
|
||||
if kind == LiteralKind::AbsolutePath {
|
||||
// Extra ".." has no effect for absolute path.
|
||||
supers = 0;
|
||||
}
|
||||
Literal::Path(Path {
|
||||
anchor,
|
||||
supers,
|
||||
raw_segments,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ mod tests;
|
||||
|
||||
use crate::source::{FileId, SourceDatabase};
|
||||
use la_arena::{Arena, Idx};
|
||||
use ordered_float::OrderedFloat;
|
||||
use smol_str::SmolStr;
|
||||
use std::collections::HashMap;
|
||||
use std::ops;
|
||||
@ -70,6 +71,7 @@ pub enum Expr {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Literal {
|
||||
Int(i64),
|
||||
Float(OrderedFloat<f64>),
|
||||
String(Box<str>),
|
||||
Path(Path),
|
||||
// TODO
|
||||
@ -93,6 +95,7 @@ impl From<String> for Name {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Path {
|
||||
pub anchor: PathAnchor,
|
||||
pub supers: usize,
|
||||
// Normalized path separated by `/`, with no `.` or `..` segments.
|
||||
pub raw_segments: Box<str>,
|
||||
}
|
||||
|
77
src/def/tests/lower.rs
Normal file
77
src/def/tests/lower.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use crate::def::lower::lower;
|
||||
use crate::source::{FileId, InFile};
|
||||
use expect_test::{expect, Expect};
|
||||
use std::fmt::Write;
|
||||
use syntax::parse_file;
|
||||
|
||||
fn check_lower(src: &str, expect: Expect) {
|
||||
let parse = parse_file(src);
|
||||
let (module, _source_map) = lower(InFile::new(FileId(0), parse.root()));
|
||||
let mut got = String::new();
|
||||
for (i, e) in module.exprs.iter() {
|
||||
writeln!(got, "{}: {:?}", i.into_raw(), e).unwrap();
|
||||
}
|
||||
expect.assert_eq(&got);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn literal() {
|
||||
check_lower(
|
||||
"42",
|
||||
expect![[r#"
|
||||
0: Literal(Int(42))
|
||||
"#]],
|
||||
);
|
||||
check_lower(
|
||||
"1.2e3",
|
||||
expect![[r#"
|
||||
0: Literal(Float(OrderedFloat(1200.0)))
|
||||
"#]],
|
||||
);
|
||||
check_lower(
|
||||
"a:b",
|
||||
expect![[r#"
|
||||
0: Literal(String("a:b"))
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path() {
|
||||
check_lower(
|
||||
"./.",
|
||||
expect![[r#"
|
||||
0: Literal(Path(Path { anchor: Relative(FileId(0)), supers: 0, raw_segments: "" }))
|
||||
"#]],
|
||||
);
|
||||
check_lower(
|
||||
"../.",
|
||||
expect![[r#"
|
||||
0: Literal(Path(Path { anchor: Relative(FileId(0)), supers: 1, raw_segments: "" }))
|
||||
"#]],
|
||||
);
|
||||
check_lower(
|
||||
"../a/../../.b/./c",
|
||||
expect![[r#"
|
||||
0: Literal(Path(Path { anchor: Relative(FileId(0)), supers: 2, raw_segments: ".b/c" }))
|
||||
"#]],
|
||||
);
|
||||
check_lower(
|
||||
"/../a/../../.b/./c",
|
||||
expect![[r#"
|
||||
0: Literal(Path(Path { anchor: Absolute, supers: 0, raw_segments: ".b/c" }))
|
||||
"#]],
|
||||
);
|
||||
check_lower(
|
||||
"~/../a/../../.b/./c",
|
||||
expect![[r#"
|
||||
0: Literal(Path(Path { anchor: Home, supers: 2, raw_segments: ".b/c" }))
|
||||
"#]],
|
||||
);
|
||||
check_lower(
|
||||
"<p/../a/../../.b/./c>",
|
||||
expect![[r#"
|
||||
0: Literal(Path(Path { anchor: Search("p"), supers: 2, raw_segments: ".b/c" }))
|
||||
"#]],
|
||||
);
|
||||
}
|
@ -2,33 +2,11 @@ use super::DefDatabase;
|
||||
use crate::tests::TestDB;
|
||||
use expect_test::expect;
|
||||
|
||||
mod lower;
|
||||
|
||||
#[test]
|
||||
fn module_basic() {
|
||||
fn source_map() {
|
||||
let (db, root_id) = TestDB::from_file("foo 123");
|
||||
expect![[r#"
|
||||
Module {
|
||||
exprs: Arena {
|
||||
len: 3,
|
||||
data: [
|
||||
Ident(
|
||||
Name(
|
||||
"foo",
|
||||
),
|
||||
),
|
||||
Literal(
|
||||
Int(
|
||||
123,
|
||||
),
|
||||
),
|
||||
Apply(
|
||||
Idx::<Expr>(0),
|
||||
Idx::<Expr>(1),
|
||||
),
|
||||
],
|
||||
},
|
||||
}
|
||||
"#]]
|
||||
.assert_debug_eq(&db.module(root_id));
|
||||
|
||||
let source_map = db.source_map(root_id);
|
||||
let mut expr_map = source_map.expr_map.iter().collect::<Vec<_>>();
|
Loading…
Reference in New Issue
Block a user