static function compile_splatted_array($options, $list, $apply = FALSE) { $index = -1; while (isset($list[++$index]) && ($node = $list[$index]) && !$node instanceof yy_Splat) { continue; } if ($index >= count($list)) { return ''; } if (count($list) === 1) { $code = $list[0]->compile($options, LEVEL_LIST); if ($apply) { return $code; } return utility('slice') . ".call({$code})"; } $args = array_slice($list, $index); foreach ($args as $i => $node) { $code = $node->compile($options, LEVEL_LIST); $args[$i] = $node instanceof yy_Splat ? utility('slice') . ".call({$code})" : "[{$code}]"; } if ($index === 0) { return $args[0] . '.concat(' . implode(', ', array_slice($args, 1)) . ')'; } $base = array(); foreach (array_slice($list, 0, $index) as $node) { $base[] = $node->compile($options, LEVEL_LIST); } return '[' . implode(', ', $base) . '].concat(' . implode(', ', $args) . ')'; }
function add_bound_functions($options) { if ($this->bound_funcs) { foreach ($this->bound_funcs as $bvar) { $lhs = yy('Value', yy('Literal', 'this'), array(yy('Access', $bvar)))->compile($options); $this->ctor->body->unshift(yy('Literal', "{$lhs} = " . utility('bind') . "({$lhs}, this)")); } } }
function add_bound_functions($options) { if ($this->bound_funcs) { foreach ($this->bound_funcs as $bvar) { $bname = $bvar->compile($options); $this->ctor->body->unshift(yy('Literal', "this.{$bname} = " . utility('bind') . "(this.{$bname}, this)")); } } }
function compile_loop_test($options) { list($sub, $ref) = $this->object->cache($options, LEVEL_LIST); $code = utility('indexOf') . ".call(" . $this->array->compile($options, LEVEL_LIST) . ", {$ref}) " . ($this->negated ? '< 0' : '>= 0'); if ($sub === $ref) { return $code; } $code = $sub . ', ' . $code; return isset($options['level']) && $options['level'] < LEVEL_LIST ? $code : "({$code})"; }
function add_bound_functions($options) { if (count($this->bound_funcs)) { foreach ($this->bound_funcs as $bvar) { $bname = $bvar->compile($options); $body = is_array($this->ctor->body) ? $this->ctor->body : array($this->ctor->body); array_unshift($body, yy('Literal', "this.{$bname} = " . utility('bind') . "(this.{$bname}, this)")); } } }
function compile_node($options) { $body = yy_Block::wrap(array($this->body)); $last_jumps = last($body->expressions); $last_jumps = $last_jumps ? $last_jumps->jumps() : FALSE; if ($last_jumps && $last_jumps instanceof yy_Return) { $this->returns = FALSE; } if ($this->range) { $source = $this->source->base; } else { $source = $this->source; } $scope = $options['scope']; $name = $this->name ? $this->name->compile($options, LEVEL_LIST) : FALSE; $index = $this->index ? $this->index->compile($options, LEVEL_LIST) : FALSE; if ($name && !$this->pattern) { $scope->find($name, array('immediate' => TRUE)); } if ($index) { $scope->find($index, array('immediate' => TRUE)); } if ($this->returns) { $rvar = $scope->free_variable('results'); } $ivar = $this->object ? $index : $scope->free_variable('i'); $kvar = $this->range ? $name ? $name : ($index ? $index : $ivar) : ($index ? $index : $ivar); $kvar_assign = $kvar !== $ivar ? "{$kvar} = " : ''; if ($this->step && !$this->range) { $stepvar = $scope->free_variable('step'); } if ($this->pattern) { $name = $ivar; } $var_part = ''; $guard_part = ''; $def_part = ''; $idt1 = $this->tab . TAB; if ($this->range) { $for_part = $source->compile(array_merge($options, array('index' => $ivar, 'name' => $name, 'step' => $this->step))); } else { $svar = $this->source->compile($options, LEVEL_LIST); if (($name || $this->own) && !preg_match(IDENTIFIER, $svar)) { $ref = $scope->free_variable('ref'); $def_part = "{$this->tab}{$ref} = {$svar};\n"; $svar = $ref; } if ($name && !$this->pattern) { $name_part = "{$name} = {$svar}[{$kvar}]"; } if (!$this->object) { $lvar = $scope->free_variable('len'); $for_var_part = "{$kvar_assign}{$ivar} = 0, {$lvar} = {$svar}.length"; if ($this->step) { $for_var_part .= ", {$stepvar} = " . $this->step->compile($options, LEVEL_OP); } $step_part = $kvar_assign . ($this->step ? "{$ivar} += {$stepvar}" : ($kvar !== $ivar ? "++{$ivar}" : "{$ivar}++")); $for_part = "{$for_var_part}; {$ivar} < {$lvar}; {$step_part}"; } } if ($this->returns) { $result_part = "{$this->tab}{$rvar} = [];\n"; $return_result = "\n{$this->tab}return {$rvar};"; $body->make_return($rvar); } if ($this->guard) { if ($body->expressions) { array_unshift($body->expressions, yy('If', yy('Parens', $this->guard)->invert(), yy('Literal', 'continue'))); } else { $body = yy_Block::wrap(array(yy('If', $this->guard, $body))); } } if ($this->pattern) { array_unshift($body->expressions, yy('Assign', $this->name, yy('Literal', "{$svar}[{$kvar}]"))); } $def_part .= $this->pluck_direct_call($options, $body); if (isset($name_part) && $name_part) { $var_part = "\n{$idt1}{$name_part};"; } if ($this->object) { $for_part = "{$kvar} in {$svar}"; if ($this->own) { $guard_part = "\n{$idt1}if (!" . utility('hasProp') . ".call({$svar}, {$kvar})) continue;"; } } $body = $body->compile(array_merge($options, array('indent' => $idt1)), LEVEL_TOP); if ($body) { $body = "\n{$body}\n"; } return "{$def_part}" . (isset($result_part) ? $result_part : '') . "{$this->tab}for ({$for_part}) {{$guard_part}{$var_part}{$body}{$this->tab}}" . (isset($return_result) ? $return_result : ''); }
function compile_pattern_match($options) { $top = $options['level'] === LEVEL_TOP; $value = $this->value; $objects = $this->variable->base->objects; if (!($olen = count($objects))) { $code = $value->compile($options); return $options['level'] >= LEVEL_OP ? "({$code})" : $code; } $is_object = $this->variable->is_object(); if ($top && $olen === 1 && !($obj = $objects[0]) instanceof yy_Splat) { if ($obj instanceof yy_Assign) { $idx = $obj->variable->base; $obj = $obj->value; } else { if ($obj->base instanceof yy_Parens) { $tmp = yy('Value', $obj->unwrap_all()); list($obj, $idx) = $tmp->cache_reference($options); } else { if ($is_object) { $idx = $obj->this ? $obj->properties[0]->name : $obj; } else { $idx = yy('Literal', 0); } } } $acc = preg_match(IDENTIFIER, $idx->unwrap()->value); $value = yy('Value', $value); if ($acc) { $value->properties[] = yy('Access', $idx); } else { $value->properties[] = yy('Index', $idx); } $tmp = $obj->unwrap(); $tmp = isset($tmp->value) ? $tmp->value : NULL; if (in_array($tmp, Lexer::$COFFEE_RESERVED)) { throw new SyntaxError('assignment to a reserved word: ' . $obj->compile($options) . ' = ' . $value->compile($options)); } return yy('Assign', $obj, $value, NULL, array('param' => $this->param))->compile($options, LEVEL_TOP); } $vvar = $value->compile($options, LEVEL_LIST); $assigns = array(); $splat = FALSE; if (!preg_match(IDENTIFIER, $vvar) || $this->variable->assigns($vvar)) { $assigns[] = ($ref = $options['scope']->free_variable('ref')) . ' = ' . $vvar; $vvar = $ref; } foreach ($objects as $i => $obj) { $idx = $i; if ($is_object) { if ($obj instanceof yy_Assign) { $idx = $obj->variable->base; $obj = $obj->value; } else { if ($obj->base instanceof yy_Parens) { $tmp = yy('Value', $obj->unwrap_all()); list($obj, $idx) = $tmp->cache_reference($options); } else { $idx = $obj->this ? $obj->properties[0]->name : $obj; } } } if (!$splat && $obj instanceof yy_Splat) { $name = $obj->name->unwrap()->value; $obj = $obj->unwrap(); $val = "{$olen} <= {$vvar}.length ? " . utility('slice') . ".call({$vvar}, {$i}"; $ivar = 'undefined'; if ($rest = $olen - $i - 1) { $ivar = $options['scope']->free_variable('i'); $val .= ", {$ivar} = {$vvar}.length - {$rest}) : ({$ivar} = {$i}, [])"; } else { $val .= ') : []'; } $val = yy('Literal', $val); $splat = "{$ivar}++"; } else { $name = $obj->unwrap(); $name = isset($name->value) ? $name->value : NULL; if ($obj instanceof yy_Splat) { $obj = $obj->name->compile($options); throw new SyntaxError("multiple splats are disallowed in an assignment: {$obj}..."); } if (is_numeric($idx)) { $idx = yy('Literal', $splat ? $splat : $idx); $acc = FALSE; } else { $acc = $is_object ? preg_match(IDENTIFIER, $idx->unwrap()->value) : 0; } $val = yy('Value', yy('Literal', $vvar), array($acc ? yy('Access', $idx) : yy('Index', $idx))); } if (isset($name) && $name && in_array($name, Lexer::$COFFEE_RESERVED)) { throw new SyntaxError("assignment to a reserved word: " . $obj->compile($options) . ' = ' . $val->compile($options)); } $tmp = yy('Assign', $obj, $val, NULL, array('param' => $this->param, 'subpattern' => TRUE)); $assigns[] = $tmp->compile($options, LEVEL_TOP); } if (!($top || $this->subpattern)) { $assigns[] = $vvar; } $code = implode(', ', $assigns); return $options['level'] < LEVEL_LIST ? $code : "({$code})"; }
function compile($options) { $tmp = yy('Call', yy('Value', yy('Literal', utility('extends'))), array($this->child, $this->parent)); return $tmp->compile($options); }
function compile_node($options) { $options['scope'] = new Scope($options['scope'], $this->body, $this); $options['scope']->shared = del($options, 'sharedScope'); $options['indent'] .= TAB; unset($options['bare']); $vars = array(); $exprs = array(); foreach ($this->params as $param) { if ($param->splat) { if (isset($param->name->value) && $param->name->value) { $options['scope']->add($param->name->value, 'var'); } $params = array(); foreach ($this->params as $p) { $params[] = $p->as_reference($options); } $splats = yy('Assign', yy('Value', yy('Arr', $params)), yy('Value', yy('Literal', 'arguments'))); break; } } foreach ($this->params as $param) { if ($param->is_complex()) { $val = $ref = $param->as_reference($options); if ($param->value) { $val = yy('Op', '?', $ref, $param->value); } $exprs[] = yy('Assign', yy('Value', $param->name), $val, '=', array('param' => TRUE)); } else { $ref = $param; if ($param->value) { $lit = yy('Literal', $ref->name->value . ' == null'); $val = yy('Assign', yy('Value', $param->name), $param->value, '='); $exprs[] = yy('If', $lit, $val); } } if (!(isset($splats) && $splats)) { $vars[] = $ref; } } $was_empty = $this->body->is_empty(); if (isset($splats) && $splats) { array_unshift($exprs, $splats); } if (count($exprs)) { $this->body->expressions = array_merge($this->body->expressions, $exprs); } if (!(isset($splats) && $splats)) { foreach ($vars as $i => $v) { $options['scope']->parameter($vars[$i] = $v->compile($options)); } } if (!($was_empty || $this->no_return)) { $this->body->make_return(); } $idt = $options['indent']; $code = 'function'; if ($this->ctor) { $code .= ' ' . $this->name; } $code .= '(' . implode(', ', $vars) . ') {'; if (!$this->body->is_empty()) { $code .= "\n" . $this->body->compile_with_declarations($options) . "\n{$this->tab}"; } $code .= '}'; if ($this->ctor) { return $this->tab . $code; } if ($this->bound) { return utility('bind') . "({$code}, {$this->context})"; } return $this->front || $options['level'] >= LEVEL_ACCESS ? "({$code})" : $code; }