difftreelog
Merge remote-tracking branch 'origin/feature/importbin' into gcmodule
in: master
11 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth223use jrsonnet_evaluator::{3use jrsonnet_evaluator::{4 error::{Error::*, Result},4 error::{Error::*, Result},5 throw, EvaluationState, IStr, ImportResolver,5 throw, EvaluationState, ImportResolver,6};6};7use std::{7use std::{8 any::Any,8 any::Any,30 cb: JsonnetImportCallback,30 cb: JsonnetImportCallback,31 ctx: *mut c_void,31 ctx: *mut c_void,3233 out: RefCell<HashMap<PathBuf, IStr>>,32 out: RefCell<HashMap<PathBuf, Vec<u8>>>,34}33}35impl ImportResolver for CallbackImportResolver {34impl ImportResolver for CallbackImportResolver {36 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {35 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {757476 Ok(found_here_buf.into())75 Ok(found_here_buf.into())77 }76 }78 fn load_file_contents(&self, resolved: &Path) -> Result<IStr> {77 fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>> {79 Ok(self.out.borrow().get(resolved).unwrap().clone())78 Ok(self.out.borrow().get(resolved).unwrap().clone())80 }79 }80124 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))124 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))125 }125 }126 }126 }127 fn load_file_contents(&self, id: &Path) -> Result<IStr> {127 fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {128 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;128 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;129 let mut out = String::new();129 let mut out = Vec::new();130 file.read_to_string(&mut out)130 file.read_to_end(&mut out)131 .map_err(|_e| ImportBadFileUtf8(id.to_owned()))?;131 .map_err(|e| ImportIo(e.to_string()))?;132 Ok(out.into())132 Ok(out)133 }133 }134 unsafe fn as_any(&self) -> &dyn Any {134 unsafe fn as_any(&self) -> &dyn Any {135 self135 selfcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth1use crate::function::{CallLocation, StaticBuiltin};1use crate::function::{CallLocation, StaticBuiltin};2use crate::typed::{Any, PositiveF64, VecVal, M1};2use crate::typed::{Any, Bytes, PositiveF64, VecVal, M1};3use crate::{3use crate::{4 builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},4 builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},5 equals,5 equals,447}447}448448449#[jrsonnet_macros::builtin]449#[jrsonnet_macros::builtin]450fn builtin_encode_utf8(str: IStr) -> Result<VecVal> {450fn builtin_encode_utf8(str: IStr) -> Result<Bytes> {451 Ok(VecVal(451 Ok(Bytes(str.bytes().map(|b| b).collect::<Vec<u8>>().into()))452 str.bytes()453 .map(|b| Val::Num(b as f64))454 .collect::<Vec<Val>>(),455 ))456}452}457453458#[jrsonnet_macros::builtin]454#[jrsonnet_macros::builtin]459fn builtin_decode_utf8(arr: Vec<u8>) -> Result<String> {455fn builtin_decode_utf8(arr: Bytes) -> Result<IStr> {460 Ok(String::from_utf8(arr).map_err(|_| RuntimeError("bad utf8".into()))?)456 Ok(std::str::from_utf8(&arr.0)457 .map_err(|_| RuntimeError("bad utf8".into()))?458 .into())461}459}462460463#[jrsonnet_macros::builtin]461#[jrsonnet_macros::builtin]483}481}484482485#[jrsonnet_macros::builtin]483#[jrsonnet_macros::builtin]486fn builtin_base64(input: Either![Vec<u8>, IStr]) -> Result<String> {484fn builtin_base64(input: Either![Bytes, IStr]) -> Result<String> {487 use Either2::*;485 use Either2::*;488 Ok(match input {486 Ok(match input {489 A(a) => base64::encode(a),487 A(a) => base64::encode(a.0),490 B(l) => base64::encode(l.bytes().collect::<Vec<_>>()),488 B(l) => base64::encode(l.bytes().collect::<Vec<_>>()),491 })489 })492}490}493491494#[jrsonnet_macros::builtin]492#[jrsonnet_macros::builtin]495fn builtin_base64_decode_bytes(input: IStr) -> Result<Vec<u8>> {493fn builtin_base64_decode_bytes(input: IStr) -> Result<Bytes> {496 Ok(base64::decode(&input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?)494 Ok(Bytes(495 base64::decode(&input.as_bytes())496 .map_err(|_| RuntimeError("bad base64".into()))?497 .into(),498 ))497}499}498500499#[jrsonnet_macros::builtin]501#[jrsonnet_macros::builtin]crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth82 ResolvedFileNotFound(PathBuf),82 ResolvedFileNotFound(PathBuf),83 #[error("imported file is not valid utf-8: {0:?}")]83 #[error("imported file is not valid utf-8: {0:?}")]84 ImportBadFileUtf8(PathBuf),84 ImportBadFileUtf8(PathBuf),85 #[error("import io error: {0}")]86 ImportIo(String),85 #[error("tried to import {1} from {0}, but imports is not supported")]87 #[error("tried to import {1} from {0}, but imports is not supported")]86 ImportNotSupported(PathBuf, PathBuf),88 ImportNotSupported(PathBuf, PathBuf),87 #[error(89 #[error(crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth701 import_location.pop();701 import_location.pop();702 Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)702 Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)703 }703 }704 ImportBin(path) => {705 let tmp = loc.clone().0;706 let mut import_location = tmp.to_path_buf();707 import_location.pop();708 let bytes = with_state(|s| s.import_file_bin(&import_location, path))?;709 Val::Arr(ArrValue::Bytes(bytes))710 }704 })711 })705}712}706713crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth5use fs::File;5use fs::File;6use jrsonnet_interner::IStr;6use jrsonnet_interner::IStr;7use std::fs;7use std::fs;8use std::io::Read;9use std::{8use std::{10 any::Any,9 any::Any,11 cell::RefCell,12 collections::HashMap,13 path::{Path, PathBuf},10 path::{Path, PathBuf},14 rc::Rc,11 rc::Rc,15};12};13use std::{convert::TryFrom, io::Read};161417/// Implements file resolution logic for `import` and `importStr`15/// Implements file resolution logic for `import` and `importStr`18pub trait ImportResolver {16pub trait ImportResolver {21 /// where `${vendor}` is a library path.19 /// where `${vendor}` is a library path.22 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>>;20 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>>;2122 fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>>;232324 /// Reads file from filesystem, should be used only with path received from `resolve_file`24 /// Reads file from filesystem, should be used only with path received from `resolve_file`25 fn load_file_contents(&self, resolved: &Path) -> Result<IStr>;25 fn load_file_str(&self, resolved: &Path) -> Result<IStr> {26 Ok(IStr::try_from(&self.load_file_contents(resolved)? as &[u8])27 .map_err(|_| ImportBadFileUtf8(resolved.to_path_buf()))?)28 }2930 /// Reads file from filesystem, should be used only with path received from `resolve_file`31 fn load_file_bin(&self, resolved: &Path) -> Result<Rc<[u8]>> {32 Ok(self.load_file_contents(resolved)?.into())33 }263427 /// # Safety35 /// # Safety28 ///36 ///39 throw!(ImportNotSupported(from.into(), path.into()))47 throw!(ImportNotSupported(from.into(), path.into()))40 }48 }414942 fn load_file_contents(&self, _resolved: &Path) -> Result<IStr> {50 fn load_file_contents(&self, _resolved: &Path) -> Result<Vec<u8>> {43 // Can be only caused by library direct consumer, not by supplied jsonnet44 panic!("dummy resolver can't load any file")51 panic!("dummy resolver can't load any file")45 }52 }465379 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))86 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))80 }87 }81 }88 }82 fn load_file_contents(&self, id: &Path) -> Result<IStr> {89 fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {83 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;90 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;84 let mut out = String::new();91 let mut out = Vec::new();85 file.read_to_string(&mut out)92 file.read_to_end(&mut out)86 .map_err(|_e| ImportBadFileUtf8(id.to_owned()))?;93 .map_err(|e| ImportIo(e.to_string()))?;87 Ok(out.into())94 Ok(out)88 }95 }89 unsafe fn as_any(&self) -> &dyn Any {96 unsafe fn as_any(&self) -> &dyn Any {90 panic!("this resolver can't be used as any")97 panic!("this resolver can't be used as any")91 }98 }92}99}9394type ResolutionData = (PathBuf, PathBuf);9596/// Caches results of the underlying resolver97pub struct CachingImportResolver {98 resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<Path>>>>,99 loading_cache: RefCell<HashMap<PathBuf, Result<IStr>>>,100 inner: Box<dyn ImportResolver>,101}102impl ImportResolver for CachingImportResolver {103 fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {104 self.resolution_cache105 .borrow_mut()106 .entry((from.to_owned(), path.to_owned()))107 .or_insert_with(|| self.inner.resolve_file(from, path))108 .clone()109 }110111 fn load_file_contents(&self, resolved: &Path) -> Result<IStr> {112 self.loading_cache113 .borrow_mut()114 .entry(resolved.to_owned())115 .or_insert_with(|| self.inner.load_file_contents(resolved))116 .clone()117 }118 unsafe fn as_any(&self) -> &dyn Any {119 panic!("this resolver can't be used as any")120 }121}122100crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth118118119 breakpoints: Breakpoints,119 breakpoints: Breakpoints,120 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces120 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces121 files: HashMap<Rc<Path>, FileData>,121 files: GcHashMap<Rc<Path>, FileData>,122 str_files: HashMap<Rc<Path>, IStr>,122 str_files: GcHashMap<Rc<Path>, IStr>,123 bin_files: GcHashMap<Rc<Path>, Rc<[u8]>>,123}124}124125125pub struct FileData {126pub struct FileData {280 return self.evaluate_loaded_file_raw(&file_path);281 return self.evaluate_loaded_file_raw(&file_path);281 }282 }282 }283 }283 let contents = self.load_file_contents(&file_path)?;284 let contents = self.load_file_str(&file_path)?;284 self.add_file(file_path.clone(), contents)?;285 self.add_file(file_path.clone(), contents)?;285 self.evaluate_loaded_file_raw(&file_path)286 self.evaluate_loaded_file_raw(&file_path)286 }287 }287 pub(crate) fn import_file_str(&self, from: &Path, path: &Path) -> Result<IStr> {288 pub(crate) fn import_file_str(&self, from: &Path, path: &Path) -> Result<IStr> {288 let path = self.resolve_file(from, path)?;289 let path = self.resolve_file(from, path)?;289 if !self.data().str_files.contains_key(&path) {290 if !self.data().str_files.contains_key(&path) {290 let file_str = self.load_file_contents(&path)?;291 let file_str = self.load_file_str(&path)?;291 self.data_mut().str_files.insert(path.clone(), file_str);292 self.data_mut().str_files.insert(path.clone(), file_str);292 }293 }293 Ok(self.data().str_files.get(&path).cloned().unwrap())294 Ok(self.data().str_files.get(&path).cloned().unwrap())294 }295 }296 pub(crate) fn import_file_bin(&self, from: &Path, path: &Path) -> Result<Rc<[u8]>> {297 let path = self.resolve_file(from, path)?;298 if !self.data().bin_files.contains_key(&path) {299 let file_bin = self.load_file_bin(&path)?;300 self.data_mut().bin_files.insert(path.clone(), file_bin);301 }302 Ok(self.data().bin_files.get(&path).cloned().unwrap())303 }295304296 fn evaluate_loaded_file_raw(&self, name: &Path) -> Result<Val> {305 fn evaluate_loaded_file_raw(&self, name: &Path) -> Result<Val> {297 let expr: LocExpr = {306 let expr: LocExpr = {607 pub fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {616 pub fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {608 self.settings().import_resolver.resolve_file(from, path)617 self.settings().import_resolver.resolve_file(from, path)609 }618 }610 pub fn load_file_contents(&self, path: &Path) -> Result<IStr> {619 pub fn load_file_str(&self, path: &Path) -> Result<IStr> {611 self.settings().import_resolver.load_file_contents(path)620 self.settings().import_resolver.load_file_str(path)612 }621 }622 pub fn load_file_bin(&self, path: &Path) -> Result<Rc<[u8]>> {623 self.settings().import_resolver.load_file_bin(path)624 }613625614 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {626 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {615 Ref::map(self.settings(), |s| &*s.import_resolver)627 Ref::map(self.settings(), |s| &*s.import_resolver)687 primitive_equals, EvaluationState,699 primitive_equals, EvaluationState,688 };700 };689 use gcmodule::{Cc, Trace};701 use gcmodule::{Cc, Trace};690 use jrsonnet_interner::IStr;691 use jrsonnet_parser::*;702 use jrsonnet_parser::*;692 use std::{703 use std::{693 path::{Path, PathBuf},704 path::{Path, PathBuf},1204 Ok(())1215 Ok(())1205 }1216 }120612171207 struct TestImportResolver(IStr);1218 struct TestImportResolver(Vec<u8>);1208 impl crate::import::ImportResolver for TestImportResolver {1219 impl crate::import::ImportResolver for TestImportResolver {1209 fn resolve_file(&self, _: &Path, _: &Path) -> crate::error::Result<Rc<Path>> {1220 fn resolve_file(&self, _: &Path, _: &Path) -> crate::error::Result<Rc<Path>> {1210 Ok(PathBuf::from("/test").into())1221 Ok(PathBuf::from("/test").into())1211 }1222 }121212231213 fn load_file_contents(&self, _: &Path) -> crate::error::Result<IStr> {1224 fn load_file_contents(&self, _: &Path) -> crate::error::Result<Vec<u8>> {1214 Ok(self.0.clone())1225 Ok(self.0.clone())1215 }1226 }121612271217 unsafe fn as_any(&self) -> &dyn std::any::Any {1228 unsafe fn as_any(&self) -> &dyn std::any::Any {1218 panic!()1229 panic!()1219 }1230 }12311232 fn load_file_bin(&self, _resolved: &Path) -> crate::error::Result<Rc<[u8]>> {1233 panic!()1234 }1220 }1235 }122112361222 #[test]1237 #[test]crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth1use std::convert::{TryFrom, TryInto};1use std::{2 convert::{TryFrom, TryInto},3 rc::Rc,4};253use gcmodule::Cc;6use gcmodule::Cc;4use jrsonnet_interner::IStr;7use jrsonnet_interner::IStr;306 }309 }307}310}311312/// Specialization313pub struct Bytes(pub Rc<[u8]>);314315impl Typed for Bytes {316 const TYPE: &'static ComplexValType =317 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));318}319impl TryFrom<Val> for Bytes {320 type Error = LocError;321322 fn try_from(value: Val) -> Result<Self> {323 match value {324 Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),325 _ => {326 <Self as Typed>::TYPE.check(&value)?;327 match value {328 Val::Arr(a) => {329 let mut out = Vec::with_capacity(a.len());330 for e in a.iter() {331 let r = e?;332 out.push(u8::try_from(r)?);333 }334 Ok(Self(out.into()))335 }336 _ => unreachable!(),337 }338 }339 }340 }341}342impl TryFrom<Bytes> for Val {343 type Error = LocError;344345 fn try_from(value: Bytes) -> Result<Self> {346 Ok(Val::Arr(ArrValue::Bytes(value.0)))347 }348}308349309pub struct M1;350pub struct M1;310impl Typed for M1 {351impl Typed for M1 {crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth174#[derive(Debug, Clone, Trace)]174#[derive(Debug, Clone, Trace)]175#[force_tracking]175#[force_tracking]176pub enum ArrValue {176pub enum ArrValue {177 Bytes(#[skip_trace] Rc<[u8]>),177 Lazy(Cc<Vec<LazyVal>>),178 Lazy(Cc<Vec<LazyVal>>),178 Eager(Cc<Vec<Val>>),179 Eager(Cc<Vec<Val>>),179 Extended(Box<(Self, Self)>),180 Extended(Box<(Self, Self)>),185186186 pub fn len(&self) -> usize {187 pub fn len(&self) -> usize {187 match self {188 match self {189 Self::Bytes(i) => i.len(),188 Self::Lazy(l) => l.len(),190 Self::Lazy(l) => l.len(),189 Self::Eager(e) => e.len(),191 Self::Eager(e) => e.len(),190 Self::Extended(v) => v.0.len() + v.1.len(),192 Self::Extended(v) => v.0.len() + v.1.len(),197199198 pub fn get(&self, index: usize) -> Result<Option<Val>> {200 pub fn get(&self, index: usize) -> Result<Option<Val>> {199 match self {201 match self {202 Self::Bytes(i) => i203 .get(index)204 .map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),200 Self::Lazy(vec) => {205 Self::Lazy(vec) => {201 if let Some(v) = vec.get(index) {206 if let Some(v) = vec.get(index) {202 Ok(Some(v.evaluate()?))207 Ok(Some(v.evaluate()?))218223219 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {224 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {220 match self {225 match self {226 Self::Bytes(i) => i227 .get(index)228 .map(|b| LazyVal::new_resolved(Val::Num(*b as f64))),221 Self::Lazy(vec) => vec.get(index).cloned(),229 Self::Lazy(vec) => vec.get(index).cloned(),222 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),230 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),223 Self::Extended(v) => {231 Self::Extended(v) => {233241234 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {242 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {235 Ok(match self {243 Ok(match self {244 Self::Bytes(i) => {245 let mut out = Vec::with_capacity(i.len());246 for v in i.iter() {247 out.push(Val::Num(*v as f64));248 }249 Cc::new(out)250 }236 Self::Lazy(vec) => {251 Self::Lazy(vec) => {237 let mut out = Vec::with_capacity(vec.len());252 let mut out = Vec::with_capacity(vec.len());238 for item in vec.iter() {253 for item in vec.iter() {253268254 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {269 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {255 (0..self.len()).map(move |idx| match self {270 (0..self.len()).map(move |idx| match self {271 Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),256 Self::Lazy(l) => l[idx].evaluate(),272 Self::Lazy(l) => l[idx].evaluate(),257 Self::Eager(e) => Ok(e[idx].clone()),273 Self::Eager(e) => Ok(e[idx].clone()),258 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),274 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),261277262 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {278 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {263 (0..self.len()).map(move |idx| match self {279 (0..self.len()).map(move |idx| match self {280 Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),264 Self::Lazy(l) => l[idx].clone(),281 Self::Lazy(l) => l[idx].clone(),265 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),282 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),266 Self::Extended(_) => self.get_lazy(idx).unwrap(),283 Self::Extended(_) => self.get_lazy(idx).unwrap(),269286270 pub fn reversed(self) -> Self {287 pub fn reversed(self) -> Self {271 match self {288 match self {289 Self::Bytes(b) => {290 let mut out = b.to_vec();291 out.reverse();292 Self::Bytes(out.into())293 }272 Self::Lazy(vec) => {294 Self::Lazy(vec) => {273 let mut out = (&vec as &Vec<_>).clone();295 let mut out = (&vec as &Vec<_>).clone();274 out.reverse();296 out.reverse();crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth4use std::{4use std::{5 borrow::Cow,5 borrow::Cow,6 cell::RefCell,6 cell::RefCell,7 convert::TryFrom,7 fmt::{self, Display},8 fmt::{self, Display},8 hash::{BuildHasherDefault, Hash, Hasher},9 hash::{BuildHasherDefault, Hash, Hasher},9 ops::Deref,10 ops::Deref,10 rc::Rc,11 rc::Rc,12 str::Utf8Error,11};13};121413#[derive(Clone, PartialOrd, Ord, Eq)]15#[derive(Clone, PartialOrd, Ord, Eq)]85 }87 }86}88}8990impl TryFrom<&[u8]> for IStr {91 type Error = Utf8Error;9293 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {94 let str = std::str::from_utf8(value)?;95 Ok(str.into())96 }97}879888impl From<String> for IStr {99impl From<String> for IStr {89 fn from(str: String) -> Self {100 fn from(str: String) -> Self {crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth285 Import(PathBuf),285 Import(PathBuf),286 /// importStr "file.txt"286 /// importStr "file.txt"287 ImportStr(PathBuf),287 ImportStr(PathBuf),288 /// importBin "file.txt"289 ImportBin(PathBuf),288 /// error "I'm broken"290 /// error "I'm broken"289 ErrorStmt(LocExpr),291 ErrorStmt(LocExpr),290 /// a(b, c)292 /// a(b, c)crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.parse().map_err(|_| "<number>") }} / expected!("<number>")53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.parse().map_err(|_| "<number>") }} / expected!("<number>")545455 /// Reserved word followed by any non-alphanumberic55 /// Reserved word followed by any non-alphanumberic56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "importbin" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()57 rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")57 rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")585859 rule keyword(id: &'static str) -> ()59 rule keyword(id: &'static str) -> ()218 / array_comp_expr(s)218 / array_comp_expr(s)219219220 / keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}220 / keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}221 / keyword("importbin") _ path:string() {Expr::ImportBin(PathBuf::from(path))}221 / keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}222 / keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}222223223 / var_expr(s)224 / var_expr(s)