Skip to content

Commit

Permalink
Merge ImlTarget into ImlValue
Browse files Browse the repository at this point in the history
The previous implementation did not have any real advantage, except making the code more complex at this point.
  • Loading branch information
phorward committed Mar 19, 2023
1 parent 2b2d89d commit 19c8b1c
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 97 deletions.
18 changes: 3 additions & 15 deletions src/compiler/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,7 @@ fn traverse_node_static(compiler: &mut Compiler, lvalue: Option<&str>, node: &Di
value!(void).into()
}
// Defined parselet or value
ImlOp::Load {
target: ImlTarget::Static(value),
..
} => {
ImlOp::Load { target: value, .. } => {
compiler.parselet_pop(None, None, None, None, None, ImlOp::Nop);

if let Some(lvalue) = lvalue {
Expand Down Expand Up @@ -1233,16 +1230,7 @@ fn traverse_node(compiler: &mut Compiler, node: &Dict) -> ImlOp {
"opt" => "?",
other => other,
},
if matches!(
res,
ImlOp::Load {
target: ImlTarget::Static(_),
..
} | ImlOp::Call {
target: ImlTarget::Static(_),
..
}
) {
if matches!(res, ImlOp::Load { .. } | ImlOp::Call { .. }) {
"value"
} else {
"sequence"
Expand All @@ -1255,7 +1243,7 @@ fn traverse_node(compiler: &mut Compiler, node: &Dict) -> ImlOp {

// Modifiers on usages of Token::Char can be optimized for better efficiency
if let ImlOp::Call {
target: ImlTarget::Static(ImlValue::Value(target)),
target: ImlValue::Value(target),
..
} = &res
{
Expand Down
6 changes: 1 addition & 5 deletions src/compiler/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,7 @@ impl Compiler {
println!("--- Global scope ---\n{:#?}", self.scopes.last().unwrap())
}

if let ImlOp::Call {
target: ImlTarget::Static(main),
..
} = ret
{
if let ImlOp::Call { target: main, .. } = ret {
if self.debug > 1 {
println!("--- Intermediate main ---\n{:#?}", main);
}
Expand Down
86 changes: 25 additions & 61 deletions src/compiler/iml/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,19 @@ use std::rc::Rc;

pub(in crate::compiler) type SharedImlOp = Rc<RefCell<ImlOp>>;

/// Target of a call or load
#[derive(Clone)]
pub(in crate::compiler) enum ImlTarget {
Unknown(String), // Compile-time unknown identifier
Undefined(String), // Compile-time declared but undefined identifier (used by generic parselets)
Static(ImlValue), // Compile-time static value
Local(usize), // Runtime local value
Global(usize), // Runtime global value
}

impl ImlTarget {
pub fn is_consuming(&self) -> bool {
match self {
Self::Unknown(name) | Self::Undefined(name) => {
crate::utils::identifier_is_consumable(name)
}
Self::Static(value) => value.is_consuming(),
_ => false, // cannot determine!
}
}
}

impl std::fmt::Debug for ImlTarget {
// Manual implementation is required to avoid endless recursion here
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Unknown(name) | Self::Undefined(name) => write!(f, "{}", name),
Self::Static(value) => write!(f, "{}", value),
Self::Local(addr) => write!(f, "local@{}", addr),
Self::Global(addr) => write!(f, "global@{}", addr),
}
}
}

#[derive(Debug, Clone)]
pub(in crate::compiler) enum ImlOp {
Nop, // Empty operation
Op(Op), // VM Operation
Shared(SharedImlOp), // Shared ImlOp tree can be shared from various locations during compilation
Load {
offset: Option<Offset>,
target: ImlTarget,
target: ImlValue,
//copy: bool, //enforce copy (Op::Sep)
},
Call {
offset: Option<Offset>,
target: ImlTarget,
target: ImlValue,
args: Option<(usize, bool)>,
},

Expand Down Expand Up @@ -144,15 +110,15 @@ impl ImlOp {
pub fn load(offset: Option<Offset>, value: ImlValue) -> ImlOp {
ImlOp::Load {
offset,
target: ImlTarget::Static(value),
target: value,
}
}

/// Load unknown value by name
pub fn load_by_name(compiler: &mut Compiler, offset: Option<Offset>, name: String) -> ImlOp {
ImlOp::Load {
offset,
target: ImlTarget::Unknown(name),
target: ImlValue::Unknown(name),
}
.try_resolve(compiler)
}
Expand All @@ -174,7 +140,7 @@ impl ImlOp {

ImlOp::Call {
offset,
target: ImlTarget::Static(value),
target: value,
args,
}
}
Expand All @@ -193,7 +159,7 @@ impl ImlOp {

ImlOp::Call {
offset,
target: ImlTarget::Unknown(name),
target: ImlValue::Unknown(name),
args,
}
.try_resolve(compiler)
Expand All @@ -214,21 +180,21 @@ impl ImlOp {
match self {
Self::Shared(op) => return op.borrow_mut().resolve(compiler),
Self::Load { target, .. } | Self::Call { target, .. } => {
if let ImlTarget::Unknown(name) = target {
if let ImlValue::Unknown(name) = target {
if let Some(value) = compiler.get_constant(&name) {
// In case this is a generic, the value is resolved to a generic for later dispose
if matches!(value, ImlValue::Undefined(_)) {
*target = ImlTarget::Undefined(name.clone());
*target = ImlValue::Undefined(name.clone());
} else {
*target = ImlTarget::Static(value);
*target = value;
}

return true;
} else if let Some(addr) = compiler.get_local(&name) {
*target = ImlTarget::Local(addr);
*target = ImlValue::Local(addr);
return true;
} else if let Some(addr) = compiler.get_global(&name) {
*target = ImlTarget::Global(addr);
*target = ImlValue::Global(addr);
return true;
}
}
Expand Down Expand Up @@ -367,20 +333,20 @@ impl ImlOp {
}

ops.push(match target {
ImlTarget::Unknown(name) => {
ImlValue::Unknown(name) => {
linker.errors.push(Error::new(
*offset,
format!("Use of unresolved symbol '{}'", name),
));

Op::Nop
}
ImlTarget::Undefined(name) => {
ImlValue::Undefined(name) => {
unreachable!("Use of undefined symbol '{}'", name)
}
ImlTarget::Static(value) => linker.push(value),
ImlTarget::Local(idx) => Op::LoadFast(*idx),
ImlTarget::Global(idx) => Op::LoadGlobal(*idx),
ImlValue::Local(idx) => Op::LoadFast(*idx),
ImlValue::Global(idx) => Op::LoadGlobal(*idx),
value => linker.push(value),
});
}
ImlOp::Call {
Expand All @@ -393,16 +359,19 @@ impl ImlOp {
}

match target {
ImlTarget::Unknown(name) => {
ImlValue::Unknown(name) => {
linker.errors.push(Error::new(
*offset,
format!("Call to unresolved symbol '{}'", name),
));
}
ImlTarget::Undefined(name) => {
ImlValue::Undefined(name) => {
unreachable!("Call to undefined symbol '{}' may not occur", name)
}
ImlTarget::Static(value) => {
ImlValue::Local(idx) => ops.push(Op::LoadFast(*idx)),
ImlValue::Global(idx) => ops.push(Op::LoadGlobal(*idx)),
value => {
// When value is a parselet, check for accepted constant configuration
if let ImlValue::Parselet {
parselet,
constants,
Expand Down Expand Up @@ -459,8 +428,6 @@ impl ImlOp {

return ops.len() - start;
}
ImlTarget::Local(idx) => ops.push(Op::LoadFast(*idx)),
ImlTarget::Global(idx) => ops.push(Op::LoadGlobal(*idx)),
}

match args {
Expand Down Expand Up @@ -728,10 +695,7 @@ impl ImlOp {
) -> Option<Consumable> {
match self {
ImlOp::Shared(op) => op.borrow().finalize(visited, configs),
ImlOp::Call {
target: ImlTarget::Static(callee),
..
} => {
ImlOp::Call { target: callee, .. } => {
match callee {
ImlValue::Parselet {
parselet,
Expand Down Expand Up @@ -791,7 +755,7 @@ impl ImlOp {
None
}
}
_ => unreachable!(),
_ => None,
}
}
ImlOp::Alt { alts } => {
Expand Down Expand Up @@ -984,7 +948,7 @@ impl ImlOp {
pub fn get_evaluable_value(&self) -> Result<RefValue, ()> {
if cfg!(feature = "static_expression_evaluation") {
if let Self::Load {
target: ImlTarget::Static(ImlValue::Value(value)),
target: ImlValue::Value(value),
..
} = self
{
Expand Down
42 changes: 26 additions & 16 deletions src/compiler/iml/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

/** Compile-time values */
/** Intermediate value */
#[derive(Clone, PartialEq, Eq)]
pub(in crate::compiler) enum ImlValue {
Undefined(String), // Known but undefined value (used in generic parselets)
Value(RefValue), // Standard value object
Unknown(String), // Compile-time unknown identifier
Undefined(String), // Compile-time known but undefined identifier (used in generic parselets)
Value(RefValue), // Compile-time static value
Parselet {
// Parselet instance
// Compile-time parselet instance
parselet: Rc<RefCell<ImlParselet>>, // The parselet definition
constants: HashMap<String, ImlValue>, // Optional parselet instance configuation
},
Local(usize), // Runtime local value
Global(usize), // Runtime global value
}

impl ImlValue {
pub fn value(self) -> RefValue {
if let ImlValue::Value(value) = self {
if let Self::Value(value) = self {
value
} else {
panic!("{:?} cannot be unwrapped", self)
Expand All @@ -30,8 +33,8 @@ impl ImlValue {
/// and when its callable if with or without arguments.
pub fn is_callable(&self, without_arguments: bool) -> bool {
match self {
ImlValue::Value(value) => value.is_callable(without_arguments),
ImlValue::Parselet { parselet, .. } => {
Self::Value(value) => value.is_callable(without_arguments),
Self::Parselet { parselet, .. } => {
let parselet = parselet.borrow();

if without_arguments {
Expand All @@ -41,35 +44,40 @@ impl ImlValue {
true
}
}
_ => unreachable!(),
_ => false,
}
}

/// Check whether intermediate value represents consuming
pub fn is_consuming(&self) -> bool {
match self {
ImlValue::Undefined(ident) => crate::utils::identifier_is_consumable(ident),
ImlValue::Value(value) => value.is_consuming(),
ImlValue::Parselet { parselet, .. } => parselet.borrow().consuming,
Self::Unknown(name) | Self::Undefined(name) => {
crate::utils::identifier_is_consumable(name)
}
Self::Value(value) => value.is_consuming(),
Self::Parselet { parselet, .. } => parselet.borrow().consuming,
_ => false,
}
}
}

impl std::fmt::Debug for ImlValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Undefined(s) => write!(f, "{}", s),
Self::Unknown(name) | Self::Undefined(name) => write!(f, "{}", name),
Self::Value(v) => v.borrow().fmt(f),
ImlValue::Parselet { parselet, .. } => parselet.borrow().fmt(f),
Self::Parselet { .. } => write!(f, "{}", self),
Self::Local(addr) => write!(f, "local@{}", addr),
Self::Global(addr) => write!(f, "global@{}", addr),
}
}
}

impl std::fmt::Display for ImlValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Undefined(s) => write!(f, "{}", s),
Self::Value(v) => write!(f, "{}", v.repr()),
Self::Unknown(name) | Self::Undefined(name) => write!(f, "{}", name),
Self::Value(value) => write!(f, "{}", value.repr()),
Self::Parselet {
parselet,
constants,
Expand All @@ -94,14 +102,15 @@ impl std::fmt::Display for ImlValue {

Ok(())
}
Self::Local(addr) => write!(f, "local@{}", addr),
Self::Global(addr) => write!(f, "global@{}", addr),
}
}
}

impl std::hash::Hash for ImlValue {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Undefined(_) => unreachable!(),
Self::Value(v) => {
state.write_u8('v' as u8);
v.hash(state)
Expand All @@ -114,6 +123,7 @@ impl std::hash::Hash for ImlValue {
parselet.borrow().hash(state);
constants.iter().collect::<Vec<_>>().hash(state);
}
other => unreachable!("{:?} is unhashable", other),
}
}
}
Expand Down

0 comments on commit 19c8b1c

Please sign in to comment.