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