예제 #1
0
파일: v7.c 프로젝트: di3online/v7
enum v7_err v7_call(struct v7 *v7, int num_args) {
  struct v7_val **top = v7_top(v7), **v = top - (num_args + 1), *f = v[0];

  if (v7->no_exec) return V7_OK;
  CHECK(v7->sp > num_args, V7_INTERNAL_ERROR);
  CHECK(f->type == V7_FUNC || f->type == V7_C_FUNC, V7_CALLED_NON_FUNCTION);

  // Return value will substitute function objest on a stack
  v[0] = v7_mkval(v7, V7_UNDEF);  // Set return value to 'undefined'
  v[0]->ref_count++;

  if (f->type == V7_FUNC) {
    const char *src = v7->cursor;
    v7->cursor = f->v.func;     // Move control flow to function body
    TRY(parse_function_definition(v7, v, num_args));  // Execute function body
    v7->cursor = src;           // Return control flow
    if (v7_top(v7) > top) {     // If function body pushed some value on stack,
      free_val(v7, v[0]);
      v[0] = top[0];            // use that value as return value
      v[0]->ref_count++;
    }
  } else if (f->type == V7_C_FUNC) {
    f->v.c_func(v7, v7->cur_obj, v[0], v + 1, num_args);
  }
  free_val(v7, f);

  TRY(inc_stack(v7, - (int) (v7_top(v7) - (v + 1))));  // Clean up stack
  return V7_OK;
}
예제 #2
0
V7_PRIVATE enum v7_err do_exec(struct v7 *v7, const char *file_name,
  const char *source_code, int sp) {
  int has_ret = 0;
  struct v7_pstate old_pstate = v7->pstate;
  enum v7_err err = V7_OK;

  v7->pstate.source_code = v7->pstate.pc = source_code;
  v7->pstate.file_name = file_name;
  v7->pstate.line_no = 1;

  // Prior calls to v7_exec() may have left current_scope modified, reset now
  // TODO(lsm): free scope chain
  v7->this_obj = &v7->root_scope;

  next_tok(v7);
  while ((err == V7_OK) && (v7->cur_tok != TOK_END_OF_INPUT)) {
    // Reset stack on each statement
    if ((err = inc_stack(v7, sp - v7->sp)) == V7_OK) {
      err = parse_statement(v7, &has_ret);
    }
  }

  //printf("%s: [%s] %d %d\n", __func__, file_name, v7->pstate.line_no, err);
  assert(v7->root_scope.proto == &s_global);
  v7->pstate = old_pstate;

  return err;
}
예제 #3
0
파일: v7.c 프로젝트: di3online/v7
//  factor  =   number | string_literal | "(" expression ")" |
//              variable | "this" | "null" | "true" | "false" |
//              "{" object_literal "}" |
//              "[" array_literal "]" |
//              function_definition |
//              function_call
static enum v7_err parse_factor(struct v7 *v7) {
  int old_sp = v7_sp(v7);

  if (*v7->cursor == '(') {
    TRY(match(v7, '('));
    TRY(parse_expression(v7));
    TRY(match(v7, ')'));
  } else if (*v7->cursor == '\'' || *v7->cursor == '"') {
    TRY(parse_string_literal(v7));
  } else if (*v7->cursor == '{') {
    TRY(parse_object_literal(v7));
  } else if (is_alpha(*v7->cursor) || *v7->cursor == '_') {
    TRY(parse_identifier(v7));
    if (test_token(v7, "this", 4)) {
      inc_stack(v7, 1);
      v7_top(v7)[-1] = &v7->scopes[v7->current_scope];
    } else if (test_token(v7, "null", 4)) {
      TRY(v7_make_and_push(v7, V7_NULL));
    } else if (test_token(v7, "true", 4)) {
      TRY(v7_make_and_push(v7, V7_BOOL));
      v7_top(v7)[-1]->v.num = 1;
    } else if (test_token(v7, "false", 5)) {
      TRY(v7_make_and_push(v7, V7_BOOL));
      v7_top(v7)[-1]->v.num = 0;
    } else if (test_token(v7, "function", 8)) {
      TRY(parse_function_definition(v7, NULL, 0));
    } else if (test_token(v7, "delete", 6)) {
      TRY(parse_delete(v7));
    } else {
      TRY(parse_variable(v7));
    }
  } else {
    TRY(parse_num(v7));
  }

  if (*v7->cursor == '(') {
    TRY(parse_function_call(v7));
  }

  // Don't leave anything on stack if no execution flag is set
  if (v7->no_exec) {
    inc_stack(v7, old_sp - v7->sp);
  }

  return V7_OK;
}
예제 #4
0
파일: v7.c 프로젝트: di3online/v7
//  code        =   { statement }
enum v7_err v7_exec(struct v7 *v7, const char *source_code) {
  v7->source_code = v7->cursor = source_code;
  skip_whitespaces_and_comments(v7);

  // The following code may raise an exception and jump to the previous line,
  // returning non-zero from the setjmp() call
  // Prior calls to v7_exec() may have left current_scope modified, reset now
  v7->current_scope = 0;  // XXX free up higher scopes?
  inc_stack(v7, -v7->sp);

  while (*v7->cursor != '\0') {
    inc_stack(v7, -v7->sp);         // Reset stack on each statement
    TRY(parse_statement(v7, 0));    // Leave the result of last expr on stack
  }

  return V7_OK;
}
예제 #5
0
파일: v7.c 프로젝트: di3online/v7
// function_defition = "function" "(" func_params ")" "{" func_body "}"
static enum v7_err parse_function_definition(struct v7 *v7, struct v7_val **v,
                                             int num_params) {
  int i = 0, old_no_exec = v7->no_exec, old_sp = v7->sp;
  const char *src = v7->cursor;

  // If 'v' (func to call) is NULL, that means we're just parsing function
  // definition to save it's body.
  v7->no_exec = v == NULL;
  TRY(match(v7, '('));

  // Initialize new scope
  if (!v7->no_exec) {
    v7->current_scope++;
    CHECK(v7->current_scope < (int) ARRAY_SIZE(v7->scopes),
          V7_RECURSION_TOO_DEEP);
    CHECK(v7->scopes[v7->current_scope].v.props == NULL, V7_INTERNAL_ERROR);
    CHECK(v7->scopes[v7->current_scope].type == V7_OBJ, V7_INTERNAL_ERROR);
  }

  while (*v7->cursor != ')') {
    TRY(parse_identifier(v7));
    if (!v7->no_exec) {
      struct v7_val *key = v7_mkval_str(v7, v7->tok, v7->tok_len);
      struct v7_val *val = i < num_params ? v[i + 1] : v7_mkval(v7, V7_UNDEF);
      v7_set(v7, &v7->scopes[v7->current_scope], key, val);
    }
    i++;
    if (!test_and_skip_char(v7, ',')) break;
  }
  TRY(match(v7, ')'));
  TRY(match(v7, '{'));

  while (*v7->cursor != '}') {
    int is_return_statement = 0;
    inc_stack(v7, old_sp - v7->sp);   // Clean up the stack from prev stmt
    TRY(parse_statement(v7, &is_return_statement));
    if (is_return_statement) break;   // Leave statement value on stack
  }

  if (v7->no_exec) {
    TRY(v7_make_and_push(v7, V7_FUNC));
    v7_top(v7)[-1]->v.func = v7_strdup(src, (v7->cursor + 1) - src);
  }
  TRY(match(v7, '}'));

  // Deinitialize scope
  if (!v7->no_exec) {
    v7->scopes[v7->current_scope].ref_count = 1;  // Force free_val() below
    free_val(v7, &v7->scopes[v7->current_scope]);
    v7->current_scope--;
    assert(v7->current_scope >= 0);
  }

  v7->no_exec = old_no_exec;
  return V7_OK;
}
예제 #6
0
파일: v7.c 프로젝트: di3online/v7
void v7_destroy(struct v7 **v7) {
  size_t i;
  if (v7 == NULL || v7[0] == NULL) return;
  assert(v7[0]->sp >= 0);
  inc_stack(v7[0], -v7[0]->sp);
  for (i = 0; i < ARRAY_SIZE(v7[0]->scopes); i++) {
    v7[0]->scopes[i].ref_count = 1;   // Force free_val() below to free memory
    free_val(v7[0], &v7[0]->scopes[i]);
  }
  free(v7[0]);
  v7[0] = NULL;
}
예제 #7
0
파일: string.c 프로젝트: amihwan/v7
V7_PRIVATE enum v7_err check_str_re_conv(struct v7 *v7, struct v7_val **arg,
                                         int re_fl) {
  /* If argument is not (RegExp + re_fl) or string, do type conversion */
  if (!is_string(*arg) &&
      !(re_fl && instanceof(*arg, &s_constructors[V7_CLASS_REGEXP]))) {
    TRY(toString(v7, *arg));
    *arg = v7_top_val(v7);
    INC_REF_COUNT(*arg);
    TRY(inc_stack(v7, -2));
    TRY(v7_push(v7, *arg));
  }
  return V7_OK;
}
예제 #8
0
파일: v7.c 프로젝트: di3online/v7
//  declaration =   "var" identifier [ "=" expression ] [ "," { i [ "=" e ] } ]
static enum v7_err parse_declaration(struct v7 *v7) {
  int sp = v7_sp(v7);

  do {
    inc_stack(v7, sp - v7_sp(v7));  // Clean up the stack after prev decl
    TRY(parse_identifier(v7));
    if (*v7->cursor == '=') {
      if (!v7->no_exec) v7_make_and_push(v7, V7_UNDEF);
      TRY(parse_assignment(v7, &v7->scopes[v7->current_scope]));
    }
  } while (test_and_skip_char(v7, ','));

  return V7_OK;
}
예제 #9
0
파일: v7.c 프로젝트: di3online/v7
static enum v7_err parse_compound_statement(struct v7 *v7) {
  if (*v7->cursor == '{') {
    int old_sp = v7->sp;
    match(v7, '{');
    while (*v7->cursor != '}') {
      if (v7->sp > old_sp) inc_stack(v7, old_sp - v7->sp);
      TRY(parse_statement(v7, NULL));
    }
    match(v7, '}');
  } else {
    TRY(parse_statement(v7, NULL));
  }
  return V7_OK;
}
예제 #10
0
파일: v7.c 프로젝트: di3online/v7
// variable = identifier { '.' identifier | '[' expression ']' }
static enum v7_err parse_variable(struct v7 *v7) {
  struct v7_val **v = NULL, key = str_to_val(v7->tok, v7->tok_len);
  struct v7_val *ns = find(v7, &key), ro_prop;

  if (!v7->no_exec) {
    TRY(v7_make_and_push(v7, V7_UNDEF));
    v = v7_top(v7);
  }

  while (*v7->cursor == '.' || *v7->cursor == '[') {
    int ch = *v7->cursor;

    TRY(match(v7, ch));
    CHECK(v7->no_exec || ns != NULL, V7_SYNTAX_ERROR);
    v7->cur_obj = ns;

    if (ch == '.') {
      TRY(parse_identifier(v7));
      if (!v7->no_exec) {
        key = str_to_val(v7->tok, v7->tok_len);
        ns = get2(ns, &key);
        if (ns != NULL && ns->type == V7_RO_PROP) {
          ns->v.prop_func(v7->cur_obj, &ro_prop);
          ns = &ro_prop;
        }
      }
    } else {
      TRY(parse_expression(v7));
      TRY(match(v7, ']'));
      if (!v7->no_exec) {
        ns = get2(ns, v7_top(v7)[-1]);
        if (ns != NULL && ns->type == V7_RO_PROP) {
          ns->v.prop_func(v7->cur_obj, &ro_prop);
          ns = &ro_prop;
        }
        TRY(inc_stack(v7, -1));
      }
    }
  }

  if (v != NULL && ns != NULL) {
    free_val(v7, v[-1]);
    v[-1] = ns;
    v[-1]->ref_count++;
  }

  return V7_OK;
}
예제 #11
0
파일: v7.c 프로젝트: di3online/v7
static enum v7_err do_logical_op(struct v7 *v7, int op) {
  struct v7_val **v = v7_top(v7) - 2;

  if (v7->no_exec) return V7_OK;
  CHECK(v[0]->type == V7_NUM && v[1]->type == V7_NUM, V7_TYPE_MISMATCH);

  switch (op) {
    case OP_GT: v[0]->v.num = v[0]->v.num >  v[1]->v.num ? 1.0 : 0.0; break;
    case OP_GE: v[0]->v.num = v[0]->v.num >= v[1]->v.num ? 1.0 : 0.0; break;
    case OP_LT: v[0]->v.num = v[0]->v.num <  v[1]->v.num ? 1.0 : 0.0; break;
    case OP_LE: v[0]->v.num = v[0]->v.num <= v[1]->v.num ? 1.0 : 0.0; break;
    case OP_EQ: v[0]->v.num = v[0]->v.num == v[1]->v.num ? 1.0 : 0.0; break;
  }

  TRY(inc_stack(v7, -1));
  return V7_OK;
}
예제 #12
0
파일: v7.c 프로젝트: di3online/v7
static enum v7_err parse_assignment(struct v7 *v7, struct v7_val *obj) {
  const char *tok = v7->tok;
  unsigned long tok_len = v7->tok_len;
  struct v7_val **top = v7_top(v7);

  TRY(match(v7, '='));
  TRY(parse_expression(v7));

  if (!v7->no_exec) {
    TRY(v7_make_and_push_string(v7, tok, tok_len, 1));
    v7_set(v7, obj, top[1], top[0]);
    CHECK(v7_top(v7) - top > 1, V7_INTERNAL_ERROR);
    CHECK(v7->sp > 1, V7_STACK_UNDERFLOW);
    free_val(v7, top[-1]);
    top[-1] = top[0];
    top[-1]->ref_count++;
    inc_stack(v7, (int) (top - v7_top(v7)));
  }

  return V7_OK;
}
예제 #13
0
파일: v7.c 프로젝트: di3online/v7
static enum v7_err parse_object_literal(struct v7 *v7) {
  TRY(v7_make_and_push(v7, V7_OBJ));
  TRY(match(v7, '{'));
  while (*v7->cursor != '}') {
    if (*v7->cursor == '\'' || *v7->cursor == '"') {
      TRY(parse_string_literal(v7));
    } else {
      TRY(parse_identifier(v7));
      TRY(v7_make_and_push_string(v7, v7->tok, v7->tok_len, 1));
    }
    TRY(match(v7, ':'));
    TRY(parse_expression(v7));
    if (!v7->no_exec) {
      struct v7_val **v = v7_top(v7) - 3;
      CHECK(v[0]->type == V7_OBJ, V7_TYPE_MISMATCH);
      v7_set(v7, v[0], v[1], v[2]);
      inc_stack(v7, -2);
    }
    test_and_skip_char(v7, ',');
  }
  TRY(match(v7, '}'));
  return V7_OK;
}
예제 #14
0
파일: v7.c 프로젝트: di3online/v7
static enum v7_err do_arithmetic_op(struct v7 *v7, int op) {
  struct v7_val **v = v7_top(v7) - 2;
  double a, b, res = 0;

  if (v7->no_exec) return V7_OK;
  CHECK(v7->sp >= 2, V7_STACK_UNDERFLOW);
  CHECK(v[0]->type == V7_NUM && v[1]->type == V7_NUM, V7_TYPE_MISMATCH);
  a = v[0]->v.num;
  b = v[1]->v.num;

  switch (op) {
    case '+': res = a + b; break;
    case '-': res = a - b; break;
    case '*': res = a * b; break;
    case '/': res = a / b; break;
  }

  TRY(inc_stack(v7, -2));
  TRY(v7_make_and_push(v7, V7_NUM));
  v7_top(v7)[-1]->v.num = res;

  return V7_OK;
}
예제 #15
0
파일: string.c 프로젝트: amihwan/v7
V7_PRIVATE enum v7_err Str_replace(struct v7_c_func_arg *cfa) {
#define v7 (cfa->v7) /* Needed for TRY() macro below */
  struct v7_val *result = v7_push_new_object(v7);
  const char *out_str = cfa->this_obj->v.str.buf;
  uint8_t own = 1;
  size_t out_len = cfa->this_obj->v.str.len;
  int old_sp = v7->sp;

  if (cfa->num_args > 1) {
    const char *const str_end =
        cfa->this_obj->v.str.buf + cfa->this_obj->v.str.len;
    char *p = cfa->this_obj->v.str.buf;
    uint32_t out_sub_num = 0;
    struct v7_val *re = cfa->args[0], *str_func = cfa->args[1], *arr = NULL;
    struct re_tok out_sub[V7_RE_MAX_REPL_SUB], *ptok = out_sub;
    struct Resub loot;
    TRY(check_str_re_conv(v7, &re, 1));
    TRY(regex_check_prog(re));
    if (v7_is_class(str_func, V7_CLASS_FUNCTION)) {
      arr = v7_push_new_object(v7);
      v7_set_class(arr, V7_CLASS_ARRAY);
      TRY(v7_push(v7, str_func));
    } else
      TRY(check_str_re_conv(v7, &str_func, 0));

    out_len = 0;
    do {
      int i;
      if (re_exec(re->v.str.prog, re->fl.fl, p, &loot)) break;
      if (p != loot.sub->start) {
        ptok->start = p;
        ptok->end = loot.sub->start;
        ptok++;
        out_len += loot.sub->start - p;
        out_sub_num++;
      }

      if (NULL != arr) { /* replace function */
        Rune rune;
        int old_sp = v7->sp, utf_shift = 0;
        struct v7_val *rez_str;
        for (i = 0; i < loot.subexpr_num; i++)
          v7_push_string(v7, loot.sub[i].start,
                         loot.sub[i].end - loot.sub[i].start, 1);
        for (i = 0; p + i < loot.sub[0].start;
             i += chartorune(&rune, p + i), utf_shift++)
          ;
        TRY(push_number(v7, utf_shift));
        TRY(v7_push(v7, cfa->this_obj));
        rez_str = v7_call(v7, cfa->this_obj, loot.subexpr_num + 2);
        TRY(check_str_re_conv(v7, &rez_str, 0));
        if (rez_str->v.str.len) {
          ptok->start = rez_str->v.str.buf;
          ptok->end = rez_str->v.str.buf + rez_str->v.str.len;
          ptok++;
          out_len += rez_str->v.str.len;
          out_sub_num++;
          v7_append(v7, arr, rez_str);
        }
        TRY(inc_stack(v7, old_sp - v7->sp));
      } else { /* replace string */
        struct Resub newsub;
        re_rplc(&loot, p, str_func->v.str.buf, &newsub);
        for (i = 0; i < newsub.subexpr_num; i++) {
          ptok->start = newsub.sub[i].start;
          ptok->end = newsub.sub[i].end;
          ptok++;
          out_len += newsub.sub[i].end - newsub.sub[i].start;
          out_sub_num++;
        }
      }
      p = (char *)loot.sub->end;
    } while (re->fl.fl.re_g && p < str_end);
    if (p < str_end) {
      ptok->start = p;
      ptok->end = str_end;
      ptok++;
      out_len += str_end - p;
      out_sub_num++;
    }
    out_str = malloc(out_len + 1);
    CHECK(out_str, V7_OUT_OF_MEMORY);
    ptok = out_sub;
    p = (char *)out_str;
    do {
      size_t ln = ptok->end - ptok->start;
      memcpy(p, ptok->start, ln);
      p += ln;
      ptok++;
    } while (--out_sub_num);
    *p = '\0';
    own = 0;
  }
  TRY(inc_stack(v7, old_sp - v7->sp));
  v7_init_str(result, out_str, out_len, own);
  result->fl.fl.str_alloc = 1;
  return V7_OK;
#undef v7
}
예제 #16
0
V7_PRIVATE enum v7_err v7_push(struct v7 *v7, struct v7_val *v) {
  inc_ref_count(v);
  TRY(inc_stack(v7, 1));
  v7->stack[v7->sp - 1] = v;
  return V7_OK;
}
예제 #17
0
파일: v7.c 프로젝트: di3online/v7
enum v7_err v7_push(struct v7 *v7, struct v7_val *v) {
  v->ref_count++;
  TRY(inc_stack(v7, 1));
  v7->stack[v7->sp - 1] = v;
  return V7_OK;
}