Skip to content

Commit

Permalink
Further experiments towards tokay-lang#127
Browse files Browse the repository at this point in the history
  • Loading branch information
phorward committed Feb 28, 2024
1 parent 3d0b17d commit d0ecff6
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 68 deletions.
76 changes: 43 additions & 33 deletions src/compiler/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
let param = &genarg["children"].borrow();
let param = param.object::<Dict>().unwrap();

args.push((
offset,
traverse_node_static(scope, None, param).try_resolve(scope),
));
args.push((offset, traverse_node_static(scope, None, param)));
}

"genarg_named" => {
Expand All @@ -361,17 +358,23 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV

nargs.insert(
ident.to_string(),
(
offset,
traverse_node_static(scope, None, param).try_resolve(scope),
),
(offset, traverse_node_static(scope, None, param)),
);
}

other => unimplemented!("Unhandled genarg type {:?}", other),
}
}

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

ImlValue::Instance {
target: Box::new(target),
args,
Expand All @@ -380,44 +383,60 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
severity: None,
is_generated: false,
}
.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)
if emit.starts_with("value_") && (emit != "value_generic" || assign.is_none()) {
traverse_node_value(scope, node, assign)
} 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,
));

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

//println!("ret = {:?}", ret);

match ret {
ImlOp::Nop => return value!(void).into(),
// Defined value load becomes just the value
ImlOp::Load { target: value, .. } => return value,
// Defined value call without parameters, or load becomes just the value
ImlOp::Load { target: value, .. }
| ImlOp::Call {
target: value,
args: None,
..
} if emit != "value_generic" => return value,

// Any other code becomes its own parselet without any signature.
body => body,
Expand Down Expand Up @@ -1387,19 +1406,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 @@ -1426,9 +1436,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
50 changes: 19 additions & 31 deletions src/compiler/iml/imlvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,18 @@ impl ImlValue {
This is used internally to implement `Kle<P>` from `P*` syntax
during the AST traversal.
*/
pub fn into_generic(
self,
name: &str,
scope: &Scope,
severity: Option<u8>,
offset: Option<Offset>,
) -> Self {
pub fn into_generic(self, name: &str, severity: Option<u8>, offset: Option<Offset>) -> Self {
Self::Instance {
offset: None,
target: Box::new(
ImlValue::Name {
offset: None,
name: name.to_string(),
}
.try_resolve(scope),
),
target: Box::new(ImlValue::Name {
offset: None,
name: name.to_string(),
}),
args: vec![(offset, self)],
nargs: IndexMap::new(),
severity,
is_generated: true,
}
.try_resolve(scope)
}

/// Returns the value's definition offset, if available
Expand All @@ -97,7 +87,7 @@ impl ImlValue {

/// Try to resolve immediatelly, otherwise push shared reference to compiler's unresolved ImlValue.
pub fn try_resolve(mut self, scope: &Scope) -> Self {
self = self.resolve(scope, 0);
self = self.resolve(scope);

match &self {
Self::Name { .. } | Self::Instance { .. } => {
Expand All @@ -124,25 +114,23 @@ impl ImlValue {
Returns Some(value) with the resolved value on success, None otherwise.
*/
fn resolve(self, scope: &Scope, i: usize) -> ImlValue {
// println!("i = {} {:?}", i, &self);

fn resolve(self, scope: &Scope) -> ImlValue {
match self {
Self::Shared(rc) => {
match Rc::try_unwrap(rc) {
Ok(value) => {
// println!("UNCHAIN {:?}", value);
value.into_inner().resolve(scope, i + 1)
value.into_inner().resolve(scope)
}
Err(rc) => {
let resolved = rc.borrow().clone().resolve(scope, i + 1);
let resolved = rc.borrow().clone().resolve(scope);

if !matches!(resolved, Self::Name { .. } | Self::Instance { .. }) {
if matches!(resolved, Self::Name { .. } | Self::Instance { .. }) {
ImlValue::Shared(rc)
} else {
let mut value = rc.borrow_mut();
*value = resolved.clone();
resolved
} else {
ImlValue::Shared(rc)
}

/*
Expand Down Expand Up @@ -180,7 +168,7 @@ impl ImlValue {
severity,
is_generated,
} => {
let target = target.try_resolve(scope);
let target = target.resolve(scope);

if let ImlValue::Parselet(parselet) = &target {
let parselet = parselet.borrow();
Expand All @@ -193,11 +181,11 @@ impl ImlValue {
// Take arguments by sequence first
let arg = if !args.is_empty() {
let arg = args.remove(0);
(arg.0, Some(arg.1.resolve(scope, i + 1)))
(arg.0, Some(arg.1.try_resolve(scope)))
}
// Otherwise, take named arguments
else if let Some(narg) = nargs.shift_remove(name) {
(narg.0, Some(narg.1.resolve(scope, i + 1)))
(narg.0, Some(narg.1.try_resolve(scope)))
}
// Otherwise, use default
else {
Expand Down Expand Up @@ -458,10 +446,10 @@ impl std::fmt::Display for ImlValue {
),
Self::Variable {
name, is_global, ..
} if *is_global => write!(f, "global '{}'", name),
Self::Variable { name, .. } => write!(f, "local '{}'", name),
Self::Name { name, .. } => write!(f, "name '{}'", name),
Self::Generic { name, .. } => write!(f, "generic '{}'", name),
} if *is_global => write!(f, "{}", name),
Self::Variable { name, .. } => write!(f, "{}", name),
Self::Name { name, .. } => write!(f, "{}", name),
Self::Generic { name, .. } => write!(f, "{}", name),
Self::Instance {
target,
args,
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ impl<'compiler, 'parent> Scope<'compiler, 'parent> {

if name == "_" || name == "__" {
// `__` becomes `Value+`
value = value.into_generic("Pos", self, Some(0), None);
value = value.into_generic("Pos", Some(0), None).try_resolve(self);
secondary = Some(("__", value.clone()));

// ...and then in-place "_" is defined as `_ : __?`
value = value.into_generic("Opt", self, Some(0), None);
value = value.into_generic("Opt", Some(0), None).try_resolve(self);
}

// Insert constant into current scope
Expand Down
2 changes: 0 additions & 2 deletions tests/parselet_generic_selfref.tok
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ X: @<X> {
'x' X
}

Y<'a'> print("Ja!")
X<'x'> print("Jx!")
#---
#ERR:SKIP
#ERR:not yet implemented: Recursive resolve() impossible by design, see bug #127
Expand Down

0 comments on commit d0ecff6

Please sign in to comment.