diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7706ac5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,63 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" version "1.3.72" + //id "org.jetbrains.dokka" version "0.10.0" +} + +repositories { + mavenCentral() +} + +kotlin { + jvm() + js { + browser { + } + nodejs { + } + } + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib-common') + } + } + + commonTest { + dependencies { + implementation kotlin('test-common') + implementation kotlin('test-annotations-common') + } + } + + jvmMain { + dependencies { + implementation kotlin('stdlib-jdk8') + implementation "org.jetbrains:annotations:18.0.0" + } + } + + jvmTest { + dependencies { + implementation kotlin('test-junit') + } + } + + nonJvmMain { + dependsOn commonMain + } + + jsMain { + dependencies { + implementation kotlin('stdlib-js') + } + dependsOn nonJvmMain + } + + jsTest { + dependencies { + implementation kotlin('test-js') + } + } + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts deleted file mode 100644 index 7dfc6cf..0000000 --- a/build.gradle.kts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Kotlin library project to get you started. - */ - -import org.jetbrains.dokka.gradle.DokkaTask - -plugins { - // Apply the Kotlin JVM plugin to add support for Kotlin. - id("org.jetbrains.kotlin.jvm") version "1.3.71" - id("org.jetbrains.dokka") version "0.10.0" - - // Apply the java-library plugin for API and implementation separation. - `java-library` - jacoco - maven -} - -repositories { - // Use jcenter for resolving dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() -} - -dependencies { - // Align versions of all Kotlin components - implementation(platform("org.jetbrains.kotlin:kotlin-bom")) - - // Use the Kotlin JDK 8 standard library. - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - - // Also use the annotations for more documentation fun - implementation("org.jetbrains:annotations:18.0.0") - - // Use the Kotlin test library. - testImplementation("org.jetbrains.kotlin:kotlin-test") - - // Use the Kotlin JUnit integration. - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") -} - -tasks { - val dokka by getting(DokkaTask::class) { - outputFormat = "html" - outputDirectory = "$buildDir/dokka" - configuration { - includes = listOf("kdoc.md") - } - - } -} - -tasks.jacocoTestReport { - reports { - xml.isEnabled = true - } -} \ No newline at end of file diff --git a/src/main/kotlin/guru/zoroark/lixy/Buildable.kt b/src/commonMain/kotlin/guru/zoroark/lixy/Buildable.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/Buildable.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/Buildable.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyDsl.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyDsl.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyDsl.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyDsl.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyDslEnvironment.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyDslEnvironment.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyDslEnvironment.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyDslEnvironment.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyDslGenericMatcherEnvironment.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyDslGenericMatcherEnvironment.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyDslGenericMatcherEnvironment.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyDslGenericMatcherEnvironment.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyDslIgnoringMatcherEnvironment.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyDslIgnoringMatcherEnvironment.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyDslIgnoringMatcherEnvironment.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyDslIgnoringMatcherEnvironment.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyDslMatchedMatcherEnvironment.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyDslMatchedMatcherEnvironment.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyDslMatchedMatcherEnvironment.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyDslMatchedMatcherEnvironment.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyDslStateEnvironment.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyDslStateEnvironment.kt similarity index 81% rename from src/main/kotlin/guru/zoroark/lixy/LixyDslStateEnvironment.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyDslStateEnvironment.kt index 10652ca..944abb4 100644 --- a/src/main/kotlin/guru/zoroark/lixy/LixyDslStateEnvironment.kt +++ b/src/commonMain/kotlin/guru/zoroark/lixy/LixyDslStateEnvironment.kt @@ -1,9 +1,6 @@ package guru.zoroark.lixy import guru.zoroark.lixy.matchers.* -import guru.zoroark.lixy.matchers.RegexPatternRecognizer -import org.intellij.lang.annotations.Language -import java.util.regex.Pattern /** * This classed is used to build a lexer state ([LixyState]) using a DSL, and is @@ -50,19 +47,6 @@ class LixyDslStateEnvironment : Buildable { tokenMatchers += this.selfBuildable() } - /** - * Create a recognizer that recognizes the given regular expression. Use - * this before [isToken] to create a matcher that matches against a regular - * expression. - * - * @param regex The regular expression to use in the recognizer - * @see isToken - */ - fun matches(@Language("RegExp") regex: String): LixyTokenRecognizer = - RegexPatternRecognizer( - Pattern.compile(regex) - ) - /** * Anything that matches the given recognizer (or pseudo-recognizer) exactly * will be ignored when encountered. This would be equivalent to a `isToken` diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyException.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyException.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyException.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyException.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyLexer.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyLexer.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyLexer.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyLexer.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyNoMatchException.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyNoMatchException.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyNoMatchException.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyNoMatchException.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyState.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyState.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyState.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyState.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyStateLabel.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyStateLabel.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyStateLabel.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyStateLabel.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyToken.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyToken.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyToken.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyToken.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/LixyTokenType.kt b/src/commonMain/kotlin/guru/zoroark/lixy/LixyTokenType.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/LixyTokenType.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/LixyTokenType.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/OffsetCharSequence.kt b/src/commonMain/kotlin/guru/zoroark/lixy/OffsetCharSequence.kt similarity index 56% rename from src/main/kotlin/guru/zoroark/lixy/OffsetCharSequence.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/OffsetCharSequence.kt index d146e17..ecbc1bc 100644 --- a/src/main/kotlin/guru/zoroark/lixy/OffsetCharSequence.kt +++ b/src/commonMain/kotlin/guru/zoroark/lixy/OffsetCharSequence.kt @@ -1,14 +1,22 @@ package guru.zoroark.lixy -internal class OffsetCharSequence(val charSequence: CharSequence, val offsetBy: Int) : CharSequence { +internal class OffsetCharSequence( + val charSequence: CharSequence, + val offsetBy: Int +) : CharSequence { init { if (offsetBy > charSequence.length) error("Invalid offset, exceeds original sequence's length") } + override val length: Int get() = charSequence.length - offsetBy - override fun get(index: Int): Char = charSequence[index + offsetBy] + override fun get(index: Int): Char = + if (index + offsetBy >= charSequence.length) + throw IndexOutOfBoundsException("Index ${index + offsetBy} is out of bounds (max. ${charSequence.length}") + else + charSequence[index + offsetBy] override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = charSequence.subSequence(startIndex + offsetBy, endIndex + offsetBy) diff --git a/src/main/kotlin/guru/zoroark/lixy/SelfBuildable.kt b/src/commonMain/kotlin/guru/zoroark/lixy/SelfBuildable.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/SelfBuildable.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/SelfBuildable.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyCharRangeTokenRecognizer.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyCharRangeTokenRecognizer.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyCharRangeTokenRecognizer.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyCharRangeTokenRecognizer.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyMatcherResult.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyMatcherResult.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyMatcherResult.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyMatcherResult.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyNextStateBehavior.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyNextStateBehavior.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyNextStateBehavior.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyNextStateBehavior.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyRepeatedRecognizer.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyRepeatedRecognizer.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyRepeatedRecognizer.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyRepeatedRecognizer.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyStringSetTokenRecognizer.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyStringSetTokenRecognizer.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyStringSetTokenRecognizer.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyStringSetTokenRecognizer.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyStringTokenRecognizer.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyStringTokenRecognizer.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyStringTokenRecognizer.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyStringTokenRecognizer.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenMatcher.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenMatcher.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenMatcher.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenMatcher.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizer.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizer.kt similarity index 96% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizer.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizer.kt index 4707274..ddebaf4 100644 --- a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizer.kt +++ b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizer.kt @@ -56,6 +56,6 @@ fun toRecognizer(x: Any): LixyTokenRecognizer = is String -> LixyStringTokenRecognizer(x) is CharRange -> LixyCharRangeTokenRecognizer(x) else -> throw LixyException( - "Unable to convert ${x::class.java.simpleName} to a recognizer." + "Unable to convert ${x::class.simpleName} to a recognizer." ) } \ No newline at end of file diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerIgnored.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerIgnored.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerIgnored.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerIgnored.kt diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerMatched.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerMatched.kt similarity index 100% rename from src/main/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerMatched.kt rename to src/commonMain/kotlin/guru/zoroark/lixy/matchers/LixyTokenRecognizerMatched.kt diff --git a/src/commonMain/kotlin/guru/zoroark/lixy/matchers/RegexPatternRecognizer.kt b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/RegexPatternRecognizer.kt new file mode 100644 index 0000000..93681cb --- /dev/null +++ b/src/commonMain/kotlin/guru/zoroark/lixy/matchers/RegexPatternRecognizer.kt @@ -0,0 +1,12 @@ +package guru.zoroark.lixy.matchers + +import guru.zoroark.lixy.LixyDslStateEnvironment + +/** + * Create a recognizer that recognizes the given regular expression. Use + * this before isToken to create a matcher that matches against a regular + * expression. + * + * @param pattern The regular expression to use in the recognizer + */ +expect fun LixyDslStateEnvironment.matches(pattern: String): LixyTokenRecognizer \ No newline at end of file diff --git a/src/test/kotlin/guru/zoroark/lixy/IgnoreMatcherTest.kt b/src/commonTest/kotlin/guru/zoroark/lixy/IgnoreMatcherTest.kt similarity index 92% rename from src/test/kotlin/guru/zoroark/lixy/IgnoreMatcherTest.kt rename to src/commonTest/kotlin/guru/zoroark/lixy/IgnoreMatcherTest.kt index 237551f..17b5d90 100644 --- a/src/test/kotlin/guru/zoroark/lixy/IgnoreMatcherTest.kt +++ b/src/commonTest/kotlin/guru/zoroark/lixy/IgnoreMatcherTest.kt @@ -1,11 +1,12 @@ package guru.zoroark.lixy import guru.zoroark.lixy.matchers.anyOf +import guru.zoroark.lixy.matchers.matches import kotlin.test.* class IgnoreMatcherTest { @Test - fun `Ignore matcher on string in single state`() { + fun ignore_matcher_on_string_in_single_state() { val tone = tokenType() val ttwo = tokenType() val lexer = lixy { @@ -31,7 +32,7 @@ class IgnoreMatcherTest { } @Test - fun `Ignore matcher on string in multiple states`() { + fun ignore_matcher_on_string_in_multiple_states() { val tkey = tokenType() val tvalue = tokenType() val svalue = stateLabel() @@ -63,7 +64,7 @@ class IgnoreMatcherTest { } @Test - fun `Ignore matcher on any matcher in single state`() { + fun ignore_matcher_on_any_matcher_in_single_state() { val tspace = tokenType() val tword = tokenType() val lexer = lixy { diff --git a/src/test/kotlin/guru/zoroark/lixy/LixyStateTest.kt b/src/commonTest/kotlin/guru/zoroark/lixy/LixyStateTest.kt similarity index 85% rename from src/test/kotlin/guru/zoroark/lixy/LixyStateTest.kt rename to src/commonTest/kotlin/guru/zoroark/lixy/LixyStateTest.kt index 0e76a8f..88ba53c 100644 --- a/src/test/kotlin/guru/zoroark/lixy/LixyStateTest.kt +++ b/src/commonTest/kotlin/guru/zoroark/lixy/LixyStateTest.kt @@ -6,7 +6,7 @@ import kotlin.test.* class LixyStateTest { @Test - fun `Lixy supports constructing one default state`() { + fun lixy_supports_constructing_one_default_state() { val dottoken = tokenType() val lixy = lixy { default state { @@ -26,7 +26,7 @@ class LixyStateTest { } @Test - fun `Lixy fails to construct unlabeled then labeled default`() { + fun lixy_fails_to_construct_unlabeled_then_labeled_default() { val ttype = tokenType() assertFailsWith { lixy { @@ -41,7 +41,7 @@ class LixyStateTest { } @Test - fun `Lixy fails to construct labeled default then unlabeled`() { + fun lixy_fails_to_construct_labeled_default_then_unlabeled() { val ttype = tokenType() assertFailsWith { lixy { @@ -56,7 +56,7 @@ class LixyStateTest { } @Test - fun `Lixy fails to construct multiple unlabeled states`() { + fun lixy_fails_to_construct_multiple_unlabeled_states() { val ttype = tokenType() assertFailsWith { lixy { @@ -71,7 +71,7 @@ class LixyStateTest { } @Test - fun `Lixy fails to construct multiple default states`() { + fun lixy_fails_to_construct_multiple_default_states() { val ttype = tokenType() assertFailsWith { lixy { @@ -86,7 +86,7 @@ class LixyStateTest { } @Test - fun `Lixy cannot create two states with the same label`() { + fun lixy_cannot_create_two_states_with_the_same_label() { val a = stateLabel() val ta = tokenType() val tb = tokenType() @@ -103,11 +103,11 @@ class LixyStateTest { } } } - assert(exc.message!!.contains("two states with the same label")) + assertTrue(exc.message!!.contains("two states with the same label")) } @Test - fun `Lixy successfully constructs multiple states and starts on default`() { + fun lixy_successfully_constructs_multiple_states_and_starts_on_default() { val one = tokenType() val two = tokenType() val other = stateLabel() @@ -149,7 +149,7 @@ class LixyStateTest { } @Test - fun `Lixy supports switching from state to state`() { + fun lixy_supports_switching_from_state_to_state() { val one = tokenType() val two = tokenType() val other = stateLabel() @@ -175,7 +175,7 @@ class LixyStateTest { } @Test - fun `Lixy supports redirecting the default state`() { + fun lixy_supports_redirecting_the_default_state() { val a = stateLabel() val b = stateLabel() val ta = tokenType() @@ -205,7 +205,7 @@ class LixyStateTest { } @Test - fun `Lixy cannot redefine default after redirecting default`() { + fun lixy_cannot_redefine_default_after_redirecting_default() { val a = stateLabel() val ta = tokenType() val b = stateLabel() @@ -221,11 +221,11 @@ class LixyStateTest { } } } - assert(exc.message!!.contains("already defined")) + assertTrue(exc.message!!.contains("already defined")) } @Test - fun `Lixy cannot redefine default state in single state lexer kind`() { + fun lixy_cannot_redefine_default_state_in_single_state_lexer_kind() { val a = stateLabel() val ta = tokenType() val exc = assertFailsWith { @@ -236,7 +236,7 @@ class LixyStateTest { default state a } } - assert(exc.message!!.contains("Cannot redefine")) - assert(exc.message!!.contains("single-state")) + assertTrue(exc.message!!.contains("Cannot redefine")) + assertTrue(exc.message!!.contains("single-state")) } } \ No newline at end of file diff --git a/src/test/kotlin/guru/zoroark/lixy/LixyTest.kt b/src/commonTest/kotlin/guru/zoroark/lixy/LixyTest.kt similarity index 89% rename from src/test/kotlin/guru/zoroark/lixy/LixyTest.kt rename to src/commonTest/kotlin/guru/zoroark/lixy/LixyTest.kt index 10c1cf2..c2dfba5 100644 --- a/src/test/kotlin/guru/zoroark/lixy/LixyTest.kt +++ b/src/commonTest/kotlin/guru/zoroark/lixy/LixyTest.kt @@ -1,12 +1,13 @@ package guru.zoroark.lixy import guru.zoroark.lixy.matchers.anyOf +import guru.zoroark.lixy.matchers.matches import kotlin.test.* class LixyTest { @Test - fun `Empty Lixy should crash`() { + fun empty_lixy_should_crash() { // I mean, yeah, that lexer is not going to do anything assertFailsWith { lixy {} @@ -14,18 +15,18 @@ class LixyTest { } @Test - fun `Lixy constructs single unlabeled state`() { + fun lixy_constructs_single_unlabeled_state() { // Should construct a single empty state val ret = lixy { state {} } assertEquals(ret.statesCount, 1) - assert(ret.defaultState.matchers.isEmpty()) + assertTrue(ret.defaultState.matchers.isEmpty()) } @Test - fun `Lixy is able to lex simple unlabeled state`() { + fun lixy_is_able_to_lex_simple_unlabeled_state() { // Should construct a single state with a single matcher val simpleStateDot = tokenType() @@ -49,7 +50,7 @@ class LixyTest { } @Test - fun `Lixy is able to lex multiple token types unlabeled state`() { + fun lixy_is_able_to_lex_multiple_token_types_unlabeled_state() { // Should successfully lex with a single more complex state val ttdot = tokenType() val ttspace = tokenType() @@ -80,7 +81,7 @@ class LixyTest { } @Test - fun `Lixy is able to parse some funny string patterns, v2`() { + fun lixy_is_able_to_parse_some_funny_string_patterns_v2() { // Additional testing, specifically because lexing tests are supposed // to be done sequentially (i.e. check for the first pattern, then the // second, etc.) @@ -115,7 +116,7 @@ class LixyTest { } @Test - fun `Lixy supports custom matchers`() { + fun lixy_supports_custom_matchers() { // ttype will be the type returned by our custom matcher val ttype = tokenType() val ttdot = tokenType() @@ -148,7 +149,7 @@ class LixyTest { } @Test - fun `Lixy incoherent matcher results cause exception (start before index)`() { + fun lixy_incoherent_matcher_results_cause_exception_start_before_index() { // Our token types val ttype = tokenType() val ttdot = tokenType() @@ -171,11 +172,11 @@ class LixyTest { lexer.tokenize("...") } assertNotNull(exc.message) - assert(exc.message!!.contains("token starts")) + assertTrue(exc.message!!.contains("token starts")) } @Test - fun `Lixy incoherent matcher results cause exception (end is too far)`() { + fun lixy_incoherent_matcher_results_cause_exception_end_is_too_far() { val ttype = tokenType() val ttdot = tokenType() val lexer = lixy { @@ -199,11 +200,11 @@ class LixyTest { lexer.tokenize("....") } assertNotNull(exc.message) - assert(exc.message!!.contains("token ends")) + assertTrue(exc.message!!.contains("token ends")) } @Test - fun `Lixy no match fails`() { + fun lixy_no_match_fails() { val ttdot = tokenType() val lexer = lixy { state { @@ -216,7 +217,7 @@ class LixyTest { } @Test - fun `Lixy supports regex`() { + fun lixy_supports_regex() { val ttregex = tokenType() val lexer = lixy { state { @@ -234,7 +235,7 @@ class LixyTest { } @Test - fun `Lixy supports transparent look-behind in regex`() { + fun lixy_supports_transparent_lookbehind_in_regex() { val ttregex = tokenType() val ttype = tokenType() val lexer = lixy { @@ -256,7 +257,7 @@ class LixyTest { } @Test - fun `Lixy regex matches start and end of string as real start and end`() { + fun lixy_regex_matches_start_and_end_of_string_as_real_start_and_end() { val ttregex = tokenType() val ttype = tokenType() val lexer = lixy { @@ -280,7 +281,7 @@ class LixyTest { } @Test - fun `Lixy anyOf crashes if no provided arguments`() { + fun lixy_anyOf_crashes_if_no_provided_arguments() { val tokenType = tokenType() val exc = assertFailsWith { @@ -291,11 +292,11 @@ class LixyTest { } } assertNotNull(exc.message) - assert(exc.message!!.contains("anyOf") && exc.message!!.contains("at least one")) + assertTrue(exc.message!!.contains("anyOf") && exc.message!!.contains("at least one")) } @Test - fun `Lixy supports anyOf multistring matcher`() { + fun lixy_supports_anyOf_multistring_matcher() { val basicTokenType = tokenType() val multiTokenType = diff --git a/src/test/kotlin/guru/zoroark/lixy/OffsetCharSequenceTest.kt b/src/commonTest/kotlin/guru/zoroark/lixy/OffsetCharSequenceTest.kt similarity index 63% rename from src/test/kotlin/guru/zoroark/lixy/OffsetCharSequenceTest.kt rename to src/commonTest/kotlin/guru/zoroark/lixy/OffsetCharSequenceTest.kt index 550c9b1..2d51f9f 100644 --- a/src/test/kotlin/guru/zoroark/lixy/OffsetCharSequenceTest.kt +++ b/src/commonTest/kotlin/guru/zoroark/lixy/OffsetCharSequenceTest.kt @@ -5,23 +5,23 @@ import kotlin.test.* class OffsetCharSequenceTest { @Test - fun `Offset char sequence length`() { + fun offset_char_sequence_length() { assertEquals("hello".offsetBy(3).length, 2) } @Test - fun `Offset char sequence throws error if incorrect offset`() { + fun offset_char_sequence_throws_error_if_incorrect_offset() { assertFails { "hey".offsetBy(4) } } @Test - fun `Offset char sequence correct`() { + fun offset_char_sequence_correct() { val offset = "hello".offsetBy(2) assertEquals(offset[0], 'l') assertEquals(offset[1], 'l') assertEquals(offset[2], 'o') - assertFailsWith { offset[3] } + assertFailsWith { offset[3] } } } \ No newline at end of file diff --git a/src/test/kotlin/guru/zoroark/lixy/RangeRecognizerTests.kt b/src/commonTest/kotlin/guru/zoroark/lixy/RangeRecognizerTests.kt similarity index 94% rename from src/test/kotlin/guru/zoroark/lixy/RangeRecognizerTests.kt rename to src/commonTest/kotlin/guru/zoroark/lixy/RangeRecognizerTests.kt index c1cf6ee..dc22f74 100644 --- a/src/test/kotlin/guru/zoroark/lixy/RangeRecognizerTests.kt +++ b/src/commonTest/kotlin/guru/zoroark/lixy/RangeRecognizerTests.kt @@ -2,12 +2,12 @@ package guru.zoroark.lixy import guru.zoroark.lixy.matchers.anyOf import guru.zoroark.lixy.matchers.repeated -import guru.zoroark.lixy.matchers.toRecognizer -import kotlin.test.* +import kotlin.test.Test +import kotlin.test.assertEquals class RangeRecognizerTests { @Test - fun `Range can be used as bare recognizer`() { + fun range_can_be_used_as_bare_recognizer() { val ta = tokenType() val tdigit = tokenType() val lexer = lixy { @@ -42,7 +42,7 @@ class RangeRecognizerTests { } @Test - fun `Range can be used with repetition`() { + fun range_can_be_used_with_repetition() { val top = tokenType() val tsign = tokenType() val tnumber = tokenType() diff --git a/src/test/kotlin/guru/zoroark/lixy/RepeatedRecognizerTest.kt b/src/commonTest/kotlin/guru/zoroark/lixy/RepeatedRecognizerTest.kt similarity index 94% rename from src/test/kotlin/guru/zoroark/lixy/RepeatedRecognizerTest.kt rename to src/commonTest/kotlin/guru/zoroark/lixy/RepeatedRecognizerTest.kt index 4bc239b..079f99a 100644 --- a/src/test/kotlin/guru/zoroark/lixy/RepeatedRecognizerTest.kt +++ b/src/commonTest/kotlin/guru/zoroark/lixy/RepeatedRecognizerTest.kt @@ -7,7 +7,7 @@ import kotlin.test.* class RepeatedRecognizerTest { @Test - fun `Repeated string recognizer test`() { + fun repeated_string_recognizer_test() { val thi = tokenType() val thello = tokenType() val lexer = lixy { @@ -30,7 +30,7 @@ class RepeatedRecognizerTest { } @Test - fun `Repeated string recognizer with additional parameters test`() { + fun repeated_string_recognizer_with_additional_parameters_test() { val thi = tokenType() val thello = tokenType() val lexer = lixy { @@ -66,7 +66,7 @@ class RepeatedRecognizerTest { } @Test - fun `Any repeated recognizer test`() { + fun any_repeated_recognizer_test() { val tgreet = tokenType() val ttest = tokenType() val lexer = lixy { @@ -90,7 +90,7 @@ class RepeatedRecognizerTest { } @Test - fun `Any repeated recognizer with additional parameters test`() { + fun any_repeated_recognizer_with_additional_parameters_test() { val tgreet = tokenType() val ttest = tokenType() val lexer = lixy { diff --git a/src/commonTest/kotlin/guru/zoroark/lixy/samples/NumberWordDetector.kt b/src/commonTest/kotlin/guru/zoroark/lixy/samples/NumberWordDetector.kt new file mode 100644 index 0000000..7cb12bc --- /dev/null +++ b/src/commonTest/kotlin/guru/zoroark/lixy/samples/NumberWordDetector.kt @@ -0,0 +1,36 @@ +package guru.zoroark.lixy.samples + +import guru.zoroark.lixy.LixyTokenType +import guru.zoroark.lixy.lixy +import guru.zoroark.lixy.matchers.anyOf +import guru.zoroark.lixy.matchers.matches +import guru.zoroark.lixy.matchers.repeated +import guru.zoroark.lixy.samples.TokenTypes.* +import kotlin.test.* + +enum class TokenTypes : LixyTokenType { + WORD, NUMBER, WHITESPACE +} + +val lexer = lixy { + state { + matches("\\d+") isToken NUMBER + matches("\\w+") isToken WORD + anyOf(" ", "\n", "\t").repeated isToken WHITESPACE + } +} + +class WordNumberDetectorTest { + @Test + fun test_my_lexer() { + val result = lexer.tokenize( + """ + Hello 42 World + I hope you are having a good time + """.trimIndent() + ) + result.forEach { + println("${it.string} --> ${it.tokenType}") + } + } +} diff --git a/src/test/kotlin/guru/zoroark/lixy/samples/StringDetector.kt b/src/commonTest/kotlin/guru/zoroark/lixy/samples/StringDetector.kt similarity index 94% rename from src/test/kotlin/guru/zoroark/lixy/samples/StringDetector.kt rename to src/commonTest/kotlin/guru/zoroark/lixy/samples/StringDetector.kt index d8828d4..65859b5 100644 --- a/src/test/kotlin/guru/zoroark/lixy/samples/StringDetector.kt +++ b/src/commonTest/kotlin/guru/zoroark/lixy/samples/StringDetector.kt @@ -4,6 +4,7 @@ import guru.zoroark.lixy.LixyStateLabel import guru.zoroark.lixy.LixyTokenType import guru.zoroark.lixy.lixy import guru.zoroark.lixy.matchers.anyOf +import guru.zoroark.lixy.matchers.matches import guru.zoroark.lixy.samples.StringDetectorLabels.* import guru.zoroark.lixy.samples.StringDetectorTypes.* import kotlin.test.* @@ -18,7 +19,7 @@ enum class StringDetectorLabels: LixyStateLabel { class StringDetector { @Test - fun `String detector`() { + fun string_detector() { val lexer = lixy { default state { anyOf(" ", "\t", "\n") isToken whitespace diff --git a/src/main/kotlin/guru/zoroark/lixy/matchers/RegexPatternRecognizer.kt b/src/jvmMain/kotlin/guru/zoroark/lixy/matchers/JvmRegexRecognizer.kt similarity index 56% rename from src/main/kotlin/guru/zoroark/lixy/matchers/RegexPatternRecognizer.kt rename to src/jvmMain/kotlin/guru/zoroark/lixy/matchers/JvmRegexRecognizer.kt index a4535fb..3d3de27 100644 --- a/src/main/kotlin/guru/zoroark/lixy/matchers/RegexPatternRecognizer.kt +++ b/src/jvmMain/kotlin/guru/zoroark/lixy/matchers/JvmRegexRecognizer.kt @@ -1,19 +1,25 @@ package guru.zoroark.lixy.matchers +import guru.zoroark.lixy.LixyDslStateEnvironment +import org.intellij.lang.annotations.Language import java.util.regex.Pattern -internal class RegexPatternRecognizer(val regexPattern: Pattern) : +internal class RegexPatternRecognizer(private val pattern: Pattern) : LixyTokenRecognizer { override fun recognize(s: String, startAt: Int): Pair? { - val matcher = regexPattern.matcher(s).apply { + val matcher = pattern.matcher(s).apply { region(startAt, s.length) // Look-behind and look-ahead can go beyond region bounds useTransparentBounds(true) // ^ and $ match the real start and end of the original string useAnchoringBounds(false) } - if(!matcher.lookingAt()) + if (!matcher.lookingAt()) return null return matcher.group() to matcher.end() } } + +actual fun LixyDslStateEnvironment.matches( + @Language("RegExp") pattern: String +): LixyTokenRecognizer = RegexPatternRecognizer(Pattern.compile(pattern)) \ No newline at end of file diff --git a/src/nonJvmMain/kotlin/NonJvmRegexRecognizer.kt b/src/nonJvmMain/kotlin/NonJvmRegexRecognizer.kt new file mode 100644 index 0000000..a8f73d5 --- /dev/null +++ b/src/nonJvmMain/kotlin/NonJvmRegexRecognizer.kt @@ -0,0 +1,21 @@ +package guru.zoroark.lixy.matchers + +import guru.zoroark.lixy.LixyDslStateEnvironment + +/* + * This version is less optimized than the JVM version due to limitations on the + * Regex object, which does not have all of the features of the JVM's Matcher and + * Pattern objects. + */ +internal class NonJvmRegexPatternRecognizer(private val regex: Regex) : + LixyTokenRecognizer { + override fun recognize(s: String, startAt: Int): Pair? = + regex.find(s, startAt) + ?.takeIf { it.range.first == startAt } + ?.let { + it.value to it.range.last + 1 + } +} + +actual fun LixyDslStateEnvironment.matches(pattern: String): LixyTokenRecognizer = + NonJvmRegexPatternRecognizer(pattern.toRegex()) \ No newline at end of file