variable = $variable; $this->value = $value; $this->context = $context; $this->param = $options ? $options['param'] : NULL; $this->subpattern = isset($options['subpattern']) ? $options['subpattern'] : NULL; $tmp = $this->variable->unwrap_all(); $forbidden = in_array($name = isset($tmp->value) ? $tmp->value : NULL, Lexer::$STRICT_PROSCRIBED); if ($forbidden && $this->context !== 'object') { throw new SyntaxError("variable name may not be $name"); } return $this; } function assigns($name) { if ($this->context === 'object') { return $this->value->assigns($name); } else { return $this->variable->assigns($name); } } function compile_conditional($options) { list($left, $right) = $this->variable->cache_reference($options); if ( ! count($left->properties) && $left->base instanceof yy_Literal && $left->base->value !== 'this' && ! $options['scope']->check($left->base->value)) { throw new Error('the variable "'.$this->left->base->value.'" can\'t be assigned with '.$this->context.' because it has not been defined.'); } if (strpos($this->context, '?') > -1) { $options['isExistentialEquals'] = TRUE; } $tmp = yy('Op', substr($this->context, 0, -1), $left, yy('Assign', $right, $this->value, '=')); return $tmp->compile($options); } function compile_node($options) { if (($is_value = ($this->variable instanceof yy_Value))) { if ($this->variable->is_array() || $this->variable->is_object()) { return $this->compile_pattern_match($options); } if ($this->variable->is_splice()) { return $this->compile_splice($options); } if (in_array($this->context, array('||=', '&&=', '?='), TRUE)) { return $this->compile_conditional($options); } } $name = $this->variable->compile($options, LEVEL_LIST); if ( ! $this->context) { if ( ! ( ($var_base = $this->variable->unwrap_all()) && $var_base->is_assignable())) { throw new SyntaxError('"'.$this->variable->compile($options).'" cannot be assigned.'); } if ( ! (is_callable(array($var_base, 'has_properties')) && $var_base->has_properties())) { if ($this->param) { $options['scope']->add($name, 'var'); } else { $options['scope']->find($name); } } } if ($this->value instanceof yy_Code && preg_match(METHOD_DEF, ''.$name, $match)) { if (isset($match[1]) && $match[1] !== '') { $this->value->klass = $match[1]; } foreach (range(2, 5) as $i) { if (isset($match[$i]) && $match[$i] !== '') { $this->value->name = $match[$i]; break; } } } $val = $this->value->compile($options, LEVEL_LIST); if ($this->context === 'object') { return "{$name}: {$val}"; } $val = $name.' '.($this->context ? $this->context : '=').' '.$val; return $options['level'] <= LEVEL_LIST ? $val : "({$val})"; } 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_splice($options) { $tmp = array_pop($this->variable->properties); $from = $tmp->range->from; $to = $tmp->range->to; $exclusive = $tmp->range->exclusive; $name = $this->variable->compile($options); list($from_decl, $from_ref) = $from ? $from->cache($options, LEVEL_OP) : array('0', '0'); if ($to) { if (($from && $from->is_simple_number()) && $to->is_simple_number()) { $to = intval($to->compile($options)) - intval($from_ref); if ( ! $exclusive) { $to++; } } else { $to = $to->compile($options, LEVEL_ACCESS).' - '. $from_ref; if ( ! $exclusive) { $to .= ' + 1'; } } } else { $to = '9e9'; } list($val_def, $val_ref) = $this->value->cache($options, LEVEL_LIST); $code = "[].splice.apply({$name}, [{$from_decl}, {$to}].concat({$val_def})), {$val_ref}"; return $options['level'] > LEVEL_TOP ? "({$code})" : $code; } function is_statement($options) { return isset($options['level']) && $options['level'] === LEVEL_TOP && $this->context && strpos($this->context, '?') > -1; } function unfold_soak($options) { return unfold_soak($options, $this, 'variable'); } } ?>