// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library parser_helper;

import "package:expect/expect.dart";

import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
import "../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart";
import "../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart";
import "../../../sdk/lib/_internal/compiler/implementation/source_file.dart";
import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";

import "../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart"
    show CompilationUnitElementX,
         LibraryElementX;

import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart";

export "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart"
    show DiagnosticListener;
// TODO(ahe): We should have token library to export instead.
export "../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart";

class LoggerCanceler implements DiagnosticListener {
  void cancel(String reason, {node, token, instruction, element}) {
    throw new CompilerCancelledException(reason);
  }

  void log(message) {
    print(message);
  }

  void internalErrorOnElement(element, String message) {
    log(message);
  }

  void internalError(String message, {node, token, instruction, element}) {
    log(message);
  }

  SourceSpan spanFromSpannable(node) {
    throw 'unsupported operation';
  }

  void reportMessage(SourceSpan span, Message message, kind) {
    log(message);
  }

  void reportError(Spannable node, MessageKind errorCode, [Map arguments]) {
    log(new Message(errorCode, arguments, false));
  }

  void reportWarning(Spannable node, MessageKind errorCode, [Map arguments]) {
    log(new Message(errorCode, arguments, false));
  }

  void reportInfo(Spannable node, MessageKind errorCode, [Map arguments]) {
    log(new Message(errorCode, arguments, false));
  }

  withCurrentElement(Element element, f()) => f();
}

Token scan(String text) => new StringScanner.fromString(text).tokenize();

Node parseBodyCode(String text, Function parseMethod,
                   {DiagnosticListener diagnosticHandler}) {
  Token tokens = scan(text);
  if (diagnosticHandler == null) diagnosticHandler = new LoggerCanceler();
  Uri uri = new Uri(scheme: "source");
  Script script = new Script(uri, uri,new MockFile(text));
  LibraryElement library = new LibraryElementX(script);
  library.canUseNative = true;
  NodeListener listener =
      new NodeListener(diagnosticHandler, library.entryCompilationUnit);
  Parser parser = new Parser(listener);
  Token endToken = parseMethod(parser, tokens);
  assert(endToken.kind == EOF_TOKEN);
  Node node = listener.popNode();
  Expect.isNotNull(node);
  Expect.isTrue(listener.nodes.isEmpty, 'Not empty: ${listener.nodes}');
  return node;
}

Node parseStatement(String text) =>
  parseBodyCode(text, (parser, tokens) => parser.parseStatement(tokens));

Node parseFunction(String text, Compiler compiler) {
  Element element = parseUnit(text, compiler, compiler.mainApp).head;
  Expect.isNotNull(element);
  Expect.equals(ElementKind.FUNCTION, element.kind);
  return element.parseNode(compiler);
}

Node parseMember(String text, {DiagnosticListener diagnosticHandler}) {
  return parseBodyCode(text, (parser, tokens) => parser.parseMember(tokens),
                       diagnosticHandler: diagnosticHandler);
}

class MockFile extends StringSourceFile {
  MockFile(text)
      : super('<string>', text);
}

var sourceCounter = 0;

Link<Element> parseUnit(String text, Compiler compiler,
                        LibraryElement library,
                        [void registerSource(Uri uri, String source)]) {
  Token tokens = scan(text);
  Uri uri = new Uri(scheme: "source", path: '${++sourceCounter}');
  if (registerSource != null) {
    registerSource(uri, text);
  }
  var script = new Script(uri, uri, new MockFile(text));
  var unit = new CompilationUnitElementX(script, library);
  int id = 0;
  ElementListener listener = new ElementListener(compiler, unit, () => id++);
  PartialParser parser = new PartialParser(listener);
  compiler.withCurrentElement(unit, () => parser.parseUnit(tokens));
  return unit.localMembers;
}

NodeList fullParseUnit(String source, {DiagnosticListener diagnosticHandler}) {
  return parseBodyCode(source, (parser, tokens) => parser.parseUnit(tokens),
                       diagnosticHandler: diagnosticHandler);
}
