Initial commit
This commit is contained in:
commit
70f1f90cc7
12 changed files with 1455 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -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"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -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]
|
27
README.md
Normal file
27
README.md
Normal file
|
@ -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 <matthieu@imagevo.fr>, developper
|
155
src/execution_tree/mod.rs
Normal file
155
src/execution_tree/mod.rs
Normal file
|
@ -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<Id, Scope>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<ExprInner>);
|
||||||
|
|
||||||
|
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<Id>,
|
||||||
|
pub local_variables: Vec<Id>,
|
||||||
|
pub expressions: Vec<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<Id>,
|
||||||
|
pub body_scope_id: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FnCall {
|
||||||
|
pub variable_id: Id,
|
||||||
|
pub arguments: Vec<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod parser;
|
447
src/execution_tree/parser.rs
Normal file
447
src/execution_tree/parser.rs
Normal file
|
@ -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<Id, execution_tree::Scope>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub fn parse<F>(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<Rc<Mutex<ParserScopeVariables>>>,
|
||||||
|
local_variables: HashMap<String, Id>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParserScopeVariables {
|
||||||
|
pub fn get_id(&self, name: &str) -> Option<Id> {
|
||||||
|
self.get_id_in_local(name)
|
||||||
|
.or_else(|| self.get_id_in_parents(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_id_in_local(&self, name: &str) -> Option<Id> {
|
||||||
|
self.local_variables.get(name).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_id_in_parents(&self, name: &str) -> Option<Id> {
|
||||||
|
self.parent_scope
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|parent| parent.lock().unwrap().get_id(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_variable_ids(&self) -> Vec<Id> {
|
||||||
|
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<Mutex<ParserScopeVariables>>,
|
||||||
|
next_global_id: Rc<Mutex<Id>>,
|
||||||
|
current_id: Id,
|
||||||
|
parent_id: Option<Id>,
|
||||||
|
current_function_scope_id: Option<Id>,
|
||||||
|
current_loop_scope_id: Option<Id>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Id> {
|
||||||
|
self.current_function_scope_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_loop_id(&self) -> Option<Id> {
|
||||||
|
self.current_loop_scope_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parent_id(&self) -> Option<Id> {
|
||||||
|
self.parent_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_variable_id(&self, name: &str) -> Option<Id> {
|
||||||
|
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<Id> {
|
||||||
|
self.variables.lock().unwrap().local_variable_ids()
|
||||||
|
}
|
||||||
|
}
|
39
src/main.rs
Normal file
39
src/main.rs
Normal file
|
@ -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);
|
||||||
|
}
|
14
src/prelude.rs
Normal file
14
src/prelude.rs
Normal file
|
@ -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>) -> Value {
|
||||||
|
let to_print = args.get(0).unwrap();
|
||||||
|
println!("{to_print:?}");
|
||||||
|
Value::Bool(true)
|
||||||
|
}
|
434
src/runtime.rs
Normal file
434
src/runtime.rs
Normal file
|
@ -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<Id, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Id, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
/// Puts all variable of that scope in the new frame
|
||||||
|
pub fn new<F>(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<Frame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Value> {
|
||||||
|
if let Self::Value(value) = self {
|
||||||
|
Some(value)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_shortcircuit(self) -> Option<ShortCircuit> {
|
||||||
|
if let Self::ShortCircuit(short_circuit) = self {
|
||||||
|
Some(short_circuit)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<ExecReturn> 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<F>(
|
||||||
|
&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<Value>,
|
||||||
|
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<Value>,
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
src/sequencing.rs
Normal file
43
src/sequencing.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{abstract_tree::Id, value::Value};
|
||||||
|
|
||||||
|
pub struct Program {
|
||||||
|
statements: Vec<Statement>,
|
||||||
|
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<Id, Vec<Value>>,
|
||||||
|
next_instruction_index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
pub fn run(&self, state: &mut State) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod parser {
|
||||||
|
pub struct Parser;
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub fn parse() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
166
src/syntax_tree.rs
Normal file
166
src/syntax_tree.rs
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Program {
|
||||||
|
pub body: Scope,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Expr(pub Box<ExprInner>);
|
||||||
|
|
||||||
|
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<Expr>) -> Self {
|
||||||
|
Self(Box::new(ExprInner::Scope(Scope { instructions })))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_literal<V: Into<Value>>(value: V) -> Self {
|
||||||
|
Self(Box::new(ExprInner::Literal(Literal(value.into()))))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_variable_definition<S: ToString>(name: S, value: Expr) -> Self {
|
||||||
|
let name = name.to_string();
|
||||||
|
Self(Box::new(ExprInner::VarDef(VarDef { name, value })))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_variable_assignment<S: ToString>(name: S, value: Expr) -> Self {
|
||||||
|
let name = name.to_string();
|
||||||
|
Self(Box::new(ExprInner::VarAssign(VarAssign { name, value })))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_variable_call<S: ToString>(name: S) -> Self {
|
||||||
|
let name = name.to_string();
|
||||||
|
Self(Box::new(ExprInner::VarCall(VarCall { name })))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_function_definition<S: ToString>(parameter_names: Vec<S>, 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<S: ToString>(name: S, arguments: Vec<Expr>) -> 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<Expr>) -> Self {
|
||||||
|
Self(Box::new(ExprInner::Cond(Cond {
|
||||||
|
condition,
|
||||||
|
arm_true,
|
||||||
|
arm_false,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Expr
|
||||||
|
where
|
||||||
|
T: Into<Value>,
|
||||||
|
{
|
||||||
|
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<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn new(instructions: Vec<Expr>) -> 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<String>,
|
||||||
|
pub body: Scope,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FnCall {
|
||||||
|
pub name: String,
|
||||||
|
pub arguments: Vec<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<Expr>,
|
||||||
|
}
|
114
src/value.rs
Normal file
114
src/value.rs
Normal file
|
@ -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<Id>,
|
||||||
|
pub body_scope_id: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct NativeFunctionExecutor {
|
||||||
|
pub closure: fn(Vec<Value>) -> 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<Id>, 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>) -> Value) -> Self {
|
||||||
|
let executor = FunctionExecutor::Native(NativeFunctionExecutor { closure });
|
||||||
|
Self {
|
||||||
|
argument_count,
|
||||||
|
executor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn executor(&self) -> &FunctionExecutor {
|
||||||
|
&self.executor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Value> for Function {
|
||||||
|
fn into(self) -> Value {
|
||||||
|
Value::Function(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Value {
|
||||||
|
None,
|
||||||
|
Bool(bool),
|
||||||
|
Number(f64),
|
||||||
|
String(String),
|
||||||
|
Object(HashMap<String, Value>),
|
||||||
|
Function(Function),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn as_function(&self) -> Option<&Function> {
|
||||||
|
match self {
|
||||||
|
Self::Function(function) => Some(function),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for Value {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
Self::Bool(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for Value {
|
||||||
|
fn from(value: f64) -> Self {
|
||||||
|
Self::Number(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> 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<T> From<Option<T>> for Value
|
||||||
|
where
|
||||||
|
T: Into<Value>,
|
||||||
|
{
|
||||||
|
fn from(value: Option<T>) -> Self {
|
||||||
|
value.map_or(Value::None, |v| v.into())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue