various fixes

This commit is contained in:
JOLIMAITRE Matthieu 2023-06-12 01:02:07 +02:00
parent c08c263f32
commit 28377bd3c2
11 changed files with 149 additions and 87 deletions

32
Cargo.lock generated
View file

@ -28,9 +28,9 @@ dependencies = [
[[package]] [[package]]
name = "const-random" name = "const-random"
version = "0.1.13" version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e"
dependencies = [ dependencies = [
"const-random-macro", "const-random-macro",
"proc-macro-hack", "proc-macro-hack",
@ -38,12 +38,12 @@ dependencies = [
[[package]] [[package]]
name = "const-random-macro" name = "const-random-macro"
version = "0.1.13" version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"lazy_static", "once_cell",
"proc-macro-hack", "proc-macro-hack",
"tiny-keccak", "tiny-keccak",
] ]
@ -65,12 +65,6 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.126" version = "0.2.126"
@ -78,18 +72,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]] [[package]]
name = "proc-macro-hack" name = "once_cell"
version = "0.5.19" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]] [[package]]
name = "prout" name = "porte"
version = "0.3.0" version = "0.4.0"
dependencies = [ dependencies = [
"chumsky", "chumsky",
] ]
[[package]]
name = "proc-macro-hack"
version = "0.5.20+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]] [[package]]
name = "tiny-keccak" name = "tiny-keccak"
version = "2.0.2" version = "2.0.2"

View file

@ -1,11 +1,11 @@
[package] [package]
name = "prout" name = "porte"
version = "0.3.0" version = "0.4.0"
edition = "2021" edition = "2021"
authors = ["JOLIMAITRE Matthieu <matthieu@imagevo.fr>"] authors = ["JOLIMAITRE Matthieu <matthieu@imagevo.fr>"]
description = "A minimal programming language providing tools to automate file management like backups, building process or unit testing." description = "A minimal programming language providing tools to automate file management like backups, building process or unit testing."
license = "MIT" license = "MIT"
repository = "https://github.com/MajorBarnulf/prout" repository = "https://github.com/MajorBarnulf/porte"
# 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

View file

@ -1,15 +1,15 @@
# PROUT # PORTE
* Programmable * Programmable
* Repeatable
* Opinionated * Opinionated
* Understandable * Repeatable
* Tiny * Tiny
* Extensible
## Description ## Description
PROUT is a minimal programming language providing tools to automate file management like backups, building process or unit testing. PORTE is a minimal programming language providing tools to automate file management like backups, building process or unit testing.
## Usage ## Usage
@ -17,7 +17,7 @@ PROUT is a minimal programming language providing tools to automate file managem
```sh ```sh
$ prout hello-world.pr $ porte hello-world.pr
``` ```

View file

@ -22,6 +22,13 @@ array_get: (self, index) => {
get(self, str(index)) get(self, str(index))
}; };
foreach: (arr, f) => {
l: array_len(arr);
for(0, l, (i) => {
f(array_get(arr, i))
})
};
array_push: (self, e) => { array_push: (self, e) => {
i: array_len(self); i: array_len(self);
self <- set(self, str(i), e); self <- set(self, str(i), e);
@ -39,30 +46,72 @@ array_pop: (self) => {
e: array_get(self, i); e: array_get(self, i);
self <- set(self, str(i), false); self <- set(self, str(i), false);
rest: array_new();
foreach(self, (item) => { if not(eq(item, false)) rest <- array_push(rest, item) });
r: obj(); r: obj();
r <- set(r, "tail", e); r <- set(r, "tail", e);
r <- set(r, "rest", self); r <- set(r, "rest", rest);
r r
}; };
array_swap: (self, i, j) => {
i_value: array_get(self, i);
j_value: array_get(self, j);
self <- set(self, str(j), i_value);
self <- set(self, str(i), j_value);
self
};
array_sort: (self, cmp) => {
l: array_len(self);
for(0, sub(l, 1), (i) => {
i_min: i;
for(add(i, 1), l, (j) => {
e_j: array_get(self, j);
e_min: array_get(self, i_min);
if inf(cmp(e_j, e_min), 0) i_min <- j
});
self <- array_swap(self, i, i_min)
});
self
};
array_print: (self) => { array_print: (self) => {
l: array_len(self); l: array_len(self);
r: "["; r: "[ ";
for(0, l, (i) => { for(0, l, (i) => {
r <- add(r, array_get(self, i)); r <- add(r, array_get(self, i));
r <- add(r, ", ") if not(eq(i, sub(l, 1))) r <- add(r, ", ")
}); });
r <- add(r, "]"); r <- add(r, " ]");
out(r) out(r)
}; };
main: () => { "########################";
a: array_new(); "# main #";
a <- array_push(a, 1); "########################";
a <- array_push(a, 2);
a <- array_push(a, 3);
a <- array_push(a, 4);
array_print(a)
};
main(); a: array_new();
out("new:");
array_print(a);
a <- array_push(a, 1);
a <- array_push(a, 4);
a <- array_push(a, 6);
a <- array_push(a, 3);
a <- array_push(a, 2);
out("");
out("pushed:");
array_print(a);
r: array_pop(a);
a <- get(r, "rest");
out("");
out("popped:");
array_print(a);
a <- array_sort(a, (a, b) => { if sup(a, b) 1 else -1 });
out("");
out("sorted:");
array_print(a);

View file

@ -1,10 +1,10 @@
hello: "hello"; hello: "hello";
prout: "prout"; porte: "porte";
line: hello; line: hello;
line <- add(line, " "); line <- add(line, " ");
line <- add(line, prout); line <- add(line, porte);
say-it: () => { say-it: () => {
out(line) out(line)

View file

@ -73,7 +73,7 @@ impl Parser {
let parent_scope_id = parser_scope.get_parent_id(); let parent_scope_id = parser_scope.get_parent_id();
let expressions = instructions let expressions = instructions
.into_iter() .into_iter()
.map(|expression| self.parse_expression(expression, &parser_scope)) .map(|expression| self.parse_expression(expression, parser_scope))
.collect(); .collect();
let local_variables = parser_scope.local_variable_ids(); let local_variables = parser_scope.local_variable_ids();
@ -218,7 +218,7 @@ impl Parser {
let variable_id = parser_scope let variable_id = parser_scope
.get_variable_id(&name) .get_variable_id(&name)
.expect(&format!("call of undeclared function '{name}'")); .unwrap_or_else(|| panic!("call of undeclared function '{name}'"));
let parameters = arguments let parameters = arguments
.into_iter() .into_iter()
.map(|argument| self.parse_expression(argument, parser_scope)) .map(|argument| self.parse_expression(argument, parser_scope))
@ -390,7 +390,7 @@ impl ParserScope {
next_id: self.next_id.clone(), next_id: self.next_id.clone(),
variables: Rc::new(Mutex::new(variables)), variables: Rc::new(Mutex::new(variables)),
current_id, current_id,
current_function_scope_id: Some(current_id.clone()), current_function_scope_id: Some(current_id),
current_loop_scope_id: None, current_loop_scope_id: None,
} }
} }
@ -409,24 +409,24 @@ impl ParserScope {
variables: Rc::new(Mutex::new(variables)), variables: Rc::new(Mutex::new(variables)),
current_id, current_id,
current_function_scope_id: self.get_current_function_id(), current_function_scope_id: self.get_current_function_id(),
current_loop_scope_id: Some(current_id.clone()), current_loop_scope_id: Some(current_id),
} }
} }
pub fn get_current_id(&self) -> Id { pub fn get_current_id(&self) -> Id {
self.current_id.clone() self.current_id
} }
pub fn get_current_function_id(&self) -> Option<Id> { pub fn get_current_function_id(&self) -> Option<Id> {
self.current_function_scope_id.clone() self.current_function_scope_id
} }
pub fn get_current_loop_id(&self) -> Option<Id> { pub fn get_current_loop_id(&self) -> Option<Id> {
self.current_loop_scope_id.clone() self.current_loop_scope_id
} }
pub fn get_parent_id(&self) -> Option<Id> { pub fn get_parent_id(&self) -> Option<Id> {
self.parent_id.clone() self.parent_id
} }
pub fn get_variable_id(&self, name: &str) -> Option<Id> { pub fn get_variable_id(&self, name: &str) -> Option<Id> {

View file

@ -1,20 +1,20 @@
use std::{env::args, fs}; use std::{env::args, fs};
pub mod demo;
pub mod execution_tree; pub mod execution_tree;
pub mod prelude; pub mod prelude;
pub mod runtime; pub mod runtime;
pub mod syntax_tree; pub mod syntax_tree;
pub mod value; pub mod value;
pub mod demo;
fn main() { fn main() {
use prelude::std_prelude; use prelude::std_prelude;
let path = args().nth(1).expect("[error]: usage 'prout <path>'"); let path = args().nth(1).expect("[error]: usage 'porte <path>'");
let input = fs::read_to_string(path).expect("file not found"); let input = fs::read_to_string(path).expect("file not found");
let ast_parser = syntax_tree::parser::ParserWrapper::new(); let ast_parser = syntax_tree::parser::ParserWrapper::new();
let parsed = ast_parser.parse(&input).unwrap(); let parsed = ast_parser.parse(&input).unwrap();
let executable = execution_tree::parser::Parser::parse(parsed, |b| std_prelude(b)); let executable = execution_tree::parser::Parser::parse(parsed, std_prelude);
let mut runtime = runtime::Runtime::new(); let mut runtime = runtime::Runtime::new();
runtime.execute(&executable); runtime.execute(&executable);
} }
@ -40,11 +40,11 @@ fn it_works() {
]), ]),
), ),
), ),
Expr::new_function_call("my_print", vec!["hello, PROUT".into()]), Expr::new_function_call("my_print", vec!["hello, PORTE".into()]),
Expr::new_function_call("print", vec![Expr::new_variable_call("a")]), Expr::new_function_call("print", vec![Expr::new_variable_call("a")]),
]), ]),
}; };
let exec = Parser::parse(ast, |builder| std_prelude(builder)); let exec = Parser::parse(ast, std_prelude);
println!("\n\n\n-- running: --"); println!("\n\n\n-- running: --");
let _result = Runtime::new().execute(&exec); let _result = Runtime::new().execute(&exec);
} }

View file

@ -6,7 +6,8 @@ use crate::{
}; };
pub fn std_prelude(builder: &mut ParserBuilder) { pub fn std_prelude(builder: &mut ParserBuilder) {
let functions: Vec<(_, _, fn(Vec<Value>) -> Value)> = vec![ type FunctOper = fn(Vec<Value>) -> Value;
let functions: Vec<(_, _, FunctOper)> = vec![
("out", 1, out), ("out", 1, out),
("add", 2, add), ("add", 2, add),
("sub", 2, sub), ("sub", 2, sub),
@ -42,7 +43,7 @@ fn add(args: Vec<Value>) -> Value {
(Value::String(l), Value::String(r)) => format!("{l}{r}").into(), (Value::String(l), Value::String(r)) => format!("{l}{r}").into(),
(Value::Number(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(), (Value::String(l), Value::Number(r)) => format!("{l}{r}").into(),
_ => unreachable!(), _ => panic!("adding incompatible types"),
} }
} }
@ -62,7 +63,7 @@ fn eq(args: Vec<Value>) -> Value {
(Value::Bool(l), Value::Bool(r)) => (l == r).into(), (Value::Bool(l), Value::Bool(r)) => (l == r).into(),
(Value::Number(l), Value::Number(r)) => (l == r).into(), (Value::Number(l), Value::Number(r)) => (l == r).into(),
(Value::String(l), Value::String(r)) => (l == r).into(), (Value::String(l), Value::String(r)) => (l == r).into(),
_ => panic!("comparing different types"), _ => false.into(),
} }
} }
@ -143,8 +144,5 @@ fn set(args: Vec<Value>) -> Value {
fn get(args: Vec<Value>) -> Value { fn get(args: Vec<Value>) -> Value {
let object = args.get(0).unwrap().as_object().unwrap(); let object = args.get(0).unwrap().as_object().unwrap();
let name = args.get(1).unwrap().as_string().unwrap(); let name = args.get(1).unwrap().as_string().unwrap();
object object.get(name).cloned().unwrap_or_else(|| false.into())
.get(name)
.map(|value| value.clone())
.unwrap_or_else(|| false.into())
} }

View file

@ -24,7 +24,7 @@ impl FrameBuilder {
} }
pub fn variable(&mut self, variable_id: &Id, default: Value) { pub fn variable(&mut self, variable_id: &Id, default: Value) {
self.variables.insert(variable_id.clone(), default); self.variables.insert(*variable_id, default);
} }
} }
@ -52,7 +52,7 @@ impl Frame {
builder(&mut frame_builder); builder(&mut frame_builder);
let FrameBuilder { variables } = frame_builder; let FrameBuilder { variables } = frame_builder;
let scope_id = scope_id.clone(); let scope_id = *scope_id;
Self { Self {
_scope_id: scope_id, _scope_id: scope_id,
variables, variables,
@ -99,6 +99,12 @@ impl Stack {
} }
} }
impl Default for Stack {
fn default() -> Self {
Self::new()
}
}
pub struct ShortCircuit { pub struct ShortCircuit {
value: Value, value: Value,
destination_scope_id: Id, destination_scope_id: Id,
@ -138,9 +144,9 @@ impl ExecReturn {
} }
} }
impl Into<ExecReturn> for Value { impl From<Value> for ExecReturn {
fn into(self) -> ExecReturn { fn from(val: Value) -> Self {
ExecReturn::new_value(self) ExecReturn::new_value(val)
} }
} }
@ -169,7 +175,7 @@ impl Runtime {
where where
F: FnOnce(&mut FrameBuilder), F: FnOnce(&mut FrameBuilder),
{ {
let scope = program.scopes.get(&scope_id).unwrap(); let scope = program.scopes.get(scope_id).unwrap();
let Scope { let Scope {
parent_scope_id: _, parent_scope_id: _,
expressions, expressions,
@ -210,9 +216,7 @@ impl Runtime {
ExprInner::FnDef(function_definition) => { ExprInner::FnDef(function_definition) => {
self.execute_function_definition(function_definition) self.execute_function_definition(function_definition)
} }
ExprInner::FnCall(function_call) => { ExprInner::FnCall(function_call) => self.execute_function_call(function_call, program),
self.execute_function_call(function_call, program).into()
}
ExprInner::FnRet(function_return) => { ExprInner::FnRet(function_return) => {
self.execute_function_return(function_return, program) self.execute_function_return(function_return, program)
} }
@ -272,7 +276,7 @@ impl Runtime {
parameter_ids: argument_ids, parameter_ids: argument_ids,
body_scope_id, body_scope_id,
} = function_definition; } = function_definition;
let value = Function::new_constructed(argument_ids.clone(), body_scope_id.clone()); let value = Function::new_constructed(argument_ids.clone(), *body_scope_id);
let value = Value::Function(value); let value = Value::Function(value);
value.into() value.into()
} }
@ -367,7 +371,7 @@ impl Runtime {
}) => value, }) => value,
}; };
ExecReturn::new_short_circuit(value, function_scope_id.clone()) ExecReturn::new_short_circuit(value, *function_scope_id)
} }
pub fn execute_loop(&mut self, loop_: &Loop, program: &Program) -> ExecReturn { pub fn execute_loop(&mut self, loop_: &Loop, program: &Program) -> ExecReturn {
@ -401,7 +405,7 @@ impl Runtime {
} }
}; };
ExecReturn::new_short_circuit(value, loop_scope_id.clone()) ExecReturn::new_short_circuit(value, *loop_scope_id)
} }
pub fn execute_condition(&mut self, condition: &Cond, program: &Program) -> ExecReturn { pub fn execute_condition(&mut self, condition: &Cond, program: &Program) -> ExecReturn {
@ -432,3 +436,9 @@ impl Runtime {
} }
} }
} }
impl Default for Runtime {
fn default() -> Self {
Self::new()
}
}

View file

@ -52,8 +52,7 @@ pub fn literal_value() -> impl AbstractParser<Value> {
.unwrapped() .unwrapped()
.map(|n: f64| n.into()); .map(|n: f64| n.into());
let literal = bool.or(none).or(string).or(number); bool.or(none).or(string).or(number)
literal
} }
#[test] #[test]
@ -66,11 +65,11 @@ fn test_literal_value() {
pub fn name() -> impl AbstractParser<String> + Clone { pub fn name() -> impl AbstractParser<String> + Clone {
let first = one_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); let first = one_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
let rest = first.clone().or(one_of("1234567890-_+/*")); let rest = first.clone().or(one_of("1234567890-_+/*"));
let name = first.then(rest.repeated()).map(|(f, v)| {
first.then(rest.repeated()).map(|(f, v)| {
let rest = String::from_iter(&v); let rest = String::from_iter(&v);
format!("{f}{rest}") format!("{f}{rest}")
}); })
name
} }
pub fn variable_definition_parser( pub fn variable_definition_parser(
@ -205,7 +204,7 @@ pub fn condition_parser(
just("if ") just("if ")
.ignore_then(expression.clone()) .ignore_then(expression.clone())
.then(expression.clone()) .then(expression.clone())
.then(just("else ").ignore_then(expression.clone()).or_not()) .then(just("else ").ignore_then(expression).or_not())
.map(|((condition, arm_true), arm_false)| Cond { .map(|((condition, arm_true), arm_false)| Cond {
condition, condition,
arm_true, arm_true,
@ -296,7 +295,7 @@ fn _sugar_parser(expression: impl AbstractParser<Expr> + Clone) -> impl Abstract
let and = expression let and = expression
.clone() .clone()
.then_ignore(just(" && ")) .then_ignore(just(" && "))
.then(expression.clone()) .then(expression)
.map(|(l, r)| { .map(|(l, r)| {
FnCall { FnCall {
name: "and".into(), name: "and".into(),
@ -317,7 +316,7 @@ pub fn expression_parser() -> impl AbstractParser<Expr> {
let loop_ = loop_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 loop_break = loop_break_parser(expression.clone()).map(|i| i.into());
let scope = scope_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 litteral = literal_value().map(Expr::new_literal);
let variable_definition = variable_definition_parser(expression.clone()).map(|i| i.into()); 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 variable_assignment = variable_assignement_parser(expression.clone()).map(|i| i.into());
let function_call = function_call_parser(expression.clone()).map(|i| i.into()); let function_call = function_call_parser(expression.clone()).map(|i| i.into());
@ -354,11 +353,11 @@ fn parser() -> impl AbstractParser<Program> {
.separated_by(just(';').padded()) .separated_by(just(';').padded())
.then_ignore(just(';').padded().or_not()) .then_ignore(just(';').padded().or_not())
.then_ignore(end()); .then_ignore(end());
let program = scope.map(|instructions| {
scope.map(|instructions| {
let body = Scope { instructions }; let body = Scope { instructions };
Program { body } Program { body }
}); })
program
} }
#[test] #[test]
@ -390,11 +389,17 @@ impl ParserWrapper {
ParserWrapper { inner } ParserWrapper { inner }
} }
pub fn parse<'i>(&self, input: &'i str) -> Result<Program, Vec<Simple<char>>> { pub fn parse(&self, input: &str) -> Result<Program, Vec<Simple<char>>> {
self.inner.parse(input) self.inner.parse(input)
} }
} }
impl Default for ParserWrapper {
fn default() -> Self {
Self::new()
}
}
/* /*
// example // example

View file

@ -55,9 +55,9 @@ pub mod function {
} }
} }
impl Into<Value> for Function { impl From<Function> for Value {
fn into(self) -> Value { fn from(val: Function) -> Self {
Value::Function(self) Value::Function(val)
} }
} }
} }