Skip to content
Merged
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import org.gradle.api.tasks.testing.logging.TestLogEvent.*
import org.gradle.tooling.GradleConnector
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
Expand Down Expand Up @@ -148,6 +147,7 @@ kotlin {
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("org.yaml:snakeyaml:2.2")
}
}
val jsMain by getting
Expand Down
1 change: 0 additions & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import org.gradle.api.tasks.testing.logging.TestLogEvent.*
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
Expand Down
82 changes: 58 additions & 24 deletions src/commonMain/kotlin/org/kson/Kson.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.kson

import org.kson.ast.AstNode
import org.kson.ast.CompileTarget
import org.kson.ast.KsonRoot
import org.kson.collections.ImmutableList
import org.kson.parser.*
import org.kson.parser.messages.MessageType

Expand All @@ -22,56 +25,87 @@ class Kson {
val tokens = Lexer(source).tokenize()
if (tokens[0].tokenType == TokenType.EOF) {
messageSink.error(tokens[0].lexeme.location, MessageType.BLANK_SOURCE.create())
return ParseResult(null, tokens, messageSink)
}
val ast = if (messageSink.hasErrors()) {
// parsing failed at the lexing stage
return ParseResult(null, tokens, messageSink)
} else {
val builder = KsonBuilder(tokens)
Parser(builder, maxNestingLevel).parse()
builder.buildTree(messageSink)
return AstParseResult(null, tokens, messageSink)
}

val builder = KsonBuilder(tokens)
Parser(builder, maxNestingLevel).parse()
val ast = builder.buildTree(messageSink)

if (schemaJson == NO_SCHEMA) {
return ParseResult(ast, tokens, messageSink)
return AstParseResult(ast, tokens, messageSink)
} else {
TODO("Json Schema support for Kson not yet implemented")
}
}

/**
* Parse the given Kson [source] and compile it to Yaml
*
* @param source The Kson source to parse
* @param retainEmbedTags If true, embed blocks will be compiled to objects containing both tag and content.
* Default: false, which means embed blocks are compiled to multi-line strings of the
* block's content
* @param maxNestingLevel Maximum object/list nesting parser must support in the given Kson
* @return A [YamlParseResult]
*/
fun parseToYaml(source: String,
retainEmbedTags: Boolean = false,
maxNestingLevel: Int = DEFAULT_MAX_NESTING_LEVEL
): YamlParseResult {
return YamlParseResult(parse(source, maxNestingLevel), retainEmbedTags)
}
}
}

/**
* @param ast is the parsed AST, or null if the source was invalid kson (in which cases [messages] will contain errors)
* @param lexedTokens
* @param messageSink the messages logged during parsing to return to the user
* The type generated by our [Kson] parser
*/
data class ParseResult(
interface ParseResult {
/**
* The parsed AST, or null if the source was invalid kson (in which cases [hasErrors] will be true)
*/
val ast: KsonRoot?,
val ast: KsonRoot?

/**
* The tokens lexed from the input source, provided for debug purposes
*/
val lexedTokens: List<Token>,

/**
* The message sink used during parsing, exposed by this class in [messages] and [hasErrors]
*/
private val messageSink: MessageSink) {
val lexedTokens: List<Token>

/**
* The user-facing messages logged during this parse
*/
val messages = messageSink.loggedMessages()
val messages: ImmutableList<LoggedMessage>

/**
* True if the input source could not be parsed. [messages] will contain errors in this case.
* True if the input source could not be parsed. [messages] will contain errors in this case.
*/
fun hasErrors(): Boolean {
fun hasErrors(): Boolean
}

/**
* Core [ParseResult] produced by the [Kson] parser attempting to create a Kson abstract syntax tree ([ast])
* from some Kson source
*/
data class AstParseResult(
override val ast: KsonRoot?,
override val lexedTokens: List<Token>,
private val messageSink: MessageSink
) : ParseResult {
override val messages = messageSink.loggedMessages()

override fun hasErrors(): Boolean {
return messageSink.hasErrors()
}
}

class YamlParseResult(
val parseResult: ParseResult,
retainEmbedTags: Boolean = false
) : ParseResult by parseResult {
/**
* The Yaml compiled from some Kson source, or null if there were errors trying to parse
* (consult [parseResult] for information on any errors)
*/
val yaml: String? = parseResult.ast?.toCommentedSource(AstNode.Indent(), CompileTarget.Yaml(retainEmbedTags))
}
Loading