예제 #1
0
파일: n-loop.c 프로젝트: mbk/ren-c
*/	static void Loop_Series(REBVAL *out, REBVAL *var, REBSER* body, REBVAL *start, REBINT ei, REBINT ii)
/*
***********************************************************************/
{
	REBINT si = VAL_INDEX(start);
	REBCNT type = VAL_TYPE(start);

	*var = *start;

	if (ei >= cast(REBINT, VAL_TAIL(start)))
		ei = cast(REBINT, VAL_TAIL(start));

	if (ei < 0) ei = 0;

	SET_NONE(out); // Default result to NONE if the loop does not run

	for (; (ii > 0) ? si <= ei : si >= ei; si += ii) {
		VAL_INDEX(var) = si;

		if (!DO_BLOCK(out, body, 0) && Check_Error(out) >= 0) break;

		if (VAL_TYPE(var) != type) Trap1(RE_INVALID_TYPE, var);
		si = VAL_INDEX(var);
	}
}
예제 #2
0
파일: n-loop.c 프로젝트: mbk/ren-c
*/	static void Loop_Number(REBVAL *out, REBVAL *var, REBSER* body, REBVAL *start, REBVAL *end, REBVAL *incr)
/*
***********************************************************************/
{
	REBDEC s;
	REBDEC e;
	REBDEC i;

	if (IS_INTEGER(start)) s = cast(REBDEC, VAL_INT64(start));
	else if (IS_DECIMAL(start) || IS_PERCENT(start)) s = VAL_DECIMAL(start);
	else { Trap_Arg(start); DEAD_END_VOID; }

	if (IS_INTEGER(end)) e = cast(REBDEC, VAL_INT64(end));
	else if (IS_DECIMAL(end) || IS_PERCENT(end)) e = VAL_DECIMAL(end);
	else { Trap_Arg(end); DEAD_END_VOID; }

	if (IS_INTEGER(incr)) i = cast(REBDEC, VAL_INT64(incr));
	else if (IS_DECIMAL(incr) || IS_PERCENT(incr)) i = VAL_DECIMAL(incr);
	else { Trap_Arg(incr); DEAD_END_VOID; }

	VAL_SET(var, REB_DECIMAL);

	SET_NONE(out); // Default result to NONE if the loop does not run

	for (; (i > 0.0) ? s <= e : s >= e; s += i) {
		VAL_DECIMAL(var) = s;

		if (!DO_BLOCK(out, body, 0) && Check_Error(out) >= 0) break;

		if (!IS_DECIMAL(var)) Trap_Type(var);
		s = VAL_DECIMAL(var);
	}
}
예제 #3
0
파일: n-loop.c 프로젝트: mbk/ren-c
*/	static void Loop_Integer(REBVAL *out, REBVAL *var, REBSER* body, REBI64 start, REBI64 end, REBI64 incr)
/*
***********************************************************************/
{
	VAL_SET(var, REB_INTEGER);

	SET_NONE(out); // Default result to NONE if the loop does not run

	while ((incr > 0) ? start <= end : start >= end) {
		VAL_INT64(var) = start;

		if (!DO_BLOCK(out, body, 0) && Check_Error(out) >= 0) break;

		if (!IS_INTEGER(var)) Trap_Type(var);
		start = VAL_INT64(var);

		if (REB_I64_ADD_OF(start, incr, &start)) {
			Trap(RE_OVERFLOW);
		}
	}
}
예제 #4
0
파일: n-loop.c 프로젝트: mbk/ren-c
*/	static REB_R Loop_Each(struct Reb_Call *call_, REBINT mode)
/*
**		Supports these natives (modes):
**			0: foreach
**			1: remove-each
**			2: map
**
***********************************************************************/
{
	REBSER *body;
	REBVAL *vars;
	REBVAL *words;
	REBSER *frame;
	REBVAL *value;
	REBSER *series;
	REBSER *out;	// output block (for MAP, mode = 2)

	REBINT index;	// !!!! should these be REBCNT?
	REBINT tail;
	REBINT windex;	// write
	REBINT rindex;	// read
	REBINT err;
	REBCNT i;
	REBCNT j;
	REBVAL *ds;

	assert(mode >= 0 && mode < 3);

	value = D_ARG(2); // series
	if (IS_NONE(value)) return R_NONE;

	body = Init_Loop(D_ARG(1), D_ARG(3), &frame); // vars, body
	SET_OBJECT(D_ARG(1), frame); // keep GC safe
	Set_Block(D_ARG(3), body);	 // keep GC safe

	SET_NONE(D_OUT); // Default result to NONE if the loop does not run

	// If it's MAP, create result block:
	if (mode == 2) {
		out = Make_Block(VAL_LEN(value));
		SAVE_SERIES(out);
	}

	// Get series info:
	if (ANY_OBJECT(value)) {
		series = VAL_OBJ_FRAME(value);
		out = FRM_WORD_SERIES(series); // words (the out local reused)
		index = 1;
		//if (frame->tail > 3) Trap_Arg_DEAD_END(FRM_WORD(frame, 3));
	}
	else if (IS_MAP(value)) {
		series = VAL_SERIES(value);
		index = 0;
		//if (frame->tail > 3) Trap_Arg_DEAD_END(FRM_WORD(frame, 3));
	}
	else {
		series = VAL_SERIES(value);
		index  = VAL_INDEX(value);
		if (index >= cast(REBINT, SERIES_TAIL(series))) {
			if (mode == 1) {
				SET_INTEGER(D_OUT, 0);
			} else if (mode == 2) {
				Set_Block(D_OUT, out);
				UNSAVE_SERIES(out);
			}
			return R_OUT;
		}
	}

	windex = index;

	// Iterate over each value in the series block:
	while (index < (tail = SERIES_TAIL(series))) {

		rindex = index;  // remember starting spot
		j = 0;

		// Set the FOREACH loop variables from the series:
		for (i = 1; i < frame->tail; i++) {

			vars = FRM_VALUE(frame, i);
			words = FRM_WORD(frame, i);

			// var spec is WORD
			if (IS_WORD(words)) {

				if (index < tail) {

					if (ANY_BLOCK(value)) {
						*vars = *BLK_SKIP(series, index);
					}

					else if (ANY_OBJECT(value)) {
						if (!VAL_GET_EXT(BLK_SKIP(out, index), EXT_WORD_HIDE)) {
							// Alternate between word and value parts of object:
							if (j == 0) {
								Init_Word(vars, REB_WORD, VAL_WORD_SYM(BLK_SKIP(out, index)), series, index);
								if (NOT_END(vars+1)) index--; // reset index for the value part
							}
							else if (j == 1)
								*vars = *BLK_SKIP(series, index);
							else
								Trap_Arg_DEAD_END(words);
							j++;
						}
						else {
							// Do not evaluate this iteration
							index++;
							goto skip_hidden;
						}
					}

					else if (IS_VECTOR(value)) {
						Set_Vector_Value(vars, series, index);
					}

					else if (IS_MAP(value)) {
						REBVAL *val = BLK_SKIP(series, index | 1);
						if (!IS_NONE(val)) {
							if (j == 0) {
								*vars = *BLK_SKIP(series, index & ~1);
								if (IS_END(vars+1)) index++; // only words
							}
							else if (j == 1)
								*vars = *BLK_SKIP(series, index);
							else
								Trap_Arg_DEAD_END(words);
							j++;
						}
						else {
							index += 2;
							goto skip_hidden;
						}
					}

					else { // A string or binary
						if (IS_BINARY(value)) {
							SET_INTEGER(vars, (REBI64)(BIN_HEAD(series)[index]));
						}
						else if (IS_IMAGE(value)) {
							Set_Tuple_Pixel(BIN_SKIP(series, index), vars);
						}
						else {
							VAL_SET(vars, REB_CHAR);
							VAL_CHAR(vars) = GET_ANY_CHAR(series, index);
						}
					}
					index++;
				}
				else SET_NONE(vars);
			}

			// var spec is SET_WORD:
			else if (IS_SET_WORD(words)) {
				if (ANY_OBJECT(value) || IS_MAP(value)) {
					*vars = *value;
				} else {
					VAL_SET(vars, REB_BLOCK);
					VAL_SERIES(vars) = series;
					VAL_INDEX(vars) = index;
				}
				//if (index < tail) index++; // do not increment block.
			}
			else Trap_Arg_DEAD_END(words);
		}
		if (index == rindex) index++; //the word block has only set-words: foreach [a:] [1 2 3][]

		if (!DO_BLOCK(D_OUT, body, 0)) {
			if ((err = Check_Error(D_OUT)) >= 0) {
				index = rindex;
				break;
			}
			// else CONTINUE:
			if (mode == 1) SET_FALSE(D_OUT); // keep the value (for mode == 1)
		} else {
			err = 0; // prevent later test against uninitialized value
		}

		if (mode > 0) {
			//if (ANY_OBJECT(value)) Trap_Types_DEAD_END(words, REB_BLOCK, VAL_TYPE(value)); //check not needed

			// If FALSE return, copy values to the write location:
			if (mode == 1) {  // remove-each
				if (IS_CONDITIONAL_FALSE(D_OUT)) {
					REBCNT wide = SERIES_WIDE(series);
					// memory areas may overlap, so use memmove and not memcpy!
					memmove(series->data + (windex * wide), series->data + (rindex * wide), (index - rindex) * wide);
					windex += index - rindex;
					// old: while (rindex < index) *BLK_SKIP(series, windex++) = *BLK_SKIP(series, rindex++);
				}
			}
			else
				if (!IS_UNSET(D_OUT)) Append_Value(out, D_OUT); // (mode == 2)
		}
skip_hidden: ;
	}

	// Finish up:
	if (mode == 1) {
		// Remove hole (updates tail):
		if (windex < index) Remove_Series(series, windex, index - windex);
		SET_INTEGER(D_OUT, index - windex);

		return R_OUT;
	}

	// If MAP...
	if (mode == 2) {
		UNSAVE_SERIES(out);
		if (err != 2) {
			// ...and not BREAK/RETURN:
			Set_Block(D_OUT, out);
			return R_OUT;
		}
	}

	return R_OUT;
}
예제 #5
0
파일: n-loop.c 프로젝트: mbk/ren-c
*/	static int Loop_All(struct Reb_Call *call_, REBINT mode)
/*
**		0: forall
**		1: forskip
**
***********************************************************************/
{
	REBVAL *var;
	REBSER *body;
	REBCNT bodi;
	REBSER *dat;
	REBINT idx;
	REBINT inc = 1;
	REBCNT type;
	REBVAL *ds;

	var = GET_MUTABLE_VAR(D_ARG(1));
	if (IS_NONE(var)) return R_NONE;

	// Save the starting var value:
	*D_ARG(1) = *var;

	SET_NONE(D_OUT);

	if (mode == 1) inc = Int32(D_ARG(2));

	type = VAL_TYPE(var);
	body = VAL_SERIES(D_ARG(mode+2));
	bodi = VAL_INDEX(D_ARG(mode+2));

	// Starting location when past end with negative skip:
	if (inc < 0 && VAL_INDEX(var) >= VAL_TAIL(var)) {
		VAL_INDEX(var) = VAL_TAIL(var) + inc;
	}

	// NOTE: This math only works for index in positive ranges!

	if (ANY_SERIES(var)) {
		while (TRUE) {
			dat = VAL_SERIES(var);
			idx = VAL_INDEX(var);
			if (idx < 0) break;
			if (idx >= cast(REBINT, SERIES_TAIL(dat))) {
				if (inc >= 0) break;
				idx = SERIES_TAIL(dat) + inc; // negative
				if (idx < 0) break;
				VAL_INDEX(var) = idx;
			}

			if (!DO_BLOCK(D_OUT, body, bodi)) {	// Break, throw, continue, error.
				if (Check_Error(D_OUT) >= 0) {
					break;
				}
			}

			if (VAL_TYPE(var) != type) Trap_Arg_DEAD_END(var);

			VAL_INDEX(var) += inc;
		}
	}
	else Trap_Arg_DEAD_END(var);

	// !!!!! ???? allowed to write VAR????
	*var = *D_ARG(1);

	return R_OUT;
}
예제 #6
0
/** Scan converts the RLE encoded char - see notes above re structure of form. */
void rlechar(render_blit_t *rb, FORM *theform , dcoord sx , dcoord sy )
{
  register dcoord x1 , x2 , ey, h ;
  register int32 wupdate , wclipupdate;
  register dcoord x1c , x2c ;
  dcoord y1c, y2c;
  const dbbox_t *clip ;
  /* register */ uint8 *memory ;
  uint8 repeat ;
  int32 temp ;
  RLECACHE_LINE_READ_STATE state ;
  int32 span_lengths[2] ;

  HQASSERT( theFormH(*theform) > 0, "Rlechar height zero") ;
  HQASSERT( theFormW(*theform) > 0, "Rlechar width zero") ;

/* Preclip bounding box. */
  clip = &rb->p_ri->clip ;
  h = theFormH(*theform) ;
  y1c = clip->y1;
  if ( sy + h <= y1c )
    return ;
  y2c = clip->y2;
  if ( sy > y2c )
    return ;
  x2c = clip->x2;
  if ( sx > x2c )
    return ;
  x1c = clip->x1;
  if ( sx + theFormW(*theform) <= x1c )
    return ;

  memory = (uint8 *)theFormA(*theform) ;

  /* Partial clip of the top. */
  if ( ( temp = sy - y1c ) < 0 ) {
    for (;;) {  /* Skip block if totally clipped. */
      temp += memory[0] ;
      if ( temp > 0 )
        break ;
      memory += 2 + memory[1] ;

      /* Bail out if we've read all the data in the form */
      if ( memory >= (uint8 *)theform->addr + theform->size ) {
        HQFAIL("Off the end of a form");
        return;
      }
    }
    repeat =  (uint8)temp ;
    h -= y1c - sy;
    sy = y1c;
  }
  else {
    repeat = memory[0] ;
  }

  /* Partial clip of the bottom. */
  temp = sy + h ;
  if ( temp > y2c )
    h -= ( temp - y2c - 1 );

  if ( h <= 0 )
    return ;

  if ( h < (int32)repeat )
    repeat = (uint8)h ;

  /* Go for it.. */
  wupdate = theFormL(*rb->outputform) ;
  rb->ylineaddr = BLIT_ADDRESS(theFormA(*rb->outputform),
    wupdate * (sy - theFormHOff(*rb->outputform) - rb->y_sep_position)) ;
  wclipupdate = theFormL(*rb->clipform) ;
  rb->ymaskaddr = BLIT_ADDRESS(theFormA(*rb->clipform),
    wclipupdate * (sy - theFormHOff(*rb->clipform) - rb->y_sep_position)) ;

  /* use end coordinates 1 past the end of the span to reduce */
  /* number of +1 and -1 calculations */
  ++x2c ;
  state.next_line = memory;
  for ( ;; ) {
    rlecache_line_read_init(&state, theform, state.next_line);

    ey = sy + (int32)repeat - 1 ;
    x2 = sx ;   /* Start of first white span. */

    /* Last nibble can be ignored, because it would be a single white span */
    while ( ! state.line_finished ) {
      rlecache_get_span_pair(&state, span_lengths) ;
      x1 = x2 + span_lengths[0] ; /* White span - ignore. */
      x2 = x1 + span_lengths[1] ; /* Black span. */

      if ( x1 < x1c )
        x1 = x1c ;

      if ( x2 >= x2c ) { /* Touching or clipped off to the right, so ignore rest. */
        if ( x1 < x2c )
          DO_BLOCK(rb, sy, ey, x1, x2c - 1 );
        break ;
      }
      if ( x1 < x2 )
        DO_BLOCK(rb, sy, ey, x1, x2 - 1 ) ;
    }

    if ( ( h -= (int32)repeat ) <= 0 )
      return ;

    {
      int32 rows = ey - sy + 1 ;
      rb->ylineaddr = BLIT_ADDRESS(rb->ylineaddr, rows * wupdate) ;
      rb->ymaskaddr = BLIT_ADDRESS(rb->ymaskaddr, rows * wclipupdate) ;
      sy += rows ;
    }

    /* Bail out if we've read all the data in the form */
    if (state.next_line >= ((uint8 *) theform->addr) + theform->size) {
      HQFAIL("Off the end of a form");
      return;
    }

    repeat = state.next_line[0] ;
    if ( h < (int32)repeat )
      repeat = (uint8)h ;
  }
}