Guest User

Untitled

a guest
May 24th, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.27 KB | None | 0 0
  1. // TODO: Nice error messages.
  2.  
  3. use nom::{self, multispace0, multispace1};
  4.  
  5. use ast::AstNode;
  6.  
  7. named!(pub expression<AstNode>, alt!(string | integer | variable_lookup));
  8.  
  9. named!(pub statement<AstNode>, alt!(variable_creation_statement | variable_assignment_statement | attribute_setting_statement | function_call_statement));
  10.  
  11. named!(
  12. function_call_statement<AstNode>,
  13. do_parse!(
  14. // XXX: Do we need to wrap the `expression` in parenthesis?
  15. func: alt!(variable_lookup | delimited!(char!('('), expression, char!(')'))) >> // func
  16. args: many0!(tuple!(multispace0, expression)) >> // args
  17. tuple!(nom::multispace0, char!(';')) >> // semicolon
  18. (AstNode::FunctionCall {
  19. func: Box::new(func),
  20. args: args.into_iter().map(|(_, e)| e).collect(),
  21. })
  22. )
  23. );
  24.  
  25. named!(
  26. variable_creation_statement<AstNode>,
  27. do_parse!(
  28. tag!("var") >> multispace1 >> // var
  29. lhs_rhs: assignment >> // lhs, rhs
  30. multispace0 >> char!(';') >> // semicolon
  31. (AstNode::VariableCreation {
  32. ident: lhs_rhs.0,
  33. value: Box::new(lhs_rhs.1),
  34. })
  35. )
  36. );
  37.  
  38. // TESTME
  39. named!(
  40. attribute_lookup<AstNode>,
  41. do_parse!(
  42. // FIXME: We should allow parenthesised function calls.
  43. expr: variable_lookup >> // expr
  44. multispace0 >> char!('.') >> // dot
  45. multispace0 >> attr: identifier >> // attr
  46. (AstNode::AttributeLookup {
  47. expr: Box::new(expr),
  48. attr,
  49. })
  50. )
  51. );
  52.  
  53. // TESTME
  54. named!(
  55. attribute_setting_statement<AstNode>,
  56. do_parse!(
  57. attr: attribute_lookup >> // attr
  58. multispace0 >> char!('=') >> // equals
  59. multispace0 >> value: expression >> // value
  60. (AstNode::AttributeAssignment {
  61. attr: Box::new(attr),
  62. value: Box::new(value),
  63. })
  64. )
  65. );
  66.  
  67. // TESTME
  68. named!(
  69. variable_assignment_statement<AstNode>,
  70. do_parse!(
  71. lhs_rhs: assignment >> // lhs, rhs
  72. multispace0 >> char!(';') >> // semicolon
  73. (AstNode::VariableCreation {
  74. ident: lhs_rhs.0,
  75. value: Box::new(lhs_rhs.1),
  76. })
  77. )
  78. );
  79.  
  80. // TESTME
  81. named!(
  82. assignment<(String, AstNode)>,
  83. do_parse!(
  84. lhs: identifier >> multispace0 >> // lhs
  85. char!('=') >> multispace0 >> // equals
  86. rhs: expression >> // rhs
  87. (lhs, rhs)
  88. )
  89. );
  90.  
  91. named!(
  92. identifier<String>,
  93. do_parse!(
  94. first: one_of!("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_") >> // first
  95. rest: many0!(one_of!("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890")) >> // rest
  96. (::std::iter::once(first).chain(rest.into_iter()).collect())
  97. )
  98. );
  99.  
  100. // TESTME
  101. named!(
  102. variable_lookup<AstNode>,
  103. map!(identifier, |ident| AstNode::VariableLookup { ident })
  104. );
  105.  
  106. // TESTME
  107. named!(pub program< Vec<AstNode> >, ws!(many0!(statement)));
  108.  
  109. // TESTME
  110. named!(
  111. string<AstNode>,
  112. map!(
  113. delimited!(char!('"'), many0!(none_of!("\"")), char!('"')),
  114. |s| AstNode::String(s.into_iter().collect())
  115. )
  116. );
  117.  
  118. // XXX: Can we use `parse_to!` here?
  119. // TESTME
  120. named!(
  121. integer<AstNode>,
  122. map_opt!(nom::digit1, |n: &[u8]| Some(AstNode::Integer(
  123. String::from_utf8(n.to_vec()).ok()?.parse().ok()?
  124. )))
  125. );
  126.  
  127. #[cfg(test)]
  128. mod tests {
  129. use super::*;
  130.  
  131. #[test]
  132. fn test_identifier() {
  133. assert_eq!(identifier(b"foo ").unwrap().1, "foo");
  134. assert_eq!(identifier(b"foo_bar ").unwrap().1, "foo_bar");
  135. }
  136.  
  137. #[test]
  138. fn test_variable_creation_statement() {
  139. assert_eq!(
  140. variable_creation_statement(b"var a = 2;").unwrap().1,
  141. AstNode::VariableCreation {
  142. ident: "a".to_owned(),
  143. value: Box::new(AstNode::Integer(2))
  144. }
  145. );
  146. }
  147.  
  148. #[test]
  149. fn test_function_call_statement() {
  150. assert_eq!(
  151. function_call_statement(b"print wintext 42;").unwrap().1,
  152. AstNode::FunctionCall {
  153. func: Box::new(AstNode::VariableLookup {
  154. ident: "print".to_string()
  155. }),
  156. args: vec![
  157. AstNode::VariableLookup {
  158. ident: "wintext".to_string(),
  159. },
  160. AstNode::Integer(42),
  161. ],
  162. }
  163. );
  164. }
  165. }
Add Comment
Please, Sign In to add comment