difftreelog
feat(parser) save ast expression location
in: master
2 files changed
crates/jsonnet-parser/src/expr.rsdiffbeforeafterboth1use std::fmt::Display;1use std::{2 fmt::{Debug, Display},3 rc::Rc,4};253#[derive(Debug, Clone, PartialEq)]6#[derive(Debug, Clone, PartialEq)]4pub enum FieldName {7pub enum FieldName {5 /// {fixed: 2}8 /// {fixed: 2}6 Fixed(String),9 Fixed(String),7 /// {["dyn"+"amic"]: 3}10 /// {["dyn"+"amic"]: 3}8 Dyn(Box<Expr>),11 Dyn(LocExpr),9}12}101311#[derive(Debug, Clone, PartialEq)]14#[derive(Debug, Clone, PartialEq)]19}22}202321#[derive(Debug, Clone, PartialEq)]24#[derive(Debug, Clone, PartialEq)]22pub struct AssertStmt(pub Box<Expr>, pub Option<Box<Expr>>);25pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);232624#[derive(Debug, Clone, PartialEq)]27#[derive(Debug, Clone, PartialEq)]25pub struct FieldMember {28pub struct FieldMember {26 pub name: FieldName,29 pub name: FieldName,27 pub plus: bool,30 pub plus: bool,28 pub params: Option<ParamsDesc>,31 pub params: Option<ParamsDesc>,29 pub visibility: Visibility,32 pub visibility: Visibility,30 pub value: Expr,33 pub value: LocExpr,31}34}323533#[derive(Debug, Clone, PartialEq)]36#[derive(Debug, Clone, PartialEq)]778078/// name, default value81/// name, default value79#[derive(Debug, Clone, PartialEq)]82#[derive(Debug, Clone, PartialEq)]80pub struct Param(pub String, pub Option<Box<Expr>>);83pub struct Param(pub String, pub Option<LocExpr>);81/// Defined function parameters84/// Defined function parameters82#[derive(Debug, Clone, PartialEq)]85#[derive(Debug, Clone, PartialEq)]83pub struct ParamsDesc(pub Vec<Param>);86pub struct ParamsDesc(pub Vec<Param>);88}91}899290#[derive(Debug, Clone, PartialEq)]93#[derive(Debug, Clone, PartialEq)]91pub struct Arg(pub Option<String>, pub Box<Expr>);94pub struct Arg(pub Option<String>, pub LocExpr);92#[derive(Debug, Clone, PartialEq)]95#[derive(Debug, Clone, PartialEq)]93pub struct ArgsDesc(pub Vec<Arg>);96pub struct ArgsDesc(pub Vec<Arg>);949795#[derive(Debug, Clone, PartialEq)]98#[derive(Debug, Clone, PartialEq)]96pub struct BindSpec {99pub struct BindSpec {97 pub name: String,100 pub name: String,98 pub params: Option<ParamsDesc>,101 pub params: Option<ParamsDesc>,99 pub value: Box<Expr>,102 pub value: LocExpr,100}103}101104102#[derive(Debug, Clone, PartialEq)]105#[derive(Debug, Clone, PartialEq)]103pub struct IfSpecData(pub Box<Expr>);106pub struct IfSpecData(pub LocExpr);104#[derive(Debug, Clone, PartialEq)]107#[derive(Debug, Clone, PartialEq)]105pub struct ForSpecData(pub String, pub Box<Expr>);108pub struct ForSpecData(pub String, pub LocExpr);106109107#[derive(Debug, Clone, PartialEq)]110#[derive(Debug, Clone, PartialEq)]108pub enum CompSpec {111pub enum CompSpec {115 MemberList(Vec<Member>),118 MemberList(Vec<Member>),116 ObjComp {119 ObjComp {117 pre_locals: Vec<BindSpec>,120 pre_locals: Vec<BindSpec>,118 key: Box<Expr>,121 key: LocExpr,119 value: Box<Expr>,122 value: LocExpr,120 post_locals: Vec<BindSpec>,123 post_locals: Vec<BindSpec>,121 first: ForSpecData,124 first: ForSpecData,122 rest: Vec<CompSpec>,125 rest: Vec<CompSpec>,147150148#[derive(Debug, Clone, PartialEq)]151#[derive(Debug, Clone, PartialEq)]149pub struct SliceDesc {152pub struct SliceDesc {150 pub start: Option<Box<Expr>>,153 pub start: Option<LocExpr>,151 pub end: Option<Box<Expr>>,154 pub end: Option<LocExpr>,152 pub step: Option<Box<Expr>>,155 pub step: Option<LocExpr>,153}156}154157155/// Syntax base158/// Syntax base165 Var(String),168 Var(String),166169167 /// Array of expressions: [1, 2, "Hello"]170 /// Array of expressions: [1, 2, "Hello"]168 Arr(Vec<Expr>),171 Arr(Vec<LocExpr>),169 /// Array comprehension:172 /// Array comprehension:170 /// ```jsonnet173 /// ```jsonnet171 /// ingredients: [174 /// ingredients: [177 /// ]180 /// ]178 /// ],181 /// ],179 /// ```182 /// ```180 ArrComp(Box<Expr>, ForSpecData, Vec<CompSpec>),183 ArrComp(LocExpr, ForSpecData, Vec<CompSpec>),181184182 /// Object: {a: 2}185 /// Object: {a: 2}183 Obj(ObjBody),186 Obj(ObjBody),184 /// Object extension: var1 {b: 2}187 /// Object extension: var1 {b: 2}185 ObjExtend(Box<Expr>, ObjBody),188 ObjExtend(LocExpr, ObjBody),186189187 /// (obj)190 /// (obj)188 Parened(Box<Expr>),191 Parened(LocExpr),189192190 /// Params in function definition193 /// Params in function definition191 /// hello, world, test = 2194 /// hello, world, test = 2195 Args(ArgsDesc),198 Args(ArgsDesc),196199197 /// -2200 /// -2198 UnaryOp(UnaryOpType, Box<Expr>),201 UnaryOp(UnaryOpType, LocExpr),199 /// 2 - 2202 /// 2 - 2200 BinaryOp(Box<Expr>, BinaryOpType, Box<Expr>),203 BinaryOp(LocExpr, BinaryOpType, LocExpr),201 /// assert 2 == 2 : "Math is broken"204 /// assert 2 == 2 : "Math is broken"202 AssertExpr(AssertStmt, Box<Expr>),205 AssertExpr(AssertStmt, LocExpr),203 /// local a = 2; { b: a }206 /// local a = 2; { b: a }204 LocalExpr(Vec<BindSpec>, Box<Expr>),207 LocalExpr(Vec<BindSpec>, LocExpr),205208206 /// a = 3209 /// a = 3207 Bind(BindSpec),210 Bind(BindSpec),210 /// importStr "file.txt"213 /// importStr "file.txt"211 ImportStr(String),214 ImportStr(String),212 /// error "I'm broken"215 /// error "I'm broken"213 Error(Box<Expr>),216 Error(LocExpr),214 /// a(b, c)217 /// a(b, c)215 Apply(Box<Expr>, ArgsDesc),218 Apply(LocExpr, ArgsDesc),216 ///219 ///217 Select(Box<Expr>, String),220 Select(LocExpr, String),218 /// a[b]221 /// a[b]219 Index(Box<Expr>, Box<Expr>),222 Index(LocExpr, LocExpr),220 /// a[1::2]223 /// a[1::2]221 Slice(Box<Expr>, SliceDesc),224 Slice(LocExpr, SliceDesc),222 /// function(x) x225 /// function(x) x223 Function(ParamsDesc, Box<Expr>),226 Function(ParamsDesc, LocExpr),224 /// if true == false then 1 else 2227 /// if true == false then 1 else 2225 IfElse {228 IfElse {226 cond: IfSpecData,229 cond: IfSpecData,227 cond_then: Box<Expr>,230 cond_then: LocExpr,228 cond_else: Option<Box<Expr>>,231 cond_else: Option<LocExpr>,229 },232 },230 /// if 2 = 3233 /// if 2 = 3231 IfSpec(IfSpecData),234 IfSpec(IfSpecData),232 /// for elem in array235 /// for elem in array233 ForSpec(ForSpecData),236 ForSpec(ForSpecData),234}237}238239/// file, begin offset, end offset240#[derive(Clone, PartialEq)]241pub struct ExprLocation(pub String, pub usize, pub usize);242impl Debug for ExprLocation {243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {244 write!(f, "{}:{:?}", self.0, self.1)245 }246}247248/// Holds AST expression and its location in source file+249#[derive(Clone, PartialEq)]250pub struct LocExpr(pub Rc<Expr>, pub Option<Rc<ExprLocation>>);251impl Debug for LocExpr {252 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {253 write!(f, "{:?} from {:?}", self.0, self.1)254 }255}256257/// Creates LocExpr from Expr and ExprLocation components258#[macro_export]259macro_rules! loc_expr {260 ($expr:expr, $need_loc:expr, ($name:expr, $start:expr, $end:expr)) => {261 LocExpr(262 Rc::new($expr),263 if $need_loc {264 Some(Rc::new(ExprLocation($name.to_owned(), $start, $end)))265 } else {266 None267 },268 )269 };270}271272/// Creates LocExpr without location info273#[macro_export]274macro_rules! loc_expr_todo {275 ($expr:expr) => {276 LocExpr(Rc::new($expr), None)277 };278}235279crates/jsonnet-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jsonnet-parser/src/lib.rs
+++ b/crates/jsonnet-parser/src/lib.rs
@@ -1,18 +1,24 @@
#![feature(box_syntax)]
use peg::parser;
-
+use std::rc::Rc;
mod expr;
pub use expr::*;
enum Suffix {
String(String),
Slice(SliceDesc),
- Expression(Expr),
+ Expression(LocExpr),
Apply(expr::ArgsDesc),
Extend(expr::ObjBody),
}
+struct LocSuffix(Suffix, ExprLocation);
+pub struct ParserSettings {
+ pub loc_data: bool,
+ pub file_name: String,
+}
+
parser! {
grammar jsonnet_parser() for str {
use peg::ParseLiteral;
@@ -34,11 +40,13 @@
/// Reserved word followed by any non-alphanumberic
rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()
rule id() -> String = quiet!{ !reserved() s:$(alpha() (alpha() / digit())*) {s.to_owned()}} / expected!("<identifier>")
+
rule keyword(id: &'static str) = ##parse_string_literal(id) end_of_ident()
+ rule l(s: &ParserSettings, x: rule<Expr>) -> LocExpr = start:position!() v:x() end:position!() {loc_expr!(v, s.loc_data, (s.file_name.clone(), start, end))}
- pub rule param() -> expr::Param = name:id() expr:(_ "=" _ expr:boxed_expr(){expr})? { expr::Param(name, expr) }
- pub rule params() -> expr::ParamsDesc
- = params:(param() ** comma()) {
+ pub rule param(s: &ParserSettings) -> expr::Param = name:id() expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }
+ pub rule params(s: &ParserSettings) -> expr::ParamsDesc
+ = params:(param(s) ** comma()) {
let mut defaults_started = false;
for param in ¶ms {
defaults_started = defaults_started || param.1.is_some();
@@ -48,11 +56,11 @@
}
/ { expr::ParamsDesc(Vec::new()) }
- pub rule arg() -> expr::Arg
- = name:id() _ "=" _ expr:boxed_expr() {expr::Arg(Some(name), expr)}
- / expr:boxed_expr() {expr::Arg(None, expr)}
- pub rule args() -> expr::ArgsDesc
- = args:arg() ** comma() comma()? {
+ pub rule arg(s: &ParserSettings) -> expr::Arg
+ = name:id() _ "=" _ expr:expr(s) {expr::Arg(Some(name), expr)}
+ / expr:expr(s) {expr::Arg(None, expr)}
+ pub rule args(s: &ParserSettings) -> expr::ArgsDesc
+ = args:arg(s) ** comma() comma()? {
let mut named_started = false;
for arg in &args {
named_started = named_started || arg.0.is_some();
@@ -62,44 +70,44 @@
}
/ { expr::ArgsDesc(Vec::new()) }
- pub rule bind() -> expr::BindSpec
- = name:id() _ "=" _ expr:boxed_expr() {expr::BindSpec{name, params: None, value: expr}}
- / name:id() _ "(" _ params:params() _ ")" _ "=" _ expr:boxed_expr() {expr::BindSpec{name, params: Some(params), value: expr}}
- pub rule assertion() -> expr::AssertStmt = keyword("assert") _ cond:boxed_expr() msg:(_ ":" _ e:boxed_expr() {e})? { expr::AssertStmt(cond, msg) }
+ pub rule bind(s: &ParserSettings) -> expr::BindSpec
+ = name:id() _ "=" _ expr:expr(s) {expr::BindSpec{name, params: None, value: expr}}
+ / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec{name, params: Some(params), value: expr}}
+ pub rule assertion(s: &ParserSettings) -> expr::AssertStmt = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }
pub rule string() -> String
= "\"" str:$(("\\\"" / !['"'][_])*) "\"" {str.to_owned()}
/ "'" str:$((!['\''][_])*) "'" {str.to_owned()}
- pub rule field_name() -> expr::FieldName
+ pub rule field_name(s: &ParserSettings) -> expr::FieldName
= name:id() {expr::FieldName::Fixed(name)}
/ name:string() {expr::FieldName::Fixed(name)}
- / "[" _ expr:boxed_expr() _ "]" {expr::FieldName::Dyn(expr)}
+ / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}
pub rule visibility() -> expr::Visibility
= ":::" {expr::Visibility::Unhide}
/ "::" {expr::Visibility::Hidden}
/ ":" {expr::Visibility::Normal}
- pub rule field() -> expr::FieldMember
- = name:field_name() _ plus:"+"? _ visibility:visibility() _ value:expr() {expr::FieldMember{
+ pub rule field(s: &ParserSettings) -> expr::FieldMember
+ = name:field_name(s) _ plus:"+"? _ visibility:visibility() _ value:expr(s) {expr::FieldMember{
name,
plus: plus.is_some(),
params: None,
visibility,
value,
}}
- / name:field_name() _ "(" _ params:params() _ ")" _ visibility:visibility() _ value:expr() {expr::FieldMember{
+ / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{
name,
plus: false,
params: Some(params),
visibility,
value,
}}
- pub rule obj_local() -> BindSpec
- = keyword("local") _ bind:bind() {bind}
- pub rule member() -> expr::Member
- = bind:obj_local() {expr::Member::BindStmt(bind)}
- / assertion:assertion() {expr::Member::AssertStmt(assertion)}
- / field:field() {expr::Member::Field(field)}
- pub rule objinside() -> expr::ObjBody
- = pre_locals:(b: obj_local() comma() {b})* "[" _ key:boxed_expr() _ "]" _ ":" _ value:boxed_expr() post_locals:(comma() b:obj_local() {b})* _ first:forspec() rest:(_ rest:compspec() {rest})? {
+ pub rule obj_local(s: &ParserSettings) -> BindSpec
+ = keyword("local") _ bind:bind(s) {bind}
+ pub rule member(s: &ParserSettings) -> expr::Member
+ = bind:obj_local(s) {expr::Member::BindStmt(bind)}
+ / assertion:assertion(s) {expr::Member::AssertStmt(assertion)}
+ / field:field(s) {expr::Member::Field(field)}
+ pub rule objinside(s: &ParserSettings) -> expr::ObjBody
+ = pre_locals:(b: obj_local(s) comma() {b})* "[" _ key:expr(s) _ "]" _ ":" _ value:expr(s) post_locals:(comma() b:obj_local(s) {b})* _ first:forspec(s) rest:(_ rest:compspec(s) {rest})? {
expr::ObjBody::ObjComp {
pre_locals,
key,
@@ -109,73 +117,69 @@
rest: rest.unwrap_or_default(),
}
}
- / members:(member() ** comma()) comma()? {expr::ObjBody::MemberList(members)}
- pub rule ifspec() -> IfSpecData = keyword("if") _ expr:boxed_expr() {IfSpecData(expr)}
- pub rule forspec() -> ForSpecData = keyword("for") _ id:id() _ keyword("in") _ cond:boxed_expr() {ForSpecData(id, cond)}
- pub rule compspec() -> Vec<expr::CompSpec> = s:(i:ifspec() { expr::CompSpec::IfSpec(i) } / f:forspec() {expr::CompSpec::ForSpec(f)} )+ {s}
- pub rule bind_expr() -> Expr = bind:bind() {Expr::Bind(bind)}
- pub rule local_expr() -> Expr = keyword("local") _ binds:bind() ** comma() _ ";" _ expr:boxed_expr() { Expr::LocalExpr(binds, expr) }
- pub rule string_expr() -> Expr = s:string() {Expr::Str(s)}
- pub rule parened_expr() -> Expr = "(" e:boxed_expr() ")" {Expr::Parened(e)}
- pub rule obj_expr() -> Expr = "{" _ body:objinside() _ "}" {Expr::Obj(body)}
- pub rule array_expr() -> Expr = "[" _ elems:(expr() ** comma()) _ comma()? "]" {Expr::Arr(elems)}
- pub rule array_comp_expr() -> Expr = "[" _ expr:boxed_expr() _ comma()? _ forspec:forspec() _ others:(others: compspec() _ {others})? "]" {Expr::ArrComp(expr, forspec, others.unwrap_or_default())}
- pub rule index_expr() -> Expr
- = val:boxed_expr() "." idx:id() {Expr::Index(val, Box::new(Expr::Str(idx)))}
- / val:boxed_expr() "[" key:boxed_expr() "]" {Expr::Index(val, key)}
- pub rule number_expr() -> Expr = n:number() { expr::Expr::Num(n) }
- pub rule var_expr() -> Expr = n:id() { expr::Expr::Var(n) }
- pub rule if_then_else_expr() -> Expr = cond:ifspec() _ keyword("then") _ cond_then:boxed_expr() cond_else:(_ keyword("else") _ e:boxed_expr() {e})? {Expr::IfElse{
+ / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)}
+ pub rule ifspec(s: &ParserSettings) -> IfSpecData = keyword("if") _ expr:expr(s) {IfSpecData(expr)}
+ pub rule forspec(s: &ParserSettings) -> ForSpecData = keyword("for") _ id:id() _ keyword("in") _ cond:expr(s) {ForSpecData(id, cond)}
+ pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec> = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} )+ {s}
+ pub rule local_expr(s: &ParserSettings) -> LocExpr = l(s,<keyword("local") _ binds:bind(s) ** comma() _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, expr) }>)
+ pub rule string_expr(s: &ParserSettings) -> LocExpr = l(s, <s:string() {Expr::Str(s)}>)
+ pub rule obj_expr(s: &ParserSettings) -> LocExpr = l(s,<"{" _ body:objinside(s) _ "}" {Expr::Obj(body)}>)
+ pub rule array_expr(s: &ParserSettings) -> LocExpr = l(s,<"[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}>)
+ pub rule array_comp_expr(s: &ParserSettings) -> LocExpr = l(s,<"[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {Expr::ArrComp(expr, forspec, others.unwrap_or_default())}>)
+ pub rule number_expr(s: &ParserSettings) -> LocExpr = l(s,<n:number() { expr::Expr::Num(n) }>)
+ pub rule var_expr(s: &ParserSettings) -> LocExpr = l(s,<n:id() { expr::Expr::Var(n) }>)
+ pub rule if_then_else_expr(s: &ParserSettings) -> LocExpr = l(s,<cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{
cond,
cond_then,
cond_else,
- }}
+ }}>)
- pub rule literal() -> Expr
- = v:(
+ pub rule literal(s: &ParserSettings) -> LocExpr
+ = l(s,<v:(
keyword("null") {LiteralType::Null}
/ keyword("true") {LiteralType::True}
/ keyword("false") {LiteralType::False}
/ keyword("self") {LiteralType::This}
/ keyword("$") {LiteralType::Dollar}
/ keyword("super") {LiteralType::Super}
- ) {Expr::Literal(v)}
+ ) {Expr::Literal(v)}>)
- pub rule expr_basic() -> Expr
- = literal()
+ pub rule expr_basic(s: &ParserSettings) -> LocExpr
+ = literal(s)
- / string_expr() / number_expr()
- / array_expr()
- / obj_expr()
- / array_expr()
- / array_comp_expr()
+ / string_expr(s) / number_expr(s)
+ / array_expr(s)
+ / obj_expr(s)
+ / array_expr(s)
+ / array_comp_expr(s)
- / var_expr()
- / local_expr()
- / if_then_else_expr()
+ / var_expr(s)
+ / local_expr(s)
+ / if_then_else_expr(s)
- / keyword("function") _ "(" _ params:params() _ ")" _ expr:boxed_expr() {Expr::Function(params, expr)}
- / assertion:assertion() _ ";" _ expr:boxed_expr() { Expr::AssertExpr(assertion, expr) }
+ / l(s,<keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, expr)}>)
+ / l(s,<assertion:assertion(s) _ ";" _ expr:expr(s) { Expr::AssertExpr(assertion, expr) }>)
- / keyword("error") _ expr:boxed_expr() { Expr::Error(expr) }
+ / l(s,<keyword("error") _ expr:expr(s) { Expr::Error(expr) }>)
- rule expr_basic_with_suffix() -> Expr
- = a:expr_basic() suffixes:(_ suffix:expr_suffix() {suffix})* {
+ rule expr_basic_with_suffix(s: &ParserSettings) -> LocExpr
+ = a:expr_basic(s) suffixes:(_ suffix:l_expr_suffix(s) {suffix})* {
let mut cur = a;
for suffix in suffixes {
- cur = match suffix {
- Suffix::String(index) => Expr::Index(Box::new(cur), Box::new(Expr::Str(index))),
- Suffix::Slice(desc) => Expr::Slice(Box::new(cur), desc),
- Suffix::Expression(index) => Expr::Index(Box::new(cur), Box::new(index)),
- Suffix::Apply(args) => Expr::Apply(Box::new(cur), args),
- Suffix::Extend(body) => Expr::ObjExtend(box cur, body),
- }
+ let LocSuffix(suffix, location) = suffix;
+ cur = LocExpr(Rc::new(match suffix {
+ Suffix::String(index) => Expr::Index(cur, loc_expr!(Expr::Str(index), s.loc_data, (s.file_name.clone(), location.1, location.2))),
+ Suffix::Slice(desc) => Expr::Slice(cur, desc),
+ Suffix::Expression(index) => Expr::Index(cur, index),
+ Suffix::Apply(args) => Expr::Apply(cur, args),
+ Suffix::Extend(body) => Expr::ObjExtend(cur, body),
+ }), if s.loc_data { Some(Rc::new(location)) } else { None })
}
cur
}
- pub rule slice_desc() -> SliceDesc
- = start:boxed_expr()? _ ":" _ pair:(end:boxed_expr()? _ step:(":" _ e:boxed_expr() {e})? {(end, step)})? {
+ pub rule slice_desc(s: &ParserSettings) -> SliceDesc
+ = start:expr(s)? _ ":" _ pair:(end:expr(s)? _ step:(":" _ e:expr(s) {e})? {(end, step)})? {
if let Some((end, step)) = pair {
SliceDesc { start, end, step }
}else{
@@ -183,115 +187,144 @@
}
}
- rule expr_suffix() -> Suffix
+ rule expr_suffix(s: &ParserSettings) -> Suffix
= "." _ s:id() { Suffix::String(s) }
- / "[" _ s:slice_desc() _ "]" { Suffix::Slice(s) }
- / "[" _ s:expr() _ "]" { Suffix::Expression(s) }
- / "(" _ args:args() _ ")" (_ keyword("tailstrict"))? { Suffix::Apply(args) }
- / "{" _ body:objinside() _ "}" { Suffix::Extend(body) }
+ / "[" _ s:slice_desc(s) _ "]" { Suffix::Slice(s) }
+ / "[" _ s:expr(s) _ "]" { Suffix::Expression(s) }
+ / "(" _ args:args(s) _ ")" (_ keyword("tailstrict"))? { Suffix::Apply(args) }
+ / "{" _ body:objinside(s) _ "}" { Suffix::Extend(body) }
+ rule l_expr_suffix(s: &ParserSettings) -> LocSuffix
+ = start:position!() suffix:expr_suffix(s) end:position!() {LocSuffix(suffix, ExprLocation(s.file_name.clone(), start, end))}
- rule expr() -> Expr
- = a:precedence! {
- a:(@) _ "||" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Or, Box::new(b))}
+ rule expr(s: &ParserSettings) -> LocExpr
+ = start:position!() a:precedence! {
+ a:(@) _ "||" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Or, b))}
--
- a:(@) _ "&&" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::And, Box::new(b))}
+ a:(@) _ "&&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::And, b))}
--
- a:(@) _ "|" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::BitOr, Box::new(b))}
+ a:(@) _ "|" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitOr, b))}
--
- a:@ _ "^" _ b:(@) {Expr::BinaryOp(Box::new(a), BinaryOpType::BitXor, Box::new(b))}
+ a:@ _ "^" _ b:(@) {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitXor, b))}
--
- a:(@) _ "&" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::BitAnd, Box::new(b))}
+ a:(@) _ "&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitAnd, b))}
--
- a:(@) _ "==" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Eq, Box::new(b))}
- a:(@) _ "!=" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Ne, Box::new(b))}
+ a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Eq, b))}
+ a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Ne, b))}
--
- a:(@) _ "<" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Lt, Box::new(b))}
- a:(@) _ ">" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Gt, Box::new(b))}
- a:(@) _ "<=" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Lte, Box::new(b))}
- a:(@) _ ">=" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Gte, Box::new(b))}
+ a:(@) _ "<" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lt, b))}
+ a:(@) _ ">" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gt, b))}
+ a:(@) _ "<=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lte, b))}
+ a:(@) _ ">=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gte, b))}
--
- a:(@) _ "<<" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Lhs, Box::new(b))}
- a:(@) _ ">>" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Rhs, Box::new(b))}
+ a:(@) _ "<<" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lhs, b))}
+ a:(@) _ ">>" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Rhs, b))}
--
- a:(@) _ "+" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Add, Box::new(b))}
- a:(@) _ "-" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Sub, Box::new(b))}
+ a:(@) _ "+" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Add, b))}
+ a:(@) _ "-" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Sub, b))}
--
- a:(@) _ "*" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Mul, Box::new(b))}
- a:(@) _ "/" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Div, Box::new(b))}
- a:(@) _ "%" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Mod, Box::new(b))}
+ a:(@) _ "*" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Mul, b))}
+ a:(@) _ "/" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Div, b))}
+ a:(@) _ "%" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Mod, b))}
--
- e:expr_basic_with_suffix() {e}
- "-" _ expr:expr_basic_with_suffix() { Expr::UnaryOp(UnaryOpType::Minus, box expr) }
- "!" _ expr:expr_basic_with_suffix() { Expr::UnaryOp(UnaryOpType::Not, box expr) }
- "(" _ e:boxed_expr() _ ")" {Expr::Parened(e)}
+ e:expr_basic_with_suffix(s) {e}
+ "-" _ expr:expr_basic_with_suffix(s) { loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Minus, expr)) }
+ "!" _ expr:expr_basic_with_suffix(s) { loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Not, expr)) }
+ "(" _ e:expr(s) _ ")" {loc_expr_todo!(Expr::Parened(e))}
+ } end:position!() {
+ let LocExpr(e, _) = a;
+ LocExpr(e, if s.loc_data {
+ Some(Rc::new(ExprLocation(s.file_name.to_owned(), start, end)))
+ } else {
+ None
+ })
}
- / e:expr_basic_with_suffix() {e}
+ / e:expr_basic_with_suffix(s) {e}
- pub rule boxed_expr() -> Box<Expr> = e:expr() {Box::new(e)}
- pub rule jsonnet() -> Expr = _ e:expr() _ {e}
+ pub rule jsonnet(s: &ParserSettings) -> LocExpr = _ e:expr(s) _ {e}
}
}
// TODO: impl FromStr from Expr
-pub fn parse(str: &str) -> Result<Expr, peg::error::ParseError<peg::str::LineCol>> {
- jsonnet_parser::jsonnet(str)
+pub fn parse(
+ str: &str,
+ settings: &ParserSettings,
+) -> Result<LocExpr, peg::error::ParseError<peg::str::LineCol>> {
+ jsonnet_parser::jsonnet(str, settings)
}
#[cfg(test)]
pub mod tests {
use super::{expr::*, parse};
+ use crate::ParserSettings;
+ macro_rules! el {
+ ($expr:expr) => {
+ LocExpr(std::rc::Rc::new($expr), None)
+ };
+ }
+ macro_rules! parse {
+ ($s:expr) => {
+ parse(
+ $s,
+ &ParserSettings {
+ loc_data: false,
+ file_name: "test.jsonnet".to_owned(),
+ },
+ )
+ .unwrap()
+ };
+ }
mod expressions {
use super::*;
- pub fn basic_math() -> Expr {
- Expr::BinaryOp(
- Box::new(Expr::Num(2.0)),
+ pub fn basic_math() -> LocExpr {
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(2.0)),
BinaryOpType::Add,
- Box::new(Expr::BinaryOp(
- Box::new(Expr::Num(2.0)),
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(2.0)),
BinaryOpType::Mul,
- Box::new(Expr::Num(2.0)),
+ el!(Expr::Num(2.0)),
)),
- )
+ ))
}
}
#[test]
fn empty_object() {
- assert_eq!(parse("{}").unwrap(), Expr::Obj(ObjBody::MemberList(vec![])));
+ assert_eq!(parse!("{}"), el!(Expr::Obj(ObjBody::MemberList(vec![]))));
}
#[test]
fn basic_math() {
assert_eq!(
- parse("2+2*2").unwrap(),
- Expr::BinaryOp(
- Box::new(Expr::Num(2.0)),
+ parse!("2+2*2"),
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(2.0)),
BinaryOpType::Add,
- Box::new(Expr::BinaryOp(
- Box::new(Expr::Num(2.0)),
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(2.0)),
BinaryOpType::Mul,
- Box::new(Expr::Num(2.0))
+ el!(Expr::Num(2.0))
))
- )
+ ))
);
}
#[test]
fn basic_math_with_indents() {
- assert_eq!(parse("2 + 2 * 2 ").unwrap(), expressions::basic_math());
+ assert_eq!(parse!("2 + 2 * 2 "), expressions::basic_math());
}
#[test]
fn basic_math_parened() {
assert_eq!(
- parse("2+(2+2*2)").unwrap(),
- Expr::BinaryOp(
- Box::new(Expr::Num(2.0)),
+ parse!("2+(2+2*2)"),
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(2.0)),
BinaryOpType::Add,
- Box::new(Expr::Parened(Box::new(expressions::basic_math()))),
- )
+ el!(Expr::Parened(expressions::basic_math())),
+ ))
);
}
@@ -299,12 +332,16 @@
#[test]
fn comments() {
assert_eq!(
- parse("2//comment\n+//comment\n3/*test*/*/*test*/4").unwrap(),
- Expr::BinaryOp(
- box Expr::Num(2.0),
+ parse!("2//comment\n+//comment\n3/*test*/*/*test*/4"),
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(2.0)),
BinaryOpType::Add,
- box Expr::BinaryOp(box Expr::Num(3.0), BinaryOpType::Mul, box Expr::Num(4.0))
- )
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(3.0)),
+ BinaryOpType::Mul,
+ el!(Expr::Num(4.0))
+ ))
+ ))
);
}
@@ -312,8 +349,12 @@
#[test]
fn comment_escaping() {
assert_eq!(
- parse("2/*\\*/+*/ - 22").unwrap(),
- Expr::BinaryOp(box Expr::Num(2.0), BinaryOpType::Sub, box Expr::Num(22.0))
+ parse!("2/*\\*/+*/ - 22"),
+ el!(Expr::BinaryOp(
+ el!(Expr::Num(2.0)),
+ BinaryOpType::Sub,
+ el!(Expr::Num(22.0))
+ ))
);
}
@@ -321,15 +362,18 @@
fn suffix_comparsion() {
use Expr::*;
assert_eq!(
- parse("std.type(a) == \"string\"").unwrap(),
- BinaryOp(
- box Apply(
- box Index(box Var("std".to_owned()), box Str("type".to_owned())),
- ArgsDesc(vec![Arg(None, box Var("a".to_owned()))])
- ),
+ parse!("std.type(a) == \"string\""),
+ el!(BinaryOp(
+ el!(Apply(
+ el!(Index(
+ el!(Var("std".to_owned())),
+ el!(Str("type".to_owned()))
+ )),
+ ArgsDesc(vec![Arg(None, el!(Var("a".to_owned())))])
+ )),
BinaryOpType::Eq,
- box Str("string".to_owned())
- )
+ el!(Str("string".to_owned()))
+ ))
);
}
@@ -337,15 +381,18 @@
fn array_comp() {
use Expr::*;
assert_eq!(
- parse("[std.deepJoin(x) for x in arr]").unwrap(),
- ArrComp(
- box Apply(
- box Index(box Var("std".to_owned()), box Str("deepJoin".to_owned())),
- ArgsDesc(vec![Arg(None, box Var("x".to_owned()))])
- ),
- ForSpecData("x".to_owned(), box Var("arr".to_owned())),
+ parse!("[std.deepJoin(x) for x in arr]"),
+ el!(ArrComp(
+ el!(Apply(
+ el!(Index(
+ el!(Var("std".to_owned())),
+ el!(Str("deepJoin".to_owned()))
+ )),
+ ArgsDesc(vec![Arg(None, el!(Var("x".to_owned())))])
+ )),
+ ForSpecData("x".to_owned(), el!(Var("arr".to_owned()))),
vec![]
- ),
+ )),
)
}
@@ -353,55 +400,58 @@
fn array_comp_with_ifs() {
use Expr::*;
assert_eq!(
- parse("[k for k in std.objectFields(patch) if patch[k] == null]").unwrap(),
- ArrComp(
- box Var("k".to_owned()),
+ parse!("[k for k in std.objectFields(patch) if patch[k] == null]"),
+ el!(ArrComp(
+ el!(Var("k".to_owned())),
ForSpecData(
"k".to_owned(),
- box Apply(
- box Index(
- box Var("std".to_owned()),
- box Str("objectFields".to_owned())
- ),
- ArgsDesc(vec![Arg(None, box Var("patch".to_owned()))])
- )
+ el!(Apply(
+ el!(Index(
+ el!(Var("std".to_owned())),
+ el!(Str("objectFields".to_owned()))
+ )),
+ ArgsDesc(vec![Arg(None, el!(Var("patch".to_owned())))])
+ ))
),
- vec![CompSpec::IfSpec(IfSpecData(box BinaryOp(
- box Index(box Var("patch".to_owned()), box Var("k".to_owned())),
+ vec![CompSpec::IfSpec(IfSpecData(el!(BinaryOp(
+ el!(Index(
+ el!(Var("patch".to_owned())),
+ el!(Var("k".to_owned()))
+ )),
BinaryOpType::Eq,
- box Literal(LiteralType::Null)
- )))]
- ),
+ el!(Literal(LiteralType::Null))
+ ))))]
+ ))
);
}
#[test]
fn reserved() {
use Expr::*;
- assert_eq!(parse("null").unwrap(), Literal(LiteralType::Null));
- assert_eq!(parse("nulla").unwrap(), Var("nulla".to_owned()));
+ assert_eq!(parse!("null"), el!(Literal(LiteralType::Null)));
+ assert_eq!(parse!("nulla"), el!(Var("nulla".to_owned())));
}
#[test]
fn multiple_args_buf() {
- parse("a(b, null_fields)").unwrap();
+ parse!("a(b, null_fields)");
}
#[test]
fn infix_precedence() {
use Expr::*;
assert_eq!(
- parse("!a && !b").unwrap(),
- BinaryOp(
- box UnaryOp(UnaryOpType::Not, box Var("a".to_owned())),
+ parse!("!a && !b"),
+ el!(BinaryOp(
+ el!(UnaryOp(UnaryOpType::Not, el!(Var("a".to_owned())))),
BinaryOpType::And,
- box UnaryOp(UnaryOpType::Not, box Var("b".to_owned()))
- )
+ el!(UnaryOp(UnaryOpType::Not, el!(Var("b".to_owned()))))
+ ))
);
}
#[test]
fn can_parse_stdlib() {
- parse(jsonnet_stdlib::STDLIB_STR).unwrap();
+ parse!(jsonnet_stdlib::STDLIB_STR);
}
}