diff --git a/ast/src/main/ast/pork.yml b/ast/src/main/ast/pork.yml index 8ff561b..26c901b 100644 --- a/ast/src/main/ast/pork.yml +++ b/ast/src/main/ast/pork.yml @@ -18,6 +18,11 @@ types: - name: modifiers type: DefinitionModifiers required: true + TypeSpec: + parent: Node + values: + - name: symbol + type: Symbol DefinitionModifiers: values: - name: export @@ -42,6 +47,8 @@ types: type: Symbol - name: value type: Expression + - name: typeSpec + type: TypeSpec? VarAssignment: parent: Expression namedElementValue: symbol @@ -50,6 +57,8 @@ types: type: Symbol - name: value type: Expression + - name: typeSpec + type: TypeSpec? SetAssignment: parent: Expression values: @@ -142,6 +151,8 @@ types: values: - name: symbol type: Symbol + - name: typeSpec + type: TypeSpec? - name: multiple type: Boolean defaultValue: "false" @@ -155,6 +166,8 @@ types: type: Symbol - name: arguments type: List + - name: returnType + type: TypeSpec? - name: block type: Block? - name: nativeFunctionDescriptor @@ -167,6 +180,8 @@ types: type: DefinitionModifiers - name: symbol type: Symbol + - name: typeSpec + type: TypeSpec? - name: value type: Expression If: diff --git a/ast/src/main/graph/types.dot b/ast/src/main/graph/types.dot index 03312f8..1b5c561 100644 --- a/ast/src/main/graph/types.dot +++ b/ast/src/main/graph/types.dot @@ -4,6 +4,7 @@ digraph A { type_Symbol [shape=box,label="Symbol"] type_Declaration [shape=box,label="Declaration"] type_Definition [shape=box,label="Definition"] + type_TypeSpec [shape=box,label="TypeSpec"] type_DefinitionModifiers [shape=box,label="DefinitionModifiers"] type_Block [shape=box,label="Block"] type_CompilationUnit [shape=box,label="CompilationUnit"] @@ -44,6 +45,7 @@ digraph A { type_Node -> type_Symbol type_Node -> type_Declaration type_Node -> type_Definition + type_Node -> type_TypeSpec type_Node -> type_Block type_Node -> type_CompilationUnit type_Node -> type_ArgumentSpec @@ -78,13 +80,16 @@ digraph A { type_Declaration -> type_ImportDeclaration type_Definition -> type_Symbol [style=dotted] type_Definition -> type_DefinitionModifiers [style=dotted] + type_TypeSpec -> type_Symbol [style=dotted] type_Block -> type_Expression [style=dotted] type_CompilationUnit -> type_Declaration [style=dotted] type_CompilationUnit -> type_Definition [style=dotted] type_LetAssignment -> type_Symbol [style=dotted] type_LetAssignment -> type_Expression [style=dotted] + type_LetAssignment -> type_TypeSpec [style=dotted] type_VarAssignment -> type_Symbol [style=dotted] type_VarAssignment -> type_Expression [style=dotted] + type_VarAssignment -> type_TypeSpec [style=dotted] type_SetAssignment -> type_Symbol [style=dotted] type_SetAssignment -> type_Expression [style=dotted] type_InfixOperation -> type_Expression [style=dotted] @@ -92,13 +97,16 @@ digraph A { type_FunctionCall -> type_Symbol [style=dotted] type_FunctionCall -> type_Expression [style=dotted] type_ArgumentSpec -> type_Symbol [style=dotted] + type_ArgumentSpec -> type_TypeSpec [style=dotted] type_FunctionDefinition -> type_DefinitionModifiers [style=dotted] type_FunctionDefinition -> type_Symbol [style=dotted] type_FunctionDefinition -> type_ArgumentSpec [style=dotted] + type_FunctionDefinition -> type_TypeSpec [style=dotted] type_FunctionDefinition -> type_Block [style=dotted] type_FunctionDefinition -> type_NativeFunctionDescriptor [style=dotted] type_LetDefinition -> type_DefinitionModifiers [style=dotted] type_LetDefinition -> type_Symbol [style=dotted] + type_LetDefinition -> type_TypeSpec [style=dotted] type_LetDefinition -> type_Expression [style=dotted] type_If -> type_Expression [style=dotted] type_If -> type_Block [style=dotted] diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionLevelVisitor.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionLevelVisitor.kt index 9695277..d3aa92c 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionLevelVisitor.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/FunctionLevelVisitor.kt @@ -9,6 +9,9 @@ abstract class FunctionLevelVisitor : NodeVisitor { override fun visitSymbol(node: Symbol): T = throw RuntimeException("Visiting Symbol is not supported.") + override fun visitTypeSpec(node: TypeSpec): T = + throw RuntimeException("Visiting TypeSpec is not supported.") + override fun visitLetDefinition(node: LetDefinition): T { topLevelUsedError("LetDefinition") } diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/ArgumentSpec.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/ArgumentSpec.kt index f567510..d924db7 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/ArgumentSpec.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/ArgumentSpec.kt @@ -6,22 +6,23 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("argumentSpec") -class ArgumentSpec(val symbol: Symbol, val multiple: Boolean = false) : Node() { +class ArgumentSpec(val symbol: Symbol, val typeSpec: TypeSpec?, val multiple: Boolean = false) : Node() { override val type: NodeType = NodeType.ArgumentSpec override fun visitChildren(visitor: NodeVisitor): List = - visitor.visitNodes(symbol) + visitor.visitNodes(symbol, typeSpec) override fun visit(visitor: NodeVisitor): T = visitor.visitArgumentSpec(this) override fun equals(other: Any?): Boolean { if (other !is ArgumentSpec) return false - return other.symbol == symbol && other.multiple == multiple + return other.symbol == symbol && other.typeSpec == typeSpec && other.multiple == multiple } override fun hashCode(): Int { var result = symbol.hashCode() + result = 31 * result + typeSpec.hashCode() result = 31 * result + multiple.hashCode() result = 31 * result + type.hashCode() return result diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/FunctionDefinition.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/FunctionDefinition.kt index 32c1a19..fc83075 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/FunctionDefinition.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/FunctionDefinition.kt @@ -6,24 +6,25 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("functionDefinition") -class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List, val block: Block?, val nativeFunctionDescriptor: NativeFunctionDescriptor?) : Definition() { +class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List, val returnType: TypeSpec?, val block: Block?, val nativeFunctionDescriptor: NativeFunctionDescriptor?) : Definition() { override val type: NodeType = NodeType.FunctionDefinition override fun visitChildren(visitor: NodeVisitor): List = - visitor.visitAll(listOf(symbol), arguments, listOf(block), listOf(nativeFunctionDescriptor)) + visitor.visitAll(listOf(symbol), arguments, listOf(returnType), listOf(block), listOf(nativeFunctionDescriptor)) override fun visit(visitor: NodeVisitor): T = visitor.visitFunctionDefinition(this) override fun equals(other: Any?): Boolean { if (other !is FunctionDefinition) return false - return other.modifiers == modifiers && other.symbol == symbol && other.arguments == arguments && other.block == block && other.nativeFunctionDescriptor == nativeFunctionDescriptor + return other.modifiers == modifiers && other.symbol == symbol && other.arguments == arguments && other.returnType == returnType && other.block == block && other.nativeFunctionDescriptor == nativeFunctionDescriptor } override fun hashCode(): Int { var result = modifiers.hashCode() result = 31 * result + symbol.hashCode() result = 31 * result + arguments.hashCode() + result = 31 * result + returnType.hashCode() result = 31 * result + block.hashCode() result = 31 * result + nativeFunctionDescriptor.hashCode() result = 31 * result + type.hashCode() diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetAssignment.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetAssignment.kt index 46f5b90..635aaae 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetAssignment.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetAssignment.kt @@ -6,23 +6,24 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("letAssignment") -class LetAssignment(val symbol: Symbol, val value: Expression) : Expression() { +class LetAssignment(val symbol: Symbol, val value: Expression, val typeSpec: TypeSpec?) : Expression() { override val type: NodeType = NodeType.LetAssignment override fun visitChildren(visitor: NodeVisitor): List = - visitor.visitNodes(symbol, value) + visitor.visitNodes(symbol, value, typeSpec) override fun visit(visitor: NodeVisitor): T = visitor.visitLetAssignment(this) override fun equals(other: Any?): Boolean { if (other !is LetAssignment) return false - return other.symbol == symbol && other.value == value + return other.symbol == symbol && other.value == value && other.typeSpec == typeSpec } override fun hashCode(): Int { var result = symbol.hashCode() result = 31 * result + value.hashCode() + result = 31 * result + typeSpec.hashCode() result = 31 * result + type.hashCode() return result } diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetDefinition.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetDefinition.kt index a09bb70..cdf7668 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetDefinition.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/LetDefinition.kt @@ -6,23 +6,24 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("letDefinition") -class LetDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val value: Expression) : Definition() { +class LetDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val typeSpec: TypeSpec?, val value: Expression) : Definition() { override val type: NodeType = NodeType.LetDefinition override fun visitChildren(visitor: NodeVisitor): List = - visitor.visitNodes(symbol, value) + visitor.visitNodes(symbol, typeSpec, value) override fun visit(visitor: NodeVisitor): T = visitor.visitLetDefinition(this) override fun equals(other: Any?): Boolean { if (other !is LetDefinition) return false - return other.modifiers == modifiers && other.symbol == symbol && other.value == value + return other.modifiers == modifiers && other.symbol == symbol && other.typeSpec == typeSpec && other.value == value } override fun hashCode(): Int { var result = modifiers.hashCode() result = 31 * result + symbol.hashCode() + result = 31 * result + typeSpec.hashCode() result = 31 * result + value.hashCode() result = 31 * result + type.hashCode() return result diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt index f172721..12e3a87 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt @@ -95,6 +95,9 @@ class NodeCoalescer(val followChildren: Boolean = true, val handler: (Node) -> U override fun visitSymbolReference(node: SymbolReference): Unit = handle(node) + override fun visitTypeSpec(node: TypeSpec): Unit = + handle(node) + override fun visitVarAssignment(node: VarAssignment): Unit = handle(node) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt index 88cc60d..353981a 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt @@ -70,6 +70,8 @@ interface NodeParser { fun parseSymbolReference(): SymbolReference + fun parseTypeSpec(): TypeSpec + fun parseVarAssignment(): VarAssignment fun parseWhile(): While diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt index 40bf2a1..9c8095a 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt @@ -7,6 +7,7 @@ fun NodeParser.parse(type: NodeType): Node = NodeType.Symbol -> parseSymbol() NodeType.Declaration -> parseDeclaration() NodeType.Definition -> parseDefinition() + NodeType.TypeSpec -> parseTypeSpec() NodeType.Block -> parseBlock() NodeType.CompilationUnit -> parseCompilationUnit() NodeType.LetAssignment -> parseLetAssignment() diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt index 157c785..b09f5fe 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt @@ -37,6 +37,7 @@ enum class NodeType(val parent: NodeType? = null) { SuffixOperation(Expression), Symbol(Node), SymbolReference(Expression), + TypeSpec(Node), VarAssignment(Expression), While(Expression) } diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt index caf5ef9..6c772bf 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt @@ -64,6 +64,8 @@ interface NodeVisitor { fun visitSymbolReference(node: SymbolReference): T + fun visitTypeSpec(node: TypeSpec): T + fun visitVarAssignment(node: VarAssignment): T fun visitWhile(node: While): T diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt index 4e98113..466cc99 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt @@ -4,6 +4,7 @@ package gay.pizza.pork.ast.gen fun NodeVisitor.visit(node: Node): T = when (node) { is Symbol -> visitSymbol(node) + is TypeSpec -> visitTypeSpec(node) is Block -> visitBlock(node) is CompilationUnit -> visitCompilationUnit(node) is LetAssignment -> visitLetAssignment(node) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/TypeSpec.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/TypeSpec.kt new file mode 100644 index 0000000..2bfa7ed --- /dev/null +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/TypeSpec.kt @@ -0,0 +1,28 @@ +// GENERATED CODE FROM PORK AST CODEGEN +package gay.pizza.pork.ast.gen + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +@SerialName("typeSpec") +class TypeSpec(val symbol: Symbol) : Node() { + override val type: NodeType = NodeType.TypeSpec + + override fun visitChildren(visitor: NodeVisitor): List = + visitor.visitNodes(symbol) + + override fun visit(visitor: NodeVisitor): T = + visitor.visitTypeSpec(this) + + override fun equals(other: Any?): Boolean { + if (other !is TypeSpec) return false + return other.symbol == symbol + } + + override fun hashCode(): Int { + var result = symbol.hashCode() + result = 31 * result + type.hashCode() + return result + } +} diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/VarAssignment.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/VarAssignment.kt index 7b8e3ad..244cf31 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/VarAssignment.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/VarAssignment.kt @@ -6,23 +6,24 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("varAssignment") -class VarAssignment(val symbol: Symbol, val value: Expression) : Expression() { +class VarAssignment(val symbol: Symbol, val value: Expression, val typeSpec: TypeSpec?) : Expression() { override val type: NodeType = NodeType.VarAssignment override fun visitChildren(visitor: NodeVisitor): List = - visitor.visitNodes(symbol, value) + visitor.visitNodes(symbol, value, typeSpec) override fun visit(visitor: NodeVisitor): T = visitor.visitVarAssignment(this) override fun equals(other: Any?): Boolean { if (other !is VarAssignment) return false - return other.symbol == symbol && other.value == value + return other.symbol == symbol && other.value == value && other.typeSpec == typeSpec } override fun hashCode(): Int { var result = symbol.hashCode() result = 31 * result + value.hashCode() + result = 31 * result + typeSpec.hashCode() result = 31 * result + type.hashCode() return result } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt index 03869be..bd135d9 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -54,8 +54,6 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito override fun visitLongLiteral(node: LongLiteral): Any = node.value - override fun visitSymbol(node: Symbol): Any = None - override fun visitFunctionCall(node: FunctionCall): Any { val arguments = node.arguments.map { it.visit(this) } val functionValue = currentScope.value(node.symbol.id) as CallableFunction diff --git a/examples/fib.pork b/examples/fib.pork index 609d729..af5a33d 100644 --- a/examples/fib.pork +++ b/examples/fib.pork @@ -1,5 +1,5 @@ /* fibonacci sequence */ -func fib(n) { +func fib(n: int32): int32 { if n < 2 { return n } else { @@ -8,6 +8,6 @@ func fib(n) { } export func main() { - let result = fib(28) + let result: int32 = fib(28) println(result) } diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt index 352b2df..7cae9e1 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiNativeProvider.kt @@ -118,7 +118,7 @@ class FfiNativeProvider : ExpandedNativeProvider, NativeProvider { val buffer = HeapInvocationBuffer(context) val useFunctionArguments = functionArgumentSpecs ?: functionArguments.map { - ArgumentSpec(symbol = Symbol(""), multiple = false) + ArgumentSpec(symbol = Symbol(""), typeSpec = null, multiple = false) } for ((index, spec) in useFunctionArguments.withIndex()) { diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt index 0bdb5bf..d56b4bc 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaAutogen.kt @@ -147,11 +147,13 @@ class JavaAutogen(val javaClass: Class<*>) { arguments = parameterNames.map { ArgumentSpec( symbol = Symbol(it), - multiple = false + multiple = false, + typeSpec = null, ) }, nativeFunctionDescriptor = asNative(functionDefinition), - block = null + block = null, + returnType = null, ) private fun asNative(functionDefinition: JavaFunctionDefinition): NativeFunctionDescriptor = diff --git a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt index 0fb7b89..8fff0fd 100644 --- a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt +++ b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt @@ -119,6 +119,10 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor() { checkAndContribute(node.symbol) } + override fun visitTypeSpec(node: TypeSpec) { + checkAndContribute(node.symbol) + } + override fun visitVarAssignment(node: VarAssignment) { internalSymbols.last().add(node.symbol) node.value.visit(this) diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt index d7bb4b5..e30a953 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt @@ -8,7 +8,11 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : ParserBase(source, attribution) { override fun parseArgumentSpec(): ArgumentSpec = produce(NodeType.ArgumentSpec) { val symbol = parseSymbol() - ArgumentSpec(symbol, next(TokenType.DotDotDot)) + var typeSpec: TypeSpec? = null + if (next(TokenType.Colon)) { + typeSpec = parseTypeSpec() + } + ArgumentSpec(symbol, typeSpec = typeSpec, next(TokenType.DotDotDot)) } override fun parseBlock(): Block = expect(NodeType.Block, TokenType.LeftCurly) { @@ -213,7 +217,10 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : parseArgumentSpec() } expect(TokenType.RightParentheses) - + var returnType: TypeSpec? = null + if (next(TokenType.Colon)) { + returnType = parseTypeSpec() + } var native: NativeFunctionDescriptor? = null var block: Block? = null if (peek(TokenType.Native)) { @@ -221,7 +228,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : } else { block = parseBlock() } - FunctionDefinition(modifiers, name, arguments, block, native) + FunctionDefinition(modifiers = modifiers, symbol = name, arguments = arguments, returnType = returnType, block = block, nativeFunctionDescriptor = native) } override fun parseIf(): If = expect(NodeType.If, TokenType.If) { @@ -280,18 +287,26 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : override fun parseLetAssignment(): LetAssignment = expect(NodeType.LetAssignment, TokenType.Let) { val symbol = parseSymbol() + var typeSpec: TypeSpec? = null + if (next(TokenType.Colon)) { + typeSpec = parseTypeSpec() + } expect(TokenType.Equals) val value = parseExpression() - LetAssignment(symbol, value) + LetAssignment(symbol = symbol, typeSpec = typeSpec, value = value) } override fun parseLetDefinition(): LetDefinition = produce(NodeType.LetDefinition) { val definitionModifiers = parseDefinitionModifiers() expect(TokenType.Let) val name = parseSymbol() + var typeSpec: TypeSpec? = null + if (next(TokenType.Colon)) { + typeSpec = parseTypeSpec() + } expect(TokenType.Equals) val value = parseExpression() - LetDefinition(definitionModifiers, name, value) + LetDefinition(modifiers = definitionModifiers, symbol = name, typeSpec = typeSpec, value = value) } override fun parseListLiteral(): ListLiteral = expect(NodeType.ListLiteral, TokenType.LeftBracket) { @@ -375,11 +390,19 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : SymbolReference(parseSymbol()) } + override fun parseTypeSpec(): TypeSpec = produce(NodeType.TypeSpec) { + TypeSpec(parseSymbol()) + } + override fun parseVarAssignment(): VarAssignment = expect(NodeType.VarAssignment, TokenType.Var) { val symbol = parseSymbol() + var typeSpec: TypeSpec? = null + if (next(TokenType.Colon)) { + typeSpec = parseTypeSpec() + } expect(TokenType.Equals) val value = parseExpression() - VarAssignment(symbol, value) + VarAssignment(symbol = symbol, typeSpec = typeSpec, value = value) } override fun parseWhile(): While = expect(NodeType.While, TokenType.While) { diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt index a8b239c..c3abfaa 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt @@ -113,6 +113,10 @@ class Printer(buffer: StringBuilder) : NodeVisitor { override fun visitLetAssignment(node: LetAssignment) { append("let ") visit(node.symbol) + if (node.typeSpec != null) { + append(": ") + visit(node.typeSpec!!) + } append(" = ") visit(node.value) } @@ -121,6 +125,10 @@ class Printer(buffer: StringBuilder) : NodeVisitor { visitDefinitionModifiers(node.modifiers) append("let ") visit(node.symbol) + if (node.typeSpec != null) { + append(": ") + visit(node.typeSpec!!) + } append(" = ") visit(node.value) } @@ -129,9 +137,17 @@ class Printer(buffer: StringBuilder) : NodeVisitor { visit(node.symbol) } + override fun visitTypeSpec(node: TypeSpec) { + visit(node.symbol) + } + override fun visitVarAssignment(node: VarAssignment) { append("var ") visit(node.symbol) + if (node.typeSpec != null) { + append(": ") + visit(node.typeSpec!!) + } append(" = ") visit(node.value) } @@ -209,6 +225,10 @@ class Printer(buffer: StringBuilder) : NodeVisitor { } } append(") ") + if (node.returnType != null) { + append(": ") + visit(node.returnType!!) + } if (node.block != null) { visit(node.block!!) } diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt index 93cd476..46b86d0 100644 --- a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/PorkElementFactory.kt @@ -11,6 +11,7 @@ object PorkElementFactory { fun create(node: ASTNode): PsiElement = when (PorkElementTypes.nodeTypeFor(node.elementType)) { NodeType.Symbol -> SymbolElement(node) + NodeType.TypeSpec -> TypeSpecElement(node) NodeType.Block -> BlockElement(node) NodeType.CompilationUnit -> CompilationUnitElement(node) NodeType.LetAssignment -> LetAssignmentElement(node) diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/TypeSpecElement.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/TypeSpecElement.kt new file mode 100644 index 0000000..a22173d --- /dev/null +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/TypeSpecElement.kt @@ -0,0 +1,15 @@ +// GENERATED CODE FROM PORK AST CODEGEN +package gay.pizza.pork.idea.psi.gen + +import com.intellij.lang.ASTNode +import com.intellij.navigation.ItemPresentation +import gay.pizza.pork.idea.psi.PorkElementHelpers +import javax.swing.Icon + +class TypeSpecElement(node: ASTNode) : PorkElement(node) { + override fun getIcon(flags: Int): Icon? = + PorkElementHelpers.iconOf(this) + + override fun getPresentation(): ItemPresentation? = + PorkElementHelpers.presentationOf(this) +} diff --git a/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt b/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt index db70ebb..57db02b 100644 --- a/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt +++ b/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt @@ -50,6 +50,7 @@ enum class TokenType(vararg val properties: TokenTypeProperty) { Mod(ManyChars("mod"), KeywordFamily), Rem(ManyChars("rem"), KeywordFamily), Comma(SingleChar(',')), + Colon(SingleChar(':')), DotDotDot(ManyChars("...")), DotDot(ManyChars(".."), Promotion('.', DotDotDot)), Dot(SingleChar('.'), Promotion('.', DotDot)),