Skip to content

Commit

Permalink
refactor: switch to stable toolchain
Browse files Browse the repository at this point in the history
feat: implement scope manipulation features
refactor: make import an expression
test: add tests for scope manipulation
  • Loading branch information
leokostarev committed Jun 13, 2024
1 parent 03b29b1 commit a908ece
Show file tree
Hide file tree
Showing 30 changed files with 593 additions and 481 deletions.
13 changes: 6 additions & 7 deletions obsidian/FIXME.canvas
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
{
"nodes":[
{"id":"813b32f2728a4a94","x":-800,"y":-440,"width":640,"height":820,"type":"group","label":"ordinary"},
{"id":"e6b12e213f195739","x":-1420,"y":-440,"width":520,"height":500,"type":"group","label":"critical"},
{"id":"02fe9a5b84622932","x":-1400,"y":-414,"width":250,"height":79,"type":"text","text":"`fru_clone()` horror"},
{"id":"813b32f2728a4a94","type":"group","x":-800,"y":-440,"width":640,"height":820,"label":"ordinary"},
{"id":"e6b12e213f195739","type":"group","x":-1420,"y":-440,"width":520,"height":500,"label":"critical"},
{"id":"02fe9a5b84622932","type":"text","text":"`fru_clone()` horror","x":-1400,"y":-414,"width":250,"height":79},
{"id":"cd9a0d2eaf046fee","type":"text","text":"implement Display for FruValue and fix for FruObject","x":-740,"y":-409,"width":250,"height":110},
{"id":"2dc5ff956d956862","type":"text","text":"introduce a new error type for \"method/field not found\"","x":-740,"y":-275,"width":250,"height":130},
{"id":"b18a8755b912d870","type":"text","text":"remove or fix BACKWARDS_MAP in Identifier (fails testing with some probability) !! probably already fixed","x":-740,"y":-100,"width":305,"height":170},
{"id":"8b8b22b9de04c759","type":"text","text":"automate wasm module for book","x":-740,"y":120,"width":250,"height":60},
{"id":"4cbdbc839acac840","type":"text","text":"make set expression, not statement","x":-740,"y":240,"width":250,"height":60}
{"id":"b18a8755b912d870","type":"text","text":"remove or fix BACKWARDS_MAP in Identifier (fails testing with some probability) !! probably already fixed","x":-740,"y":-260,"width":305,"height":170},
{"id":"8b8b22b9de04c759","type":"text","text":"automate wasm module for book","x":-740,"y":-60,"width":250,"height":60},
{"id":"4cbdbc839acac840","type":"text","text":"make set expression, not statement","x":-740,"y":40,"width":250,"height":60}
],
"edges":[]
}
27 changes: 18 additions & 9 deletions obsidian/TODO.canvas
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
{
"nodes":[
{"id":"feb6594a9d261a54","type":"text","text":"implement modules and imports","x":340,"y":-20,"width":250,"height":60},
{"id":"4ab66adbfddd4d15","type":"text","text":"implement scope manipulation features","x":-40,"y":-100,"width":250,"height":60},
{"id":"41499d9f6eafdeec","type":"text","text":"add trait polymorphism for native types","x":-480,"y":-50,"width":250,"height":60,"color":"4"},
{"id":"1c18b7117da43e6e","type":"text","text":"implement \"evil\" features","x":-460,"y":-167,"width":250,"height":67,"color":"5"},
{"id":"18df0d00841f02bd","type":"text","text":"add collections\n- [ ] list\n- [ ] set\n- [ ] map\n- [ ] tuple?","x":-60,"y":120,"width":250,"height":182,"color":"3"},
{"id":"550b9c0e5c7cd03a","type":"text","text":"add derivation and implicit derivation, and make them overridable (the main reason is equality of objects)","x":680,"y":249,"width":250,"height":160},
{"id":"b9e932828d9a3c13","type":"text","text":"make cd for windows and linux releases","x":680,"y":140,"width":250,"height":60},
{"id":"5d4e5bd937436926","type":"text","text":"add computed properties","x":-700,"y":140,"width":250,"height":60,"color":"4"}
{"id":"0c274527d795ce38","x":-80,"y":600,"width":400,"height":400,"type":"group","label":"OPTIMIZATIONS"},
{"id":"0e8289b07d6ca556","type":"group","x":-600,"y":600,"width":400,"height":380,"label":"CI/CD"},
{"id":"b9c4b54397d2bf2d","x":-43,"y":666,"width":250,"height":87,"type":"text","text":"macro for computing hash of ident in compile time"},
{"id":"b9e932828d9a3c13","type":"text","text":"make cd for windows and linux releases","x":-580,"y":640,"width":250,"height":50},
{"id":"070a7b543247f7a2","type":"text","text":"simplified syntax for read-only properties","x":-290,"y":360,"width":250,"height":60},
{"id":"5d4e5bd937436926","type":"text","text":"computed properties","x":-640,"y":360,"width":250,"height":60,"color":"4"},
{"id":"18df0d00841f02bd","type":"text","text":"collections\n- [ ] list\n- [ ] set\n- [ ] map\n- [ ] tuple?","x":-80,"y":10,"width":250,"height":182,"color":"3"},
{"id":"97a68fbd25b52ede","x":260,"y":-280,"width":250,"height":60,"type":"text","text":"destructuring let statements"},
{"id":"1c18b7117da43e6e","type":"text","text":"\"evil\" features","x":-460,"y":-180,"width":250,"height":67,"color":"5"},
{"id":"41499d9f6eafdeec","type":"text","text":"trait polymorphism for native types","x":-460,"y":-40,"width":250,"height":60,"color":"4"},
{"id":"4ab66adbfddd4d15","type":"text","text":"scope manipulation features","x":-80,"y":-180,"width":250,"height":60},
{"id":"feb6594a9d261a54","type":"text","text":"modules and imports","x":260,"y":-180,"width":250,"height":60},
{"id":"545169f683d1ebef","x":620,"y":-180,"width":250,"height":60,"type":"text","text":"import as expression"},
{"id":"550b9c0e5c7cd03a","type":"text","text":"derivation and implicit derivation, and make them overridable (the main reason is equality of objects)","x":620,"y":300,"width":250,"height":160}
],
"edges":[
{"id":"4f43eea514ca8881","fromNode":"41499d9f6eafdeec","fromSide":"right","toNode":"4ab66adbfddd4d15","toSide":"left"},
{"id":"94361d23f182cbe8","fromNode":"4ab66adbfddd4d15","fromSide":"right","toNode":"feb6594a9d261a54","toSide":"left"},
{"id":"e3e0be30be175453","fromNode":"1c18b7117da43e6e","fromSide":"right","toNode":"4ab66adbfddd4d15","toSide":"left"},
{"id":"8706d0e0442108f4","fromNode":"41499d9f6eafdeec","fromSide":"right","toNode":"18df0d00841f02bd","toSide":"left"}
{"id":"8706d0e0442108f4","fromNode":"41499d9f6eafdeec","fromSide":"right","toNode":"18df0d00841f02bd","toSide":"left"},
{"id":"10698732105d19f9","fromNode":"5d4e5bd937436926","fromSide":"right","toNode":"070a7b543247f7a2","toSide":"left"},
{"id":"889e945801477a2c","fromNode":"97a68fbd25b52ede","fromSide":"right","toNode":"545169f683d1ebef","toSide":"left"},
{"id":"3f046cb411b32fae","fromNode":"feb6594a9d261a54","fromSide":"right","toNode":"545169f683d1ebef","toSide":"left"}
]
}
2 changes: 0 additions & 2 deletions rust-toolchain.toml

This file was deleted.

67 changes: 38 additions & 29 deletions src/interpreter/builtins/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,44 @@ macro_rules! operator_group {
}

pub fn builtin_operators() -> HashMap<OpId, AnyOperator> {
let mut res = HashMap::from(operator_group!(Id::for_number(), Id::for_number(), [
(for_plus, num_plus_num),
(for_minus, num_minus_num),
(for_multiply, num_mul_num),
(for_divide, num_div_num),
(for_mod, num_mod_num),
(for_pow, num_pow_num),
(for_less, num_less_num),
(for_less_eq, num_less_eq_num),
(for_greater, num_greater_num),
(for_greater_eq, num_greater_eq_num),
(for_eq, num_eq_num),
(for_not_eq, num_not_eq_num)
]));

res.extend(operator_group!(Id::for_bool(), Id::for_bool(), [
(for_and, bool_and_bool),
(for_or, bool_or_bool)
]));

res.extend(operator_group!(Id::for_string(), Id::for_string(), [
(for_combine, string_concat),
(for_less, string_less_string),
(for_less_eq, string_less_eq_string),
(for_greater, string_greater_string),
(for_greater_eq, string_greater_eq_string),
(for_eq, string_eq_string),
(for_not_eq, string_not_eq_string)
]));
let mut res = HashMap::from(operator_group!(
Id::for_number(),
Id::for_number(),
[
(for_plus, num_plus_num),
(for_minus, num_minus_num),
(for_multiply, num_mul_num),
(for_divide, num_div_num),
(for_mod, num_mod_num),
(for_pow, num_pow_num),
(for_less, num_less_num),
(for_less_eq, num_less_eq_num),
(for_greater, num_greater_num),
(for_greater_eq, num_greater_eq_num),
(for_eq, num_eq_num),
(for_not_eq, num_not_eq_num)
]
));

res.extend(operator_group!(
Id::for_bool(),
Id::for_bool(),
[(for_and, bool_and_bool), (for_or, bool_or_bool)]
));

res.extend(operator_group!(
Id::for_string(),
Id::for_string(),
[
(for_combine, string_concat),
(for_less, string_less_string),
(for_less_eq, string_less_eq_string),
(for_greater, string_greater_string),
(for_greater_eq, string_greater_eq_string),
(for_eq, string_eq_string),
(for_not_eq, string_not_eq_string)
]
));

res.extend([
(
Expand Down
94 changes: 69 additions & 25 deletions src/interpreter/expression.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::rc::Rc;
use std::{path::PathBuf, rc::Rc};

use crate::interpreter::{
control::Control,
identifier::{Identifier, OperatorIdentifier},
runner,
scope::Scope,
statement::FruStatement,
value::fru_value::FruValue,
value::function::{ArgumentList, EvaluatedArgumentList, FormalParameters, FruFunction},
};
use crate::stdlib::scope::fru_scope::{extract_scope_from_value, FruScope};

#[derive(Debug, Clone)]
pub enum FruExpression {
Expand All @@ -17,6 +19,7 @@ pub enum FruExpression {
Variable {
ident: Identifier,
},
ScopeAccessor,
Function {
args: FormalParameters,
body: Rc<FruStatement>,
Expand All @@ -25,6 +28,11 @@ pub enum FruExpression {
body: Vec<FruStatement>,
expr: Box<FruExpression>,
},
ScopeModifier {
what: Box<FruExpression>,
body: Vec<FruStatement>,
expr: Box<FruExpression>,
},
Call {
what: Box<FruExpression>,
args: ArgumentList,
Expand All @@ -51,6 +59,9 @@ pub enum FruExpression {
then_body: Box<FruExpression>,
else_body: Box<FruExpression>,
},
Import {
path: Box<FruExpression>,
},
}

fn eval_args(args: &ArgumentList, scope: Rc<Scope>) -> Result<EvaluatedArgumentList, Control> {
Expand All @@ -61,7 +72,7 @@ fn eval_args(args: &ArgumentList, scope: Rc<Scope>) -> Result<EvaluatedArgumentL
.map(|(ident, arg)| -> Result<_, Control> {
Ok((*ident, arg.evaluate(scope.clone())?))
})
.try_collect()?,
.collect::<Result<_, _>>()?,
})
}

Expand All @@ -72,26 +83,42 @@ impl FruExpression {

FruExpression::Variable { ident } => Ok(scope.get_variable(*ident)?),

FruExpression::Function { args, body } => {
Ok(FruFunction {
argument_idents: args.clone(),
body: body.clone(),
scope: scope.clone(),
}
.into())
FruExpression::ScopeAccessor => Ok(FruScope::new_value(scope)),

FruExpression::Function { args, body } => Ok(FruFunction {
argument_idents: args.clone(),
body: body.clone(),
scope: scope.clone(),
}
.into()),

FruExpression::Block { body, expr } => {
if !body.is_empty() {
scope = Scope::new_with_parent(scope.clone())
};
scope = Scope::new_with_parent(scope.clone());

for statement in body {
statement.execute(scope.clone())?;
}

expr.evaluate(scope)
}
FruExpression::ScopeModifier { what, body, expr } => {
let what = what.evaluate(scope)?;
let new_scope = match extract_scope_from_value(&what) {
Some(x) => x,
None => {
return Control::new_err(format!(
"Expected `Scope` in scope modifier expression, got `{}`",
what.get_type_identifier()
))
}
};

for statement in body {
statement.execute(new_scope.clone())?;
}

expr.evaluate(new_scope)
}

FruExpression::Call { what, args } => {
let callee = what.evaluate(scope.clone())?;
Expand Down Expand Up @@ -143,23 +170,40 @@ impl FruExpression {
condition,
then_body,
else_body,
} => {
match condition.evaluate(scope.clone())? {
FruValue::Bool(b) => {
if b {
then_body.evaluate(scope.clone())
} else {
else_body.evaluate(scope.clone())
}
} => match condition.evaluate(scope.clone())? {
FruValue::Bool(b) => {
if b {
then_body.evaluate(scope.clone())
} else {
else_body.evaluate(scope.clone())
}
}

unexpected => Control::new_err(format!(
"Expected `Bool` in if condition, got `{}`",
unexpected.get_type_identifier()
)),
},

FruExpression::Import { path } => {
let path = path.evaluate(scope.clone())?;

unexpected => {
Control::new_err(format!(
"Expected `Bool` in if condition, got `{}`",
unexpected.get_type_identifier()
let path = match path {
FruValue::String(path) => path,

_ => {
return Control::new_err(format!(
"Expected `String` in import path, got `{}`",
path.get_type_identifier()
))
}
}
};

let path = PathBuf::from(path);

let result_scope = runner::execute_file(&path)?;

Ok(FruScope::new_value(result_scope))
}
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/interpreter/identifier.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
use std::{
collections::HashMap,
fmt::Debug,
fmt::Display,
hash::DefaultHasher,
hash::Hash,
hash::Hasher,
collections::HashMap, fmt::Debug, fmt::Display, hash::DefaultHasher, hash::Hash, hash::Hasher,
sync::Mutex,
};

Expand Down
5 changes: 3 additions & 2 deletions src/interpreter/runner.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::{path::Path, rc::Rc};
use std::{fs::read_to_string, path::Path, rc::Rc};

use crate::interpreter::{control::Control, error::FruError, scope::Scope, tree_sitter_parser};

pub fn execute_file(path: &Path) -> Result<Rc<Scope>, FruError> {
let source_code = std::fs::read_to_string(path).unwrap();
let source_code = read_to_string(path)
.map_err(|err| FruError::new(format!("Error reading file {path:?} {err}")))?;

let ast = match tree_sitter_parser::parse(source_code) {
Ok(ast) => ast,
Expand Down
30 changes: 14 additions & 16 deletions src/interpreter/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,10 @@ impl Scope {
Ok(op.clone())
} else {
match &self.parent {
ScopeAncestor::None => {
Err(FruError::new(format!(
"operator `{:?}` does not exist",
ident
)))
}
ScopeAncestor::None => Err(FruError::new(format!(
"operator `{:?}` does not exist",
ident
))),
ScopeAncestor::Parent(parent)
| ScopeAncestor::Object { parent, .. }
| ScopeAncestor::Type { parent, .. } => parent.get_operator(ident),
Expand All @@ -118,6 +116,10 @@ impl Scope {
pub fn has_variable(&self, ident: Identifier) -> bool {
self.variables.borrow().contains_key(&ident)
}

pub fn let_set_variable(&self, ident: Identifier, value: FruValue) {
self.variables.borrow_mut().insert(ident, value);
}
}

impl ScopeAncestor {
Expand All @@ -144,17 +146,13 @@ impl ScopeAncestor {

ScopeAncestor::Parent(parent) => parent.set_variable(ident, value),

ScopeAncestor::Object { object, parent } => {
object
.set_prop(ident, value.clone())
.or_else(|_| parent.set_variable(ident, value))
}
ScopeAncestor::Object { object, parent } => object
.set_prop(ident, value.clone())
.or_else(|_| parent.set_variable(ident, value)),

ScopeAncestor::Type { type_, parent } => {
type_
.set_prop(ident, value.clone())
.or_else(|_| parent.set_variable(ident, value))
}
ScopeAncestor::Type { type_, parent } => type_
.set_prop(ident, value.clone())
.or_else(|_| parent.set_variable(ident, value)),
}
}
}
Loading

0 comments on commit a908ece

Please sign in to comment.