<commit_before>/*
 *
 * parser.c
 *
 * Created at:  Fri Nov  8 18:27:39 2013 18:27:39
 *
 * Author:  <NAME> <<EMAIL>>
 *
 * License:  please visit the LICENSE file for details.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

#include "ast.h"
#include "mem.h"
#include "nob.h"
#include "lexer.h"
#include "utf8.h"
#include "util.h"

/*
 * Fetches the type, at the lexer's current 'position'.
 * If the type already exists, like "int", it return's the pointer to it.
 *
 * If the type doesn't already exist (by the way, it can't be a single word,
 * lexer wouldn't let it through), like an anonymous tuple, creates it as a
 * whole new type, and returns the pointer to it.
 */
static struct nob_type *type(struct lexer *lex)
{
  /* the fields (names + associated types) used to be passed over to `new_type' */
  struct field fields[MAX_TUPLE_FIELDS + 1] = { { 0, 0 } };
  /* 'pointer' to the current field */
  unsigned currt = 0;

  if (accept(lex, TOK_TYPE)){
    printf("%s", lex->curr_tok.value.s);
    return get_type_by_name(lex->curr_tok.value.s);
  } else if (accept(lex, TOK_LCHEVRON)){
    /* TODO: guard against having two fields of the same name */
    printf("<");
    fields[currt].type = type(lex);
    /* see if the field was given a name, and if not, print a meaningful
     * message */
    if (accept(lex, TOK_NAME)){
      printf(" %s", lex->curr_tok.value.s);
      fields[currt].name = strdup(lex->curr_tok.value.s);
    } else {
      fprintf(stderr, "the field is missing it's name");
      exit(1);
    }
    currt++;
    /* fetch more fields if they're present */
    while (accept(lex, TOK_COMMA) && currt <= MAX_TUPLE_FIELDS){
      printf(", ");
      fields[currt].type = type(lex);
      /* see if the field was given a name, and if not, print a meaningful
       * message */
      if (accept(lex, TOK_NAME)){
        printf(" %s", lex->curr_tok.value.s);
        fields[currt].name = strdup(lex->curr_tok.value.s);
      } else {
        fprintf(stderr, "the field is missing it's name");
        exit(1);
      }
      currt++;
    }
    /* NOTE: there's really no need to NULL-terminate the array, because it was
     * initialized to zeros, and && currt <= MAX_TUPLE_FIELDS guards against
     * writing to the last element */
    force(lex, TOK_RCHEVRON);
    printf(">");
    /* create the new type. for now it's gonna be anonymous */
    return new_type(NULL /* no name */, OT_TUPLE, fields);
  }

  /* it's not a type, really */
  return NULL;
}
<commit_msg>The parser guards against tuples having few fields with the same name.<commit_after>/*
 *
 * parser.c
 *
 * Created at:  Fri Nov  8 18:27:39 2013 18:27:39
 *
 * Author:  <NAME> <<EMAIL>>
 *
 * License:  please visit the LICENSE file for details.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

#include "ast.h"
#include "mem.h"
#include "nob.h"
#include "lexer.h"
#include "utf8.h"
#include "util.h"

/*
 * Fetches the type, at the lexer's current 'position'.
 * If the type already exists, like "int", it return's the pointer to it.
 *
 * If the type doesn't already exist (by the way, it can't be a single word,
 * lexer wouldn't let it through), like an anonymous tuple, creates it as a
 * whole new type, and returns the pointer to it.
 */
static struct nob_type *type(struct lexer *lex)
{
  /* the fields (names + associated types) used to be passed over to `new_type' */
  struct field fields[MAX_TUPLE_FIELDS + 1] = { { 0, 0 } };
  /* 'pointer' to the current field */
  unsigned currt = 0;

  if (accept(lex, TOK_TYPE)){
    printf("%s", lex->curr_tok.value.s);
    return get_type_by_name(lex->curr_tok.value.s);
  } else if (accept(lex, TOK_LCHEVRON)){
    /* define one handy macro, so we stay DRY */
#define fetch_name() \
    /* {{{ fetch_name body */ \
    do { \
      /* see if the field was given a name, and if not, print a meaningful \
       * message */ \
      if (accept(lex, TOK_NAME)){ \
        struct field *p = fields; \
        for (; p->name != NULL && p->type != NULL; p++){ \
          if (!strcmp(p->name, lex->curr_tok.value.s)){ \
            fprintf(stderr, "error: duplicate field names ('%s') in a tuple\n", p->name); \
            exit(1); \
          } \
        } \
        printf(" %s", lex->curr_tok.value.s); \
        fields[currt].name = strdup(lex->curr_tok.value.s); \
      } else { \
        fprintf(stderr, "the field is missing it's name"); \
        exit(1); \
      } \
    } while (0)
    /* }}} */

    printf("<");
    fields[currt].type = type(lex);
    fetch_name();
    currt++;
    /* fetch more fields if they're present */
    while (accept(lex, TOK_COMMA) && currt <= MAX_TUPLE_FIELDS){
      printf(", ");
      fields[currt].type = type(lex);
      fetch_name();
      currt++;
    }
    /* NOTE: there's really no need to NULL-terminate the array, because it was
     * initialized to zeros, and && currt <= MAX_TUPLE_FIELDS guards against
     * writing to the last element */
    force(lex, TOK_RCHEVRON);
    printf(">");
    /* we don't need you anymore, bye! */
#undef fetch_name
    /* create the new type. for now it's gonna be anonymous */
    return new_type(NULL /* no name */, OT_TUPLE, fields);
  }

  /* it's not a type, really */
  return NULL;
}

{'fraction_non_alphanumeric': 0.14945753834642725, 'fraction_numerical': 0.00916573138795361, 'mean_word_length': 2.7003460207612457, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3118867', 'n_tokens_mistral': 1881, 'n_tokens_neox': 1804, 'n_words': 596}