mirror of
				https://github.com/GayPizzaSpecifications/pork.git
				synced 2025-11-03 17:39:38 +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