Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // TODO: Nice error messages.
- use nom::{self, multispace0, multispace1};
- use ast::AstNode;
- named!(pub expression<AstNode>, alt!(string | integer | variable_lookup));
- named!(pub statement<AstNode>, alt!(variable_creation_statement | variable_assignment_statement | attribute_setting_statement | function_call_statement));
- named!(
- function_call_statement<AstNode>,
- do_parse!(
- // XXX: Do we need to wrap the `expression` in parenthesis?
- func: alt!(variable_lookup | delimited!(char!('('), expression, char!(')'))) >> // func
- args: many0!(tuple!(multispace0, expression)) >> // args
- tuple!(nom::multispace0, char!(';')) >> // semicolon
- (AstNode::FunctionCall {
- func: Box::new(func),
- args: args.into_iter().map(|(_, e)| e).collect(),
- })
- )
- );
- named!(
- variable_creation_statement<AstNode>,
- do_parse!(
- tag!("var") >> multispace1 >> // var
- lhs_rhs: assignment >> // lhs, rhs
- multispace0 >> char!(';') >> // semicolon
- (AstNode::VariableCreation {
- ident: lhs_rhs.0,
- value: Box::new(lhs_rhs.1),
- })
- )
- );
- // TESTME
- named!(
- attribute_lookup<AstNode>,
- do_parse!(
- // FIXME: We should allow parenthesised function calls.
- expr: variable_lookup >> // expr
- multispace0 >> char!('.') >> // dot
- multispace0 >> attr: identifier >> // attr
- (AstNode::AttributeLookup {
- expr: Box::new(expr),
- attr,
- })
- )
- );
- // TESTME
- named!(
- attribute_setting_statement<AstNode>,
- do_parse!(
- attr: attribute_lookup >> // attr
- multispace0 >> char!('=') >> // equals
- multispace0 >> value: expression >> // value
- (AstNode::AttributeAssignment {
- attr: Box::new(attr),
- value: Box::new(value),
- })
- )
- );
- // TESTME
- named!(
- variable_assignment_statement<AstNode>,
- do_parse!(
- lhs_rhs: assignment >> // lhs, rhs
- multispace0 >> char!(';') >> // semicolon
- (AstNode::VariableCreation {
- ident: lhs_rhs.0,
- value: Box::new(lhs_rhs.1),
- })
- )
- );
- // TESTME
- named!(
- assignment<(String, AstNode)>,
- do_parse!(
- lhs: identifier >> multispace0 >> // lhs
- char!('=') >> multispace0 >> // equals
- rhs: expression >> // rhs
- (lhs, rhs)
- )
- );
- named!(
- identifier<String>,
- do_parse!(
- first: one_of!("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_") >> // first
- rest: many0!(one_of!("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890")) >> // rest
- (::std::iter::once(first).chain(rest.into_iter()).collect())
- )
- );
- // TESTME
- named!(
- variable_lookup<AstNode>,
- map!(identifier, |ident| AstNode::VariableLookup { ident })
- );
- // TESTME
- named!(pub program< Vec<AstNode> >, ws!(many0!(statement)));
- // TESTME
- named!(
- string<AstNode>,
- map!(
- delimited!(char!('"'), many0!(none_of!("\"")), char!('"')),
- |s| AstNode::String(s.into_iter().collect())
- )
- );
- // XXX: Can we use `parse_to!` here?
- // TESTME
- named!(
- integer<AstNode>,
- map_opt!(nom::digit1, |n: &[u8]| Some(AstNode::Integer(
- String::from_utf8(n.to_vec()).ok()?.parse().ok()?
- )))
- );
- #[cfg(test)]
- mod tests {
- use super::*;
- #[test]
- fn test_identifier() {
- assert_eq!(identifier(b"foo ").unwrap().1, "foo");
- assert_eq!(identifier(b"foo_bar ").unwrap().1, "foo_bar");
- }
- #[test]
- fn test_variable_creation_statement() {
- assert_eq!(
- variable_creation_statement(b"var a = 2;").unwrap().1,
- AstNode::VariableCreation {
- ident: "a".to_owned(),
- value: Box::new(AstNode::Integer(2))
- }
- );
- }
- #[test]
- fn test_function_call_statement() {
- assert_eq!(
- function_call_statement(b"print wintext 42;").unwrap().1,
- AstNode::FunctionCall {
- func: Box::new(AstNode::VariableLookup {
- ident: "print".to_string()
- }),
- args: vec![
- AstNode::VariableLookup {
- ident: "wintext".to_string(),
- },
- AstNode::Integer(42),
- ],
- }
- );
- }
- }
Add Comment
Please, Sign In to add comment