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
use crate::compiler::*;
use crate::reader::Offset;
use crate::value::{Object, RefValue, Value};
/** Intermediate traversal result.
This enum is used to allow either for a value or ops created during the AST traversal in the compiler.
*/
#[derive(Debug)]
pub enum ImlResult {
Empty,
Value(ImlValue),
Identifier(String, Option<Offset>),
Ops(Vec<ImlOp>),
}
impl ImlResult {
/** Turns a traversal result into a vector of operations;
In case the result is a Value, it can either be called when calling with 0 arguments is possible,
which is specified by the call flag.
*/
pub fn into_ops(self, compiler: &mut Compiler, call: bool) -> Vec<ImlOp> {
match self {
ImlResult::Empty => Vec::new(),
ImlResult::Value(value) => {
vec![ImlOp::Op(if call && value.is_callable(true) {
if let ImlValue::Value(value) = &value {
if value.name() == "token" {
compiler.mark_consuming();
}
}
Op::CallStatic(compiler.define_value(value))
} else {
let mut op = None;
if let ImlValue::Value(value) = &value {
op = match &*value.borrow() {
Value::Void => Some(Op::PushVoid),
Value::Null => Some(Op::PushNull),
Value::True => Some(Op::PushTrue),
Value::False => Some(Op::PushFalse),
Value::Int(0) => Some(Op::Push0),
Value::Int(1) => Some(Op::Push1),
_ => None,
}
}
op.unwrap_or_else(|| Op::LoadStatic(compiler.define_value(value)))
})]
}
ImlResult::Identifier(name, offset) => {
let usage = if call {
Usage::CallOrCopy { name, offset }
} else {
Usage::Load { name, offset }
};
usage.resolve_or_dispose(compiler)
}
ImlResult::Ops(ops) => {
// Filter any Op::Nop from the ops.
ops.into_iter()
.filter(|op| !matches!(op, ImlOp::Nop))
.collect()
}
}
}
/** Returns a value to operate with or evaluate during compile-time.
The function will only return Ok(Value) when static_expression_evaluation-feature
is enabled, the ImlResult contains a value and this value is NOT a callable! */
pub fn get_evaluable_value(&self) -> Result<RefValue, ()> {
if cfg!(feature = "static_expression_evaluation") {
if let ImlResult::Value(ImlValue::Value(value)) = self {
if !value.is_callable(true) {
return Ok(value.clone().into());
}
}
}
Err(())
}
}