diff --git a/rust/compiler/src/parser.rs b/rust/compiler/src/parser.rs index 1c307de4..98d9a07a 100644 --- a/rust/compiler/src/parser.rs +++ b/rust/compiler/src/parser.rs @@ -25,6 +25,7 @@ use nom::{ pair, delimited, preceded, + terminated, }, error::{ VerboseError, @@ -53,6 +54,16 @@ fn ws<'a, F: 'a, O, E: ParseError<&'a str>>(inner: F) -> impl FnMut(&'a str) -> ) } +// Match a tag and surrounding whitespace +fn wtag<'a, E: ParseError<&'a str>>(t: &'static str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str, E> +{ + delimited( + multispace0, + tag(t), + multispace0 + ) +} + pub fn ident0(i: &str) -> Res<&str,&str> { recognize( @@ -94,9 +105,11 @@ pub fn module(i: &str) -> Res<&str,adlast::Module> { let (i,_) = ws(tag("module"))(i)?; let (i,name) = ws(module_name)(i)?; let (i,mut decls) = delimited( - ws(tag("{")), - many0(decl), - ws(tag("}")), + wtag("{"), + many0( + terminated(decl, wtag(";")) + ), + wtag("}"), )(i)?; let decls: HashMap> = decls.drain(..).map( |d| (d.name.clone(),d) ).collect(); @@ -124,19 +137,21 @@ pub fn decl(i: &str) -> Res<&str,adlast::Decl> { pub fn decl_type(i: &str) -> Res<&str,(&str,adlast::DeclType)> { alt(( map(struct_, |(name,s)| (name,adlast::DeclType::Struct(s))), - map(union, |(name,u)| (name,adlast::DeclType::Union(u))), + map(union, |(name,u)| (name,adlast::DeclType::Union(u))), + map(typedef, |(name,t)| (name,adlast::DeclType::Type(t))), + map(newtype, |(name,n)| (name,adlast::DeclType::Newtype(n))), ))(i) } pub fn struct_(i: &str) -> Res<&str,(&str,adlast::Struct)> { - let (i,_) = ws(tag("struct"))(i)?; + let (i,_) = wtag("struct")(i)?; let (i,name) = ws(ident0)(i)?; let (i,type_params) = type_params(i)?; let (i,fields) = delimited( - ws(tag("{")), + wtag("{"), many0(field), - ws(tag("}")), + wtag("}"), )(i)?; let struct_ = adlast::Struct{ fields: fields, @@ -147,14 +162,19 @@ pub fn struct_(i: &str) -> Res<&str,(&str,adlast::Struct)> { pub fn union(i: &str) -> Res<&str,(&str,adlast::Union)> { - let (i,_) = ws(tag("struct"))(i)?; + let (i,_) = wtag("struct")(i)?; let (i,name) = ws(ident0)(i)?; let (i,type_params) = type_params(i)?; let (i,fields) = delimited( - ws(tag("{")), - many0(field), - ws(tag("}")), + wtag("{"), + many0( + terminated( + field, + wtag(";"), + ) + ), + wtag("}"), )(i)?; let union = adlast::Union{ fields: fields, @@ -163,11 +183,49 @@ pub fn union(i: &str) -> Res<&str,(&str,adlast::Union)> { Ok((i,(name,union))) } +pub fn typedef(i: &str) -> Res<&str,(&str,adlast::TypeDef)> { + let (i,_) = wtag("type")(i)?; + let (i,name) = ws(ident0)(i)?; + let (i,type_params) = type_params(i)?; + let (i,type_expr) = + preceded( + wtag("="), + type_expr, + )(i)?; + let typedef = adlast::TypeDef{ + type_params, + type_expr, + }; + Ok((i,(name,typedef))) +} + +pub fn newtype(i: &str) -> Res<&str,(&str,adlast::NewType)> { + let (i,_) = ws(tag("newtype"))(i)?; + let (i,name) = ws(ident0)(i)?; + let (i,type_params) = type_params(i)?; + let (i,type_expr) = preceded( + wtag("="), + type_expr, + )(i)?; + let (i,default) = opt( + preceded( + wtag("="), + json, + ) + )(i)?; + + let newtype = adlast::NewType{ + type_params, + type_expr, + default: maybe_from_option(default), + }; + Ok((i,(name,newtype))) +} + pub fn field(i: &str) -> Res<&str,adlast::Field> { let (i,texpr) = ws(type_expr)(i)?; let (i,name) = ws(ident0)(i)?; - let (i,default) = opt( preceded( ws(tag("=")), json))(i)?; - let (i,_) = ws(tag(";"))(i)?; + let (i,default) = opt( preceded( wtag("="), json))(i)?; let field = adlast::Field{ name: name.to_string(), serialized_name: name.to_string(), @@ -181,9 +239,9 @@ pub fn field(i: &str) -> Res<&str,adlast::Field> { pub fn type_params(i: &str) -> Res<&str,Vec> { map( opt(delimited( - ws(tag("<")), + wtag("<"), separated_list0(ws(tag(",")), map( ident0, |i| i.to_string())), - ws(tag(">")) + wtag(">") )), |idents| idents.unwrap_or_else( || Vec::new() ) )(i) @@ -202,9 +260,9 @@ pub fn type_expr(i: &str) -> Res<&str,TypeExpr0> { pub fn type_expr_params(i: &str) -> Res<&str,Vec> { map( opt(delimited( - ws(tag("<")), + wtag("<"), separated_list0(ws(tag(",")), type_expr), - ws(tag(">")) + wtag(">") )), |texpr| texpr.unwrap_or_else( || Vec::new() ) )(i) @@ -303,6 +361,24 @@ mod tests { ); } + #[test] + fn parse_decl() { + + assert_eq!( + decl("struct A { F f1; A f2; }"), + Ok(("", adlast::Decl{ + name: "A".to_string(), + version: crate::adlrt::custom::sys::types::maybe::Maybe::nothing(), + annotations: crate::adlrt::custom::sys::types::map::Map::new(Vec::new()), + r#type: adlast::DeclType::Struct(adlast::Struct{ + type_params: Vec::new(), + fields: vec![ + ], + }), + })), + ) + } + #[test] fn parse_module() { let pm = module("module x {\n}");