diff --git a/src/main.rs b/src/main.rs index 155dfb9..d875eef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ fn main() { - let src = "log(1, 2)"; + let src = r#"function add(left, right) { return 5; }"#; let ast = pivot::parse(src); println!("{}", ast); } diff --git a/src/parse/combinators.rs b/src/parse/combinators.rs index 76044e4..de28ddb 100644 --- a/src/parse/combinators.rs +++ b/src/parse/combinators.rs @@ -124,7 +124,7 @@ impl Parser { } } Ignore => { - self.subparsers[0].parse(s) + Ok(("".into(), self.subparsers[0].parse(s)?.1)) } Or => { if let Ok(lresult) = self.subparsers[0].parse(s.clone()) { diff --git a/src/parse/mod.rs b/src/parse/mod.rs index a779167..76c02c8 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -6,7 +6,178 @@ use ron::{from_str, to_string}; pub fn parse>(src: T) -> AstNode { let src: String = src.into(); - from_str::(&parse_expression(src).unwrap().0).unwrap() + let parse_program = Parser::custom(parse_statement) + .repeat_range(0..usize::MAX) + .map(|matched| { + let data = from_str::>(&matched)?; + let mut statements = vec![]; + for d in data { + statements.push(from_str::(&d)?); + } + Ok(to_string(&AstNode::program(statements))?) + }); + from_str::(&parse_program.parse(src).unwrap().0).unwrap() +} +fn parse_statement(src: String) -> Result<(String, String), String> { + let whitespace = Parser::regex(r"[ \n\r\t]+"); + let comments = Parser::regex(r"[/][/].*").or(Parser::regex(r"[/][*].*[*][/]")); + let ignored = whitespace.or(comments).repeat_range(0..usize::MAX); + // Token parser constructor. + let i = ignored.clone(); + let token = move |pattern: &str| i.clone().ignore().and(Parser::regex(pattern)); + // Token helper parsers. + let FUNCTION = Parser::regex(r"function\b").or(ignored.clone()); + let RETURN = token(r"return\b"); + let SEMICOLON = token(r"[;]"); + let IF = token(r"if\b"); + let ELSE = token(r"else\b"); + let LEFT_PAREN = token(r"[(]"); + let RIGHT_PAREN = token(r"[)]"); + let LEFT_BRACE = token(r"[{]"); + let RIGHT_BRACE = token(r"[}]"); + let WHILE = token(r"while\b"); + let VAR = token(r"var\b"); + let IDENTIFIER = token(r"[a-zA-Z_][a-zA-Z0-9_]*") + .map(|matched| Ok(to_string(&AstNode::identifier(matched))?)); + let ASSIGN = + token(r"=").map(|matched| Ok(to_string(&AstNode::assign("".into(), AstNode::null()))?)); + let COMMA = token(r"[,]"); + let expression = Parser::custom(parse_expression); + // Statement parser. + let statement = Parser::custom(parse_statement); + // Return statement parser. + let return_statement = RETURN.clone().ignore() + .and(expression.clone()) + .and(SEMICOLON.clone().ignore()) + .map(|matched| { + let data = from_str::(&matched)?; + Ok(to_string(&AstNode::function_return(data))?) + }); + // return_statement.parse(src.clone()) + // Expression statement parser. + let expression_statement = expression.clone() + .and(SEMICOLON.clone().ignore()); + // If statement parser. + let if_statement = IF.clone().ignore() + .and( + LEFT_PAREN.clone().ignore() + .and(expression.clone()) + .and(RIGHT_PAREN.clone().ignore()) + ) + .and(statement.clone()) + .and( + ELSE.clone().ignore() + .and(statement.clone()) + .optional() + ) + .map(|matched| { + let data = from_str::>(&matched)?; + let alternative = from_str::>(&data[1])?; + let alternative = match alternative.get(0) { + Some(s) => from_str::(&s)?, + None => AstNode::null(), + }; + let others = from_str::>(&data[0])?; + let conditional = from_str::(&others[0])?; + let consequence = from_str::(&others[1])?; + Ok(to_string(&AstNode::if_statement(conditional, consequence, alternative))?) + }); + // if_statement.parse(src.clone()) + let while_statement = WHILE.clone().ignore() + .and( + LEFT_PAREN.clone().ignore() + .and(expression.clone()) + .and(RIGHT_PAREN.clone().ignore()) + ) + .and(statement.clone()) + .map(|matched| { + let data = from_str::>(&matched)?; + let conditional = from_str::(&data[0])?; + let body = from_str::(&data[1])?; + Ok(to_string(&AstNode::while_loop(conditional, body))?) + }); + // while_statement.parse(src.clone()) + let var_statement = VAR.clone().ignore() + .and(IDENTIFIER.clone()) + .and(ASSIGN.clone().ignore()) + .and(expression.clone()) + .and(SEMICOLON.clone().ignore()) + .map(|matched| { + let data = from_str::>(&matched)?; + let name = from_str::(&data[0])?.value; + let value = from_str::(&data[1])?; + Ok(to_string(&AstNode::variable_definition(name, value))?) + }); + // var_statement.parse(src.clone()) + let assignment_statement = IDENTIFIER.clone() + .and(ASSIGN.clone().ignore()) + .and(expression.clone()) + .and(SEMICOLON.clone().ignore()) + .map(|matched| { + let data = from_str::>(&matched)?; + let name = from_str::(&data[0])?.value; + let value = from_str::(&data[1])?; + Ok(to_string(&AstNode::assign(name, value))?) + }); + // asssignment_statement.parse(src.clone()) + let block_statement = LEFT_BRACE.clone().ignore() + .and(statement.clone().repeat_range(0..usize::MAX)) + .and(RIGHT_BRACE.clone().ignore()) + .map(|matched| { + let data = from_str::>(&matched)?; + let mut statements = vec![]; + for d in data { + statements.push(from_str::(&d)?); + } + Ok(to_string(&AstNode::block(statements))?) + }); + // block_statement.parse(src.clone()) + let args = IDENTIFIER.clone() + .and( + COMMA.clone().ignore() + .and(IDENTIFIER.clone()) + .repeat_range(0..usize::MAX), + ) + .map(|matched| { + let mut args = vec![]; + let data = from_str::>(&matched)?; + args.push(data[0].clone()); + let others = from_str::>(&data[1])?; + for o in others { + args.push(o.clone()); + } + Ok(to_string(&args)?) + }); + // args.parse(src.clone()) + let function_statement = FUNCTION.clone().ignore() + .and(IDENTIFIER.clone()) + .and( + LEFT_PAREN.clone().ignore() + .and(args.clone()) + .and(RIGHT_PAREN.clone().ignore()) + ) + .and(block_statement.clone()) + .map(|matched| { + let data = from_str::>(&matched)?; + let body = from_str::(&data[1])?; + let data = from_str::>(&data[0])?; + let name = from_str::(&data[0])?.value; + let params = from_str::>(&data[1])?; + let mut parameters = vec![]; + for p in params { + parameters.push(from_str::(&p)?); + } + Ok(to_string(&AstNode::function_definition(name, parameters, body))?) + }); + return_statement.clone() + .or(if_statement.clone()) + .or(while_statement.clone()) + .or(var_statement.clone()) + .or(assignment_statement.clone()) + .or(block_statement.clone()) + .or(function_statement.clone()) + .or(expression_statement.clone()) + .parse(src) } fn parse_expression(src: String) -> Result<(String, String), String> { let whitespace = Parser::regex(r"[ \n\r\t]+"); @@ -91,7 +262,7 @@ fn parse_expression(src: String) -> Result<(String, String), String> { }); let call = IDENTIFIER.clone() .and(LEFT_PAREN.clone().ignore()) - .and(args.clone()) + .and(args.clone().optional()) .and(RIGHT_PAREN.clone().ignore()) .map(|matched| { let data = from_str::>(&matched)?;