Compare commits

..

No commits in common. "1711d17fa6f89e6b9adc4884f0d35b9955b02acd" and "2d59a7f560bf81d24c0fc418a614f858efb454b2" have entirely different histories.

8 changed files with 381 additions and 197 deletions

View file

@ -7,7 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
logos = "0.14" logos = "0.14"
chumsky = {version= "1.0.0-alpha.7", features=["label", "extension"]} chumsky = {version= "1.0.0-alpha.7", features=["label"]}
petgraph = { workspace = true} petgraph = { workspace = true}
indexmap = "2.2.6" indexmap = "2.2.6"
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }

View file

@ -1,4 +1,3 @@
#![feature(type_alias_impl_trait)]
pub mod err_reporting; pub mod err_reporting;
pub mod parser; pub mod parser;
pub mod tokens; pub mod tokens;

View file

@ -3,10 +3,7 @@ use std::{fs, path::PathBuf};
use clap::Parser; use clap::Parser;
use lang::{ use lang::{
err_reporting::ErrorCollector, err_reporting::ErrorCollector,
parser::ast::lossless::{ parser::ast::lossless::{lex, parser},
lex,
parser::{self, parse},
},
}; };
#[derive(Parser)] #[derive(Parser)]
@ -20,11 +17,8 @@ fn main() {
let n = args.file.clone(); let n = args.file.clone();
let f = fs::read_to_string(n.clone()).expect("failed to read file"); let f = fs::read_to_string(n.clone()).expect("failed to read file");
println!("toks: {:?}", lex::lex(&f)); println!("toks: {:?}", lex::lex(&f));
println!("parse res: {:?}", parse(&f)); let parse_res = parser::parse(&f);
println!("parse: {:?}", parse_res);
// let parse_res = parser::parse(&f);
// println!("parse: {:?}", parse_res);
// dbg!(lex::lex(&f)); // dbg!(lex::lex(&f));
// let mut err_collector = ErrorCollector::new(vec![(n.to_str().unwrap(), &f)]); // let mut err_collector = ErrorCollector::new(vec![(n.to_str().unwrap(), &f)]);

View file

@ -10,6 +10,7 @@ pub fn lex(src: &str) -> Vec<(SyntaxKind, &str)> {
r.push((tok_res.unwrap_or(SyntaxKind::LEX_ERR), lex.slice())) r.push((tok_res.unwrap_or(SyntaxKind::LEX_ERR), lex.slice()))
} }
r.reverse();
r r
} }

View file

@ -9,137 +9,22 @@ use crate::parser::{
Span, Span,
}; };
use self::parser_to_events::{to_events, Event};
use super::lex::{self, SyntaxKind}; use super::lex::{self, SyntaxKind};
pub mod parser_to_events { mod parsers {
use chumsky::prelude::*; use rowan::GreenNode;
use crate::parser::ast::lossless::lex::{ use crate::parser::ast::lossless::lex::SyntaxKind;
self,
SyntaxKind::{self, *},
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)] use super::SyntaxError;
pub enum Event {
StartNode(SyntaxKind), struct ParseResult {
StartErr(SyntaxError), green_node: GreenNode,
EatToken, errors: Vec<SyntaxError>,
FinishNode,
FinishErr,
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy)] trait Parser {
pub enum SyntaxError { fn parse<'src>(input: &[(SyntaxKind, &'src str)]) -> ParseResult;
Expected(SyntaxKind),
AttrExpectedValue,
/// guessed if there's a newline and attr on next line without comma
/// should then suggest comma after attr
ExpectedCommaBetweenAttrs,
}
pub fn to_events(tokens: &[(SyntaxKind, &str)]) -> Vec<Event> {
let mut only_toks: Vec<SyntaxKind> = tokens.iter().map(|(t, _)| *t).collect();
let res = parser().parse(&only_toks);
res.unwrap()
}
macro_rules! padded {
($parser:expr) => {{
let ws = one_of([WHITESPACE, NEWLINE])
.to(Event::EatToken)
.repeated()
.collect::<Vec<Event>>();
ws.then($parser)
.then(ws)
.map(|((mut before, mut c), mut after)| {
before.append(&mut c);
before.append(&mut after);
before
})
}};
}
pub fn parser<'toks>() -> impl Parser<'toks, &'toks [SyntaxKind], Vec<Event>> {
let ws = one_of([WHITESPACE, NEWLINE])
.to(Event::EatToken)
.repeated()
.collect::<Vec<Event>>();
// let ws_without_newlines = just(WHITESPACE)
// .to(Event::EatToken)
// .repeated()
// .collect::<Vec<Event>>();
let parenthesized = |c| {
just(L_PAREN)
.to(vec![Event::EatToken])
.then(c)
.then(just(R_PAREN).to(vec![Event::EatToken]))
.map(|((mut before, mut c), mut after)| {
before.append(&mut c);
before.append(&mut after);
before
})
};
let expr = recursive(|expr| {
let lit = one_of([INT_NUM, FLOAT_NUM, STRING]).to(vec![
Event::StartNode(EXPR),
Event::EatToken,
Event::FinishNode,
]);
let atom = lit.clone().or(parenthesized(expr));
let ident = just(IDENT).to(vec![Event::EatToken]);
let instr_name = ident
.clone()
.map(|mut v| {
v.insert(0, Event::StartNode(INSTR_NAME));
v
})
.foldl(
ws.then(ident).repeated(),
|mut ident, (mut ws, mut next)| {
ident.append(&mut ws);
ident.append(&mut next);
ident
},
)
.map(|mut v| {
v.push(Event::FinishNode);
v
});
let instr = padded!(instr_name)
.then(
atom.clone()
.map(|mut v| {
v.insert(0, Event::StartNode(INSTR_PARAMS));
v
})
.foldl(
ws.then(atom.clone()).repeated(),
|mut cur, (mut ws, mut next)| {
cur.append(&mut ws);
cur.append(&mut next);
cur
},
)
.map(|mut v| {
v.push(Event::FinishNode);
v
}),
)
.map(|(mut name, mut params)| {
name.insert(0, Event::StartNode(INSTR));
name.append(&mut params);
name.push(Event::FinishNode);
name
});
padded!(instr.or(lit).or(atom))
});
expr
// .map(|(lit, mut ev)| lit.append(&mut ev));
} }
} }
@ -197,7 +82,7 @@ enum SyntaxError {
} }
pub fn parse(src: &str) -> Parse { pub fn parse(src: &str) -> Parse {
let tokens = lex::lex(src); let mut tokens = lex::lex(src);
Parser { Parser {
tokens, tokens,
builder: GreenNodeBuilder::new(), builder: GreenNodeBuilder::new(),
@ -208,19 +93,12 @@ pub fn parse(src: &str) -> Parse {
impl Parser<'_> { impl Parser<'_> {
fn parse(mut self) -> Parse { fn parse(mut self) -> Parse {
let evs = to_events(&self.tokens); self.start_node(ROOT);
self.builder.start_node(ROOT.into());
self.tokens.reverse(); match self.expr(None) {
expr::ExprRes::Ok => (),
for ev in evs { expr::ExprRes::Eof => (),
match ev { expr::ExprRes::NoExpr => todo!(),
Event::StartNode(kind) => self.builder.start_node(kind.into()),
Event::StartErr(SyntaxError) => todo!(),
Event::EatToken => self.bump(),
Event::FinishNode => self.builder.finish_node(),
Event::FinishErr => todo!(),
}
} }
self.builder.finish_node(); self.builder.finish_node();
@ -229,6 +107,13 @@ impl Parser<'_> {
} }
} }
fn start_node(&mut self, kind: SyntaxKind) {
self.builder.start_node(kind.into());
}
fn finish_node(&mut self) {
self.builder.finish_node();
}
/// Advance one token, adding it to the current branch of the tree builder. /// Advance one token, adding it to the current branch of the tree builder.
fn bump(&mut self) { fn bump(&mut self) {
let (kind, text) = self.tokens.pop().unwrap(); let (kind, text) = self.tokens.pop().unwrap();
@ -241,7 +126,7 @@ impl Parser<'_> {
} }
fn syntax_err_by_checkpoint(&mut self, checkpoint: Checkpoint, err: SyntaxError) { fn syntax_err_by_checkpoint(&mut self, checkpoint: Checkpoint, err: SyntaxError) {
self.builder.start_node_at(checkpoint, PARSE_ERR.into()); self.builder.start_node_at(checkpoint, PARSE_ERR.into());
self.builder.finish_node(); self.finish_node();
self.errors.push(err); self.errors.push(err);
} }
fn expected(&mut self, expected: SyntaxKind) { fn expected(&mut self, expected: SyntaxKind) {
@ -256,4 +141,313 @@ impl Parser<'_> {
.get(self.tokens.len() - 2) .get(self.tokens.len() - 2)
.map(|(kind, _)| *kind) .map(|(kind, _)| *kind)
} }
fn skip_ws(&mut self) {
while self.current() == Some(WHITESPACE) || self.current() == Some(NEWLINE) {
self.bump()
}
}
fn skip_ws_without_newlines(&mut self) {
while self.current() == Some(WHITESPACE) {
self.bump()
}
}
}
mod expr {
use rowan::Checkpoint;
use super::{attrset::AttrsetRes, instr::NodeRes, Parser};
use crate::parser::{ast::lossless::lex::SyntaxKind::*, Span};
impl Parser<'_> {
pub(super) fn expr(&mut self, start: Option<Checkpoint>) -> ExprRes {
self.skip_ws();
let start = start.unwrap_or_else(|| self.builder.checkpoint());
match self.current() {
Some(IDENT) => {
let expr_res = match self.instr() {
NodeRes::Ok => ExprRes::Ok,
NodeRes::Eof => ExprRes::Eof,
};
self.builder.start_node_at(start, EXPR.into());
self.finish_node();
expr_res
}
Some(_) => self.atom(Some(start)),
None => ExprRes::Eof,
}
}
pub(super) fn atom(&mut self, start: Option<Checkpoint>) -> ExprRes {
self.skip_ws();
let start = start.unwrap_or_else(|| self.builder.checkpoint());
match self.current() {
Some(INT_NUM | FLOAT_NUM | STRING) => {
self.bump();
self.builder.start_node_at(start, EXPR.into());
self.finish_node();
ExprRes::Ok
}
Some(L_CURLY) => match self.attrset(start) {
AttrsetRes::Ok => ExprRes::Ok,
AttrsetRes::Eof => ExprRes::Eof,
},
Some(L_PAREN) => {
self.builder.start_node_at(start, PARENTHESIZED_EXPR.into());
self.bump();
self.expr(None);
self.skip_ws();
match self.current() {
Some(R_PAREN) => ExprRes::Ok,
Some(_) => todo!(),
None => ExprRes::Eof,
}
}
Some(_) => ExprRes::NoExpr,
None => ExprRes::Eof,
}
}
}
pub enum ExprRes {
Ok,
Eof,
/// isnt an expression
NoExpr,
}
}
mod attrset {
use chumsky::container::Container;
use rowan::Checkpoint;
use super::{expr::ExprRes, instr::NodeRes, Parser};
use crate::parser::{
ast::lossless::{lex::SyntaxKind::*, parser::SyntaxError},
Span,
};
impl Parser<'_> {
pub(super) fn attrset(&mut self, checkpoint: Checkpoint) -> AttrsetRes {
assert_eq!(self.current(), Some(L_CURLY));
self.bump();
self.skip_ws();
match self.current() {
Some(R_CURLY) => {
self.builder.start_node_at(checkpoint, ATTR_SET.into());
self.bump();
self.finish_node();
AttrsetRes::Ok
}
Some(_) => {
self.builder.start_node_at(checkpoint, ATTR_SET.into());
let res = match self.attrs() {
AttrRes::Eof => AttrsetRes::Eof,
AttrRes::RCurly | AttrRes::Ok => {
println!("curr: {:?}", self.current());
AttrsetRes::Ok
}
};
self.finish_node();
res
}
None => AttrsetRes::Eof,
}
// self.start_node(ATTR);
}
fn attrs(&mut self) -> AttrRes {
let mut res = AttrRes::Ok;
while res == AttrRes::Ok {
println!("it: {:?}", self.tokens.last());
match self.attr() {
AttrRes::Ok => {
self.skip_ws_without_newlines();
println!(
"a: {:?}, {:?}",
self.tokens.last(),
self.tokens.get(self.tokens.len() - 2)
);
println!("errs: {:?}", self.errors);
res = AttrRes::Ok;
let checkpoint_previous_end = self.builder.checkpoint();
res = match self.current() {
Some(COMMA) => {
self.bump();
AttrRes::Ok
}
Some(R_CURLY) => {
self.bump();
res = AttrRes::Ok;
break;
}
Some(NEWLINE) => {
self.skip_ws();
println!(
"b: {:?}, {:?}",
self.tokens.last(),
self.tokens.get(self.tokens.len() - 2)
);
match self.current() {
Some(COMMA) => {
self.bump();
AttrRes::Ok
}
Some(R_CURLY) => {
self.bump();
res = AttrRes::Ok;
break;
}
Some(IDENT) => {
println!("wtf");
self.syntax_err_by_checkpoint(
checkpoint_previous_end,
SyntaxError::ExpectedCommaBetweenAttrs,
);
// self.syntax_err(SyntaxError::ExpectedCommaBetweenAttrs);
AttrRes::Ok
}
Some(_) => {
self.bump();
AttrRes::Ok
}
None => {
res = AttrRes::Eof;
break;
}
}
}
Some(_) => {
self.bump();
println!(
"c: {:?}, {:?}",
self.tokens.last(),
self.tokens.get(self.tokens.len() - 2)
);
AttrRes::Ok
}
None => {
res = AttrRes::Eof;
break;
}
}
}
AttrRes::Eof => {
res = AttrRes::Eof;
break;
}
AttrRes::RCurly => {
res = AttrRes::RCurly;
break;
}
}
}
println!("toks_left: {:?}", self.tokens);
res
}
fn attr(&mut self) -> AttrRes {
self.skip_ws();
self.start_node(ATTR);
self.start_node(ATTR_NAME);
match self.current() {
Some(IDENT) => self.bump(),
Some(R_CURLY) => return AttrRes::Ok,
Some(_) => self.expected(IDENT),
None => return AttrRes::Eof,
}
self.finish_node();
self.skip_ws();
match self.current() {
Some(COLON) => self.bump(),
Some(R_CURLY) => {
self.expected(COLON);
return AttrRes::RCurly;
}
Some(_) => self.expected(COLON),
None => return AttrRes::Eof,
}
self.skip_ws();
self.start_node(ATTR_VALUE);
match self.expr(None) {
ExprRes::Ok => self.bump(),
ExprRes::Eof => return AttrRes::Eof,
ExprRes::NoExpr => match self.current() {
Some(COMMA) => self.syntax_err(SyntaxError::AttrExpectedValue),
Some(R_CURLY) => {
self.syntax_err(SyntaxError::AttrExpectedValue);
return AttrRes::RCurly;
}
Some(_) => self.expected(EXPR),
None => unreachable!(),
},
}
self.finish_node();
self.finish_node();
AttrRes::Ok
}
}
#[derive(PartialEq, Eq)]
pub enum AttrsetRes {
Ok,
Eof,
}
#[derive(PartialEq, Eq)]
enum AttrRes {
Ok,
Eof,
RCurly,
}
}
mod instr {
use super::Parser;
use crate::parser::{
ast::lossless::{lex::SyntaxKind::*, parser::expr::ExprRes},
Span,
};
impl Parser<'_> {
pub(super) fn instr(&mut self) -> NodeRes {
assert_eq!(self.current(), Some(IDENT));
self.skip_ws();
self.start_node(INSTR);
self.instr_name();
// used to count positionals
let mut i = 0;
let params_checkpoint = self.builder.checkpoint();
loop {
match self.expr(None) {
ExprRes::Ok => {
i += 1;
continue;
}
ExprRes::NoExpr | ExprRes::Eof => break,
}
}
if i >= 1 {
self.builder
.start_node_at(params_checkpoint, INSTR_PARAMS.into());
self.finish_node();
}
self.finish_node();
NodeRes::Ok
}
fn instr_name(&mut self) {
self.start_node(INSTR_NAME);
while self.current() == Some(IDENT) {
self.bump();
self.skip_ws_without_newlines();
}
self.finish_node();
}
}
pub(super) enum NodeRes {
Ok,
Eof,
}
} }

View file

@ -11,11 +11,11 @@
"pre-commit-hooks": "pre-commit-hooks" "pre-commit-hooks": "pre-commit-hooks"
}, },
"locked": { "locked": {
"lastModified": 1712055811, "lastModified": 1710475558,
"narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", "narHash": "sha256-egKrPCKjy/cE+NqCj4hg2fNX/NwLCf0bRDInraYXDgs=",
"owner": "cachix", "owner": "cachix",
"repo": "cachix", "repo": "cachix",
"rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", "rev": "661bbb7f8b55722a0406456b15267b5426a3bda6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -33,11 +33,11 @@
"pre-commit-hooks": "pre-commit-hooks_2" "pre-commit-hooks": "pre-commit-hooks_2"
}, },
"locked": { "locked": {
"lastModified": 1712925466, "lastModified": 1712724616,
"narHash": "sha256-MJ6VxGNu/ftbn8SErJjBz80FUNXkZfcObHg/JP7wwAc=", "narHash": "sha256-qs9uEbrOpp6oXcDOp5cpilyU52t78ZpEPATtaHRVLIU=",
"owner": "cachix", "owner": "cachix",
"repo": "devenv", "repo": "devenv",
"rev": "1af93652caf48bfeef6ba7d1cf59fc66e506e5c2", "rev": "d1a11d14dbe96a03c7f9068e4d3af05f283734e0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -83,11 +83,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1712903033, "lastModified": 1712730246,
"narHash": "sha256-KcvsEm0h1mIwBHFAzWFBjGihnbf2fxpAaXOdVbUfAI4=", "narHash": "sha256-iB8bFj+07RHpmt+XuGGvYQk2Iwm12u6+DklGq/+Tg5s=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "c739f83545e625227f4d0af7fe2a71e69931fa4c", "rev": "d402ae4a5e5676722290470f61a5e8e3155b5487",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -335,11 +335,11 @@
"nixpkgs-regression": "nixpkgs-regression_2" "nixpkgs-regression": "nixpkgs-regression_2"
}, },
"locked": { "locked": {
"lastModified": 1712911606, "lastModified": 1710500156,
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", "narHash": "sha256-zvCqeUO2GLOm7jnU23G4EzTZR7eylcJN+HJ5svjmubI=",
"owner": "domenkozar", "owner": "domenkozar",
"repo": "nix", "repo": "nix",
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", "rev": "c5bbf14ecbd692eeabf4184cc8d50f79c2446549",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -431,11 +431,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1710796454, "lastModified": 1710236354,
"narHash": "sha256-lQlICw60RhH8sHTDD/tJiiJrlAfNn8FDI9c+7G2F0SE=", "narHash": "sha256-vWrciFdq49vve43g4pbi7NjmL4cwG1ifXnQx+dU3T5E=",
"owner": "cachix", "owner": "cachix",
"repo": "devenv-nixpkgs", "repo": "devenv-nixpkgs",
"rev": "06fb0f1c643aee3ae6838dda3b37ef0abc3c763b", "rev": "829e73affeadfb4198a7105cbe3a03153d13edc9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -447,11 +447,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1712791164, "lastModified": 1712608508,
"narHash": "sha256-3sbWO1mbpWsLepZGbWaMovSO7ndZeFqDSdX0hZ9nVyw=", "narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "1042fd8b148a9105f3c0aca3a6177fd1d9360ba5", "rev": "4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -463,11 +463,11 @@
}, },
"nixpkgs_4": { "nixpkgs_4": {
"locked": { "locked": {
"lastModified": 1712791164, "lastModified": 1712608508,
"narHash": "sha256-3sbWO1mbpWsLepZGbWaMovSO7ndZeFqDSdX0hZ9nVyw=", "narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "1042fd8b148a9105f3c0aca3a6177fd1d9360ba5", "rev": "4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -543,11 +543,11 @@
"nixpkgs-stable": "nixpkgs-stable_2" "nixpkgs-stable": "nixpkgs-stable_2"
}, },
"locked": { "locked": {
"lastModified": 1712897695, "lastModified": 1712055707,
"narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=", "narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
"owner": "cachix", "owner": "cachix",
"repo": "pre-commit-hooks.nix", "repo": "pre-commit-hooks.nix",
"rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8", "rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -567,11 +567,11 @@
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1712818880, "lastModified": 1712663608,
"narHash": "sha256-VDxsvgj/bNypHq48tQWtc3VRbWvzlFjzKf9ZZIVO10Y=", "narHash": "sha256-tN9ZL6kGppmHg84lxlpAlaN+kXWNctKK7Yitq/iXDEw=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "657b33b0cb9bd49085202e91ad5b4676532c9140", "rev": "a5feb4f05f09adca661c869b1bf2324898cbaa43",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -15,7 +15,6 @@
self, self,
nixpkgs, nixpkgs,
devenv, devenv,
fenix,
systems, systems,
... ...
} @ inputs: let } @ inputs: let
@ -25,11 +24,6 @@
forEachSystem forEachSystem
(system: let (system: let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
toolchain = with fenix.packages.${system};
combine [
default.toolchain
rust-analyzer
];
in { in {
default = devenv.lib.mkShell { default = devenv.lib.mkShell {
inherit inputs pkgs; inherit inputs pkgs;
@ -39,18 +33,17 @@
config, config,
... ...
}: { }: {
# languages.rust = { languages.rust = {
# enable = true; enable = true;
# channel = "nightly"; channel = "nightly";
# components = [ components = [
# "rustc" "rustc"
# "cargo" "cargo"
# "clippy" "clippy"
# "rustfmt" "rustfmt"
# "rust-src" "rust-src"
# "rust-analyzer" ];
# ]; };
# };
pre-commit.hooks = { pre-commit.hooks = {
clippy.enable = false; clippy.enable = false;
@ -66,7 +59,7 @@
mold mold
cargo-nextest cargo-nextest
cargo-watch cargo-watch
toolchain rust-analyzer
]; ];
}) })
]; ];

View file

@ -1 +1,4 @@
hello world test 42 3.14 "uwu" meow mew meow 5 3.14 "uwu" {
meow: test 24
another: hi "hello",
} "awa"