difftreelog
docs(ir) deny(missing_docs)
in: master
8 files changed
crates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth2use jrsonnet_ir::{2use jrsonnet_ir::{3 ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BinaryOpType, BindSpec, CompSpec, Destruct, Expr,3 ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BinaryOpType, BindSpec, CompSpec, Destruct, Expr,4 ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IdentityKind, IfElse,4 ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IdentityKind, IfElse,5 IfSpecData, ImportKind, IndexPart, Member, NumValue, ObjBody, ObjComp, ObjMembers, Slice,5 IfSpecData, ImportKind, IndexPart, NumValue, ObjBody, ObjComp, ObjMembers, Slice, SliceDesc,6 SliceDesc, Source, Span, Spanned, TrivialVal, UnaryOpType, Visibility,6 Source, Span, Spanned, TrivialVal, UnaryOpType, Visibility,7};7};8use jrsonnet_lexer::{8use jrsonnet_lexer::{9 Lexeme, Lexer, Span as LexSpan, SyntaxKind, T, collect_lexed_str_block, unescape,9 Lexeme, Lexer, Span as LexSpan, SyntaxKind, T, collect_lexed_str_block, unescape,558 }558 }559}559}560560561enum Member {562 BindStmt(BindSpec),563 AssertStmt(AssertStmt),564 Field(FieldMember),565}561fn member(p: &mut Parser<'_>) -> Result<Member> {566fn member(p: &mut Parser<'_>) -> Result<Member> {562 if p.at(T![local]) {567 if p.at(T![local]) {563 p.eat(T![local])?;568 p.eat(T![local])?;crates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth1//! Jrsonnet AST expression types.21use std::{3use std::{2 fmt::{self, Debug, Display},4 fmt::{self, Debug, Display},12 source::Source,14 source::Source,13};15};141617/// Field name in object/obj-comp definition.15#[derive(Debug, PartialEq, Acyclic)]18#[derive(Debug, PartialEq, Acyclic)]16pub enum FieldName {19pub enum FieldName {17 /// {fixed: 2}20 /// `{fixed: 2}`18 Fixed(IStr),21 Fixed(IStr),19 /// {["dyn"+"amic"]: 3}22 /// `{["dyn"+"amic"]: 3}` - may only reference locals defined outside of the object.20 Dyn(Expr),23 Dyn(Expr),21}24}222526/// Field visibility in object/obj-comp/exp-object-iteration definition.23#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]27#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]24#[repr(u8)]28#[repr(u8)]25pub enum Visibility {29pub enum Visibility {26 /// :30 /// `:` - normal visibility, visible by default, but inherits field visibility from `super`.27 Normal,31 Normal,28 /// ::32 /// `::` - hidden visibility, field should not be visible by default manifest functions and iteration.29 Hidden,33 Hidden,30 /// :::34 /// `:::` - unhide visibility, visible by default, ignores `super` visibility,35 /// can be overriden by [`Visibility::Hidden`]31 Unhide,36 Unhide,32}37}333839/// Trivial values are passed from the AST to the evaluator as-is and have trivial conversions from and to40/// jsonnet runtime values.34#[derive(Debug, Clone, PartialEq, Acyclic)]41#[derive(Debug, Clone, PartialEq, Acyclic)]35pub enum TrivialVal {42pub enum TrivialVal {43 /// Jsonnet `null`.36 Null,44 Null,45 /// Jsonnet `true` or `false`.37 Bool(bool),46 Bool(bool),47 /// Jsonnet number, finite, non-nan, see [`NumValue`].38 Num(NumValue),48 Num(NumValue),49 /// Jsonnet interned flat string, see [`IStr`].39 Str(IStr),50 Str(IStr),40}51}415242impl Visibility {53impl Visibility {54 /// Is this visibility defines/matches (in exp-object-iteration) a visible field?55 ///56 /// Note: [`Self::Unhide`] also matches hidden fields.43 pub fn is_visible(&self) -> bool {57 pub fn is_visible(&self) -> bool {44 matches!(self, Self::Normal | Self::Unhide)58 matches!(self, Self::Normal | Self::Unhide)45 }59 }46}60}476162/// Assert statement, used in `assert` expressions and for object assertions.63///64/// ```jsonnet65/// assert a == 1: "message"66/// ```48#[derive(Debug, PartialEq, Acyclic)]67#[derive(Debug, PartialEq, Acyclic)]49pub struct AssertStmt {68pub struct AssertStmt {69 /// Assertion condition, `a == 1`.50 pub assertion: Spanned<Expr>,70 pub assertion: Spanned<Expr>,71 /// Message to be shown on assertion failure, `"message"`.51 pub message: Option<Expr>,72 pub message: Option<Expr>,52}73}537475/// Object/obj-comp full field definition.76///77/// ```jsonnet78/// [name]+:: value,79/// ```54#[derive(Debug, PartialEq, Acyclic)]80#[derive(Debug, PartialEq, Acyclic)]55pub struct FieldMember {81pub struct FieldMember {82 /// Field name, possibly dynamic, see [`FieldName`].56 pub name: Spanned<FieldName>,83 pub name: Spanned<FieldName>,84 /// Is this a `+:` field? (extends super field with the same name using `+`).57 pub plus: bool,85 pub plus: bool,86 /// Method definition syntax: `a(b): c` is equivalent to `a: function(b) c`.58 pub params: Option<ExprParams>,87 pub params: Option<ExprParams>,88 /// Field visibility, see [`Visibility`].59 pub visibility: Visibility,89 pub visibility: Visibility,90 /// Field value.60 pub value: Expr,91 pub value: Expr,61}92}629363#[derive(Debug, PartialEq, Acyclic)]94/// Unary operator.64pub enum Member {65 Field(FieldMember),66 BindStmt(BindSpec),67 AssertStmt(AssertStmt),68}6970#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]95#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]71pub enum UnaryOpType {96pub enum UnaryOpType {97 /// `+v`72 Plus,98 Plus,99 /// `-v`73 Minus,100 Minus,101 /// `~v`74 BitNot,102 BitNot,103 /// `!v`75 Not,104 Not,76}105}7710691 }120 }92}121}93122123/// Jsonnet binary expression.124///125/// ```jsonnet126/// a + b127/// ```94#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]128#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]95pub enum BinaryOpType {129pub enum BinaryOpType {130 /// `*`96 Mul,131 Mul,132 /// `/`97 Div,133 Div,9813499 /// Implemented as intrinsic, put here for completeness135 /// `%` - modulo for numbers, formatting for strings, equivalent to `std.mod(a, b)`.100 Mod,136 Mod,101137138 /// `+`102 Add,139 Add,140 /// `-`103 Sub,141 Sub,104142143 /// `<<`105 Lhs,144 Lhs,145 /// `>>`106 Rhs,146 Rhs,107147148 /// `<`108 Lt,149 Lt,150 /// `>`109 Gt,151 Gt,152 /// `<=`110 Lte,153 Lte,154 /// `>=`111 Gte,155 Gte,112156157 /// `&`113 BitAnd,158 BitAnd,159 /// `|`114 BitOr,160 BitOr,161 /// `^`115 BitXor,162 BitXor,116163164 /// `==`117 Eq,165 Eq,166 /// `!=`118 Neq,167 Neq,119168169 /// `&&`120 And,170 And,171 /// `||`121 Or,172 Or,173 /// `??`122 #[cfg(feature = "exp-null-coaelse")]174 #[cfg(feature = "exp-null-coaelse")]123 NullCoaelse,175 NullCoaelse,124176125 // Equialent to std.objectHasEx(a, b, true)177 /// `in` - equialent to `std.objectHasEx(a, b, true)`.126 In,178 In,127}179}128180159 }211 }160}212}161213214/// Parameter definition in function expression/method object member.215///216/// ```jsonnet162/// name, default value217/// name = default218/// ```163#[derive(Debug, PartialEq, Acyclic)]219#[derive(Debug, PartialEq, Acyclic)]164pub struct ExprParam {220pub struct ExprParam {221 /// Destruct for the field value, if not [`Destruct::Full`] - can only be used with positional argument.165 pub destruct: Destruct,222 pub destruct: Destruct,223 /// Default value.166 pub default: Option<Expr>,224 pub default: Option<Expr>,167}225}168226169/// Defined function parameters227/// Defined function parameters.170#[derive(Debug, PartialEq, Acyclic)]228#[derive(Debug, PartialEq, Acyclic)]171pub struct ExprParams {229pub struct ExprParams {230 /// Defined function parameters.172 pub exprs: Vec<ExprParam>,231 pub exprs: Vec<ExprParam>,232 /// Cached function signature. TODO: Should be calculated by static analyzer.173 pub signature: FunctionSignature,233 pub signature: FunctionSignature,174 pub(crate) binds_len: usize,234 pub(crate) binds_len: usize,175}235}176impl ExprParams {236impl ExprParams {237 /// Number of all parameters, including those with set defaults.177 pub fn len(&self) -> usize {238 pub fn len(&self) -> usize {178 self.exprs.len()239 self.exprs.len()179 }240 }241 /// Is this function has no parameters?180 pub fn is_empty(&self) -> bool {242 pub fn is_empty(&self) -> bool {181 self.exprs.is_empty()243 self.exprs.is_empty()182 }244 }183245246 /// Amount of bound locals, equal to number of parameters without `exp-destruct`.184 pub fn binds_len(&self) -> usize {247 pub fn binds_len(&self) -> usize {185 self.binds_len248 self.binds_len186 }249 }250 /// Create an [`ExprParams`].187 pub fn new(exprs: Vec<ExprParam>) -> Self {251 pub fn new(exprs: Vec<ExprParam>) -> Self {188 Self {252 Self {189 signature: FunctionSignature::new(253 signature: FunctionSignature::new(203 }267 }204}268}205269270/// Function call arguments.271///272/// ```jsonnet273/// call(unnamed1, unnamed2, named1 = value, named2 = value)274/// ```275///276/// TODO: should `tailstrict` be moved here?206#[derive(Debug, PartialEq, Acyclic)]277#[derive(Debug, PartialEq, Acyclic)]207pub struct ArgsDesc {278pub struct ArgsDesc {279 /// Positional argument values.208 pub unnamed: Vec<Expr>,280 pub unnamed: Vec<Expr>,281 /// Named argument names.209 pub names: Vec<IStr>,282 pub names: Vec<IStr>,283 /// Named argument values.210 pub values: Vec<Expr>,284 pub values: Vec<Expr>,211}285}212impl ArgsDesc {286impl ArgsDesc {287 /// Construct an [`ArgsDesc`].213 pub fn new(unnamed: Vec<Expr>, names: Vec<IStr>, values: Vec<Expr>) -> Self {288 pub fn new(unnamed: Vec<Expr>, names: Vec<IStr>, values: Vec<Expr>) -> Self {214 Self {289 Self {215 unnamed,290 unnamed,219 }294 }220}295}221296297/// In [`Destruct`], unmatched array elements/object fields should either not exist,298/// or be explicitly dropped [`DestructRest::Drop`] or collected into another local [`DestructRest::Keep`].222#[derive(Debug, PartialEq, Eq, Acyclic)]299#[derive(Debug, PartialEq, Eq, Acyclic)]223pub enum DestructRest {300pub enum DestructRest {224 /// ...rest301 /// `...rest`225 Keep(IStr),302 Keep(IStr),226 /// ...303 /// `...`227 Drop,304 Drop,228}305}229306307/// Local definition/destructuring (with `exp-destruct`).308///309/// `name` in `local name = value`.230#[derive(Debug, PartialEq, Acyclic)]310#[derive(Debug, PartialEq, Acyclic)]231pub enum Destruct {311pub enum Destruct {312 /// `name` - normal local definition, value is assigned to the specified name.232 Full(Spanned<IStr>),313 Full(Spanned<IStr>),314 /// `?` - value is ignored, mostly useful for nested destructuring of arrays/objects.233 #[cfg(feature = "exp-destruct")]315 #[cfg(feature = "exp-destruct")]234 Skip,316 Skip,317 /// `[a, b, ...rest, c]` - destructure the value as array.318 ///319 /// If the value length is not matched by `start` and there is no `rest` - throws.235 #[cfg(feature = "exp-destruct")]320 #[cfg(feature = "exp-destruct")]236 Array {321 Array {322 /// How to collect first elements.237 start: Vec<Destruct>,323 start: Vec<Destruct>,324 /// How the elements in between the `start` and `end` should be handled.238 rest: Option<DestructRest>,325 rest: Option<DestructRest>,326 /// How to collect last elements. Might only be non-empty in presence of `rest`.239 end: Vec<Destruct>,327 end: Vec<Destruct>,240 },328 },329 /// `{a, b = default, c: rename, ...rest}` - destructure the value as object.241 #[cfg(feature = "exp-destruct")]330 #[cfg(feature = "exp-destruct")]242 Object {331 Object {332 /// Destructuring of the individual fields.333 ///334 /// Source field name, target destructure (defaults to `Destruct::Full` with the source name),335 /// default value (defaults to throw on the match time due to match failure).243 #[allow(clippy::type_complexity)]336 #[allow(clippy::type_complexity)]244 fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,337 fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,338 /// How the remaining fields should be handled, the result is similar to how `std.objectRemoveField` behaves.245 rest: Option<DestructRest>,339 rest: Option<DestructRest>,246 },340 },247}341}248impl Destruct {342impl Destruct {249 /// Name of destructure, used for function parameter names343 /// Name of destructure, used for function named parameter names.250 pub fn name(&self) -> ParamName {344 pub fn name(&self) -> ParamName {251 match self {345 match self {252 Self::Full(name) => ParamName::Named(name.value.clone()),346 Self::Full(name) => ParamName::Named(name.value.clone()),253 #[cfg(feature = "exp-destruct")]347 #[cfg(feature = "exp-destruct")]254 _ => ParamName::Unnamed,348 _ => ParamName::Unnamed,255 }349 }256 }350 }351 /// How many local names this [`Destruct`] will create, always `1` when `exp-destruct` feature is not enabled.257 pub fn binds_len(&self) -> usize {352 pub fn binds_len(&self) -> usize {258 #[cfg(feature = "exp-destruct")]353 #[cfg(feature = "exp-destruct")]259 fn cap_rest(rest: &Option<DestructRest>) -> usize {354 fn cap_rest(rest: &Option<DestructRest>) -> usize {289 }384 }290}385}291386387/// Single element of `local` expression/value of the `local` object/obj-comp member.388///389/// ```jsonnet390/// local a = b;391/// ```292#[derive(Debug, PartialEq, Acyclic)]392#[derive(Debug, PartialEq, Acyclic)]293pub enum BindSpec {393pub enum BindSpec {394 /// Normal local definition/destructure: `local a = b;`.294 Field {395 Field {396 /// Local name/destructure.295 into: Destruct,397 into: Destruct,398 /// Value.296 value: Expr,399 value: Expr,297 },400 },401 /// Method-like local: `local a(b) = c;`, equivalent to `local a = function(b) c;`.298 Function {402 Function {403 /// Local name, can't be destructure since functions can't be destructured.299 name: Spanned<IStr>,404 name: Spanned<IStr>,405 /// Function parameters.300 params: ExprParams,406 params: ExprParams,407 /// Function body.301 value: Expr,408 value: Expr,302 },409 },303}410}304impl BindSpec {411impl BindSpec {412 /// How many locals will this local definition define.305 pub fn binds_len(&self) -> usize {413 pub fn binds_len(&self) -> usize {306 match self {414 match self {307 BindSpec::Field { into, .. } => into.binds_len(),415 BindSpec::Field { into, .. } => into.binds_len(),310 }418 }311}419}312420421/// `if` expression/`if` compspec condition.422///423/// ```jsonnet424/// if a == b425/// ```313#[derive(Debug, PartialEq, Acyclic)]426#[derive(Debug, PartialEq, Acyclic)]314pub struct IfSpecData {427pub struct IfSpecData {428 /// Span for the `if` token.315 pub span: Span,429 pub span: Span,430 /// Condition expression.316 pub cond: Expr,431 pub cond: Expr,317}432}318433434/// `for` compspec definition.435///436/// ```jsonnet437/// for a in b438/// ```319#[derive(Debug, PartialEq, Acyclic)]439#[derive(Debug, PartialEq, Acyclic)]320pub struct ForSpecData {440pub struct ForSpecData {441 /// New local definition, will be set per `over` iteration.321 pub destruct: Destruct,442 pub destruct: Destruct,443 /// Expression which should evaluate to array to be iterated over.322 pub over: Expr,444 pub over: Expr,323}445}324446325#[cfg(feature = "exp-object-iteration")]447/// `for` compspec object iteration definition.448///449/// ```jsonnet450/// for [key]: value in obj451/// ```452///453/// TODO: `exp-preserve-order` integration.326#[derive(Debug, PartialEq, Acyclic)]454#[derive(Debug, PartialEq, Acyclic)]327pub struct ForObjSpecData {455pub struct ForObjSpecData {456 /// Object field name, will be set per `over` field iteration.328 pub key: IStr,457 pub key: IStr,458 /// Filter for the iterated object fields,459 /// - `:` will iterate over visible fields.460 /// - `::` will iterate over only invisible fields.461 /// - `:::` will iterate over all defined fields.329 pub visibility: Visibility,462 pub visibility: Visibility,463 /// Object value destructure, will be set per `over` field iteration.330 pub value: Destruct,464 pub value: Destruct,465 /// Expression which should evaluate to object to be iterated over.331 pub over: Expr,466 pub over: Expr,332}467}333468469/// One element of array/obj-comp iteration definition.470///471/// `for a in b if c` in [1 for a in b if c].334#[derive(Debug, PartialEq, Acyclic)]472#[derive(Debug, PartialEq, Acyclic)]335pub enum CompSpec {473pub enum CompSpec {474 /// `if` filter, see [`IfSpecData`].336 IfSpec(IfSpecData),475 IfSpec(IfSpecData),476 /// `for` array iterator, see [`ForSpecData`].337 ForSpec(ForSpecData),477 ForSpec(ForSpecData),478 /// `for` object iterator, see [`ForObjSpecData`].338 #[cfg(feature = "exp-object-iteration")]479 #[cfg(feature = "exp-object-iteration")]339 ForObjSpec(ForObjSpecData),480 ForObjSpec(ForObjSpecData),340}481}341482483/// Object constructed from dynamically constructed field list using iteration.484///485/// ```jsonnet486/// {487/// ["field_" + id]: value488/// for id in [1, 2, 3]489/// }490/// ```342#[derive(Debug, PartialEq, Acyclic)]491#[derive(Debug, PartialEq, Acyclic)]343pub struct ObjComp {492pub struct ObjComp {493 /// Locals to be defined to be used by object field values, may reference object identity.344 pub locals: Vec<BindSpec>,494 pub locals: Vec<BindSpec>,495 /// Field definition template, will be evaluated for every compspec iteration, normally uses [`FieldName::Dyn`].345 pub field: Box<FieldMember>,496 pub field: Box<FieldMember>,497 /// Compspec.346 pub compspecs: Vec<CompSpec>,498 pub compspecs: Vec<CompSpec>,347}499}348500501/// Object constructed from explicitly defined elements.502///503/// ```jsonnet504/// {505/// a: 1,506/// b: 2,507/// }508/// ```349#[derive(Debug, PartialEq, Acyclic)]509#[derive(Debug, PartialEq, Acyclic)]350pub struct ObjMembers {510pub struct ObjMembers {511 /// Locals to be defined to be used by object field values, may reference object identity.351 pub locals: Vec<BindSpec>,512 pub locals: Vec<BindSpec>,513 /// Associated object assertions, checked on first time object field value is computed.352 pub asserts: Vec<AssertStmt>,514 pub asserts: Vec<AssertStmt>,515 /// Static list of field definitions.353 pub fields: Vec<FieldMember>,516 pub fields: Vec<FieldMember>,354}517}355518519/// Object constructed by any means.356#[derive(Debug, PartialEq, Acyclic)]520#[derive(Debug, PartialEq, Acyclic)]357pub enum ObjBody {521pub enum ObjBody {522 /// Static field list, see [`ObjMembers`].358 MemberList(ObjMembers),523 MemberList(ObjMembers),524 /// Field list is created by iteration, see [`ObjComp`].359 ObjComp(ObjComp),525 ObjComp(ObjComp),360}526}361527362/// Object identity reference: `self`, `super`, or `$`.#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]528/// Object identity reference: `self`, `super`, or `$`.#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]363#[derive(Debug, PartialEq, Acyclic)]529#[derive(Debug, PartialEq, Acyclic)]364pub enum IdentityKind {530pub enum IdentityKind {531 /// `self` - renamed to `this` for easier usage in the code.365 This,532 This,533 /// `super`.366 Super,534 Super,535 /// `$`.367 Dollar,536 Dollar,368}537}369538539/// Slice expression range/step.540///541/// `[start:end:step]` in `array[start:end:step]`.370#[derive(Debug, PartialEq, Acyclic)]542#[derive(Debug, PartialEq, Acyclic)]371pub struct SliceDesc {543pub struct SliceDesc {544 /// Slice start (inclusive) - elements before are not included. Counts from the end when negative.545 ///546 /// `0` when `None`.372 pub start: Option<Spanned<Expr>>,547 pub start: Option<Spanned<Expr>>,548 /// Slice end (exclusive) - elements after/at are not included. Counts from the end when negative.549 ///550 /// `std.length(array)` when `None`.373 pub end: Option<Spanned<Expr>>,551 pub end: Option<Spanned<Expr>>,552 /// Slice step - every `step`'th element is included in the resulting array. `step >= 1`.553 ///554 /// `1` when `None`.374 pub step: Option<Spanned<Expr>>,555 pub step: Option<Spanned<Expr>>,375}556}376557558/// Assert expression.559///560/// ```jsonnet561/// assert value; rest562/// ```563///564/// Asserts `value`, continues with the evaluation of `rest`.377#[derive(Debug, PartialEq, Acyclic)]565#[derive(Debug, PartialEq, Acyclic)]378pub struct AssertExpr {566pub struct AssertExpr {567 /// Value to assert, see [`AssertStmt`].379 pub assert: AssertStmt,568 pub assert: AssertStmt,569 /// What value to return when the assertion is succeeded.380 pub rest: Expr,570 pub rest: Expr,381}571}382572573/// Binary expression.574///575/// ```jsonnet576/// a + b577/// ```383#[derive(Debug, PartialEq, Acyclic)]578#[derive(Debug, PartialEq, Acyclic)]384pub struct BinaryOp {579pub struct BinaryOp {580 /// Value to the left of binary operator.385 pub lhs: Expr,581 pub lhs: Expr,582 /// Operator to apply.386 pub op: BinaryOpType,583 pub op: BinaryOpType,584 /// Value to the right of binary operator.387 pub rhs: Expr,585 pub rhs: Expr,388}586}389587588/// Import expression kind.589///590/// `str` in `importstr "path"`.390#[derive(Debug, PartialEq, Acyclic, Clone, Copy)]591#[derive(Debug, PartialEq, Acyclic, Clone, Copy)]391pub enum ImportKind {592pub enum ImportKind {593 /// `import`392 Normal,594 Normal,595 /// `importstr`393 Str,596 Str,597 /// `importbin`394 Bin,598 Bin,395}599}396600601/// If else expression.602///603/// ```jsonnet604/// if a then b else c605/// ```397#[derive(Debug, PartialEq, Acyclic)]606#[derive(Debug, PartialEq, Acyclic)]398pub struct IfElse {607pub struct IfElse {608 /// Condition to evaluate, see [`IfSpecData`].399 pub cond: IfSpecData,609 pub cond: IfSpecData,610 /// Value to return if the condition is `true`.400 pub cond_then: Expr,611 pub cond_then: Expr,612 /// Value to return if the condition is `false`, `null` when `None`.401 pub cond_else: Option<Expr>,613 pub cond_else: Option<Expr>,402}614}403615616/// Slice expression.617///618/// ```jsonnet619/// value[start:end:slice]620/// ```404#[derive(Debug, PartialEq, Acyclic)]621#[derive(Debug, PartialEq, Acyclic)]405pub struct Slice {622pub struct Slice {623 /// Value to slice, should evaluate to iterable.406 pub value: Expr,624 pub value: Expr,625 /// Slice definition, see [`SliceDesc`].407 pub slice: SliceDesc,626 pub slice: SliceDesc,408}627}409628413 /// Object-identity reference: `self`, `super`, `$`.632 /// Object-identity reference: `self`, `super`, `$`.414 Identity(Span, IdentityKind),633 Identity(Span, IdentityKind),415634416 /// Trivial value literal635 /// Trivial value literal, see [`TrivialVal`].417 Trivial(TrivialVal),636 Trivial(TrivialVal),418637419 /// Variable name: test638 /// Local reference.420 Var(Spanned<IStr>),639 Var(Spanned<IStr>),421640422 /// Array of expressions: [1, 2, "Hello"]641 /// Array of expressions.642 ///643 /// ```jsonnet644 /// [1, 2, "Hello"]645 /// ```423 Arr(Vec<Expr>),646 Arr(Vec<Expr>),424 /// Array comprehension:647 /// Array comprehension.648 ///425 /// ```jsonnet649 /// ```jsonnet426 /// ingredients: [650 /// ingredients: [427 /// { kind: kind, qty: 4 / 3 }651 /// { kind: kind, qty: 4 / 3 }434 /// ```658 /// ```435 ArrComp(Box<Expr>, Vec<CompSpec>),659 ArrComp(Box<Expr>, Vec<CompSpec>),436660661 /// Object creation, see [`ObjBody`].662 ///663 /// ```jsonnet437 /// Object: {a: 2}664 /// {a: 2}665 /// ```438 Obj(ObjBody),666 Obj(ObjBody),439 /// Object extension: var1 {b: 2}667 /// Object extension.668 ///669 /// ```jsonnet670 /// var1 {b: 2}671 /// ```672 ///673 /// Equivalent to `var {b: 2}`.440 ObjExtend(Box<Expr>, ObjBody),674 ObjExtend(Box<Expr>, ObjBody),441675676 /// Unary operator expression, see [`UnaryOpType`].677 ///678 /// ```jsonnet442 /// -2679 /// -2680 /// ```443 UnaryOp(UnaryOpType, Box<Expr>),681 UnaryOp(UnaryOpType, Box<Expr>),682 /// Binary operator expression, see [`BinaryOp`].683 ///684 /// ```jsonnet444 /// 2 - 2685 /// 2 - 2686 /// ```445 BinaryOp(Box<BinaryOp>),687 BinaryOp(Box<BinaryOp>),688 /// Assertion expression, see [`AssertExpr`].689 ///690 /// ```jsonnet446 /// assert 2 == 2 : "Math is broken"691 /// assert 2 == 2 : "Math is broken"692 /// ```447 AssertExpr(Box<AssertExpr>),693 AssertExpr(Box<AssertExpr>),694 /// Local expression.695 ///696 /// Defines locals using [`BindSpec`], then evaluates expression in the resulting context scope.697 ///698 /// ```jsonnet448 /// local a = 2; { b: a }699 /// local a = 2; { b: a }700 /// ```449 LocalExpr(Vec<BindSpec>, Box<Expr>),701 LocalExpr(Vec<BindSpec>, Box<Expr>),450702703 /// Import expression704 ///705 /// ```jsonnet451 /// import* "hello"706 /// import "hello"707 /// ```452 Import(Spanned<ImportKind>, Box<Expr>),708 Import(Spanned<ImportKind>, Box<Expr>),709 /// Error expression, immideately throws the error on evaluation.710 ///711 /// ```jsonnet453 /// error "I'm broken"712 /// error "I'm broken"713 /// ```454 ErrorStmt(Span, Box<Expr>),714 ErrorStmt(Span, Box<Expr>),455 /// a(b, c)715 /// Function call.716 ///717 /// See [`ArgsDesc`].456 Apply(Box<Expr>, Spanned<ArgsDesc>, bool),718 Apply(Box<Expr>, Spanned<ArgsDesc>, bool),719 /// Indexing chain.720 ///457 /// a[b], a.b, a?.b721 /// `a[b]`, `a.b`, `a?.b`458 Index {722 Index {723 /// Value to index into.459 indexable: Box<Expr>,724 indexable: Box<Expr>,725 /// Indexing operators to apply in sequence, see [`IndexPart`].460 parts: Vec<IndexPart>,726 parts: Vec<IndexPart>,461 },727 },728 /// Function definition.729 ///730 /// ```jsonnet462 /// function(x) x731 /// function(x) x732 /// ```463 Function(Span, ExprParams, Box<Expr>),733 Function(Span, ExprParams, Box<Expr>),464 /// if true == false then 1 else 2734 /// IfElse expression, see [`IfElse`]465 IfElse(Box<IfElse>),735 IfElse(Box<IfElse>),736 /// Slice expression, see [`Slice`]466 Slice(Box<Slice>),737 Slice(Box<Slice>),467}738}468739740/// Single index chain expression.741///742/// `.value` in `indexed.value`.469#[derive(Debug, PartialEq, Acyclic)]743#[derive(Debug, PartialEq, Acyclic)]470pub struct IndexPart {744pub struct IndexPart {745 /// Span encompassing the current index element definition.471 pub span: Span,746 pub span: Span,747 /// Field/element to get from the indexable value.472 pub value: Expr,748 pub value: Expr,749 /// Null-coaelsing - interrupt the chain earlier returning `null` when the field is missing in the indexed value.473 #[cfg(feature = "exp-null-coaelse")]750 #[cfg(feature = "exp-null-coaelse")]474 pub null_coaelse: bool,751 pub null_coaelse: bool,475}752}476753477/// file, begin offset, end offset754/// A slice of source code, plus path and code itself. Contains begin byte offset, end byte offset.478#[derive(Clone, PartialEq, Eq, Acyclic)]755#[derive(Clone, PartialEq, Eq, Acyclic)]479#[repr(C)]756#[repr(C)]480pub struct Span(pub Source, pub u32, pub u32);757pub struct Span(pub Source, pub u32, pub u32);481impl Span {758impl Span {759 /// Is this span a substring of the other span?482 pub fn belongs_to(&self, other: &Span) -> bool {760 pub fn belongs_to(&self, other: &Span) -> bool {483 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2761 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2484 }762 }763 /// Span standard inclusive range value.485 pub fn range(&self) -> RangeInclusive<usize> {764 pub fn range(&self) -> RangeInclusive<usize> {486 let start = self.1;765 let start = self.1;487 let mut end = self.2;766 let mut end = self.2;502 }781 }503}782}504783784/// Spanned expression.505#[derive(Clone, PartialEq, Acyclic)]785#[derive(Clone, PartialEq, Acyclic)]506pub struct Spanned<T: Acyclic> {786pub struct Spanned<T: Acyclic> {787 /// Spanned expression.507 pub value: T,788 pub value: T,789 /// Span.508 pub span: Span,790 pub span: Span,509}791}510impl<T: Acyclic> Deref for Spanned<T> {792impl<T: Acyclic> Deref for Spanned<T> {514 }796 }515}797}516impl<T: Acyclic> Spanned<T> {798impl<T: Acyclic> Spanned<T> {799 /// Construct the spanned expression.517 #[inline]800 #[inline]518 pub fn new(value: T, span: Span) -> Self {801 pub fn new(value: T, span: Span) -> Self {519 Self { value, span }802 Self { value, span }520 }803 }804 /// Map the spanned expression, leaving span as is.521 pub fn map<U: Acyclic>(self, v: impl FnOnce(T) -> U) -> Spanned<U> {805 pub fn map<U: Acyclic>(self, v: impl FnOnce(T) -> U) -> Spanned<U> {522 Spanned {806 Spanned {523 span: self.span,807 span: self.span,524 value: v(self.value),808 value: v(self.value),525 }809 }526 }810 }811 /// Create [`Spanned`] with the reference to the expression.527 pub fn as_ref<'a>(&'a self) -> Spanned<&'a T>812 pub fn as_ref<'a>(&'a self) -> Spanned<&'a T>528 where813 where529 &'a T: Acyclic,814 &'a T: Acyclic,crates/jrsonnet-ir/src/function.rsdiffbeforeafterboth1//! Function signature definition.2//!3//! TODO: To be moved to analyzer.4//! TODO: Unify the anonymous/unnamed/positional naming.51use std::{fmt, ops::Deref, rc::Rc};6use std::{fmt, ops::Deref, rc::Rc};273use jrsonnet_gcmodule::Acyclic;8use jrsonnet_gcmodule::Acyclic;4use jrsonnet_interner::IStr;9use jrsonnet_interner::IStr;51011/// Function parameter name.6#[derive(Clone, Acyclic, Debug, PartialEq, Eq)]12#[derive(Clone, Acyclic, Debug, PartialEq, Eq)]7pub enum ParamName {13pub enum ParamName {14 /// Unnamed (only possible with `exp-destruct`).8 Unnamed,15 Unnamed,16 /// Named.9 Named(IStr),17 Named(IStr),10}18}11impl ParamName {19impl ParamName {20 /// Get the named parameter name as string.12 pub fn as_str(&self) -> Option<&str> {21 pub fn as_str(&self) -> Option<&str> {13 match self {22 match self {14 ParamName::Unnamed => None,23 ParamName::Unnamed => None,15 ParamName::Named(istr) => Some(istr),24 ParamName::Named(istr) => Some(istr),16 }25 }17 }26 }27 /// Is the parameter positional.18 pub fn is_anonymous(&self) -> bool {28 pub fn is_anonymous(&self) -> bool {19 matches!(self, Self::Unnamed)29 matches!(self, Self::Unnamed)20 }30 }31 /// Is the parameter named.21 pub fn is_named(&self) -> bool {32 pub fn is_named(&self) -> bool {22 matches!(self, Self::Named(_))33 matches!(self, Self::Named(_))23 }34 }40 }51 }41}52}425354/// Parameter default value description.43#[derive(Clone, Copy, Debug, Acyclic, PartialEq, Eq)]55#[derive(Clone, Copy, Debug, Acyclic, PartialEq, Eq)]44pub enum ParamDefault {56pub enum ParamDefault {57 /// No default exists.45 None,58 None,59 /// Default exists, but omitted from the error details (e.g handled in native code).46 Exists,60 Exists,61 /// Default exists, stringified.47 Literal(&'static str),62 Literal(&'static str),48}63}49impl ParamDefault {64impl ParamDefault {65 /// Createn optional [`ParamDefault`] without the stringified value for the error messages.50 pub const fn exists(is_exists: bool) -> Self {66 pub const fn exists(is_exists: bool) -> Self {51 if is_exists { Self::Exists } else { Self::None }67 if is_exists { Self::Exists } else { Self::None }52 }68 }61 }77 }62}78}637980/// Function parameter for argument matching purposes.64#[derive(Clone, Acyclic, Debug, PartialEq, Eq)]81#[derive(Clone, Acyclic, Debug, PartialEq, Eq)]65pub struct ParamParse {82pub struct ParamParse {66 name: ParamName,83 name: ParamName,67 default: ParamDefault,84 default: ParamDefault,68}85}69impl ParamParse {86impl ParamParse {87 /// Construct the function parameter definition.70 pub fn new(name: ParamName, default: ParamDefault) -> Self {88 pub fn new(name: ParamName, default: ParamDefault) -> Self {71 Self { name, default }89 Self { name, default }72 }90 }73 /// Parameter name for named call parsing91 /// Parameter name for named call parsing.74 pub fn name(&self) -> &ParamName {92 pub fn name(&self) -> &ParamName {75 &self.name93 &self.name76 }94 }95 /// Default value for error reporting.77 pub fn default(&self) -> ParamDefault {96 pub fn default(&self) -> ParamDefault {78 self.default97 self.default79 }98 }99 /// Can this parameter be derived implicitly?80 pub fn has_default(&self) -> bool {100 pub fn has_default(&self) -> bool {81 !matches!(self.default, ParamDefault::None)101 !matches!(self.default, ParamDefault::None)82 }102 }87 }107 }88}108}89109110/// Function definition signature internals.90#[derive(Debug, Clone, Acyclic, PartialEq, Eq)]111#[derive(Debug, Clone, Acyclic, PartialEq, Eq)]91pub struct FunctionSignature(Rc<[ParamParse]>);112pub struct FunctionSignature(Rc<[ParamParse]>);92impl Deref for FunctionSignature {113impl Deref for FunctionSignature {102}123}103124104impl FunctionSignature {125impl FunctionSignature {126 /// Construct a function signature.105 pub fn new(v: Rc<[ParamParse]>) -> Self {127 pub fn new(v: Rc<[ParamParse]>) -> Self {106 Self(v)128 Self(v)107 }129 }130 /// Function signature of a degenerate function `function() value`.108 pub fn empty() -> Self {131 pub fn empty() -> Self {109 EMPTY_SIGNATURE.with(|p| p.clone())132 EMPTY_SIGNATURE.with(|p| p.clone())110 }133 }crates/jrsonnet-ir/src/lib.rsdiffbeforeafterboth1#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]1#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]2#![deny(missing_docs)]2//! Jrsonnet AST definitions3//! Jrsonnet AST definitions344mod expr;5mod expr;crates/jrsonnet-ir/src/location.rsdiffbeforeafterboth1/// Parsed source code location info.1#[allow(clippy::module_name_repetitions)]2#[allow(clippy::module_name_repetitions)]2#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]3#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]3pub struct CodeLocation {4pub struct CodeLocation {5 /// Source code byte offset.4 pub offset: usize,6 pub offset: usize,578 /// 1-based line number.6 pub line: usize,9 pub line: usize,10 /// 1-based column number.7 pub column: usize,11 pub column: usize,81213 /// Source code byte offset for the current line start.9 pub line_start_offset: usize,14 pub line_start_offset: usize,15 /// Source code byte offset for the current line end.10 pub line_end_offset: usize,16 pub line_end_offset: usize,11}17}1218crates/jrsonnet-ir/src/source.rsdiffbeforeafterboth141415macro_rules! any_ext_methods {15macro_rules! any_ext_methods {16 ($T:ident) => {16 ($T:ident) => {17 fn as_any(&self) -> &dyn Any;17 /// Object-safe Hash implementation, usually provided by [`any_ext_impl`] macro.18 fn dyn_hash(&self, hasher: &mut dyn Hasher);18 fn dyn_hash(&self, hasher: &mut dyn Hasher);19 /// Object-safe PartialEq/Eq implementation, usually provided by [`any_ext_impl`] macro.19 fn dyn_eq(&self, other: &dyn $T) -> bool;20 fn dyn_eq(&self, other: &dyn $T) -> bool;20 fn dyn_debug(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;21 };21 };22}22}23macro_rules! any_ext_impl {23macro_rules! any_ext_impl {24 ($T:ident) => {24 ($T:ident) => {25 fn as_any(&self) -> &dyn Any {26 self27 }28 fn dyn_hash(&self, mut hasher: &mut dyn Hasher) {25 fn dyn_hash(&self, mut hasher: &mut dyn Hasher) {29 self.hash(&mut hasher)26 self.hash(&mut hasher)30 }27 }31 fn dyn_eq(&self, other: &dyn $T) -> bool {28 fn dyn_eq(&self, other: &dyn $T) -> bool {29 let other: &dyn Any = &*other;32 let Some(other) = other.as_any().downcast_ref::<Self>() else {30 let Some(other) = other.downcast_ref::<Self>() else {33 return false;31 return false;34 };32 };35 let this = <Self as $T>::as_any(self)33 let this: &dyn Any = &*self;36 .downcast_ref::<Self>()34 let this = this.downcast_ref::<Self>().expect("restricted by impl");37 .expect("restricted by impl");38 this == other35 this == other39 }36 }40 fn dyn_debug(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {41 <Self as std::fmt::Debug>::fmt(self, fmt)42 }43 };37 };44}38}45macro_rules! any_ext {39macro_rules! any_ext {57 impl Eq for dyn $T {}51 impl Eq for dyn $T {}58 };52 };59}53}54/// Represents trait methods used by [`SourcePath`] implementation.60pub trait SourcePathT: Acyclic + Debug + Display {55pub trait SourcePathT: Acyclic + Debug + Display + Any {61 /// This method should be checked by resolver before panicking with bad SourcePath input56 /// This method should be checked by resolver before panicking with bad SourcePath input62 /// if `true` - then resolver may threat this path as default, and default is usally a CWD57 /// if `true` - then resolver may threat this path as default, and default is usally a CWD.63 fn is_default(&self) -> bool;58 fn is_default(&self) -> bool;59 /// If this source path is backed by Os [`Path`] - it can be obtained from here.64 fn path(&self) -> Option<&Path>;60 fn path(&self) -> Option<&Path>;65 any_ext_methods!(SourcePathT);61 any_ext_methods!(SourcePathT);66}62}67any_ext!(SourcePathT);63any_ext!(SourcePathT);686469/// Represents location of a file65/// Represents location of a file.70///66///71/// Standard CLI only operates using67/// Standard CLI only operates using72/// - [`SourceFile`] - for any file68/// - [`SourceFile`] - for any file.73/// - [`SourceDirectory`] - for resolution from CWD69/// - [`SourceDirectory`] - for resolution from CWD.74/// - [`SourceVirtual`] - for stdlib/ext-str70/// - [`SourceVirtual`] - for stdlib/ext-str.75/// - [`SourceFifo`] - for /dev/fd/X (This path may appear with `jrsonnet <(command_that_produces_jsonnet)`)71/// - [`SourceFifo`] - for /dev/fd/X (This path may appear with `jrsonnet <(command_that_produces_jsonnet)`).76///72///77/// From all of those, only [`SourceVirtual`] may be constructed manually, any other path kind should be only obtained73/// From all of those, only [`SourceVirtual`] may be constructed manually, any other path kind should be only obtained78/// from assigned `ImportResolver`74/// from assigned `ImportResolver`.79/// However, you should always check `is_default` method return, as it will return true for any paths, where default75/// However, you should always check `is_default` method return, as it will return true for any paths, where default80/// search location is applicable76/// search location is applicable.81///77///82/// Resolver may also return custom implementations of this trait, for example it may return http url in case of remotely loaded files78/// Resolver may also return custom implementations of this trait, for example it may return http url in case of79/// remotely loaded files.83#[derive(Eq, Clone, Acyclic)]80#[derive(Eq, Clone, Acyclic)]84pub struct SourcePath(Rc<dyn SourcePathT>);81pub struct SourcePath(Rc<dyn SourcePathT>);85impl SourcePath {82impl SourcePath {83 /// Create [`SourcePath`] structure from a unboxed [`SourcePathT`]86 pub fn new(inner: impl SourcePathT) -> Self {84 pub fn new(inner: impl SourcePathT) -> Self {87 Self(Rc::new(inner))85 Self(Rc::new(inner))88 }86 }87 /// Try to downcast the inner boxed [`SourcePathT`] to the specific type.89 pub fn downcast_ref<T: SourcePathT>(&self) -> Option<&T> {88 pub fn downcast_ref<T: SourcePathT>(&self) -> Option<&T> {90 self.0.as_any().downcast_ref()89 let this: &dyn Any = &*self.0;90 this.downcast_ref()91 }91 }92 /// This method should be checked by resolver before panicking with bad SourcePath input93 /// if `true` - then resolver may threat this path as default, and default is usally a CWD.92 pub fn is_default(&self) -> bool {94 pub fn is_default(&self) -> bool {93 self.0.is_default()95 self.0.is_default()94 }96 }97 /// If this source path is backed by Os [`Path`] - it can be obtained from here.95 pub fn path(&self) -> Option<&Path> {98 pub fn path(&self) -> Option<&Path> {96 self.0.path()99 self.0.path()97 }100 }123 }126 }124}127}125128129/// Used as a search base, represents default search path, including JPATH.130/// Used for import resolution for `--ext-str` and other methods without definitive import source.126#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]131#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]127struct SourceDefault;132pub struct SourceDefault;128impl Display for SourceDefault {133impl Display for SourceDefault {129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {130 write!(f, "<default>")135 write!(f, "<default>")140 any_ext_impl!(SourcePathT);145 any_ext_impl!(SourcePathT);141}146}142147148/// Used as a search base, represents default search path, excluding JPATH.149/// Used by default by jrsonnet cli.143#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]150#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]144pub struct SourceDefaultIgnoreJpath;151pub struct SourceDefaultIgnoreJpath;145impl Display for SourceDefaultIgnoreJpath {152impl Display for SourceDefaultIgnoreJpath {157 any_ext_impl!(SourcePathT);164 any_ext_impl!(SourcePathT);158}165}159166160/// Represents path to the file on the disk167/// Represents path to the file on the disk.168///161/// Directories shouldn't be put here, as resolution for files differs from resolution for directories:169/// Directories shouldn't be put here, as resolution for files differs from resolution for directories:162///170///163/// When `file` is being resolved from `SourceFile(a/b/c)`, it should be resolved to `SourceFile(a/b/file)`,171/// When `file` is being resolved from `SourceFile(a/b/c)`, it should be resolved to `SourceFile(a/b/file)`,164/// however if it is being resolved from `SourceDirectory(a/b/c)`, then it should be resolved to `SourceDirectory(a/b/c/file)`172/// however if it is being resolved from `SourceDirectory(a/b/c)`, then it should be resolved to `SourceDirectory(a/b/c/file)`165#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]173#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]166pub struct SourceFile(PathBuf);174pub struct SourceFile(PathBuf);167impl SourceFile {175impl SourceFile {176 /// Wrap a path buf for [`SourceFile`]168 pub fn new(path: PathBuf) -> Self {177 pub fn new(path: PathBuf) -> Self {169 Self(path)178 Self(path)170 }179 }180 /// Retrieve a wrapped [`Path`]171 pub fn path(&self) -> &Path {181 pub fn path(&self) -> &Path {172 &self.0182 &self.0173 }183 }187 any_ext_impl!(SourcePathT);197 any_ext_impl!(SourcePathT);188}198}189199200/// Represents path to the file by URL, used for WASM builds, and UNUSABLE by the default import resolvers.201///202/// Note that it might contain file: urls, but they are not returned in .path() getter (TODO: should it be?..),203/// since we have no defined OsStr encoding for wasm.190#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]204#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]191pub struct SourceUrl(Url);205pub struct SourceUrl(Url);192impl SourceUrl {206impl SourceUrl {207 /// Wrap a url for [`SourceUrl`]193 pub fn new(url: Url) -> Self {208 pub fn new(url: Url) -> Self {194 Self(url)209 Self(url)195 }210 }204 false219 false205 }220 }206 fn path(&self) -> Option<&Path> {221 fn path(&self) -> Option<&Path> {222 // TODO: Parse file:?207 None223 None208 }224 }209 any_ext_impl!(SourcePathT);225 any_ext_impl!(SourcePathT);210}226}211227212/// Represents path to the directory on the disk228/// Represents path to the directory on the disk.213///229///214/// See also [`SourceFile`]230/// See also [`SourceFile`].215#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]231#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]216pub struct SourceDirectory(PathBuf);232pub struct SourceDirectory(PathBuf);217impl SourceDirectory {233impl SourceDirectory {234 /// Wrap a path buf pointing to directory for [`SourceDirectory`]218 pub fn new(path: PathBuf) -> Self {235 pub fn new(path: PathBuf) -> Self {219 Self(path)236 Self(path)220 }237 }238 /// Retrieve a wrapped [`Path`]221 pub fn path(&self) -> &Path {239 pub fn path(&self) -> &Path {222 &self.0240 &self.0223 }241 }300pub struct Source(pub Rc<(SourcePath, IStr)>);318pub struct Source(pub Rc<(SourcePath, IStr)>);301319302impl Source {320impl Source {321 /// Wrap a source path and source code.303 pub fn new(path: SourcePath, code: IStr) -> Self {322 pub fn new(path: SourcePath, code: IStr) -> Self {304 Self(Rc::new((path, code)))323 Self(Rc::new((path, code)))305 }324 }306325326 /// Create a virtual source for the given name and source code.307 pub fn new_virtual(name: IStr, code: IStr) -> Self {327 pub fn new_virtual(name: IStr, code: IStr) -> Self {308 Self::new(SourcePath::new(SourceVirtual(name)), code)328 Self::new(SourcePath::new(SourceVirtual(name)), code)309 }329 }310330331 /// Retrieve the stored source code.311 pub fn code(&self) -> &str {332 pub fn code(&self) -> &str {312 &self.0.1333 &self.0.1313 }334 }314335336 /// Retrieve the stored file path.315 pub fn source_path(&self) -> &SourcePath {337 pub fn source_path(&self) -> &SourcePath {316 &self.0.0338 &self.0.0317 }339 }318340341 /// Convert span locations into line number+column+extra information for diagnostics/lsp.342 ///343 /// See [`CodeLocation`].319 pub fn map_source_locations<const S: usize>(&self, locs: &[u32; S]) -> [CodeLocation; S] {344 pub fn map_source_locations<const S: usize>(&self, locs: &[u32; S]) -> [CodeLocation; S] {320 offset_to_location(&self.0.1, locs)345 offset_to_location(&self.0.1, locs)321 }346 }347 /// Unconvert the line number+column from the representaion used by [`CodeLocation`] to the span offset.322 pub fn map_from_source_location(&self, line: usize, column: usize) -> Option<usize> {348 pub fn map_from_source_location(&self, line: usize, column: usize) -> Option<usize> {323 location_to_offset(&self.0.1, line, column)349 location_to_offset(&self.0.1, line, column)324 }350 }crates/jrsonnet-ir/src/visit.rsdiffbeforeafterboth1//! Visitor for jrsonnet AST2//!3//! Only useful for import analysis for now, if you want to use it for something else -4//! feel free to submit your PRs for the necessary features.51use jrsonnet_interner::IStr;6use jrsonnet_interner::IStr;27crates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth2use jrsonnet_ir::{2use jrsonnet_ir::{3 ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, DestructRest, Expr,3 ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, DestructRest, Expr,4 ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IdentityKind, IfElse,4 ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IdentityKind, IfElse,5 IfSpecData, ImportKind, IndexPart, Member, NumValue, ObjBody, ObjComp, ObjMembers, Slice,5 IfSpecData, ImportKind, IndexPart, NumValue, ObjBody, ObjComp, ObjMembers, Slice, SliceDesc,6 SliceDesc, Source, Span, Spanned, TrivialVal, Visibility,6 Source, Span, Spanned, TrivialVal, Visibility,7};7};8use jrsonnet_lexer::unescape;8use jrsonnet_lexer::unescape;27 };27 };28}28}292930enum Member {31 BindStmt(BindSpec),32 AssertStmt(AssertStmt),33 Field(FieldMember),34}30parser! {35parser! {31 pub grammar jsonnet_parser() for str {36 pub grammar jsonnet_parser() for str {32 use peg::ParseLiteral;37 use peg::ParseLiteral;