Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
anyhow = "1.0.69"
lazy_static = "1.4.0"
once_cell = "1.17.1"
pest = "2.5.6"
pest_consume = "1.1.3"
pest_derive = "2.5.6"
Expand Down
119 changes: 117 additions & 2 deletions src/bytecode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,75 @@ See `constexpr`.

---

### `make_object`
Create an object by grouping all of the variables local to a scope; they are stored under the name of a function.

Objects can:
* be passed to functions
* be mutated (type safety checked at runtime)
* have methods associated to them

For example, the following code:

```
person = obj(name, age)
.grow_up()
age += 1

me = person("Mateo", 16)
me.grow_up()
```

Will compile into:

```
function person$grow_up
load_object age
int 1
bin_op +
store_object age

void
ret
end

function person
arg 0
store name
arg 1
store age

make_object

ret
end

function main
string "Mateo"
int 16
call path/to/file.mmm#person
store me

load_local me
call_object path/to/file.mmm#person$grow_up

void
ret
end
```

---

### `make_vector ! [[capacity]?]`
If capacity is present, will initialize a blank vector with a specified capacity.
Otherwise, will consume the local operating stack and copy its contents to a new vector.

| ! | Reason |
| - | - |
| 1 | [capacity] is not a usize. |

---

### `make_function ! [path_to_function, [callback_variable, ...]?]`
Make a function "pointer", from a path. The path is not checked until a user calls this pointer.

Expand Down Expand Up @@ -295,12 +364,26 @@ If the interpreter accepts the request, and calling the function returns a value

---

### `call_object ! [path] (>=1)`
Sends a request to call a method on an object, given a path.

Acts just like `call`, except that the first item on the local operating stack must be an Object. This parameter is not passed as an argument, but the calling function will have access to its fields and other methods.

| ! | Reason |
| - | - |
| 1 | Argument length == 0. |
| 2 | First item on the local is not an Object. |
| 3 | [path] does not match one of object's methods. |
| 4 | (_Indirect_) If the request to jump is accepted and the path is malformed. |

---

### `stack_size`
Will return the depth of the call stack, ie. how many function calls can be traced to the current executing instruction. The result of this operation gets pushed on to the end of the local stack.

---

### `store ! [name]`
### `store ! [name] (==1)`
Stores a variable to the current stack frame. Child frames will have access to its value.

| ! | Reason |
Expand All @@ -309,6 +392,28 @@ Stores a variable to the current stack frame. Child frames will have access to i

---

### `store_object ! [name] (==1)`
Stores a variable to an object. The variable must have already been mapped, and the type of the item in the stack must equal the type of the previous object field. This is the way to mutate an object from within a function. For external modification, use the `mutate` instruction.

| ! | Reason |
| - | - |
| 1 | Argument length != 1. |
| 2 | Field does not exist on object |
| 3 | Type mismatch |

---

### `mutate ! [name] (==2)`
Update an object's fields. The first item in the stack must be the object, and the second the updated value.

| ! | Reason |
| - | - |
| 1 | Argument length != 2. |
| 2 | Field [name] does not exist on the object |
| 3 | Type mismatch |w

---

### `load ! [name]`
Loads a variable from the current stack frame. If not found, will trickle the search upwards.

Expand All @@ -335,7 +440,17 @@ Loads a variable from the frozen callback pool. If not found, the program will e

| ! | Reason |
| - | - |
| 2 | The variable hasn't been stored in the callback pool. |
| 1 | The variable hasn't been stored in the data pool. |

---

### `load_object ! [name]`

Equivalent to `load_callback`. This was introduced to make it clearer when you're dealing with objects.

| ! | Reason |
| - | - |
| 1 | The variable hasn't been stored in the data pool. |

---

Expand Down
59 changes: 16 additions & 43 deletions src/bytecode/bin/test.mmm
Original file line number Diff line number Diff line change
@@ -1,63 +1,36 @@
function add_n$0
arg 0
store x

load_callback number
load_local x

function person$grow_up
load_object age
int 1
bin_op +
store_object age

void
ret
end

function add_n
function person
arg 0
store number
store name
arg 1
store age

make_function src/bytecode/bin/test.mmm#add_n$0 number
make_object

ret
end

function main
bool false
if
int 50
call src/bytecode/bin/test.mmm#add_n
store add_fifty
string "Mateo"
int 16
call src/bytecode/bin/test.mmm#person

int 75
load add_fifty
call
store me

load_local me
printn *

void
endif

call src/bytecode/bin/test.mmm#test_vecs

void
ret
end

function test_vecs
int 5
int 0
string "Hello, World!"
float 3.14159
constexpr 0b101
make_vector

call_object src/bytecode/bin/test.mmm#person$grow_up
printn *

int 10
vec_op mut 0

printn *

stack_dump

void
ret
end
11 changes: 7 additions & 4 deletions src/bytecode/bin/test.ms
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
add_n = fn(number)
result = fn(x)
return number + x
return result
person = obj(name, age)
.grow_up()
age += 1

me = person("mateo", 16)

me.grow_up()
39 changes: 28 additions & 11 deletions src/bytecode/context.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use std::{cell::Cell, fmt::Debug, sync::Arc, collections::VecDeque};

use super::attributes_parser::Attributes;
use super::file::IfStatement;
use super::function::{Function, InstructionExitState};
use super::stack::VariableMapping;
use super::variables::{Primitive, Variable};
use super::Stack;
use anyhow::{bail, Result};

use super::{
attributes_parser::Attributes,
file::IfStatement,
function::{Function, InstructionExitState},
stack::VariableMapping,
variables::{Primitive, Variable},
Stack,
};
use std::cell::Cell;
use std::collections::VecDeque;
use std::fmt::Debug;
use std::sync::Arc;

pub struct Ctx<'a> {
stack: VecDeque<Primitive>,
Expand Down Expand Up @@ -45,6 +44,20 @@ impl<'a> Ctx<'a> {
}
}

pub fn update_callback_variable(&mut self, name: String, value: Variable) -> Result<()> {
let Some(ref mapping) = self.callback_state else {
bail!("this function is not a callback")
};

let mapping = Arc::as_ptr(mapping) as *mut VariableMapping;

unsafe {
(*mapping).update(name, value)?;
}

Ok(())
}

pub fn load_callback_variable(&self, name: &String) -> Result<Option<&Variable>> {
let Some(ref mapping) = self.callback_state else {
bail!("this function is not a callback")
Expand Down Expand Up @@ -152,6 +165,10 @@ impl<'a> Ctx<'a> {
unsafe { (*self.call_stack.as_ptr()).find_name(name) }
}

pub(crate) fn get_frame_variables(&self) -> &VariableMapping {
unsafe { (*self.call_stack.as_ptr()).get_frame_variables() }
}

pub(crate) fn load_local(&self, name: &String) -> Option<&Variable> {
unsafe { (*self.call_stack.as_ptr()).get_frame_variables().get(name) }
}
Expand Down
8 changes: 8 additions & 0 deletions src/bytecode/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ impl MScriptFile {
functions.if_mapper.get(&if_pos).map(|x| x.clone())
}

pub fn get_object_functions<'a, 'b: 'a>(&'a mut self, name: &'b String) -> Result<impl Iterator<Item = &Function> + 'a> {
let Some(ref mut functions) = self.functions else {
bail!("no functions")
};

Ok(functions.get_object_functions(name))
}

fn get_functions(arc_of_self: &Arc<RefCell<Self>>) -> Result<Functions> {
println!("Functions in {}", arc_of_self.borrow().path);

Expand Down
14 changes: 13 additions & 1 deletion src/bytecode/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub struct Function {
line_number: u32,
pub(crate) seek_pos: u64,
pub(crate) attributes: Vec<Attributes>,
name: String,
pub name: String,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -295,6 +295,18 @@ pub struct Functions {
}

impl<'a> Functions {
pub fn get_object_functions<'b: 'a>(
&'a self,
name: &'b String,
) -> impl Iterator<Item = &Function> + 'a {
self.map.iter().filter_map(move |(key, val)| {
if key.starts_with(name) {
Some(val.clone())
} else {
None
}
})
}
pub fn get(&self, signature: &str) -> Result<&Function> {
let result = self
.map
Expand Down
Loading