Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Computed propeties #7

Merged
merged 8 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ serde_json = "1.0.115"
snailquote = "0.3.1"
thiserror = "1.0.58"
tree-sitter = "0.22.5"
tree-sitter-frugurt = "0.0.9"
tree-sitter-frugurt = "0.0.10"
#tree-sitter-frugurt = { path = "../tree-sitter-frugurt" }
#uid = "0.1.7"

Expand All @@ -22,3 +22,8 @@ tempfile = "3.10.1"

[build-dependencies]
cc = "*"

[[test]]
name = "integration"
harness = true
path = "tests/lib.rs"
21 changes: 0 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ Also, there are three flavors of types:
- `class` - mutable, passed by reference
- `data` - immutable, passed by reference

There is also builtin data validation, using "watches",
see [docs](https://frugurt-lang.github.io/frugurt/03-object-oriented-programming/06-watches.html).

```frugurt
struct Vector {
x;
Expand All @@ -54,24 +51,6 @@ struct Vector {
// there are static fields too (see docs)
Vector:{x + other.x, y + other.y }
}
} constraints {
watch (x) {
if x < -1000 {
x = -1000;
}
if x > 1000 {
x = 1000;
}
}

watch (y) {
if y < -1000 {
y = -1000;
}
if y > 1000 {
y = 1000;
}
}
}

// you can define operator with any name you want!
Expand Down
3 changes: 0 additions & 3 deletions docs/highlighter/highlighter-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ window.highlighterInfo = {
"return" @keyword
"struct" @keyword
"static" @keyword
"watch" @keyword
"while" @keyword
"constraints" @keyword
"impl" @keyword


(number_literal) @number
(string_literal) @string
(bool_literal) @bool
Expand Down
1 change: 0 additions & 1 deletion docs/highlighter/highlighter.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ window.TreeSitter.init().then(async () => {
}
});


/** @param {string} str
@param {{from: number, to: number, color: string}[]} ranges */
function colorString(str, ranges) {
Expand Down
Binary file modified docs/highlighter/tree-sitter-frugurt.wasm
Binary file not shown.
3 changes: 0 additions & 3 deletions docs/src/02-common-concepts/04-control-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

The control flow in Frugurt can be implemented using both statements and expressions.



## Conditionals

### using statements
Expand All @@ -19,7 +17,6 @@ if age < 12 {
}
```


### using expressions
```frugurt
let age = 16;
Expand Down
2 changes: 1 addition & 1 deletion docs/src/02-common-concepts/05-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ print(f(5, 10)); // 15
print(f(y: 10, x: 5)); // 15
```

Named parameters can be computed using positional ones and other named parameters, that go before them.
Named parameters can be computed using positional ones and other named parameters that go before them.

```frugurt
let f = fn (x, y=x + 5, z=x + y + 5) {
Expand Down
48 changes: 48 additions & 0 deletions docs/src/03-object-oriented-programming/06-properties.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Properties

Properties are type members that externally look like fields, but internally behave like methods.

```frugurt
struct Vec {
x;
y;

Length {
get => (x * x + y * y) ** 0.5;
set(new_length) {
let k = new_length / Length;
x = x * k;
y = y * k;
}
}
}

let v = Vec :{ x: 3, y: 4 };
print(v.Length); // 5

v.Length = 1;

print(v); // Vec { x: 0.6, y: 0.8 }
```

In this example, Vec has a "property" Length, that is freely computable from other fields.
Like methods, properties can access fields, methods and other properties of the object.
`(new_length)` can be omitted, in which case the default identifier `value` is used.
Properties can be static.
Also, there is no need to implement `get` and `set` every time.

```frugurt
class Time {
static time = 0;

pub static Now {
get { time } // this is equivalent to `get => time;`
}
}

print(Time.Now);
```

In this example, imagine game engine.
Static field time is updated by game engine every frame, and public property `Now` can be used to obtain current time
on the user side.
37 changes: 0 additions & 37 deletions docs/src/03-object-oriented-programming/06-watches.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
- [Operators](./03-object-oriented-programming/03-operators.md)
- [Methods](./03-object-oriented-programming/04-methods.md)
- [Statics](./03-object-oriented-programming/05-statics.md)
- [Watches](./03-object-oriented-programming/06-watches.md)
- [Properties](./03-object-oriented-programming/06-properties.md)
5 changes: 5 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
imports_layout = "HorizontalVertical"
force_multiline_blocks = true
overflow_delimited_expr = true
struct_variant_width = 0
chain_width = 80
37 changes: 15 additions & 22 deletions src/interpreter/builtins/functions.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,30 @@
//FIXME: all of this mess
// FIXME: all of this mess

use std::{collections::HashMap, io, io::Write};

use crate::interpreter::{
error::FruError,
identifier::Identifier,
value::fru_value::FruValue,
value::fru_value::{FruValue, TFnBuiltin},
value::function::{AnyFunction, BuiltinFunction, EvaluatedArgumentList},
};

pub fn builtin_functions() -> HashMap<Identifier, FruValue> {
HashMap::from(
[
("print", b_print as TFnBuiltin),
("input", b_input as TFnBuiltin),
("assert_eq", b_assert_eq as TFnBuiltin),
]
.map(|(ident, function)| {
(
Identifier::new("print"),
FruValue::Function(AnyFunction::BuiltinFunction(BuiltinFunction {
function: b_print,
})),
),
(
Identifier::new("input"),
FruValue::Function(AnyFunction::BuiltinFunction(BuiltinFunction {
function: b_input,
})),
),
(
Identifier::new("assert_eq"),
FruValue::Function(AnyFunction::BuiltinFunction(BuiltinFunction {
function: b_assert_eq,
})),
),
] // TODO: rewrite with map
Identifier::new(ident),
FruValue::Function(AnyFunction::BuiltinFunction(BuiltinFunction::new(function))),
)
}),
)
}


fn b_print(args: EvaluatedArgumentList) -> Result<FruValue, FruError> {
for arg in args.args {
print!("{:?} ", arg.1);
Expand All @@ -59,6 +49,9 @@ fn b_assert_eq(args: EvaluatedArgumentList) -> Result<FruValue, FruError> {
if args.args[0].1 == args.args[1].1 {
Ok(FruValue::Bool(true))
} else {
FruError::new_val(format!("assertion failed: {:?} != {:?}", args.args[0].1, args.args[1].1))
FruError::new_res(format!(
"assertion failed: {:?} != {:?}",
args.args[0].1, args.args[1].1
))
}
}
75 changes: 33 additions & 42 deletions src/interpreter/builtins/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,44 +33,35 @@ 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 All @@ -93,7 +84,7 @@ builtin_operator!(num_mul_num, Number, Number, Number, *);
fn num_div_num(left: FruValue, right: FruValue) -> Result<FruValue, FruError> {
if let (FruValue::Number(l), FruValue::Number(r)) = (left, right) {
if r == 0.0 {
return FruError::new_val_slice("division by zero");
return FruError::new_res("division by zero");
}
return Ok(FruValue::Number(l / r));
}
Expand All @@ -104,7 +95,7 @@ fn num_div_num(left: FruValue, right: FruValue) -> Result<FruValue, FruError> {
fn num_mod_num(left: FruValue, right: FruValue) -> Result<FruValue, FruError> {
if let (FruValue::Number(l), FruValue::Number(r)) = (left, right) {
if r == 0.0 {
return FruError::new_val_slice("division by zero");
return FruError::new_res("division by zero");
}
return Ok(FruValue::Number(l.rem_euclid(r)));
}
Expand All @@ -130,7 +121,7 @@ builtin_operator!(num_not_eq_num, Number, Number, Bool, !=);
builtin_operator!(bool_or_bool, Bool, Bool, Bool, ||);
builtin_operator!(bool_and_bool, Bool, Bool, Bool, &&);

//string
// string
builtin_operator!(string_less_string, String, String, Bool, <);
builtin_operator!(string_less_eq_string, String, String, Bool, <=);
builtin_operator!(string_greater_string, String, String, Bool, >);
Expand All @@ -148,7 +139,7 @@ fn string_concat(left: FruValue, right: FruValue) -> Result<FruValue, FruError>
fn string_mul_num(left: FruValue, right: FruValue) -> Result<FruValue, FruError> {
if let (FruValue::String(l), FruValue::Number(r)) = (left, right) {
if r.fract() != 0.0 || r < 0.0 {
return FruError::new_val_slice("String * number must be a positive integer");
return FruError::new_res("String * number must be a positive integer");
}

return Ok(FruValue::String(l.repeat(r as usize)));
Expand Down
Loading
Loading