made the parser work

This commit is contained in:
JOLIMAITRE Matthieu 2022-06-01 03:41:20 +03:00
parent 7aa98bdd04
commit dac8ac1e9c
9 changed files with 588 additions and 112 deletions

2
Cargo.lock generated
View file

@ -85,7 +85,7 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]] [[package]]
name = "prout" name = "prout"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"chumsky", "chumsky",
] ]

View file

@ -1,9 +1,9 @@
[package] [package]
name = "prout" name = "prout"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
chumsky = "0.8.0" chumsky = "0.8"

View file

@ -17,11 +17,11 @@ PROUT is a minimal programming language providing tools to automate file managem
```sh ```sh
$ prout hello_world.pr $ prout hello-world.pr
``` ```
## Author ## Authors
- JOLIMAITRE Matthieu <matthieu@imagevo.fr>, developper - JOLIMAITRE Matthieu <matthieu@imagevo.fr>

36
examples/hello-world.pr Normal file
View file

@ -0,0 +1,36 @@
hello: "hello";
prout: "prout";
line: hello;
line <- add(line, " ");
line <- add(line, prout);
say-it: () => {
out(line)
};
say-it();
for: (from, to, incr, fn) => {
index: from;
loop {
if not(inf(index, to)) break true;
result: fn(index);
index <- add(index, incr)
}
};
for(0, 3, 0.5, (index) => {
out(add("index: ", index))
});
a: 1;
b: 2;
c: 3;
a <- b <- c;
out(add("a :", a));
out(add("b :", b));
out(add("c :", c));

View file

@ -1,3 +1,5 @@
use std::{env::args, fs};
pub mod execution_tree; pub mod execution_tree;
pub mod prelude; pub mod prelude;
pub mod runtime; pub mod runtime;
@ -6,11 +8,14 @@ pub mod value;
fn main() { fn main() {
use prelude::std_prelude; use prelude::std_prelude;
let input = todo!();
// let parsed = syntax_tree::parser::Parser::parse(input); let path = args().nth(1).expect("[error]: usage 'prout <path>'");
// let executable = execution_tree::parser::Parser::parse(parsed, |b| std_prelude(b)); let input = fs::read_to_string(path).expect("file not found");
// let runtime = runtime::Runtime::new(); let ast_parser = syntax_tree::parser::ParserWrapper::new();
// runtime.execute(&executable); let parsed = ast_parser.parse(&input).unwrap();
let executable = execution_tree::parser::Parser::parse(parsed, |b| std_prelude(b));
let mut runtime = runtime::Runtime::new();
runtime.execute(&executable);
} }
#[test] #[test]

View file

@ -1,14 +1,146 @@
use std::collections::HashMap;
use crate::{ use crate::{
execution_tree::parser::ParserBuilder, execution_tree::parser::ParserBuilder,
value::{function::Function, Value}, value::{function::Function, Value},
}; };
pub fn std_prelude(builder: &mut ParserBuilder) { pub fn std_prelude(builder: &mut ParserBuilder) {
builder.prelude("print".into(), Function::new_native(1, print).into()) let functions: Vec<(_, _, fn(Vec<Value>) -> Value)> = vec![
("out", 1, out),
("add", 2, add),
("sub", 2, sub),
("eq", 2, eq),
("sup", 2, sup),
("inf", 2, inf),
("and", 2, and),
("or", 2, or),
("not", 1, not),
("str", 2, str),
("obj", 0, obj),
("set", 3, set),
("get", 2, get),
];
for (name, arg_count, closure) in functions {
builder.prelude(name.into(), Function::new_native(arg_count, closure).into());
}
} }
fn print(args: Vec<Value>) -> Value { fn out(args: Vec<Value>) -> Value {
let to_print = args.get(0).unwrap(); let to_print = args.get(0).unwrap();
println!("{to_print:?}"); let str = value_to_string(to_print);
Value::Bool(true) println!("{str}");
to_print.clone()
}
fn add(args: Vec<Value>) -> Value {
let lhs = args.get(0).unwrap();
let rhs = args.get(1).unwrap();
match (lhs, rhs) {
(Value::Number(l), Value::Number(r)) => (l + r).into(),
(Value::String(l), Value::String(r)) => format!("{l}{r}").into(),
(Value::Number(l), Value::String(r)) => format!("{l}{r}").into(),
(Value::String(l), Value::Number(r)) => format!("{l}{r}").into(),
_ => unreachable!(),
}
}
fn sub(args: Vec<Value>) -> Value {
let lhs = args.get(0).unwrap();
let rhs = args.get(1).unwrap();
match (lhs, rhs) {
(Value::Number(l), Value::Number(r)) => (l - r).into(),
_ => panic!("substracting non-numbers"),
}
}
fn eq(args: Vec<Value>) -> Value {
let lhs = args.get(0).unwrap();
let rhs = args.get(1).unwrap();
match (lhs, rhs) {
(Value::Bool(l), Value::Bool(r)) => (l == r).into(),
(Value::Number(l), Value::Number(r)) => (l == r).into(),
(Value::String(l), Value::String(r)) => (l == r).into(),
_ => panic!("comparing different types"),
}
}
fn sup(args: Vec<Value>) -> Value {
let lhs = args.get(0).unwrap();
let rhs = args.get(1).unwrap();
match (lhs, rhs) {
(Value::Number(l), Value::Number(r)) => (l > r).into(),
_ => panic!("comparing non-numeric"),
}
}
fn inf(args: Vec<Value>) -> Value {
let lhs = args.get(0).unwrap();
let rhs = args.get(1).unwrap();
match (lhs, rhs) {
(Value::Number(l), Value::Number(r)) => (l < r).into(),
_ => panic!("comparing non-numeric"),
}
}
fn and(args: Vec<Value>) -> Value {
let lhs = args.get(0).unwrap();
let rhs = args.get(1).unwrap();
match (lhs, rhs) {
(Value::Bool(l), Value::Bool(r)) => (*l && *r).into(),
_ => panic!("intersection of non-boolean"),
}
}
fn or(args: Vec<Value>) -> Value {
let lhs = args.get(0).unwrap();
let rhs = args.get(1).unwrap();
match (lhs, rhs) {
(Value::Bool(l), Value::Bool(r)) => (*l || *r).into(),
_ => panic!("union of non-boolean"),
}
}
fn not(args: Vec<Value>) -> Value {
let input = args.get(0).unwrap();
let result = !input.as_bool().expect("complementing non-bool");
result.into()
}
fn value_to_string(input: &Value) -> String {
match input {
Value::None => "None".to_string(),
Value::Bool(b) => format!("{b}"),
Value::Number(n) => format!("{n}"),
Value::String(s) => s.clone(),
Value::Object(_) => "[object]".into(),
Value::Function(_) => "[function]".into(),
}
}
fn str(args: Vec<Value>) -> Value {
let input = args.get(0).unwrap();
value_to_string(input).into()
}
fn obj(_: Vec<Value>) -> Value {
Value::Object(HashMap::new())
}
fn set(mut args: Vec<Value>) -> Value {
let name = args.get(1).unwrap().as_string().unwrap().to_string();
let value = args.get(2).unwrap().clone();
let object = args.get_mut(0).unwrap().as_object_mut().unwrap();
object.insert(name, value.clone());
value
}
fn get(args: Vec<Value>) -> Value {
let object = args.get(0).unwrap().as_object().unwrap();
let name = args.get(1).unwrap().as_string().unwrap();
object
.get(name)
.map(|value| value.clone())
.unwrap_or_else(|| false.into())
} }

View file

@ -29,7 +29,7 @@ impl FrameBuilder {
} }
pub struct Frame { pub struct Frame {
scope_id: Id, _scope_id: Id,
variables: HashMap<Id, Value>, variables: HashMap<Id, Value>,
} }
@ -54,7 +54,7 @@ impl Frame {
let FrameBuilder { variables } = frame_builder; let FrameBuilder { variables } = frame_builder;
let scope_id = scope_id.clone(); let scope_id = scope_id.clone();
Self { Self {
scope_id, _scope_id: scope_id,
variables, variables,
} }
} }

View file

@ -1,20 +1,47 @@
use chumsky::prelude::*;
use super::*; use super::*;
use chumsky::{prelude::*, text::whitespace};
pub fn scope_parser() -> impl Parser<char, Scope, Error = Simple<char>> { pub trait AbstractParser<T>: Parser<char, T, Error = Simple<char>> {}
expression_parser()
.chain( impl<T, U: Parser<char, T, Error = Simple<char>>> AbstractParser<T> for U {}
just(';')
.padded() pub fn debugging_expression_parser() -> impl AbstractParser<Expr> + Clone {
.ignore_then(expression_parser()) variable_call_parser().padded().map(|v| v.into())
.repeated(),
)
.delimited_by(just('{'), just('}'))
.map(|instructions| Scope { instructions })
} }
pub fn literal_value() -> impl Parser<char, Value, Error = Simple<char>> { pub fn scope_parser(expression: impl AbstractParser<Expr> + Clone) -> impl AbstractParser<Scope> {
let open_list = expression.separated_by(just(';'));
let closed_list = open_list.clone().then_ignore(just(';').then(whitespace()));
open_list
.map(|instructions| Scope { instructions })
.or(closed_list.map(|mut instructions| {
instructions.push(Value::None.into());
Scope { instructions }
}))
.padded()
.delimited_by(just('{'), just('}'))
}
#[test]
fn test_scope_parser() {
let parser = scope_parser(debugging_expression_parser());
let value = parser.parse("{ arbre }");
dbg!(value.unwrap());
}
// TODO: add objects ?
pub fn literal_value() -> impl AbstractParser<Value> {
let bool = just("false")
.map(|_| false.into())
.or(just("true").map(|_| true.into()));
let none = just("none").map(|_| Value::None);
let string = just('\"')
.ignore_then(none_of("\"").repeated())
.then_ignore(just('\"'))
.map(|v| String::from_iter(&v).into());
let frac = just('.').chain(text::digits(10)); let frac = just('.').chain(text::digits(10));
let number = just('-') let number = just('-')
.or_not() .or_not()
@ -22,105 +49,346 @@ pub fn literal_value() -> impl Parser<char, Value, Error = Simple<char>> {
.chain::<char, _, _>(frac.or_not().flatten()) .chain::<char, _, _>(frac.or_not().flatten())
.collect::<String>() .collect::<String>()
.from_str() .from_str()
.unwrapped(); .unwrapped()
let literal = number.clone().map(|n| Value::Number(n)); // TODO: add other types .map(|n: f64| n.into());
let literal = bool.or(none).or(string).or(number);
literal literal
} }
pub fn name() -> impl Parser<char, String, Error = Simple<char>> { #[test]
let name = just('a') fn test_literal_value() {
.or(just('b')) let parser = literal_value();
.or(just('c')) let value = parser.parse("5");
.or(just('d')) assert_eq!(value.unwrap().as_number().unwrap(), 5.);
.or(just('e')) }
.or(just('f'))
.or(just('g')) pub fn name() -> impl AbstractParser<String> + Clone {
.or(just('h')) let first = one_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
.or(just('i')) let rest = first.clone().or(one_of("1234567890-_+/*"));
.or(just('j')) let name = first.then(rest.repeated()).map(|(f, v)| {
.or(just('k')) let rest = String::from_iter(&v);
.or(just('l')) format!("{f}{rest}")
.or(just('m')) });
.or(just('n'))
.or(just('o'))
.or(just('p'))
.or(just('q'))
.or(just('r'))
.or(just('s'))
.or(just('t'))
.or(just('u'))
.or(just('v'))
.or(just('w'))
.or(just('x'))
.or(just('y'))
.or(just('z'))
.or(just('-'))
.or(just('_'))
.repeated()
.map(|v| String::from_iter(&v));
name name
} }
pub fn variable_definition_parser() -> impl Parser<char, VarDef, Error = Simple<char>> { pub fn variable_definition_parser(
expression: impl AbstractParser<Expr>,
) -> impl AbstractParser<VarDef> {
name() name()
.padded() .then_ignore(just(":").padded())
.then_ignore(just(":")) .then(expression)
.padded()
.then(expression_parser())
.map(|(name, value)| VarDef { name, value }) .map(|(name, value)| VarDef { name, value })
} }
pub fn variable_assignement_parser() -> impl Parser<char, VarAssign, Error = Simpl<char>> { #[test]
expression_parser().then() name() fn test_variable_definition_parser() {
let parser = variable_definition_parser(debugging_expression_parser());
let value = parser.parse("a : b");
dbg!(value.unwrap());
} }
pub fn expression_parser() -> impl Parser<char, Expr, Error = Simple<char>> { pub fn variable_assignement_parser(
let scope = scope_parser().map(|s| s.into()); expression: impl AbstractParser<Expr>,
let litteral = literal_value().map(|v| Expr::new_literal(v)); ) -> impl AbstractParser<VarAssign> {
let variable_definition = variable_definition_parser().map(|s| s.into()); name()
let variable_assignment; .then_ignore(just("<-").padded())
let variable_call; .then(expression)
let function_definition; .map(|(name, value)| VarAssign { name, value })
let function_call;
let function_return;
let loop_;
let loop_break;
let condition;
scope
.or(litteral)
.or(variable_definition)
.or(variable_assignment)
.or(variable_call)
.or(function_definition)
.or(function_call)
.or(function_return)
.or(loop_)
.or(loop_break)
.or(condition)
} }
pub fn parser() -> impl Parser<char, Program, Error = Simple<char>> { #[test]
let scope = expression_parser().chain( fn test_variable_assignement_parser() {
just(';') let parser = variable_assignement_parser(debugging_expression_parser());
.padded() let value = parser.parse("arbre <- expr");
.ignore_then(expression_parser()) dbg!(value.unwrap());
.repeated(), }
);
let program = scope pub fn variable_call_parser() -> impl AbstractParser<VarCall> + Clone {
.map(|instructions| { name().map(|name| VarCall { name })
let body = Scope { instructions }; }
Program { body }
#[test]
fn test_variable_call_parser() {
let parser = variable_call_parser();
let value = parser.parse("arbre");
assert_eq!(value.unwrap().name, "arbre".to_string());
}
pub fn function_definition_parser(
expression: impl AbstractParser<Expr> + Clone,
) -> impl AbstractParser<FnDef> {
let parameters = name().separated_by(just(',').padded());
let body = scope_parser(expression);
parameters
.padded()
.delimited_by(just('('), just(')'))
.then_ignore(just("=>").padded())
.then(body)
.map(|(parameter_names, body)| FnDef {
body,
parameter_names,
}) })
.then_ignore(end().recover_with(skip_then_retry_until([]))); }
#[test]
fn test_function_definition_parser() {
let parser = function_definition_parser(debugging_expression_parser());
let value = parser.parse("(a) => { b }");
dbg!(value.unwrap());
}
pub fn function_call_parser(expression: impl AbstractParser<Expr>) -> impl AbstractParser<FnCall> {
let parameters = expression.separated_by(just(',').padded());
name()
.then(parameters.padded().delimited_by(just('('), just(')')))
.map(|(name, arguments)| FnCall { arguments, name })
}
#[test]
fn test_function_call_parser() {
let parser = function_call_parser(debugging_expression_parser());
let value = parser.parse("f( a , b )");
dbg!(value.unwrap());
}
pub fn function_return_parser(expression: impl AbstractParser<Expr>) -> impl AbstractParser<FnRet> {
just("return")
.ignore_then(expression.or_not())
.map(|expr| expr.unwrap_or(From::<Value>::from(true.into())))
.map(|value| FnRet { value })
}
#[test]
fn test_function_return_parser() {
let parser = function_return_parser(debugging_expression_parser());
let value = parser.parse("return a");
dbg!(value.unwrap());
}
pub fn loop_parser(expression: impl AbstractParser<Expr> + Clone) -> impl AbstractParser<Loop> {
just("loop")
.then(whitespace())
.ignore_then(scope_parser(expression))
.map(|body| Loop { body })
}
#[test]
fn test_loop_parser() {
let parser = loop_parser(debugging_expression_parser());
let value = parser.parse("loop { a}");
dbg!(value.unwrap());
}
pub fn loop_break_parser(expression: impl AbstractParser<Expr>) -> impl AbstractParser<LoopBr> {
just("break")
.ignore_then(just(" ").then(whitespace()).ignore_then(expression))
.map(|value| LoopBr { value })
}
#[test]
fn test_loop_break_parser() {
let parser = loop_break_parser(debugging_expression_parser());
let value = parser.parse("break a");
dbg!(value.unwrap());
}
pub fn condition_parser(
expression: impl AbstractParser<Expr> + Clone,
) -> impl AbstractParser<Cond> {
just("if ")
.ignore_then(expression.clone())
.then(expression.clone())
.then(just("else ").ignore_then(expression.clone()).or_not())
.map(|((condition, arm_true), arm_false)| Cond {
condition,
arm_true,
arm_false,
})
}
#[test]
fn test_condition_parser() {
let parser = condition_parser(debugging_expression_parser());
let value = parser.parse("if a t else f");
dbg!(value.unwrap());
}
fn sugar_parser(expression: impl AbstractParser<Expr> + Clone) -> impl AbstractParser<Expr> {
let add = expression
.clone()
.then_ignore(just(" + "))
.then(expression.clone())
.map(|(l, r)| {
FnCall {
name: "add".into(),
arguments: vec![l, r],
}
.into()
});
let sub = expression
.clone()
.then_ignore(just(" - "))
.then(expression.clone())
.map(|(l, r)| {
FnCall {
name: "sub".into(),
arguments: vec![l, r],
}
.into()
});
let eq = expression
.clone()
.then_ignore(just(" == "))
.then(expression.clone())
.map(|(l, r)| {
FnCall {
name: "eq".into(),
arguments: vec![l, r],
}
.into()
});
let sup = expression
.clone()
.then_ignore(just(" > "))
.then(expression.clone())
.map(|(l, r)| {
FnCall {
name: "sup".into(),
arguments: vec![l, r],
}
.into()
});
let inf = expression
.clone()
.then_ignore(just(" < "))
.then(expression.clone())
.map(|(l, r)| {
FnCall {
name: "inf".into(),
arguments: vec![l, r],
}
.into()
});
let or = expression
.clone()
.then_ignore(just(" || "))
.then(expression.clone())
.map(|(l, r)| {
FnCall {
name: "or".into(),
arguments: vec![l, r],
}
.into()
});
let and = expression
.clone()
.then_ignore(just(" && "))
.then(expression.clone())
.map(|(l, r)| {
FnCall {
name: "and".into(),
arguments: vec![l, r],
}
.into()
});
eq.or(add).or(sub).or(sup).or(inf).or(or).or(and)
}
pub fn expression_parser() -> impl AbstractParser<Expr> {
let expression = recursive(|expression| {
//let sugar = sugar_parser(expression.clone());
let condition = condition_parser(expression.clone()).map(|i| i.into());
let function_definition = function_definition_parser(expression.clone()).map(|i| i.into());
let function_return = function_return_parser(expression.clone()).map(|i| i.into());
let loop_ = loop_parser(expression.clone()).map(|i| i.into());
let loop_break = loop_break_parser(expression.clone()).map(|i| i.into());
let scope = scope_parser(expression.clone()).map(|i| i.into());
let litteral = literal_value().map(|v| Expr::new_literal(v));
let variable_definition = variable_definition_parser(expression.clone()).map(|i| i.into());
let variable_assignment = variable_assignement_parser(expression.clone()).map(|i| i.into());
let function_call = function_call_parser(expression.clone()).map(|i| i.into());
let variable_call = variable_call_parser().map(|i| i.into());
//sugar
// .or(condition)
condition
.or(function_definition)
.or(function_return)
.or(loop_)
.or(loop_break)
.or(scope)
.or(litteral)
.or(variable_definition)
.or(variable_assignment)
.or(function_call)
.or(variable_call)
.padded()
});
expression
}
#[test]
fn test_expression_parser() {
let text = r##"if a b"##;
let parser = expression_parser();
let value = parser.parse(text);
dbg!(value.unwrap());
}
fn parser() -> impl AbstractParser<Program> {
let scope = expression_parser()
.separated_by(just(';').padded())
.then_ignore(just(';').padded().or_not())
.then_ignore(end());
let program = scope.map(|instructions| {
let body = Scope { instructions };
Program { body }
});
program program
} }
// impl Parser { #[test]
// pub fn parse(input: &str) -> Program { fn test_parser() {
// todo!() let example = r##"
// } print(3);
// }
a: 3;
b: (a) => {
print("a")
};
f(a)
"##;
let parser = parser();
let e = parser.parse(example);
dbg!(e.unwrap());
}
pub struct ParserWrapper {
inner: Box<dyn AbstractParser<Program>>,
}
impl ParserWrapper {
pub fn new() -> Self {
let inner = Box::new(parser());
ParserWrapper { inner }
}
pub fn parse<'i>(&self, input: &'i str) -> Result<Program, Vec<Simple<char>>> {
self.inner.parse(input)
}
}
/* /*
// example // example
@ -137,7 +405,7 @@ loop {
if a <= 0 { if a <= 0 {
break true break true
} else { } else {
a - 1 -> a a <- a - 1
} }
} }

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use self::function::Function; use self::function::Function;
pub mod function { pub mod function {
use crate::execution_tree::{Expr, Id}; use crate::execution_tree::Id;
use super::Value; use super::Value;
@ -72,6 +72,41 @@ pub enum Value {
} }
impl Value { impl Value {
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_number(&self) -> Option<f64> {
match self {
Self::Number(n) => Some(*n),
_ => None,
}
}
pub fn as_string(&self) -> Option<&str> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
match self {
Self::Object(h) => Some(h),
_ => None,
}
}
pub fn as_object_mut(&mut self) -> Option<&mut HashMap<String, Value>> {
match self {
Self::Object(h) => Some(h),
_ => None,
}
}
pub fn as_function(&self) -> Option<&Function> { pub fn as_function(&self) -> Option<&Function> {
match self { match self {
Self::Function(function) => Some(function), Self::Function(function) => Some(function),