Patch title: Release 85 bulk changes
Abstract:
File: /pliant/language/parser/engine.c
Key:
    Removed line
    Added line
// Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// version 2 along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

/*
abstract
  text "Pliant parser engine."
*/
 

FUNCTION Void ParserContext_position(struct ParserContext *context,struct ListingPosition *position) {
  ListingPosition_set(context->module,context->y+1+context->delta_y,context->x+1+context->delta_x,position); }


FUNCTION Void ParserContext_set_root(struct ParserContext *context) {
  struct Expression *e;
  e=(struct Expression *)entry_new(G.type_Expression);
  Arrow_set((Arrow *)&e->module,context->module);
  ParserContext_position(context,&e->position);
  Arrow_set(&e->value,entry(G.type_Ident,"{}",END));
  Arrow_set((Arrow *)&context->root,e);
  context->current_expr=e; }


FUNCTION struct Expression *ParserContext_add_token(struct ParserContext *context,Address value) {
  struct Expression *e; Int i;
  e=(struct Expression *)entry_new(G.type_Expression);
  Arrow_set((Arrow *)&e->module,context->module);
  ParserContext_position(context,&e->position);
  Arrow_set(&e->value,value);
  i=context->current_expr->arguments.nb; Array_extend(&context->current_expr->arguments,i+1);
  Array_set_index(&context->current_expr->arguments,i,e);
  return e; }


FUNCTION struct Expression *ParserContext_add_ident(struct ParserContext *context,struct Str *ident) {
  struct Str *id;
  id=(struct Str *)entry_new(G.type_Ident);
  Str_copy(ident,id);
  return ParserContext_add_token(context,id); }


FUNCTION Void ParserContext_open_sublevel(struct ParserContext *context,struct Str *closeop) {
  struct Str *co;
  List_append(&context->levels,context->current_expr);
  context->current_expr=Array_get_index(&context->current_expr->arguments,context->current_expr->arguments.nb-1);
  co=entry_new(G.type_Str); Str_copy(closeop,co); Arrow_set((Arrow *)&context->current_expr->closeop,co); }


FUNCTION Void ParserContext_close_sublevel(struct ParserContext *context,struct Str *closeop) {
  Arrow *c;
  Array_resize(&context->current_expr->arguments,context->current_expr->arguments.nb);
  if(context->current_expr->closeop==null) {
    error_notifyn(error_id_compile,Z,"Unmatched ",S,closeop,Z," operator",END);
    return; }
  if(compare_str(closeop,context->current_expr->closeop)!=compare_equal) {
    error_notifyn(error_id_compile,Z,"Expected ",S,context->current_expr->closeop,Z," instead of ",S,closeop,END);
    return; }
  Arrow_set((Arrow *)&context->current_expr->closeop,null);
  c=List_last(&context->levels); context->current_expr=*c; 
  if(c!=G.null_constant) List_remove(&context->levels,c); }


FUNCTION Void ParserContext_forward(struct ParserContext *context,Int nb_chars) {
  context->x+=nb_chars; }


/*****************************************************************************/


FUNCTION Void ParserContext_add_pending(struct ParserContext *context,Int y,Int x,struct Function *function,Address parameter) {
  struct List *pendings; struct Str temp; Arrow *c; struct ParserPending *p,*p2;
  c=Dictionary_first(&context->locals,Str_map_string(&temp,"pliant pendings"));
  if(c!=G.null_constant && entry_type(*c)==G.type_List) {
    pendings=(struct List *)*c;
  other
    pendings=(struct List *)entry_new(G.type_List);
    Dictionary_insert(&context->locals,&temp,true,pendings); }
  p=(struct ParserPending *)entry_new(G.type_ParserPending);
  p->y=y,p->x=x;
  Arrow_set((Arrow *)&p->function,function);
  Arrow_set(&p->parameter,parameter);
  for(c=List_first(pendings); c!=G.null_constant; c=List_next(c)) {
    p2=(struct ParserPending *)*c;
    if(p2->y>y || (p2->y==y && p2->x>x)) break; }
  List_insert_before(pendings,c,p); }


static Void parser_filter_handle_pendings(struct ParserContext *context,struct Str *line,Address drop) {
  struct List *pendings; struct Str temp; Arrow *c; struct ParserPending *p;
  c=Dictionary_first(&context->locals,Str_map_string(&temp,"pliant pendings"));
  if(c==G.null_constant || entry_type(*c)!=G.type_List) return;
  pendings=(struct List *)*c;
  for(;;) {
    c=List_first(pendings); if(c==G.null_constant) break;
    p=(struct ParserPending *)*c;
    if(p->y>context->y) break;
    if(p->y==context->y && p->x>context->x) break;
    ((ParserPendingPrototype)p->function->exe)(context,p->parameter);
    List_remove(pendings,c); } }


static Void ParserContext_fold_operators(struct Array *arguments) {
  Int i; struct Expression *e;
  Int best_i; struct Expression *best_e; Int best_priority;
  for(;;) {
    best_e=null; best_priority=int_min;
    for(i=0; i<arguments->nb; i++) {
      e=(struct Expression *)Array_get_index(arguments,i); check(entry_type(e)==G.type_Expression);
      if(e->op!=null && e->op->priority>best_priority)
        best_i=i,best_e=e,best_priority=e->op->priority; }
    if(best_e==null) break;
    ((ParserOperatorPrototype)best_e->op->function->exe)(arguments,best_i,best_e->op->parameter);
    Arrow_set((Arrow *)&best_e->op,null); }
  for(i=0; i<arguments->nb; i++) {
    e=(struct Expression *)Array_get_index(arguments,i);
    if(e->arguments.nb!=0)
      ParserContext_fold_operators(&e->arguments); } }


static Void rec_precompile_rewrite(struct Expression *e) {
  Int i;
  for(i=0; i<e->arguments.nb; i++)
    rec_precompile_rewrite(EARG(e,i)); 
  Expression_precompile_rewrite(e); }

FUNCTION Void ParserContext_rearrange(struct ParserContext *context) {
  ParserContext_fold_operators(&context->root->arguments);
  rec_precompile_rewrite(context->root); }
static Void default_pre_execute(struct Expression *e) {}

FUNCTION Void ParserContext_execute(struct ParserContext *context) {
  ParserContext_fold_operators(&context->root->arguments);
  rec_precompile_rewrite(context->root); 
  (*G.pre_execute_hook)(context->root);
  Expression_execute(context->root);
  ParserContext_set_root(context);
  context->possible_side_effect=true; }


static Void parser_filter_execute(struct ParserContext *context,struct Str *line,Address drop) {
  Arrow *c; struct Str temp; struct Str *id;
  if(context->current_expr!=context->root) return;
  for(c=Module_first(context->module,Str_map_string(&temp,"pliant continue")); c!=G.null_constant; c=Module_next(context->module,&temp,c)) {
    check(entry_type(*c)==G.type_Ident);
    id=(struct Str *)*c;
    if(Str_len(line)>=Str_len(id) && memory_compare(line->chars,Str_len(id),id->chars,Str_len(id))==compare_equal && (Str_len(line)==Str_len(id) || !isidentdigit(id->chars[0]) || !isidentdigit(line->chars[Str_len(id)]))) return; }
  if(context->root->arguments.nb!=0){
    ParserContext_rearrange(context);
    ParserContext_execute(context); }}
  if(context->root->arguments.nb!=0)
    ParserContext_execute(context); }


/*****************************************************************************/


FUNCTION Void fold_arguments(struct Array *arguments,Int center,Int nb_before,Address before_value,Int nb_after,Address after_value) {
  struct Expression *root;
  struct Expression *node; Int nb,i,base; struct Expression *e;
  root=(struct Expression *)Array_get_index(arguments,center);
  if(before_value!=null) {
    node=(struct Expression *)entry_new(G.type_Expression);
    Arrow_set((Arrow *)&node->module,root->module);
    ListingPosition_copy(&root->position,&node->position);
    Arrow_set(&node->value,before_value);
    Arrow_copy((Arrow *)&root->module,(Arrow *)&node->module);
    ListingPosition_copy(&root->position,&node->position);
  other
    node=root; }
  nb=minimum(nb_before,center);
  if(nb>0) {
    base=node->arguments.nb;
    Array_resize(&node->arguments,base+nb);
    for(i=0; i<nb; i++) {
      e=(struct Expression *)Array_get_index(arguments,center-nb+i);
      Array_set_index(&node->arguments,base+i,e); }
    for(i=center-nb; i<arguments->nb-nb; i++) Array_set_index(arguments,i,Array_get_index(arguments,i+nb));
    Array_resize(arguments,arguments->nb-nb);
    center-=nb; }
  if(before_value!=null) {
    base=root->arguments.nb;
    Array_resize(&root->arguments,base+1);
    Array_set_index(&root->arguments,base,node); }
  if(after_value!=null) {
    node=(struct Expression *)entry_new(G.type_Expression);
    Arrow_set((Arrow *)&node->module,root->module);
    ListingPosition_copy(&root->position,&node->position);
    Arrow_set(&node->value,after_value);
    Arrow_copy((Arrow *)&root->module,(Arrow *)&node->module);
    ListingPosition_copy(&root->position,&node->position);
  other
    node=root; }
  nb=minimum(nb_after,arguments->nb-(center+1));
  if(nb>0) {
    base=node->arguments.nb;
    Array_resize(&node->arguments,base+nb);
    for(i=0; i<nb; i++) {
      e=(struct Expression *)Array_get_index(arguments,center+1+i);
      Array_set_index(&node->arguments,base+i,e); }
    for(i=center+1; i<arguments->nb-nb; i++) Array_set_index(arguments,i,Array_get_index(arguments,i+nb));
    Array_resize(arguments,arguments->nb-nb); }
  if(after_value!=null) {
    base=root->arguments.nb;
    Array_resize(&root->arguments,base+1);
    Array_set_index(&root->arguments,base,node); } }


/*****************************************************************************/


static Void ParserContext_parse_one_token(struct ParserContext *context) {
  Int x,y; Arrow *cl; struct List *text;
  struct Str *line; struct Str line2;
  Arrow *c; struct List *sections;
  Arrow *c2; struct ParserFilter *f;
  struct ActionRecord ca; Char buffer[16]; struct Str temp;
  struct ListingPosition p; struct Str s;
  x=context->x,y=context->y; cl=context->current_line; text=context->text;
  if(*cl!=null) {
    line=(struct Str *)*cl; check(entry_type(line)==G.type_Str);
    check(x>=0 && x<=Str_len(line));
    line2.chars=line->chars+x;
    line2.len2=Str_len(line)-x;
  other
    line2.chars=null;
    line2.len2=0; }
  c=Module_first(context->module,Str_map_string(&temp,"pliant parser sections"));
  if(c!=G.null_constant && entry_type(*c)==G.type_GlobalVariable) c=&((struct GlobalVariable *)*c)->variable;
  if(c==G.null_constant || entry_type(*c)!=G.type_List) {
    error_notifyn(error_id_missing,Z,"'pliant parser sections' identifier is missing",END);
    return; }
  sections=(struct List *)*c;
  ListingPosition_build(&p); Str_build(&s);
  ParserContext_position(context,&p); ListingPosition_get(&p,&s);
  ActionRecord_build(&ca);
  action_push_recordn(&ca,Z,"parse ",S,&s,END);
  ListingPosition_destroy(&p); Str_destroy(&s);
  context->possible_side_effect=false;
  for(c=List_first(sections); c!=G.null_constant; c=List_next(c))
    if(entry_type(*c)==G.type_Str)
      for(c2=Module_first(context->module,(struct Str *)*c); c2!=G.null_constant; c2=Module_next(context->module,(struct Str *)*c,c2))
        if(entry_type(*c2)==G.type_ParserFilter) {
          f=(struct ParserFilter *)*c2;
          ((ParserFilterPrototype)f->function->exe)(context,&line2,f->parameter);
          if(context->x!=x || context->y!=y || error_notified() || context->possible_side_effect) {
            action_pull_record(&ca);
            ActionRecord_destroy(&ca);
            return; } }
  if(context->x==x && context->y==y && *context->current_line!=null) {
    if(Str_len(&line2)!=0)
      error_notifyn(error_id_compile,Z,"Failed to parse token ",S,&line2,Z," (",S,Str_map_area(&temp,buffer,Int_str2((Int)line2.chars[0],10,buffer)),Z,")",END);
    else
      error_notifyn(error_id_compile,Z,"Failed to parse token ",S,&line2,END); }
  action_pull_record(&ca);
  ActionRecord_destroy(&ca); }


FUNCTION Void compile_text(struct List *text,struct Module *module) {
  struct ParserContext *pc; struct ActionRecord ca;
  ActionRecord_build(&ca);
  action_push_recordn(&ca,Z,"module ",S,module->external!=null ? module->external->name : module->name,END);
  check(module!=null);
  pc=entry_new(G.type_ParserContext); entry_lock(pc);
  Arrow_set((Arrow *)&pc->text,text);
  Arrow_set((Arrow *)&pc->module,module);
  pc->y=pc->x=0; pc->current_line=List_first(text);
  Str_copy(module->name,&pc->filename); pc->delta_y=pc->delta_x=0;
  ParserContext_set_root(pc);
  for(;;) {
    while(*pc->current_line!=null && pc->x==Str_len((struct Str *)*pc->current_line)) 
      pc->y++,pc->x=0,pc->current_line=List_next(pc->current_line);
    ParserContext_parse_one_token(pc); if(error_notified()) break;
    if(*pc->current_line==null) break; }
  entry_unlock(pc);
  action_pull_record(&ca);
  ActionRecord_destroy(&ca); }