diff --git a/WORKSPACE b/WORKSPACE index dd868944..09fa85b8 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -49,8 +49,8 @@ http_file( # In some way, it'd be nicer to make use of https://github.com/JasonSteving99/claro-lang/releases/latest/download/.. # instead of naming the release explicitly. However, this would make it impossible to cherrypick an old version and # rebuild without manual work. - sha256 = "316f6a8399f5b9f5296458b3c9759330fe9b692dac90833a78f709329251db0e", - url = "https://github.com/JasonSteving99/claro-lang/releases/download/v0.1.277/claro-cli-install.tar.gz", + sha256 = "0d4a4eb0083f3b89b9ecfb740acbce3c1addfa5f3233e6693ec66db487f5942d", + url = "https://github.com/JasonSteving99/claro-lang/releases/download/v0.1.278/claro-cli-install.tar.gz", ) # ClaroDocs is built atop Google's Closure Templates in order to ensure that I'm not generating unsafe html since the diff --git a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_http_server.claro b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_http_server.claro index 52b3aee4..76402f75 100644 --- a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_http_server.claro +++ b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_http_server.claro @@ -32,8 +32,7 @@ endpoint_handlers MyDemoService { root res <- http::getOk200HttpResponseForHtml(@formattedHtml); node formattedHtml <- Utils::handleBuggyResponseAsHtmlStrParts(@joinResponse)[0]; node joinResponse <- BuggyBuggies::friendsJoin( - # TODO(steving) Migrate to using a singleton client once Claro's Modules can export static (singleton) values. - BuggyBuggies::getClient("https://buggy-buggies.gigalixirapp.com"), + BuggyBuggies::HTTP_CLIENT, gameId, handle ); @@ -49,8 +48,7 @@ endpoint_handlers MyDemoService { root res <- http::getOk200HttpResponseForJson(@formattedJson); node formattedJson <- EndpointHandlers::getBestMovesHandler(@parsedWorld); node parsedWorld <- BuggyBuggies::worldInfo( - # TODO(steving) Migrate to using a singleton client once Claro's Modules can export static (singleton) values. - BuggyBuggies::getClient("https://buggy-buggies.gigalixirapp.com"), + BuggyBuggies::HTTP_CLIENT, gameId, playerSecret ); @@ -60,8 +58,7 @@ endpoint_handlers MyDemoService { root res <- http::getOk200HttpResponseForJson(@formattedJson); node formattedJson <- Utils::handleBuggyResponseAsHtmlStrParts(@resetResponse)[0]; node resetResponse <- BuggyBuggies::reset( - # TODO(steving) Migrate to using a singleton client once Claro's Modules can export static (singleton) values. - BuggyBuggies::getClient("https://buggy-buggies.gigalixirapp.com"), + BuggyBuggies::HTTP_CLIENT, gameId, playerSecret ); diff --git a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro index 0ddb9cd9..6283fa44 100644 --- a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro +++ b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro @@ -1,4 +1,5 @@ -function getClient(url: string) -> HttpClient { - return http::getHttpClient(url); +provider static_HTTP_CLIENT() -> HttpClient { + # This now only needs to happen once throughout the entire program. + return http::getHttpClient("https://buggy-buggies.gigalixirapp.com"); } diff --git a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro_module_api b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro_module_api index 0ced7683..1abb866b 100644 --- a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro_module_api +++ b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service/buggy_buggies_client.claro_module_api @@ -10,7 +10,8 @@ HttpService BuggyBuggies { reset: "/api/game/{gameId}/player/{secret}/reset" } -function getClient(url: string) -> HttpClient; +# Now there's a single static definition of which client will be used for sending reqs to the Buggy Buggies server. +static HTTP_CLIENT: HttpClient; # This type models the JSON response from the Buggy-Buggies service as a Claro type to enable parsing the response into # something that you can work with programmatically with strict type validation on the edge. diff --git a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/BUILD b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/BUILD index f673e72c..b29e413b 100644 --- a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/BUILD +++ b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/BUILD @@ -13,7 +13,7 @@ claro_module( ], deps = { "Agent": "//src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_agent:buggy_agent", - "BuggyBuggiesClient": "//src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service:buggy_buggies_client", + "BuggyBuggies": "//src/java/com/claro/claro_programs/demo_server/buggy_buggies/buggy_buggies_service:buggy_buggies_client", "Utils": "//src/java/com/claro/claro_programs/demo_server/buggy_buggies/utils:utils", "Pos": "//src/java/com/claro/claro_programs/demo_server/buggy_buggies/data_structures:position", }, diff --git a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/game_move_handler.claro b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/game_move_handler.claro index dadd5d6b..1d16a31e 100644 --- a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/game_move_handler.claro +++ b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/game_move_handler.claro @@ -3,9 +3,8 @@ graph function gameMoveHandler(gameId: string, playerSecret: string, dir: string root formattedHtml <- Utils::reduce(@htmlStrParts, "", lambda (accum, curr) -> { return "{accum}{curr}"; }); node htmlStrParts <- Utils::handleBuggyResponseAsHtmlStrParts(@moveBuggyResponse); node moveBuggyResponse <- - BuggyBuggiesClient::move( - # TODO(steving) Migrate to using a singleton client once Claro's Modules can export static (singleton) values. - BuggyBuggiesClient::getClient("https://buggy-buggies.gigalixirapp.com"), + BuggyBuggies::move( + BuggyBuggies::HTTP_CLIENT, gameId, playerSecret, dir diff --git a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/get_best_moves_handler.claro b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/get_best_moves_handler.claro index 0713d0b1..04c243df 100644 --- a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/get_best_moves_handler.claro +++ b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/get_best_moves_handler.claro @@ -2,9 +2,9 @@ function getBestMovesHandler(buggyResponse: oneof>) -> string { match (buggyResponse) { case _:string -> - var moveResponse = unwrap(BuggyBuggiesClient::getParsedMoveResponse(buggyResponse)).result; + var moveResponse = unwrap(BuggyBuggies::getParsedMoveResponse(buggyResponse)).result; match (moveResponse) { - case _:BuggyBuggiesClient::MoveResponse -> + case _:BuggyBuggies::MoveResponse -> Agent::parseWorldMap(moveResponse.result.world) |> Agent::dijkstra(^, Pos::Position({x = moveResponse.result.you.x, y = moveResponse.result.you.y})) |> var computedMoves = ["\"{dir}\"" | dir in Agent::movesFromBestPath(^)]; diff --git a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/start_new_game_handler.claro b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/start_new_game_handler.claro index 0243e47f..20a85cdc 100644 --- a/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/start_new_game_handler.claro +++ b/src/java/com/claro/claro_programs/demo_server/buggy_buggies/endpoint_handlers/start_new_game_handler.claro @@ -1,10 +1,5 @@ graph function startNewGameHandler(handle: string) -> future { root joinRes <- Utils::handleBuggyResponseAsHtmlStrParts(@moveBuggyResponse)[0]; - node moveBuggyResponse <- - BuggyBuggiesClient::hostGame( - # TODO(steving) Migrate to using a singleton client once Claro's Modules can export static (singleton) values. - BuggyBuggiesClient::getClient("https://buggy-buggies.gigalixirapp.com"), - handle - ); + node moveBuggyResponse <- BuggyBuggies::hostGame(BuggyBuggies::HTTP_CLIENT, handle); } diff --git a/src/java/com/claro/claro_programs/modules/test_main.claro b/src/java/com/claro/claro_programs/modules/test_main.claro index 391d36c0..25c13878 100644 --- a/src/java/com/claro/claro_programs/modules/test_main.claro +++ b/src/java/com/claro/claro_programs/modules/test_main.claro @@ -27,4 +27,7 @@ TestDep2::addFancyInt(2, 3) |> myPrint(^, ":multi_hop_module_api via Addition via TestDep2"); # Demonstrate that dep module types with generic type params can actually be instantiated. -print(TestDep2::List([1])); \ No newline at end of file +print(TestDep2::List([1])); + +# Demonstrate that static values exported by dep modules can be read. +print("Here's the definition of `TestDep::PI`: {TestDep::PI}"); \ No newline at end of file diff --git a/src/java/com/claro/compiler_backends/java_source/JavaSourceCompilerBackend.java b/src/java/com/claro/compiler_backends/java_source/JavaSourceCompilerBackend.java index ff8ce684..a76ff3d5 100644 --- a/src/java/com/claro/compiler_backends/java_source/JavaSourceCompilerBackend.java +++ b/src/java/com/claro/compiler_backends/java_source/JavaSourceCompilerBackend.java @@ -431,8 +431,27 @@ private ImmutableList setupModuleDepBindings( } // After having successfully parsed all dep module files and registered all of their exported types, it's time to - // finally register all of their exported procedure signatures. + // finally register their remaining exports. ImmutableMap parsedClaroModuleProtos = parsedClaroModuleProtosBuilder.build(); + + // Register the exported static values. + for (Map.Entry moduleDep : parsedClaroModuleProtos.entrySet()) { + // Setup the regular exported procedures. + for (SerializedClaroModule.ExportedStaticValue depExportedStaticValue : + moduleDep.getValue().getExportedStaticValuesList()) { + String disambiguatedStaticValueIdentifier = + String.format( + "%s$%s", + depExportedStaticValue.getName(), + moduleDep.getValue().getModuleDescriptor().getUniqueModuleName() + ); + scopedHeap.observeStaticIdentifierValue( + disambiguatedStaticValueIdentifier, Types.parseTypeProto(depExportedStaticValue.getType())); + scopedHeap.initializeIdentifier(disambiguatedStaticValueIdentifier); + } + } + + // Register the exported procedures. for (Map.Entry moduleDep : parsedClaroModuleProtos.entrySet()) { // Setup the regular exported procedures. for (SerializedClaroModule.Procedure depExportedProc : diff --git a/src/java/com/claro/intermediate_representation/expressions/term/IdentifierReferenceTerm.java b/src/java/com/claro/intermediate_representation/expressions/term/IdentifierReferenceTerm.java index 3891020c..b21105ce 100644 --- a/src/java/com/claro/intermediate_representation/expressions/term/IdentifierReferenceTerm.java +++ b/src/java/com/claro/intermediate_representation/expressions/term/IdentifierReferenceTerm.java @@ -8,7 +8,6 @@ import com.claro.intermediate_representation.types.Type; import com.claro.intermediate_representation.types.Types; import com.claro.internal_static_state.InternalStaticStateUtil; -import com.claro.module_system.module_serialization.proto.SerializedClaroModule; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -221,31 +220,20 @@ public Type getValidatedExprType(ScopedHeap scopedHeap) throws ClaroTypeExceptio @Override public StringBuilder generateJavaSourceBodyOutput(ScopedHeap scopedHeap) { - scopedHeap.markIdentifierUsed(this.identifier); + if (scopedHeap.getIdentifierData(this.identifier).isStaticValue) { + System.err.println( + "TESTING!!! FOUND STATIC ID REF: " + this.identifier + " " + this.optionalDefiningModuleDisambiguator); + } + ScopedHeap.IdentifierData identifierData = scopedHeap.getIdentifierData(this.identifier); + identifierData.used = true; return new StringBuilder( this.alternateCodegenString.orElse( () -> { - if (scopedHeap.getValidatedIdentifierType(this.identifier).baseType().equals(BaseType.ATOM) - && scopedHeap.getIdentifierData(this.identifier).isTypeDefinition) { + if (identifierData.type.baseType().equals(BaseType.ATOM) && identifierData.isTypeDefinition) { // Here it turns out that we actually need to codegen a lookup into the ATOM CACHE. - Optional uniqueModuleDescriptor = - ScopedHeap.getModuleNameFromDisambiguator( - this.optionalDefiningModuleDisambiguator.orElse("$THIS_MODULE$")) - .map(moduleName -> - ScopedHeap.currProgramDepModules.rowMap().get(moduleName) - .values().stream().findFirst().get()); return String.format( - "%s%sATOM_CACHE[%s]", - uniqueModuleDescriptor.map(m -> m.getProjectPackage() + '.').orElse(""), - this.optionalDefiningModuleDisambiguator.map(s -> s + '.').orElseGet( - () -> { - String definingModuleDisambiguator = - ScopedHeap.getDefiningModuleDisambiguator(Optional.empty()); - if (definingModuleDisambiguator.isEmpty()) { - return definingModuleDisambiguator; - } - return definingModuleDisambiguator + '.'; - }), + "%sATOM_CACHE[%s]", + getFullySpecifiedIdentifierNamespace(), InternalStaticStateUtil.AtomDefinition_CACHE_INDEX_BY_MODULE_AND_ATOM_NAME.build().get( this.optionalDefiningModuleDisambiguator.orElseGet( () -> ScopedHeap.getDefiningModuleDisambiguator(Optional.empty())), @@ -256,12 +244,38 @@ public StringBuilder generateJavaSourceBodyOutput(ScopedHeap scopedHeap) { // Nested comprehension Exprs depend on a synthetic class wrapping the nested identifier refs to // workaround Java's restriction that all lambda captures must be effectively final. return "$nestedComprehensionState." + this.identifier; + } else if (identifierData.isStaticValue) { + // To ensure that static values can be referenced across dep module monomorphization boundaries, I need + // to fully specify their namespace at all times. + return getFullySpecifiedIdentifierNamespace() + + this.optionalDefiningModuleDisambiguator + .map(unused -> { + int identifierEndIndex = this.identifier.indexOf('$'); + if (identifierEndIndex == -1) { + return this.identifier; + } + return this.identifier.substring(0, identifierEndIndex); + }) + .orElse(this.identifier); } return this.identifier; } ).get()); } + // Returns empty only if referencing an identifier from the current compilation unit, and the current compilation unit + // is in fact the top-level claro_binary(). Else, returns the actual UniqueModuleDescriptor to explicitly reference + // currently identifier. + private String getFullySpecifiedIdentifierNamespace() { + return ScopedHeap.getModuleNameFromDisambiguator( + this.optionalDefiningModuleDisambiguator.orElse("$THIS_MODULE$")) + .map(moduleName -> + ScopedHeap.currProgramDepModules.rowMap().get(moduleName) + .values().stream().findFirst().get()) + .map(m -> String.format("%s.%s.", m.getProjectPackage(), m.getUniqueModuleName())) + .orElse(""); + } + @Override public Object generateInterpretedOutput(ScopedHeap scopedHeap) { scopedHeap.markIdentifierUsed(this.identifier);