001/*
002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 */
009
010package org.eclipse.golo.doc;
011
012import org.eclipse.golo.compiler.parser.*;
013import org.eclipse.golo.compiler.ir.*;
014import org.eclipse.golo.compiler.GoloCompiler;
015
016import java.util.*;
017
018public class ModuleDocumentation implements DocumentationElement {
019
020  private String moduleName;
021  private int moduleDefLine;
022  private String moduleDocumentation;
023
024  private final Map<String, Integer> imports = new TreeMap<>();
025  private final Map<String, Integer> moduleStates = new TreeMap<>();
026  private final SortedSet<FunctionDocumentation> functions = new TreeSet<>();
027  private final Map<String, AugmentationDocumentation> augmentations = new TreeMap<>();
028  private final SortedSet<StructDocumentation> structs = new TreeSet<>();
029  private final SortedSet<UnionDocumentation> unions = new TreeSet<>();
030  private final Set<NamedAugmentationDocumentation> namedAugmentations = new TreeSet<>();
031
032  /**
033   * {@inheritDoc}
034   */
035  @Override
036  public String type() {
037    return "module";
038  }
039
040  ModuleDocumentation(GoloModule module) {
041    module.accept(new ModuleVisitor());
042  }
043
044  public static ModuleDocumentation load(String filename, GoloCompiler compiler) throws java.io.IOException {
045    return new ModuleDocumentation(compiler.transform(compiler.parse(filename)));
046  }
047
048  public String goloVersion() {
049    return org.eclipse.golo.cli.command.Metadata.VERSION;
050  }
051
052  public SortedSet<StructDocumentation> structs() {
053    return structs;
054  }
055
056  public SortedSet<UnionDocumentation> unions() {
057    return unions;
058  }
059
060  public SortedSet<FunctionDocumentation> functions() {
061    return functions(false);
062  }
063
064  public SortedSet<FunctionDocumentation> functions(boolean withLocal) {
065    if (withLocal) {
066      return functions;
067    }
068    TreeSet<FunctionDocumentation> pubFunctions = new TreeSet<>();
069    for (FunctionDocumentation f : functions) {
070      if (!f.local()) {
071        pubFunctions.add(f);
072      }
073    }
074    return pubFunctions;
075  }
076
077  public String moduleName() {
078    return moduleName;
079  }
080
081  /**
082   * {@inheritDoc}
083   */
084  @Override
085  public String name() {
086    return moduleName;
087  }
088
089  /**
090   * {@inheritDoc}
091   */
092  @Override
093  public String fullName() {
094    return moduleName;
095  }
096
097  /**
098   * {@inheritDoc}
099   */
100  @Override
101  public String id() {
102    return "";
103  }
104
105  /**
106   * {@inheritDoc}
107   */
108  @Override
109  public DocumentationElement parent() {
110    return this;
111  }
112
113  public int moduleDefLine() {
114    return moduleDefLine;
115  }
116
117  /**
118   * {@inheritDoc}
119   */
120  @Override
121  public int line() {
122    return moduleDefLine;
123  }
124
125  public String moduleDocumentation() {
126    return (moduleDocumentation != null) ? moduleDocumentation : "\n";
127  }
128
129  /**
130   * {@inheritDoc}
131   */
132  @Override
133  public String documentation() {
134    return moduleDocumentation();
135  }
136
137  public Map<String, Integer> moduleStates() {
138    return moduleStates;
139  }
140
141  public Collection<AugmentationDocumentation> augmentations() {
142    return augmentations.values();
143  }
144
145  public Collection<NamedAugmentationDocumentation> namedAugmentations() {
146    return namedAugmentations;
147  }
148
149  public Map<String, Integer> imports() {
150    return imports;
151  }
152
153  private class ModuleVisitor implements GoloIrVisitor {
154
155    private Deque<Set<FunctionDocumentation>> functionContext = new LinkedList<>();
156    private FunctionDocumentation currentFunction = null;
157    private UnionDocumentation currentUnion;
158    private MemberHolder currentMemberHolder;
159    private Deque<DocumentationElement> parents = new LinkedList<>();
160
161    @Override
162    public void visitModule(GoloModule module) {
163      functionContext.push(functions);
164      parents.push(ModuleDocumentation.this);
165      moduleName = module.getPackageAndClass().toString();
166      moduleDefLine = module.getPositionInSourceCode().getLine();
167      moduleDocumentation = module.getDocumentation();
168      module.walk(this);
169    }
170
171    @Override
172    public void visitModuleImport(ModuleImport moduleImport) {
173      if (!moduleImport.isImplicit()) {
174        imports.put(moduleImport.getPackageAndClass().toString(), moduleImport.getPositionInSourceCode().getLine());
175      }
176    }
177
178    @Override
179    public void visitStruct(Struct struct) {
180      StructDocumentation doc = new StructDocumentation()
181              .parent(parents.peek())
182              .name(struct.getName())
183              .documentation(struct.getDocumentation())
184              .line(struct.getPositionInSourceCode().getLine());
185      structs.add(doc);
186      currentMemberHolder = doc;
187      parents.push(doc);
188      struct.walk(this);
189      parents.pop();
190      currentMemberHolder = null;
191    }
192
193    @Override
194    public void visitUnion(Union union) {
195      this.currentUnion = new UnionDocumentation()
196          .parent(parents.peek())
197          .name(union.getName())
198          .documentation(union.getDocumentation())
199          .line(union.getPositionInSourceCode().getLine());
200      unions.add(this.currentUnion);
201      parents.push(currentUnion);
202      union.walk(this);
203      parents.pop();
204    }
205
206    @Override
207    public void visitUnionValue(UnionValue value) {
208      UnionDocumentation.UnionValueDocumentation doc = this.currentUnion.addValue(value.getName())
209          .parent(parents.peek())
210          .documentation(value.getDocumentation())
211          .line(value.getPositionInSourceCode().getLine());
212      currentMemberHolder = doc;
213      parents.push(doc);
214      value.walk(this);
215      parents.pop();
216      currentMemberHolder = null;
217    }
218
219    @Override
220    public void visitAugmentation(Augmentation augment) {
221      /* NOTE:
222       * if multiple augmentations are defined for the same target
223       * only the line of the first one is kept.
224       */
225      String target = augment.getTarget().toString();
226      if (!augmentations.containsKey(target)) {
227        augmentations.put(target, new AugmentationDocumentation()
228                .target(target)
229                .parent(parents.peek())
230                .augmentationNames(augment.getNames())
231                .line(augment.getPositionInSourceCode().getLine())
232        );
233      }
234      AugmentationDocumentation ad = augmentations.get(target);
235      ad.documentation(ad.documentation() + '\n' + augment.getDocumentation());
236      functionContext.push(ad);
237      parents.push(ad);
238      augment.walk(this);
239      functionContext.pop();
240      parents.pop();
241    }
242
243    @Override
244    public void visitNamedAugmentation(NamedAugmentation augment) {
245      NamedAugmentationDocumentation augmentDoc = new NamedAugmentationDocumentation()
246          .parent(parents.peek())
247          .name(augment.getName())
248          .documentation(augment.getDocumentation())
249          .line(augment.getPositionInSourceCode().getLine());
250      namedAugmentations.add(augmentDoc);
251      functionContext.push(augmentDoc);
252      parents.push(augmentDoc);
253      augment.walk(this);
254      functionContext.pop();
255      parents.pop();
256    }
257
258    @Override
259    public void visitFunction(GoloFunction function) {
260      if (!GoloModule.MODULE_INITIALIZER_FUNCTION.equals(function.getName())) {
261        functionContext.peek().add(new FunctionDocumentation()
262            .parent(parents.peek())
263            .name(function.getName())
264            .documentation(function.getDocumentation())
265            .augmentation(function.isInAugment())
266            .line(function.getPositionInSourceCode().getLine())
267            .local(function.isLocal())
268            .arguments(function.getParameterNames())
269            .varargs(function.isVarargs()));
270      }
271    }
272
273    @Override
274    public void visitLocalReference(LocalReference localRef) {
275      if (localRef.isModuleState()) {
276        moduleStates.put(localRef.getName(), localRef.getPositionInSourceCode().getLine());
277      }
278    }
279
280    @Override
281    public void visitMember(Member member) {
282      currentMemberHolder.addMember(member.getName())
283        .parent(parents.peek())
284        .documentation(member.getDocumentation())
285        .line(member.getPositionInSourceCode().getLine());
286    }
287
288    @Override
289    public void visitDecorator(Decorator decorator) {
290    }
291
292    @Override
293    public void visitBlock(Block block) {
294    }
295
296    @Override
297    public void visitConstantStatement(ConstantStatement constantStatement) {
298    }
299
300    @Override
301    public void visitReturnStatement(ReturnStatement returnStatement) {
302    }
303
304    @Override
305    public void visitFunctionInvocation(FunctionInvocation functionInvocation) {
306    }
307
308    @Override
309    public void visitMethodInvocation(MethodInvocation methodInvocation) {
310    }
311
312    @Override
313    public void visitAssignmentStatement(AssignmentStatement assignmentStatement) {
314    }
315
316    @Override
317    public void visitDestructuringAssignment(DestructuringAssignment assignment) {
318    }
319
320    @Override
321    public void visitReferenceLookup(ReferenceLookup referenceLookup) {
322    }
323
324    @Override
325    public void visitConditionalBranching(ConditionalBranching conditionalBranching) {
326    }
327
328    @Override
329    public void visitBinaryOperation(BinaryOperation binaryOperation) {
330    }
331
332    @Override
333    public void visitUnaryOperation(UnaryOperation unaryOperation) {
334    }
335
336    @Override
337    public void visitLoopStatement(LoopStatement loopStatement) {
338    }
339
340    @Override
341    public void visitForEachLoopStatement(ForEachLoopStatement foreachStatement) {
342    }
343
344    @Override
345    public void visitCaseStatement(CaseStatement caseStatement) {
346    }
347
348    @Override
349    public void visitMatchExpression(MatchExpression matchExpression) {
350    }
351
352    @Override
353    public void visitWhenClause(WhenClause<?> whenClause) {
354    }
355
356    @Override
357    public void visitThrowStatement(ThrowStatement throwStatement) {
358    }
359
360    @Override
361    public void visitTryCatchFinally(TryCatchFinally tryCatchFinally) {
362    }
363
364    @Override
365    public void visitClosureReference(ClosureReference closureReference) {
366    }
367
368    @Override
369    public void visitLoopBreakFlowStatement(LoopBreakFlowStatement loopBreakFlowStatement) {
370    }
371
372    @Override
373    public void visitCollectionLiteral(CollectionLiteral collectionLiteral) {
374    }
375
376    @Override
377    public void visitCollectionComprehension(CollectionComprehension collectionComprehension) {
378    }
379
380    @Override
381    public void visitNamedArgument(NamedArgument namedArgument) {
382    }
383  }
384
385}