From fee50aa28e6303fe91bd3f34bc6fadfc906c79f2 Mon Sep 17 00:00:00 2001 From: Per <Per Lindgren> Date: Fri, 20 Sep 2019 15:06:52 +0200 Subject: [PATCH] work in progress --- examples/tmp.rs | 28 +++--- src/ast.rs | 74 ++++++++++++++- src/parse.rs | 240 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 315 insertions(+), 27 deletions(-) diff --git a/examples/tmp.rs b/examples/tmp.rs index c84931c..bde570e 100644 --- a/examples/tmp.rs +++ b/examples/tmp.rs @@ -1,17 +1,17 @@ -extern crate nom; - - -use crust::parse::test; +use crust::{ + ast::Span, + parse::{parse_assign, test}, +}; fn main() { - test("- -1 + + 1", - -1 + 1); // rust does not allow + as a unary op (I do ;) - test("(-1-1)+(-1+3)", (-1 - 1) + (-1) + 3); - // just to check that right associative works (you don't need to implement pow) - test("2+3**2**3*5+1", 2 + 3i32.pow(2u32.pow(3)) * 5 + 1); - test("(12*2)/3-4", (12 * 2) / 3 - 4); - test("1*2+3", 1 * 2 + 3); - // just to check that we get a parse error - test("1*2+3+3*21-a12+2", 1 * 2 + 3 + 3 * 21 - 12 + 2); + // test("- -1 + + 1", - -1 + 1); // rust does not allow + as a unary op (I do ;) + // test("(-1-1)+(-1+3)", (-1 - 1) + (-1) + 3); + // // just to check that right associative works (you don't need to implement pow) + // test("2+3**2**3*5+1", 2 + 3i32.pow(2u32.pow(3)) * 5 + 1); + // test("(12*2)/3-4", (12 * 2) / 3 - 4); + // test("1*2+3", 1 * 2 + 3); + // // just to check that we get a parse error + // test("1*2+3+3*21-a12+2", 1 * 2 + 3 + 3 * 21 - 12 + 2); + test("1 + a(1, 2)", 1 + 2); + println!("{:?}", parse_assign(Span::new("3 = 4"))); } - - diff --git a/src/ast.rs b/src/ast.rs index bc4464e..f296112 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -23,11 +23,81 @@ type SpanOp<'a> = (Span<'a>, Op); #[derive(Debug, Clone, PartialEq)] pub enum Expr<'a> { Num(i32), + Bool(bool), Par(Box<SpanExpr<'a>>), - // Identifier - // Function application + Id(String), + Fn(String, Vec<SpanExpr<'a>>), BinOp(Op, Box<SpanExpr<'a>>, Box<SpanExpr<'a>>), UnaryOp(Op, Box<SpanExpr<'a>>), } pub type SpanExpr<'a> = (Span<'a>, Expr<'a>); + +#[derive(Debug, PartialEq, Clone)] +pub enum Cmd<'a> { + // let <mut> id : <& <mut>>Type = expr + Let(SpanMut<'a>, String, SpanType<'a>, SpanExpr<'a>), + // id = expr + Assign(SpanExpr<'a>, SpanExpr<'a>), + // /// if predicate do-this, and optionally do-that) + // If(Expr, Block, Option<Block>), + // /// while predicate do-this + // While(Expr, Block), + // Return(Expr), +} + +pub type SpanCmd<'a> = (Span<'a>, Cmd<'a>); + +#[derive(Debug, PartialEq, Clone)] +pub enum Mutability { + Imm, + Mut, +} + +pub type SpanMut<'a> = (Span<'a>, Mutability); + +// #[derive(Debug, PartialEq, Clone)] +// pub enum Cmd { +// /// let <mut> id : <& <mut>>Type = expr +// Let(Mutability, String, Type, Expr), +// /// id = expr +// Assign(Expr, Expr), +// /// if predicate do-this, and optionally do-that) +// If(Expr, Block, Option<Block>), +// /// while predicate do-this +// While(Expr, Block), +// Return(Expr), +// } + +pub type SpanBlock<'a> = (Span<'a>, Vec<SpanCmd<'a>>); + +#[derive(Debug, PartialEq, Clone)] +pub enum Type<'a> { + I32, + Bool, + Unit, + Mut(Box<SpanType<'a>>), + Ref(Box<SpanType<'a>>), + // no structs +} + +pub type SpanType<'a> = (Span<'a>, Type<'a>); + +// #[derive(Debug, PartialEq, Clone)] +// pub enum TypeDecl { +// Struct(String, Vec<(String, Type)>), +// } + +// #[derive(Debug, PartialEq, Clone)] +// pub struct Function { +// pub sig: (String, Vec<(String, Type)>, Type), +// pub body: Block, +// } + +// #[derive(Debug, PartialEq, Clone)] +// pub enum Item { +// TypeDecl(TypeDecl), +// Function(Function), +// } + +// pub type Prog = Vec<Item>; diff --git a/src/parse.rs b/src/parse.rs index 77e8edc..95e2105 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -6,16 +6,15 @@ use std::slice::Iter; use nom::{ branch::alt, bytes::complete::tag, - character::complete::char, - character::complete::{digit1, multispace0}, + character::complete::{alpha1, char, digit1, multispace0}, combinator::{cut, map}, error::ParseError, - multi::many1, - sequence::{delimited, preceded}, + multi::{many1, separated_list}, + sequence::{delimited, preceded, tuple}, IResult, }; -use crate::ast::{Expr, Op, Span, SpanExpr}; +use crate::ast::{Cmd, Expr, Op, Span, SpanCmd, SpanExpr}; pub fn parse_i32(i: Span) -> IResult<Span, (Span, i32)> { map(digit1, |digit_str: Span| { @@ -41,6 +40,9 @@ fn parse_op(i: Span) -> IResult<Span, (Span, Op)> { #[derive(Debug, Clone, PartialEq)] pub enum Token<'a> { Num(i32), + Bool(bool), + Id(String), + Fn(String, Vec<(Span<'a>, Vec<SpanToken<'a>>)>), Par(Vec<SpanToken<'a>>), Op(Op), } @@ -50,6 +52,12 @@ type SpanToken<'a> = (Span<'a>, Token<'a>); fn parse_terminal(i: Span) -> IResult<Span, SpanToken> { alt(( map(parse_i32, |(s, v)| (s, Token::Num(v))), + map(tag("true"), |s| (s, Token::Bool(true))), + map(tag("false"), |s| (s, Token::Bool(false))), + map(tuple((alpha1, parse_par(separated_list(char(','), parse_tokens)))), |(s, t)| { + (s, Token::Fn(s.to_string(), t)) + }), + map(alpha1, |s: Span| (s, Token::Id(s.to_string()))), map(parse_par(parse_tokens), |(s, tokens)| { (s, Token::Par(tokens)) }), @@ -71,8 +79,12 @@ fn parse_tokens(i: Span) -> IResult<Span, (Span, Vec<SpanToken>)> { fn compute_atom<'a>(t: &mut Peekable<Iter<SpanToken<'a>>>) -> SpanExpr<'a> { match t.next() { Some((s, Token::Num(i))) => (*s, Expr::Num(*i)), + Some((s, Token::Bool(b))) => (*s, Expr::Bool(*b)), + Some((s, Token::Id(id))) => (*s, Expr::Id(id.to_string())), Some((_, Token::Par(v))) => climb(&mut v.iter().peekable(), 0), - Some((s, Token::Op(op))) => (*s, Expr::UnaryOp(*op, Box::new(climb(t, 4)))), // assume highest precedence + Some((s, Token::Op(op))) => { + (*s, Expr::UnaryOp(*op, Box::new(climb(t, 4)))) + } // assume highest precedence _ => panic!("error in compute atom"), } } @@ -107,12 +119,15 @@ fn climb<'a>( result } +pub fn parse_expr(i: Span) -> IResult<Span, SpanExpr> { + map(parse_tokens, |(_, tokens)| { + climb(&mut tokens.iter().peekable(), 0) + })(i) +} + pub fn test(s: &str, v: i32) { - match parse_tokens(Span::new(s)) { - Ok((Span { fragment: "", .. }, (_, t))) => { - let mut t = t.iter().peekable(); - println!("{:?}", &t); - let e = climb(&mut t, 0); + match parse_expr(Span::new(s)) { + Ok((Span { fragment: "", .. }, e)) => { println!("{:?}", &e); println!("eval {} {}", math_eval(&e), v); assert_eq!(math_eval(&e), v); @@ -138,6 +153,209 @@ where delimited(char('('), preceded(multispace0, inner), cut(char(')'))) } +// fn parse_if<'a>(i: Span) -> IResult<Span, SpanCmd> { +// map( +// preceded( +// // here to avoid ambiguity with other names starting with `if`, if we added +// // variables to our language, we say that if must be terminated by at least +// // one whitespace character +// terminated(tag("if"), multispace1), +// cut(tuple(( +// parse_expr, +// parse_block, +// opt(preceded(preceded(multispace0, tag("else")), parse_block)), +// ))), +// ), +// |(pred, true_branch, maybe_false_branch)| { +// Cmd::If(pred, true_branch, maybe_false_branch) +// }, +// )(i) +// } + +// pub fn parse_let(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> { +// context( +// "let expression", +// map( +// preceded( +// // here to avoid ambiguity with other names starting with `let`, if we added +// // variables to our language, we say that if must be terminated by at least +// // one whitespace character +// terminated(tag("let"), multispace1), +// cut(tuple(( +// opt(preceded(multispace0, terminated(tag("mut"), multispace1))), +// parse_id, +// preceded(preceded(multispace0, tag(":")), parse_type), +// preceded(preceded(multispace0, tag("=")), parse_expr), +// ))), +// ), +// |(m, id, t, expr)| { +// Cmd::Let( +// if m.is_some() { +// Mutability::Mut +// } else { +// Mutability::Imm +// }, +// id, +// t, +// expr, +// ) +// }, +// ), +// )(i) +// } + +pub fn parse_assign<'a>(i: Span<'a>) -> IResult<Span<'a>, Cmd<'a>> { + map( + // here to avoid ambiguity with other names starting with `let`, if we added + // variables to our language, we say that if must be terminated by at least + // one whitespace character + tuple(( + parse_expr, + preceded(preceded(multispace0, tag("=")), parse_expr), + )), + |(id_expr, expr)| Cmd::Assign(id_expr, expr), + )(i) +} + +// pub fn parse_return(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> { +// context( +// "assign", +// map( +// preceded(terminated(tag("return"), multispace1), parse_expr), +// |expr| Cmd::Return(expr), +// ), +// )(i) +// } + +// pub fn parse_while(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> { +// context( +// "while expression", +// map( +// preceded( +// // here to avoid ambiguity with other names starting with `let`, if we added +// // variables to our language, we say that if must be terminated by at least +// // one whitespace character +// terminated(tag("while"), multispace1), +// cut(tuple((parse_expr, parse_block))), +// ), +// |(pred, body)| Cmd::While(pred, body), +// ), +// )(i) +// } + +// pub fn parse_cmd(i: &str) -> IResult<&str, Cmd, VerboseError<&str>> { +// preceded( +// multispace0, +// alt((parse_while, parse_let, parse_if, parse_assign, parse_return)), +// )(i) +// } + +// pub fn parse_block(i: &str) -> IResult<&str, Block, VerboseError<&str>> { +// preceded(multispace0, s_cmd(separated_list(tag(";"), parse_cmd)))(i) +// } + +// fn s_cmd<'a, O, F>(inner: F) -> impl Fn(&'a str) -> IResult<&'a str, O, VerboseError<&'a str>> +// where +// F: Fn(&'a str) -> IResult<&'a str, O, VerboseError<&'a str>>, +// { +// // delimited allows us to split up the input +// // cut allows us to consume the input (and prevent backtracking) +// preceded( +// multispace0, +// delimited( +// char('{'), +// preceded(multispace0, inner), +// context( +// "closing curly bracket", +// cut(preceded(multispace0, char('}'))), +// ), +// ), +// ) +// } + +// pub fn parse_type(i: &str) -> IResult<&str, Type, VerboseError<&str>> { +// preceded( +// multispace0, +// alt(( +// map(tag("i32"), |_| Type::I32), +// map(tag("bool"), |_| Type::Bool), +// map(preceded(tag("&"), parse_type), |t| Type::Ref(Box::new(t))), +// map( +// preceded(terminated(tag("mut"), multispace1), parse_type), +// |t| Type::Mut(Box::new(t)), +// ), +// )), +// )(i) +// } + +// pub fn parse_field_decl(i: &str) -> IResult<&str, (String, Type), VerboseError<&str>> { +// map( +// tuple((parse_id, preceded(multispace0, tag(":")), parse_type)), +// |(l, _, r)| (l, r), +// )(i) +// } + +// pub fn parse_field_decls(i: &str) -> IResult<&str, Vec<(String, Type)>, VerboseError<&str>> { +// s_cmd(separated_list(tag(","), parse_field_decl))(i) +// } + +// // pub fn parse_par_decls(i: &str) -> IResult<&str, Vec<(String, Type)>, VerboseError<&str>> { +// // s_cmd(separated_list(tag(","), parse_par_decl))(i) +// // } + +// pub fn parse_par_decl(i: &str) -> IResult<&str, (String, Type), VerboseError<&str>> { +// map( +// tuple(( +// opt(preceded(multispace0, terminated(tag("mut"), multispace1))), +// parse_id, +// preceded(multispace0, tag(":")), +// parse_type, +// )), +// |(b, id, _, t)| (id, t), +// )(i) +// } + +// pub fn parse_type_decl(i: &str) -> IResult<&str, TypeDecl, VerboseError<&str>> { +// preceded( +// preceded(multispace0, terminated(tag("struct"), multispace1)), +// map(tuple((parse_id, parse_field_decls)), |(id, fields)| { +// TypeDecl::Struct(id, fields) +// }), +// )(i) +// } + +// pub fn parse_function_decl(i: &str) -> IResult<&str, Function, VerboseError<&str>> { +// map( +// preceded( +// preceded(multispace0, terminated(tag("fn"), multispace1)), +// tuple(( +// parse_id, +// s_exp(separated_list(tag(","), parse_par_decl)), +// opt(preceded( +// preceded(multispace0, terminated(tag("->"), multispace1)), +// parse_type, +// )), +// parse_block, +// )), +// ), +// |(id, par, ret, body)| Function { +// sig: (id, par, ret.unwrap_or(Type::Unit)), +// body: body, +// }, +// )(i) +// } + +// pub fn parse_prog(i: &str) -> IResult<&str, Prog, VerboseError<&str>> { +// separated_list( +// multispace0, +// alt(( +// map(parse_function_decl, |f| Item::Function(f)), +// map(parse_type_decl, |t| Item::TypeDecl(t)), +// )), +// )(i) +// } + +// tests fn math_eval(e: &SpanExpr) -> i32 { match e.clone().1 { Expr::Num(i) => i, -- GitLab