Skip to content

Commit

Permalink
second stream
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyas-taouaou committed Mar 13, 2024
1 parent 2f37eb1 commit 6386d6a
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 45 deletions.
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
chumsky = { git = "https://github.com/zesterer/chumsky", version = "1.0.0-alpha.6", features = ["unstable"] }
ariadne = { git = "https://github.com/zesterer/ariadne.git", version = "0.4.0" }
chumsky = { git = "https://github.com/zesterer/chumsky", version = "1.0.0-alpha.6", features = [
"unstable",
] }
2 changes: 1 addition & 1 deletion sample.cdtk
Original file line number Diff line number Diff line change
@@ -1 +1 @@
let x = 1+2;
let numbers = (0..10).for(|x| (x + 1) * 2);
158 changes: 115 additions & 43 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,48 @@

use std::collections::HashMap;

use ariadne::{Label, Report, ReportKind, Source};
use chumsky::prelude::*;

type Args<'src> = Vec<Expression<'src>>;
type Parameters<'src> = Vec<&'src str>;
type Bound<'src> = Option<Box<Expression<'src>>>;

#[derive(Debug, Clone)]
enum Expression<'src> {
Number(f64),
Identifier(&'src str),
Let(&'src str, Box<Expression<'src>>, Box<Expression<'src>>),
Mul(Box<Expression<'src>>, Box<Expression<'src>>),
Div(Box<Expression<'src>>, Box<Expression<'src>>),
Add(Box<Expression<'src>>, Box<Expression<'src>>),
Sub(Box<Expression<'src>>, Box<Expression<'src>>),
Call(&'src str, Args<'src>),
Tuple(Args<'src>),
Closure(Parameters<'src>, Box<Expression<'src>>),
Range(Bound<'src>, Bound<'src>),
// Dot(Vec<&'src str>),
Dot(Box<Expression<'src>>, Box<Expression<'src>>),
End,
}

type BinaryOperator<'src> = fn(Expression<'src>, Expression<'src>) -> Expression<'src>;
type BinaryOperator<'src> = fn(Box<Expression<'src>>, Box<Expression<'src>>) -> Expression<'src>;

fn binary_parser<'src>(
previous_parser: impl Parser<'src, &'src str, Expression<'src>, extra::Err<Simple<'src, char>>>
+ Clone,
operator1: (char, BinaryOperator<'src>),
operator2: (char, BinaryOperator<'src>),
) -> impl Parser<'src, &'src str, Expression<'src>, extra::Err<Simple<'src, char>>> + Clone {
let binary_operator = choice((
just(operator1.0).to(operator1.1),
just(operator2.0).to(operator2.1),
));
previous_parser.clone().foldl(
binary_operator.then(previous_parser).repeated(),
|a, (op, b)| op(Box::new(a), Box::new(b)),
)
}

fn parser<'src>() -> impl Parser<'src, &'src str, Expression<'src>, extra::Err<Simple<'src, char>>>
{
Expand All @@ -28,64 +56,108 @@ fn parser<'src>() -> impl Parser<'src, &'src str, Expression<'src>, extra::Err<S
.unwrapped()
.map(Expression::Number);
let identifier = text::ident().map(Expression::Identifier);
let value = number.or(identifier).padded();
let unary_operator = choice((just('-').to(-1.0f64), just('+').to(1.0f64)))
.repeated()
.foldr(value, |a, b| {
Expression::Mul(Box::new(Expression::Number(a)), Box::new(b))
});

let x = choice((
just('+').to((|a, b| Expression::Add(Box::new(a), Box::new(b))) as BinaryOperator<'src>),
just('-').to((|a, b| Expression::Sub(Box::new(a), Box::new(b))) as BinaryOperator<'src>),
));
let sum = unary_operator
.then(x)
.then(unary_operator)
.map(|((lhs, operation), rhs)| operation(lhs, rhs));

let expression = recursive(|expression| {
let tuple = expression
.clone()
.separated_by(just(','))
.allow_trailing()
.collect::<Vec<_>>()
.delimited_by(just('('), just(')'));

let range = expression
.clone()
.or_not()
.separated_by(just(".."))
.exactly(2)
.collect_exactly::<[_; 2]>()
.delimited_by(just('('), just(')'))
.map(|[min, max]| Expression::Range(min.map(Box::new), max.map(Box::new)));

let call = text::ident()
.then(tuple.clone())
.map(|(name, arguments)| Expression::Call(name, arguments));

let closure = text::ident()
.padded()
.separated_by(just(','))
.allow_trailing()
.collect::<Vec<_>>()
.delimited_by(just('|'), just('|'))
.then(expression.clone())
.map(|(parameters, expression)| Expression::Closure(parameters, Box::new(expression)));

let value = choice((
range,
closure,
call,
number,
identifier,
expression.delimited_by(just('('), just(')')),
tuple.map(Expression::Tuple),
))
.padded();

let dot_operator = value
.clone()
.foldl(just('.').ignore_then(value.clone()).repeated(), |a, b| {
Expression::Dot(Box::new(a), Box::new(b))
});

// let dot_operator = text::ident()
// .separated_by(just('.'))
// .collect::<Vec<_>>()
// .map(Expression::Dot);

let unary_operator = choice((just('-').to(-1.0f64), just('+').to(1.0f64)))
.repeated()
.foldr(dot_operator, |a, b| {
Expression::Mul(Box::new(Expression::Number(a)), Box::new(b))
});

let product = binary_parser(
unary_operator,
('*', Expression::Mul),
('/', Expression::Div),
);
let sum = binary_parser(
product.clone(),
('+', Expression::Add),
('-', Expression::Sub),
);
sum
});

let r#let = recursive(|r#let| {
text::keyword("let")
.padded()
.ignore_then(text::ident())
.then_ignore(just('=').padded())
.then(sum)
.then(expression.clone())
.then_ignore(just(';'))
.then(r#let.or(sum).or_not())
.map(|((identifier, sum), then)| {
.then(r#let.or(expression).or_not())
.map(|((identifier, expression), then)| {
Expression::Let(
identifier,
Box::new(sum),
Box::new(expression),
Box::new(then.unwrap_or(Expression::End)),
)
})
});
r#let
}

fn eval<'src>(
expression: Expression<'src>,
variables: &mut HashMap<&'src str, Expression<'src>>,
) -> Expression<'src> {
match expression {
Expression::Number(number) => Expression::Number(number),
Expression::Identifier(identifier) => variables.get(identifier).unwrap().clone(),
Expression::Let(name, value, then) => {
variables.insert(name, *value).unwrap();
eval(*then, variables)
}
Expression::Mul(_, _) => todo!(),
Expression::Add(lhs, rhs) => match (*lhs, *rhs) {
(Expression::Number(lhs), Expression::Number(rhs)) => Expression::Number(lhs * rhs),
(a, b) => Expression::Add(Box::new(eval(a, variables)), Box::new(eval(b, variables))),
},
Expression::Sub(_, _) => todo!(),
Expression::End => Expression::End,
}
}

fn main() {
let source = std::fs::read_to_string("sample.cdtk").unwrap();
let ast = parser().parse(source.as_str()).unwrap();
println!("{ast:?}");
match parser().parse(source.as_str()).into_result() {
Ok(ast) => println!("{ast:#?}"),
Err(errors) => errors.into_iter().for_each(|error| {
Report::build(ReportKind::Error, (), error.span().start)
.with_message("Parse error")
.with_label(Label::new(error.span().into_range()).with_message(error.to_string()))
.finish()
.print(Source::from(source.clone()))
.unwrap();
}),
};
}

0 comments on commit 6386d6a

Please sign in to comment.