1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
use std::rc::Rc;
use crate::{lang::*, InternalString};
use crate::{RantFunctionHandle, RantList, RantMap, RantValue};
use super::{RuntimeResult, VM, resolver::Weights};
/// Actions that can be queued on a stack frame that are performed before the frame runs.
///
/// ## "Call" or "Invoke"?
/// In the context of Rant runtime intents, "calling" and "invoking" have specific meanings:
/// * "Invoke" means that argument expressions potentially need to be evaluated before the call can proceed;
/// * "Call" means that all argument values are already known (either in the intent or on the value stack).
pub enum Intent {
/// Pops a value off the value stack and print it to the current frame's output.
PrintLast,
/// Pops a value off the value stack and returns it from the current function.
ReturnLast,
/// Pops a value off the value stack and continues to the next repeater iteration with it.
ContinueLast,
/// Pops a value off the value stack and breaks from the current repeater with it.
BreakLast,
/// Pops a map off the stack and loads it as a module with the specified name.
ImportLastAsModule { module_name: String, descope: usize },
/// Check if the current block is finished and either continue the block or pop the state from the stack
TickCurrentBlock,
/// Pops a value off the stack and assign it to an existing variable.
SetVar { vname: Identifier, access_kind: VarAccessMode, },
/// Pops a value off the stack and assign it to a new variable.
DefVar { vname: Identifier, access_kind: VarAccessMode, is_const: bool },
/// Pops a block from `pending_exprs` and evaluate it. If there are no expressions left, switch intent to `GetValue`.
BuildDynamicGetter {
path: Rc<AccessPath>,
dynamic_key_count: usize,
pending_exprs: Vec<Rc<Sequence>>,
override_print: bool,
prefer_function: bool,
fallback: Option<Rc<Sequence>>,
},
/// Pops dynamic key values off the stack and runs a getter. If the getter fails, evaluates the fallback.
GetValue {
path: Rc<AccessPath>,
dynamic_key_count: usize,
override_print: bool,
prefer_function: bool,
fallback: Option<Rc<Sequence>>,
},
/// Used to evaluate a setter path with dynamic keys.
///
/// Pops a block from `pending_exprs` and evaluate it. If there are no expressions left, switch intent to `SetValue`.
BuildDynamicSetter {
path: Rc<AccessPath>,
write_mode: VarWriteMode,
expr_count: usize,
pending_exprs: Vec<Rc<Sequence>>,
val_source: SetterValueSource,
},
/// Pops `expr_count` values off the stack and uses them for expression fields in a setter.
SetValue {
path: Rc<AccessPath>,
write_mode: VarWriteMode,
expr_count: usize
},
/// Evaluates `arg_exprs` in order, then pops the argument values off the stack, pops a function off the stack, and passes the arguments to the function.
Invoke {
arg_exprs: Rc<Vec<ArgumentExpr>>,
arg_eval_count: usize,
is_temporal: bool,
},
/// Invokes a single function in a piped function call chain.
InvokePipeStep {
/// All steps in the entire piped function call
steps: Rc<Vec<FunctionCall>>,
/// The current step being executed
step_index: usize,
/// Current state of the intent.
state: InvokePipeStepState,
/// The pipe value from the last step
pipeval: Option<RantValue>,
/// Optional assignment pipe
assignment_pipe: Option<Rc<AssignmentPipeTarget>>,
},
/// Evaluates each sequence in `default_arg_exprs` in order and assigns their results to local constants with their associated `Identifier`.
CreateDefaultArgs { context: RantFunctionHandle, default_arg_exprs: Vec<(Rc<Sequence>, usize)>, eval_index: usize, },
/// Pops `argc` args off the stack, then pops a function off the stack and calls it with the args.
Call { argc: usize, override_print: bool },
/// Calls a sequence without an inner variable scope, then pushes its output to the value stack.
CallOperand { sequence: Rc<Sequence> },
/// Calls a function for every variant of a temporal argument set and increments the provided temporal state.
CallTemporal { func: RantFunctionHandle, arg_exprs: Rc<Vec<ArgumentExpr>>, args: Rc<Vec<RantValue>>, temporal_state: TemporalSpreadState, },
/// Pops value from stack and adds it to a list. If `index` is out of range, prints the list.
BuildList { init: Rc<Vec<Rc<Sequence>>>, index: usize, list: RantList },
/// Pops a value from the stack and adds it to `items`. If `index` is out of range, produces a tuple from `items` and prints it.
BuildTuple { init: Rc<Vec<Rc<Sequence>>>, index: usize, items: Vec<RantValue> },
/// Pops a value and optional key from stack and adds them to `map`. If `pair_index` is out of range, prints `map`.
BuildMap { init: Rc<Vec<(MapKeyExpr, Rc<Sequence>)>>, pair_index: usize, map: RantMap },
/// Evaluates expressions in `weights` and then runs the block with the computed element weights.
BuildWeightedBlock { block: Rc<Block>, weights: Weights, pop_next_weight: bool, },
/// Calls a function that accepts a mutable reference to the current runtime. Optionally interrupts the intent loop to force another tick.
RuntimeCall { function: Box<dyn FnOnce(&mut VM) -> RuntimeResult<()>>, interrupt: bool },
/// Drops all unwind states that are no longer within the call stack.
DropStaleUnwinds,
/// Pops two values (RHS, LHS), performs addition, and pushes the result.
Add,
/// Pops two values (RHS, LHS), performs subtraction, and pushes the result.
Subtract,
/// Pops two values (RHS, LHS), performs multiplication, and pushes the result.
Multiply,
/// Pops two values (RHS, LHS), performs division, and pushes the result.
Divide,
/// Pops two values (RHS, LHS), performs modulo, and pushes the result.
Modulo,
/// Pops two values (RHS, LHS), performs exponentiation, and pushes the result.
Power,
/// Pops a value, performs logical NOT, and pushes the result.
LogicNot,
/// Pops a value, performs negation, and pushes the result.
Negate,
/// Pops a value off the value stack and compares its truthiness against `on_truthiness`, and re-pushes the value.
/// If they match, do nothing and continue.
/// If they don't match, calls `gen_op_intent` and pushes the returned intent onto the current frame, then evaluates `rhs` using the `CallOperand` intent.
LogicShortCircuit { on_truthiness: bool, short_circuit_result: LogicShortCircuitHandling, gen_op_intent: Box<dyn FnOnce() -> Intent>, rhs: Rc<Sequence> },
/// Pops two values, performs logical AND, and pushes the result.
LogicAnd,
/// Pops two values, performs logical OR, and pushes the result.
LogicOr,
/// Pops two values (RHS, LHS), performs logical XOR, and pushes the result.
LogicXor,
/// Pops two values (RHS, LHS), calculates `LHS == RHS`, and pushes the result.
Equals,
/// Pops two values (RHS, LHS), calculates `LHS != RHS`, and pushes the result.
NotEquals,
/// Pops two values (RHS, LHS), calculates `LHS > RHS`, and pushes the result.
Greater,
/// Pops two values (RHS, LHS), calculates `LHS >= RHS`, and pushes the result.
GreaterOrEqual,
/// Pops two values (RHS, LHS), calculates `LHS < RHS`, and pushes the result.
Less,
/// Pops two values (RHS, LHS), calculates `LHS <= RHS`, and pushes the result.
LessOrEqual,
/// If `index` is nonzero, pops a value off the value stack and checks its truthiness.
/// If it's falsy, pushes the next condition (or fallback) to the call stack and re-pushes this intent with `index = index + 1`.
/// If it's truthy, pushes it to the value stack and exits.
CheckCondition { conditions: Rc<Vec<(Rc<Sequence>, Rc<Block>)>>, fallback: Option<Rc<Block>>, index: usize },
}
impl Intent {
pub(crate) fn name(&self) -> &'static str {
match self {
Self::PrintLast => "print",
Self::TickCurrentBlock => "check_block",
Self::SetVar { .. } => "set_var",
Self::DefVar { .. } => "def_var",
Self::BuildDynamicGetter { .. } => "build_dyn_getter",
Self::GetValue { .. } => "get_value",
Self::BuildDynamicSetter { .. } => "build_dyn_setter",
Self::SetValue { .. } => "set_value",
Self::Invoke { .. } => "invoke",
Self::InvokePipeStep { .. } => "invoke_pipe_step",
Self::Call { .. } => "call",
Self::CallOperand { .. } => "call_operand",
Self::CallTemporal { .. } => "call_temporal",
Self::BuildList { .. } => "build_list",
Self::BuildTuple { .. } => "build_tuple",
Self::BuildMap { .. } => "build_map",
Self::ImportLastAsModule { .. } => "load_module",
Self::RuntimeCall { .. } => "runtime_call",
Self::DropStaleUnwinds => "drop_stale_unwinds",
Self::ReturnLast => "return_last",
Self::ContinueLast => "continue_last",
Self::BreakLast => "break_last",
Self::BuildWeightedBlock { .. } => "build_weighted_block",
Self::CreateDefaultArgs { .. } => "create_default_args",
Self::Add => "add",
Self::Subtract => "subtract",
Self::Multiply => "multiply",
Self::Divide => "divide",
Self::Modulo => "modulo",
Self::Power => "power",
Self::Negate => "negate",
Self::LogicShortCircuit { .. } => "logic_short_circuit",
Self::LogicNot => "not",
Self::LogicAnd => "and",
Self::LogicOr => "or",
Self::LogicXor => "xor",
Self::Equals => "equals",
Self::NotEquals => "not_equals",
Self::Less => "less",
Self::LessOrEqual => "less_or_equal",
Self::Greater => "greater",
Self::GreaterOrEqual => "greater_or_equal",
Self::CheckCondition { .. } => "conditional",
}
}
}
/// Defines short-circuiting behaviors for logic operators.
#[derive(Debug, Copy, Clone)]
pub enum LogicShortCircuitHandling {
/// Pass through the LHS untouched.
Passthrough,
/// Use the specified boolean value as the LHS.
OverrideWith(bool),
}
/// States for the `InvokePipeStep` intent.
#[derive(Debug)]
pub enum InvokePipeStepState {
/// Evaluate step function and leave it on the value stack.
///
/// Transitions to `EvaluatingArgs`.
EvaluatingFunc,
/// Evaluate argument expressions, then pop them off the value stack.
/// Then, before transitioning, pop the function off the value stack and store it.
///
/// Transitions to `PreCall` or `PreTemporalCall`.
EvaluatingArgs {
/// Number of arguments that have already been evaluated.
num_evaluated: usize
},
/// Temporal step function is ready to iterate.
///
/// Transitions to `PostTemporalCall`.
PreTemporalCall {
step_function: RantFunctionHandle,
temporal_state: TemporalSpreadState,
args: Vec<RantValue>,
},
/// Step function is ready to call.
///
/// Transitions to `PostCall`.
PreCall {
step_function: RantFunctionHandle,
args: Vec<RantValue>,
},
/// Step function has returned and output can be used.
PostCall,
/// Temporal step function has iterated and output can be used.
///
/// Might transition to `PreTemporalCall`.
PostTemporalCall {
step_function: RantFunctionHandle,
temporal_state: TemporalSpreadState,
args: Vec<RantValue>,
}
}
/// Defines variable write modes for setter intents.
/// Used by function definitions to control conditional definition behavior.
#[derive(Debug, Copy, Clone)]
pub enum VarWriteMode {
/// Only set existing variables.
SetOnly,
/// Defines and sets a variable.
Define,
/// Defines and sets a new constant.
DefineConst,
}
#[derive(Debug)]
pub enum SetterKey<'a> {
Index(i64),
Slice(Slice),
KeyRef(&'a str),
KeyString(InternalString),
}
/// Describes where a setter gets its RHS value.
#[derive(Debug)]
pub enum SetterValueSource {
/// Setter RHS is evaluated from an expression.
FromExpression(Rc<Sequence>),
/// Setter RHS is a value.
FromValue(RantValue),
/// Setter RHS was already consumed and pushed to the value stack.
FromStack
}