Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static dev.ionfusion.fusion.UnboundIdentifierException.makeUnboundError;

import dev.ionfusion.fusion.FusionSymbol.BaseSymbol;
import dev.ionfusion.runtime._private.doc.BindingDoc;
import dev.ionfusion.runtime.base.FusionException;
import dev.ionfusion.runtime.base.ModuleIdentity;
import dev.ionfusion.runtime.base.SourceLocation;
Expand Down Expand Up @@ -378,6 +379,13 @@ Object lookup(ModuleInstance module)
return store.lookup(myAddress);
}

@Override
BindingDoc lookupDoc(Namespace current)
{
ModuleInstance module = current.getRegistry().lookup(myModuleId);
return (module == null) ? null : module.getStore().document(myAddress);
}

@Override
String mutationSyntaxErrorMessage()
{
Expand Down
4 changes: 4 additions & 0 deletions runtime/src/main/java/dev/ionfusion/fusion/ModuleStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ else if (value instanceof SyntacticForm)
{
doc.setKind(BindingDoc.Kind.SYNTAX);
}
else
{
doc.setKind(BindingDoc.Kind.CONSTANT);
}
}
return doc;
}
Expand Down
2 changes: 2 additions & 0 deletions runtime/src/main/java/dev/ionfusion/fusion/Namespace.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ final boolean isOwnedBy(Namespace ns)
return Namespace.this.myModuleId == ns.myModuleId;
}

abstract BindingDoc lookupDoc(Namespace current);

@Override
public boolean equals(Object other)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import dev.ionfusion.fusion.FusionSymbol.BaseSymbol;
import dev.ionfusion.fusion.ModuleNamespace.ProvidedBinding;
import dev.ionfusion.runtime._private.doc.BindingDoc;
import dev.ionfusion.runtime.base.FusionException;
import dev.ionfusion.runtime.base.ModuleIdentity;
import java.util.Iterator;
Expand Down Expand Up @@ -68,6 +69,14 @@ public Object lookup(Namespace ns)
return ns.lookupDefinition(this);
}


@Override
BindingDoc lookupDoc(Namespace current)
{
assert current == TopLevelNamespace.this; // Not always, but just testing
return TopLevelNamespace.this.document(myAddress);
}

@Override
NsDefinedBinding redefine(SyntaxSymbol identifier,
SyntaxValue formForErrors)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package dev.ionfusion.fusion;

import dev.ionfusion.fusion.Namespace.NsDefinedBinding;
import dev.ionfusion.runtime._private.doc.BindingDoc;
import dev.ionfusion.runtime._private.doc.ModuleDocs;
import dev.ionfusion.runtime.base.FusionException;
import dev.ionfusion.runtime.base.ModuleIdentity;
Expand Down Expand Up @@ -61,6 +63,24 @@ public static ModuleDocs instantiateModuleDocs(TopLevel top, ModuleIdentity id)
}


/**
* @param identifier must be a syntax symbol.
*
* @return null if no documentation is available.
*/
public static BindingDoc findBindingDoc(TopLevel top, Object identifier)
{
Evaluator eval = ((StandardTopLevel) top).getEvaluator();
Binding binding = ((SyntaxSymbol) identifier).resolve().target();
if (binding instanceof NsDefinedBinding)
{
Namespace current = eval.findCurrentNamespace();
return ((NsDefinedBinding) binding).lookupDoc(current);
}
return null;
}


public static FusionException newFusionException(String message,
Throwable cause)
{
Expand Down
24 changes: 24 additions & 0 deletions runtime/src/test/fusion/modules/documentation.fusion
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright Ion Fusion contributors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

(module documentation "/fusion"
"This is the module body doc."

(require "/fusion/private/syntax")

(provide const proc macro)


(define const
"This is the const doc."
true)

(define (proc)
"This is the proc doc."
true)

(define_syntax macro
"This is the macro doc."
(lambda (stx)
(quote_syntax (void))))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright Ion Fusion contributors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package dev.ionfusion.fusion;

import static dev.ionfusion.fusion._Private_Trampoline.findBindingDoc;
import static dev.ionfusion.fusion._Private_Trampoline.instantiateModuleDocs;
import static dev.ionfusion.fusion._Private_Trampoline.setDocumenting;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;

import dev.ionfusion.runtime._private.doc.BindingDoc;
import dev.ionfusion.runtime._private.doc.ModuleDocs;
import dev.ionfusion.runtime.base.FusionException;
import dev.ionfusion.runtime.base.ModuleIdentity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class DocumentationAccessTest
extends CoreTestCase
{
@BeforeEach
public void setup()
throws Exception
{
setDocumenting(runtimeBuilder(), true);
useTstRepo();

topLevel().requireModule("/fusion/private/syntax");
topLevel().requireModule("/documentation");
}


private ModuleDocs moduleDocs(String modulePath)
throws FusionException
{
ModuleIdentity modId = ModuleIdentity.forAbsolutePath(modulePath);

ModuleDocs doc = instantiateModuleDocs(topLevel(), modId);
if (doc != null)
{
assertSame(doc.getIdentity(), modId);
}

return doc;
}

private BindingDoc bindingDoc(String name)
throws FusionException
{
Object id = topLevel().eval("(quote_syntax " + name + ")");
return findBindingDoc(topLevel(), id);
}


@Test
public void docForUnknownModule()
throws FusionException
{
assertNull(moduleDocs("/unknown/module/path"));
}


@Test
public void docForModule()
throws FusionException
{
ModuleDocs doc = moduleDocs("/documentation");

assertThat(doc.getOneLiner(), is("This is the module body doc."));
assertThat(doc.getOverview(), is("This is the module body doc."));

assertThat(doc.getProvidedNames(),
containsInAnyOrder("const", "macro", "proc"));


BindingDoc constDoc = doc.getBindingDocs().get("const");

assertThat(constDoc.getKind(), is(BindingDoc.Kind.CONSTANT));
assertThat(constDoc.getBody(), is("This is the const doc."));
}


@Test
public void docForUnboundIdentifier()
throws FusionException
{
assertNull(bindingDoc("unbound_var"));
}

@Test
public void docForConstant()
throws FusionException
{
BindingDoc doc = bindingDoc("const");

assertThat(doc.getKind(), is(BindingDoc.Kind.CONSTANT));
assertThat(doc.getBody(), is("This is the const doc."));
}

@Test
public void docForProcedure()
throws FusionException
{
BindingDoc doc = bindingDoc("proc");

assertThat(doc.getKind(), is(BindingDoc.Kind.PROCEDURE));
assertThat(doc.getBody(), containsString("(proc)"));
assertThat(doc.getBody(), containsString("This is the proc doc."));
}

@Test
public void docForMacro()
throws FusionException
{
BindingDoc doc = bindingDoc("macro");

assertThat(doc.getKind(), is(BindingDoc.Kind.SYNTAX));
assertThat(doc.getBody(), is("This is the macro doc."));
}
}
Loading