diff --git a/src/compiler/ast.rs b/src/compiler/ast.rs index 1ceaa590..a7134bbe 100644 --- a/src/compiler/ast.rs +++ b/src/compiler/ast.rs @@ -333,10 +333,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option) -> ImlV let param = &genarg["children"].borrow(); let param = param.object::().unwrap(); - args.push(( - offset, - traverse_node_static(scope, None, param).try_resolve(scope), - )); + args.push((offset, traverse_node_static(scope, None, param))); } "genarg_named" => { @@ -361,10 +358,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option) -> ImlV nargs.insert( ident.to_string(), - ( - offset, - traverse_node_static(scope, None, param).try_resolve(scope), - ), + (offset, traverse_node_static(scope, None, param)), ); } @@ -372,6 +366,15 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option) -> ImlV } } + /* + if let Some(name) = &name { + println!( + "name = {} target = {:?} args = {:?} nargs = {:?}", + name, target, args, nargs + ); + } + */ + ImlValue::Instance { target: Box::new(target), args, @@ -380,7 +383,12 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option) -> ImlV severity: None, is_generated: false, } - .try_resolve(scope) + + /* + if let Some(_) = &name { + println!("ret = {:?}", ret); + } + */ } _ => unimplemented!("unhandled value node {}", emit), @@ -388,36 +396,47 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option) -> ImlV } /** 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, node: &Dict) -> ImlValue { +fn traverse_node_static(scope: &Scope, assign: Option, node: &Dict) -> ImlValue { let emit = node["emit"].borrow(); let emit = emit.object::().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, @@ -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 @@ -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, diff --git a/src/compiler/iml/imlvalue.rs b/src/compiler/iml/imlvalue.rs index 6d5c10ce..69c6121a 100644 --- a/src/compiler/iml/imlvalue.rs +++ b/src/compiler/iml/imlvalue.rs @@ -62,28 +62,18 @@ impl ImlValue { This is used internally to implement `Kle

` from `P*` syntax during the AST traversal. */ - pub fn into_generic( - self, - name: &str, - scope: &Scope, - severity: Option, - offset: Option, - ) -> Self { + pub fn into_generic(self, name: &str, severity: Option, offset: Option) -> 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 @@ -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 { .. } => { @@ -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) } /* @@ -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(); @@ -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 { @@ -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, diff --git a/src/compiler/scope.rs b/src/compiler/scope.rs index 2d40da68..fa97e770 100644 --- a/src/compiler/scope.rs +++ b/src/compiler/scope.rs @@ -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 diff --git a/tests/parselet_generic_selfref.tok b/tests/parselet_generic_selfref.tok index f6a90d35..c8e7bd02 100644 --- a/tests/parselet_generic_selfref.tok +++ b/tests/parselet_generic_selfref.tok @@ -4,8 +4,6 @@ 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