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 118 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}