mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 13:11:32 +00:00
language: floating point support
This commit is contained in:
@ -114,11 +114,16 @@ types:
|
|||||||
type: Symbol
|
type: Symbol
|
||||||
- name: components
|
- name: components
|
||||||
type: List<Symbol>
|
type: List<Symbol>
|
||||||
IntLiteral:
|
IntegerLiteral:
|
||||||
parent: Expression
|
parent: Expression
|
||||||
values:
|
values:
|
||||||
- name: value
|
- name: value
|
||||||
type: Int
|
type: Int
|
||||||
|
DoubleLiteral:
|
||||||
|
parent: Expression
|
||||||
|
values:
|
||||||
|
- name: value
|
||||||
|
type: Double
|
||||||
ListLiteral:
|
ListLiteral:
|
||||||
parent: Expression
|
parent: Expression
|
||||||
values:
|
values:
|
||||||
|
@ -5,15 +5,15 @@ import kotlinx.serialization.SerialName
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("intLiteral")
|
@SerialName("doubleLiteral")
|
||||||
class IntLiteral(val value: Int) : Expression() {
|
class DoubleLiteral(val value: Double) : Expression() {
|
||||||
override val type: NodeType = NodeType.IntLiteral
|
override val type: NodeType = NodeType.DoubleLiteral
|
||||||
|
|
||||||
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
visitor.visitIntLiteral(this)
|
visitor.visitDoubleLiteral(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is IntLiteral) return false
|
if (other !is DoubleLiteral) return false
|
||||||
return other.value == value
|
return other.value == value
|
||||||
}
|
}
|
||||||
|
|
25
ast/src/main/kotlin/gay/pizza/pork/ast/IntegerLiteral.kt
Normal file
25
ast/src/main/kotlin/gay/pizza/pork/ast/IntegerLiteral.kt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("integerLiteral")
|
||||||
|
class IntegerLiteral(val value: Int) : Expression() {
|
||||||
|
override val type: NodeType = NodeType.IntegerLiteral
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitIntegerLiteral(this)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is IntegerLiteral) return false
|
||||||
|
return other.value == value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = value.hashCode()
|
||||||
|
result = 31 * result + type.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,9 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
|||||||
override fun visitContinue(node: Continue): Unit =
|
override fun visitContinue(node: Continue): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
|
override fun visitDoubleLiteral(node: DoubleLiteral): Unit =
|
||||||
|
handle(node)
|
||||||
|
|
||||||
override fun visitFunctionCall(node: FunctionCall): Unit =
|
override fun visitFunctionCall(node: FunctionCall): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
@ -32,7 +35,7 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
|||||||
override fun visitInfixOperation(node: InfixOperation): Unit =
|
override fun visitInfixOperation(node: InfixOperation): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
override fun visitIntLiteral(node: IntLiteral): Unit =
|
override fun visitIntegerLiteral(node: IntegerLiteral): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
override fun visitLetAssignment(node: LetAssignment): Unit =
|
override fun visitLetAssignment(node: LetAssignment): Unit =
|
||||||
|
@ -11,12 +11,13 @@ enum class NodeType(val parent: NodeType? = null) {
|
|||||||
Continue(Expression),
|
Continue(Expression),
|
||||||
Declaration(Node),
|
Declaration(Node),
|
||||||
Definition(Node),
|
Definition(Node),
|
||||||
|
DoubleLiteral(Expression),
|
||||||
FunctionCall(Expression),
|
FunctionCall(Expression),
|
||||||
FunctionDefinition(Definition),
|
FunctionDefinition(Definition),
|
||||||
If(Expression),
|
If(Expression),
|
||||||
ImportDeclaration(Declaration),
|
ImportDeclaration(Declaration),
|
||||||
InfixOperation(Expression),
|
InfixOperation(Expression),
|
||||||
IntLiteral(Expression),
|
IntegerLiteral(Expression),
|
||||||
LetAssignment(Expression),
|
LetAssignment(Expression),
|
||||||
ListLiteral(Expression),
|
ListLiteral(Expression),
|
||||||
Native(Node),
|
Native(Node),
|
||||||
|
@ -12,6 +12,8 @@ interface NodeVisitor<T> {
|
|||||||
|
|
||||||
fun visitContinue(node: Continue): T
|
fun visitContinue(node: Continue): T
|
||||||
|
|
||||||
|
fun visitDoubleLiteral(node: DoubleLiteral): T
|
||||||
|
|
||||||
fun visitFunctionCall(node: FunctionCall): T
|
fun visitFunctionCall(node: FunctionCall): T
|
||||||
|
|
||||||
fun visitFunctionDefinition(node: FunctionDefinition): T
|
fun visitFunctionDefinition(node: FunctionDefinition): T
|
||||||
@ -22,7 +24,7 @@ interface NodeVisitor<T> {
|
|||||||
|
|
||||||
fun visitInfixOperation(node: InfixOperation): T
|
fun visitInfixOperation(node: InfixOperation): T
|
||||||
|
|
||||||
fun visitIntLiteral(node: IntLiteral): T
|
fun visitIntegerLiteral(node: IntegerLiteral): T
|
||||||
|
|
||||||
fun visitLetAssignment(node: LetAssignment): T
|
fun visitLetAssignment(node: LetAssignment): T
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ fun <T> NodeVisitor<T>.visit(node: Node): T =
|
|||||||
is FunctionDefinition -> visitFunctionDefinition(node)
|
is FunctionDefinition -> visitFunctionDefinition(node)
|
||||||
is If -> visitIf(node)
|
is If -> visitIf(node)
|
||||||
is ImportDeclaration -> visitImportDeclaration(node)
|
is ImportDeclaration -> visitImportDeclaration(node)
|
||||||
is IntLiteral -> visitIntLiteral(node)
|
is IntegerLiteral -> visitIntegerLiteral(node)
|
||||||
|
is DoubleLiteral -> visitDoubleLiteral(node)
|
||||||
is ListLiteral -> visitListLiteral(node)
|
is ListLiteral -> visitListLiteral(node)
|
||||||
is Parentheses -> visitParentheses(node)
|
is Parentheses -> visitParentheses(node)
|
||||||
is PrefixOperation -> visitPrefixOperation(node)
|
is PrefixOperation -> visitPrefixOperation(node)
|
||||||
|
@ -3,5 +3,6 @@ package gay.pizza.pork.buildext.ast
|
|||||||
enum class AstPrimitive(val id: kotlin.String) {
|
enum class AstPrimitive(val id: kotlin.String) {
|
||||||
Boolean("Boolean"),
|
Boolean("Boolean"),
|
||||||
String("String"),
|
String("String"),
|
||||||
Int("Int")
|
Int("Int"),
|
||||||
|
Double("Double")
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ import gay.pizza.pork.ast.*
|
|||||||
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
||||||
private var currentScope: Scope = root
|
private var currentScope: Scope = root
|
||||||
|
|
||||||
override fun visitIntLiteral(node: IntLiteral): Any = node.value
|
override fun visitIntegerLiteral(node: IntegerLiteral): Any = node.value
|
||||||
|
override fun visitDoubleLiteral(node: DoubleLiteral): Any = node.value
|
||||||
override fun visitStringLiteral(node: StringLiteral): Any = node.text
|
override fun visitStringLiteral(node: StringLiteral): Any = node.text
|
||||||
override fun visitBooleanLiteral(node: BooleanLiteral): Any = node.value
|
override fun visitBooleanLiteral(node: BooleanLiteral): Any = node.value
|
||||||
|
|
||||||
@ -95,15 +96,77 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
throw RuntimeException("Failed to evaluate infix operation, bad types.")
|
throw RuntimeException("Failed to evaluate infix operation, bad types.")
|
||||||
}
|
}
|
||||||
|
|
||||||
val leftInt = left.toInt()
|
if (left is Double || right is Double) {
|
||||||
val rightInt = right.toInt()
|
return numericOperation(
|
||||||
|
node.op,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
convert = { it.toDouble() },
|
||||||
|
add = { a, b -> a + b },
|
||||||
|
subtract = { a, b -> a - b },
|
||||||
|
multiply = { a, b -> a * b },
|
||||||
|
divide = { a, b -> a / b }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return when (node.op) {
|
if (left is Float || right is Float) {
|
||||||
InfixOperator.Plus -> leftInt + rightInt
|
return numericOperation(
|
||||||
InfixOperator.Minus -> leftInt - rightInt
|
node.op,
|
||||||
InfixOperator.Multiply -> leftInt * rightInt
|
left,
|
||||||
InfixOperator.Divide -> leftInt / rightInt
|
right,
|
||||||
else -> throw RuntimeException("Unable to handle operation ${node.op}")
|
convert = { it.toFloat() },
|
||||||
|
add = { a, b -> a + b },
|
||||||
|
subtract = { a, b -> a - b },
|
||||||
|
multiply = { a, b -> a * b },
|
||||||
|
divide = { a, b -> a / b }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left is Long || right is Long) {
|
||||||
|
return numericOperation(
|
||||||
|
node.op,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
convert = { it.toLong() },
|
||||||
|
add = { a, b -> a + b },
|
||||||
|
subtract = { a, b -> a - b },
|
||||||
|
multiply = { a, b -> a * b },
|
||||||
|
divide = { a, b -> a / b }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left is Int || right is Int) {
|
||||||
|
return numericOperation(
|
||||||
|
node.op,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
convert = { it.toInt() },
|
||||||
|
add = { a, b -> a + b },
|
||||||
|
subtract = { a, b -> a - b },
|
||||||
|
multiply = { a, b -> a * b },
|
||||||
|
divide = { a, b -> a / b }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw RuntimeException("Unknown numeric type: ${left.javaClass.name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <T: Number> numericOperation(
|
||||||
|
op: InfixOperator,
|
||||||
|
left: Number,
|
||||||
|
right: Number,
|
||||||
|
convert: (Number) -> T,
|
||||||
|
add: (T, T) -> T,
|
||||||
|
subtract: (T, T) -> T,
|
||||||
|
multiply: (T, T) -> T,
|
||||||
|
divide: (T, T) -> T
|
||||||
|
): T {
|
||||||
|
return when (op) {
|
||||||
|
InfixOperator.Plus -> add(convert(left), convert(right))
|
||||||
|
InfixOperator.Minus -> subtract(convert(left), convert(right))
|
||||||
|
InfixOperator.Multiply -> multiply(convert(left), convert(right))
|
||||||
|
InfixOperator.Divide -> divide(convert(left), convert(right))
|
||||||
|
else -> throw RuntimeException("Unable to handle operation $op")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
import java java.lang.Math
|
||||||
import java java.lang.System
|
import java java.lang.System
|
||||||
import java java.io.PrintStream
|
import java java.io.PrintStream
|
||||||
|
|
||||||
export func main() {
|
export func main() {
|
||||||
let stream = java_lang_System_err_get()
|
let stream = java_lang_System_err_get()
|
||||||
java_io_PrintStream_println_string(stream, "Hello World")
|
java_io_PrintStream_println_string(stream, "Hello World")
|
||||||
|
let pi = java_lang_Math_PI_get()
|
||||||
|
println(pi)
|
||||||
}
|
}
|
||||||
|
4
examples/numbers.pork
Normal file
4
examples/numbers.pork
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export func main() {
|
||||||
|
let pi = 3.141592653589793
|
||||||
|
println(pi)
|
||||||
|
}
|
@ -11,8 +11,8 @@ class FfiFunctionDefinition(
|
|||||||
if (parts.size !in arrayOf(3, 4) || parts.any { it.trim().isEmpty() }) {
|
if (parts.size !in arrayOf(3, 4) || parts.any { it.trim().isEmpty() }) {
|
||||||
throw RuntimeException(
|
throw RuntimeException(
|
||||||
"FFI function definition is invalid, " +
|
"FFI function definition is invalid, " +
|
||||||
"excepted format is 'library:function:return-type:(optional)parameters'" +
|
"accepted format is 'library:function:return-type:(optional)parameters' " +
|
||||||
" but '${def}' was specified")
|
"but '${def}' was specified")
|
||||||
}
|
}
|
||||||
val (library, function, returnType) = parts
|
val (library, function, returnType) = parts
|
||||||
return FfiFunctionDefinition(library, function, returnType)
|
return FfiFunctionDefinition(library, function, returnType)
|
||||||
|
@ -13,7 +13,8 @@ class JavaFunctionDefinition(
|
|||||||
if (!(parts.size == 4 || parts.size == 5) || parts.any { it.trim().isEmpty() }) {
|
if (!(parts.size == 4 || parts.size == 5) || parts.any { it.trim().isEmpty() }) {
|
||||||
throw RuntimeException(
|
throw RuntimeException(
|
||||||
"Java function definition is invalid, " +
|
"Java function definition is invalid, " +
|
||||||
"excepted format is 'type:kind:symbol:return-type:(optional)parameters' but '${def}' was specified")
|
"accepted format is 'type:kind:symbol:return-type:(optional)parameters' " +
|
||||||
|
"but '${def}' was specified")
|
||||||
}
|
}
|
||||||
val (type, kind, symbol, returnType) = parts
|
val (type, kind, symbol, returnType) = parts
|
||||||
val parameters = if (parts.size > 4) parts[4].split(",") else emptyList()
|
val parameters = if (parts.size > 4) parts[4].split(",") else emptyList()
|
||||||
|
@ -32,6 +32,8 @@ class JavaNativeProvider : NativeFunctionProvider {
|
|||||||
"short" -> Short::class.java
|
"short" -> Short::class.java
|
||||||
"int" -> Int::class.java
|
"int" -> Int::class.java
|
||||||
"long" -> Long::class.java
|
"long" -> Long::class.java
|
||||||
|
"float" -> Float::class.java
|
||||||
|
"double" -> Double::class.java
|
||||||
else -> lookup.findClass(name)
|
else -> lookup.findClass(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,14 @@ import gay.pizza.pork.ast.*
|
|||||||
class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
||||||
private val unsanitizedSource = source
|
private val unsanitizedSource = source
|
||||||
|
|
||||||
private fun readIntLiteral(): IntLiteral = within {
|
private fun readNumberLiteral(): Expression = within {
|
||||||
expect(TokenType.IntLiteral) { IntLiteral(it.text.toInt()) }
|
expect(TokenType.NumberLiteral) {
|
||||||
|
if (it.text.contains(".")) {
|
||||||
|
DoubleLiteral(it.text.toDouble())
|
||||||
|
} else {
|
||||||
|
IntegerLiteral(it.text.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readStringLiteral(): StringLiteral = within {
|
private fun readStringLiteral(): StringLiteral = within {
|
||||||
@ -97,8 +103,8 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
|||||||
fun readExpression(): Expression {
|
fun readExpression(): Expression {
|
||||||
val token = peek()
|
val token = peek()
|
||||||
val expression = when (token.type) {
|
val expression = when (token.type) {
|
||||||
TokenType.IntLiteral -> {
|
TokenType.NumberLiteral -> {
|
||||||
readIntLiteral()
|
readNumberLiteral()
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType.StringLiteral -> {
|
TokenType.StringLiteral -> {
|
||||||
|
@ -20,7 +20,11 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
autoIndentState = true
|
autoIndentState = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitIntLiteral(node: IntLiteral) {
|
override fun visitIntegerLiteral(node: IntegerLiteral) {
|
||||||
|
append(node.value.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoubleLiteral(node: DoubleLiteral) {
|
||||||
append(node.value.toString())
|
append(node.value.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,13 @@ import gay.pizza.pork.parser.TokenTypeProperty.*
|
|||||||
import gay.pizza.pork.parser.TokenFamily.*
|
import gay.pizza.pork.parser.TokenFamily.*
|
||||||
|
|
||||||
enum class TokenType(vararg properties: TokenTypeProperty) {
|
enum class TokenType(vararg properties: TokenTypeProperty) {
|
||||||
Symbol(SymbolFamily, CharConsumer { (it in 'a'..'z') || (it in 'A'..'Z') || it == '_' }, KeywordUpgrader),
|
NumberLiteral(NumericLiteralFamily, CharIndexConsumer { it, index ->
|
||||||
IntLiteral(NumericLiteralFamily, CharConsumer { it in '0'..'9' }),
|
(it in '0'..'9') || (index > 0 && it == '.') }),
|
||||||
|
Symbol(SymbolFamily, CharConsumer {
|
||||||
|
(it in 'a'..'z') ||
|
||||||
|
(it in 'A'..'Z') ||
|
||||||
|
(it == '_') ||
|
||||||
|
(it in '0' .. '9')}, KeywordUpgrader),
|
||||||
StringLiteral(StringLiteralFamily),
|
StringLiteral(StringLiteralFamily),
|
||||||
Equality(OperatorFamily),
|
Equality(OperatorFamily),
|
||||||
Inequality(OperatorFamily),
|
Inequality(OperatorFamily),
|
||||||
@ -40,17 +45,24 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
|
|||||||
LineComment(CommentFamily),
|
LineComment(CommentFamily),
|
||||||
EndOfFile;
|
EndOfFile;
|
||||||
|
|
||||||
val promotions: List<Promotion> = properties.filterIsInstance<Promotion>()
|
val promotions: List<Promotion> =
|
||||||
val keyword: Keyword? = properties.filterIsInstance<Keyword>().singleOrNull()
|
properties.filterIsInstance<Promotion>()
|
||||||
val singleChar: SingleChar? = properties.filterIsInstance<SingleChar>().singleOrNull()
|
val keyword: Keyword? =
|
||||||
|
properties.filterIsInstance<Keyword>().singleOrNull()
|
||||||
|
val singleChar: SingleChar? =
|
||||||
|
properties.filterIsInstance<SingleChar>().singleOrNull()
|
||||||
val family: TokenFamily =
|
val family: TokenFamily =
|
||||||
properties.filterIsInstance<TokenFamily>().singleOrNull() ?: OtherFamily
|
properties.filterIsInstance<TokenFamily>().singleOrNull() ?: OtherFamily
|
||||||
val charConsumer: CharConsumer? = properties.filterIsInstance<CharConsumer>().singleOrNull()
|
val charConsumer: CharConsumer? = properties.filterIsInstance<CharConsumer>().singleOrNull()
|
||||||
val tokenUpgrader: TokenUpgrader? = properties.filterIsInstance<TokenUpgrader>().singleOrNull()
|
val charIndexConsumer: CharIndexConsumer? =
|
||||||
|
properties.filterIsInstance<CharIndexConsumer>().singleOrNull()
|
||||||
|
val tokenUpgrader: TokenUpgrader? =
|
||||||
|
properties.filterIsInstance<TokenUpgrader>().singleOrNull()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val Keywords = entries.filter { item -> item.keyword != null }
|
val Keywords = entries.filter { item -> item.keyword != null }
|
||||||
val SingleChars = entries.filter { item -> item.singleChar != null }
|
val SingleChars = entries.filter { item -> item.singleChar != null }
|
||||||
val CharConsumers = entries.filter { item -> item.charConsumer != null }
|
val CharConsumers = entries.filter { item ->
|
||||||
|
item.charConsumer != null || item.charIndexConsumer != null }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ interface TokenTypeProperty {
|
|||||||
class Promotion(val nextChar: Char, val type: TokenType) : TokenTypeProperty
|
class Promotion(val nextChar: Char, val type: TokenType) : TokenTypeProperty
|
||||||
class Keyword(val text: String) : TokenTypeProperty
|
class Keyword(val text: String) : TokenTypeProperty
|
||||||
class CharConsumer(val isValid: (Char) -> Boolean) : TokenTypeProperty
|
class CharConsumer(val isValid: (Char) -> Boolean) : TokenTypeProperty
|
||||||
|
class CharIndexConsumer(val isValid: (Char, Int) -> Boolean) : TokenTypeProperty
|
||||||
open class TokenUpgrader(val maybeUpgrade: (Token) -> Token?) : TokenTypeProperty
|
open class TokenUpgrader(val maybeUpgrade: (Token) -> Token?) : TokenTypeProperty
|
||||||
|
|
||||||
object KeywordUpgrader : TokenUpgrader({ token ->
|
object KeywordUpgrader : TokenUpgrader({ token ->
|
||||||
|
@ -90,15 +90,29 @@ class Tokenizer(val source: CharSource) {
|
|||||||
return Token(type, tokenStart, text)
|
return Token(type, tokenStart, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var index = 0
|
||||||
for (item in TokenType.CharConsumers) {
|
for (item in TokenType.CharConsumers) {
|
||||||
val consumer = item.charConsumer ?: continue
|
if (item.charConsumer != null) {
|
||||||
if (!consumer.isValid(char)) {
|
if (!item.charConsumer.isValid(char)) {
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
} else if (item.charIndexConsumer != null) {
|
||||||
|
if (!item.charIndexConsumer.isValid(char, index)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw RuntimeException("Unknown Char Consumer")
|
||||||
}
|
}
|
||||||
|
|
||||||
val text = buildString {
|
val text = buildString {
|
||||||
append(char)
|
append(char)
|
||||||
while (consumer.isValid(source.peek())) {
|
|
||||||
|
while (
|
||||||
|
if (item.charConsumer != null)
|
||||||
|
item.charConsumer.isValid(source.peek())
|
||||||
|
else
|
||||||
|
item.charIndexConsumer!!.isValid(source.peek(), ++index)
|
||||||
|
) {
|
||||||
append(source.next())
|
append(source.next())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user