Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(311)

Unified Diff: sdk/lib/_internal/compiler/implementation/prolog/prolog.dart

Issue 1259553002: Emit program and dependency information as relations in a Prolog database. Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/prolog/prolog.dart
diff --git a/sdk/lib/_internal/compiler/implementation/prolog/prolog.dart b/sdk/lib/_internal/compiler/implementation/prolog/prolog.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e85f75f91966ffddaa8b30164c88450f10d7925d
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/prolog/prolog.dart
@@ -0,0 +1,251 @@
+library prolog;
+
+import '../common.dart';
+import 'dart:async';
+import 'dart:collection';
+
+abstract class Node {
+ const Node();
+}
+
+abstract class Term extends Node {
+ const Term();
+}
+
+class Atom extends Term {
+ final String text;
+ const Atom(this.text);
+
+ get hashCode => text.hashCode;
+
+ operator ==(other) => text == other.text;
+
+ static const Atom AND = const Atom(",");
+ static const Atom OR = const Atom(";");
+ static const Atom IMPLY = const Atom(":-");
+}
+
+class Compound extends Term {
+ final Atom functor;
+ final List<Term> arguments;
+ const Compound(this.functor, [this.arguments = const <Term>[]]);
+ bool get isAnd => functor == Atom.AND;
+ bool get isOr => functor == Atom.OR;
+ bool get isImply => functor == Atom.IMPLY;
+}
+
+class And extends Compound {
+ const And(List<Term> arguments) : super(Atom.AND, arguments);
+}
+
+class Or extends Compound {
+ const Or(List<Term> arguments) : super(Atom.OR, arguments);
+}
+
+class Clause extends Compound {
+ Clause(Term head, [List<Term> body = const <Term>[]])
+ : super(Atom.IMPLY, <Term>[head]..addAll(body));
+
+ Atom get predicate {
+ Term head = arguments.first;
+ return head is Compound ? head.functor : head;
+ }
+
+ Term get head => arguments.first;
+
+ Iterable<Term> get body => arguments.skip(1);
+}
+
+
+class Program {
+ Map<Atom, List<Clause>> clauses = <Atom, List<Clause>>{};
+
+ void add(Clause clause) {
+ assert(clause != null);
+ clauses.putIfAbsent(clause.predicate, () => <Clause>[]).add(clause);
+ }
+
+ void addClause(Term head, List<Term> body) => add(new Clause(head, body));
+
+ Iterable<Clause> getClausesFor(Atom predicate) {
+ return clauses.containsKey(predicate)
+ ? clauses[predicate]
+ : const <Clause>[];
+ }
+
+ Program mergeWith(Program other) {
+ clauses.addAll(other.clauses);
+ return this;
+ }
+}
+
+
+class ProgramEmitter {
+ final EventSink<String> _sink;
+
+ ProgramEmitter(this._sink);
+
+ String _quoteAtom(Atom atom) {
+ String text = atom.text;
+ if (text == "" ||
+ text.contains(new RegExp(r'[^_0-9a-zA-Z]')) ||
+ text.indexOf(new RegExp('[_0-9A-Z]')) == 0) {
+ return "'$text'";
+ } else {
+ return text;
+ }
+ }
+
+ void _emit(String text) => _sink.add(text);
+
+ void _emitAtom(Atom atom, {quote: true}) {
+ _emit(quote ? _quoteAtom(atom) : atom.text);
+ }
+
+ void _emitTerm(Term term) {
+ if (term is Atom) {
+ _emitAtom(term);
+ } else if (term is Compound) {
+ _emitAtom(term.functor);
+ _open();
+ _emitList(term.arguments);
+ _close();
+ } else {
+ throw 'unsupported $term';
+ }
+ }
+
+ void _emitList(Iterable<Term> terms, {separator: ', '}) {
+ if (terms.isEmpty) return;
+ _emitTerm(terms.first);
+ for (Term term in terms.skip(1)) {
+ _emit(separator);
+ _emitTerm(term);
+ }
+ }
+
+ void _open() => _emit('(');
+
+ void _close() => _emit(')');
+
+ void _space() => _emit(' ');
+
+ void _endClause() => _emit('.\n');
+
+ void emitProgram(Program program) {
+ for (Atom predicate in program.clauses.keys) {
+ if (program.clauses[predicate] == null) print(predicate.text);
+ for (Clause clause in program.clauses[predicate]) {
+ _emitTerm(clause.head);
+ Iterable<Term> body = clause.body;
+ if (body.isNotEmpty) {
+ _space();
+ _emitAtom(Atom.IMPLY, quote: false);
+ _space();
+ _emitList(body);
+ }
+ _endClause();
+ }
+ }
+ }
+}
+
+
+/// Used to build a program from recorded relations and the element model.
+class ProgramBuilder {
+ Program _program = new Program();
+
+ Map<String, dynamic> _usedNames = <String, dynamic>{};
+
+ bool _alreadyUsed(entity, String name) {
+ return _usedNames.containsKey(name) && entity != _usedNames[name];
+ }
+
+ Map<Element, Atom> _identifiers = <Element, Atom>{};
+
+ Queue<Function> _queue = new Queue<Function>();
+
+ void defer(f()) {
+ _queue.add(f);
+ }
+
+ void _addFact(Atom predicate, List<Term> arguments) {
+ _program.add(new Clause(new Compound(predicate, arguments)));
+ }
+
+ void _addClause(Clause clause) {
+ _program.add(clause);
+ }
+
+ void _addContains(Atom container, Atom element) {
+ _addFact(const Atom('contains'), <Atom>[container, element]);
+ }
+
+ Atom _elementPredicate(Element element) => new Atom(element.kind.id);
+
+ // TODO(karlklose): Extract a strategy object for these two functions.
+ Clause _elementDefinition(Element element, Atom reference) {
+ Atom name = new Atom(element.name);
+ Atom kind = new Atom(element.kind.id);
+ List<Term> properties = <Term>[reference, name];
+ return new Clause(new Compound(kind, properties));
+ }
+
+ String _getNameProposal(entity) {
+ if (entity is CompilationUnitElement) {
+ return 'file_${entity.script.readableUri.pathSegments.last}';
+ } else if (entity is LibraryElement) {
+ return 'lib_${entity.canonicalUri.pathSegments.last}';
+ } else if (entity is Element) {
+ return entity.name;
+ } else {
+ return entity.toString();
+ }
+ }
+
+ Atom _elementReference(Element element) {
+ if (_identifiers.containsKey(element)) return _identifiers[element];
+ Atom reference = new Atom(_getName(element));
+ Element container = element.enclosingElement;
+ if (container != null) {
+ defer(() {
+ _addContains(_elementReference(container), reference);
+ _addClause(_elementDefinition(element, reference));
+ });
+ }
+ return _identifiers[element] = reference;
+ }
+
+ String _makeUniqueName(entity, String base) {
+ int nr = 0;
+ String proposal = base;
+ while (_alreadyUsed(entity, proposal)) {
+ proposal = '$base$nr';
+ nr++;
+ }
+ _usedNames[proposal] = entity;
+ return proposal;
+ }
+
+ String _getName(entity) => _makeUniqueName(entity, _getNameProposal(entity));
+
+ Term _terminize(object) {
+ return object is Element ? _elementReference(object)
+ : new Atom(object.toString());
+ }
+
+ void addRelation(String relation, List elements) {
+ List<Term> references = elements.map(_terminize).toList();
+ _addFact(new Atom(relation), references);
+ while (_queue.isNotEmpty) {
+ Function continuation = _queue.removeFirst();
+ continuation();
+ }
+ }
+
+ Program get program {
+ Program result = _program;
+ _program = null;
+ return result;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698