From 1a09d1b0242915e77c64ec7917942fc7768d8eda Mon Sep 17 00:00:00 2001 From: Amir Hesamian Date: Thu, 3 Sep 2026 05:19:00 +0000 Subject: [PATCH 1/5] complex patterns in sequence are finally handled --- aps2scala/dump-scala.cc | 50 ++++++++++---- aps2scala/dump-scala.h | 1 + aps2scala/dyn-impl.cc | 147 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 174 insertions(+), 24 deletions(-) diff --git a/aps2scala/dump-scala.cc b/aps2scala/dump-scala.cc index 7c633cde..e71dce47 100644 --- a/aps2scala/dump-scala.cc +++ b/aps2scala/dump-scala.cc @@ -270,7 +270,9 @@ void dump_debug_end(ostream& os) // Output Scala pattern for APS pattern int formal_count = 0; -static void dump_pattern_call(Pattern p, Pattern result, const char* resultS, ostream& os) +static void dump_Pattern_impl(Pattern p, ostream& os, std::vector *conditions); + +static void dump_pattern_call(Pattern p, Pattern result, const char* resultS, ostream& os, std::vector *conditions = 0) { Pattern pf = pattern_call_func(p); PatternActuals pactuals = pattern_call_actuals(p); @@ -286,20 +288,35 @@ static void dump_pattern_call(Pattern p, Pattern result, const char* resultS, os dump_Use(pfuse,"p_",os); os << "("; if (result) { - dump_Pattern(result,os); + dump_Pattern_impl(result,os,conditions); } else { os << resultS; } formal_count = 0; for (Pattern pa = first_PatternActual(pactuals); pa ; pa = PAT_NEXT(pa)) { os << ","; - dump_Pattern(pa,os); + dump_Pattern_impl(pa,os,conditions); formal_count++; } os << ")"; } -void dump_Pattern(Pattern p, ostream& os) +void dump_sequence_element_pattern(Pattern p, ostream& os) +{ + std::vector conditions; + dump_Pattern_impl(p,os,&conditions); + if (!conditions.empty()) { + os << " if "; + bool started = false; + for (Expression condition : conditions) { + if (started) os << " && "; + else started = true; + dump_Expression(condition,os); + } + } +} + +static void dump_Pattern_impl(Pattern p, ostream& os, std::vector *conditions) { switch (Pattern_KEY(p)) { default: @@ -313,14 +330,14 @@ void dump_Pattern(Pattern p, ostream& os) break; case KEYpattern_var: break; } - dump_Pattern(match_pattern_pat(p),os); + dump_Pattern_impl(match_pattern_pat(p),os,conditions); os << ":"; dump_Type(match_pattern_type(p),os); break; case KEYpattern_call: { - dump_pattern_call(p,((Pattern)0),"_",os); + dump_pattern_call(p,((Pattern)0),"_",os,conditions); } break; @@ -342,18 +359,22 @@ void dump_Pattern(Pattern p, ostream& os) switch (Pattern_KEY(and_pattern_p2(p))) { default: break; case KEYcondition: - dump_Pattern(and_pattern_p1(p),os); - os << " if "; - dump_Expression(condition_e(and_pattern_p2(p)),os); + dump_Pattern_impl(and_pattern_p1(p),os,conditions); + if (conditions) { + conditions->push_back(condition_e(and_pattern_p2(p))); + } else { + os << " if "; + dump_Expression(condition_e(and_pattern_p2(p)),os); + } return; case KEYpattern_call: - dump_pattern_call(and_pattern_p2(p),and_pattern_p1(p),"",os); + dump_pattern_call(and_pattern_p2(p),and_pattern_p1(p),"",os,conditions); return; } os << "P_AND("; - dump_Pattern(and_pattern_p1(p),os); + dump_Pattern_impl(and_pattern_p1(p),os,conditions); os << ","; - dump_Pattern(and_pattern_p2(p),os); + dump_Pattern_impl(and_pattern_p2(p),os,conditions); os << ")"; break; @@ -379,6 +400,11 @@ void dump_Pattern(Pattern p, ostream& os) } } +void dump_Pattern(Pattern p, ostream& os) +{ + dump_Pattern_impl(p,os,0); +} + bool type_is_syntax(Type t) { diff --git a/aps2scala/dump-scala.h b/aps2scala/dump-scala.h index 5a17eb3c..f5a64a27 100644 --- a/aps2scala/dump-scala.h +++ b/aps2scala/dump-scala.h @@ -53,6 +53,7 @@ void dump_debug_end(ostream& os); // these two must always be called in pairs: the first // leaves information around for the second: void dump_Pattern(Pattern p, ostream&); +void dump_sequence_element_pattern(Pattern p, ostream&); // override << ostream& operator<<(ostream&o,Symbol s); diff --git a/aps2scala/dyn-impl.cc b/aps2scala/dyn-impl.cc index 3dbddc88..0c66ac31 100644 --- a/aps2scala/dyn-impl.cc +++ b/aps2scala/dyn-impl.cc @@ -40,6 +40,60 @@ static void *attr_context[MAXDEPTH]; static int attr_context_depth = 0; /* current depth of attribute assigns */ static int attr_context_started = 0; /* depth of last activation */ +static bool sequence_search_pattern(Pattern p, Pattern *middle) +{ + Symbol sequence_symbol = intern_symbol("{}"); + if (Pattern_KEY(p) != KEYpattern_call) return false; + + Pattern pf = pattern_call_func(p); + if (Pattern_KEY(pf) != KEYpattern_use) return false; + Declaration pfdecl = USE_DECL(pattern_use_use(pf)); + if (!pfdecl || def_name(declaration_def(pfdecl)) != sequence_symbol) return false; + + Pattern leading = first_PatternActual(pattern_call_actuals(p)); + Pattern element = leading ? PAT_NEXT(leading) : 0; + Pattern trailing = element ? PAT_NEXT(element) : 0; + if (!leading || Pattern_KEY(leading) != KEYrest_pattern || + Pattern_KEY(rest_pattern_constraint(leading)) != KEYno_pattern || + !element || !trailing || Pattern_KEY(trailing) != KEYrest_pattern || + Pattern_KEY(rest_pattern_constraint(trailing)) != KEYno_pattern || + PAT_NEXT(trailing)) { + return false; + } + + *middle = element; + return true; +} + +static void dump_sequence_elements(Pattern p, Expression value, ostream& os) +{ + Pattern pf = pattern_call_func(p); + dump_Use(pattern_use_use(pf),"p_",os); + os << ".unapplySeq("; + dump_Expression(value,os); + os << ").get._2"; +} + +static bool sequence_search_matcher(Declaration decl, Match *match, Pattern *middle) +{ + Matches matchers; + switch (Declaration_KEY(decl)) { + case KEYcase_stmt: + matchers = case_stmt_matchers(decl); + break; + case KEYfor_stmt: + matchers = for_stmt_matchers(decl); + break; + default: + return false; + } + Match first = first_Match(matchers); + if (!first || MATCH_NEXT(first)) return false; + if (!sequence_search_pattern(matcher_pat(first),middle)) return false; + if (match) *match = first; + return true; +} + static void push_attr_context(void *node) { if (attr_context_depth >= MAXDEPTH) { @@ -173,7 +227,7 @@ static void dump_context_close(void *c, ostream& os) { os << indent() << "}\n"; break; case KEYtop_level_match: - os << indent() << "case _ => {}\n"; + os << indent() << "case _ => {}\n"; /*FALLTHROUGH*/ default: --nesting_level; @@ -211,7 +265,7 @@ static void pop_attr_context(ostream& os) if (ABSTRACT_APS_tnode_phylum(p) == KEYDeclaration && Declaration_KEY((Declaration)p) == KEYcase_stmt && (Block)c == case_stmt_default((Declaration)p)) { - os << indent() << "case _ => {}\n"; + os << indent() << "case _ => {}\n"; } } } @@ -313,6 +367,59 @@ void dump_Matches(Matches ms, bool exclusive, ASSIGNFUNC f, void*arg, ostream&os ); } +static void dump_sequence_case(Declaration d, Match match, Pattern middle, + ASSIGNFUNC f, void *arg, ostream& os) +{ + activate_attr_context(os); + os << indent() << "{\n"; + ++nesting_level; + os << indent() << "val sequenceMatch = "; + dump_sequence_elements(matcher_pat(match),case_stmt_expr(d),os); + os << ".collectFirst {\n"; + ++nesting_level; + os << indent() << "case "; + dump_sequence_element_pattern(middle,os); + os << " => {\n"; + ++nesting_level; + dump_Block(matcher_body(match),f,arg,os); + os << indent() << "()\n"; + --nesting_level; + os << indent() << "}\n"; + --nesting_level; + os << indent() << "}\n"; + os << indent() << "if (sequenceMatch.isEmpty) {\n"; + ++nesting_level; + dump_Block(case_stmt_default(d),f,arg,os); + --nesting_level; + os << indent() << "}\n"; + --nesting_level; + os << indent() << "}\n"; +} + +static void dump_sequence_for(Declaration d, Match match, Pattern middle, + ASSIGNFUNC f, void *arg, ostream& os) +{ + activate_attr_context(os); + os << indent(); + dump_sequence_elements(matcher_pat(match),for_stmt_expr(d),os); + os << ".foreach { v_sequence_element =>\n"; + ++nesting_level; + os << indent() << "v_sequence_element match {\n"; + ++nesting_level; + os << indent() << "case "; + dump_sequence_element_pattern(middle,os); + os << " => {\n"; + ++nesting_level; + dump_Block(matcher_body(match),f,arg,os); + --nesting_level; + os << indent() << "}\n"; + os << indent() << "case _ => {}\n"; + --nesting_level; + os << indent() << "}\n"; + --nesting_level; + os << indent() << "}\n"; +} + void dump_Block(Block b,ASSIGNFUNC f,void*arg,ostream&os) { FOR_SEQUENCE @@ -335,18 +442,34 @@ void dump_Block(Block b,ASSIGNFUNC f,void*arg,ostream&os) pop_attr_context(os); break; case KEYcase_stmt: - push_attr_context(d); - //!! we implement case and for!! - dump_Matches(case_stmt_matchers(d),true,f,arg,os); - push_attr_context(case_stmt_default(d)); - dump_Block(case_stmt_default(d),f,arg,os); - pop_attr_context(os); - pop_attr_context(os); + { + Match match; + Pattern middle; + if (sequence_search_matcher(d,&match,&middle)) { + dump_sequence_case(d,match,middle,f,arg,os); + } else { + push_attr_context(d); + //!! we implement case and for!! + dump_Matches(case_stmt_matchers(d),true,f,arg,os); + push_attr_context(case_stmt_default(d)); + dump_Block(case_stmt_default(d),f,arg,os); + pop_attr_context(os); + pop_attr_context(os); + } + } break; case KEYfor_stmt: - push_attr_context(d); - dump_Matches(for_stmt_matchers(d),false,f,arg,os); - pop_attr_context(os); + { + Match match; + Pattern middle; + if (sequence_search_matcher(d,&match,&middle)) { + dump_sequence_for(d,match,middle,f,arg,os); + } else { + push_attr_context(d); + dump_Matches(for_stmt_matchers(d),false,f,arg,os); + pop_attr_context(os); + } + } break; case KEYvalue_decl: if (!(Declaration_info(d)->decl_flags & LOCAL_ATTRIBUTE_FLAG) && From f72d228eadadbf0ee1fa811645a6e4beb1465e28 Mon Sep 17 00:00:00 2001 From: Amir Hesamian Date: Thu, 3 Sep 2026 15:07:31 +0000 Subject: [PATCH 2/5] Complex sequence expressions are handled --- analyze/aps-dnc.c | 17 ++- aps2scala/dump-scala.cc | 40 +++++- aps2scala/dump-scala.h | 2 + aps2scala/dyn-impl.cc | 134 +++++++++++---------- codegen/static-scc-impl.cc | 95 ++++++++++++++- examples/scala/Makefile | 54 ++++++++- examples/scala/compare-evaluators.sh | 5 + examples/scala/simple-binding-driver.scala | 33 +++++ examples/scala/test-for-driver.scala | 16 +++ 9 files changed, 326 insertions(+), 70 deletions(-) create mode 100644 examples/scala/simple-binding-driver.scala create mode 100644 examples/scala/test-for-driver.scala diff --git a/analyze/aps-dnc.c b/analyze/aps-dnc.c index e3582770..9f99359f 100644 --- a/analyze/aps-dnc.c +++ b/analyze/aps-dnc.c @@ -455,10 +455,20 @@ static void *count_if_rules(void *pint, void *node) { ++*count; break; case KEYcase_stmt: + { for (m = first_Match(case_stmt_matchers(decl)); m; m=MATCH_NEXT(m)) { Match_info(m)->if_index = *count; ++*count; } + } + break; + case KEYfor_stmt: + { + for (m = first_Match(for_stmt_matchers(decl)); m; m=MATCH_NEXT(m)) { + Match_info(m)->if_index = *count; + ++*count; + } + } break; default: break; } @@ -477,7 +487,12 @@ static void *get_if_rules(void *varray, void *node) { array[Declaration_info(decl)->if_index] = decl; break; case KEYcase_stmt: - for (m = first_Match(case_stmt_matchers(decl)); m; m=MATCH_NEXT(m)) { + for (m = first_Match(case_stmt_matchers(decl)); m; m=MATCH_NEXT(m)) { + array[Match_info(m)->if_index] = m; + } + break; + case KEYfor_stmt: + for (m = first_Match(for_stmt_matchers(decl)); m; m=MATCH_NEXT(m)) { array[Match_info(m)->if_index] = m; } break; diff --git a/aps2scala/dump-scala.cc b/aps2scala/dump-scala.cc index e71dce47..cfc6e78d 100644 --- a/aps2scala/dump-scala.cc +++ b/aps2scala/dump-scala.cc @@ -316,6 +316,40 @@ void dump_sequence_element_pattern(Pattern p, ostream& os) } } +bool sequence_search_pattern(Pattern p, Pattern *middle) +{ + Symbol sequence_symbol = intern_symbol("{}"); + if (Pattern_KEY(p) != KEYpattern_call) return false; + + Pattern pf = pattern_call_func(p); + if (Pattern_KEY(pf) != KEYpattern_use) return false; + Declaration pfdecl = USE_DECL(pattern_use_use(pf)); + if (!pfdecl || def_name(declaration_def(pfdecl)) != sequence_symbol) return false; + + Pattern leading = first_PatternActual(pattern_call_actuals(p)); + Pattern element = leading ? PAT_NEXT(leading) : 0; + Pattern trailing = element ? PAT_NEXT(element) : 0; + if (!leading || Pattern_KEY(leading) != KEYrest_pattern || + Pattern_KEY(rest_pattern_constraint(leading)) != KEYno_pattern || + !element || !trailing || Pattern_KEY(trailing) != KEYrest_pattern || + Pattern_KEY(rest_pattern_constraint(trailing)) != KEYno_pattern || + PAT_NEXT(trailing)) { + return false; + } + + *middle = element; + return true; +} + +void dump_sequence_elements(Pattern p, Expression value, ostream& os) +{ + Pattern pf = pattern_call_func(p); + dump_Use(pattern_use_use(pf),"p_",os); + os << ".unapplySeq("; + dump_Expression(value,os); + os << ").get._2"; +} + static void dump_Pattern_impl(Pattern p, ostream& os, std::vector *conditions) { switch (Pattern_KEY(p)) { @@ -2015,11 +2049,11 @@ void dump_scala_Declaration(Declaration decl,ostream& oss) case KEYattribute_decl: break; // handled by module - case KEYfunction_decl: + case KEYsome_function_decl: { - Type fty = function_decl_type(decl); + Type fty = some_function_decl_type(decl); Declaration rdecl = first_Declaration(function_type_return_values(fty)); - Block b = function_decl_body(decl); + Block b = some_function_decl_body(decl); Declaration mdecl = get_enclosing_some_class_decl(decl); bool override_needed = false; if (mdecl != NULL) { diff --git a/aps2scala/dump-scala.h b/aps2scala/dump-scala.h index f5a64a27..e56450ca 100644 --- a/aps2scala/dump-scala.h +++ b/aps2scala/dump-scala.h @@ -54,6 +54,8 @@ void dump_debug_end(ostream& os); // leaves information around for the second: void dump_Pattern(Pattern p, ostream&); void dump_sequence_element_pattern(Pattern p, ostream&); +bool sequence_search_pattern(Pattern p, Pattern *middle); +void dump_sequence_elements(Pattern p, Expression value, ostream&); // override << ostream& operator<<(ostream&o,Symbol s); diff --git a/aps2scala/dyn-impl.cc b/aps2scala/dyn-impl.cc index 0c66ac31..6045f8b8 100644 --- a/aps2scala/dyn-impl.cc +++ b/aps2scala/dyn-impl.cc @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -40,40 +41,6 @@ static void *attr_context[MAXDEPTH]; static int attr_context_depth = 0; /* current depth of attribute assigns */ static int attr_context_started = 0; /* depth of last activation */ -static bool sequence_search_pattern(Pattern p, Pattern *middle) -{ - Symbol sequence_symbol = intern_symbol("{}"); - if (Pattern_KEY(p) != KEYpattern_call) return false; - - Pattern pf = pattern_call_func(p); - if (Pattern_KEY(pf) != KEYpattern_use) return false; - Declaration pfdecl = USE_DECL(pattern_use_use(pf)); - if (!pfdecl || def_name(declaration_def(pfdecl)) != sequence_symbol) return false; - - Pattern leading = first_PatternActual(pattern_call_actuals(p)); - Pattern element = leading ? PAT_NEXT(leading) : 0; - Pattern trailing = element ? PAT_NEXT(element) : 0; - if (!leading || Pattern_KEY(leading) != KEYrest_pattern || - Pattern_KEY(rest_pattern_constraint(leading)) != KEYno_pattern || - !element || !trailing || Pattern_KEY(trailing) != KEYrest_pattern || - Pattern_KEY(rest_pattern_constraint(trailing)) != KEYno_pattern || - PAT_NEXT(trailing)) { - return false; - } - - *middle = element; - return true; -} - -static void dump_sequence_elements(Pattern p, Expression value, ostream& os) -{ - Pattern pf = pattern_call_func(p); - dump_Use(pattern_use_use(pf),"p_",os); - os << ".unapplySeq("; - dump_Expression(value,os); - os << ").get._2"; -} - static bool sequence_search_matcher(Declaration decl, Match *match, Pattern *middle) { Matches matchers; @@ -350,12 +317,51 @@ void dump_local_decl(void *, Declaration local, ostream& o) dump_Expression(simple_value(init),o); break; default: - aps_error(local,"Can only handle initialized locals"); - o << "0"; + o << "null.asInstanceOf[" << value_decl_type(local) << "]"; } o << ";\n"; } +static bool block_assigns_to(Block b, void *vdecl) +{ + for (Declaration d = first_Declaration(block_body(b)); d; d = DECL_NEXT(d)) { + switch (Declaration_KEY(d)) { + case KEYassign: + { + Expression lhs = assign_lhs(d); + if (Expression_KEY(lhs) == KEYvalue_use && + USE_DECL(value_use_use(lhs)) == vdecl) return true; + if (Expression_KEY(lhs) == KEYfuncall && + USE_DECL(value_use_use(funcall_f(lhs))) == vdecl) return true; + } + break; + case KEYblock_stmt: + if (block_assigns_to(block_stmt_body(d),vdecl)) return true; + break; + case KEYif_stmt: + if (block_assigns_to(if_stmt_if_true(d),vdecl) || + block_assigns_to(if_stmt_if_false(d),vdecl)) return true; + break; + case KEYcase_stmt: + for (Match m = first_Match(case_stmt_matchers(d)); m; m = MATCH_NEXT(m)) { + if (block_assigns_to(matcher_body(m),vdecl)) return true; + } + if (block_assigns_to(case_stmt_default(d),vdecl)) return true; + break; + case KEYfor_stmt: + for (Match m = first_Match(for_stmt_matchers(d)); m; m = MATCH_NEXT(m)) { + if (block_assigns_to(matcher_body(m),vdecl)) return true; + } + break; + case KEYfor_in_stmt: + if (block_assigns_to(for_in_stmt_body(d),vdecl)) return true; + break; + default: + break; + } + } + return false; +} void dump_Matches(Matches ms, bool exclusive, ASSIGNFUNC f, void*arg, ostream&os) { @@ -370,10 +376,11 @@ void dump_Matches(Matches ms, bool exclusive, ASSIGNFUNC f, void*arg, ostream&os static void dump_sequence_case(Declaration d, Match match, Pattern middle, ASSIGNFUNC f, void *arg, ostream& os) { + unsigned sequence_number = (unsigned)(uintptr_t)match; activate_attr_context(os); os << indent() << "{\n"; ++nesting_level; - os << indent() << "val sequenceMatch = "; + os << indent() << "val sequenceMatch" << sequence_number << " = "; dump_sequence_elements(matcher_pat(match),case_stmt_expr(d),os); os << ".collectFirst {\n"; ++nesting_level; @@ -387,7 +394,7 @@ static void dump_sequence_case(Declaration d, Match match, Pattern middle, os << indent() << "}\n"; --nesting_level; os << indent() << "}\n"; - os << indent() << "if (sequenceMatch.isEmpty) {\n"; + os << indent() << "if (sequenceMatch" << sequence_number << ".isEmpty) {\n"; ++nesting_level; dump_Block(case_stmt_default(d),f,arg,os); --nesting_level; @@ -443,32 +450,35 @@ void dump_Block(Block b,ASSIGNFUNC f,void*arg,ostream&os) break; case KEYcase_stmt: { - Match match; - Pattern middle; - if (sequence_search_matcher(d,&match,&middle)) { - dump_sequence_case(d,match,middle,f,arg,os); - } else { - push_attr_context(d); - //!! we implement case and for!! - dump_Matches(case_stmt_matchers(d),true,f,arg,os); - push_attr_context(case_stmt_default(d)); - dump_Block(case_stmt_default(d),f,arg,os); - pop_attr_context(os); - pop_attr_context(os); - } + Match match; + Pattern middle; + if (sequence_search_matcher(d,&match,&middle) && + (block_assigns_to(matcher_body(match),arg) || + block_assigns_to(case_stmt_default(d),arg))) { + dump_sequence_case(d,match,middle,f,arg,os); + } else { + push_attr_context(d); + //!! we implement case and for!! + dump_Matches(case_stmt_matchers(d),true,f,arg,os); + push_attr_context(case_stmt_default(d)); + dump_Block(case_stmt_default(d),f,arg,os); + pop_attr_context(os); + pop_attr_context(os); + } } break; case KEYfor_stmt: { - Match match; - Pattern middle; - if (sequence_search_matcher(d,&match,&middle)) { - dump_sequence_for(d,match,middle,f,arg,os); - } else { - push_attr_context(d); - dump_Matches(for_stmt_matchers(d),false,f,arg,os); - pop_attr_context(os); - } + Match match; + Pattern middle; + if (sequence_search_matcher(d,&match,&middle) && + block_assigns_to(matcher_body(match),arg)) { + dump_sequence_for(d,match,middle,f,arg,os); + } else { + push_attr_context(d); + dump_Matches(for_stmt_matchers(d),false,f,arg,os); + pop_attr_context(os); + } } break; case KEYvalue_decl: @@ -843,9 +853,9 @@ class Dynamic : public Implementation } void implement_function_body(Declaration f, ostream& os) { - Type fty = function_decl_type(f); + Type fty = some_function_decl_type(f); Declaration rdecl = first_Declaration(function_type_return_values(fty)); - Block b = function_decl_body(f); + Block b = some_function_decl_body(f); bool is_col = direction_is_collection(value_decl_direction(rdecl)); const char *name = decl_name(f); diff --git a/codegen/static-scc-impl.cc b/codegen/static-scc-impl.cc index 74fa6f61..cde26fdb 100644 --- a/codegen/static-scc-impl.cc +++ b/codegen/static-scc-impl.cc @@ -1,4 +1,5 @@ #include +#include #include #include extern "C" { @@ -13,6 +14,12 @@ extern "C" { #include "dump.h" #include "implement.h" +#ifdef APS2SCALA +bool sequence_search_pattern(Pattern, Pattern*); +void dump_sequence_element_pattern(Pattern, ostream&); +void dump_sequence_elements(Pattern, Expression, ostream&); +#endif + #define LOCAL_VALUE_FLAG (1 << 28) #ifdef APS2SCALA @@ -551,6 +558,87 @@ static bool implement_visit_function( Match m = (Match)ad; Pattern p = matcher_pat(m); Declaration header = Match_info(m)->header; +#ifdef APS2SCALA + Pattern middle; + if (sequence_search_pattern(p, &middle)) { + bool is_for = Declaration_KEY(header) == KEYfor_stmt; + unsigned sequence_number = (unsigned)(uintptr_t)m; + Expression e = is_for ? for_stmt_expr(header) : case_stmt_expr(header); + if (is_for) { + ow->get_outstream() << indent(); + dump_sequence_elements(p, e, ow->get_outstream()); + ow->get_outstream() << ".foreach { v_sequence_element =>\n"; + ++nesting_level; + ow->get_outstream() << indent() << "v_sequence_element match {\n"; + ++nesting_level; + ow->get_outstream() << indent() << "case "; + dump_sequence_element_pattern(middle, ow->get_outstream()); + ow->get_outstream() << " => {\n"; + ++nesting_level; + } else { + ow->get_outstream() << indent() << "{\n"; + ++nesting_level; + ow->get_outstream() << indent() << "val sequenceMatch" + << sequence_number << " = "; + dump_sequence_elements(p, e, ow->get_outstream()); + ow->get_outstream() << ".collectFirst {\n"; + ++nesting_level; + ow->get_outstream() << indent() << "case "; + dump_sequence_element_pattern(middle, ow->get_outstream()); + ow->get_outstream() << " => {\n"; + ++nesting_level; + } + + Block true_block = matcher_body(m); + vector > true_assignment = + make_instance_assignment(aug_graph, true_block, + instance_assignment, false); + int cmask = 1 << if_rule_index(ad); + cond->positive |= cmask; + bool true_cont = implement_visit_function( + aug_graph, phase, cto->cto_if_true, true_assignment, nch, cond, + cto->chunk_index, loop_allowed, loop_id, + skip_previous_visit_code, ow); + cond->positive &= ~cmask; + --nesting_level; + ow->get_outstream() << indent() << "}\n"; + + if (is_for) { + ow->get_outstream() << indent() << "case _ => {}\n"; + --nesting_level; + ow->get_outstream() << indent() << "}\n"; + --nesting_level; + ow->get_outstream() << indent() << "}\n"; + } else { + --nesting_level; + ow->get_outstream() << indent() << "}\n"; + ow->get_outstream() << indent() << "if (sequenceMatch" + << sequence_number << ".isEmpty) {\n"; + ++nesting_level; + } + + Block false_block = is_for || MATCH_NEXT(m) + ? 0 : case_stmt_default(header); + vector > false_assignment = false_block + ? make_instance_assignment(aug_graph, false_block, + instance_assignment, false) + : instance_assignment; + cond->negative |= cmask; + bool false_cont = implement_visit_function( + aug_graph, phase, cto->cto_if_false, false_assignment, nch, cond, + cto->chunk_index, loop_allowed, loop_id, + skip_previous_visit_code, ow); + cond->negative &= ~cmask; + if (!is_for) { + --nesting_level; + ow->get_outstream() << indent() << "}\n"; + --nesting_level; + ow->get_outstream() << indent() << "}\n"; + } + loop_allowed = prev_loop_allowed; + return true_cont || false_cont; + } +#endif /* APS2SCALA */ // if first match in case, we evaluate variable: if (m == first_Match(case_stmt_matchers(header))) { Expression e = case_stmt_expr(header); @@ -818,7 +906,8 @@ static bool implement_visit_function( << "." << decl_name(ad) << " implicit.\n"; } } else if (rhs) { - if (Declaration_KEY(in->node) == KEYfunction_decl) { + if (Declaration_KEY(in->node) == KEYfunction_decl || + Declaration_KEY(in->node) == KEYprocedure_decl) { if (direction_is_collection(value_decl_direction(ad))) { std::cout << "Not expecting collection here!\n"; ow->get_outstream() @@ -1251,7 +1340,7 @@ static void* dump_scheduled_local(void* pbs, void* node) { static void dump_scheduled_function_body(Declaration fd, STATE* s, ostream& bs) { const char* name = decl_name(fd); - Type ft = function_decl_type(fd); + Type ft = some_function_decl_type(fd); // dump any local values: traverse_Declaration(dump_scheduled_local, &bs, fd); @@ -1278,7 +1367,7 @@ static void dump_scheduled_function_body(Declaration fd, STATE* s, ostream& bs) vector > default_instance_assignments( aug_graph->instances.length, std::set()); vector > instance_assignment = make_instance_assignment( - aug_graph, function_decl_body(fd), default_instance_assignments, true /* include defaults */); + aug_graph, some_function_decl_body(fd), default_instance_assignments, true /* include defaults */); CONDITION cond; cond.positive = 0; diff --git a/examples/scala/Makefile b/examples/scala/Makefile index 638ea7d0..271e44a3 100644 --- a/examples/scala/Makefile +++ b/examples/scala/Makefile @@ -30,7 +30,8 @@ AST_TREE_SCALAGEN = simple.scala tiny.scala grammar.scala \ EVALUATOR_EXAMPLES = classic-binding first follow nullable test-coll \ test-use-coll test-cycle test-fields use-global broad-fiber-cycle \ below-fiber-cycle below-single-fiber-cycle local-fiber-cycle nested-cycles \ - farrow-lv farrow-ubd farrow-ubd-fiber nested-ubd nested-ubd-fiber simple-snc + farrow-lv farrow-ubd farrow-ubd-fiber nested-ubd nested-ubd-fiber simple-snc \ + simple-binding simple-binding1 simple-binding2 simple-binding3 test-for SCALAGEN = ${AST_TREE_SCALAGEN} \ $(foreach example,${EVALUATOR_EXAMPLES},$(example).scala $(example).static.scala) @@ -65,6 +66,9 @@ all : ${OUT}/below_single_fiber_cycle_implicit.class ${OUT}/BelowSingleFiberCycl all : ${OUT}/local_fiber_cycle_implicit.class ${OUT}/LocalFiberCycleDriver.class all : ${OUT}/test_fields_implicit.class ${OUT}/TestFieldsDriver.class all : ${OUT}/simple_snc_implicit.class ${OUT}/SimpleSncDriver.class +all : ${OUT}/simple_binding_implicit.class ${OUT}/SimpleBindingDriver.class +all : SimpleBinding1Driver.class SimpleBinding2Driver.class SimpleBinding3Driver.class +all : ${OUT}/test_for_implicit.class ${OUT}/TestForDriver.class .PHONY: run @@ -366,6 +370,54 @@ ${OUT}/simple_snc_implicit.class : ${OUT}/simple-snc.class ${OUT}/simple_implici ${OUT}/SimpleSncDriver.class: ${OUT}/simple_snc_implicit.class ${OUT}/SimpleParser.class ${SCALAC} ${SCALACFLAGS} simple-snc-driver.scala +${OUT}/simple_binding_implicit.class : simple-binding${IMPL_SUFFIX} ${OUT}/simple_implicit.class + ${SCALAC} ${SCALACFLAGS} $< + @touch $@ + +${OUT}/SimpleBindingDriver.class : ${OUT}/simple_binding_implicit.class ${OUT}/SimpleParser.class simple-binding-driver.scala + ${SCALAC} ${SCALACFLAGS} simple-binding-driver.scala + +.PHONY: SimpleBinding1Driver.class SimpleBinding2Driver.class SimpleBinding3Driver.class + +SimpleBinding1Driver.class : ${OUT}/simple-binding1/SimpleBindingDriver.class ; + +${OUT}/simple-binding1/SimpleBindingDriver.class : simple.scala simple-binding1${IMPL_SUFFIX} simple-binding-driver.scala ${OUT}/SimpleParser.class + rm -rf ${OUT}/simple-binding1 + mkdir -p ${OUT}/simple-binding1 + ${SCALAC} -cp .:${OUT}/simple-binding1:${OUT}:${APSLIB} -d ${OUT}/simple-binding1 simple.scala simple-binding1${IMPL_SUFFIX} simple-binding-driver.scala + +SimpleBinding2Driver.class : ${OUT}/simple-binding2/SimpleBindingDriver.class ; + +${OUT}/simple-binding2/SimpleBindingDriver.class : simple.scala simple-binding2${IMPL_SUFFIX} simple-binding-driver.scala ${OUT}/SimpleParser.class + rm -rf ${OUT}/simple-binding2 + mkdir -p ${OUT}/simple-binding2 + ${SCALAC} -cp .:${OUT}/simple-binding2:${OUT}:${APSLIB} -d ${OUT}/simple-binding2 simple.scala simple-binding2${IMPL_SUFFIX} simple-binding-driver.scala + +SimpleBinding3Driver.class : ${OUT}/simple-binding3/SimpleBindingDriver.class ; + +${OUT}/simple-binding3/SimpleBindingDriver.class : simple.scala simple-binding3${IMPL_SUFFIX} simple-binding-driver.scala ${OUT}/SimpleParser.class + rm -rf ${OUT}/simple-binding3 + mkdir -p ${OUT}/simple-binding3 + ${SCALAC} -cp .:${OUT}/simple-binding3:${OUT}:${APSLIB} -d ${OUT}/simple-binding3 simple.scala simple-binding3${IMPL_SUFFIX} simple-binding-driver.scala + +${OUT}/test_for_implicit.class : test-for${IMPL_SUFFIX} ${OUT}/tiny_implicit.class + ${SCALAC} ${SCALACFLAGS} $< + @touch $@ + +${OUT}/TestForDriver.class : ${OUT}/test_for_implicit.class ${OUT}/TinyParser.class test-for-driver.scala + ${SCALAC} ${SCALACFLAGS} test-for-driver.scala + +.PHONY: SimpleBinding1Driver.run SimpleBinding2Driver.run SimpleBinding3Driver.run + +SimpleBinding1Driver.run : ${OUT}/simple-binding1/SimpleBindingDriver.class + ${SCALA} ${JVMFLAGS} -cp .:${OUT}/simple-binding1:${APSLIB} SimpleBindingDriver ${ARGS} + +SimpleBinding2Driver.run : ${OUT}/simple-binding2/SimpleBindingDriver.class + ${SCALA} ${JVMFLAGS} -cp .:${OUT}/simple-binding2:${APSLIB} SimpleBindingDriver ${ARGS} + +SimpleBinding3Driver.run : ${OUT}/simple-binding3/SimpleBindingDriver.class + ${SCALA} ${JVMFLAGS} -cp .:${OUT}/simple-binding3:${APSLIB} SimpleBindingDriver ${ARGS} + .PHONY: %.run %.run : ${OUT}/%.class diff --git a/examples/scala/compare-evaluators.sh b/examples/scala/compare-evaluators.sh index 1d33d650..fdf19f25 100755 --- a/examples/scala/compare-evaluators.sh +++ b/examples/scala/compare-evaluators.sh @@ -113,6 +113,11 @@ TESTS=( "FollowDriver|grammar.cfg|$DEFAULT_EVALUATORS" "NullableDriver|grammar.cfg|$DEFAULT_EVALUATORS" "SimpleSncDriver|simple.program|DYNAMIC" + "SimpleBindingDriver|simple.program|$DEFAULT_EVALUATORS" + "SimpleBinding1Driver|simple.program|$DEFAULT_EVALUATORS" + "SimpleBinding2Driver|simple.program|$DEFAULT_EVALUATORS" + "SimpleBinding3Driver|simple.program|$DEFAULT_EVALUATORS" + "TestForDriver|tiny.program|$DEFAULT_EVALUATORS" ) failures=0 diff --git a/examples/scala/simple-binding-driver.scala b/examples/scala/simple-binding-driver.scala new file mode 100644 index 00000000..b2ef87ee --- /dev/null +++ b/examples/scala/simple-binding-driver.scala @@ -0,0 +1,33 @@ +object SimpleBindingDriver extends App { + var tree: M_SIMPLE = null + if (args.length == 0) { + tree = new M_SIMPLE("Simple") + val simple = tree.t_Result + val declarations = simple.v_xcons_decls( + simple.v_no_decls(), + simple.v_decl("x", simple.v_integer_type())) + val statement = simple.v_assign_stmt( + simple.v_variable("x"), + simple.v_variable("y")) + val statements = simple.v_xcons_stmts(simple.v_no_stmts(), statement) + simple.v_program(simple.v_block(declarations, statements)) + } else { + val scanner = new SimpleScanner(new java.io.FileReader(args(0))) + val parser = new SimpleParser() + parser.reset(scanner, args(0)) + if (!parser.yyparse()) { + println("Errors found.") + System.exit(1) + } + tree = parser.getTree() + } + + val simpleTree = tree + val binding = new M_NAME_RESOLUTION[simpleTree.T_Result]("Binding", simpleTree.t_Result) + + simpleTree.finish() + binding.finish() + + println("Results:") + binding.v_msgs.toSeq.sorted.foreach(println) +} \ No newline at end of file diff --git a/examples/scala/test-for-driver.scala b/examples/scala/test-for-driver.scala new file mode 100644 index 00000000..0edf7282 --- /dev/null +++ b/examples/scala/test-for-driver.scala @@ -0,0 +1,16 @@ +object TestForDriver extends App { + val tree = new M_TINY("Tiny") + val parser = new TinyParser(tree) + val root = if (args.length > 0) { + parser.parseFile(args(0)) + } else { + tree.v_root(tree.v_branch(tree.v_leaf(3), tree.v_leaf(9))) + } + val test = new M_TEST_FOR[tree.T_Result]("Test For", tree) + + tree.finish() + test.finish() + + println("Results:") + println(test.v_answer(root.asInstanceOf[test.T_Root])) +} \ No newline at end of file From 91d1697ca38e22990f160bbf06d346263876f5f1 Mon Sep 17 00:00:00 2001 From: Amir Hesamian Date: Thu, 3 Sep 2026 15:58:08 +0000 Subject: [PATCH 3/5] Fixed makefile --- examples/scala/Makefile | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/scala/Makefile b/examples/scala/Makefile index 271e44a3..f61bfdea 100644 --- a/examples/scala/Makefile +++ b/examples/scala/Makefile @@ -375,7 +375,7 @@ ${OUT}/simple_binding_implicit.class : simple-binding${IMPL_SUFFIX} ${OUT}/simpl @touch $@ ${OUT}/SimpleBindingDriver.class : ${OUT}/simple_binding_implicit.class ${OUT}/SimpleParser.class simple-binding-driver.scala - ${SCALAC} ${SCALACFLAGS} simple-binding-driver.scala + ${SCALAC} -cp ${OUT}:.:${APSLIB} -d ${OUT} simple-binding-driver.scala .PHONY: SimpleBinding1Driver.class SimpleBinding2Driver.class SimpleBinding3Driver.class @@ -384,21 +384,21 @@ SimpleBinding1Driver.class : ${OUT}/simple-binding1/SimpleBindingDriver.class ; ${OUT}/simple-binding1/SimpleBindingDriver.class : simple.scala simple-binding1${IMPL_SUFFIX} simple-binding-driver.scala ${OUT}/SimpleParser.class rm -rf ${OUT}/simple-binding1 mkdir -p ${OUT}/simple-binding1 - ${SCALAC} -cp .:${OUT}/simple-binding1:${OUT}:${APSLIB} -d ${OUT}/simple-binding1 simple.scala simple-binding1${IMPL_SUFFIX} simple-binding-driver.scala + ${SCALAC} -cp ${OUT}/simple-binding1:${OUT}:.:${APSLIB} -d ${OUT}/simple-binding1 simple.scala simple-binding1${IMPL_SUFFIX} simple-binding-driver.scala SimpleBinding2Driver.class : ${OUT}/simple-binding2/SimpleBindingDriver.class ; ${OUT}/simple-binding2/SimpleBindingDriver.class : simple.scala simple-binding2${IMPL_SUFFIX} simple-binding-driver.scala ${OUT}/SimpleParser.class rm -rf ${OUT}/simple-binding2 mkdir -p ${OUT}/simple-binding2 - ${SCALAC} -cp .:${OUT}/simple-binding2:${OUT}:${APSLIB} -d ${OUT}/simple-binding2 simple.scala simple-binding2${IMPL_SUFFIX} simple-binding-driver.scala + ${SCALAC} -cp ${OUT}/simple-binding2:${OUT}:.:${APSLIB} -d ${OUT}/simple-binding2 simple.scala simple-binding2${IMPL_SUFFIX} simple-binding-driver.scala SimpleBinding3Driver.class : ${OUT}/simple-binding3/SimpleBindingDriver.class ; ${OUT}/simple-binding3/SimpleBindingDriver.class : simple.scala simple-binding3${IMPL_SUFFIX} simple-binding-driver.scala ${OUT}/SimpleParser.class rm -rf ${OUT}/simple-binding3 mkdir -p ${OUT}/simple-binding3 - ${SCALAC} -cp .:${OUT}/simple-binding3:${OUT}:${APSLIB} -d ${OUT}/simple-binding3 simple.scala simple-binding3${IMPL_SUFFIX} simple-binding-driver.scala + ${SCALAC} -cp ${OUT}/simple-binding3:${OUT}:.:${APSLIB} -d ${OUT}/simple-binding3 simple.scala simple-binding3${IMPL_SUFFIX} simple-binding-driver.scala ${OUT}/test_for_implicit.class : test-for${IMPL_SUFFIX} ${OUT}/tiny_implicit.class ${SCALAC} ${SCALACFLAGS} $< @@ -409,14 +409,17 @@ ${OUT}/TestForDriver.class : ${OUT}/test_for_implicit.class ${OUT}/TinyParser.cl .PHONY: SimpleBinding1Driver.run SimpleBinding2Driver.run SimpleBinding3Driver.run +SimpleBindingDriver.run : ${OUT}/SimpleBindingDriver.class + ${SCALA} ${JVMFLAGS} -cp ${OUT}:.:${APSLIB} SimpleBindingDriver ${ARGS} + SimpleBinding1Driver.run : ${OUT}/simple-binding1/SimpleBindingDriver.class - ${SCALA} ${JVMFLAGS} -cp .:${OUT}/simple-binding1:${APSLIB} SimpleBindingDriver ${ARGS} + ${SCALA} ${JVMFLAGS} -cp ${OUT}/simple-binding1:${OUT}:.:${APSLIB} SimpleBindingDriver ${ARGS} SimpleBinding2Driver.run : ${OUT}/simple-binding2/SimpleBindingDriver.class - ${SCALA} ${JVMFLAGS} -cp .:${OUT}/simple-binding2:${APSLIB} SimpleBindingDriver ${ARGS} + ${SCALA} ${JVMFLAGS} -cp ${OUT}/simple-binding2:${OUT}:.:${APSLIB} SimpleBindingDriver ${ARGS} SimpleBinding3Driver.run : ${OUT}/simple-binding3/SimpleBindingDriver.class - ${SCALA} ${JVMFLAGS} -cp .:${OUT}/simple-binding3:${APSLIB} SimpleBindingDriver ${ARGS} + ${SCALA} ${JVMFLAGS} -cp ${OUT}/simple-binding3:${OUT}:.:${APSLIB} SimpleBindingDriver ${ARGS} .PHONY: %.run From 8a3f0af71cc18f43e717fad86bbe3a5a0ca0ba2f Mon Sep 17 00:00:00 2001 From: Amir Hesamian Date: Mon, 7 Sep 2026 20:06:47 +0000 Subject: [PATCH 4/5] C++ infra working --- aps2scala/dump-scala.cc | 25 ------------ aps2scala/dump-scala.h | 1 - aps2scala/dyn-impl.cc | 61 ----------------------------- codegen/implement.cc | 86 +++++++++++++++++++++++++++++++++++++++++ codegen/implement.h | 4 ++ 5 files changed, 90 insertions(+), 87 deletions(-) diff --git a/aps2scala/dump-scala.cc b/aps2scala/dump-scala.cc index cfc6e78d..d8360476 100644 --- a/aps2scala/dump-scala.cc +++ b/aps2scala/dump-scala.cc @@ -316,31 +316,6 @@ void dump_sequence_element_pattern(Pattern p, ostream& os) } } -bool sequence_search_pattern(Pattern p, Pattern *middle) -{ - Symbol sequence_symbol = intern_symbol("{}"); - if (Pattern_KEY(p) != KEYpattern_call) return false; - - Pattern pf = pattern_call_func(p); - if (Pattern_KEY(pf) != KEYpattern_use) return false; - Declaration pfdecl = USE_DECL(pattern_use_use(pf)); - if (!pfdecl || def_name(declaration_def(pfdecl)) != sequence_symbol) return false; - - Pattern leading = first_PatternActual(pattern_call_actuals(p)); - Pattern element = leading ? PAT_NEXT(leading) : 0; - Pattern trailing = element ? PAT_NEXT(element) : 0; - if (!leading || Pattern_KEY(leading) != KEYrest_pattern || - Pattern_KEY(rest_pattern_constraint(leading)) != KEYno_pattern || - !element || !trailing || Pattern_KEY(trailing) != KEYrest_pattern || - Pattern_KEY(rest_pattern_constraint(trailing)) != KEYno_pattern || - PAT_NEXT(trailing)) { - return false; - } - - *middle = element; - return true; -} - void dump_sequence_elements(Pattern p, Expression value, ostream& os) { Pattern pf = pattern_call_func(p); diff --git a/aps2scala/dump-scala.h b/aps2scala/dump-scala.h index e56450ca..d5f040ea 100644 --- a/aps2scala/dump-scala.h +++ b/aps2scala/dump-scala.h @@ -54,7 +54,6 @@ void dump_debug_end(ostream& os); // leaves information around for the second: void dump_Pattern(Pattern p, ostream&); void dump_sequence_element_pattern(Pattern p, ostream&); -bool sequence_search_pattern(Pattern p, Pattern *middle); void dump_sequence_elements(Pattern p, Expression value, ostream&); // override << diff --git a/aps2scala/dyn-impl.cc b/aps2scala/dyn-impl.cc index 6045f8b8..6b83f323 100644 --- a/aps2scala/dyn-impl.cc +++ b/aps2scala/dyn-impl.cc @@ -41,26 +41,6 @@ static void *attr_context[MAXDEPTH]; static int attr_context_depth = 0; /* current depth of attribute assigns */ static int attr_context_started = 0; /* depth of last activation */ -static bool sequence_search_matcher(Declaration decl, Match *match, Pattern *middle) -{ - Matches matchers; - switch (Declaration_KEY(decl)) { - case KEYcase_stmt: - matchers = case_stmt_matchers(decl); - break; - case KEYfor_stmt: - matchers = for_stmt_matchers(decl); - break; - default: - return false; - } - Match first = first_Match(matchers); - if (!first || MATCH_NEXT(first)) return false; - if (!sequence_search_pattern(matcher_pat(first),middle)) return false; - if (match) *match = first; - return true; -} - static void push_attr_context(void *node) { if (attr_context_depth >= MAXDEPTH) { @@ -322,47 +302,6 @@ void dump_local_decl(void *, Declaration local, ostream& o) o << ";\n"; } -static bool block_assigns_to(Block b, void *vdecl) -{ - for (Declaration d = first_Declaration(block_body(b)); d; d = DECL_NEXT(d)) { - switch (Declaration_KEY(d)) { - case KEYassign: - { - Expression lhs = assign_lhs(d); - if (Expression_KEY(lhs) == KEYvalue_use && - USE_DECL(value_use_use(lhs)) == vdecl) return true; - if (Expression_KEY(lhs) == KEYfuncall && - USE_DECL(value_use_use(funcall_f(lhs))) == vdecl) return true; - } - break; - case KEYblock_stmt: - if (block_assigns_to(block_stmt_body(d),vdecl)) return true; - break; - case KEYif_stmt: - if (block_assigns_to(if_stmt_if_true(d),vdecl) || - block_assigns_to(if_stmt_if_false(d),vdecl)) return true; - break; - case KEYcase_stmt: - for (Match m = first_Match(case_stmt_matchers(d)); m; m = MATCH_NEXT(m)) { - if (block_assigns_to(matcher_body(m),vdecl)) return true; - } - if (block_assigns_to(case_stmt_default(d),vdecl)) return true; - break; - case KEYfor_stmt: - for (Match m = first_Match(for_stmt_matchers(d)); m; m = MATCH_NEXT(m)) { - if (block_assigns_to(matcher_body(m),vdecl)) return true; - } - break; - case KEYfor_in_stmt: - if (block_assigns_to(for_in_stmt_body(d),vdecl)) return true; - break; - default: - break; - } - } - return false; -} - void dump_Matches(Matches ms, bool exclusive, ASSIGNFUNC f, void*arg, ostream&os) { FOR_SEQUENCE diff --git a/codegen/implement.cc b/codegen/implement.cc index 1347cd86..e2d8739d 100644 --- a/codegen/implement.cc +++ b/codegen/implement.cc @@ -45,3 +45,89 @@ void clear_implementation_marks(Declaration d) { int nothing; traverse_Declaration(clear_impl_marks,¬hing,d); } + +bool sequence_search_pattern(Pattern p, Pattern *middle) +{ + Symbol sequence_symbol = intern_symbol("{}"); + if (Pattern_KEY(p) != KEYpattern_call) return false; + + Pattern pf = pattern_call_func(p); + if (Pattern_KEY(pf) != KEYpattern_use) return false; + Declaration pfdecl = USE_DECL(pattern_use_use(pf)); + if (!pfdecl || def_name(declaration_def(pfdecl)) != sequence_symbol) return false; + + Pattern leading = first_PatternActual(pattern_call_actuals(p)); + Pattern element = leading ? PAT_NEXT(leading) : 0; + Pattern trailing = element ? PAT_NEXT(element) : 0; + if (!leading || Pattern_KEY(leading) != KEYrest_pattern || + Pattern_KEY(rest_pattern_constraint(leading)) != KEYno_pattern || + !element || !trailing || Pattern_KEY(trailing) != KEYrest_pattern || + Pattern_KEY(rest_pattern_constraint(trailing)) != KEYno_pattern || + PAT_NEXT(trailing)) { + return false; + } + + *middle = element; + return true; +} + +bool sequence_search_matcher(Declaration decl, Match *match, Pattern *middle) +{ + Matches matchers; + switch (Declaration_KEY(decl)) { + case KEYcase_stmt: + matchers = case_stmt_matchers(decl); + break; + case KEYfor_stmt: + matchers = for_stmt_matchers(decl); + break; + default: + return false; + } + Match first = first_Match(matchers); + if (!first || MATCH_NEXT(first)) return false; + if (!sequence_search_pattern(matcher_pat(first),middle)) return false; + if (match) *match = first; + return true; +} + +bool block_assigns_to(Block b, void *vdecl) +{ + for (Declaration d = first_Declaration(block_body(b)); d; d = DECL_NEXT(d)) { + switch (Declaration_KEY(d)) { + case KEYassign: + { + Expression lhs = assign_lhs(d); + if (Expression_KEY(lhs) == KEYvalue_use && + USE_DECL(value_use_use(lhs)) == vdecl) return true; + if (Expression_KEY(lhs) == KEYfuncall && + USE_DECL(value_use_use(funcall_f(lhs))) == vdecl) return true; + } + break; + case KEYblock_stmt: + if (block_assigns_to(block_stmt_body(d),vdecl)) return true; + break; + case KEYif_stmt: + if (block_assigns_to(if_stmt_if_true(d),vdecl) || + block_assigns_to(if_stmt_if_false(d),vdecl)) return true; + break; + case KEYcase_stmt: + for (Match m = first_Match(case_stmt_matchers(d)); m; m = MATCH_NEXT(m)) { + if (block_assigns_to(matcher_body(m),vdecl)) return true; + } + if (block_assigns_to(case_stmt_default(d),vdecl)) return true; + break; + case KEYfor_stmt: + for (Match m = first_Match(for_stmt_matchers(d)); m; m = MATCH_NEXT(m)) { + if (block_assigns_to(matcher_body(m),vdecl)) return true; + } + break; + case KEYfor_in_stmt: + if (block_assigns_to(for_in_stmt_body(d),vdecl)) return true; + break; + default: + break; + } + } + return false; +} diff --git a/codegen/implement.h b/codegen/implement.h index 22314831..9f4bc6be 100644 --- a/codegen/implement.h +++ b/codegen/implement.h @@ -83,4 +83,8 @@ extern Implementation *static_scc_impl; void clear_implementation_marks(Declaration d); +bool sequence_search_pattern(Pattern p, Pattern *middle); +bool sequence_search_matcher(Declaration decl, Match *match, Pattern *middle); +bool block_assigns_to(Block b, void *vdecl); + #endif From 16f91cff77e0214d638c7019421bdf682c3199d9 Mon Sep 17 00:00:00 2001 From: Amir Hesamian Date: Tue, 8 Sep 2026 23:56:56 +0000 Subject: [PATCH 5/5] revert format changes, make PR surgical --- aps2scala/dyn-impl.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aps2scala/dyn-impl.cc b/aps2scala/dyn-impl.cc index 6b83f323..37006832 100644 --- a/aps2scala/dyn-impl.cc +++ b/aps2scala/dyn-impl.cc @@ -174,7 +174,7 @@ static void dump_context_close(void *c, ostream& os) { os << indent() << "}\n"; break; case KEYtop_level_match: - os << indent() << "case _ => {}\n"; + os << indent() << "case _ => {}\n"; /*FALLTHROUGH*/ default: --nesting_level; @@ -212,7 +212,7 @@ static void pop_attr_context(ostream& os) if (ABSTRACT_APS_tnode_phylum(p) == KEYDeclaration && Declaration_KEY((Declaration)p) == KEYcase_stmt && (Block)c == case_stmt_default((Declaration)p)) { - os << indent() << "case _ => {}\n"; + os << indent() << "case _ => {}\n"; } } } @@ -302,6 +302,7 @@ void dump_local_decl(void *, Declaration local, ostream& o) o << ";\n"; } + void dump_Matches(Matches ms, bool exclusive, ASSIGNFUNC f, void*arg, ostream&os) { FOR_SEQUENCE