static function wrap($name, $exps) { if ($exps->is_empty() || last($exps->expressions)->jumps()) { return $exps; } return $exps->push(yy('Call', yy('Value', yy('Literal', $name), array(yy('Access', yy('Literal', 'push')))), array($exps->pop()))); }
function compile_node($options) { $options['indent'] .= TAB; $set = ''; $body = $this->body; if ($body->is_empty()) { $body = ''; } else { if ($this->returns) { $body->make_return($rvar = $options['scope']->free_variable('results')); $set = "{$this->tab}{$rvar} = [];\n"; } if ($this->guard) { if (count($body->expressions) > 1) { 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))); } } $body = "\n" . $body->compile($options, LEVEL_TOP) . "\n{$this->tab}"; } $code = $set . $this->tab . 'while (' . $this->condition->compile($options, LEVEL_PAREN) . ") {{$body}}"; if ($this->returns) { $code .= "\n{$this->tab}return {$rvar};"; } return $code; }
function compile_node($options) { $options['indent'] .= TAB; $set = ''; $body = $this->body; if ($body->is_empty()) { $body = ''; } else { if ($options['level'] > LEVEL_TOP || $this->returns) { $rvar = $options['scope']->free_variable('results'); $set = "{$this->tab}{$rvar} = [];\n"; if ($body) { $body = yy_Push::wrap($rvar, $body); } } if ($this->guard) { $body = yy_Block::wrap(array(yy('If', $this->guard, $body))); } $body = "\n" . $body->compile($options, LEVEL_TOP) . "\n{$this->tab}"; } $code = $set . $this->tab . 'while (' . $this->condition->compile($options, LEVEL_PAREN) . ") {{$body}}"; if ($this->returns) { $code .= "\n{$this->tab}return {$rvar};"; } return $code; }
function compile_node($options) { $props = $this->properties; $prop_names = array(); foreach ($this->properties as $prop) { if ($prop->is_complex()) { $prop = isset($prop->variable) ? $prop->variable : NULL; } if ($prop) { $prop_name = $prop->unwrap_all(); $prop_name = isset($prop_name->value) ? $prop_name->value . '' : NULL; if (in_array($prop_name, $prop_names)) { throw new SyntaxError('multiple object literal properties named "' . $prop_name . '"'); } $prop_names[] = $prop_name; } } if (!count($props)) { return $this->front ? '({})' : '{}'; } if ($this->generated) { foreach ($props as $node) { if ($node instanceof yy_Value) { throw new Error('cannot have an implicit value in an implicit object'); } } } $idt = $options['indent'] .= TAB; $last_non_com = $this->last_non_comment($this->properties); foreach ($props as $i => $prop) { if ($i === count($props) - 1) { $join = ''; } else { if ($prop === $last_non_com || $prop instanceof yy_Comment) { $join = "\n"; } else { $join = ",\n"; } } $indent = $prop instanceof yy_Comment ? '' : $idt; if ($prop instanceof yy_Value && (isset($prop->this) && $prop->this)) { $prop = yy('Assign', $prop->properties[0]->name, $prop, 'object'); } if (!$prop instanceof yy_Comment) { if (!$prop instanceof yy_Assign) { $prop = yy('Assign', $prop, $prop, 'object'); } if (isset($prop->variable->base)) { $prop->variable->base->as_key = TRUE; } else { $prop->variable->as_key = TRUE; } } $props[$i] = $indent . $prop->compile($options, LEVEL_TOP) . $join; } $props = implode('', $props); $obj = '{' . ($props ? "\n{$props}\n{$this->tab}" : '') . '}'; return $this->front ? "({$obj})" : $obj; }
function constructor($name) { if (is_object($name)) { $this->name = $name; } else { $this->name = yy('Literal', $name); } return $this; }
static function unfold_soak($options, $parent, $name) { if (!(isset($parent->{$name}) && $parent->{$name} && ($ifn = $parent->{$name}->unfold_soak($options)))) { return NULL; } $parent->{$name} = $ifn->body; $ifn->body = yy('Value', $parent); return $ifn; }
function make_return($res = NULL) { foreach ($this->cases as $pair) { $pair[1]->make_return($res); } if ($res && !$this->otherwise) { $this->otherwise = yy('Block', array(yy('Literal', 'void 0'))); } if ($this->otherwise) { $this->otherwise->make_return($res); } return $this; }
static function wrap($expressions, $statement = NULL, $no_return = FALSE) { if ($expressions->jumps()) { return $expressions; } $func = yy('Code', array(), yy_Block::wrap(array($expressions))); $args = array(); if (($mentions_args = $expressions->contains('yy_Closure::literal_args')) || $expressions->contains('yy_Closure::literal_this')) { $meth = yy('Literal', $mentions_args ? 'apply' : 'call'); $args = array(yy('Literal', 'this')); if ($mentions_args) { $args[] = yy('Literal', 'arguments'); } $func = yy('Value', $func, array(yy('Access', $meth))); } $func->no_return = $no_return; $call = yy('Call', $func, $args); return $statement ? yy_Block::wrap(array($call)) : $call; }
function as_reference($options) { if (isset($this->reference) && $this->reference) { return $this->reference; } $node = $this->name; if (isset($node->this) && $node->this) { $node = $node->properties[0]->name; if (isset($this->value->reserved) && $this->value->reserved) { $node = yy('Literal', $options['scope']->free_variable($node->value)); } } else { if ($node->is_complex()) { $node = yy('Literal', $options['scope']->free_variable('arg')); } } $node = yy('Value', $node); if ($this->splat) { $node = yy('Splat', $node); } return $this->reference = $node; }
function filter_implicit_objects() { return call_user_func_array(array(yy('Call'), __FUNCTION__), func_get_args()); }
function unfold_soak($options) { if ($this->soak) { if ($this->variable) { if ($ifn = unfold_soak($options, $this, 'variable')) { return $ifn; } $tmp = yy('Value', $this->variable); list($left, $rite) = $tmp->cache_reference($options); } else { $left = yy('Literal', $this->super_reference($options)); $rite = yy('Value', $left); } $rite = yy('Call', $rite, $this->args); $rite->is_new($this->is_new()); $left = yy('Literal', 'typeof ' . $left->compile($options) . ' === "function"'); return yy('If', $left, yy('Value', $rite), array('soak' => TRUE)); } $call = $this; $list = array(); while (TRUE) { if ($call->variable instanceof yy_Call) { $list[] = $call; $call = $call->variable; continue; } if (!$call->variable instanceof yy_Value) { break; } $list[] = $call; if (!($call = $call->variable->base) instanceof yy_Call) { break; } } foreach (array_reverse($list) as $call) { if (isset($ifn)) { if ($call->variable instanceof yy_Call) { $call->variable = $ifn; } else { $call->variable->base = $ifn; } } $ifn = unfold_soak($options, $call, 'variable'); } return isset($ifn) ? $ifn : NULL; }
function pluck_direct_call($options, $body) { $defs = ''; foreach ($body->expressions as $idx => $expr) { $expr = $expr->unwrap_all(); if (!$expr instanceof yy_Call) { continue; } $val = $expr->variable->unwrap_all(); if (!($val instanceof yy_Code || $val instanceof yy_Value && (isset($val->base) && $val->base && $val->base->unwrap_all() instanceof yy_Code && count($val->properties) === 1 && isset($val->properties[0]->name) && in_array($val->properties[0]->name['value'], array('call', 'apply'), TRUE)))) { continue; } $fn = isset($val->base) && $val->base ? $val->base->unwrap_all() : $val; $ref = yy('Literal', $options['scope']->free_variable('fn')); $base = yy('Value', $ref); if (isset($val->base) && $val->base) { list($val->base, $base) = array($base, $val); } $body->expressions[$idx] = yy('Call', $base, $expr->args); $tmp = yy('Assign', $ref, $fn); $defs .= $this->tab . $tmp->compile($options, LEVEL_TOP) . ";\n"; } return $defs; }
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 make_return($res = NULL) { $me = $this->unwrap_all(); if ($res) { return yy('Call', yy('Literal', "{$res}.push"), array($me)); } else { return yy('Return', $me); } }
function make_return() { if ($this->body) { $this->body = yy('Block', array($this->body->make_return())); } if ($this->else_body) { $this->else_body = yy('Block', array($this->else_body->make_return())); } return $this; }
function make_return() { return yy('Return', $this); }
function invert() { if ($this->is_chainable() && $this->first->is_chainable()) { $all_invertable = TRUE; $curr = $this; while ($curr && (isset($curr->operator) && $curr->operator)) { $all_invertable = $all_invertable && isset(self::$INVERSIONS[$curr->operator]); $curr = $curr->first; } if (!$all_invertable) { $tmp = yy('Parens', $this); return $tmp->invert(); } $curr = $this; while ($curr && (isset($curr->operator) && $curr->operator)) { $curr->invert = !(isset($curr->invert) && $curr->invert); $curr->operator = self::$INVERSIONS[$curr->operator]; $curr = $curr->first; } return $this; } else { if (isset(self::$INVERSIONS[$this->operator]) && ($op = self::$INVERSIONS[$this->operator])) { $this->operator = $op; if ($this->first->unwrap() instanceof yy_Op) { $this->first->invert(); } return $this; } else { if ($this->second) { $tmp = yy('Parens', $this); return $tmp->invert(); } else { if ($this->operator === '!' && ($fst = $this->first->unwrap()) instanceof yy_Op && in_array($fst->operator, array('!', 'in', 'instanceof'), TRUE)) { return $fst; } else { return yy('Op', '!', $this); } } } } }
function compile($options) { $tmp = yy('Call', yy('Value', yy('Literal', utility('extends'))), array($this->child, $this->parent)); return $tmp->compile($options); }
function make_return() { return $this->is_statement() ? $this : yy('Return', $this); }
function generate_do($exp) { $passed_params = array(); $func = $exp; if ($exp instanceof yy_Assign && ($ref = $exp->value->unwrap()) instanceof yy_Code) { $func = $ref; } foreach (isset($func->params) && $func->params ? $func->params : array() as $param) { if (isset($param->value) && $param->value) { $passed_params[] = $param->value; unset($param->value); } else { $passed_params[] = $param; } } $call = yy('Call', $exp, $passed_params); $call->do = TRUE; return $call; }
function unfold_soak($options) { if (isset($this->unfolded_soak)) { return $this->unfolded_soak; } $result = NULL; if ($ifn = $this->base->unfold_soak($options)) { $ifn->body->properties = array_merge($ifn->body->properties, $this->properties); $result = $ifn; } else { foreach ($this->properties as $i => $prop) { if (isset($prop->soak) && $prop->soak) { $prop->soak = FALSE; $fst = yy('Value', $this->base, array_slice($this->properties, 0, $i)); $snd = yy('Value', $this->base, array_slice($this->properties, $i)); if ($fst->is_complex()) { $ref = yy('Literal', $options['scope']->free_variable('ref')); $fst = yy('Parens', yy('Assign', $ref, $fst)); $snd->base = $ref; } $result = yy('If', yy('Existence', $fst), $snd, array('soak' => TRUE)); } } } $this->unfolded_soak = $result ? $result : FALSE; return $this->unfolded_soak; }
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; }
function make_return($res = NULL) { if (!(isset($this->else_body) && $this->else_body)) { if ($res) { $this->else_body = yy('Block', array(yy('Literal', 'void 0'))); } } if ($this->body) { $this->body = yy('Block', array($this->body->make_return($res))); } if ($this->else_body) { $this->else_body = yy('Block', array($this->else_body->make_return($res))); } return $this; }
static function wrap($nodes) { if (!is_array($nodes)) { $nodes = array($nodes); } if (count($nodes) === 1 && $nodes[0] instanceof yy_Block) { return $nodes[0]; } return yy('Block', $nodes); }
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']); unset($options['isExistentialEquals']); $params = array(); $exprs = array(); foreach ($this->param_names() as $name) { if (!$options['scope']->check($name)) { $options['scope']->parameter($name); } } foreach ($this->params as $param) { if ($param->splat) { if (isset($param->name->value) && $param->name->value) { $options['scope']->add($param->name->value, 'var', TRUE); } $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 (isset($param->value) && $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)) { $params[] = $ref; } } $was_empty = $this->body->is_empty(); if (isset($splats) && $splats) { array_unshift($exprs, $splats); } if ($exprs) { foreach (array_reverse($exprs) as $expr) { array_unshift($this->body->expressions, $expr); } } foreach ($params as $i => $p) { $options['scope']->parameter($params[$i] = $p->compile($options)); } $uniqs = array(); foreach ($this->param_names() as $name) { if (in_array($name, $uniqs)) { throw new SyntaxError("multiple parameters named {$name}"); } $uniqs[] = $name; } if (!($was_empty || $this->no_return)) { $this->body->make_return(); } if ($this->bound) { if (isset($options['scope']->parent->method->bound) && $options['scope']->parent->method->bound) { $this->bound = $this->context = $options['scope']->parent->method->context; } else { if (!(isset($this->static) && $this->static)) { $options['scope']->parent->assign('_this', 'this'); } } } $idt = $options['indent']; $code = 'function'; if ($this->ctor) { $code .= ' ' . $this->name; } $code .= '(' . implode(', ', $params) . ') {'; if (!$this->body->is_empty()) { $code .= "\n" . $this->body->compile_with_declarations($options) . "\n{$this->tab}"; } $code .= '}'; if ($this->ctor) { return $this->tab . $code; } return $this->front || $options['level'] >= LEVEL_ACCESS ? "({$code})" : $code; }
function ensure_constructor($name) { if (!(isset($this->ctor) && $this->ctor)) { $this->ctor = yy('Code'); if ($this->parent) { $this->ctor->body->push(yy('Literal', "{$name}.__super__.constructor.apply(this, arguments)")); } if (isset($this->external_ctor) && $this->external_ctor) { $this->ctor->body->push(yy('Literal', "{$this->external_ctor}.apply(this, arguments)")); } $this->ctor->body->make_return(); array_unshift($this->body->expressions, $this->ctor); } $this->ctor->ctor = $this->ctor->name = $name; $this->ctor->klass = NULL; $this->ctor->no_return = TRUE; }