cedar_policy_validator/cedar_schema/parser.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
/*
* Copyright Cedar Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! Parser for schemas in the Cedar syntax
use std::sync::Arc;
use lalrpop_util::lalrpop_mod;
use miette::Diagnostic;
use thiserror::Error;
use super::{
ast::Schema,
err::{self, ParseError, ParseErrors, SchemaWarning, ToJsonSchemaErrors},
to_json_schema::cedar_schema_to_json_schema,
};
use crate::json_schema;
use cedar_policy_core::extensions::Extensions;
lalrpop_mod!(
#[allow(warnings, unused, missing_docs, missing_debug_implementations)]
//PANIC SAFETY: lalrpop uses unwraps, and we are trusting lalrpop to generate correct code
#[allow(clippy::unwrap_used)]
//PANIC SAFETY: lalrpop uses slicing, and we are trusting lalrpop to generate correct code
#[allow(clippy::indexing_slicing)]
//PANIC SAFETY: lalrpop uses unreachable, and we are trusting lalrpop to generate correct code
#[allow(clippy::unreachable)]
//PANIC SAFETY: lalrpop uses panic, and we are trusting lalrpop to generate correct code
#[allow(clippy::panic)]
pub grammar,
"/src/cedar_schema/grammar.rs"
);
/// This helper function calls a generated parser, collects errors that could be
/// generated multiple ways, and returns a single Result where the error type is
/// [`err::ParseErrors`].
fn parse_collect_errors<'a, P, T>(
parser: &P,
parse: impl FnOnce(
&P,
&mut Vec<err::RawErrorRecovery<'a>>,
&Arc<str>,
&'a str,
) -> Result<T, err::RawParseError<'a>>,
text: &'a str,
) -> Result<T, err::ParseErrors> {
let mut errs = Vec::new();
let result = parse(parser, &mut errs, &Arc::from(text), text);
let errors = errs
.into_iter()
.map(Into::into)
.collect::<Vec<ParseError>>();
let parsed = match result {
Ok(parsed) => parsed,
Err(e) => {
return Err(ParseErrors::new(e.into(), errors));
}
};
match ParseErrors::from_iter(errors) {
Some(errors) => Err(errors),
// No Errors: good to return parse
None => Ok(parsed),
}
}
// Thread-safe "global" parsers, initialized at first use
lazy_static::lazy_static! {
static ref SCHEMA_PARSER: grammar::SchemaParser = grammar::SchemaParser::new();
static ref TYPE_PARSER: grammar::TypeParser = grammar::TypeParser::new();
}
/// Parse errors for parsing a schema in the Cedar syntax
//
// This is NOT a publicly exported error type.
#[derive(Debug, Diagnostic, Error)]
#[non_exhaustive]
pub enum CedarSchemaParseErrors {
/// Parse error for the Cedar syntax
#[error(transparent)]
#[diagnostic(transparent)]
SyntaxError(#[from] err::ParseErrors),
/// Error converting the parsed representation into the internal JSON representation
#[error(transparent)]
#[diagnostic(transparent)]
JsonError(#[from] ToJsonSchemaErrors),
}
/// Parse a schema fragment, in the Cedar syntax, into a [`json_schema::Fragment`],
/// possibly generating warnings
pub fn parse_cedar_schema_fragment<'a>(
src: &str,
extensions: &Extensions<'a>,
) -> Result<
(
json_schema::Fragment<crate::RawName>,
impl Iterator<Item = SchemaWarning> + 'a,
),
CedarSchemaParseErrors,
> {
let ast: Schema = parse_collect_errors(&*SCHEMA_PARSER, grammar::SchemaParser::parse, src)?;
let tuple = cedar_schema_to_json_schema(ast, extensions)?;
Ok(tuple)
}
/// Parse schema from text
pub fn parse_schema(text: &str) -> Result<Schema, err::ParseErrors> {
parse_collect_errors(&*SCHEMA_PARSER, grammar::SchemaParser::parse, text)
}