git.delta.rocks / jrsonnet / refs/commits / c4387b31b01a

difftreelog

feat(parser) save ast expression location

Лач2020-06-01parent: #ad8b59d.patch.diff
in: master

2 files changed

modifiedcrates/jsonnet-parser/src/expr.rsdiffbeforeafterboth
1use std::fmt::Display;1use std::{
2 fmt::{Debug, Display},
3 rc::Rc,
4};
25
3#[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}
1013
11#[derive(Debug, Clone, PartialEq)]14#[derive(Debug, Clone, PartialEq)]
19}22}
2023
21#[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>);
2326
24#[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}
3235
33#[derive(Debug, Clone, PartialEq)]36#[derive(Debug, Clone, PartialEq)]
7780
78/// name, default value81/// name, default value
79#[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 parameters
82#[derive(Debug, Clone, PartialEq)]85#[derive(Debug, Clone, PartialEq)]
83pub struct ParamsDesc(pub Vec<Param>);86pub struct ParamsDesc(pub Vec<Param>);
88}91}
8992
90#[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>);
9497
95#[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}
101104
102#[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);
106109
107#[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>,
147150
148#[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}
154157
155/// Syntax base158/// Syntax base
165 Var(String),168 Var(String),
166169
167 /// 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 /// ```jsonnet
171 /// ingredients: [174 /// ingredients: [
177 /// ]180 /// ]
178 /// ],181 /// ],
179 /// ```182 /// ```
180 ArrComp(Box<Expr>, ForSpecData, Vec<CompSpec>),183 ArrComp(LocExpr, ForSpecData, Vec<CompSpec>),
181184
182 /// 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),
186189
187 /// (obj)190 /// (obj)
188 Parened(Box<Expr>),191 Parened(LocExpr),
189192
190 /// Params in function definition193 /// Params in function definition
191 /// hello, world, test = 2194 /// hello, world, test = 2
195 Args(ArgsDesc),198 Args(ArgsDesc),
196199
197 /// -2200 /// -2
198 UnaryOp(UnaryOpType, Box<Expr>),201 UnaryOp(UnaryOpType, LocExpr),
199 /// 2 - 2202 /// 2 - 2
200 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),
205208
206 /// a = 3209 /// a = 3
207 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) x
223 Function(ParamsDesc, Box<Expr>),226 Function(ParamsDesc, LocExpr),
224 /// if true == false then 1 else 2227 /// if true == false then 1 else 2
225 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 = 3
231 IfSpec(IfSpecData),234 IfSpec(IfSpecData),
232 /// for elem in array235 /// for elem in array
233 ForSpec(ForSpecData),236 ForSpec(ForSpecData),
234}237}
238
239/// file, begin offset, end offset
240#[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}
247
248/// 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}
256
257/// Creates LocExpr from Expr and ExprLocation components
258#[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 None
267 },
268 )
269 };
270}
271
272/// Creates LocExpr without location info
273#[macro_export]
274macro_rules! loc_expr_todo {
275 ($expr:expr) => {
276 LocExpr(Rc::new($expr), None)
277 };
278}
235279
modifiedcrates/jsonnet-parser/src/lib.rsdiffbeforeafterboth
1#![feature(box_syntax)]1#![feature(box_syntax)]
22
3use peg::parser;3use peg::parser;
44use std::rc::Rc;
5mod expr;5mod expr;
6pub use expr::*;6pub use expr::*;
77
8enum Suffix {8enum Suffix {
9 String(String),9 String(String),
10 Slice(SliceDesc),10 Slice(SliceDesc),
11 Expression(Expr),11 Expression(LocExpr),
12 Apply(expr::ArgsDesc),12 Apply(expr::ArgsDesc),
13 Extend(expr::ObjBody),13 Extend(expr::ObjBody),
14}14}
15struct LocSuffix(Suffix, ExprLocation);
1516
17pub struct ParserSettings {
18 pub loc_data: bool,
19 pub file_name: String,
20}
21
16parser! {22parser! {
17 grammar jsonnet_parser() for str {23 grammar jsonnet_parser() for str {
18 use peg::ParseLiteral;24 use peg::ParseLiteral;
34 /// Reserved word followed by any non-alphanumberic40 /// Reserved word followed by any non-alphanumberic
35 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()41 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()
36 rule id() -> String = quiet!{ !reserved() s:$(alpha() (alpha() / digit())*) {s.to_owned()}} / expected!("<identifier>")42 rule id() -> String = quiet!{ !reserved() s:$(alpha() (alpha() / digit())*) {s.to_owned()}} / expected!("<identifier>")
43
37 rule keyword(id: &'static str) = ##parse_string_literal(id) end_of_ident()44 rule keyword(id: &'static str) = ##parse_string_literal(id) end_of_ident()
45 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))}
3846
39 pub rule param() -> expr::Param = name:id() expr:(_ "=" _ expr:boxed_expr(){expr})? { expr::Param(name, expr) }47 pub rule param(s: &ParserSettings) -> expr::Param = name:id() expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }
40 pub rule params() -> expr::ParamsDesc48 pub rule params(s: &ParserSettings) -> expr::ParamsDesc
41 = params:(param() ** comma()) {49 = params:(param(s) ** comma()) {
42 let mut defaults_started = false;50 let mut defaults_started = false;
43 for param in &params {51 for param in &params {
44 defaults_started = defaults_started || param.1.is_some();52 defaults_started = defaults_started || param.1.is_some();
48 }56 }
49 / { expr::ParamsDesc(Vec::new()) }57 / { expr::ParamsDesc(Vec::new()) }
5058
51 pub rule arg() -> expr::Arg59 pub rule arg(s: &ParserSettings) -> expr::Arg
52 = name:id() _ "=" _ expr:boxed_expr() {expr::Arg(Some(name), expr)}60 = name:id() _ "=" _ expr:expr(s) {expr::Arg(Some(name), expr)}
53 / expr:boxed_expr() {expr::Arg(None, expr)}61 / expr:expr(s) {expr::Arg(None, expr)}
54 pub rule args() -> expr::ArgsDesc62 pub rule args(s: &ParserSettings) -> expr::ArgsDesc
55 = args:arg() ** comma() comma()? {63 = args:arg(s) ** comma() comma()? {
56 let mut named_started = false;64 let mut named_started = false;
57 for arg in &args {65 for arg in &args {
58 named_started = named_started || arg.0.is_some();66 named_started = named_started || arg.0.is_some();
62 }70 }
63 / { expr::ArgsDesc(Vec::new()) }71 / { expr::ArgsDesc(Vec::new()) }
6472
65 pub rule bind() -> expr::BindSpec73 pub rule bind(s: &ParserSettings) -> expr::BindSpec
66 = name:id() _ "=" _ expr:boxed_expr() {expr::BindSpec{name, params: None, value: expr}}74 = name:id() _ "=" _ expr:expr(s) {expr::BindSpec{name, params: None, value: expr}}
67 / name:id() _ "(" _ params:params() _ ")" _ "=" _ expr:boxed_expr() {expr::BindSpec{name, params: Some(params), value: expr}}75 / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec{name, params: Some(params), value: expr}}
68 pub rule assertion() -> expr::AssertStmt = keyword("assert") _ cond:boxed_expr() msg:(_ ":" _ e:boxed_expr() {e})? { expr::AssertStmt(cond, msg) }76 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }
69 pub rule string() -> String77 pub rule string() -> String
70 = "\"" str:$(("\\\"" / !['"'][_])*) "\"" {str.to_owned()}78 = "\"" str:$(("\\\"" / !['"'][_])*) "\"" {str.to_owned()}
71 / "'" str:$((!['\''][_])*) "'" {str.to_owned()}79 / "'" str:$((!['\''][_])*) "'" {str.to_owned()}
72 pub rule field_name() -> expr::FieldName80 pub rule field_name(s: &ParserSettings) -> expr::FieldName
73 = name:id() {expr::FieldName::Fixed(name)}81 = name:id() {expr::FieldName::Fixed(name)}
74 / name:string() {expr::FieldName::Fixed(name)}82 / name:string() {expr::FieldName::Fixed(name)}
75 / "[" _ expr:boxed_expr() _ "]" {expr::FieldName::Dyn(expr)}83 / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}
76 pub rule visibility() -> expr::Visibility84 pub rule visibility() -> expr::Visibility
77 = ":::" {expr::Visibility::Unhide}85 = ":::" {expr::Visibility::Unhide}
78 / "::" {expr::Visibility::Hidden}86 / "::" {expr::Visibility::Hidden}
79 / ":" {expr::Visibility::Normal}87 / ":" {expr::Visibility::Normal}
80 pub rule field() -> expr::FieldMember88 pub rule field(s: &ParserSettings) -> expr::FieldMember
81 = name:field_name() _ plus:"+"? _ visibility:visibility() _ value:expr() {expr::FieldMember{89 = name:field_name(s) _ plus:"+"? _ visibility:visibility() _ value:expr(s) {expr::FieldMember{
82 name,90 name,
83 plus: plus.is_some(),91 plus: plus.is_some(),
84 params: None,92 params: None,
85 visibility,93 visibility,
86 value,94 value,
87 }}95 }}
88 / name:field_name() _ "(" _ params:params() _ ")" _ visibility:visibility() _ value:expr() {expr::FieldMember{96 / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{
89 name,97 name,
90 plus: false,98 plus: false,
91 params: Some(params),99 params: Some(params),
92 visibility,100 visibility,
93 value,101 value,
94 }}102 }}
95 pub rule obj_local() -> BindSpec103 pub rule obj_local(s: &ParserSettings) -> BindSpec
96 = keyword("local") _ bind:bind() {bind}104 = keyword("local") _ bind:bind(s) {bind}
97 pub rule member() -> expr::Member105 pub rule member(s: &ParserSettings) -> expr::Member
98 = bind:obj_local() {expr::Member::BindStmt(bind)}106 = bind:obj_local(s) {expr::Member::BindStmt(bind)}
99 / assertion:assertion() {expr::Member::AssertStmt(assertion)}107 / assertion:assertion(s) {expr::Member::AssertStmt(assertion)}
100 / field:field() {expr::Member::Field(field)}108 / field:field(s) {expr::Member::Field(field)}
101 pub rule objinside() -> expr::ObjBody109 pub rule objinside(s: &ParserSettings) -> expr::ObjBody
102 = 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})? {110 = 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})? {
103 expr::ObjBody::ObjComp {111 expr::ObjBody::ObjComp {
104 pre_locals,112 pre_locals,
105 key,113 key,
109 rest: rest.unwrap_or_default(),117 rest: rest.unwrap_or_default(),
110 }118 }
111 }119 }
112 / members:(member() ** comma()) comma()? {expr::ObjBody::MemberList(members)}120 / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)}
113 pub rule ifspec() -> IfSpecData = keyword("if") _ expr:boxed_expr() {IfSpecData(expr)}121 pub rule ifspec(s: &ParserSettings) -> IfSpecData = keyword("if") _ expr:expr(s) {IfSpecData(expr)}
114 pub rule forspec() -> ForSpecData = keyword("for") _ id:id() _ keyword("in") _ cond:boxed_expr() {ForSpecData(id, cond)}122 pub rule forspec(s: &ParserSettings) -> ForSpecData = keyword("for") _ id:id() _ keyword("in") _ cond:expr(s) {ForSpecData(id, cond)}
115 pub rule compspec() -> Vec<expr::CompSpec> = s:(i:ifspec() { expr::CompSpec::IfSpec(i) } / f:forspec() {expr::CompSpec::ForSpec(f)} )+ {s}123 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec> = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} )+ {s}
116 pub rule bind_expr() -> Expr = bind:bind() {Expr::Bind(bind)}124 pub rule local_expr(s: &ParserSettings) -> LocExpr = l(s,<keyword("local") _ binds:bind(s) ** comma() _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, expr) }>)
117 pub rule local_expr() -> Expr = keyword("local") _ binds:bind() ** comma() _ ";" _ expr:boxed_expr() { Expr::LocalExpr(binds, expr) }
118 pub rule string_expr() -> Expr = s:string() {Expr::Str(s)}125 pub rule string_expr(s: &ParserSettings) -> LocExpr = l(s, <s:string() {Expr::Str(s)}>)
119 pub rule parened_expr() -> Expr = "(" e:boxed_expr() ")" {Expr::Parened(e)}
120 pub rule obj_expr() -> Expr = "{" _ body:objinside() _ "}" {Expr::Obj(body)}126 pub rule obj_expr(s: &ParserSettings) -> LocExpr = l(s,<"{" _ body:objinside(s) _ "}" {Expr::Obj(body)}>)
121 pub rule array_expr() -> Expr = "[" _ elems:(expr() ** comma()) _ comma()? "]" {Expr::Arr(elems)}127 pub rule array_expr(s: &ParserSettings) -> LocExpr = l(s,<"[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}>)
122 pub rule array_comp_expr() -> Expr = "[" _ expr:boxed_expr() _ comma()? _ forspec:forspec() _ others:(others: compspec() _ {others})? "]" {Expr::ArrComp(expr, forspec, others.unwrap_or_default())}128 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())}>)
123 pub rule index_expr() -> Expr
124 = val:boxed_expr() "." idx:id() {Expr::Index(val, Box::new(Expr::Str(idx)))}
125 / val:boxed_expr() "[" key:boxed_expr() "]" {Expr::Index(val, key)}129 pub rule number_expr(s: &ParserSettings) -> LocExpr = l(s,<n:number() { expr::Expr::Num(n) }>)
126 pub rule number_expr() -> Expr = n:number() { expr::Expr::Num(n) }
127 pub rule var_expr() -> Expr = n:id() { expr::Expr::Var(n) }130 pub rule var_expr(s: &ParserSettings) -> LocExpr = l(s,<n:id() { expr::Expr::Var(n) }>)
128 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{131 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{
129 cond,132 cond,
130 cond_then,133 cond_then,
131 cond_else,134 cond_else,
132 }}135 }}>)
133136
134 pub rule literal() -> Expr137 pub rule literal(s: &ParserSettings) -> LocExpr
135 = v:(138 = l(s,<v:(
136 keyword("null") {LiteralType::Null}139 keyword("null") {LiteralType::Null}
137 / keyword("true") {LiteralType::True}140 / keyword("true") {LiteralType::True}
138 / keyword("false") {LiteralType::False}141 / keyword("false") {LiteralType::False}
139 / keyword("self") {LiteralType::This}142 / keyword("self") {LiteralType::This}
140 / keyword("$") {LiteralType::Dollar}143 / keyword("$") {LiteralType::Dollar}
141 / keyword("super") {LiteralType::Super}144 / keyword("super") {LiteralType::Super}
142 ) {Expr::Literal(v)}145 ) {Expr::Literal(v)}>)
143146
144 pub rule expr_basic() -> Expr147 pub rule expr_basic(s: &ParserSettings) -> LocExpr
145 = literal()148 = literal(s)
146149
147 / string_expr() / number_expr()150 / string_expr(s) / number_expr(s)
148 / array_expr()151 / array_expr(s)
149 / obj_expr()152 / obj_expr(s)
150 / array_expr()153 / array_expr(s)
151 / array_comp_expr()154 / array_comp_expr(s)
152155
153 / var_expr()156 / var_expr(s)
154 / local_expr()157 / local_expr(s)
155 / if_then_else_expr()158 / if_then_else_expr(s)
156159
157 / keyword("function") _ "(" _ params:params() _ ")" _ expr:boxed_expr() {Expr::Function(params, expr)}160 / l(s,<keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, expr)}>)
158 / assertion:assertion() _ ";" _ expr:boxed_expr() { Expr::AssertExpr(assertion, expr) }161 / l(s,<assertion:assertion(s) _ ";" _ expr:expr(s) { Expr::AssertExpr(assertion, expr) }>)
159162
160 / keyword("error") _ expr:boxed_expr() { Expr::Error(expr) }163 / l(s,<keyword("error") _ expr:expr(s) { Expr::Error(expr) }>)
161164
162 rule expr_basic_with_suffix() -> Expr165 rule expr_basic_with_suffix(s: &ParserSettings) -> LocExpr
163 = a:expr_basic() suffixes:(_ suffix:expr_suffix() {suffix})* {166 = a:expr_basic(s) suffixes:(_ suffix:l_expr_suffix(s) {suffix})* {
164 let mut cur = a;167 let mut cur = a;
165 for suffix in suffixes {168 for suffix in suffixes {
166 cur = match suffix {169 let LocSuffix(suffix, location) = suffix;
170 cur = LocExpr(Rc::new(match suffix {
167 Suffix::String(index) => Expr::Index(Box::new(cur), Box::new(Expr::Str(index))),171 Suffix::String(index) => Expr::Index(cur, loc_expr!(Expr::Str(index), s.loc_data, (s.file_name.clone(), location.1, location.2))),
168 Suffix::Slice(desc) => Expr::Slice(Box::new(cur), desc),172 Suffix::Slice(desc) => Expr::Slice(cur, desc),
169 Suffix::Expression(index) => Expr::Index(Box::new(cur), Box::new(index)),173 Suffix::Expression(index) => Expr::Index(cur, index),
170 Suffix::Apply(args) => Expr::Apply(Box::new(cur), args),174 Suffix::Apply(args) => Expr::Apply(cur, args),
171 Suffix::Extend(body) => Expr::ObjExtend(box cur, body),175 Suffix::Extend(body) => Expr::ObjExtend(cur, body),
172 }176 }), if s.loc_data { Some(Rc::new(location)) } else { None })
173 }177 }
174 cur178 cur
175 }179 }
176180
177 pub rule slice_desc() -> SliceDesc181 pub rule slice_desc(s: &ParserSettings) -> SliceDesc
178 = start:boxed_expr()? _ ":" _ pair:(end:boxed_expr()? _ step:(":" _ e:boxed_expr() {e})? {(end, step)})? {182 = start:expr(s)? _ ":" _ pair:(end:expr(s)? _ step:(":" _ e:expr(s) {e})? {(end, step)})? {
179 if let Some((end, step)) = pair {183 if let Some((end, step)) = pair {
180 SliceDesc { start, end, step }184 SliceDesc { start, end, step }
181 }else{185 }else{
182 SliceDesc { start, end: None, step: None }186 SliceDesc { start, end: None, step: None }
183 }187 }
184 }188 }
185189
186 rule expr_suffix() -> Suffix190 rule expr_suffix(s: &ParserSettings) -> Suffix
187 = "." _ s:id() { Suffix::String(s) }191 = "." _ s:id() { Suffix::String(s) }
188 / "[" _ s:slice_desc() _ "]" { Suffix::Slice(s) }192 / "[" _ s:slice_desc(s) _ "]" { Suffix::Slice(s) }
189 / "[" _ s:expr() _ "]" { Suffix::Expression(s) }193 / "[" _ s:expr(s) _ "]" { Suffix::Expression(s) }
190 / "(" _ args:args() _ ")" (_ keyword("tailstrict"))? { Suffix::Apply(args) }194 / "(" _ args:args(s) _ ")" (_ keyword("tailstrict"))? { Suffix::Apply(args) }
191 / "{" _ body:objinside() _ "}" { Suffix::Extend(body) }195 / "{" _ body:objinside(s) _ "}" { Suffix::Extend(body) }
196 rule l_expr_suffix(s: &ParserSettings) -> LocSuffix
197 = start:position!() suffix:expr_suffix(s) end:position!() {LocSuffix(suffix, ExprLocation(s.file_name.clone(), start, end))}
192198
193 rule expr() -> Expr199 rule expr(s: &ParserSettings) -> LocExpr
194 = a:precedence! {200 = start:position!() a:precedence! {
195 a:(@) _ "||" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Or, Box::new(b))}201 a:(@) _ "||" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Or, b))}
196 --202 --
197 a:(@) _ "&&" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::And, Box::new(b))}203 a:(@) _ "&&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::And, b))}
198 --204 --
199 a:(@) _ "|" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::BitOr, Box::new(b))}205 a:(@) _ "|" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitOr, b))}
200 --206 --
201 a:@ _ "^" _ b:(@) {Expr::BinaryOp(Box::new(a), BinaryOpType::BitXor, Box::new(b))}207 a:@ _ "^" _ b:(@) {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitXor, b))}
202 --208 --
203 a:(@) _ "&" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::BitAnd, Box::new(b))}209 a:(@) _ "&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitAnd, b))}
204 --210 --
205 a:(@) _ "==" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Eq, Box::new(b))}211 a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Eq, b))}
206 a:(@) _ "!=" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Ne, Box::new(b))}212 a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Ne, b))}
207 --213 --
208 a:(@) _ "<" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Lt, Box::new(b))}214 a:(@) _ "<" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lt, b))}
209 a:(@) _ ">" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Gt, Box::new(b))}215 a:(@) _ ">" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gt, b))}
210 a:(@) _ "<=" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Lte, Box::new(b))}216 a:(@) _ "<=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lte, b))}
211 a:(@) _ ">=" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Gte, Box::new(b))}217 a:(@) _ ">=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gte, b))}
212 --218 --
213 a:(@) _ "<<" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Lhs, Box::new(b))}219 a:(@) _ "<<" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lhs, b))}
214 a:(@) _ ">>" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Rhs, Box::new(b))}220 a:(@) _ ">>" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Rhs, b))}
215 --221 --
216 a:(@) _ "+" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Add, Box::new(b))}222 a:(@) _ "+" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Add, b))}
217 a:(@) _ "-" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Sub, Box::new(b))}223 a:(@) _ "-" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Sub, b))}
218 --224 --
219 a:(@) _ "*" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Mul, Box::new(b))}225 a:(@) _ "*" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Mul, b))}
220 a:(@) _ "/" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Div, Box::new(b))}226 a:(@) _ "/" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Div, b))}
221 a:(@) _ "%" _ b:@ {Expr::BinaryOp(Box::new(a), BinaryOpType::Mod, Box::new(b))}227 a:(@) _ "%" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Mod, b))}
222 --228 --
223 e:expr_basic_with_suffix() {e}229 e:expr_basic_with_suffix(s) {e}
224 "-" _ expr:expr_basic_with_suffix() { Expr::UnaryOp(UnaryOpType::Minus, box expr) }230 "-" _ expr:expr_basic_with_suffix(s) { loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Minus, expr)) }
225 "!" _ expr:expr_basic_with_suffix() { Expr::UnaryOp(UnaryOpType::Not, box expr) }231 "!" _ expr:expr_basic_with_suffix(s) { loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Not, expr)) }
226 "(" _ e:boxed_expr() _ ")" {Expr::Parened(e)}232 "(" _ e:expr(s) _ ")" {loc_expr_todo!(Expr::Parened(e))}
233 } end:position!() {
234 let LocExpr(e, _) = a;
235 LocExpr(e, if s.loc_data {
236 Some(Rc::new(ExprLocation(s.file_name.to_owned(), start, end)))
237 } else {
238 None
239 })
227 }240 }
228 / e:expr_basic_with_suffix() {e}241 / e:expr_basic_with_suffix(s) {e}
229242
230 pub rule boxed_expr() -> Box<Expr> = e:expr() {Box::new(e)}243 pub rule jsonnet(s: &ParserSettings) -> LocExpr = _ e:expr(s) _ {e}
231 pub rule jsonnet() -> Expr = _ e:expr() _ {e}
232 }244 }
233}245}
234246
235// TODO: impl FromStr from Expr247// TODO: impl FromStr from Expr
236pub fn parse(str: &str) -> Result<Expr, peg::error::ParseError<peg::str::LineCol>> {248pub fn parse(
249 str: &str,
250 settings: &ParserSettings,
251) -> Result<LocExpr, peg::error::ParseError<peg::str::LineCol>> {
237 jsonnet_parser::jsonnet(str)252 jsonnet_parser::jsonnet(str, settings)
238}253}
239254
240#[cfg(test)]255#[cfg(test)]
241pub mod tests {256pub mod tests {
242 use super::{expr::*, parse};257 use super::{expr::*, parse};
258 use crate::ParserSettings;
259 macro_rules! el {
260 ($expr:expr) => {
261 LocExpr(std::rc::Rc::new($expr), None)
262 };
263 }
264 macro_rules! parse {
265 ($s:expr) => {
266 parse(
267 $s,
268 &ParserSettings {
269 loc_data: false,
270 file_name: "test.jsonnet".to_owned(),
271 },
272 )
273 .unwrap()
274 };
275 }
243276
244 mod expressions {277 mod expressions {
245 use super::*;278 use super::*;
246279
247 pub fn basic_math() -> Expr {280 pub fn basic_math() -> LocExpr {
248 Expr::BinaryOp(281 el!(Expr::BinaryOp(
249 Box::new(Expr::Num(2.0)),282 el!(Expr::Num(2.0)),
250 BinaryOpType::Add,283 BinaryOpType::Add,
251 Box::new(Expr::BinaryOp(284 el!(Expr::BinaryOp(
252 Box::new(Expr::Num(2.0)),285 el!(Expr::Num(2.0)),
253 BinaryOpType::Mul,286 BinaryOpType::Mul,
254 Box::new(Expr::Num(2.0)),287 el!(Expr::Num(2.0)),
255 )),288 )),
256 )289 ))
257 }290 }
258 }291 }
259292
260 #[test]293 #[test]
261 fn empty_object() {294 fn empty_object() {
262 assert_eq!(parse("{}").unwrap(), Expr::Obj(ObjBody::MemberList(vec![])));295 assert_eq!(parse!("{}"), el!(Expr::Obj(ObjBody::MemberList(vec![]))));
263 }296 }
264297
265 #[test]298 #[test]
266 fn basic_math() {299 fn basic_math() {
267 assert_eq!(300 assert_eq!(
268 parse("2+2*2").unwrap(),301 parse!("2+2*2"),
269 Expr::BinaryOp(302 el!(Expr::BinaryOp(
270 Box::new(Expr::Num(2.0)),303 el!(Expr::Num(2.0)),
271 BinaryOpType::Add,304 BinaryOpType::Add,
272 Box::new(Expr::BinaryOp(305 el!(Expr::BinaryOp(
273 Box::new(Expr::Num(2.0)),306 el!(Expr::Num(2.0)),
274 BinaryOpType::Mul,307 BinaryOpType::Mul,
275 Box::new(Expr::Num(2.0))308 el!(Expr::Num(2.0))
276 ))309 ))
277 )310 ))
278 );311 );
279 }312 }
280313
281 #[test]314 #[test]
282 fn basic_math_with_indents() {315 fn basic_math_with_indents() {
283 assert_eq!(parse("2 + 2 * 2 ").unwrap(), expressions::basic_math());316 assert_eq!(parse!("2 + 2 * 2 "), expressions::basic_math());
284 }317 }
285318
286 #[test]319 #[test]
287 fn basic_math_parened() {320 fn basic_math_parened() {
288 assert_eq!(321 assert_eq!(
289 parse("2+(2+2*2)").unwrap(),322 parse!("2+(2+2*2)"),
290 Expr::BinaryOp(323 el!(Expr::BinaryOp(
291 Box::new(Expr::Num(2.0)),324 el!(Expr::Num(2.0)),
292 BinaryOpType::Add,325 BinaryOpType::Add,
293 Box::new(Expr::Parened(Box::new(expressions::basic_math()))),326 el!(Expr::Parened(expressions::basic_math())),
294 )327 ))
295 );328 );
296 }329 }
297330
298 /// Comments should not affect parsing331 /// Comments should not affect parsing
299 #[test]332 #[test]
300 fn comments() {333 fn comments() {
301 assert_eq!(334 assert_eq!(
302 parse("2//comment\n+//comment\n3/*test*/*/*test*/4").unwrap(),335 parse!("2//comment\n+//comment\n3/*test*/*/*test*/4"),
303 Expr::BinaryOp(336 el!(Expr::BinaryOp(
304 box Expr::Num(2.0),337 el!(Expr::Num(2.0)),
305 BinaryOpType::Add,338 BinaryOpType::Add,
306 box Expr::BinaryOp(box Expr::Num(3.0), BinaryOpType::Mul, box Expr::Num(4.0))339 el!(Expr::BinaryOp(
340 el!(Expr::Num(3.0)),
341 BinaryOpType::Mul,
342 el!(Expr::Num(4.0))
307 )343 ))
344 ))
308 );345 );
309 }346 }
310347
311 /// Comments should be able to be escaped348 /// Comments should be able to be escaped
312 #[test]349 #[test]
313 fn comment_escaping() {350 fn comment_escaping() {
314 assert_eq!(351 assert_eq!(
315 parse("2/*\\*/+*/ - 22").unwrap(),352 parse!("2/*\\*/+*/ - 22"),
316 Expr::BinaryOp(box Expr::Num(2.0), BinaryOpType::Sub, box Expr::Num(22.0))353 el!(Expr::BinaryOp(
354 el!(Expr::Num(2.0)),
355 BinaryOpType::Sub,
356 el!(Expr::Num(22.0))
357 ))
317 );358 );
318 }359 }
319360
320 #[test]361 #[test]
321 fn suffix_comparsion() {362 fn suffix_comparsion() {
322 use Expr::*;363 use Expr::*;
323 assert_eq!(364 assert_eq!(
324 parse("std.type(a) == \"string\"").unwrap(),365 parse!("std.type(a) == \"string\""),
325 BinaryOp(366 el!(BinaryOp(
326 box Apply(367 el!(Apply(
327 box Index(box Var("std".to_owned()), box Str("type".to_owned())),368 el!(Index(
369 el!(Var("std".to_owned())),
370 el!(Str("type".to_owned()))
371 )),
328 ArgsDesc(vec![Arg(None, box Var("a".to_owned()))])372 ArgsDesc(vec![Arg(None, el!(Var("a".to_owned())))])
329 ),373 )),
330 BinaryOpType::Eq,374 BinaryOpType::Eq,
331 box Str("string".to_owned())375 el!(Str("string".to_owned()))
332 )376 ))
333 );377 );
334 }378 }
335379
336 #[test]380 #[test]
337 fn array_comp() {381 fn array_comp() {
338 use Expr::*;382 use Expr::*;
339 assert_eq!(383 assert_eq!(
340 parse("[std.deepJoin(x) for x in arr]").unwrap(),384 parse!("[std.deepJoin(x) for x in arr]"),
341 ArrComp(385 el!(ArrComp(
342 box Apply(386 el!(Apply(
343 box Index(box Var("std".to_owned()), box Str("deepJoin".to_owned())),387 el!(Index(
388 el!(Var("std".to_owned())),
389 el!(Str("deepJoin".to_owned()))
390 )),
344 ArgsDesc(vec![Arg(None, box Var("x".to_owned()))])391 ArgsDesc(vec![Arg(None, el!(Var("x".to_owned())))])
345 ),392 )),
346 ForSpecData("x".to_owned(), box Var("arr".to_owned())),393 ForSpecData("x".to_owned(), el!(Var("arr".to_owned()))),
347 vec![]394 vec![]
348 ),395 )),
349 )396 )
350 }397 }
351398
352 #[test]399 #[test]
353 fn array_comp_with_ifs() {400 fn array_comp_with_ifs() {
354 use Expr::*;401 use Expr::*;
355 assert_eq!(402 assert_eq!(
356 parse("[k for k in std.objectFields(patch) if patch[k] == null]").unwrap(),403 parse!("[k for k in std.objectFields(patch) if patch[k] == null]"),
357 ArrComp(404 el!(ArrComp(
358 box Var("k".to_owned()),405 el!(Var("k".to_owned())),
359 ForSpecData(406 ForSpecData(
360 "k".to_owned(),407 "k".to_owned(),
361 box Apply(408 el!(Apply(
362 box Index(409 el!(Index(
363 box Var("std".to_owned()),410 el!(Var("std".to_owned())),
364 box Str("objectFields".to_owned())411 el!(Str("objectFields".to_owned()))
365 ),412 )),
366 ArgsDesc(vec![Arg(None, box Var("patch".to_owned()))])413 ArgsDesc(vec![Arg(None, el!(Var("patch".to_owned())))])
367 )414 ))
368 ),415 ),
369 vec![CompSpec::IfSpec(IfSpecData(box BinaryOp(416 vec![CompSpec::IfSpec(IfSpecData(el!(BinaryOp(
370 box Index(box Var("patch".to_owned()), box Var("k".to_owned())),417 el!(Index(
418 el!(Var("patch".to_owned())),
419 el!(Var("k".to_owned()))
420 )),
371 BinaryOpType::Eq,421 BinaryOpType::Eq,
372 box Literal(LiteralType::Null)422 el!(Literal(LiteralType::Null))
373 )))]423 ))))]
374 ),424 ))
375 );425 );
376 }426 }
377427
378 #[test]428 #[test]
379 fn reserved() {429 fn reserved() {
380 use Expr::*;430 use Expr::*;
381 assert_eq!(parse("null").unwrap(), Literal(LiteralType::Null));431 assert_eq!(parse!("null"), el!(Literal(LiteralType::Null)));
382 assert_eq!(parse("nulla").unwrap(), Var("nulla".to_owned()));432 assert_eq!(parse!("nulla"), el!(Var("nulla".to_owned())));
383 }433 }
384434
385 #[test]435 #[test]
386 fn multiple_args_buf() {436 fn multiple_args_buf() {
387 parse("a(b, null_fields)").unwrap();437 parse!("a(b, null_fields)");
388 }438 }
389439
390 #[test]440 #[test]
391 fn infix_precedence() {441 fn infix_precedence() {
392 use Expr::*;442 use Expr::*;
393 assert_eq!(443 assert_eq!(
394 parse("!a && !b").unwrap(),444 parse!("!a && !b"),
395 BinaryOp(445 el!(BinaryOp(
396 box UnaryOp(UnaryOpType::Not, box Var("a".to_owned())),446 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".to_owned())))),
397 BinaryOpType::And,447 BinaryOpType::And,
398 box UnaryOp(UnaryOpType::Not, box Var("b".to_owned()))448 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".to_owned()))))
399 )449 ))
400 );450 );
401 }451 }
402452
403 #[test]453 #[test]
404 fn can_parse_stdlib() {454 fn can_parse_stdlib() {
405 parse(jsonnet_stdlib::STDLIB_STR).unwrap();455 parse!(jsonnet_stdlib::STDLIB_STR);
406 }456 }
407}457}
408458