Exemple #1
0
// Strict binary operators.
static value_t *e_binary_op(env_t *env, expr_t *expr)
{
  value_t *result;
  value_t *l;
  value_t *r;

  l = e_expr(env, binary_left(expr));
  r = e_expr(env, binary_right(expr));
  result = alloc_value(v_unused);

  switch (expr->type) {
  case p_add:
    result->type = v_num;
    num_val(result) = num_val(l) + num_val(r);
    break;
  case p_div:
    result->type = v_num;
    num_val(result) = num_val(l) / num_val(r);
    break;
  case p_ge:
    result->type = v_bool;
    bool_val(result) = num_val(l) >= num_val(r);
    break;
  case p_gt:
    result->type = v_bool;
    bool_val(result) = num_val(l) > num_val(r);
    break;
  case p_le:
    result->type = v_bool;
    bool_val(result) = num_val(l) <= num_val(r);
    break;
  case p_lt:
    result->type = v_bool;
    bool_val(result) = num_val(l) < num_val(r);
    break;
  case p_mod:
    result->type = v_num;
    num_val(result) = (long)num_val(l) % (long)num_val(r);
    break;
  case p_mul:
    result->type = v_num;
    num_val(result) = num_val(l) * num_val(r);
    break;
  case p_sub:
    result->type = v_num;
    num_val(result) = num_val(l) - num_val(r);
    break;

  default:
    error("Not a strict binary operator.");
    return NULL; // gcc dataflow
  }

  return result;
}
Exemple #2
0
static value_t *e_equals(env_t *env, expr_t *l, expr_t *r)
{
  value_t *result;

  result = alloc_value(v_bool);
  bool_val(result) = equality_test(e_expr(env, l), e_expr(env, r));

  return result;
}
Exemple #3
0
static value_t *e_ite(env_t *env, expr_t *expr)
{
  value_t *cond;

  cond = e_expr(env, ite_cond(expr));
  return bool_val(cond)
    ? e_expr(env, ite_then(expr))
    : e_expr(env, ite_else(expr));
}
Exemple #4
0
static int equality_test(value_t *l, value_t *r)
{
  int result;

  switch (l->type) {
  default:
  case v_unused:
    if (*(int *)NULL) {
      printf("should crash.\n");
    }
    break;

  case v_bool:
    result = bool_val(l) == bool_val(r);
    break;
  case v_char:
    result = char_val(l) == char_val(r);
    break;
  case v_datacons:
    if (strcmp(datacons_tag(l), datacons_tag(r)) == 0) {
      result = 1;

      list_zip_with(datacons_params(l),
                    datacons_params(r),
                    equality_test_i, &result);
    } else {
      result = 0;
    }
    break;
  case v_num:
    result = num_val(l) == num_val(r);
    break;
  case v_tuple:
    result = 1;

    list_zip_with(tuple_val(l),
                  tuple_val(r),
                  equality_test_i, &result);

    break;
  }

  return result;
}
Exemple #5
0
static value_t *e_expr(env_t *env, expr_t *expr)
{
  value_t *result;

  switch (expr->type) {
  default: // This is to handle invalid tags.
  case p_unused:
    if (*(int *)NULL) {
      printf("should crash.\n");
    }
    return NULL;

  case p_and:
    {
      value_t *l = e_expr(env, binary_left(expr));

      if (bool_val(l)) {
        result = e_expr(env, binary_right(expr));
      } else {
        result = l;
      }
    }
    break;
  case p_or:
    {
      value_t *l = e_expr(env, binary_left(expr));

      if (bool_val(l)) {
        result = l;
      } else {
        result = e_expr(env, binary_right(expr));
      }
    }
    break;

  case p_add:
  case p_div:
  case p_ge:
  case p_gt:
  case p_le:
  case p_lt:
  case p_mod:
  case p_mul:
  case p_sub:
    result = e_binary_op(env, expr);
    break;

  case p_bconst:
    result = alloc_value(v_bool);
    bool_val(result) = bool_val(expr);
    break;
  case p_cconst:
    result = alloc_value(v_char);
    char_val(result) = char_val(expr);
    break;
  case p_datacons:
    result = e_datacons(env, expr);
    break;
  case p_eqop:
    result = e_equals(env, binary_left(expr), binary_right(expr));
    break;
  case p_fncall:
    result = e_fncall(env, fncall_fn(expr), fncall_args(expr));
    break;
  case p_nconst:
    result = alloc_value(v_num);
    num_val(result) = num_val(expr);
    break;
  case p_ite:
    result = e_ite(env, expr);
    break;
  case p_let:
    result = e_let(env, expr);
    break;
  case p_listcons:
    result = e_listcons(env, expr);
    break;
  case p_listlit:
    result = e_listlit(env, expr);
    break;
  case p_listempty:
    result = e_listempty();
    break;
  case p_match:
    result = e_match(env, expr);
    break;
  case p_ne:
    result = e_equals(env, binary_left(expr), binary_right(expr));
    bool_val(result) = !bool_val(result);
    break;
  case p_negate:
    result = e_expr(env, unary_expr(expr));
    bool_val(result) = !bool_val(result);
    break;
  case p_tuple:
    result = e_tuple(env, expr);
    break;
  case p_var:
    result = env_lookup(env, var_name(expr));
    if (result == NULL) {
      error("e_expr: variable '%s' not in scope on line %d.\n", var_name(expr), expr->line_num);
    }
    result = thunk_force(result);
    break;
  }

  return result;
}
Exemple #6
0
// Mapped over the clauses in a "match" expression.
static int e_match_pat_i(void *data, void *info)
{
  pm_closure_t *pmc = (pm_closure_t *)info;
  clause_t *c = (clause_t *)data;

  // The style of pattern matching depends on the type of the pattern:
  //   - constants match literally
  //   - variables match anything (and extend the environment)
  //   - tuples always match (and extend the environment)
  //   - data constructors are more complex.
  ///

  switch (c->pattern->type) {
    // Constants: match literally, no binding.
  case p_bconst:
    if (bool_val(c->pattern) == bool_val(pmc->val)) {
      pmc->match_body = c->body;
    }
    break;
  case p_cconst:
    if (char_val(c->pattern) == char_val(pmc->val)) {
      pmc->match_body = c->body;
    }
    break;
  case p_nconst:
    if (num_val(c->pattern) == num_val(pmc->val)) {
      pmc->match_body = c->body;
    }
    break;
  case p_listempty:
    if (pmc->val->type == v_datacons && strcmp(datacons_tag(pmc->val), listEmptyTag) == 0) {
      pmc->match_body = c->body;
    }
    break;

  case p_var:
    // Matches anything. Bind it.
    env_add_binding(pmc->env, var_name(c->pattern), pmc->val);
    pmc->match_body = c->body;
    break;

  case p_listcons:
    // Check the list contains at least one element, then bind variables.
    if (pmc->val->type == v_datacons && strcmp(datacons_tag(pmc->val), listConsTag) == 0) {
      value_t *head;
      value_t *tail;

      head = list_nth(datacons_params(pmc->val), 0);
      tail = list_nth(datacons_params(pmc->val), 1);

      env_add_binding(pmc->env, listcons_hvar(c->pattern), head);
      env_add_binding(pmc->env, listcons_tvar(c->pattern), tail);

      pmc->match_body = c->body;
    }
    break;

  case p_datacons:
    // Check the tag matches, then bind the arguments (if any).
    if (strcmp(datacons_tag(c->pattern), datacons_tag(pmc->val)) == 0) {
      list_zip_with(datacons_params(c->pattern),
                    datacons_params(pmc->val),
                    e_bind_params_i, pmc->env);

      pmc->match_body = c->body;
    }
    break;

  case p_tuple:
    // Always matches (assuming the program type checks). Bind the variables.
    list_zip_with(tuple_val(c->pattern),
                  tuple_val(pmc->val),
                  e_bind_params_i, pmc->env);
    pmc->match_body = c->body;
    break;

  default:
    error("INTERNAL pattern match: invalid pattern.\n");
  }

  return pmc->match_body == NULL;
}
Exemple #7
0
CCompoundID CCompoundIDDumpParser::ParseID()
{
    SkipSpace();
    x_SaveErrPos();

    if (x_EOF() || !isalpha(*m_Ch)) {
        CID_PARSER_EXCEPTION("missing compound ID class name");
    }

    const char* token_begin = m_Ch;

    do
        ++m_Ch;
    while (!x_EOF() && isalpha(*m_Ch));

    CTempString new_id_class_name(token_begin, m_Ch - token_begin);

    ECompoundIDClass new_id_class = eCIC_NumberOfClasses;

    switch (*token_begin) {
    case 'C':
        if (new_id_class_name == CIC_GENERICID_CLASS_NAME)
            new_id_class = eCIC_GenericID;
        break;
    case 'N':
        if (new_id_class_name == CIC_NETCACHEBLOBKEY_CLASS_NAME)
            new_id_class = eCIC_NetCacheBlobKey;
        else if (new_id_class_name == CIC_NETSCHEDULEJOBKEY_CLASS_NAME)
            new_id_class = eCIC_NetScheduleJobKey;
        else if (new_id_class_name == CIC_NETSTORAGEOBJECTLOC_CLASS_NAME)
            new_id_class = eCIC_NetStorageObjectLoc;
        else if (new_id_class_name == CIC_NETSTORAGEOBJECTLOC_CLASS_NAME_V1)
            new_id_class = eCIC_NetStorageObjectLocV1;
    }

    if (new_id_class == eCIC_NumberOfClasses) {
        CID_PARSER_EXCEPTION("unknown compound ID class '" <<
                new_id_class_name << '\'');
    }

    SkipSpace();

    if (x_EOF() || *m_Ch != '{') {
        x_SaveErrPos();
        CID_PARSER_EXCEPTION("missing '{'");
    }

    ++m_Ch;

    SkipSpaceToNextToken();

    CCompoundID result(m_Pool.NewID(new_id_class));

    if (*m_Ch != '}')
        for (;;) {
            token_begin = m_Ch;
            x_SaveErrPos();

            do
                ++m_Ch;
            while (isalnum(*m_Ch) || *m_Ch == '_');

            CTempString field_type_name(token_begin, m_Ch - token_begin);

            ECompoundIDFieldType field_type = eCIT_NumberOfTypes;

            switch (*token_begin) {
            case '}':
                CID_PARSER_EXCEPTION("a field type name is required");
            case 'b':
                if (field_type_name == CIT_BOOLEAN_TYPE_NAME)
                    field_type = eCIT_Boolean;
                break;
            case 'd':
                if (field_type_name == CIT_DATABASE_NAME_TYPE_NAME)
                    field_type = eCIT_DatabaseName;
                break;
            case 'f':
                if (field_type_name == CIT_FLAGS_TYPE_NAME)
                    field_type = eCIT_Flags;
                break;
            case 'h':
                if (field_type_name == CIT_HOST_TYPE_NAME)
                    field_type = eCIT_Host;
                break;
            case 'i':
                if (field_type_name == CIT_ID_TYPE_NAME)
                    field_type = eCIT_ID;
                else if (field_type_name == CIT_INTEGER_TYPE_NAME)
                    field_type = eCIT_Integer;
                else if (field_type_name == CIT_IPV4_ADDRESS_TYPE_NAME)
                    field_type = eCIT_IPv4Address;
                else if (field_type_name == CIT_IPV4_SOCK_ADDR_TYPE_NAME)
                    field_type = eCIT_IPv4SockAddr;
                break;
            case 'n':
                if (field_type_name == CIT_NESTED_CID_TYPE_NAME)
                    field_type = eCIT_NestedCID;
                else if (field_type_name == CIT_CUE_TYPE_NAME)
                    field_type = eCIT_Cue;
                break;
            case 'p':
                if (field_type_name == CIT_OBJECTREF_TYPE_NAME)
                    field_type = eCIT_ObjectRef;
                else if (field_type_name == CIT_PORT_TYPE_NAME)
                    field_type = eCIT_Port;
                break;
            case 'r':
                if (field_type_name == CIT_RANDOM_TYPE_NAME)
                    field_type = eCIT_Random;
                break;
            case 's':
                if (field_type_name == CIT_SEQ_ID_TYPE_NAME)
                    field_type = eCIT_SeqID;
                else if (field_type_name == CIT_SERVICE_NAME_TYPE_NAME)
                    field_type = eCIT_ServiceName;
                else if (field_type_name == CIT_STRING_TYPE_NAME)
                    field_type = eCIT_String;
                break;
            case 't':
                if (field_type_name == CIT_LABEL_TYPE_NAME)
                    field_type = eCIT_Label;
                else if (field_type_name == CIT_TAX_ID_TYPE_NAME)
                    field_type = eCIT_TaxID;
                else if (field_type_name == CIT_TIMESTAMP_TYPE_NAME)
                    field_type = eCIT_Timestamp;
            }

            if (field_type == eCIT_NumberOfTypes) {
                CID_PARSER_EXCEPTION("unknown field type '" <<
                        field_type_name << '\'');
            }

            SkipSpaceToNextToken();

            switch (field_type) {
            case eCIT_ID:
                result.AppendID(x_ReadUint8());
                break;
            case eCIT_Integer:
                result.AppendInteger(x_ReadInt8());
                break;
            case eCIT_ServiceName:
                result.AppendServiceName(x_ReadString());
                break;
            case eCIT_DatabaseName:
                result.AppendDatabaseName(x_ReadString());
                break;
            case eCIT_Timestamp:
                result.AppendTimestamp(x_ReadInt8());
                break;
            case eCIT_Random:
                {
                    x_SaveErrPos();
                    Uint8 random_number = x_ReadUint8();
                    if (random_number >= ((Uint8) 1) << 8 * sizeof(Uint4)) {
                        CID_PARSER_EXCEPTION(
                                "random number exceeds maximum allowed value");
                    }
                    result.AppendRandom((Uint4) random_number);
                }
                break;
            case eCIT_IPv4Address:
                result.AppendIPv4Address(x_ReadIPv4Address());
                break;
            case eCIT_Host:
                result.AppendHost(x_ReadString());
                break;
            case eCIT_Port:
                result.AppendPort(x_ReadPortNumber());
                break;
            case eCIT_IPv4SockAddr:
                {
                    Uint4 ipv4_address = x_ReadIPv4Address();
                    if (x_EOF() || *m_Ch != ':') {
                        x_SaveErrPos();
                        CID_PARSER_EXCEPTION("missing ':'");
                    }
                    ++m_Ch;
                    result.AppendIPv4SockAddr(ipv4_address, x_ReadPortNumber());
                }
                break;
            case eCIT_ObjectRef:
                result.AppendObjectRef(x_ReadString());
                break;
            case eCIT_String:
                result.AppendString(x_ReadString());
                break;
            case eCIT_Boolean:
                {
                    token_begin = m_Ch;
                    x_SaveErrPos();

                    while (!x_EOF() && isalpha(*m_Ch))
                        ++m_Ch;

                    CTempString bool_val(token_begin, m_Ch - token_begin);

                    if (bool_val == "false")
                        result.AppendBoolean(false);
                    else if (bool_val == "true")
                        result.AppendBoolean(true);
                    else {
                        CID_PARSER_EXCEPTION("invalid boolean value \"" <<
                                bool_val << '\"');
                    }
                }
                break;
            case eCIT_Flags:
                result.AppendFlags(x_ReadUint8());
                break;
            case eCIT_Label:
                result.AppendLabel(x_ReadString());
                break;
            case eCIT_Cue:
                result.AppendCue(x_ReadUint8());
                break;
            case eCIT_SeqID:
                result.AppendSeqID(x_ReadString());
                break;
            case eCIT_TaxID:
                result.AppendTaxID(x_ReadUint8());
                break;
            case eCIT_NestedCID:
                result.AppendNestedCID(ParseID());
                break;
            case eCIT_NumberOfTypes:
                break;
            }

            SkipSpaceToNextToken();

            if (*m_Ch == ',')
                ++m_Ch;
            else if (*m_Ch == '}')
                break;
            else {
                x_SaveErrPos();
                CID_PARSER_EXCEPTION("either ',' or '}' expected");
            }

            SkipSpaceToNextToken();
        }
    ++m_Ch;
    return result;
}