various fixes
This commit is contained in:
parent
c08c263f32
commit
28377bd3c2
11 changed files with 149 additions and 87 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -28,9 +28,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.13"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4"
|
||||
checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
"proc-macro-hack",
|
||||
|
@ -38,12 +38,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.13"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40"
|
||||
checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
"proc-macro-hack",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
@ -65,12 +65,6 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
|
@ -78,18 +72,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "prout"
|
||||
version = "0.3.0"
|
||||
name = "porte"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"chumsky",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
[package]
|
||||
name = "prout"
|
||||
version = "0.3.0"
|
||||
name = "porte"
|
||||
version = "0.4.0"
|
||||
edition = "2021"
|
||||
authors = ["JOLIMAITRE Matthieu <matthieu@imagevo.fr>"]
|
||||
description = "A minimal programming language providing tools to automate file management like backups, building process or unit testing."
|
||||
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
|
||||
|
||||
|
|
10
README.md
10
README.md
|
@ -1,15 +1,15 @@
|
|||
|
||||
# PROUT
|
||||
# PORTE
|
||||
|
||||
* Programmable
|
||||
* Repeatable
|
||||
* Opinionated
|
||||
* Understandable
|
||||
* Repeatable
|
||||
* Tiny
|
||||
* Extensible
|
||||
|
||||
## 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
|
||||
|
||||
|
@ -17,7 +17,7 @@ PROUT is a minimal programming language providing tools to automate file managem
|
|||
|
||||
```sh
|
||||
|
||||
$ prout hello-world.pr
|
||||
$ porte hello-world.pr
|
||||
|
||||
|
||||
```
|
||||
|
|
|
@ -22,6 +22,13 @@ array_get: (self, 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) => {
|
||||
i: array_len(self);
|
||||
self <- set(self, str(i), e);
|
||||
|
@ -39,30 +46,72 @@ array_pop: (self) => {
|
|||
e: array_get(self, i);
|
||||
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 <- set(r, "tail", e);
|
||||
r <- set(r, "rest", self);
|
||||
r <- set(r, "rest", rest);
|
||||
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) => {
|
||||
l: array_len(self);
|
||||
r: "[ ";
|
||||
for(0, l, (i) => {
|
||||
r <- add(r, array_get(self, i));
|
||||
r <- add(r, ", ")
|
||||
if not(eq(i, sub(l, 1))) r <- add(r, ", ")
|
||||
});
|
||||
r <- add(r, " ]");
|
||||
out(r)
|
||||
};
|
||||
|
||||
main: () => {
|
||||
a: array_new();
|
||||
a <- array_push(a, 1);
|
||||
a <- array_push(a, 2);
|
||||
a <- array_push(a, 3);
|
||||
a <- array_push(a, 4);
|
||||
array_print(a)
|
||||
};
|
||||
"########################";
|
||||
"# main #";
|
||||
"########################";
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
hello: "hello";
|
||||
prout: "prout";
|
||||
porte: "porte";
|
||||
|
||||
line: hello;
|
||||
line <- add(line, " ");
|
||||
line <- add(line, prout);
|
||||
line <- add(line, porte);
|
||||
|
||||
say-it: () => {
|
||||
out(line)
|
||||
|
|
|
@ -73,7 +73,7 @@ impl Parser {
|
|||
let parent_scope_id = parser_scope.get_parent_id();
|
||||
let expressions = instructions
|
||||
.into_iter()
|
||||
.map(|expression| self.parse_expression(expression, &parser_scope))
|
||||
.map(|expression| self.parse_expression(expression, parser_scope))
|
||||
.collect();
|
||||
let local_variables = parser_scope.local_variable_ids();
|
||||
|
||||
|
@ -218,7 +218,7 @@ impl Parser {
|
|||
|
||||
let variable_id = parser_scope
|
||||
.get_variable_id(&name)
|
||||
.expect(&format!("call of undeclared function '{name}'"));
|
||||
.unwrap_or_else(|| panic!("call of undeclared function '{name}'"));
|
||||
let parameters = arguments
|
||||
.into_iter()
|
||||
.map(|argument| self.parse_expression(argument, parser_scope))
|
||||
|
@ -390,7 +390,7 @@ impl ParserScope {
|
|||
next_id: self.next_id.clone(),
|
||||
variables: Rc::new(Mutex::new(variables)),
|
||||
current_id,
|
||||
current_function_scope_id: Some(current_id.clone()),
|
||||
current_function_scope_id: Some(current_id),
|
||||
current_loop_scope_id: None,
|
||||
}
|
||||
}
|
||||
|
@ -409,24 +409,24 @@ impl ParserScope {
|
|||
variables: Rc::new(Mutex::new(variables)),
|
||||
current_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 {
|
||||
self.current_id.clone()
|
||||
self.current_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> {
|
||||
self.current_loop_scope_id.clone()
|
||||
self.current_loop_scope_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> {
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -1,20 +1,20 @@
|
|||
use std::{env::args, fs};
|
||||
|
||||
pub mod demo;
|
||||
pub mod execution_tree;
|
||||
pub mod prelude;
|
||||
pub mod runtime;
|
||||
pub mod syntax_tree;
|
||||
pub mod value;
|
||||
pub mod demo;
|
||||
|
||||
fn main() {
|
||||
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 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 executable = execution_tree::parser::Parser::parse(parsed, std_prelude);
|
||||
let mut runtime = runtime::Runtime::new();
|
||||
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")]),
|
||||
]),
|
||||
};
|
||||
let exec = Parser::parse(ast, |builder| std_prelude(builder));
|
||||
let exec = Parser::parse(ast, std_prelude);
|
||||
println!("\n\n\n-- running: --");
|
||||
let _result = Runtime::new().execute(&exec);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@ use crate::{
|
|||
};
|
||||
|
||||
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),
|
||||
("add", 2, add),
|
||||
("sub", 2, sub),
|
||||
|
@ -42,7 +43,7 @@ fn add(args: Vec<Value>) -> Value {
|
|||
(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!(),
|
||||
_ => panic!("adding incompatible types"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +63,7 @@ fn eq(args: Vec<Value>) -> Value {
|
|||
(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"),
|
||||
_ => false.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,8 +144,5 @@ fn set(args: Vec<Value>) -> 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())
|
||||
object.get(name).cloned().unwrap_or_else(|| false.into())
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ impl FrameBuilder {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
let FrameBuilder { variables } = frame_builder;
|
||||
let scope_id = scope_id.clone();
|
||||
let scope_id = *scope_id;
|
||||
Self {
|
||||
_scope_id: scope_id,
|
||||
variables,
|
||||
|
@ -99,6 +99,12 @@ impl Stack {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for Stack {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShortCircuit {
|
||||
value: Value,
|
||||
destination_scope_id: Id,
|
||||
|
@ -138,9 +144,9 @@ impl ExecReturn {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<ExecReturn> for Value {
|
||||
fn into(self) -> ExecReturn {
|
||||
ExecReturn::new_value(self)
|
||||
impl From<Value> for ExecReturn {
|
||||
fn from(val: Value) -> Self {
|
||||
ExecReturn::new_value(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +175,7 @@ impl Runtime {
|
|||
where
|
||||
F: FnOnce(&mut FrameBuilder),
|
||||
{
|
||||
let scope = program.scopes.get(&scope_id).unwrap();
|
||||
let scope = program.scopes.get(scope_id).unwrap();
|
||||
let Scope {
|
||||
parent_scope_id: _,
|
||||
expressions,
|
||||
|
@ -210,9 +216,7 @@ impl Runtime {
|
|||
ExprInner::FnDef(function_definition) => {
|
||||
self.execute_function_definition(function_definition)
|
||||
}
|
||||
ExprInner::FnCall(function_call) => {
|
||||
self.execute_function_call(function_call, program).into()
|
||||
}
|
||||
ExprInner::FnCall(function_call) => self.execute_function_call(function_call, program),
|
||||
ExprInner::FnRet(function_return) => {
|
||||
self.execute_function_return(function_return, program)
|
||||
}
|
||||
|
@ -272,7 +276,7 @@ impl Runtime {
|
|||
parameter_ids: argument_ids,
|
||||
body_scope_id,
|
||||
} = 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);
|
||||
value.into()
|
||||
}
|
||||
|
@ -367,7 +371,7 @@ impl Runtime {
|
|||
}) => 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 {
|
||||
|
@ -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 {
|
||||
|
@ -432,3 +436,9 @@ impl Runtime {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Runtime {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,8 +52,7 @@ pub fn literal_value() -> impl AbstractParser<Value> {
|
|||
.unwrapped()
|
||||
.map(|n: f64| n.into());
|
||||
|
||||
let literal = bool.or(none).or(string).or(number);
|
||||
literal
|
||||
bool.or(none).or(string).or(number)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -66,11 +65,11 @@ fn test_literal_value() {
|
|||
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)| {
|
||||
|
||||
first.then(rest.repeated()).map(|(f, v)| {
|
||||
let rest = String::from_iter(&v);
|
||||
format!("{f}{rest}")
|
||||
});
|
||||
name
|
||||
})
|
||||
}
|
||||
|
||||
pub fn variable_definition_parser(
|
||||
|
@ -205,7 +204,7 @@ pub fn condition_parser(
|
|||
just("if ")
|
||||
.ignore_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 {
|
||||
condition,
|
||||
arm_true,
|
||||
|
@ -296,7 +295,7 @@ fn _sugar_parser(expression: impl AbstractParser<Expr> + Clone) -> impl Abstract
|
|||
let and = expression
|
||||
.clone()
|
||||
.then_ignore(just(" && "))
|
||||
.then(expression.clone())
|
||||
.then(expression)
|
||||
.map(|(l, r)| {
|
||||
FnCall {
|
||||
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_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 litteral = literal_value().map(Expr::new_literal);
|
||||
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());
|
||||
|
@ -354,11 +353,11 @@ fn parser() -> impl AbstractParser<Program> {
|
|||
.separated_by(just(';').padded())
|
||||
.then_ignore(just(';').padded().or_not())
|
||||
.then_ignore(end());
|
||||
let program = scope.map(|instructions| {
|
||||
|
||||
scope.map(|instructions| {
|
||||
let body = Scope { instructions };
|
||||
Program { body }
|
||||
});
|
||||
program
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -390,11 +389,17 @@ impl ParserWrapper {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ParserWrapper {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// example
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ pub mod function {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<Value> for Function {
|
||||
fn into(self) -> Value {
|
||||
Value::Function(self)
|
||||
impl From<Function> for Value {
|
||||
fn from(val: Function) -> Self {
|
||||
Value::Function(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue