Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New attempt for ImlValue resolving #138

Merged
merged 13 commits into from
Mar 20, 2024
77 changes: 51 additions & 26 deletions src/compiler/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
scope.error(
offset,
format!(
"Generic '{}' defines consumable, but {} is not consuming",
"Generic '{}' defines consumable, but '{}' is not consuming",
name, default
),
);
Expand Down Expand Up @@ -256,7 +256,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
let default = children[1].borrow();
Some(traverse_node_static(
scope,
None,
Some(name.clone()),
default.object::<Dict>().unwrap(),
))
} else {
Expand Down Expand Up @@ -366,40 +366,74 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
}
}

let ret = ImlValue::Instance {
/*
if let Some(name) = &name {
println!(
"name = {} target = {:?} args = {:?} nargs = {:?}",
name, target, args, nargs
);
}
*/

ImlValue::Instance {
target: Box::new(target),
args,
nargs,
offset: traverse_node_offset(node),
severity: None,
is_generated: false,
};
}

ret.try_resolve(scope)
/*
if let Some(_) = &name {
println!("ret = {:?}", ret);
}
*/
}

_ => unimplemented!("unhandled value node {}", emit),
}
}

/** Traverse a static value.

The value must either be a literal or something from a known constant.

The name attribute is optional and can be used to assign an identifier to parselets for debug purposes
The assign attribute is optional and is only provided when the static is being assigned to
some identifier. In this case, special handling of e.g. value_generic-nodes is being performed.
*/
fn traverse_node_static(scope: &Scope, name: Option<String>, node: &Dict) -> ImlValue {
fn traverse_node_static(scope: &Scope, assign: Option<String>, node: &Dict) -> ImlValue {
let emit = node["emit"].borrow();
let emit = emit.object::<Str>().unwrap().as_str();

if emit.starts_with("value_") {
traverse_node_value(scope, node, name)
// Special case: Put a generic with an assignment name into its own parselet
if emit == "value_generic" && assign.is_some() {
// Handle anything else as an implicit parselet in its own scope
let implicit_parselet = ImlParselet::new(ImlParseletInstance::new(
None,
None,
traverse_node_offset(node),
assign,
5,
false,
));

implicit_parselet.borrow().model.borrow_mut().body = traverse_node_rvalue(
&scope.shadow(ScopeLevel::Parselet(implicit_parselet.clone())),
node,
Rvalue::CallOrLoad,
);

ImlValue::from(implicit_parselet)
} else if emit.starts_with("value_") {
traverse_node_value(scope, node, assign).try_resolve(scope)
} else {
// Handle anything else as an implicit parselet in its own scope
let implicit_parselet = ImlParselet::new(ImlParseletInstance::new(
None,
None,
traverse_node_offset(node),
name,
assign,
5,
false,
));
Expand All @@ -411,7 +445,7 @@ fn traverse_node_static(scope: &Scope, name: Option<String>, node: &Dict) -> Iml
Rvalue::Load,
) {
ImlOp::Nop => return value!(void).into(),
// Defined value load becomes just the value
// Defined value call without parameters, or load becomes just the value
ImlOp::Load { target: value, .. } => return value,

// Any other code becomes its own parselet without any signature.
Expand Down Expand Up @@ -1110,7 +1144,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
return ImlOp::Nop;
}

//println!("{} : {:?}", ident, value);
// println!("{} : {:#?}", ident, value);
scope.define_constant(ident, value);

// Try to resolve usage of newly introduced constant in current scope
Expand Down Expand Up @@ -1382,19 +1416,10 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {

// mod_kle on Token::Char becomes optional Token::Chars
if parts[2] == "kle" {
chars = chars.into_generic(
"Opt",
scope,
None,
offset.clone(),
);
chars = chars.into_generic("Opt", None, offset.clone());
}

return ImlOp::Call {
offset,
target: chars,
args: None,
};
return ImlOp::call(scope, offset, chars, None);
}

// mod_not on Token::Char becomes a negated Token::Char
Expand All @@ -1421,9 +1446,9 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
scope,
offset.clone(),
match parts[2] {
"pos" => res.into_generic("Pos", scope, assume_severity, offset),
"kle" => res.into_generic("Kle", scope, assume_severity, offset),
"opt" => res.into_generic("Opt", scope, assume_severity, offset),
"pos" => res.into_generic("Pos", assume_severity, offset),
"kle" => res.into_generic("Kle", assume_severity, offset),
"opt" => res.into_generic("Opt", assume_severity, offset),
_ => unreachable!(),
},
None,
Expand Down
12 changes: 5 additions & 7 deletions src/compiler/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,13 @@ impl Compiler {
// try to resolve any open usages
global_scope.resolve_usages();

// println!("constants {:#?}, {} usages", global_scope.constants, global_scope.usages.borrow().len());

// Report unresolved names
// println!("usages = {:?}", global_scope.usages);

for usage in global_scope.usages.borrow_mut().drain(..) {
if let ImlValue::Unresolved(usage) = usage {
let usage = usage.borrow();
if let ImlValue::Name { offset, name } = &*usage {
global_scope
.error(offset.clone(), format!("Use of undefined name '{}'", name));
}
}
global_scope.error(usage.offset(), format!("Use of undefined name '{}'", usage));
}

// Break on error
Expand Down
1 change: 1 addition & 0 deletions src/compiler/iml/imlop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ impl ImlOp {

/// Load value; This is only a shortcut for creating an ImlOp::Load{}
pub fn load(_scope: &Scope, offset: Option<Offset>, target: ImlValue) -> ImlOp {
// FIXME: Currently, doing `target: target.resolve(scope)` here will produce two usages!
ImlOp::Load { offset, target }
}

Expand Down
2 changes: 2 additions & 0 deletions src/compiler/iml/imlparselet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ impl ImlParselet {
let instance = self.instance.borrow();
let model = instance.model.borrow();

// println!("--- compile {:#?} ---", instance);

Parselet::new(
Some(format!("{}", instance)),
None,
Expand Down
6 changes: 4 additions & 2 deletions src/compiler/iml/imlprogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl ImlProgram {
otherwiese the value is cloned and put into the statics table. */
pub fn register(&mut self, value: &ImlValue) -> usize {
match value {
ImlValue::Unresolved(value) => return self.register(&*value.borrow()),
ImlValue::Shared(value) => return self.register(&*value.borrow()),
ImlValue::Parselet(_) | ImlValue::Value(_) => match self.statics.get_index_of(value) {
None => return self.statics.insert_full(value.clone(), None).0,
Some(idx) => return idx,
Expand Down Expand Up @@ -75,6 +75,8 @@ impl ImlProgram {
}
};

// println!("\n::: {} {:?} :::\n", idx, parselet.borrow().name);

// Memoize parselets required to be finalized (needs a general rework later...)
if parselet.borrow().model.borrow().is_consuming {
//fixme...
Expand Down Expand Up @@ -160,7 +162,7 @@ impl ImlProgram {
configs: &mut HashMap<ImlParselet, Consumable>,
) -> Option<Consumable> {
match value {
ImlValue::Unresolved(value) => {
ImlValue::Shared(value) => {
finalize_value(&*value.borrow(), current, visited, configs)
}
ImlValue::SelfToken => Some(Consumable {
Expand Down
Loading
Loading