You are here

private function lessc::readChunk in Less CSS Preprocessor 6

1 call to lessc::readChunk()
lessc::parse in ./lessc.inc.php

File

./lessc.inc.php, line 106

Class

lessc

Code

private function readChunk() {
  if ($this->buffer == '') {
    return false;
  }

  // todo: media directive
  // media screen {
  // 	blocks
  // }
  // a property
  try {
    $this
      ->keyword($name)
      ->literal(':')
      ->propertyValue($value)
      ->end()
      ->advance();
    $this
      ->append($name, $value);

    // we can print it right away if we are in global scope (makes no sense, but w/e)
    if ($this->level > 1) {
      return true;
    }
    else {
      return $this
        ->compileProperty($name, array(
        $this
          ->getVal($name),
      )) . "\n";
    }
  } catch (exception $ex) {
    $this
      ->undo();
  }

  // entering a block
  try {
    $this
      ->tags($tags);

    // it can only be a function if there is one tag
    if (count($tags) == 1) {
      try {
        $save = $this->count;
        $this
          ->argumentDef($args);
      } catch (exception $ex) {
        $this->count = $save;
      }
    }
    $this
      ->literal('{')
      ->advance();
    $this
      ->push();

    //  move @ tags out of variable namespace!
    foreach ($tags as &$tag) {
      if ($tag[0] == "@") {
        $tag[0] = "%";
      }
    }
    $this
      ->set('__tags', $tags);
    if (isset($args)) {
      $this
        ->set('__args', $args);
    }
    return true;
  } catch (exception $ex) {
    $this
      ->undo();
  }

  // leaving a block
  try {
    $this
      ->literal('}')
      ->advance();
    $tags = $this
      ->multiplyTags();
    $env = end($this->env);
    $ctags = $env['__tags'];
    unset($env['__tags']);

    // insert the default arguments
    if (isset($env['__args'])) {
      foreach ($env['__args'] as $arg) {
        if (isset($arg[1])) {
          $this
            ->prepend('@' . $arg[0], $arg[1]);
        }
      }
    }
    if (!empty($tags)) {
      $out = $this
        ->compileBlock($tags, $env);
    }
    $this
      ->pop();

    // make the block(s) available in the new current scope
    foreach ($ctags as $t) {

      // if the block already exists then merge
      if ($this
        ->get($t, array(
        end($this->env),
      ))) {
        $this
          ->merge($t, $env);
      }
      else {
        $this
          ->set($t, $env);
      }
    }
    return isset($out) ? $out : true;
  } catch (exception $ex) {
    $this
      ->undo();
  }

  // look for import
  try {
    $this
      ->import($url, $media)
      ->advance();
    if ($this->importDisabled) {
      return "/* import is disabled */\n";
    }
    $full = $this->importDir . $url;
    if (file_exists($file = $full) || file_exists($file = $full . '.less')) {
      $this->buffer = $this
        ->removeComments(file_get_contents($file) . ";\n" . $this->buffer);
      return true;
    }
    return '@import url("' . $url . '")' . ($media ? ' ' . $media : '') . ";\n";
  } catch (exception $ex) {
    $this
      ->undo();
  }

  // setting a variable
  try {
    $this
      ->variable($name)
      ->literal(':')
      ->propertyValue($value)
      ->end()
      ->advance();
    $this
      ->append('@' . $name, $value);
    return true;
  } catch (exception $ex) {
    $this
      ->undo();
  }

  // look for a namespace/function to expand
  // todo: this catches a lot of invalid syntax because tag
  // consumer is liberal. This causes errors to be hidden
  try {
    $this
      ->tags($tags, true, '>');

    //  move @ tags out of variable namespace
    foreach ($tags as &$tag) {
      if ($tag[0] == "@") {
        $tag[0] = "%";
      }
    }

    // look for arguments
    $save = $this->count;
    try {
      $this
        ->argumentValues($argv);
    } catch (exception $ex) {
      $this->count = $save;
    }
    $this
      ->end()
      ->advance();

    // find the final environment
    $env = $this
      ->get(array_shift($tags));
    while ($sub = array_shift($tags)) {
      if (isset($env[$sub])) {

        // todo add a type check for environment
        $env = $env[$sub];
      }
      else {
        $env = null;
        break;
      }
    }
    if ($env == null) {
      return true;
    }

    // if we have arguments then insert them
    if (!empty($env['__args'])) {
      foreach ($env['__args'] as $arg) {
        $name = $arg[0];
        $value = is_array($argv) ? array_shift($argv) : null;

        // copy default value if there isn't one supplied
        if ($value == null && isset($arg[1])) {
          $value = $arg[1];
        }

        // if ($value == null) continue; // don't define so it can search up
        // create new entry if var doesn't exist in scope
        if (isset($env['@' . $name])) {
          array_unshift($env['@' . $name], $value);
        }
        else {

          // new element
          $env['@' . $name] = array(
            $value,
          );
        }
      }
    }

    // set all properties
    ob_start();
    foreach ($env as $name => $value) {

      // if it is a block then render it
      if (!isset($value[0])) {
        $rtags = $this
          ->multiplyTags(array(
          $name,
        ));
        echo $this
          ->compileBlock($rtags, $value);
      }

      // copy everything except metadata
      if (!preg_match('/^__/', $name)) {

        // don't overwrite previous value, look in current env for name
        if ($this
          ->get($name, array(
          end($this->env),
        ))) {
          while ($tval = array_shift($value)) {
            $this
              ->append($name, $tval);
          }
        }
        else {
          $this
            ->set($name, $value);
        }
      }
    }
    return ob_get_clean();
  } catch (exception $ex) {
    $this
      ->undo();
  }

  // ignore spare ;
  try {
    $this
      ->literal(';')
      ->advance();
    return true;
  } catch (exception $ex) {
    $this
      ->undo();
  }

  // something failed
  // print_r($this->env);
  $this
    ->match("(.*?)(\n|\$)", $m);
  throw new exception('Failed to parse line ' . $this->line . "\nOffending line: " . $m[1]);
}