Skip to content

Commit

Permalink
Implementation of ColdMUD style frobs
Browse files Browse the repository at this point in the history
  • Loading branch information
rdaum committed Oct 24, 2024
1 parent 0a37748 commit 4ea5f9a
Show file tree
Hide file tree
Showing 17 changed files with 137 additions and 26 deletions.
1 change: 1 addition & 0 deletions crates/compiler/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ pub enum Expr {
},
Index(Box<Expr>, Box<Expr>),
List(Vec<Arg>),
Frob(Box<Expr>, Box<Expr>),
Map(Vec<(Expr, Expr)>),
Scatter(Vec<ScatterItem>, Box<Expr>),
Length,
Expand Down
7 changes: 7 additions & 0 deletions crates/compiler/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,13 @@ impl CodegenState {
}
self.push_stack(1);
}
Expr::Frob(obj, val) => {
self.generate_expr(obj)?;
self.generate_expr(val)?;
self.emit(Op::MakeFrob);
self.pop_stack(2);
self.push_stack(1);
}
Expr::Scatter(scatter, right) => self.generate_scatter_assign(scatter, right)?,
Expr::Assign { left, right } => self.generate_assign(left, right)?,
}
Expand Down
6 changes: 6 additions & 0 deletions crates/compiler/src/decompile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,12 @@ impl Decompile {
map.push((k, v));
self.push_expr(Expr::Map(map));
}
Op::MakeFrob => {
// Two items on stack, obj and value
let value = self.pop_expr()?;
let obj = self.pop_expr()?;
self.push_expr(Expr::Frob(Box::new(obj), Box::new(value)));
}
Op::ListAddTail | Op::ListAppend => {
let e = self.pop_expr()?;
let list = self.pop_expr()?;
Expand Down
2 changes: 2 additions & 0 deletions crates/compiler/src/moo.pest
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ primary = _{
| sysprop_call
| sysprop
| try_expr
| frob
| map
| list
| atom
Expand All @@ -157,6 +158,7 @@ sysprop_call = { sysprop ~ arglist }
atom = { integer | float | string | object | err | ident }
arglist = { "(" ~ exprlist ~ ")" | "()" }
list = { ("{" ~ exprlist ~ "}") | "{}" }
frob = { "<" ~ expr ~ "," ~ expr ~ ">" }
exprlist = { argument ~ ("," ~ argument)* }
argument = { expr | "@" ~ expr }
map = { ("[" ~ (expr ~ "->" ~ expr) ~ ("," ~ expr ~ "->" ~ expr)* ~ "]") | "[]" }
Expand Down
1 change: 1 addition & 0 deletions crates/compiler/src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub enum Op {
MakeSingletonList,
MakeMap,
MapInsert,
MakeFrob,
Mod,
Mul,
Ne,
Expand Down
19 changes: 18 additions & 1 deletion crates/compiler/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,13 @@ impl TreeTransformer {
.collect();
Ok(Expr::Map(pairs))
}
Rule::frob => {
let mut inner = primary.into_inner();
// Two values, obj, then data
let obj = primary_self.clone().parse_expr(inner.next().unwrap().into_inner())?;
let data = primary_self.clone().parse_expr(inner.next().unwrap().into_inner())?;
Ok(Expr::Frob(Box::new(obj), Box::new(data)))
}
Rule::builtin_call => {
let mut inner = primary.into_inner();
let bf = inner.next().unwrap().as_str();
Expand Down Expand Up @@ -1194,7 +1201,7 @@ mod tests {
use moor_values::{v_none, Symbol};

use crate::ast::Arg::{Normal, Splice};
use crate::ast::Expr::{Call, Id, Prop, Value, Verb};
use crate::ast::Expr::{Call, Frob, Id, Prop, Value, Verb};
use crate::ast::{
BinaryOp, CatchCodes, CondArm, ElseArm, ExceptArm, Expr, ScatterItem, ScatterKind, Stmt,
StmtNode, UnaryOp,
Expand Down Expand Up @@ -2692,4 +2699,14 @@ mod tests {
let parse = parse_program(program, CompileOptions::default());
assert!(matches!(parse, Err(CompileError::DuplicateVariable(_))));
}

#[test]
fn test_frob_parse() {
let program = "<#123, 456>;";
let parse = parse_program(program, CompileOptions::default()).unwrap();
assert_eq!(
stripped_stmts(&parse.stmts),
vec![StmtNode::Expr(Frob(Box::new(Value(v_obj(123))), Box::new(Value(v_int(456)))))]
);
}
}
16 changes: 16 additions & 0 deletions crates/compiler/src/unparse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// this program. If not, see <https://www.gnu.org/licenses/>.
//

use tracing::info;
use moor_values::util::quote_str;
use moor_values::{Var, Variant};

Expand Down Expand Up @@ -71,6 +72,7 @@ impl Expr {
Expr::Id(_) => 1,
Expr::List(_) => 1,
Expr::Map(_) => 1,
Expr::Frob(_, _) => 1,
Expr::Pass { .. } => 1,
Expr::Call { .. } => 1,
Expr::Length => 1,
Expand Down Expand Up @@ -337,6 +339,15 @@ impl<'a> Unparse<'a> {
buffer.push_str(self.unparse_expr(expr)?.as_str());
Ok(buffer)
}
Expr::Frob(o, d) => {
let mut buffer = String::new();
buffer.push('<');
buffer.push_str(self.unparse_expr(o)?.as_str());
buffer.push_str(", ");
buffer.push_str(self.unparse_expr(d)?.as_str());
buffer.push('>');
Ok(buffer)
}
Expr::Length => Ok(String::from("$")),
}
}
Expand Down Expand Up @@ -767,6 +778,11 @@ pub fn to_literal(v: &Var) -> String {
result.push(']');
result
}
Variant::Frob(o, v) => {
// <object, value>
info!("Frob: {:?}, {:?}", o, v);
format!("<{}, {}>", o, to_literal(v.as_ref()))
}
Variant::Err(e) => e.name().to_string(),
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/kernel/src/builtins/bf_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn bf_tostr(bf_args: &mut BfCallState<'_>) -> Result<BfRet, BfErr> {
Variant::Obj(o) => result.push_str(&o.to_string()),
Variant::List(_) => result.push_str("{list}"),
Variant::Map(_) => result.push_str("[map]"),
Variant::Frob(o, d) => result.push_str(format!("<{},{:?}>", o, d).as_str()),
Variant::Err(e) => result.push_str(e.name()),
}
}
Expand Down
7 changes: 6 additions & 1 deletion crates/kernel/src/textdump/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use tracing::info;
use moor_compiler::Label;
use moor_values::model::CompileError;
use moor_values::model::WorldStateError;
use moor_values::Objid;
use moor_values::{Objid, v_frob};
use moor_values::{v_err, v_float, v_int, v_none, v_objid, v_str, Var, VarType};
use moor_values::{v_list, v_map, Error};

Expand Down Expand Up @@ -161,6 +161,11 @@ impl<R: Read> TextdumpReader<R> {
.collect();
v_map(&pairs)
}
VarType::TYPE_FROB => {
let o = self.read_objid()?;
let d = self.read_var()?;
v_frob(o, d)
}
VarType::TYPE_NONE => v_none(),
VarType::TYPE_FLOAT => v_float(self.read_float()?),
VarType::TYPE_LABEL => {
Expand Down
7 changes: 6 additions & 1 deletion crates/kernel/src/textdump/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// this program. If not, see <https://www.gnu.org/licenses/>.
//

use moor_values::{Objid, Sequence};
use moor_values::{Objid, Sequence, v_objid};
use moor_values::{Var, VarType, Variant};
use std::collections::BTreeMap;
use std::io;
Expand Down Expand Up @@ -88,6 +88,11 @@ impl<W: io::Write> TextdumpWriter<W> {
self.write_var(&v, false)?;
}
}
Variant::Frob(o, d) => {
writeln!(self.writer, "{}\n{}", VarType::TYPE_FROB as i64, o.0)?;
self.write_var(&v_objid(o), false)?;
self.write_var(d.as_ref(), false)?;
}
Variant::None => {
writeln!(self.writer, "{}", VarType::TYPE_NONE as i64)?;
}
Expand Down
20 changes: 19 additions & 1 deletion crates/kernel/src/vm/moo_execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use moor_values::model::WorldState;
use moor_values::model::WorldStateError;

use moor_values::Error::{E_ARGS, E_DIV, E_INVARG, E_INVIND, E_TYPE, E_VARNF};
use moor_values::Variant;
use moor_values::{v_frob, Variant};
use moor_values::{
v_bool, v_empty_list, v_empty_map, v_err, v_float, v_int, v_list, v_none, v_obj, v_objid,
IndexMode, Sequence,
Expand Down Expand Up @@ -356,6 +356,14 @@ pub fn moo_frame_execute(
}
}
}
Op::MakeFrob => {
// Two values on stack, <o, d>
let (d, o) = (f.pop(), f.pop());
let Variant::Obj(o) = o.variant() else {
return state.push_error(E_TYPE);
};
f.push(v_frob(o, d));
}
Op::PutTemp => {
f.temp = f.peek_top().clone();
}
Expand Down Expand Up @@ -623,7 +631,17 @@ pub fn moo_frame_execute(
Op::CallVerb => {
let (args, verb, obj) = (f.pop(), f.pop(), f.pop());
let (args, verb, obj) = match (args.variant(), verb.variant(), obj.variant()) {
// Verb on object as usual
(Variant::List(l), Variant::Str(s), Variant::Obj(o)) => (l, s, o),
// Verb via frob, we pull the object from the frob, and then insert its data portion as first argument.
(Variant::List(l), Variant::Str(s), Variant::Frob(o, d)) => {
let l = l.clone();
let l = l.insert(0, d.as_ref()).unwrap();
let Variant::List(l) = l.variant() else {
return state.push_error(E_TYPE);
};
(l, s, o)
}
_ => {
return state.push_error(E_TYPE);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/values/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use encode::{
pub use var::{
v_bool, v_empty_list, v_empty_map, v_empty_str, v_err, v_float, v_int, v_list, v_list_iter,
v_map, v_none, v_obj, v_objid, v_str, v_string, Associative, ErrorPack, IndexMode, List, Map,
Sequence, Str, Var, Variant,
Sequence, Str, Var, Variant, v_frob
};
pub use var::{Error, Objid, Symbol, VarType};

Expand Down
14 changes: 2 additions & 12 deletions crates/values/src/var/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,6 @@
// this program. If not, see <https://www.gnu.org/licenses/>.
//

//! TODO:
//! to_literal / formatting
//! move everything up and over into `../var`
//! go through all uses of existing var and update them to use the new var
//! any missed functionality along the way?
//! more tests, and make pass moot once above is done
//! later:
//! more documentation
//! builder vs reader mode? - optimization for values under construction.
//! some From/Into impls for common types might be missing
mod error;
mod list;
mod map;
Expand All @@ -46,7 +35,7 @@ use strum::FromRepr;
pub use symbol::Symbol;
pub use var::{
v_bool, v_empty_list, v_empty_map, v_empty_str, v_err, v_float, v_int, v_list, v_list_iter,
v_map, v_none, v_obj, v_objid, v_str, v_string, Var,
v_map, v_none, v_obj, v_objid, v_str, v_string, Var, v_frob,
};
pub use variant::Variant;

Expand All @@ -64,6 +53,7 @@ pub enum VarType {
TYPE_LABEL = 7, // present only in textdump */
TYPE_FLOAT = 9,
TYPE_MAP = 10,
TYPE_FROB = 11,
}

/// Sequence index modes: 0 or 1 indexed.
Expand Down
8 changes: 8 additions & 0 deletions crates/values/src/var/var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ impl Var {
Var(Store::Variant(Variant::Obj(o)))
}

pub fn mk_frob(o: Objid, data: Var) -> Self { Var(Store::Variant(Variant::Frob(o, Box::new(data)))) }

pub fn type_code(&self) -> VarType {
match self.variant() {
Variant::Int(_) => VarType::TYPE_INT,
Expand All @@ -116,6 +118,7 @@ impl Var {
Variant::None => VarType::TYPE_NONE,
Variant::Float(_) => VarType::TYPE_FLOAT,
Variant::Map(_) => VarType::TYPE_MAP,
Variant::Frob(_, _) => VarType::TYPE_FROB,
}
}

Expand Down Expand Up @@ -148,6 +151,7 @@ impl Var {
Variant::Str(s) => !s.as_string().is_empty(),
Variant::Map(m) => !m.reader.is_empty(),
Variant::Err(_) => false,
Variant::Frob(_, _) => true,
}
}

Expand Down Expand Up @@ -511,6 +515,10 @@ pub fn v_empty_map() -> Var {
v_map(&[])
}

pub fn v_frob(o: Objid, data: Var) -> Var {
Var::mk_frob(o, data)
}

impl From<i64> for Var {
fn from(i: i64) -> Self {
Var::mk_integer(i)
Expand Down
Loading

0 comments on commit 4ea5f9a

Please sign in to comment.