# HG changeset patch # User John W. Eaton # Date 1706196451 18000 # Thu Jan 25 10:27:31 2024 -0500 # Node ID 6bd930fef43c24d8a56982e63c4c19549ace95c3 # Parent e752cf76495101828b7b2f9a3b10d4c8efbf2b78 allow property initializers to use previously defined properties (bug #65214) * cdef-class.cc (cdef_class::make_meta_class): Use scope stored in tree_classdef object to create stack frame for evaluation. Also store assign property value in current stack frame during evaluation. * oct-parse.yy (base_parser::make_classdef): Set name of current symbol_scope and store it in the newly created tree_classdef object. Defer popping the current symbol table context until the end of the function. diff --git a/libinterp/octave-value/cdef-class.cc b/libinterp/octave-value/cdef-class.cc --- a/libinterp/octave-value/cdef-class.cc +++ b/libinterp/octave-value/cdef-class.cc @@ -885,15 +885,17 @@ cdef_class::make_meta_class (interpreter std::cerr << "class: " << full_class_name << std::endl; #endif - // Push a dummy scope frame on the call stack that corresponds to - // the scope that was used when parsing classdef object. Without - // this, we may pick up stray values from the current scope when - // evaluating expressions found in things like attribute lists. + // Push a frame on the call stack that uses the scope that was created + // when parsing classdef object. This stack frame allows us to + // evaluate property list initializer expressions refering to other + // properties that have been initialized. Without this, we may also + // pick up stray values from the current scope when evaluating + // expressions found in things like attribute lists. tree_evaluator& tw = interp.get_evaluator (); - tw.push_dummy_scope (full_class_name); - unwind_action pop_scope (&tree_evaluator::pop_scope, &tw); + tw.push_stack_frame (t->scope ()); + unwind_action pop_outer_scope (&tree_evaluator::pop_scope, &tw); std::list slist; @@ -1145,6 +1147,12 @@ cdef_class::make_meta_class (interpreter #endif prop.put ("DefaultValue", pvalue); + + // Also assign value in current stack frame so + // that it can be used in subsequent property + // initializer expressions. + + tw.assign (prop_name, pvalue); } // FIXME: instead of attaching attributes here, pass diff --git a/libinterp/parse-tree/oct-parse.yy b/libinterp/parse-tree/oct-parse.yy --- a/libinterp/parse-tree/oct-parse.yy +++ b/libinterp/parse-tree/oct-parse.yy @@ -1834,7 +1834,9 @@ classdef_beg : CLASSDEF YYABORT; } - // Create invalid parent scope. + // Create scope for classdef. We'll use this later + // for evaluating of expressions in properties blocks. + lexer.m_symtab_context.push (octave::symbol_scope::anonymous ()); lexer.m_parsing_classdef = true; lexer.m_parsing_classdef_decl = true; @@ -4339,13 +4341,15 @@ OCTAVE_BEGIN_NAMESPACE(octave) { tree_classdef *retval = nullptr; - m_lexer.m_symtab_context.pop (); - std::string cls_name = id->name (); std::string full_name = m_lexer.m_fcn_file_full_name; std::string short_name = m_lexer.m_fcn_file_name; + symbol_scope cls_scope = m_lexer.m_symtab_context.curr_scope (); + + cls_scope.cache_name (cls_name); + std::size_t pos = short_name.find_last_of (sys::file_ops::dir_sep_chars ()); @@ -4377,9 +4381,7 @@ OCTAVE_BEGIN_NAMESPACE(octave) if (! body) body = new tree_classdef_body (); - retval = new tree_classdef (m_lexer.m_symtab_context.curr_scope (), - a, id, sc, body, lc, tc, - m_curr_package_name, full_name, l, c); + retval = new tree_classdef (cls_scope, a, id, sc, body, lc, tc, m_curr_package_name, full_name, l, c); } else { @@ -4394,6 +4396,8 @@ OCTAVE_BEGIN_NAMESPACE(octave) } } + m_lexer.m_symtab_context.pop (); + return retval; }