All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.github.dingyi222666.monarch.loader.json.MonarchLanguageRuleAdapter.kt Maven / Gradle / Ivy
/*
* monarch-kt - Kotlin port of Monarch library.
* https://github.com/dingyi222666/monarch-kt
* Copyright (C) 2024 dingyi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.dingyi222666.monarch.loader.json
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import io.github.dingyi222666.monarch.types.MonarchLanguageAction
import io.github.dingyi222666.monarch.types.MonarchLanguageRule
class MonarchLanguageRuleAdapter : JsonAdapter>>() {
override fun fromJson(reader: JsonReader): Map> {
reader.isLenient = true
val result = mutableMapOf>()
// an object
reader.beginObject()
// { rule1: [], rule2: [] }
while (reader.peek() != JsonReader.Token.END_OBJECT) {
// get key
val key = reader.nextName()
result[key] = parseRules(reader)
}
reader.endObject()
return result
}
private fun parseRules(reader: JsonReader): List {
val result = mutableListOf()
reader.beginArray()
while (reader.peek() != JsonReader.Token.END_ARRAY) {
when (val nextToken = reader.peek()) {
JsonReader.Token.BEGIN_ARRAY -> {
result.add(parseArrayRule(reader))
}
JsonReader.Token.BEGIN_OBJECT -> {
result.add(parseObjectRule(reader))
}
else -> {
throw JsonDataException("Unexpected token: $nextToken")
}
}
}
reader.endArray()
return result
}
/* parse [regex, action]
[regex, action, next] */
private fun parseArrayRule(reader: JsonReader): MonarchLanguageRule {
reader.beginArray()
// regex
// fuck escape
val regex = reader.nextString()
.withEscapes()
// action can be a string or an object, ...
if (reader.peek() == JsonReader.Token.END_ARRAY) {
reader.endArray()
return MonarchLanguageRule.ShortRule1(regex, null)
}
val action = parseAction(reader)
val nextToken = reader.peek()
// [regex, action, next]
val result = if (nextToken == JsonReader.Token.STRING) {
val nextState = reader.nextString()
MonarchLanguageRule.ShortRule2(regex, action, nextState)
} else {
MonarchLanguageRule.ShortRule1(regex, action)
}
reader.endArray()
return result
}
// {regex: regex, action: action }
// { include: }
private fun parseObjectRule(reader: JsonReader): MonarchLanguageRule {
reader.beginObject()
var regex: String? = null
var action: MonarchLanguageAction? = null
var include: String? = null
while (reader.peek() != JsonReader.Token.END_OBJECT) {
when (val nextName = reader.nextName()) {
"regex" -> regex = reader.nextString().withEscapes()
"action" -> action = parseAction(reader)
"include" -> include = reader.nextString()
else -> throw JsonDataException("Unexpected name: $nextName in ${reader.path}")
}
}
reader.endObject()
if (include != null) {
return MonarchLanguageRule.ExpandedLanguageRule(include)
}
if (regex == null) {
throw JsonDataException("Missing regex in ${reader.path}")
}
return MonarchLanguageRule.ShortRule1(regex, action)
}
// string
// [action1,...,actionN]
// { token: tokenclass }
// { cases: { guard1: action1, ..., guardN: actionN } }
private fun parseAction(reader: JsonReader): MonarchLanguageAction {
return when (val nextToken = reader.peek()) {
// string
JsonReader.Token.STRING -> {
MonarchLanguageAction.ShortLanguageAction(reader.nextString())
}
// [action1,...,actionN]
JsonReader.Token.BEGIN_ARRAY -> {
reader.beginArray()
val result = mutableListOf()
while (reader.peek() != JsonReader.Token.END_ARRAY) {
result.add(parseAction(reader))
}
reader.endArray()
MonarchLanguageAction.ActionArray(result)
}
// { token: tokenclass }
// { cases: { guard1: action1, ..., guardN: actionN } }
JsonReader.Token.BEGIN_OBJECT -> {
reader.beginObject()
val action = MonarchLanguageAction.MutableExpandedLanguageAction()
while (reader.peek() != JsonReader.Token.END_OBJECT) {
when (val nextName = reader.nextName()) {
"cases" -> {
action.cases = parseActionCases(reader)
}
"token" -> {
action.token = reader.nextString()
}
"next" -> {
action.next = reader.nextString()
}
"switchTo" -> {
action.switchTo = reader.nextString()
}
"goBack" -> {
action.goBack = reader.nextInt()
}
"bracket" -> {
action.bracket = reader.nextString()
}
"nextEmbedded" -> {
action.nextEmbedded = reader.nextString()
}
"log" -> {
action.log = reader.nextString()
}
else -> throw JsonDataException("Unexpected name: $nextName in ${reader.path}")
}
}
reader.endObject()
action.toExpandedLanguageAction()
}
else -> throw JsonDataException("Unexpected token: $nextToken in path ${reader.path}")
}
}
// { cases: { guard1: action1, ..., guardN: actionN } }
private fun parseActionCases(reader: JsonReader): Map {
reader.beginObject()
val result = mutableMapOf()
while (reader.peek() != JsonReader.Token.END_OBJECT) {
// get key
val guard = reader.nextName()
result[guard] = parseAction(reader)
}
reader.endObject()
return result
}
private fun writeAction(writer: JsonWriter, action: MonarchLanguageAction) {
when (action) {
is MonarchLanguageAction.ShortLanguageAction -> {
writer.value(action.token)
}
is MonarchLanguageAction.ActionArray -> {
writer.beginArray()
for (action in action.actions) {
writeAction(writer, action)
}
writer.endArray()
}
is MonarchLanguageAction.ExpandedLanguageAction -> {
writer.beginObject()
val group = action.group
if (group != null) {
writer.name("group")
writer.beginArray()
for (sub in group) {
writeAction(writer, sub)
}
}
val cases = action.cases
if (cases != null) {
writer.name("cases")
writer.beginObject()
for ((guard, action) in cases) {
writer.name(guard)
writeAction(writer, action)
}
writer.endObject()
}
if (action.token != null) {
writer.name("token")
writer.value(action.token)
}
if (action.next != null) {
writer.name("next")
writer.value(action.next)
}
if (action.switchTo != null) {
writer.name("switchTo")
writer.value(action.switchTo)
}
if (action.goBack != null) {
writer.name("goBack")
writer.value(action.goBack)
}
if (action.bracket != null) {
writer.name("bracket")
writer.value(action.bracket)
}
if (action.nextEmbedded != null) {
writer.name("nextEmbedded")
writer.value(action.nextEmbedded)
}
if (action.log != null) {
writer.name("log")
writer.value(action.log)
}
writer.endObject()
}
}
}
private fun writeRule(writer: JsonWriter, rule: MonarchLanguageRule) {
when (rule) {
is MonarchLanguageRule.ExpandedLanguageRule -> {
writer.beginObject()
writer.name("include")
writer.value(rule.include)
writer.endObject()
}
is MonarchLanguageRule.ShortRule1 -> {
writer.beginArray()
val regex = rule.regex
val regexString = if (regex is String) regex.withoutEscapes() else (rule.regex as Regex).pattern
writer.value(regexString)
rule.action?.let { writeAction(writer, it) }
writer.endArray()
}
is MonarchLanguageRule.ShortRule2 -> {
writer.beginArray()
val regex = rule.regex
val regexString = if (regex is String) regex.withoutEscapes() else (rule.regex as Regex).pattern
writer.value(regexString)
writeAction(writer, rule.action)
writer.value(rule.nextState)
writer.endArray()
}
}
}
override fun toJson(writer: JsonWriter, value: Map>?) {
if (value == null) {
writer.nullValue()
return
}
writer.beginObject()
for ((key, rules) in value) {
writer.name(key)
writer.beginArray()
for (rule in rules) {
writeRule(writer, rule)
}
writer.endArray()
}
writer.endObject()
}
}
fun String.withEscapes(): String {
return this //replace("\\", "\\\\")
}
fun String.withoutEscapes(): String {
return replace("\\\\", "\\")
}