Skip to content

Commit

Permalink
don't fail parsing of module name in case of leading comment
Browse files Browse the repository at this point in the history
  • Loading branch information
Viir committed Jan 27, 2025
1 parent 0c12b6d commit e2615f2
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 5 deletions.
41 changes: 37 additions & 4 deletions implement/pine/ElmSyntax/ElmModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,21 +163,54 @@ public static Result<string, IReadOnlyList<string>> ParseModuleName(ReadOnlyMemo

public static Result<string, IReadOnlyList<string>> ParseModuleName(string moduleText)
{
// This pattern removes all leading:
// - whitespace (\s)
// - single-line comments (--... up to end of line)
// - multi-line comments ({- ... -}), which can span multiple lines
// The * at the end repeats that pattern until it no longer matches.
// Using RegexOptions.Singleline so '.' can match across newlines within {- -}.
var textWithoutLeadingComments = Regex.Replace(
moduleText,
pattern: @"\A(?:
\s+ # skip any whitespace
| --[^\r\n]*(?:\r\n|\r|\n|$) # skip single-line comment + EOL
| \{\-[\s\S]*?\-\} # skip multi-line comment
)*",
replacement: "",
options: RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline);

{
var match = Regex.Match(moduleText, @"^(port\s+)?module\s+([\w.]+)\s+exposing");
// Match: optional `port `, then `module`, then a dotted identifier, then `exposing`.
// Example: port module MyModule exposing

var match =
Regex.Match(
textWithoutLeadingComments,
@"^(port\s+)?module\s+([\w.]+)\s+exposing",
RegexOptions.Singleline);

if (match.Success)
{
return Result<string, IReadOnlyList<string>>.ok(match.Groups[2].Value.Split('.'));
return Result<string, IReadOnlyList<string>>.ok(
match.Groups[2].Value.Split('.'));
}
}

{
var match = Regex.Match(moduleText, @"^effect\s+module\s+([\w.]+)\s+(where|exposing)");
// Match: `effect module`, then dotted identifier, then `where` or `exposing`.
// Example: effect module MyModule where ...
// effect module MyModule exposing ...

var match =
Regex.Match(
textWithoutLeadingComments,
@"^effect\s+module\s+([\w.]+)\s+(where|exposing)",
RegexOptions.Singleline);

if (match.Success)
{
return Result<string, IReadOnlyList<string>>.ok(match.Groups[1].Value.Split('.'));
return Result<string, IReadOnlyList<string>>.ok(
match.Groups[1].Value.Split('.'));
}
}

Expand Down
42 changes: 41 additions & 1 deletion implement/test-elm-time/ElmSyntaxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ module Elm.JsArray
(IReadOnlyList<string>)["Elm", "JsArray"]
},

new
{
moduleText =
"""
{-| Multi-line comment
-}
module Test exposing ( .. )
""",

expectedModuleName =
(IReadOnlyList<string>)["Test"]
},

new
{
moduleText =
Expand All @@ -87,7 +101,8 @@ module Elm.JsArray

if (parseModuleNameResult.IsErrOrNull() is { } err)
{
Assert.Fail("Failed to parse module name: " + err);
Assert.Fail(
"Failed to parse module name: " + err + "\nmodule text:\n" + testCase.moduleText);
}

if (parseModuleNameResult.IsOkOrNull() is not { } parsedName)
Expand All @@ -102,6 +117,31 @@ module Elm.JsArray
}
}

[TestMethod]
public void Parse_Elm_module_name_ignores_string_literal_content()
{
var moduleText =
""""
-- module TestModule exposing (..)
test =
[ ""
, """
module Bytes.Decode exposing (..)
""" ]
"""";

var parseModuleNameResult =
ElmModule.ParseModuleName(moduleText);

Assert.IsTrue(
parseModuleNameResult.IsErr(),
message: "Expected error");
}

[TestMethod]
public void Parse_Elm_module_text_imports()
{
Expand Down

0 comments on commit e2615f2

Please sign in to comment.