Tokenize into enum instead of string
This commit is contained in:
		
							parent
							
								
									c48790f32f
								
							
						
					
					
						commit
						b54a2b16fe
					
				
					 5 changed files with 376 additions and 340 deletions
				
			
		|  | @ -1,7 +1,7 @@ | ||||||
| use crate::{ | use crate::{ | ||||||
|     scene::PbrtScene, |     scene::PbrtScene, | ||||||
|     shape::{Shape, ShapeAlpha, ShapeType}, |     shape::{Shape, ShapeAlpha, ShapeType}, | ||||||
|     tokenizer::Tokenizer, |     tokenizer::{Token, Tokenizer}, | ||||||
| }; | }; | ||||||
| use material::PbrtMaterial; | use material::PbrtMaterial; | ||||||
| use miette::{IntoDiagnostic, Result, bail, miette}; | use miette::{IntoDiagnostic, Result, bail, miette}; | ||||||
|  | @ -76,7 +76,7 @@ enum Statement { | ||||||
|     CoordinateSystem(String), |     CoordinateSystem(String), | ||||||
|     CoordSysTransform(String), |     CoordSysTransform(String), | ||||||
|     Shape(ShapeType, ShapeAlpha), |     Shape(ShapeType, ShapeAlpha), | ||||||
|     Unknown(String, Vec<String>), |     Unknown(String, Vec<Token>), | ||||||
|     Transform(AffineTransform), |     Transform(AffineTransform), | ||||||
|     Texture(String, Arc<dyn PbrtTexture>), |     Texture(String, Arc<dyn PbrtTexture>), | ||||||
|     Material(Arc<dyn PbrtMaterial>), |     Material(Arc<dyn PbrtMaterial>), | ||||||
|  | @ -96,10 +96,12 @@ fn parse_look_at(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|     let shape_type = iter.next().ok_or(miette!("unable to get shape type"))??; |     let shape_type = iter | ||||||
|  |         .next_if_string_value() | ||||||
|  |         .ok_or(miette!("unable to get shape type"))??; | ||||||
| 
 | 
 | ||||||
|     match shape_type.as_str() { |     match shape_type.as_str() { | ||||||
|         "\"sphere\"" => { |         "sphere" => { | ||||||
|             let t = parse_dict!(iter => |             let t = parse_dict!(iter => | ||||||
|                 radius, Float, 1.0; |                 radius, Float, 1.0; | ||||||
|                 zmin, Float, {-radius}; |                 zmin, Float, {-radius}; | ||||||
|  | @ -107,12 +109,12 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 phimax, Float, 360.0; |                 phimax, Float, 360.0; | ||||||
|                 alpha, ShapeAlpha, ShapeAlpha::None |                 alpha, ShapeAlpha, ShapeAlpha::None | ||||||
|                 => |                 => | ||||||
|                 radius, "\"float radius\"", iter.parse_parameter()?; |                 radius, "float radius", iter.parse_parameter()?; | ||||||
|                 zmin, "\"float zmin\"", iter.parse_parameter()?; |                 zmin, "float zmin", iter.parse_parameter()?; | ||||||
|                 zmax, "\"float zmax\"", iter.parse_parameter()?; |                 zmax, "float zmax", iter.parse_parameter()?; | ||||||
|                 phimax, "\"float phimax\"", iter.parse_parameter()?; |                 phimax, "float phimax", iter.parse_parameter()?; | ||||||
|                 alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); |                 alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?); | ||||||
|                 alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) |                 alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?) | ||||||
|             ); |             ); | ||||||
|             Ok(Statement::Shape( |             Ok(Statement::Shape( | ||||||
|                 ShapeType::Sphere { |                 ShapeType::Sphere { | ||||||
|  | @ -124,7 +126,7 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 t.alpha, |                 t.alpha, | ||||||
|             )) |             )) | ||||||
|         } |         } | ||||||
|         "\"trianglemesh\"" => { |         "trianglemesh" => { | ||||||
|             let t = parse_dict!(iter => |             let t = parse_dict!(iter => | ||||||
|                 p, Vec<Pos3>, Vec::new(); |                 p, Vec<Pos3>, Vec::new(); | ||||||
|                 n, Vec<Dir3>, Vec::new(); |                 n, Vec<Dir3>, Vec::new(); | ||||||
|  | @ -133,13 +135,13 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 indices, Vec<usize>, Vec::new(); |                 indices, Vec<usize>, Vec::new(); | ||||||
|                 alpha, ShapeAlpha, ShapeAlpha::None |                 alpha, ShapeAlpha, ShapeAlpha::None | ||||||
|                 => |                 => | ||||||
|                 p, "\"point3 P\"", iter.parse_list_3(Pos3::new)?; |                 p, "point3 P", iter.parse_list_3(Pos3::new)?; | ||||||
|                 n, "\"normal N\"", iter.parse_list_3(Dir3::new)?; |                 n, "normal N", iter.parse_list_3(Dir3::new)?; | ||||||
|                 s, "\"normal S\"", iter.parse_list_3(Dir3::new)?; |                 s, "normal S", iter.parse_list_3(Dir3::new)?; | ||||||
|                 uv, "\"point2 uv\"", iter.parse_list_2(|u, v| [u, v])?; |                 uv, "point2 uv", iter.parse_list_2(|u, v| [u, v])?; | ||||||
|                 indices, "\"integer indices\"", iter.parse_list()?; |                 indices, "integer indices", iter.parse_list()?; | ||||||
|                 alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); |                 alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?); | ||||||
|                 alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) |                 alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?) | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             if t.p.len() < 3 { |             if t.p.len() < 3 { | ||||||
|  | @ -178,7 +180,7 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 t.alpha, |                 t.alpha, | ||||||
|             )) |             )) | ||||||
|         } |         } | ||||||
|         "\"bilinearmesh\"" => { |         "bilinearmesh" => { | ||||||
|             let t = parse_dict!(iter => |             let t = parse_dict!(iter => | ||||||
|                 p, Vec<Pos3>, Vec::new(); |                 p, Vec<Pos3>, Vec::new(); | ||||||
|                 n, Vec<Dir3>, Vec::new(); |                 n, Vec<Dir3>, Vec::new(); | ||||||
|  | @ -186,12 +188,12 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 indices, Vec<usize>, Vec::new(); |                 indices, Vec<usize>, Vec::new(); | ||||||
|                 alpha, ShapeAlpha, ShapeAlpha::None |                 alpha, ShapeAlpha, ShapeAlpha::None | ||||||
|                 => |                 => | ||||||
|                 p, "\"point3 P\"", iter.parse_list_3(Pos3::new)?; |                 p, "point3 P", iter.parse_list_3(Pos3::new)?; | ||||||
|                 n, "\"normal N\"", iter.parse_list_3(Dir3::new)?; |                 n, "normal N", iter.parse_list_3(Dir3::new)?; | ||||||
|                 uv, "\"point2 uv\"", iter.parse_list_2(|u, v| [u, v])?; |                 uv, "point2 uv", iter.parse_list_2(|u, v| [u, v])?; | ||||||
|                 indices, "\"integer indices\"", iter.parse_list()?; |                 indices, "integer indices", iter.parse_list()?; | ||||||
|                 alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); |                 alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?); | ||||||
|                 alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) |                 alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?) | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             if t.p.len() < 4 { |             if t.p.len() < 4 { | ||||||
|  | @ -226,18 +228,18 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 t.alpha, |                 t.alpha, | ||||||
|             )) |             )) | ||||||
|         } |         } | ||||||
|         "\"loopsubdiv\"" => { |         "loopsubdiv" => { | ||||||
|             let t = parse_dict!(iter => |             let t = parse_dict!(iter => | ||||||
|                 levels, u32, 3; |                 levels, u32, 3; | ||||||
|                 indices, Vec<usize>, Vec::new(); |                 indices, Vec<usize>, Vec::new(); | ||||||
|                 p, Vec<Pos3>, Vec::new(); |                 p, Vec<Pos3>, Vec::new(); | ||||||
|                 alpha, ShapeAlpha, ShapeAlpha::None |                 alpha, ShapeAlpha, ShapeAlpha::None | ||||||
|                 => |                 => | ||||||
|                 levels, "\"integer levels\"", iter.parse_parameter()?; |                 levels, "integer levels", iter.parse_parameter()?; | ||||||
|                 indices, "\"integer indices\"", iter.parse_list()?; |                 indices, "integer indices", iter.parse_list()?; | ||||||
|                 p, "\"point3 P\"", iter.parse_list_3(Pos3::new)?; |                 p, "point3 P", iter.parse_list_3(Pos3::new)?; | ||||||
|                 alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); |                 alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?); | ||||||
|                 alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) |                 alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?) | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             if t.indices.is_empty() { |             if t.indices.is_empty() { | ||||||
|  | @ -257,7 +259,7 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 t.alpha, |                 t.alpha, | ||||||
|             )) |             )) | ||||||
|         } |         } | ||||||
|         "\"disk\"" => { |         "disk" => { | ||||||
|             let t = parse_dict!(iter => |             let t = parse_dict!(iter => | ||||||
|                 height, Float, 0.0; |                 height, Float, 0.0; | ||||||
|                 radius, Float, 1.0; |                 radius, Float, 1.0; | ||||||
|  | @ -265,12 +267,12 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 phimax, Float, 360.0; |                 phimax, Float, 360.0; | ||||||
|                 alpha, ShapeAlpha, ShapeAlpha::None |                 alpha, ShapeAlpha, ShapeAlpha::None | ||||||
|                 => |                 => | ||||||
|                 height, "\"float height\"", iter.parse_parameter()?; |                 height, "float height", iter.parse_parameter()?; | ||||||
|                 radius, "\"float radius\"", iter.parse_parameter()?; |                 radius, "float radius", iter.parse_parameter()?; | ||||||
|                 innerradius, "\"float innerradius\"", iter.parse_parameter()?; |                 innerradius, "float innerradius", iter.parse_parameter()?; | ||||||
|                 phimax, "\"float phimax\"", iter.parse_parameter()?; |                 phimax, "float phimax", iter.parse_parameter()?; | ||||||
|                 alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); |                 alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?); | ||||||
|                 alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) |                 alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?) | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             Ok(Statement::Shape( |             Ok(Statement::Shape( | ||||||
|  | @ -283,18 +285,18 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 t.alpha, |                 t.alpha, | ||||||
|             )) |             )) | ||||||
|         } |         } | ||||||
|         "\"plymesh\"" => { |         "plymesh" => { | ||||||
|             let t = parse_dict!(iter => |             let t = parse_dict!(iter => | ||||||
|                 filename, String, String::new(); |                 filename, String, String::new(); | ||||||
|                 displacement, Option<String>, None; |                 displacement, Option<String>, None; | ||||||
|                 edgelength, Float, 1.0; |                 edgelength, Float, 1.0; | ||||||
|                 alpha, ShapeAlpha, ShapeAlpha::None |                 alpha, ShapeAlpha, ShapeAlpha::None | ||||||
|                 => |                 => | ||||||
|                 filename, "\"string filename\"", iter.parse_parameter()?; |                 filename, "string filename", iter.parse_parameter()?; | ||||||
|                 displacement, "\"string displacement\"", Some(iter.parse_parameter()?); |                 displacement, "string displacement", Some(iter.parse_parameter()?); | ||||||
|                 edgelength, "\"float edgelength\"", iter.parse_parameter()?; |                 edgelength, "float edgelength", iter.parse_parameter()?; | ||||||
|                 alpha, "\"float alpha\"", ShapeAlpha::Value(iter.parse_parameter()?); |                 alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?); | ||||||
|                 alpha, "\"texture alpha\"", ShapeAlpha::Texture(iter.parse_parameter()?) |                 alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?) | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             Ok(Statement::Shape( |             Ok(Statement::Shape( | ||||||
|  | @ -312,11 +314,11 @@ fn parse_shape(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
| 
 | 
 | ||||||
| fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> { | fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> { | ||||||
|     let camera_type = tokenizer |     let camera_type = tokenizer | ||||||
|         .next() |         .next_if_string_value() | ||||||
|         .ok_or(miette!("unable to get shape type"))??; |         .ok_or(miette!("unable to get shape type"))??; | ||||||
| 
 | 
 | ||||||
|     match camera_type.as_str() { |     match camera_type.as_str() { | ||||||
|         "\"orthographic\"" => { |         "orthographic" => { | ||||||
|             let t = parse_dict!(tokenizer => |             let t = parse_dict!(tokenizer => | ||||||
|                 shutteropen, Float, 0.0; |                 shutteropen, Float, 0.0; | ||||||
|                 shutterclose, Float, 1.0; |                 shutterclose, Float, 1.0; | ||||||
|  | @ -325,12 +327,12 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 lens_radius, Float, 0.0; |                 lens_radius, Float, 0.0; | ||||||
|                 focal_distance, Float, Float::powi(10.0, 30) |                 focal_distance, Float, Float::powi(10.0, 30) | ||||||
|                 => |                 => | ||||||
|                 shutteropen, "\"float shutteropen\"", tokenizer.parse_parameter()?; |                 shutteropen, "float shutteropen", tokenizer.parse_parameter()?; | ||||||
|                 shutterclose, "\"float shutterclose\"", tokenizer.parse_parameter()?; |                 shutterclose, "float shutterclose", tokenizer.parse_parameter()?; | ||||||
|                 frame_aspect_ratio, "\"float frameaspectratio\"", Some(tokenizer.parse_parameter()?); |                 frame_aspect_ratio, "float frameaspectratio", Some(tokenizer.parse_parameter()?); | ||||||
|                 screen_window, "\"float screenwindow\"", Some(tokenizer.parse_parameter()?); |                 screen_window, "float screenwindow", Some(tokenizer.parse_parameter()?); | ||||||
|                 lens_radius, "\"float lensradius\"", tokenizer.parse_parameter()?; |                 lens_radius, "float lensradius", tokenizer.parse_parameter()?; | ||||||
|                 focal_distance, "\"float focaldistance\"", tokenizer.parse_parameter()? |                 focal_distance, "float focaldistance", tokenizer.parse_parameter()? | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             Ok(Statement::Camera(PbrtCamera { |             Ok(Statement::Camera(PbrtCamera { | ||||||
|  | @ -344,7 +346,7 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 shutter_close: t.shutterclose, |                 shutter_close: t.shutterclose, | ||||||
|             })) |             })) | ||||||
|         } |         } | ||||||
|         "\"perspective\"" => { |         "perspective" => { | ||||||
|             let t = parse_dict!(tokenizer => |             let t = parse_dict!(tokenizer => | ||||||
|                 shutteropen, Float, 0.0; |                 shutteropen, Float, 0.0; | ||||||
|                 shutterclose, Float, 1.0; |                 shutterclose, Float, 1.0; | ||||||
|  | @ -354,13 +356,13 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> { | ||||||
|                 focal_distance, Float, Float::powi(10.0, 30); |                 focal_distance, Float, Float::powi(10.0, 30); | ||||||
|                 fov, Float, 90.0 |                 fov, Float, 90.0 | ||||||
|                 => |                 => | ||||||
|                 shutteropen, "\"float shutteropen\"", tokenizer.parse_parameter()?; |                 shutteropen, "float shutteropen", tokenizer.parse_parameter()?; | ||||||
|                 shutterclose, "\"float shutterclose\"", tokenizer.parse_parameter()?; |                 shutterclose, "float shutterclose", tokenizer.parse_parameter()?; | ||||||
|                 frame_aspect_ratio, "\"float frameaspectratio\"", Some(tokenizer.parse_parameter()?); |                 frame_aspect_ratio, "float frameaspectratio", Some(tokenizer.parse_parameter()?); | ||||||
|                 screen_window, "\"float screenwindow\"", Some(tokenizer.parse_parameter()?); |                 screen_window, "float screenwindow", Some(tokenizer.parse_parameter()?); | ||||||
|                 lens_radius, "\"float lensradius\"", tokenizer.parse_parameter()?; |                 lens_radius, "float lensradius", tokenizer.parse_parameter()?; | ||||||
|                 focal_distance, "\"float focaldistance\"", tokenizer.parse_parameter()?; |                 focal_distance, "float focaldistance", tokenizer.parse_parameter()?; | ||||||
|                 fov, "\"float fov\"", tokenizer.parse_parameter()? |                 fov, "float fov", tokenizer.parse_parameter()? | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             Ok(Statement::Camera(PbrtCamera { |             Ok(Statement::Camera(PbrtCamera { | ||||||
|  | @ -382,16 +384,15 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> { | ||||||
| impl Lexer { | impl Lexer { | ||||||
|     fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> { |     fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> { | ||||||
|         match self.input.next() { |         match self.input.next() { | ||||||
|             Some(Ok(s)) => match s.as_str() { |             Some(Ok(Token::Identifier(s))) => match s.as_str() { | ||||||
|                 "AttributeBegin" => Some(Ok(Statement::AttributeBegin)), |                 "AttributeBegin" => Some(Ok(Statement::AttributeBegin)), | ||||||
|                 "AttributeEnd" => Some(Ok(Statement::AttributeEnd)), |                 "AttributeEnd" => Some(Ok(Statement::AttributeEnd)), | ||||||
|                 "Include" => { |                 "Include" => { | ||||||
|                     let s = self |                     let s = self | ||||||
|                         .input |                         .input | ||||||
|                         .next() |                         .next_if_string_value() | ||||||
|                         .unwrap() |                         .unwrap() | ||||||
|                         .unwrap() |                         .unwrap() | ||||||
|                         .trim_matches('"') |  | ||||||
|                         .to_string(); |                         .to_string(); | ||||||
| 
 | 
 | ||||||
|                     Some(Ok(Statement::Include(s))) |                     Some(Ok(Statement::Include(s))) | ||||||
|  | @ -434,9 +435,8 @@ impl Lexer { | ||||||
|                     } else { |                     } else { | ||||||
|                         let mut v = Vec::new(); |                         let mut v = Vec::new(); | ||||||
| 
 | 
 | ||||||
|                         while let Some(p) = self |                         while let Some(p) = | ||||||
|                             .input |                             self.input.next_if(|s| !matches!(s, Token::Identifier(_))) | ||||||
|                             .next_if(|s| !s.starts_with(|c: char| c.is_ascii_alphabetic())) |  | ||||||
|                         { |                         { | ||||||
|                             match p { |                             match p { | ||||||
|                                 Ok(c) => v.push(c), |                                 Ok(c) => v.push(c), | ||||||
|  | @ -448,6 +448,10 @@ impl Lexer { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|  |             Some(Ok(s)) => Some(Err(miette!( | ||||||
|  |                 labels = vec![self.input.last_span_labeled(Some("here"))], | ||||||
|  |                 "expected identifier got {s:?}" | ||||||
|  |             ))), | ||||||
|             Some(Err(e)) => Some(Err(e)), |             Some(Err(e)) => Some(Err(e)), | ||||||
|             None => None, |             None => None, | ||||||
|         } |         } | ||||||
|  | @ -455,29 +459,14 @@ impl Lexer { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn parse_transform(input: &mut Tokenizer) -> Result<AffineTransform> { | fn parse_transform(input: &mut Tokenizer) -> Result<AffineTransform> { | ||||||
|     if !input |     input.next_expect_bracket_open()?; | ||||||
|         .next() |  | ||||||
|         .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "[")) |  | ||||||
|     { |  | ||||||
|         bail!("expected list.") |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     let mut v = [0.0; 16]; |     let mut v = [0.0; 16]; | ||||||
| 
 | 
 | ||||||
|     for i in &mut v { |     for i in &mut v { | ||||||
|         *i = input |         *i = input.parse_next()?; | ||||||
|             .next() |  | ||||||
|             .ok_or(miette!("value expected"))?? |  | ||||||
|             .parse::<Float>() |  | ||||||
|             .into_diagnostic()?; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if !input |     input.next_expect_bracket_close()?; | ||||||
|         .next() |  | ||||||
|         .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) |  | ||||||
|     { |  | ||||||
|         bail!("expected list end.") |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if v[3] != 0.0 || v[7] != 0.0 || v[11] != 0.0 || v[15] != 1.0 { |     if v[3] != 0.0 || v[7] != 0.0 || v[11] != 0.0 || v[15] != 1.0 { | ||||||
|         bail!("invalid transform entry") |         bail!("invalid transform entry") | ||||||
|  | @ -509,24 +498,11 @@ fn parse_scale(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn parse_rotate(iter: &mut Tokenizer) -> Result<Statement> { | fn parse_rotate(iter: &mut Tokenizer) -> Result<Statement> { | ||||||
|     let angle = iter |     let angle = iter.parse_parameter()?; | ||||||
|         .next() |  | ||||||
|         .ok_or(miette!("missing argument"))?? |  | ||||||
|         .parse() |  | ||||||
|         .into_diagnostic()?; |  | ||||||
|     let dir = Dir3::new( |     let dir = Dir3::new( | ||||||
|         iter.next() |         iter.parse_parameter()?, | ||||||
|             .ok_or(miette!("missing argument"))?? |         iter.parse_parameter()?, | ||||||
|             .parse() |         iter.parse_parameter()?, | ||||||
|             .into_diagnostic()?, |  | ||||||
|         iter.next() |  | ||||||
|             .ok_or(miette!("missing argument"))?? |  | ||||||
|             .parse() |  | ||||||
|             .into_diagnostic()?, |  | ||||||
|         iter.next() |  | ||||||
|             .ok_or(miette!("missing argument"))?? |  | ||||||
|             .parse() |  | ||||||
|             .into_diagnostic()?, |  | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     Ok(Statement::ConcatTransform(AffineTransform::rotation( |     Ok(Statement::ConcatTransform(AffineTransform::rotation( | ||||||
|  | @ -721,7 +697,7 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> { | ||||||
|                     return Err(miette!("The camera can only be set once.")); |                     return Err(miette!("The camera can only be set once.")); | ||||||
|                 } |                 } | ||||||
|                 camera = Some((c, context.get_ctm())); |                 camera = Some((c, context.get_ctm())); | ||||||
|                 named_transforms.insert(String::from("\"camera\""), context.get_ctm()); |                 named_transforms.insert(String::from("camera"), context.get_ctm()); | ||||||
|             } |             } | ||||||
|             Statement::CoordinateSystem(s) => { |             Statement::CoordinateSystem(s) => { | ||||||
|                 named_transforms.insert(s, context.get_ctm()); |                 named_transforms.insert(s, context.get_ctm()); | ||||||
|  |  | ||||||
|  | @ -13,9 +13,9 @@ pub fn parse_make_named_material( | ||||||
|     input: &mut Tokenizer, |     input: &mut Tokenizer, | ||||||
|     context: &PbrtContext, |     context: &PbrtContext, | ||||||
| ) -> Result<(String, Arc<dyn PbrtMaterial>)> { | ) -> Result<(String, Arc<dyn PbrtMaterial>)> { | ||||||
|     let name = input.parse_next()?; |     let name = input.next_string_value()?; | ||||||
| 
 | 
 | ||||||
|     if input.parse_next::<String>()?.as_str() != "\"string type\"" { |     if input.next_string_value()?.as_str() != "string type" { | ||||||
|         return Err(miette!( |         return Err(miette!( | ||||||
|             "first element of make named material dict has to be type" |             "first element of make named material dict has to be type" | ||||||
|         )); |         )); | ||||||
|  | @ -71,7 +71,7 @@ fn parse_2d_float_texture( | ||||||
|     input: &mut Tokenizer, |     input: &mut Tokenizer, | ||||||
|     context: &PbrtContext, |     context: &PbrtContext, | ||||||
| ) -> Result<Arc<dyn Pbrt2dFloatTexture>> { | ) -> Result<Arc<dyn Pbrt2dFloatTexture>> { | ||||||
|     let n = input.parse_parameter()?; |     let n = input.next_string_value()?; | ||||||
| 
 | 
 | ||||||
|     context |     context | ||||||
|         .get_texture(&n) |         .get_texture(&n) | ||||||
|  | @ -83,7 +83,7 @@ fn parse_2d_spectrum_texture( | ||||||
|     input: &mut Tokenizer, |     input: &mut Tokenizer, | ||||||
|     context: &PbrtContext, |     context: &PbrtContext, | ||||||
| ) -> Result<Arc<dyn Pbrt2dSpectrumTexture>> { | ) -> Result<Arc<dyn Pbrt2dSpectrumTexture>> { | ||||||
|     let n = input.parse_parameter()?; |     let n = input.next_string_value()?; | ||||||
| 
 | 
 | ||||||
|     context |     context | ||||||
|         .get_texture(&n) |         .get_texture(&n) | ||||||
|  | @ -95,51 +95,51 @@ pub fn parse_material( | ||||||
|     input: &mut Tokenizer, |     input: &mut Tokenizer, | ||||||
|     context: &PbrtContext, |     context: &PbrtContext, | ||||||
| ) -> Result<Arc<dyn PbrtMaterial>> { | ) -> Result<Arc<dyn PbrtMaterial>> { | ||||||
|     let material: String = input.parse_parameter()?; |     let material: String = input.next_string_value()?; | ||||||
| 
 | 
 | ||||||
|     match material.as_str() { |     match material.as_str() { | ||||||
|         "\"diffuse\"" => Ok(Arc::new(parse_dict2!(input, PbrtDiffuseMaterial; |         "diffuse" => Ok(Arc::new(parse_dict2!(input, PbrtDiffuseMaterial; | ||||||
|             reflectance, Either::A(Color::black()), [ |             reflectance, Either::A(Color::black()), [ | ||||||
|                 "\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?); |                 "rgb reflectance", Either::A(texture::parse_rgb(input)?); | ||||||
|                 "\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?); |                 "spectrum reflectance", Either::A(texture::parse_spectrum(input)?); | ||||||
|                 "\"texture reflectance\"", Either::B(parse_2d_spectrum_texture(input, context)?) |                 "texture reflectance", Either::B(parse_2d_spectrum_texture(input, context)?) | ||||||
|             ] |             ] | ||||||
|         ))), |         ))), | ||||||
|         "\"coateddiffuse\"" => Ok(Arc::new(parse_dict2!(input, PbrtCoatedDiffuseMaterial; |         "coateddiffuse" => Ok(Arc::new(parse_dict2!(input, PbrtCoatedDiffuseMaterial; | ||||||
|             albedo, Either::A(Color::black()), [ |             albedo, Either::A(Color::black()), [ | ||||||
|                 "\"rgb albedo\"", Either::A(texture::parse_rgb(input)?); |                 "rgb albedo", Either::A(texture::parse_rgb(input)?); | ||||||
|                 "\"spectrum albedo\"", Either::A(texture::parse_spectrum(input)?); |                 "spectrum albedo", Either::A(texture::parse_spectrum(input)?); | ||||||
|                 "\"texture albedo\"", Either::B(parse_2d_spectrum_texture(input, context)?) |                 "texture albedo", Either::B(parse_2d_spectrum_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             g, Either::A(0.0), [ |             g, Either::A(0.0), [ | ||||||
|                 "\"float g\"", Either::A(input.parse_parameter()?); |                 "float g", Either::A(input.parse_parameter()?); | ||||||
|                 "\"texture g\"", Either::B(parse_2d_float_texture(input, context)?) |                 "texture g", Either::B(parse_2d_float_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             maxdepth, 10, ["\"integer maxdepth\"", input.parse_parameter()?]; |             maxdepth, 10, ["integer maxdepth", input.parse_parameter()?]; | ||||||
|             nsamples, 1, ["\"integer nsamples\"", input.parse_parameter()?]; |             nsamples, 1, ["integer nsamples", input.parse_parameter()?]; | ||||||
|             thickness, 0.01, ["\"float thickness\"", input.parse_parameter()?]; |             thickness, 0.01, ["float thickness", input.parse_parameter()?]; | ||||||
|             roughness, Either::A(0.0), [ |             roughness, Either::A(0.0), [ | ||||||
|                 "\"float roughness\"", Either::A(input.parse_parameter()?); |                 "float roughness", Either::A(input.parse_parameter()?); | ||||||
|                 "\"texture roughness\"", Either::B(parse_2d_float_texture(input, context)?) |                 "texture roughness", Either::B(parse_2d_float_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             uroughness, Either::A(0.0), [ |             uroughness, Either::A(0.0), [ | ||||||
|                 "\"float uroughness\"", Either::A(input.parse_parameter()?); |                 "float uroughness", Either::A(input.parse_parameter()?); | ||||||
|                 "\"texture uroughness\"", Either::B(parse_2d_float_texture(input, context)?) |                 "texture uroughness", Either::B(parse_2d_float_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             vroughness, Either::A(0.0), [ |             vroughness, Either::A(0.0), [ | ||||||
|                 "\"float vroughness\"", Either::A(input.parse_parameter()?); |                 "float vroughness", Either::A(input.parse_parameter()?); | ||||||
|                 "\"texture vroughness\"", Either::B(parse_2d_float_texture(input, context)?) |                 "texture vroughness", Either::B(parse_2d_float_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             reflectance, Either::A(Color::black()), [ |             reflectance, Either::A(Color::black()), [ | ||||||
|                 "\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?); |                 "rgb reflectance", Either::A(texture::parse_rgb(input)?); | ||||||
|                 "\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?); |                 "spectrum reflectance", Either::A(texture::parse_spectrum(input)?); | ||||||
|                 "\"texture reflectance\"", Either::B(parse_2d_spectrum_texture(input, context)?) |                 "texture reflectance", Either::B(parse_2d_spectrum_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             eta, Either::A(Either::A(1.5)), [ |             eta, Either::A(Either::A(1.5)), [ | ||||||
|                 "\"float eta\"", Either::A(Either::A(input.parse_parameter()?)); |                 "float eta", Either::A(Either::A(input.parse_parameter()?)); | ||||||
|                 "\"rgb eta\"", Either::B(Either::A(parse_rgb(input)?)); |                 "rgb eta", Either::B(Either::A(parse_rgb(input)?)); | ||||||
|                 "\"spectrum eta\"", Either::B(Either::A(texture::parse_spectrum(input)?)); |                 "spectrum eta", Either::B(Either::A(texture::parse_spectrum(input)?)); | ||||||
|                 "\"texture eta\"", { |                 "texture eta", { | ||||||
|                     let n = input.parse_parameter()?; |                     let n = input.parse_parameter()?; | ||||||
|                     let t = context.get_texture(&n).ok_or_else(|| miette!("Unknown texture"))?; |                     let t = context.get_texture(&n).ok_or_else(|| miette!("Unknown texture"))?; | ||||||
|                     match Arc::clone(t).get_2d_spectrum_texture() { |                     match Arc::clone(t).get_2d_spectrum_texture() { | ||||||
|  | @ -149,12 +149,12 @@ pub fn parse_material( | ||||||
|                 } |                 } | ||||||
|             ] |             ] | ||||||
|         ))), |         ))), | ||||||
|         "\"dielectric\"" => Ok(Arc::new(parse_dict2!(input, PbrtDielectricMaterial; |         "dielectric" => Ok(Arc::new(parse_dict2!(input, PbrtDielectricMaterial; | ||||||
|             eta, Either::A(Either::A(1.5)), [ |             eta, Either::A(Either::A(1.5)), [ | ||||||
|                 "\"float eta\"", Either::A(Either::A(input.parse_parameter()?)); |                 "float eta", Either::A(Either::A(input.parse_parameter()?)); | ||||||
|                 "\"rgb eta\"", Either::B(Either::A(parse_rgb(input)?)); |                 "rgb eta", Either::B(Either::A(parse_rgb(input)?)); | ||||||
|                 "\"spectrum eta\"", Either::B(Either::A(texture::parse_spectrum(input)?)); |                 "spectrum eta", Either::B(Either::A(texture::parse_spectrum(input)?)); | ||||||
|                 "\"texture eta\"", { |                 "texture eta", { | ||||||
|                     let n = input.parse_parameter()?; |                     let n = input.parse_parameter()?; | ||||||
|                     let t = context.get_texture(&n).ok_or_else(|| miette!("Unknown texture"))?; |                     let t = context.get_texture(&n).ok_or_else(|| miette!("Unknown texture"))?; | ||||||
|                     match Arc::clone(t).get_2d_spectrum_texture() { |                     match Arc::clone(t).get_2d_spectrum_texture() { | ||||||
|  | @ -164,16 +164,16 @@ pub fn parse_material( | ||||||
|                 } |                 } | ||||||
|             ]; |             ]; | ||||||
|             roughness, Either::A(0.0), [ |             roughness, Either::A(0.0), [ | ||||||
|                 "\"float roughness\"", Either::A(input.parse_parameter()?); |                 "float roughness", Either::A(input.parse_parameter()?); | ||||||
|                 "\"texture roughness\"", Either::B(parse_2d_float_texture(input, context)?) |                 "texture roughness", Either::B(parse_2d_float_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             uroughness, Either::A(0.0), [ |             uroughness, Either::A(0.0), [ | ||||||
|                 "\"float uroughness\"", Either::A(input.parse_parameter()?); |                 "float uroughness", Either::A(input.parse_parameter()?); | ||||||
|                 "\"texture uroughness\"", Either::B(parse_2d_float_texture(input, context)?) |                 "texture uroughness", Either::B(parse_2d_float_texture(input, context)?) | ||||||
|             ]; |             ]; | ||||||
|             vroughness, Either::A(0.0), [ |             vroughness, Either::A(0.0), [ | ||||||
|                 "\"float vroughness\"", Either::A(input.parse_parameter()?); |                 "float vroughness", Either::A(input.parse_parameter()?); | ||||||
|                 "\"texture vroughness\"", Either::B(parse_2d_float_texture(input, context)?) |                 "texture vroughness", Either::B(parse_2d_float_texture(input, context)?) | ||||||
|             ] |             ] | ||||||
|         ))), |         ))), | ||||||
|         _ => Err(miette!("Unknown material {material}")), |         _ => Err(miette!("Unknown material {material}")), | ||||||
|  |  | ||||||
|  | @ -48,8 +48,8 @@ enum TextureMapping { | ||||||
| impl TextureMapping { | impl TextureMapping { | ||||||
|     fn new(x: String) -> Result<Self> { |     fn new(x: String) -> Result<Self> { | ||||||
|         match x.as_str() { |         match x.as_str() { | ||||||
|             "\"uv\"" => Ok(TextureMapping::UV), |             "uv" => Ok(TextureMapping::UV), | ||||||
|             "\"spherical\"" => Ok(TextureMapping::Spherical), |             "spherical" => Ok(TextureMapping::Spherical), | ||||||
|             _ => Err(miette!("Error")), |             _ => Err(miette!("Error")), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -69,10 +69,10 @@ fn parse_float_texture( | ||||||
|     input: &mut Tokenizer, |     input: &mut Tokenizer, | ||||||
|     context: &PbrtContext, |     context: &PbrtContext, | ||||||
| ) -> Result<Arc<dyn PbrtTexture>> { | ) -> Result<Arc<dyn PbrtTexture>> { | ||||||
|     let texture_class: String = input.parse_next()?; |     let texture_class = input.next_string_value()?; | ||||||
| 
 | 
 | ||||||
|     match texture_class.as_str() { |     match texture_class.as_str() { | ||||||
|         "\"checkerboard\"" => { |         "checkerboard" => { | ||||||
|             let t = parse_dict!(input => |             let t = parse_dict!(input => | ||||||
|                 mapping, TextureMapping, TextureMapping::UV; |                 mapping, TextureMapping, TextureMapping::UV; | ||||||
|                 uscale, Float, 1.0; |                 uscale, Float, 1.0; | ||||||
|  | @ -83,16 +83,16 @@ fn parse_float_texture( | ||||||
|                 tex1, Either<Float, String>, Either::A(1.0); |                 tex1, Either<Float, String>, Either::A(1.0); | ||||||
|                 tex2, Either<Float, String>, Either::A(0.0) |                 tex2, Either<Float, String>, Either::A(0.0) | ||||||
|                 => |                 => | ||||||
|                 mapping, "\"string mapping\"", TextureMapping::new(input.parse_parameter()?)?; |                 mapping, "string mapping", TextureMapping::new(input.next_string_value()?)?; | ||||||
|                 uscale, "\"float uscale\"", input.parse_parameter()?; |                 uscale, "float uscale", input.parse_parameter()?; | ||||||
|                 vscale, "\"float vscale\"", input.parse_parameter()?; |                 vscale, "float vscale", input.parse_parameter()?; | ||||||
|                 udelta, "\"float udelta\"", input.parse_parameter()?; |                 udelta, "float udelta", input.parse_parameter()?; | ||||||
|                 vdelta, "\"float vdelta\"", input.parse_parameter()?; |                 vdelta, "float vdelta", input.parse_parameter()?; | ||||||
|                 dimension, "\"integer dimension\"", TextureDimension::new(input.parse_parameter()?)?; |                 dimension, "integer dimension", TextureDimension::new(input.parse_parameter()?)?; | ||||||
|                 tex1, "\"float tex1\"", Either::A(input.parse_parameter()?); |                 tex1, "float tex1", Either::A(input.parse_parameter()?); | ||||||
|                 tex1, "\"texture tex1\"", Either::B(input.parse_parameter()?); |                 tex1, "texture tex1", Either::B(input.next_string_value()?); | ||||||
|                 tex2, "\"float tex2\"", Either::A(input.parse_parameter()?); |                 tex2, "float tex2", Either::A(input.parse_parameter()?); | ||||||
|                 tex2, "\"texture tex2\"", Either::B(input.parse_parameter()?) |                 tex2, "texture tex2", Either::B(input.next_string_value()?) | ||||||
| 
 | 
 | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|  | @ -130,7 +130,11 @@ fn parse_float_texture( | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         _ => Err(miette!("unknown error {texture_class}")), |         _ => Err(miette!( | ||||||
|  |             labels = vec![input.last_span_labeled(Some("here"))], | ||||||
|  |             "unknown error {texture_class}" | ||||||
|  |         ) | ||||||
|  |         .with_source_code(input.get_src())), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -138,9 +142,9 @@ fn parse_spectrum_texture( | ||||||
|     input: &mut Tokenizer, |     input: &mut Tokenizer, | ||||||
|     context: &PbrtContext, |     context: &PbrtContext, | ||||||
| ) -> Result<Arc<dyn PbrtTexture>> { | ) -> Result<Arc<dyn PbrtTexture>> { | ||||||
|     let texture_class: String = input.parse_next()?; |     let texture_class = input.next_string_value()?; | ||||||
|     match texture_class.as_str() { |     match texture_class.as_str() { | ||||||
|         "\"checkerboard\"" => { |         "checkerboard" => { | ||||||
|             let t = parse_dict!(input => |             let t = parse_dict!(input => | ||||||
|                 mapping, TextureMapping, TextureMapping::UV; |                 mapping, TextureMapping, TextureMapping::UV; | ||||||
|                 uscale, Float, 1.0; |                 uscale, Float, 1.0; | ||||||
|  | @ -151,18 +155,18 @@ fn parse_spectrum_texture( | ||||||
|                 tex1, Either<Color, String>, Either::A(Color::white()); |                 tex1, Either<Color, String>, Either::A(Color::white()); | ||||||
|                 tex2, Either<Color, String>, Either::A(Color::black()) |                 tex2, Either<Color, String>, Either::A(Color::black()) | ||||||
|                 => |                 => | ||||||
|                 mapping, "\"string mapping\"", TextureMapping::new(input.parse_parameter()?)?; |                 mapping, "string mapping", TextureMapping::new(input.next_string_value()?)?; | ||||||
|                 uscale, "\"float uscale\"", input.parse_parameter()?; |                 uscale, "float uscale", input.parse_parameter()?; | ||||||
|                 vscale, "\"float vscale\"", input.parse_parameter()?; |                 vscale, "float vscale", input.parse_parameter()?; | ||||||
|                 udelta, "\"float udelta\"", input.parse_parameter()?; |                 udelta, "float udelta", input.parse_parameter()?; | ||||||
|                 vdelta, "\"float vdelta\"", input.parse_parameter()?; |                 vdelta, "float vdelta", input.parse_parameter()?; | ||||||
|                 dimension, "\"integer dimension\"", TextureDimension::new(input.parse_parameter()?)?; |                 dimension, "integer dimension", TextureDimension::new(input.parse_parameter()?)?; | ||||||
|                 tex1, "\"rgb tex1\"", Either::A(parse_rgb(input)?); |                 tex1, "rgb tex1", Either::A(parse_rgb(input)?); | ||||||
|                 tex1, "\"spectrum tex1\"", Either::A(parse_spectrum(input)?); |                 tex1, "spectrum tex1", Either::A(parse_spectrum(input)?); | ||||||
|                 tex1, "\"texture tex1\"", Either::B(input.parse_parameter()?); |                 tex1, "texture tex1", Either::B(input.next_string_value()?); | ||||||
|                 tex2, "\"rgb tex2\"", Either::A(parse_rgb(input)?); |                 tex2, "rgb tex2", Either::A(parse_rgb(input)?); | ||||||
|                 tex2, "\"spectrum tex2\"", Either::A(parse_spectrum(input)?); |                 tex2, "spectrum tex2", Either::A(parse_spectrum(input)?); | ||||||
|                 tex2, "\"texture tex2\"", Either::B(input.parse_parameter()?) |                 tex2, "texture tex2", Either::B(input.next_string_value()?) | ||||||
| 
 | 
 | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|  | @ -201,7 +205,7 @@ fn parse_spectrum_texture( | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         "\"imagemap\"" => { |         "imagemap" => { | ||||||
|             let t = parse_dict!(input => |             let t = parse_dict!(input => | ||||||
|                 mapping, TextureMapping, TextureMapping::UV; |                 mapping, TextureMapping, TextureMapping::UV; | ||||||
|                 uscale, Float, 1.0; |                 uscale, Float, 1.0; | ||||||
|  | @ -213,22 +217,22 @@ fn parse_spectrum_texture( | ||||||
|                 encoding, ImageMapEncoding, ImageMapEncoding::SRGB; |                 encoding, ImageMapEncoding, ImageMapEncoding::SRGB; | ||||||
|                 scale, Float, 1.0 |                 scale, Float, 1.0 | ||||||
|                 => |                 => | ||||||
|                 mapping, "\"string mapping\"", TextureMapping::new(input.parse_parameter()?)?; |                 mapping, "string mapping", TextureMapping::new(input.next_string_value()?)?; | ||||||
|                 uscale, "\"float uscale\"", input.parse_parameter()?; |                 uscale, "float uscale", input.parse_parameter()?; | ||||||
|                 vscale, "\"float vscale\"", input.parse_parameter()?; |                 vscale, "float vscale", input.parse_parameter()?; | ||||||
|                 udelta, "\"float udelta\"", input.parse_parameter()?; |                 udelta, "float udelta", input.parse_parameter()?; | ||||||
|                 vdelta, "\"float vdelta\"", input.parse_parameter()?; |                 vdelta, "float vdelta", input.parse_parameter()?; | ||||||
|                 filename, "\"string filename\"", input.parse_parameter()?; |                 filename, "string filename", input.next_string_value()?; | ||||||
|                 wrap, "\"string wrap\"", ImageMapWrap::new(input.parse_parameter()?)?; |                 wrap, "string wrap", ImageMapWrap::new(input.next_string_value()?)?; | ||||||
|                 encoding, "\"string encoding\"", ImageMapEncoding::new(input.parse_parameter()?)?; |                 encoding, "string encoding", ImageMapEncoding::new(input.next_string_value()?)?; | ||||||
|                 scale, "\"float scale\"", input.parse_parameter()? |                 scale, "float scale", input.parse_parameter()? | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             let mapping = UVMapping::new(t.mapping, t.uscale, t.vscale, t.udelta, t.vdelta); |             let mapping = UVMapping::new(t.mapping, t.uscale, t.vscale, t.udelta, t.vdelta); | ||||||
| 
 | 
 | ||||||
|             let path = dbg!(input.get_base_path()).join(t.filename.trim_matches('\"')); |             let path = dbg!(input.get_base_path()).join(t.filename); | ||||||
| 
 | 
 | ||||||
|             Ok(Arc::new(SpectrumImageMapTexture::new( |             Ok(Arc::new(SpectrumImageMapTexture::new( | ||||||
|                 mapping, |                 mapping, | ||||||
|  | @ -239,16 +243,16 @@ fn parse_spectrum_texture( | ||||||
|                 dbg!(path), |                 dbg!(path), | ||||||
|             )?)) |             )?)) | ||||||
|         } |         } | ||||||
|         "\"scale\"" => { |         "scale" => { | ||||||
|             let t = parse_dict!(input => |             let t = parse_dict!(input => | ||||||
|                 tex, Either<Color, String>, Either::A(Color::white()); |                 tex, Either<Color, String>, Either::A(Color::white()); | ||||||
|                 scale, Either<Float, String>, Either::A(1.0) |                 scale, Either<Float, String>, Either::A(1.0) | ||||||
|                 => |                 => | ||||||
|                 tex, "\"rgb tex\"", Either::A(parse_rgb(input)?); |                 tex, "rgb tex", Either::A(parse_rgb(input)?); | ||||||
|                 tex, "\"spectrum tex\"", Either::A(parse_spectrum(input)?); |                 tex, "spectrum tex", Either::A(parse_spectrum(input)?); | ||||||
|                 tex, "\"texture tex\"", Either::B(input.parse_parameter()?); |                 tex, "texture tex", Either::B(input.next_string_value()?); | ||||||
|                 scale, "\"float scale\"", Either::A(input.parse_parameter()?); |                 scale, "float scale", Either::A(input.parse_parameter()?); | ||||||
|                 scale, "\"texture scale\"", Either::B(input.parse_parameter()?) |                 scale, "texture scale", Either::B(input.next_string_value()?) | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             Ok(Arc::new(SpectrumScaleTexture2d { |             Ok(Arc::new(SpectrumScaleTexture2d { | ||||||
|  | @ -284,12 +288,12 @@ pub fn parse_texture( | ||||||
|     input: &mut Tokenizer, |     input: &mut Tokenizer, | ||||||
|     context: &PbrtContext, |     context: &PbrtContext, | ||||||
| ) -> Result<(String, Arc<dyn PbrtTexture>)> { | ) -> Result<(String, Arc<dyn PbrtTexture>)> { | ||||||
|     let texture_name: String = input.parse_next()?; |     let texture_name: String = input.next_string_value()?; | ||||||
|     let texture_type: String = input.parse_next()?; |     let texture_type: String = input.next_string_value()?; | ||||||
| 
 | 
 | ||||||
|     match texture_type.as_str() { |     match texture_type.as_str() { | ||||||
|         "\"spectrum\"" => parse_spectrum_texture(input, context).map(|t| (texture_name, t)), |         "spectrum" => parse_spectrum_texture(input, context).map(|t| (texture_name, t)), | ||||||
|         "\"float\"" => parse_float_texture(input, context).map(|t| (texture_name, t)), |         "float" => parse_float_texture(input, context).map(|t| (texture_name, t)), | ||||||
|         _ => Err(miette!("Texture type has to be spectrum or float")), |         _ => Err(miette!("Texture type has to be spectrum or float")), | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -303,6 +307,18 @@ struct UVMapping { | ||||||
|     mapping: TextureMapping, |     mapping: TextureMapping, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl std::default::Default for UVMapping { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             uscale: 1.0, | ||||||
|  |             vscale: 1.0, | ||||||
|  |             udelta: 0.0, | ||||||
|  |             vdelta: 0.0, | ||||||
|  |             mapping: TextureMapping::UV, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl UVMapping { | impl UVMapping { | ||||||
|     fn new( |     fn new( | ||||||
|         mapping: TextureMapping, |         mapping: TextureMapping, | ||||||
|  |  | ||||||
|  | @ -14,9 +14,9 @@ pub(super) enum ImageMapWrap { | ||||||
| impl ImageMapWrap { | impl ImageMapWrap { | ||||||
|     pub(super) fn new(x: String) -> Result<Self> { |     pub(super) fn new(x: String) -> Result<Self> { | ||||||
|         match x.as_str() { |         match x.as_str() { | ||||||
|             "\"repeat\"" => Ok(Self::Repeat), |             "repeat" => Ok(Self::Repeat), | ||||||
|             "\"black\"" => Ok(Self::Black), |             "black" => Ok(Self::Black), | ||||||
|             "\"clamp\"" => Ok(Self::Clamp), |             "clamp" => Ok(Self::Clamp), | ||||||
|             _ => Err(miette!("error image map wrap")), |             _ => Err(miette!("error image map wrap")), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -33,15 +33,11 @@ pub(super) enum ImageMapEncoding { | ||||||
| impl ImageMapEncoding { | impl ImageMapEncoding { | ||||||
|     pub(super) fn new(x: String) -> Result<Self> { |     pub(super) fn new(x: String) -> Result<Self> { | ||||||
|         match x.as_str() { |         match x.as_str() { | ||||||
|             "\"sRGB\"" => Ok(Self::SRGB), |             "sRGB" => Ok(Self::SRGB), | ||||||
|             "\"linear\"" => Ok(Self::Linear), |             "linear" => Ok(Self::Linear), | ||||||
|             s if s.starts_with("\"gamma ") => Ok(Self::Gamma( |             s if s.starts_with("gamma ") => { | ||||||
|                 s.split_at(7) |                 Ok(Self::Gamma(s.split_at(7).1.parse().into_diagnostic()?)) | ||||||
|                     .1 |             } | ||||||
|                     .trim_matches('\"') |  | ||||||
|                     .parse() |  | ||||||
|                     .into_diagnostic()?, |  | ||||||
|             )), |  | ||||||
|             _ => Err(miette!("error image map encoding")), |             _ => Err(miette!("error image map encoding")), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| use crate::{BytesToChar, error::SourceFile}; | use crate::{BytesToChar, error::SourceFile}; | ||||||
| use miette::{Diagnostic, IntoDiagnostic, Report, Result, SourceSpan}; | use miette::{Diagnostic, IntoDiagnostic, LabeledSpan, Report, Result, SourceSpan, miette}; | ||||||
| use std::{ | use std::{ | ||||||
|     fs::File, |     fs::File, | ||||||
|     io::{BufReader, Bytes, Read}, |     io::{BufReader, Bytes, Read}, | ||||||
|  | @ -12,7 +12,7 @@ pub struct Tokenizer { | ||||||
|     inner: InnerTokenizer, |     inner: InnerTokenizer, | ||||||
|     path: PathBuf, |     path: PathBuf, | ||||||
|     base_path: PathBuf, |     base_path: PathBuf, | ||||||
|     peeked: Option<Option<Result<(String, SourceSpan)>>>, |     peeked: Option<Option<Result<(Token, SourceSpan)>>>, | ||||||
|     last_span: SourceSpan, |     last_span: SourceSpan, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -47,8 +47,17 @@ impl InnerTokenizer { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum Token { | ||||||
|  |     Identifier(String), | ||||||
|  |     BracketOpen, | ||||||
|  |     BracketClose, | ||||||
|  |     Value(String), | ||||||
|  |     StringValue(String), | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl InnerTokenizer { | impl InnerTokenizer { | ||||||
|     fn next(&mut self) -> Option<Result<(String, SourceSpan)>> { |     fn next(&mut self) -> Option<Result<(Token, SourceSpan)>> { | ||||||
|         while self.input_iterator.peek().is_some_and(|c| { |         while self.input_iterator.peek().is_some_and(|c| { | ||||||
|             c.as_ref() |             c.as_ref() | ||||||
|                 .is_ok_and(|&(_, c)| c.is_whitespace() || c == '#') |                 .is_ok_and(|&(_, c)| c.is_whitespace() || c == '#') | ||||||
|  | @ -72,10 +81,10 @@ impl InnerTokenizer { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         match self.input_iterator.next() { |         match self.input_iterator.next() { | ||||||
|             Some(Ok((i, '['))) => Some(Ok((String::from('['), SourceSpan::new(i.into(), 1)))), |             Some(Ok((i, '['))) => Some(Ok((Token::BracketOpen, SourceSpan::new(i.into(), 1)))), | ||||||
|             Some(Ok((i, ']'))) => Some(Ok((String::from(']'), SourceSpan::new(i.into(), 1)))), |             Some(Ok((i, ']'))) => Some(Ok((Token::BracketClose, SourceSpan::new(i.into(), 1)))), | ||||||
|             Some(Ok((i, '"'))) => { |             Some(Ok((i, '"'))) => { | ||||||
|                 let mut r = String::from('"'); |                 let mut r = String::new(); | ||||||
|                 while let Some(p) = self |                 while let Some(p) = self | ||||||
|                     .input_iterator |                     .input_iterator | ||||||
|                     .next_if(|c| c.as_ref().is_ok_and(|&(_, c)| c != '"')) |                     .next_if(|c| c.as_ref().is_ok_and(|&(_, c)| c != '"')) | ||||||
|  | @ -97,9 +106,11 @@ impl InnerTokenizer { | ||||||
|                         bad_bit: SourceSpan::new(i.into(), r.len()), |                         bad_bit: SourceSpan::new(i.into(), r.len()), | ||||||
|                     }))); |                     }))); | ||||||
|                 }; |                 }; | ||||||
|                 r.push('"'); |  | ||||||
|                 let len = r.len(); |                 let len = r.len(); | ||||||
|                 Some(Ok((r, SourceSpan::new(i.into(), len)))) |                 Some(Ok(( | ||||||
|  |                     Token::StringValue(r), | ||||||
|  |                     SourceSpan::new(i.into(), len + 2), | ||||||
|  |                 ))) | ||||||
|             } |             } | ||||||
|             Some(Ok((i, c))) => { |             Some(Ok((i, c))) => { | ||||||
|                 let mut r = String::new(); |                 let mut r = String::new(); | ||||||
|  | @ -114,7 +125,12 @@ impl InnerTokenizer { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 let len = r.len(); |                 let len = r.len(); | ||||||
|                 Some(Ok((r, SourceSpan::new(i.into(), len)))) |                 if r.starts_with(|c: char| c.is_ascii_alphabetic()) && (r != "true" || r != "false") | ||||||
|  |                 { | ||||||
|  |                     Some(Ok((Token::Identifier(r), SourceSpan::new(i.into(), len)))) | ||||||
|  |                 } else { | ||||||
|  |                     Some(Ok((Token::Value(r), SourceSpan::new(i.into(), len)))) | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             Some(Err(e)) => Some(Err(e)), |             Some(Err(e)) => Some(Err(e)), | ||||||
|             None => None, |             None => None, | ||||||
|  | @ -123,14 +139,14 @@ impl InnerTokenizer { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Tokenizer { | impl Tokenizer { | ||||||
|     pub fn next_inner(&mut self) -> Option<Result<(String, SourceSpan)>> { |     pub fn next_inner(&mut self) -> Option<Result<(Token, SourceSpan)>> { | ||||||
|         match self.peeked.take() { |         match self.peeked.take() { | ||||||
|             Some(v) => v, |             Some(v) => v, | ||||||
|             None => self.inner.next(), |             None => self.inner.next(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn next(&mut self) -> Option<Result<String>> { |     pub fn next(&mut self) -> Option<Result<Token>> { | ||||||
|         let v = self.next_inner(); |         let v = self.next_inner(); | ||||||
|         if let Some(Ok((_, s))) = v { |         if let Some(Ok((_, s))) = v { | ||||||
|             self.last_span = s; |             self.last_span = s; | ||||||
|  | @ -138,9 +154,66 @@ impl Tokenizer { | ||||||
|         v.map(|o| o.map(|i| i.0)) |         v.map(|o| o.map(|i| i.0)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn next_if(&mut self, func: impl FnOnce(&String) -> bool) -> Option<Result<String>> { |     pub fn next_if(&mut self, f: impl FnOnce(&Token) -> bool) -> Option<Result<Token>> { | ||||||
|         match self.next_inner() { |         match self.next_inner() { | ||||||
|             Some(Ok((matched, s))) if func(&matched) => { |             Some(Ok((matched, s))) if f(&matched) => { | ||||||
|  |                 self.last_span = s; | ||||||
|  |                 Some(Ok(matched)) | ||||||
|  |             } | ||||||
|  |             other => { | ||||||
|  |                 assert!(self.peeked.is_none()); | ||||||
|  |                 self.peeked = Some(other); | ||||||
|  |                 None | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn next_if_value(&mut self) -> Option<Result<String>> { | ||||||
|  |         match self.next_inner() { | ||||||
|  |             Some(Ok((Token::Value(matched), s))) => { | ||||||
|  |                 self.last_span = s; | ||||||
|  |                 Some(Ok(matched)) | ||||||
|  |             } | ||||||
|  |             other => { | ||||||
|  |                 assert!(self.peeked.is_none()); | ||||||
|  |                 self.peeked = Some(other); | ||||||
|  |                 None | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn next_string_value(&mut self) -> Result<String> { | ||||||
|  |         self.next_if_string_value().ok_or_else(|| { | ||||||
|  |             miette!( | ||||||
|  |                 labels = vec![self.last_span_labeled(Some("here"))], | ||||||
|  |                 "expected a string value" | ||||||
|  |             ) | ||||||
|  |             .with_source_code(self.get_src()) | ||||||
|  |         })? | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn next_if_string_value(&mut self) -> Option<Result<String>> { | ||||||
|  |         match self.next_inner() { | ||||||
|  |             Some(Ok((Token::BracketOpen, s1))) => match self.next_inner() { | ||||||
|  |                 Some(Ok((Token::StringValue(s), s2))) => { | ||||||
|  |                     if let Err(e) = self.next_expect_bracket_close() { | ||||||
|  |                         Some(Err(e)) | ||||||
|  |                     } else { | ||||||
|  |                         self.last_span = SourceSpan::new( | ||||||
|  |                             s1.offset().into(), | ||||||
|  |                             s2.offset() - s1.offset() + s2.len(), | ||||||
|  |                         ); | ||||||
|  |                         Some(Ok(s)) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 Some(Ok((t, s2))) => Some(Err(miette!( | ||||||
|  |                     labels = vec![LabeledSpan::new_with_span(Some("here".to_string()), s2)], | ||||||
|  |                     "expected string value got {t:?}" | ||||||
|  |                 ))), | ||||||
|  |                 Some(Err(e)) => Some(Err(e)), | ||||||
|  |                 None => None, | ||||||
|  |             }, | ||||||
|  |             Some(Ok((Token::StringValue(matched), s))) => { | ||||||
|                 self.last_span = s; |                 self.last_span = s; | ||||||
|                 Some(Ok(matched)) |                 Some(Ok(matched)) | ||||||
|             } |             } | ||||||
|  | @ -158,32 +231,79 @@ impl Tokenizer { | ||||||
|         <T as std::str::FromStr>::Err: |         <T as std::str::FromStr>::Err: | ||||||
|             std::error::Error + std::marker::Send + std::marker::Sync + 'static, |             std::error::Error + std::marker::Send + std::marker::Sync + 'static, | ||||||
|     { |     { | ||||||
|         let s = self.next().ok_or_else(|| MissingValueError { |         if let Token::Value(s) = self.next().ok_or_else(|| MissingValueError { | ||||||
|             src: SourceFile { |             src: SourceFile { | ||||||
|                 path: self.path.to_path_buf(), |                 path: self.path.to_path_buf(), | ||||||
|             }, |             }, | ||||||
|             bad_bit: self.last_span(), |             bad_bit: self.last_span(), | ||||||
|         })??; |         })?? { | ||||||
| 
 |             s.parse::<T>().into_diagnostic().map_err(|e| { | ||||||
|         s.parse::<T>().into_diagnostic().map_err(|e| { |                 ParsingError { | ||||||
|             ParsingError { |                     src: SourceFile { | ||||||
|                 src: SourceFile { |                         path: self.path.clone(), | ||||||
|                     path: self.path.clone(), |                     }, | ||||||
|                 }, |                     bad_bit: self.last_span, | ||||||
|                 bad_bit: self.last_span, |                     error: Some(e), | ||||||
|                 error: Some(e), |                 } | ||||||
|             } |                 .into() | ||||||
|             .into() |             }) | ||||||
|         }) |         } else { | ||||||
|  |             Err(miette!( | ||||||
|  |                 labels = vec![self.last_span_labeled(Some("here"))], | ||||||
|  |                 "expected a value" | ||||||
|  |             ) | ||||||
|  |             .with_source_code(self.get_src())) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn parse_next_if<T>(&mut self, func: impl FnOnce(&String) -> bool) -> Option<Result<T>> |     pub fn next_expect_bracket_open(&mut self) -> Result<()> { | ||||||
|  |         let p = self.next().ok_or_else(|| { | ||||||
|  |             miette!( | ||||||
|  |                 labels = vec![self.last_span_labeled(Some("here"))], | ||||||
|  |                 "expected opening brackets" | ||||||
|  |             ) | ||||||
|  |             .with_source_code(self.get_src()) | ||||||
|  |         })??; | ||||||
|  | 
 | ||||||
|  |         match &p { | ||||||
|  |             Token::BracketOpen => Ok(()), | ||||||
|  |             s => Err(miette!( | ||||||
|  |                 labels = vec![self.last_span_labeled(Some("here"))], | ||||||
|  |                 "expected opening brackets got {s:?}" | ||||||
|  |             ) | ||||||
|  |             .with_source_code(self.get_src())), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn next_expect_bracket_close(&mut self) -> Result<()> { | ||||||
|  |         let p = self.next().ok_or_else(|| { | ||||||
|  |             miette!( | ||||||
|  |                 labels = vec![LabeledSpan::new_with_span( | ||||||
|  |                     Some("here".to_string()), | ||||||
|  |                     self.last_span() | ||||||
|  |                 )], | ||||||
|  |                 "expected closing brackets" | ||||||
|  |             ) | ||||||
|  |             .with_source_code(self.get_src()) | ||||||
|  |         })??; | ||||||
|  | 
 | ||||||
|  |         match &p { | ||||||
|  |             Token::BracketClose => Ok(()), | ||||||
|  |             s => Err(miette!( | ||||||
|  |                 labels = vec![self.last_span_labeled(Some("here"))], | ||||||
|  |                 "expected closing brackets got {s:?}" | ||||||
|  |             ) | ||||||
|  |             .with_source_code(self.get_src())), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn parse_next_if_value<T>(&mut self) -> Option<Result<T>> | ||||||
|     where |     where | ||||||
|         T: std::str::FromStr, |         T: std::str::FromStr, | ||||||
|         <T as std::str::FromStr>::Err: |         <T as std::str::FromStr>::Err: | ||||||
|             std::error::Error + std::marker::Send + std::marker::Sync + 'static, |             std::error::Error + std::marker::Send + std::marker::Sync + 'static, | ||||||
|     { |     { | ||||||
|         let s = self.next_if(func)?; |         let s = self.next_if_value()?; | ||||||
| 
 | 
 | ||||||
|         Some(match s { |         Some(match s { | ||||||
|             Ok(s) => s.parse::<T>().into_diagnostic().map_err(|e| { |             Ok(s) => s.parse::<T>().into_diagnostic().map_err(|e| { | ||||||
|  | @ -204,6 +324,10 @@ impl Tokenizer { | ||||||
|         self.last_span |         self.last_span | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn last_span_labeled(&self, label: Option<impl ToString>) -> LabeledSpan { | ||||||
|  |         LabeledSpan::new_with_span(label.map(|s| s.to_string()), self.last_span()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn parse_parameter<T>(&mut self) -> Result<T> |     pub fn parse_parameter<T>(&mut self) -> Result<T> | ||||||
|     where |     where | ||||||
|         T: std::str::FromStr, |         T: std::str::FromStr, | ||||||
|  | @ -217,25 +341,23 @@ impl Tokenizer { | ||||||
|             bad_bit: self.last_span(), |             bad_bit: self.last_span(), | ||||||
|         })??; |         })??; | ||||||
| 
 | 
 | ||||||
|         match p.as_str() { |         match p { | ||||||
|             "[" => { |             Token::BracketOpen => { | ||||||
|                 let d = self.parse_next()?; |                 let d = self.parse_next()?; | ||||||
|                 if !self | 
 | ||||||
|                     .next() |                 self.next_expect_bracket_close()?; | ||||||
|                     .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) |  | ||||||
|                 { |  | ||||||
|                     return Err(ListEndError { |  | ||||||
|                         src: SourceFile { |  | ||||||
|                             path: self.path.to_path_buf(), |  | ||||||
|                         }, |  | ||||||
|                         bad_bit: self.last_span(), |  | ||||||
|                     } |  | ||||||
|                     .into()); |  | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 Ok(d) |                 Ok(d) | ||||||
|             } |             } | ||||||
|             s => Ok(s.parse::<T>().into_diagnostic()?), |             Token::Value(s) => Ok(s.parse::<T>().into_diagnostic()?), | ||||||
|  |             _ => Err(miette!( | ||||||
|  |                 labels = vec![LabeledSpan::new_with_span( | ||||||
|  |                     Some("here".to_string()), | ||||||
|  |                     self.last_span() | ||||||
|  |                 )], | ||||||
|  |                 "expected value or [ got {p:?}" | ||||||
|  |             ) | ||||||
|  |             .with_source_code(self.get_src())), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -246,35 +368,14 @@ impl Tokenizer { | ||||||
|             std::marker::Send + std::marker::Sync + std::error::Error + 'static, |             std::marker::Send + std::marker::Sync + std::error::Error + 'static, | ||||||
|     { |     { | ||||||
|         let mut data = Vec::new(); |         let mut data = Vec::new(); | ||||||
|         if !self |  | ||||||
|             .next() |  | ||||||
|             .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "[")) |  | ||||||
|         { |  | ||||||
|             return Err(ListBeginError { |  | ||||||
|                 src: SourceFile { |  | ||||||
|                     path: self.path.to_path_buf(), |  | ||||||
|                 }, |  | ||||||
|                 bad_bit: self.last_span(), |  | ||||||
|             } |  | ||||||
|             .into()); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         while let Some(p) = self.parse_next_if(|p| p != "]").transpose()? { |         self.next_expect_bracket_open()?; | ||||||
|  | 
 | ||||||
|  |         while let Some(p) = self.parse_next_if_value().transpose()? { | ||||||
|             data.push(p); |             data.push(p); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if !self |         self.next_expect_bracket_close()?; | ||||||
|             .next() |  | ||||||
|             .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) |  | ||||||
|         { |  | ||||||
|             return Err(ListEndError { |  | ||||||
|                 src: SourceFile { |  | ||||||
|                     path: self.path.to_path_buf(), |  | ||||||
|                 }, |  | ||||||
|                 bad_bit: self.last_span(), |  | ||||||
|             } |  | ||||||
|             .into()); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Ok(data) |         Ok(data) | ||||||
|     } |     } | ||||||
|  | @ -287,21 +388,11 @@ impl Tokenizer { | ||||||
|         F: Fn(T, T) -> P, |         F: Fn(T, T) -> P, | ||||||
|     { |     { | ||||||
|         let mut data = Vec::new(); |         let mut data = Vec::new(); | ||||||
|         if !self |  | ||||||
|             .next() |  | ||||||
|             .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "[")) |  | ||||||
|         { |  | ||||||
|             return Err(ListBeginError { |  | ||||||
|                 src: SourceFile { |  | ||||||
|                     path: self.path.to_path_buf(), |  | ||||||
|                 }, |  | ||||||
|                 bad_bit: self.last_span(), |  | ||||||
|             } |  | ||||||
|             .into()); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         while let Some(pa) = self.parse_next_if(|p| p != "]").transpose()? { |         self.next_expect_bracket_open()?; | ||||||
|             if let Some(pb) = self.parse_next_if(|p| p != "]").transpose()? { | 
 | ||||||
|  |         while let Some(pa) = self.parse_next_if_value().transpose()? { | ||||||
|  |             if let Some(pb) = self.parse_next_if_value().transpose()? { | ||||||
|                 data.push(f(pa, pb)); |                 data.push(f(pa, pb)); | ||||||
|             } else { |             } else { | ||||||
|                 return Err(UncompleteError { |                 return Err(UncompleteError { | ||||||
|  | @ -314,18 +405,7 @@ impl Tokenizer { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if !self |         self.next_expect_bracket_close()?; | ||||||
|             .next() |  | ||||||
|             .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) |  | ||||||
|         { |  | ||||||
|             return Err(ListEndError { |  | ||||||
|                 src: SourceFile { |  | ||||||
|                     path: self.path.to_path_buf(), |  | ||||||
|                 }, |  | ||||||
|                 bad_bit: self.last_span(), |  | ||||||
|             } |  | ||||||
|             .into()); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Ok(data) |         Ok(data) | ||||||
|     } |     } | ||||||
|  | @ -338,22 +418,12 @@ impl Tokenizer { | ||||||
|         F: Fn(T, T, T) -> P, |         F: Fn(T, T, T) -> P, | ||||||
|     { |     { | ||||||
|         let mut data = Vec::new(); |         let mut data = Vec::new(); | ||||||
|         if !self |  | ||||||
|             .next() |  | ||||||
|             .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "[")) |  | ||||||
|         { |  | ||||||
|             return Err(ListBeginError { |  | ||||||
|                 src: SourceFile { |  | ||||||
|                     path: self.path.to_path_buf(), |  | ||||||
|                 }, |  | ||||||
|                 bad_bit: self.last_span(), |  | ||||||
|             } |  | ||||||
|             .into()); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         while let Some(pa) = self.parse_next_if(|p| p != "]").transpose()? { |         self.next_expect_bracket_open()?; | ||||||
|             if let Some(pb) = self.parse_next_if(|p| p != "]").transpose()? { | 
 | ||||||
|                 if let Some(pc) = self.parse_next_if(|p| p != "]").transpose()? { |         while let Some(pa) = self.parse_next_if_value().transpose()? { | ||||||
|  |             if let Some(pb) = self.parse_next_if_value().transpose()? { | ||||||
|  |                 if let Some(pc) = self.parse_next_if_value().transpose()? { | ||||||
|                     data.push(f(pa, pb, pc)); |                     data.push(f(pa, pb, pc)); | ||||||
|                 } else { |                 } else { | ||||||
|                     return Err(UncompleteError { |                     return Err(UncompleteError { | ||||||
|  | @ -375,18 +445,7 @@ impl Tokenizer { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if !self |         self.next_expect_bracket_close()?; | ||||||
|             .next() |  | ||||||
|             .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) |  | ||||||
|         { |  | ||||||
|             return Err(ListEndError { |  | ||||||
|                 src: SourceFile { |  | ||||||
|                     path: self.path.to_path_buf(), |  | ||||||
|                 }, |  | ||||||
|                 bad_bit: self.last_span(), |  | ||||||
|             } |  | ||||||
|             .into()); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Ok(data) |         Ok(data) | ||||||
|     } |     } | ||||||
|  | @ -406,7 +465,7 @@ macro_rules! parse_dict { | ||||||
|                 let mut $name_decl = None; |                 let mut $name_decl = None; | ||||||
|             )+ |             )+ | ||||||
| 
 | 
 | ||||||
|             while let Some(p) = $tokenizer.next_if(|p| p.starts_with('"')).transpose()? { |             while let Some(p) = $tokenizer.next_if_string_value().transpose()? { | ||||||
|                 match p.as_str() { |                 match p.as_str() { | ||||||
|                     $( |                     $( | ||||||
|                         $expr => { |                         $expr => { | ||||||
|  | @ -449,7 +508,7 @@ macro_rules! parse_dict2 { | ||||||
|                 let mut $name = None; |                 let mut $name = None; | ||||||
|             )+ |             )+ | ||||||
| 
 | 
 | ||||||
|             while let Some(p) = $tokenizer.next_if(|p| p.starts_with('"')).transpose()? { |             while let Some(p) = $tokenizer.next_if_string_value().transpose()? { | ||||||
|                 match p.as_str() { |                 match p.as_str() { | ||||||
|                     $( |                     $( | ||||||
|                         $( |                         $( | ||||||
|  | @ -548,17 +607,6 @@ struct ListBeginError { | ||||||
|     bad_bit: SourceSpan, |     bad_bit: SourceSpan, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Error, Debug, Diagnostic)] |  | ||||||
| #[error("list error")] |  | ||||||
| #[diagnostic(help("expected list to end"))] |  | ||||||
| struct ListEndError { |  | ||||||
|     #[source_code] |  | ||||||
|     src: SourceFile, |  | ||||||
| 
 |  | ||||||
|     #[label("Here")] |  | ||||||
|     bad_bit: SourceSpan, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Error, Debug, Diagnostic)] | #[derive(Error, Debug, Diagnostic)] | ||||||
| #[error("value expected")] | #[error("value expected")] | ||||||
| #[diagnostic(help("expected a value"))] | #[diagnostic(help("expected a value"))] | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue