made the parser work
This commit is contained in:
parent
7aa98bdd04
commit
dac8ac1e9c
9 changed files with 588 additions and 112 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -85,7 +85,7 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
|||
|
||||
[[package]]
|
||||
name = "prout"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"chumsky",
|
||||
]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
[package]
|
||||
name = "prout"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chumsky = "0.8.0"
|
||||
chumsky = "0.8"
|
||||
|
|
|
@ -17,11 +17,11 @@ PROUT is a minimal programming language providing tools to automate file managem
|
|||
|
||||
```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
36
examples/hello-world.pr
Normal 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));
|
15
src/main.rs
15
src/main.rs
|
@ -1,3 +1,5 @@
|
|||
use std::{env::args, fs};
|
||||
|
||||
pub mod execution_tree;
|
||||
pub mod prelude;
|
||||
pub mod runtime;
|
||||
|
@ -6,11 +8,14 @@ pub mod value;
|
|||
|
||||
fn main() {
|
||||
use prelude::std_prelude;
|
||||
let input = todo!();
|
||||
// let parsed = syntax_tree::parser::Parser::parse(input);
|
||||
// let executable = execution_tree::parser::Parser::parse(parsed, |b| std_prelude(b));
|
||||
// let runtime = runtime::Runtime::new();
|
||||
// runtime.execute(&executable);
|
||||
|
||||
let path = args().nth(1).expect("[error]: usage 'prout <path>'");
|
||||
let input = fs::read_to_string(path).expect("file not found");
|
||||
let ast_parser = syntax_tree::parser::ParserWrapper::new();
|
||||
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]
|
||||
|
|
140
src/prelude.rs
140
src/prelude.rs
|
@ -1,14 +1,146 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
execution_tree::parser::ParserBuilder,
|
||||
value::{function::Function, Value},
|
||||
};
|
||||
|
||||
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();
|
||||
println!("{to_print:?}");
|
||||
Value::Bool(true)
|
||||
let str = value_to_string(to_print);
|
||||
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())
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ impl FrameBuilder {
|
|||
}
|
||||
|
||||
pub struct Frame {
|
||||
scope_id: Id,
|
||||
_scope_id: Id,
|
||||
variables: HashMap<Id, Value>,
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ impl Frame {
|
|||
let FrameBuilder { variables } = frame_builder;
|
||||
let scope_id = scope_id.clone();
|
||||
Self {
|
||||
scope_id,
|
||||
_scope_id: scope_id,
|
||||
variables,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,47 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use super::*;
|
||||
use chumsky::{prelude::*, text::whitespace};
|
||||
|
||||
pub fn scope_parser() -> impl Parser<char, Scope, Error = Simple<char>> {
|
||||
expression_parser()
|
||||
.chain(
|
||||
just(';')
|
||||
.padded()
|
||||
.ignore_then(expression_parser())
|
||||
.repeated(),
|
||||
)
|
||||
.delimited_by(just('{'), just('}'))
|
||||
.map(|instructions| Scope { instructions })
|
||||
pub trait AbstractParser<T>: Parser<char, T, Error = Simple<char>> {}
|
||||
|
||||
impl<T, U: Parser<char, T, Error = Simple<char>>> AbstractParser<T> for U {}
|
||||
|
||||
pub fn debugging_expression_parser() -> impl AbstractParser<Expr> + Clone {
|
||||
variable_call_parser().padded().map(|v| v.into())
|
||||
}
|
||||
|
||||
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 number = just('-')
|
||||
.or_not()
|
||||
|
@ -22,105 +49,346 @@ pub fn literal_value() -> impl Parser<char, Value, Error = Simple<char>> {
|
|||
.chain::<char, _, _>(frac.or_not().flatten())
|
||||
.collect::<String>()
|
||||
.from_str()
|
||||
.unwrapped();
|
||||
let literal = number.clone().map(|n| Value::Number(n)); // TODO: add other types
|
||||
.unwrapped()
|
||||
.map(|n: f64| n.into());
|
||||
|
||||
let literal = bool.or(none).or(string).or(number);
|
||||
literal
|
||||
}
|
||||
|
||||
pub fn name() -> impl Parser<char, String, Error = Simple<char>> {
|
||||
let name = just('a')
|
||||
.or(just('b'))
|
||||
.or(just('c'))
|
||||
.or(just('d'))
|
||||
.or(just('e'))
|
||||
.or(just('f'))
|
||||
.or(just('g'))
|
||||
.or(just('h'))
|
||||
.or(just('i'))
|
||||
.or(just('j'))
|
||||
.or(just('k'))
|
||||
.or(just('l'))
|
||||
.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));
|
||||
#[test]
|
||||
fn test_literal_value() {
|
||||
let parser = literal_value();
|
||||
let value = parser.parse("5");
|
||||
assert_eq!(value.unwrap().as_number().unwrap(), 5.);
|
||||
}
|
||||
|
||||
pub fn name() -> impl AbstractParser<String> + Clone {
|
||||
let first = one_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
let rest = first.clone().or(one_of("1234567890-_+/*"));
|
||||
let name = first.then(rest.repeated()).map(|(f, v)| {
|
||||
let rest = String::from_iter(&v);
|
||||
format!("{f}{rest}")
|
||||
});
|
||||
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()
|
||||
.padded()
|
||||
.then_ignore(just(":"))
|
||||
.padded()
|
||||
.then(expression_parser())
|
||||
.then_ignore(just(":").padded())
|
||||
.then(expression)
|
||||
.map(|(name, value)| VarDef { name, value })
|
||||
}
|
||||
|
||||
pub fn variable_assignement_parser() -> impl Parser<char, VarAssign, Error = Simpl<char>> {
|
||||
expression_parser().then() name()
|
||||
#[test]
|
||||
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>> {
|
||||
let scope = scope_parser().map(|s| s.into());
|
||||
pub fn variable_assignement_parser(
|
||||
expression: impl AbstractParser<Expr>,
|
||||
) -> impl AbstractParser<VarAssign> {
|
||||
name()
|
||||
.then_ignore(just("<-").padded())
|
||||
.then(expression)
|
||||
.map(|(name, value)| VarAssign { name, value })
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_variable_assignement_parser() {
|
||||
let parser = variable_assignement_parser(debugging_expression_parser());
|
||||
let value = parser.parse("arbre <- expr");
|
||||
dbg!(value.unwrap());
|
||||
}
|
||||
|
||||
pub fn variable_call_parser() -> impl AbstractParser<VarCall> + Clone {
|
||||
name().map(|name| VarCall { name })
|
||||
}
|
||||
|
||||
#[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,
|
||||
})
|
||||
}
|
||||
|
||||
#[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().map(|s| s.into());
|
||||
let variable_assignment;
|
||||
let variable_call;
|
||||
let function_definition;
|
||||
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)
|
||||
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_call)
|
||||
.or(function_return)
|
||||
.or(loop_)
|
||||
.or(loop_break)
|
||||
.or(condition)
|
||||
.or(scope)
|
||||
.or(litteral)
|
||||
.or(variable_definition)
|
||||
.or(variable_assignment)
|
||||
.or(function_call)
|
||||
.or(variable_call)
|
||||
.padded()
|
||||
});
|
||||
expression
|
||||
}
|
||||
|
||||
pub fn parser() -> impl Parser<char, Program, Error = Simple<char>> {
|
||||
let scope = expression_parser().chain(
|
||||
just(';')
|
||||
.padded()
|
||||
.ignore_then(expression_parser())
|
||||
.repeated(),
|
||||
);
|
||||
#[test]
|
||||
fn test_expression_parser() {
|
||||
let text = r##"if a b"##;
|
||||
let parser = expression_parser();
|
||||
let value = parser.parse(text);
|
||||
dbg!(value.unwrap());
|
||||
}
|
||||
|
||||
let program = scope
|
||||
.map(|instructions| {
|
||||
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 }
|
||||
})
|
||||
.then_ignore(end().recover_with(skip_then_retry_until([])));
|
||||
});
|
||||
program
|
||||
}
|
||||
|
||||
// impl Parser {
|
||||
// pub fn parse(input: &str) -> Program {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
#[test]
|
||||
fn test_parser() {
|
||||
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
|
||||
|
@ -137,7 +405,7 @@ loop {
|
|||
if a <= 0 {
|
||||
break true
|
||||
} else {
|
||||
a - 1 -> a
|
||||
a <- a - 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
37
src/value.rs
37
src/value.rs
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use self::function::Function;
|
||||
pub mod function {
|
||||
use crate::execution_tree::{Expr, Id};
|
||||
use crate::execution_tree::Id;
|
||||
|
||||
use super::Value;
|
||||
|
||||
|
@ -72,6 +72,41 @@ pub enum 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> {
|
||||
match self {
|
||||
Self::Function(function) => Some(function),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue