git.delta.rocks / jrsonnet / refs/commits / 6314afd4640f

difftreelog

source

crates/jrsonnet-ir-parser/src/lib.rs3.8 KiBsourcehistory
1use std::rc::Rc;23use insta::assert_snapshot;4use jrsonnet_gcmodule::Acyclic;5use jrsonnet_ir::{6	AssertExpr, AssertStmt, Expr, IfElse, IfSpecData, LiteralType, Slice, SliceDesc, Source,7	SourceVirtual, Span, Spanned,8};9use jrsonnet_lexer::{Lexeme, Lexer, SyntaxKind, T};1011struct Parser<'a> {12	lexemes: Vec<Lexeme<'a>>,13	offset: usize,14	source: Source,15}1617impl<'a> Parser<'a> {18	fn new(s: &'a str) -> Self {19		Self {20			lexemes: Lexer::new(s)21				.filter(|l| l.kind != SyntaxKind::WHITESPACE)22				.collect(),23			offset: 0,24			source: Source::new_virtual("<test>".into(), s.into()),25		}26	}27	fn peek(&self) -> SyntaxKind {28		self.lexemes[self.offset].kind29	}30	fn text(&self) -> &str {31		self.lexemes[self.offset].text32	}33	fn at(&self, kind: SyntaxKind) -> bool {34		!self.at_eof() && self.peek() == kind35	}36	fn eat_any(&mut self) {37		self.offset += 138	}3940	fn at_eof(&self) -> bool {41		self.offset == self.lexemes.len()42	}4344	fn try_eat(&mut self, t: SyntaxKind) -> bool {45		if self.at(t) {46			self.eat_any();47			return true;48		}49		false50	}51	fn eat(&mut self, t: SyntaxKind) {52		assert_eq!(self.peek(), t);53		self.eat_any();54	}5556	fn span_start(&self) -> u32 {57		self.lexemes[self.offset].range.058	}59	fn span_end(&self) -> u32 {60		self.lexemes[self.offset - 1].range.161	}62}6364fn literal(p: &mut Parser<'_>) -> Option<LiteralType> {65	let t = match p.peek() {66		T![self] => LiteralType::This,67		T![super] => LiteralType::Super,68		T!['$'] => LiteralType::Dollar,69		T![null] => LiteralType::Null,70		T![true] => LiteralType::True,71		T![false] => LiteralType::False,72		_ => return None,73	};74	p.eat_any();75	Some(t)76}7778fn spanned<T: Acyclic>(p: &mut Parser<'_>, cb: impl FnOnce(&mut Parser<'_>) -> T) -> Spanned<T> {79	let start = p.span_start();80	let v = cb(p);81	let end = p.span_end();8283	Spanned::new(v, Span(p.source.clone(), start, end))84}8586fn assert_stmt(p: &mut Parser<'_>) -> AssertStmt {87	p.eat(T![assert]);88	let cond = spanned(p, expr);89	dbg!(p.peek());90	let msg = if p.try_eat(T![:]) {91		Some(spanned(p, expr))92	} else {93		None94	};95	dbg!(AssertStmt(cond, msg))96}9798fn if_spec_data(p: &mut Parser<'_>) -> IfSpecData {99	let v = spanned(p, |p| p.eat(T![if]));100	let cond = expr(p);101	IfSpecData { span: v.span, cond }102}103104fn if_else(p: &mut Parser<'_>) -> IfElse {105	let cond = if_spec_data(p);106	p.eat(T![then]);107	let cond_then = expr(p);108	let cond_else = if p.at(T![else]) { Some(expr(p)) } else { None };109	IfElse {110		cond,111		cond_then,112		cond_else,113	}114}115116fn slice_desc(p: &mut Parser<'_>, start: Option<Spanned<Expr>>) -> SliceDesc {117	// start118	p.eat(T![:]);119	let end = if !p.at(T![:]) && !p.at(T![']']) {120		Some(spanned(p, expr))121	} else {122		None123	};124	let step = if p.try_eat(T![:]) && !p.at(T![']']) {125		Some(spanned(p, expr))126	} else {127		None128	};129	SliceDesc { start, end, step }130}131132fn expr_simple(p: &mut Parser<'_>) -> Expr {133	let mut e = if let Some(literal) = literal(p) {134		Expr::Literal(literal)135	} else if p.at(T![assert]) {136		let assert = assert_stmt(p);137		p.eat(T![;]);138		let rest = expr(p);139		Expr::AssertExpr(Rc::new(AssertExpr { assert, rest }))140	} else if p.at(T![if]) {141		Expr::IfElse(Box::new(if_else(p)))142	} else {143		panic!("unexpected token: {:?}", p.peek());144	};145146	dbg!(&e);147148	loop {149		if p.try_eat(T!['[']) {150			if p.at(T![:]) {151				let slice = slice_desc(p, None);152				e = Expr::Slice(Box::new(Slice { value: e, slice }));153				p.eat(T![']']);154				continue;155			}156157			let idx = spanned(p, expr);158			if p.at(T![:]) {159				let slice = slice_desc(p, Some(idx));160				e = Expr::Slice(Box::new(Slice { value: e, slice }));161			} else {162			}163			p.eat(T![']']);164		} else {165			break;166		}167	}168169	dbg!(e)170}171172fn expr(p: &mut Parser<'_>) -> Expr {173	expr_simple(p)174}175176#[test]177fn basic_test() {178	let mut parser = Parser::new(" assert true[false] : false ; true ");179	let e = expr(&mut parser);180	let l = &parser.lexemes;181182	assert_snapshot!(format!("{l:#?}\n\n---\n\n{e:#?}"));183}