From 70f1f90cc737b36d63b6627f45a68fa5a63c239c Mon Sep 17 00:00:00 2001 From: JOLIMAITRE Matthieu Date: Wed, 25 May 2022 08:09:48 +0300 Subject: [PATCH] Initial commit --- .gitignore | 1 + Cargo.lock | 7 + Cargo.toml | 8 + README.md | 27 +++ src/execution_tree/mod.rs | 155 ++++++++++++ src/execution_tree/parser.rs | 447 +++++++++++++++++++++++++++++++++++ src/main.rs | 39 +++ src/prelude.rs | 14 ++ src/runtime.rs | 434 ++++++++++++++++++++++++++++++++++ src/sequencing.rs | 43 ++++ src/syntax_tree.rs | 166 +++++++++++++ src/value.rs | 114 +++++++++ 12 files changed, 1455 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/execution_tree/mod.rs create mode 100644 src/execution_tree/parser.rs create mode 100644 src/main.rs create mode 100644 src/prelude.rs create mode 100644 src/runtime.rs create mode 100644 src/sequencing.rs create mode 100644 src/syntax_tree.rs create mode 100644 src/value.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1018079 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "prout" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b345a3d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "prout" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..2ee8839 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ + +# PROUT + +* Programmable +* Repeatable +* Opinionated +* Understandable +* Tiny + +## Description + +PROUT is a minimal programming language providing tools to automate file management like backups, building process or unit testing. + +## Usage + +> Currently only supported in unix environment. + +```sh + +$ prout hello_world.pr + + +``` + +## Author + +- JOLIMAITRE Matthieu , developper diff --git a/src/execution_tree/mod.rs b/src/execution_tree/mod.rs new file mode 100644 index 0000000..476a85a --- /dev/null +++ b/src/execution_tree/mod.rs @@ -0,0 +1,155 @@ +use std::collections::HashMap; + +use crate::value::Value; + +#[derive(Debug)] +pub struct Program { + pub main_scope_id: Id, + pub scopes: HashMap, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Id(u64); // u64::MAX = 18_446_744_073_709_551_615 +impl Id { + pub fn zero() -> Self { + Self(0) + } + pub fn next(self) -> Self { + let Self(id) = self; + Self(id + 1) + } +} + +#[derive(Debug)] +pub struct Expr(Box); + +impl Expr { + pub fn inner(&self) -> &ExprInner { + &self.0 + } + + pub fn new_scope(scope_id: Id) -> Self { + Self(Box::new(ExprInner::Scope(scope_id))) + } + + pub fn new_literal(literal: Literal) -> Self { + Self(Box::new(ExprInner::Literal(literal))) + } + + pub fn new_variable_definition(variable_definition: VarDef) -> Self { + Self(Box::new(ExprInner::VarDef(variable_definition))) + } + + pub fn new_variable_assignment(variable_assignment: VarAssign) -> Self { + Self(Box::new(ExprInner::VarAssign(variable_assignment))) + } + + pub fn new_variable_call(variable_call: VarCall) -> Self { + Self(Box::new(ExprInner::VarCall(variable_call))) + } + + pub fn new_function_definition(function_definition: FnDef) -> Self { + Self(Box::new(ExprInner::FnDef(function_definition))) + } + + pub fn new_function_call(function_call: FnCall) -> Self { + Self(Box::new(ExprInner::FnCall(function_call))) + } + + pub fn new_function_return(function_return: FnRet) -> Self { + Self(Box::new(ExprInner::FnRet(function_return))) + } + + pub fn new_loop(loop_: Loop) -> Self { + Self(Box::new(ExprInner::Loop(loop_))) + } + + pub fn new_loop_break(loop_break: LoopBr) -> Self { + Self(Box::new(ExprInner::LoopBr(loop_break))) + } + + pub fn new_condition(condition: Cond) -> Self { + Self(Box::new(ExprInner::Cond(condition))) + } +} + +#[derive(Debug)] +pub enum ExprInner { + Scope(Id), + Literal(Literal), + VarDef(VarDef), + VarAssign(VarAssign), + VarCall(VarCall), + FnDef(FnDef), + FnCall(FnCall), + FnRet(FnRet), + Loop(Loop), + LoopBr(LoopBr), + Cond(Cond), +} + +#[derive(Debug)] +pub struct Scope { + pub scope_id: Id, + pub parent_scope_id: Option, + pub local_variables: Vec, + pub expressions: Vec, +} + +#[derive(Debug)] +pub struct Literal(pub Value); + +#[derive(Debug)] +pub struct VarDef { + pub variable_id: Id, + pub value: Expr, +} + +#[derive(Debug)] +pub struct VarAssign { + pub variable_id: Id, + pub value: Expr, +} + +#[derive(Debug)] +pub struct VarCall { + pub variable_id: Id, +} + +#[derive(Debug)] +pub struct FnDef { + pub parameter_ids: Vec, + pub body_scope_id: Id, +} + +#[derive(Debug)] +pub struct FnCall { + pub variable_id: Id, + pub arguments: Vec, +} + +#[derive(Debug)] +pub struct FnRet { + pub value: Expr, + pub function_scope_id: Id, +} + +#[derive(Debug)] +pub struct Loop { + pub body_scope_id: Id, +} + +#[derive(Debug)] +pub struct LoopBr { + pub value: Expr, + pub loop_scope_id: Id, +} + +#[derive(Debug)] +pub struct Cond { + pub condition: Expr, + pub arm_true: Expr, + pub arm_false: Option, +} + +pub mod parser; diff --git a/src/execution_tree/parser.rs b/src/execution_tree/parser.rs new file mode 100644 index 0000000..cf0c394 --- /dev/null +++ b/src/execution_tree/parser.rs @@ -0,0 +1,447 @@ +use std::{collections::HashMap, rc::Rc, sync::Mutex}; + +use crate::{ + execution_tree::{self, Id}, + syntax_tree, + value::Value, +}; + +pub struct ParserBuilder { + prelude: Vec<(String, Value)>, +} + +impl ParserBuilder { + fn new() -> Self { + let prelude = Vec::new(); + Self { prelude } + } + + pub fn prelude(&mut self, name: String, value: Value) { + self.prelude.push((name, value)); + } +} + +pub struct Parser { + scopes: HashMap, +} + +impl Parser { + pub fn parse(ast: syntax_tree::Program, builder: F) -> execution_tree::Program + where + F: FnOnce(&mut ParserBuilder), + { + let syntax_tree::Program { mut body } = ast; + + let mut parser = Self { + scopes: HashMap::new(), + }; + let parser_scope = ParserScope::new_root(); + let mut parser_builder = ParserBuilder::new(); + builder(&mut parser_builder); + for (name, value) in parser_builder.prelude.into_iter().rev() { + let value = syntax_tree::Expr::new_literal(value); + let expression = syntax_tree::Expr::new_variable_definition(name, value); + body.instructions.insert(0, expression); + } + + let body_scope_id = parser.parse_ast_scope(body, &parser_scope); + + let Self { scopes } = parser; + execution_tree::Program { + main_scope_id: body_scope_id, + scopes, + } + } + + pub fn parse_ast_scope( + &mut self, + ast_scope: syntax_tree::Scope, + parser_scope: &ParserScope, + ) -> execution_tree::Id { + let syntax_tree::Scope { instructions } = ast_scope; + + let scope_id = parser_scope.get_current_id(); + let parent_scope_id = parser_scope.get_parent_id(); + let expressions = instructions + .into_iter() + .map(|expression| self.parse_expression(expression, &parser_scope)) + .collect(); + let local_variables = parser_scope.local_variable_ids(); + + let scope = execution_tree::Scope { + parent_scope_id, + scope_id, + expressions, + local_variables, + }; + self.scopes.insert(scope_id, scope); + scope_id + } + + pub fn parse_expression( + &mut self, + expression: syntax_tree::Expr, + parser_scope: &ParserScope, + ) -> execution_tree::Expr { + let inner = expression.into_inner(); + match inner { + syntax_tree::ExprInner::Scope(scope) => { + let parser_scope = parser_scope.make_child_common(); + let scope = self.parse_ast_scope(scope, &parser_scope); + execution_tree::Expr::new_scope(scope) + } + syntax_tree::ExprInner::Literal(literal) => { + let literal = self.parse_literal(literal); + execution_tree::Expr::new_literal(literal) + } + syntax_tree::ExprInner::VarDef(variable_definition) => { + let variable_definition = + self.parse_variable_definition(variable_definition, parser_scope); + execution_tree::Expr::new_variable_definition(variable_definition) + } + syntax_tree::ExprInner::VarAssign(variable_assignment) => { + let variable_assignment = + self.parse_variable_assignment(variable_assignment, parser_scope); + execution_tree::Expr::new_variable_assignment(variable_assignment) + } + syntax_tree::ExprInner::VarCall(variable_call) => { + let variable_call = self.parse_variable_call(variable_call, parser_scope); + execution_tree::Expr::new_variable_call(variable_call) + } + syntax_tree::ExprInner::FnDef(function_definition) => { + let function_definition = + self.parse_function_definition(function_definition, parser_scope); + execution_tree::Expr::new_function_definition(function_definition) + } + syntax_tree::ExprInner::FnCall(function_call) => { + let function_call = self.parse_function_call(function_call, parser_scope); + execution_tree::Expr::new_function_call(function_call) + } + syntax_tree::ExprInner::FnRet(function_return) => { + let function_return = self.parse_function_return(function_return, parser_scope); + execution_tree::Expr::new_function_return(function_return) + } + syntax_tree::ExprInner::Loop(loop_) => { + let loop_ = self.parse_loop(loop_, parser_scope); + execution_tree::Expr::new_loop(loop_) + } + syntax_tree::ExprInner::LoopBr(loop_break) => { + let loop_break = self.parse_loop_break(loop_break, parser_scope); + execution_tree::Expr::new_loop_break(loop_break) + } + syntax_tree::ExprInner::Cond(condition) => { + let condition = self.parse_condition(condition, parser_scope); + execution_tree::Expr::new_condition(condition) + } + } + } + + pub fn parse_literal(&mut self, literal: syntax_tree::Literal) -> execution_tree::Literal { + let syntax_tree::Literal(value) = literal; + execution_tree::Literal(value) + } + + pub fn parse_variable_definition( + &mut self, + variable_definition: syntax_tree::VarDef, + parser_scope: &ParserScope, + ) -> execution_tree::VarDef { + let syntax_tree::VarDef { name, value } = variable_definition; + let value = self.parse_expression(value, parser_scope); + let variable_id = parser_scope.add_name(name); + execution_tree::VarDef { value, variable_id } + } + + pub fn parse_variable_assignment( + &mut self, + variable_assignment: syntax_tree::VarAssign, + parser_scope: &ParserScope, + ) -> execution_tree::VarAssign { + let syntax_tree::VarAssign { name, value } = variable_assignment; + let value = self.parse_expression(value, parser_scope); + let variable_id = parser_scope + .get_variable_id(&name) + .expect("assignment to undefined variable"); + execution_tree::VarAssign { value, variable_id } + } + + pub fn parse_variable_call( + &mut self, + variable_call: syntax_tree::VarCall, + parser_scope: &ParserScope, + ) -> execution_tree::VarCall { + let syntax_tree::VarCall { name } = variable_call; + let variable_id = parser_scope + .get_variable_id(&name) + .expect("call of undefined variable"); + execution_tree::VarCall { variable_id } + } + + pub fn parse_function_definition( + &mut self, + function_definition: syntax_tree::FnDef, + parser_scope: &ParserScope, + ) -> execution_tree::FnDef { + let syntax_tree::FnDef { + body, + parameter_names, + } = function_definition; + + let parser_scope = parser_scope.make_child_common(); + let parameter_ids = parameter_names + .into_iter() + .map(|name| parser_scope.add_name(name)) + .collect(); + let body_scope_id = self.parse_ast_scope(body, &parser_scope); + + execution_tree::FnDef { + body_scope_id, + parameter_ids, + } + } + + pub fn parse_function_call( + &mut self, + function_call: syntax_tree::FnCall, + parser_scope: &ParserScope, + ) -> execution_tree::FnCall { + let syntax_tree::FnCall { name, arguments } = function_call; + + let variable_id = parser_scope + .get_variable_id(&name) + .expect("call of undeclared function"); + let parameters = arguments + .into_iter() + .map(|argument| self.parse_expression(argument, parser_scope)) + .collect(); + + execution_tree::FnCall { + arguments: parameters, + variable_id, + } + } + + pub fn parse_function_return( + &mut self, + function_return: syntax_tree::FnRet, + parser_scope: &ParserScope, + ) -> execution_tree::FnRet { + let syntax_tree::FnRet { value } = function_return; + + let value = self.parse_expression(value, parser_scope); + let function_scope_id = parser_scope + .get_current_function_id() + .expect("returning outside a function"); + + execution_tree::FnRet { + value, + function_scope_id, + } + } + + pub fn parse_loop( + &mut self, + loop_: syntax_tree::Loop, + parser_scope: &ParserScope, + ) -> execution_tree::Loop { + let syntax_tree::Loop { body } = loop_; + + let parser_scope = parser_scope.make_child_loop(); + let body_scope_id = self.parse_ast_scope(body, &parser_scope); + + execution_tree::Loop { body_scope_id } + } + + pub fn parse_loop_break( + &mut self, + loop_break: syntax_tree::LoopBr, + parser_scope: &ParserScope, + ) -> execution_tree::LoopBr { + let syntax_tree::LoopBr { value } = loop_break; + + let value = self.parse_expression(value, parser_scope); + let loop_scope_id = parser_scope + .get_current_loop_id() + .expect("breaking outside a loop"); + + execution_tree::LoopBr { + value, + loop_scope_id, + } + } + + pub fn parse_condition( + &mut self, + condition: syntax_tree::Cond, + parser_scope: &ParserScope, + ) -> execution_tree::Cond { + let syntax_tree::Cond { + condition, + arm_true, + arm_false, + } = condition; + + let condition = self.parse_expression(condition, parser_scope); + let arm_true = self.parse_expression(arm_true, parser_scope); + let arm_false = arm_false.map(|arm_false| self.parse_expression(arm_false, parser_scope)); + + execution_tree::Cond { + condition, + arm_true, + arm_false, + } + } +} + +#[derive(Debug, Clone)] +struct ParserScopeVariables { + parent_scope: Option>>, + local_variables: HashMap, +} + +impl ParserScopeVariables { + pub fn get_id(&self, name: &str) -> Option { + self.get_id_in_local(name) + .or_else(|| self.get_id_in_parents(name)) + } + + fn get_id_in_local(&self, name: &str) -> Option { + self.local_variables.get(name).cloned() + } + + fn get_id_in_parents(&self, name: &str) -> Option { + self.parent_scope + .as_ref() + .and_then(|parent| parent.lock().unwrap().get_id(name)) + } + + fn local_variable_ids(&self) -> Vec { + self.local_variables.values().cloned().collect() + } + + fn add_name(&mut self, name: String, id: Id) { + let _dropped = self.local_variables.insert(name, id); + } +} + +/// Clonable, shareable. +#[derive(Debug, Clone)] +pub struct ParserScope { + variables: Rc>, + next_global_id: Rc>, + current_id: Id, + parent_id: Option, + current_function_scope_id: Option, + current_loop_scope_id: Option, +} + +impl ParserScope { + pub fn new_root() -> Self { + let current_id = Id::zero(); + let next_global_id = current_id.next(); + let variables = ParserScopeVariables { + local_variables: HashMap::new(), + parent_scope: None, + }; + Self { + parent_id: None, + current_id, + next_global_id: Rc::new(Mutex::new(next_global_id)), + variables: Rc::new(Mutex::new(variables)), + current_function_scope_id: None, + current_loop_scope_id: None, + } + } + + pub fn make_child_common(&self) -> Self { + let variables = ParserScopeVariables { + local_variables: HashMap::new(), + parent_scope: Some(self.variables.clone()), + }; + Self { + parent_id: Some(self.get_current_id()), + next_global_id: self.next_global_id.clone(), + variables: Rc::new(Mutex::new(variables)), + current_id: self.request_new_id(), + current_function_scope_id: self.get_current_function_id(), + current_loop_scope_id: self.get_current_loop_id(), + } + } + + pub fn make_child_function(&self) -> Self { + let variables = ParserScopeVariables { + local_variables: HashMap::new(), + parent_scope: Some(self.variables.clone()), + }; + + let current_id = self.request_new_id(); + + Self { + parent_id: Some(self.get_current_id()), + next_global_id: self.next_global_id.clone(), + variables: Rc::new(Mutex::new(variables)), + current_id, + current_function_scope_id: Some(current_id.clone()), + current_loop_scope_id: None, + } + } + + pub fn make_child_loop(&self) -> Self { + let variables = ParserScopeVariables { + local_variables: HashMap::new(), + parent_scope: Some(self.variables.clone()), + }; + + let current_id = self.request_new_id(); + + Self { + parent_id: Some(self.get_current_id()), + next_global_id: self.next_global_id.clone(), + 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()), + } + } + + pub fn get_current_id(&self) -> Id { + self.current_id.clone() + } + + pub fn get_current_function_id(&self) -> Option { + self.current_function_scope_id.clone() + } + + pub fn get_current_loop_id(&self) -> Option { + self.current_loop_scope_id.clone() + } + + pub fn get_parent_id(&self) -> Option { + self.parent_id.clone() + } + + pub fn get_variable_id(&self, name: &str) -> Option { + self.variables.lock().unwrap().get_id(name) + } + + fn request_new_id(&self) -> Id { + let mut next_id_ref = self.next_global_id.lock().unwrap(); + let id = *next_id_ref; + *next_id_ref = id.next(); + id + } + + pub fn add_name(&self, name: String) -> Id { + let new_id = self.request_new_id(); + self.variables.lock().unwrap().add_name(name, new_id); + new_id + } + + pub fn add_anonymous(&self) -> Id { + self.request_new_id() + } + + pub fn local_variable_ids(&self) -> Vec { + self.variables.lock().unwrap().local_variable_ids() + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..38b3733 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,39 @@ +pub mod execution_tree; +pub mod prelude; +pub mod runtime; +pub mod syntax_tree; +pub mod value; + +fn main() { + println!("Hello, world!"); +} + +#[test] +fn it_works() { + use crate::execution_tree::parser::Parser; + use crate::prelude::std_prelude; + use crate::runtime::Runtime; + use crate::syntax_tree::*; + + let ast = Program { + body: Scope::new(vec![ + Expr::new_variable_definition("a", Expr::new_literal(3.0)), + Expr::new_variable_assignment("a", Expr::new_literal(6.0)), + Expr::new_variable_definition( + "my_print", + Expr::new_function_definition( + vec!["to_print"], + Scope::new(vec![ + Expr::new_variable_definition("a", Expr::new_variable_call("to_print")), + Expr::new_function_call("print", vec![Expr::new_variable_call("a")]), + ]), + ), + ), + Expr::new_function_call("my_print", vec!["hello, PROUT".into()]), + Expr::new_function_call("print", vec![Expr::new_variable_call("a")]), + ]), + }; + let exec = Parser::parse(ast, |builder| std_prelude(builder)); + println!("\n\n\n-- running: --"); + let _result = Runtime::new().execute(&exec); +} diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..ac3d6bd --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,14 @@ +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()) +} + +fn print(args: Vec) -> Value { + let to_print = args.get(0).unwrap(); + println!("{to_print:?}"); + Value::Bool(true) +} diff --git a/src/runtime.rs b/src/runtime.rs new file mode 100644 index 0000000..a3bbcbd --- /dev/null +++ b/src/runtime.rs @@ -0,0 +1,434 @@ +use std::collections::HashMap; + +use crate::{ + execution_tree::{ + Cond, Expr, ExprInner, FnCall, FnDef, FnRet, Id, Literal, Loop, LoopBr, Program, Scope, + VarAssign, VarCall, VarDef, + }, + value::{ + function::{ + ConstructedFunctionExecutor, Function, FunctionExecutor, NativeFunctionExecutor, + }, + Value, + }, +}; + +pub struct FrameBuilder { + variables: HashMap, +} + +impl FrameBuilder { + fn new() -> Self { + let variables = HashMap::new(); + Self { variables } + } + + pub fn variable(&mut self, variable_id: &Id, default: Value) { + self.variables.insert(variable_id.clone(), default); + } +} + +pub struct Frame { + scope_id: Id, + variables: HashMap, +} + +impl Frame { + /// Puts all variable of that scope in the new frame + pub fn new(scope: &Scope, builder: F) -> Self + where + F: FnOnce(&mut FrameBuilder), + { + let Scope { + scope_id, + local_variables, + .. + } = scope; + + let mut frame_builder = FrameBuilder::new(); + for variable in local_variables { + frame_builder.variable(variable, Value::None); + } + builder(&mut frame_builder); + + let FrameBuilder { variables } = frame_builder; + let scope_id = scope_id.clone(); + Self { + scope_id, + variables, + } + } +} + +pub struct Stack { + frames: Vec, +} + +impl Stack { + pub fn new() -> Self { + let frames = Vec::new(); + Self { frames } + } + + pub fn push_frame(&mut self, frame: Frame) { + self.frames.push(frame); + } + + pub fn pop_frame(&mut self) { + let _dropped = self.frames.pop(); + } + + pub fn get(&self, variable_id: &Id) -> Option<&Value> { + self.frames.iter().rev().find_map(|frame| { + frame + .variables + .iter() + .find(|(id, _value)| **id == *variable_id) + .map(|(_id, value)| value) + }) + } + + pub fn get_mut(&mut self, variable_id: &Id) -> Option<&mut Value> { + self.frames.iter_mut().rev().find_map(|frame| { + frame + .variables + .iter_mut() + .find(|(id, _value)| **id == *variable_id) + .map(|(_id, value)| value) + }) + } +} + +pub struct ShortCircuit { + value: Value, + destination_scope_id: Id, +} + +pub enum ExecReturn { + Value(Value), + ShortCircuit(ShortCircuit), +} + +impl ExecReturn { + pub fn new_value(value: Value) -> Self { + Self::Value(value) + } + + pub fn new_short_circuit(value: Value, destination_scope_id: Id) -> Self { + Self::ShortCircuit(ShortCircuit { + destination_scope_id, + value, + }) + } + + pub fn into_value(self) -> Option { + if let Self::Value(value) = self { + Some(value) + } else { + None + } + } + + pub fn into_shortcircuit(self) -> Option { + if let Self::ShortCircuit(short_circuit) = self { + Some(short_circuit) + } else { + None + } + } +} + +impl Into for Value { + fn into(self) -> ExecReturn { + ExecReturn::new_value(self) + } +} + +pub struct Runtime { + stack: Stack, +} + +impl Runtime { + pub fn new() -> Self { + let stack = Stack::new(); + Self { stack } + } + + pub fn execute(&mut self, program: &Program) -> Value { + self.execute_scope(&program.main_scope_id, program, |_| ()) + .into_value() + .unwrap() + } + + pub fn execute_scope( + &mut self, + scope_id: &Id, + program: &Program, + frame_builder: F, + ) -> ExecReturn + where + F: FnOnce(&mut FrameBuilder), + { + let scope = program.scopes.get(&scope_id).unwrap(); + let Scope { + parent_scope_id: _, + expressions, + .. + } = scope; + let frame = Frame::new(scope, |builder| frame_builder(builder)); + self.stack.push_frame(frame); + + let mut last_expression = Value::None; + for expression in expressions { + let returned = self.execute_expression(expression, program); + match returned { + ExecReturn::ShortCircuit(short_circuit) => { + self.stack.pop_frame(); + return ExecReturn::ShortCircuit(short_circuit); + } + ExecReturn::Value(value) => { + last_expression = value; + } + } + } + + self.stack.pop_frame(); + last_expression.into() + } + + pub fn execute_expression(&mut self, expression: &Expr, program: &Program) -> ExecReturn { + match expression.inner() { + ExprInner::Scope(scope_id) => self.execute_scope(scope_id, program, |_| ()), + ExprInner::Literal(literal) => self.execute_literal(literal), + ExprInner::VarDef(variable_definition) => { + self.execute_variable_definition(variable_definition, program) + } + ExprInner::VarAssign(variable_assignment) => { + self.execute_variable_assignment(variable_assignment, program) + } + ExprInner::VarCall(variable_call) => self.execute_variable_call(variable_call), + ExprInner::FnDef(function_definition) => { + self.execute_function_definition(function_definition) + } + ExprInner::FnCall(function_call) => { + self.execute_function_call(function_call, program).into() + } + ExprInner::FnRet(function_return) => { + self.execute_function_return(function_return, program) + } + ExprInner::Loop(loop_) => self.execute_loop(loop_, program), + ExprInner::LoopBr(loop_break) => self.execute_loop_break(loop_break, program), + ExprInner::Cond(condition) => self.execute_condition(condition, program), + } + } + + pub fn execute_literal(&self, literal: &Literal) -> ExecReturn { + let Literal(value) = literal; + ExecReturn::new_value(value.clone()) + } + + pub fn execute_variable_definition( + &mut self, + variable_definition: &VarDef, + program: &Program, + ) -> ExecReturn { + let VarDef { variable_id, value } = variable_definition; + let value = match self.execute_expression(value, program) { + ExecReturn::ShortCircuit(short_circuit) => { + return ExecReturn::ShortCircuit(short_circuit); + } + ExecReturn::Value(value) => value, + }; + let variable = self.stack.get_mut(variable_id).unwrap(); + *variable = value.clone(); + value.into() + } + + pub fn execute_variable_assignment( + &mut self, + variable_assignment: &VarAssign, + program: &Program, + ) -> ExecReturn { + let VarAssign { variable_id, value } = variable_assignment; + let value = match self.execute_expression(value, program) { + ExecReturn::Value(value) => value, + ExecReturn::ShortCircuit(short_circuit) => { + return ExecReturn::ShortCircuit(short_circuit); + } + }; + let variable = self.stack.get_mut(variable_id).unwrap(); + *variable = value.clone(); + value.into() + } + + pub fn execute_variable_call(&mut self, variable_call: &VarCall) -> ExecReturn { + let VarCall { variable_id } = variable_call; + let variable = self.stack.get(variable_id).unwrap(); + variable.clone().into() + } + + pub fn execute_function_definition(&mut self, function_definition: &FnDef) -> ExecReturn { + let FnDef { + parameter_ids: argument_ids, + body_scope_id, + } = function_definition; + let value = Function::new_constructed(argument_ids.clone(), body_scope_id.clone()); + let value = Value::Function(value); + value.into() + } + + pub fn execute_function_call( + &mut self, + function_call: &FnCall, + program: &Program, + ) -> ExecReturn { + let FnCall { + variable_id, + arguments, + } = function_call; + + let mut collector = Vec::new(); + for argument in arguments { + match self.execute_expression(argument, program) { + ExecReturn::Value(value) => collector.push(value), + ExecReturn::ShortCircuit(short_circuit) => { + return ExecReturn::ShortCircuit(short_circuit) + } + } + } + let arguments = collector; + + let function = self + .stack + .get(variable_id) + .unwrap() + .as_function() + .expect("calling a non-function variable") + .clone(); + match function.executor() { + FunctionExecutor::Constructed(executor) => self + .execute_constructed_function(arguments, executor, program) + .into(), + FunctionExecutor::Native(executor) => { + self.execute_native_function(arguments, executor).into() + } + } + } + + pub fn execute_constructed_function( + &mut self, + arguments: Vec, + executor: &ConstructedFunctionExecutor, + program: &Program, + ) -> Value { + let ConstructedFunctionExecutor { + parameter_ids, + body_scope_id, + } = executor; + + let returned = self.execute_scope(body_scope_id, program, |builder| { + for (id, argument) in parameter_ids.iter().zip(arguments.into_iter()) { + builder.variable(id, argument) + } + }); + + match returned { + ExecReturn::Value(value) => value, + ExecReturn::ShortCircuit(ShortCircuit { + value, + destination_scope_id: _, + }) => value, + } + } + + pub fn execute_native_function( + &mut self, + arguments: Vec, + executor: &NativeFunctionExecutor, + ) -> Value { + (executor.closure)(arguments) + } + + pub fn execute_function_return( + &mut self, + function_return: &FnRet, + program: &Program, + ) -> ExecReturn { + let FnRet { + value, + function_scope_id, + } = function_return; + + let value = match self.execute_expression(value, program) { + ExecReturn::Value(value) => value, + ExecReturn::ShortCircuit(ShortCircuit { + value, + destination_scope_id: _, + }) => value, + }; + + ExecReturn::new_short_circuit(value, function_scope_id.clone()) + } + + pub fn execute_loop(&mut self, loop_: &Loop, program: &Program) -> ExecReturn { + let Loop { body_scope_id } = loop_; + + loop { + let value = self.execute_scope(body_scope_id, program, |_| ()); + match value { + ExecReturn::ShortCircuit(ShortCircuit { + value, + destination_scope_id, + }) if destination_scope_id == *body_scope_id => return value.into(), + ExecReturn::ShortCircuit(short_circuit) => { + return ExecReturn::ShortCircuit(short_circuit) + } + _ => (), + } + } + } + + pub fn execute_loop_break(&mut self, loop_break: &LoopBr, program: &Program) -> ExecReturn { + let LoopBr { + value, + loop_scope_id, + } = loop_break; + + let value = match self.execute_expression(value, program) { + ExecReturn::Value(value) => value, + ExecReturn::ShortCircuit(short_circuit) => { + return ExecReturn::ShortCircuit(short_circuit) + } + }; + + ExecReturn::new_short_circuit(value, loop_scope_id.clone()) + } + + pub fn execute_condition(&mut self, condition: &Cond, program: &Program) -> ExecReturn { + let Cond { + condition, + arm_true, + arm_false, + } = condition; + + let value = match self.execute_expression(condition, program) { + ExecReturn::Value(value) => value, + ExecReturn::ShortCircuit(short_circuit) => { + return ExecReturn::ShortCircuit(short_circuit) + } + }; + + if let Value::Bool(boolean) = value { + if boolean { + self.execute_expression(arm_true, program) + } else { + arm_false + .as_ref() + .map(|arm_false| self.execute_expression(arm_false, program)) + .unwrap_or(Value::Bool(false).into()) + } + } else { + panic!("non-boolean in condition"); + } + } +} diff --git a/src/sequencing.rs b/src/sequencing.rs new file mode 100644 index 0000000..f460911 --- /dev/null +++ b/src/sequencing.rs @@ -0,0 +1,43 @@ +/* + +use std::collections::HashMap; + +use crate::{abstract_tree::Id, value::Value}; + +pub struct Program { + statements: Vec, + state: State, +} + +pub enum Statement { + Label(Label), + VarAssign(VarAssign), + FnCall(FnCall), + Branch(Branch), +} + +pub struct VarAssign { + variable: +} + +pub struct FnCall {} + +pub struct State { + variables: HashMap>, + next_instruction_index: usize, +} + +impl Statement { + pub fn run(&self, state: &mut State) {} +} + +pub mod parser { + pub struct Parser; + + impl Parser { + pub fn parse() { + // + } + } +} + */ diff --git a/src/syntax_tree.rs b/src/syntax_tree.rs new file mode 100644 index 0000000..d81bbb5 --- /dev/null +++ b/src/syntax_tree.rs @@ -0,0 +1,166 @@ +use crate::value::Value; + +#[derive(Debug)] +pub struct Program { + pub body: Scope, +} + +#[derive(Debug)] +pub struct Expr(pub Box); + +impl Expr { + pub fn inner(&self) -> &ExprInner { + let Self(inner) = self; + inner + } + + pub fn into_inner(self) -> ExprInner { + let Self(inner) = self; + *inner + } + + pub fn new_scope(instructions: Vec) -> Self { + Self(Box::new(ExprInner::Scope(Scope { instructions }))) + } + + pub fn new_literal>(value: V) -> Self { + Self(Box::new(ExprInner::Literal(Literal(value.into())))) + } + + pub fn new_variable_definition(name: S, value: Expr) -> Self { + let name = name.to_string(); + Self(Box::new(ExprInner::VarDef(VarDef { name, value }))) + } + + pub fn new_variable_assignment(name: S, value: Expr) -> Self { + let name = name.to_string(); + Self(Box::new(ExprInner::VarAssign(VarAssign { name, value }))) + } + + pub fn new_variable_call(name: S) -> Self { + let name = name.to_string(); + Self(Box::new(ExprInner::VarCall(VarCall { name }))) + } + + pub fn new_function_definition(parameter_names: Vec, body: Scope) -> Self { + let parameter_names = parameter_names.into_iter().map(|s| s.to_string()).collect(); + Self(Box::new(ExprInner::FnDef(FnDef { + body, + parameter_names, + }))) + } + + pub fn new_function_call(name: S, arguments: Vec) -> Self { + let name = name.to_string(); + Self(Box::new(ExprInner::FnCall(FnCall { name, arguments }))) + } + + pub fn new_function_return(value: Expr) -> Self { + Self(Box::new(ExprInner::FnRet(FnRet { value }))) + } + + pub fn new_loop(body: Scope) -> Self { + Self(Box::new(ExprInner::Loop(Loop { body }))) + } + + pub fn new_loop_break(value: Expr) -> Self { + Self(Box::new(ExprInner::LoopBr(LoopBr { value }))) + } + + pub fn new_condition(condition: Expr, arm_true: Expr, arm_false: Option) -> Self { + Self(Box::new(ExprInner::Cond(Cond { + condition, + arm_true, + arm_false, + }))) + } +} + +impl From for Expr +where + T: Into, +{ + fn from(input: T) -> Self { + Self::new_literal(input.into()) + } +} + +#[derive(Debug)] +pub enum ExprInner { + Scope(Scope), + Literal(Literal), + VarDef(VarDef), + VarAssign(VarAssign), + VarCall(VarCall), + FnDef(FnDef), + FnCall(FnCall), + FnRet(FnRet), + Loop(Loop), + LoopBr(LoopBr), + Cond(Cond), +} + +#[derive(Debug)] +pub struct Scope { + pub instructions: Vec, +} + +impl Scope { + pub fn new(instructions: Vec) -> Self { + Self { instructions } + } +} + +#[derive(Debug)] +pub struct Literal(pub Value); + +#[derive(Debug)] +pub struct VarDef { + pub name: String, + pub value: Expr, +} + +#[derive(Debug)] +pub struct VarAssign { + pub name: String, + pub value: Expr, +} + +#[derive(Debug)] +pub struct VarCall { + pub name: String, +} + +#[derive(Debug)] +pub struct FnDef { + pub parameter_names: Vec, + pub body: Scope, +} + +#[derive(Debug)] +pub struct FnCall { + pub name: String, + pub arguments: Vec, +} + +#[derive(Debug)] +pub struct FnRet { + pub value: Expr, +} + +#[derive(Debug)] +pub struct Loop { + pub body: Scope, +} + +#[derive(Debug)] +pub struct LoopBr { + pub value: Expr, +} + +#[derive(Debug)] +pub struct Cond { + pub condition: Expr, + pub arm_true: Expr, + pub arm_false: Option, +} diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..2a82608 --- /dev/null +++ b/src/value.rs @@ -0,0 +1,114 @@ +use std::collections::HashMap; + +use self::function::Function; +pub mod function { + use crate::execution_tree::{Expr, Id}; + + use super::Value; + + #[derive(Debug, Clone)] + pub struct ConstructedFunctionExecutor { + pub parameter_ids: Vec, + pub body_scope_id: Id, + } + + #[derive(Debug, Clone)] + pub struct NativeFunctionExecutor { + pub closure: fn(Vec) -> Value, + } + + #[derive(Debug, Clone)] + pub enum FunctionExecutor { + Constructed(ConstructedFunctionExecutor), + Native(NativeFunctionExecutor), + } + + #[derive(Debug, Clone)] + pub struct Function { + pub argument_count: usize, + pub executor: FunctionExecutor, + } + + impl Function { + pub fn new_constructed(argument_ids: Vec, body_scope_id: Id) -> Self { + let argument_count = argument_ids.len(); + let executor = FunctionExecutor::Constructed(ConstructedFunctionExecutor { + parameter_ids: argument_ids, + body_scope_id, + }); + Self { + argument_count, + executor, + } + } + + pub fn new_native(argument_count: usize, closure: fn(Vec) -> Value) -> Self { + let executor = FunctionExecutor::Native(NativeFunctionExecutor { closure }); + Self { + argument_count, + executor, + } + } + + pub fn executor(&self) -> &FunctionExecutor { + &self.executor + } + } + + impl Into for Function { + fn into(self) -> Value { + Value::Function(self) + } + } +} +#[derive(Debug, Clone)] +pub enum Value { + None, + Bool(bool), + Number(f64), + String(String), + Object(HashMap), + Function(Function), +} + +impl Value { + pub fn as_function(&self) -> Option<&Function> { + match self { + Self::Function(function) => Some(function), + _ => None, + } + } +} + +impl From for Value { + fn from(value: bool) -> Self { + Self::Bool(value) + } +} + +impl From for Value { + fn from(value: f64) -> Self { + Self::Number(value) + } +} + +impl From for Value { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl From<&str> for Value { + fn from(value: &str) -> Self { + value.to_string().into() + } +} + +impl From> for Value +where + T: Into, +{ + fn from(value: Option) -> Self { + value.map_or(Value::None, |v| v.into()) + } +}