diff --git a/ast/src/main/ast/pork.yml b/ast/src/main/ast/pork.yml index 0947aa9..a33d9ae 100644 --- a/ast/src/main/ast/pork.yml +++ b/ast/src/main/ast/pork.yml @@ -59,13 +59,22 @@ types: type: Expression - name: typeSpec type: TypeSpec? - SetAssignment: + SymbolSetAssignment: parent: Expression values: - name: symbol type: Symbol - name: value type: Expression + IndexedSetAssignment: + parent: Expression + values: + - name: target + type: Expression + - name: index + type: Expression + - name: value + type: Expression InfixOperator: values: - name: token diff --git a/ast/src/main/graph/types.dot b/ast/src/main/graph/types.dot index e7e5023..d00c9d1 100644 --- a/ast/src/main/graph/types.dot +++ b/ast/src/main/graph/types.dot @@ -10,7 +10,8 @@ digraph A { type_CompilationUnit [shape=box,label="CompilationUnit"] type_LetAssignment [shape=box,label="LetAssignment"] type_VarAssignment [shape=box,label="VarAssignment"] - type_SetAssignment [shape=box,label="SetAssignment"] + type_SymbolSetAssignment [shape=box,label="SymbolSetAssignment"] + type_IndexedSetAssignment [shape=box,label="IndexedSetAssignment"] type_InfixOperator [shape=box,label="InfixOperator"] type_InfixOperation [shape=box,label="InfixOperation"] type_BooleanLiteral [shape=box,label="BooleanLiteral"] @@ -57,7 +58,8 @@ digraph A { type_Node -> type_NativeTypeDescriptor type_Expression -> type_LetAssignment type_Expression -> type_VarAssignment - type_Expression -> type_SetAssignment + type_Expression -> type_SymbolSetAssignment + type_Expression -> type_IndexedSetAssignment type_Expression -> type_InfixOperation type_Expression -> type_BooleanLiteral type_Expression -> type_FunctionCall @@ -94,8 +96,9 @@ digraph A { 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_SymbolSetAssignment -> type_Symbol [style=dotted] + type_SymbolSetAssignment -> type_Expression [style=dotted] + type_IndexedSetAssignment -> type_Expression [style=dotted] type_InfixOperation -> type_Expression [style=dotted] type_InfixOperation -> type_InfixOperator [style=dotted] type_FunctionCall -> type_Symbol [style=dotted] diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/IndexedSetAssignment.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/IndexedSetAssignment.kt new file mode 100644 index 0000000..886dcc4 --- /dev/null +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/IndexedSetAssignment.kt @@ -0,0 +1,30 @@ +// GENERATED CODE FROM PORK AST CODEGEN +package gay.pizza.pork.ast.gen + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +@SerialName("indexedSetAssignment") +class IndexedSetAssignment(val target: Expression, val index: Expression, val value: Expression) : Expression() { + override val type: NodeType = NodeType.IndexedSetAssignment + + override fun visitChildren(visitor: NodeVisitor): List = + visitor.visitNodes(target, index, value) + + override fun visit(visitor: NodeVisitor): T = + visitor.visitIndexedSetAssignment(this) + + override fun equals(other: Any?): Boolean { + if (other !is IndexedSetAssignment) return false + return other.target == target && other.index == index && other.value == value + } + + override fun hashCode(): Int { + var result = target.hashCode() + result = 31 * result + index.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 4f1092c..0a925ce 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 @@ -47,6 +47,9 @@ class NodeCoalescer(val followChildren: Boolean = true, val handler: (Node) -> U override fun visitIndexedBy(node: IndexedBy): Unit = handle(node) + override fun visitIndexedSetAssignment(node: IndexedSetAssignment): Unit = + handle(node) + override fun visitInfixOperation(node: InfixOperation): Unit = handle(node) @@ -83,9 +86,6 @@ class NodeCoalescer(val followChildren: Boolean = true, val handler: (Node) -> U override fun visitReturn(node: Return): Unit = handle(node) - override fun visitSetAssignment(node: SetAssignment): Unit = - handle(node) - override fun visitStringLiteral(node: StringLiteral): Unit = handle(node) @@ -98,6 +98,9 @@ class NodeCoalescer(val followChildren: Boolean = true, val handler: (Node) -> U override fun visitSymbolReference(node: SymbolReference): Unit = handle(node) + override fun visitSymbolSetAssignment(node: SymbolSetAssignment): Unit = + handle(node) + override fun visitTypeDefinition(node: TypeDefinition): 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 98dcb80..50b036e 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 @@ -38,6 +38,8 @@ interface NodeParser { fun parseIndexedBy(): IndexedBy + fun parseIndexedSetAssignment(): IndexedSetAssignment + fun parseInfixOperation(): InfixOperation fun parseIntegerLiteral(): IntegerLiteral @@ -62,8 +64,6 @@ interface NodeParser { fun parseReturn(): Return - fun parseSetAssignment(): SetAssignment - fun parseStringLiteral(): StringLiteral fun parseSuffixOperation(): SuffixOperation @@ -72,6 +72,8 @@ interface NodeParser { fun parseSymbolReference(): SymbolReference + fun parseSymbolSetAssignment(): SymbolSetAssignment + fun parseTypeDefinition(): TypeDefinition fun parseTypeSpec(): TypeSpec 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 1df8cbf..a36c0c8 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 @@ -12,7 +12,8 @@ fun NodeParser.parse(type: NodeType): Node = NodeType.CompilationUnit -> parseCompilationUnit() NodeType.LetAssignment -> parseLetAssignment() NodeType.VarAssignment -> parseVarAssignment() - NodeType.SetAssignment -> parseSetAssignment() + NodeType.SymbolSetAssignment -> parseSymbolSetAssignment() + NodeType.IndexedSetAssignment -> parseIndexedSetAssignment() NodeType.InfixOperation -> parseInfixOperation() NodeType.BooleanLiteral -> parseBooleanLiteral() NodeType.FunctionCall -> parseFunctionCall() 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 324ab08..cd9956d 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 @@ -21,6 +21,7 @@ enum class NodeType(val parent: NodeType? = null) { ImportDeclaration(Declaration), ImportPath(Node), IndexedBy(Expression), + IndexedSetAssignment(Expression), InfixOperation(Expression), IntegerLiteral(Expression), LetAssignment(Expression), @@ -33,11 +34,11 @@ enum class NodeType(val parent: NodeType? = null) { Parentheses(Expression), PrefixOperation(Expression), Return(Expression), - SetAssignment(Expression), StringLiteral(Expression), SuffixOperation(Expression), Symbol(Node), SymbolReference(Expression), + SymbolSetAssignment(Expression), TypeDefinition(Definition), TypeSpec(Node), VarAssignment(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 4ed8763..d86ede2 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 @@ -32,6 +32,8 @@ interface NodeVisitor { fun visitIndexedBy(node: IndexedBy): T + fun visitIndexedSetAssignment(node: IndexedSetAssignment): T + fun visitInfixOperation(node: InfixOperation): T fun visitIntegerLiteral(node: IntegerLiteral): T @@ -56,8 +58,6 @@ interface NodeVisitor { fun visitReturn(node: Return): T - fun visitSetAssignment(node: SetAssignment): T - fun visitStringLiteral(node: StringLiteral): T fun visitSuffixOperation(node: SuffixOperation): T @@ -66,6 +66,8 @@ interface NodeVisitor { fun visitSymbolReference(node: SymbolReference): T + fun visitSymbolSetAssignment(node: SymbolSetAssignment): T + fun visitTypeDefinition(node: TypeDefinition): T fun visitTypeSpec(node: TypeSpec): 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 71dce30..d789294 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 @@ -9,7 +9,8 @@ fun NodeVisitor.visit(node: Node): T = is CompilationUnit -> visitCompilationUnit(node) is LetAssignment -> visitLetAssignment(node) is VarAssignment -> visitVarAssignment(node) - is SetAssignment -> visitSetAssignment(node) + is SymbolSetAssignment -> visitSymbolSetAssignment(node) + is IndexedSetAssignment -> visitIndexedSetAssignment(node) is InfixOperation -> visitInfixOperation(node) is BooleanLiteral -> visitBooleanLiteral(node) is FunctionCall -> visitFunctionCall(node) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/SetAssignment.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/SymbolSetAssignment.kt similarity index 69% rename from ast/src/main/kotlin/gay/pizza/pork/ast/gen/SetAssignment.kt rename to ast/src/main/kotlin/gay/pizza/pork/ast/gen/SymbolSetAssignment.kt index 67a30bc..b6e061e 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/SetAssignment.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/SymbolSetAssignment.kt @@ -5,18 +5,18 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -@SerialName("setAssignment") -class SetAssignment(val symbol: Symbol, val value: Expression) : Expression() { - override val type: NodeType = NodeType.SetAssignment +@SerialName("symbolSetAssignment") +class SymbolSetAssignment(val symbol: Symbol, val value: Expression) : Expression() { + override val type: NodeType = NodeType.SymbolSetAssignment override fun visitChildren(visitor: NodeVisitor): List = visitor.visitNodes(symbol, value) override fun visit(visitor: NodeVisitor): T = - visitor.visitSetAssignment(this) + visitor.visitSymbolSetAssignment(this) override fun equals(other: Any?): Boolean { - if (other !is SetAssignment) return false + if (other !is SymbolSetAssignment) return false return other.symbol == symbol && other.value == value } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrIndex.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrIndex.kt index f25d47c..ea53797 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrIndex.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrIndex.kt @@ -3,9 +3,12 @@ package gay.pizza.pork.bir import kotlinx.serialization.Serializable @Serializable -data class IrIndex(var data: IrCodeElement, var index: IrCodeElement) : IrCodeElement() { +data class IrIndex(var data: IrCodeElement, var index: IrCodeElement, var value: IrCodeElement? = null) : IrCodeElement() { override fun crawl(block: (IrElement) -> Unit) { block(data) block(index) + if (value != null) { + block(value!!) + } } } diff --git a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt index 6b7cc2d..1dfd049 100644 --- a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt +++ b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt @@ -40,6 +40,7 @@ enum class Opcode(val id: UByte) { EuclideanModulo(37u), Remainder(38u), Index(39u), + IndexSet(44u), ScopeIn(40u), ScopeOut(41u), ReturnAddress(42u), diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt index bf24a07..50e6e52 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt @@ -228,6 +228,12 @@ class AstIrEmitter( index = visit(node.index) ) + override fun visitIndexedSetAssignment(node: IndexedSetAssignment): IrCodeElement = IrIndex( + data = visit(node.target), + index = visit(node.index), + value = visit(node.value), + ) + override fun visitInfixOperation(node: InfixOperation): IrCodeElement { val op = when (node.op) { InfixOperator.Plus -> IrInfixOp.Add @@ -288,7 +294,7 @@ class AstIrEmitter( override fun visitReturn(node: Return): IrCodeElement = IrReturn(from = self, value = node.value.visit(this)) - override fun visitSetAssignment(node: SetAssignment): IrCodeElement { + override fun visitSymbolSetAssignment(node: SymbolSetAssignment): IrCodeElement { val symbol = lookupLocalVariable(node.symbol) ?: throw CompileError("Unable to find local variable target '${node.symbol.id}'", node) return IrStore(symbol, node.value.visit(this)) diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt index 3ef1617..5601918 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt @@ -248,9 +248,16 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I } override fun visitIrIndex(ir: IrIndex) { + if (ir.value != null) { + visit(ir.value!!) + } visit(ir.index) visit(ir.data) - code.emit(Opcode.Index) + if (ir.value != null) { + code.emit(Opcode.IndexSet) + } else { + code.emit(Opcode.Index) + } } override fun visitIrListSize(ir: IrListSize) { 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 6a93445..3279f81 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -177,7 +177,7 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito return previousValue } - override fun visitSetAssignment(node: SetAssignment): Any { + override fun visitSymbolSetAssignment(node: SymbolSetAssignment): Any { val value = node.value.visit(this) currentScope.set(node.symbol.id, value) return value @@ -399,6 +399,24 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito throw RuntimeException("Failed to index '${value}' by '${index}': Unsupported types used.") } + override fun visitIndexedSetAssignment(node: IndexedSetAssignment): Any { + val value = node.value.visit(this) + val index = node.index.visit(this) + val target = node.target.visit(this) + if (target is MutableList<*> && index is Number) { + @Suppress("UNCHECKED_CAST") + (target as MutableList)[index.toInt()] = value + return None + } + + if (target is Array<*> && index is Number) { + @Suppress("UNCHECKED_CAST") + (target as MutableList)[index.toInt()] = value + return None + } + return value + } + override fun visitNoneLiteral(node: NoneLiteral): Any = None override fun visitContinue(node: Continue): Any = ContinueMarker diff --git a/examples/gameoflife/gameoflife.pork b/examples/gameoflife/gameoflife.pork index 8e91dd4..16e26fc 100644 --- a/examples/gameoflife/gameoflife.pork +++ b/examples/gameoflife/gameoflife.pork @@ -73,8 +73,8 @@ func setCell(cells, swap, x, y, state) { let mask = if swap { 2 } else { 1 } let idx = x + y * gridWidth let value = cells[idx] - if state { listSet(cells, idx, value | mask) } - else { listSet(cells, idx, value & (~mask)) } + if state { cells[idx] = value | mask } + else { cells[idx] = value & (~mask) } } } diff --git a/examples/index.pork b/examples/index.pork index d3ecdea..71218c9 100644 --- a/examples/index.pork +++ b/examples/index.pork @@ -1,4 +1,6 @@ export func main() { let items = [["Hello"], ["Goodbye"]] println(items[0][0]) + items[0][0] = "Goodbye" + println(items[0][0]) } 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 8c67376..9108184 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 @@ -2,6 +2,7 @@ package gay.pizza.pork.frontend.scope import gay.pizza.pork.ast.FunctionLevelVisitor import gay.pizza.pork.ast.gen.* +import gay.pizza.pork.ast.gen.visit class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor() { private val symbols = mutableSetOf() @@ -116,8 +117,13 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor() { node.visitChildren(this) } - override fun visitSetAssignment(node: SetAssignment) { - node.value.visit(this) + override fun visitSymbolSetAssignment(node: SymbolSetAssignment) { + checkAndContribute(node.symbol) + node.visitChildren(this) + } + + override fun visitIndexedSetAssignment(node: IndexedSetAssignment) { + node.visitChildren(this) } override fun visitStringLiteral(node: StringLiteral) { 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 e66b8e6..00abaf5 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt @@ -53,16 +53,6 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : } } - if (expression is SymbolReference && peek(TokenType.Equals)) { - val symbolReference = expression - expression = produce(NodeType.SetAssignment) { - attribution.adopt(expression) - expect(TokenType.Equals) - val value = parseExpression() - SetAssignment(symbolReference.symbol, value) - } - } - while (peek(TokenType.LeftBracket)) { expression = produce(NodeType.IndexedBy) { attribution.adopt(expression) @@ -73,12 +63,33 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : } } + if (expression is SymbolReference && peek(TokenType.Equals)) { + val symbolReference = expression + expression = produce(NodeType.SymbolSetAssignment) { + attribution.adopt(expression) + expect(TokenType.Equals) + val value = parseExpression() + SymbolSetAssignment(symbolReference.symbol, value) + } + } + + if (expression is IndexedBy && peek(TokenType.Equals)) { + val indexedBy = expression + expression = produce(NodeType.IndexedSetAssignment) { + attribution.adopt(indexedBy) + expect(TokenType.Equals) + val value = parseExpression() + IndexedSetAssignment(target = indexedBy.expression, index = indexedBy.index, value = value) + } + } + return if (peek( TokenType.Plus, TokenType.Minus, TokenType.Multiply, TokenType.Divide, TokenType.Ampersand, TokenType.Pipe, TokenType.Caret, TokenType.Equality, TokenType.Inequality, TokenType.Mod, TokenType.Rem, TokenType.Lesser, TokenType.Greater, TokenType.LesserEqual, TokenType.GreaterEqual, TokenType.And, TokenType.Or)) { produce(NodeType.InfixOperation) { + attribution.adopt(expression) val infixToken = next() val infixOperator = ParserHelpers.convertInfixOperator(infixToken) InfixOperation(expression, infixOperator, parseExpression()) @@ -263,6 +274,16 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : IndexedBy(expression, index) } + override fun parseIndexedSetAssignment(): IndexedSetAssignment = produce(NodeType.IndexedSetAssignment) { + val target = parseExpression() + expect(TokenType.LeftBracket) + val index = parseExpression() + expect(TokenType.RightBracket) + expect(TokenType.Equals) + val value = parseExpression() + IndexedSetAssignment(target, index, value) + } + override fun parseInfixOperation(): InfixOperation = produce(NodeType.InfixOperation) { val infixToken = next() val infixOperator = ParserHelpers.convertInfixOperator(infixToken) @@ -363,11 +384,11 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : Return(parseExpression()) } - override fun parseSetAssignment(): SetAssignment = produce(NodeType.SetAssignment) { + override fun parseSymbolSetAssignment(): SymbolSetAssignment = produce(NodeType.SymbolSetAssignment) { val symbol = parseSymbol() expect(TokenType.Equals) val value = parseExpression() - SetAssignment(symbol, value) + SymbolSetAssignment(symbol, value) } override fun parseStringLiteral(): StringLiteral = produce(NodeType.StringLiteral) { 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 3579a1d..e580103 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt @@ -202,7 +202,7 @@ class Printer(buffer: StringBuilder) : NodeVisitor { append(node.op.token) } - override fun visitSetAssignment(node: SetAssignment) { + override fun visitSymbolSetAssignment(node: SymbolSetAssignment) { visit(node.symbol) append(" = ") visit(node.value) @@ -304,6 +304,15 @@ class Printer(buffer: StringBuilder) : NodeVisitor { append("]") } + override fun visitIndexedSetAssignment(node: IndexedSetAssignment) { + visit(node.target) + append("[") + visit(node.index) + append("]") + append(" = ") + visit(node.value) + } + override fun visitCompilationUnit(node: CompilationUnit) { for (declaration in node.declarations) { visit(declaration) diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/IndexedSetAssignmentElement.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/IndexedSetAssignmentElement.kt new file mode 100644 index 0000000..a61c29d --- /dev/null +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/IndexedSetAssignmentElement.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 IndexedSetAssignmentElement(node: ASTNode) : PorkElement(node) { + override fun getIcon(flags: Int): Icon? = + PorkElementHelpers.iconOf(this) + + override fun getPresentation(): ItemPresentation? = + PorkElementHelpers.presentationOf(this) +} 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 6571539..0af4946 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 @@ -16,7 +16,8 @@ object PorkElementFactory { NodeType.CompilationUnit -> CompilationUnitElement(node) NodeType.LetAssignment -> LetAssignmentElement(node) NodeType.VarAssignment -> VarAssignmentElement(node) - NodeType.SetAssignment -> SetAssignmentElement(node) + NodeType.SymbolSetAssignment -> SymbolSetAssignmentElement(node) + NodeType.IndexedSetAssignment -> IndexedSetAssignmentElement(node) NodeType.InfixOperation -> InfixOperationElement(node) NodeType.BooleanLiteral -> BooleanLiteralElement(node) NodeType.FunctionCall -> FunctionCallElement(node) diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/SetAssignmentElement.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/SymbolSetAssignmentElement.kt similarity index 85% rename from support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/SetAssignmentElement.kt rename to support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/SymbolSetAssignmentElement.kt index 66d62ad..aca6e0a 100644 --- a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/SetAssignmentElement.kt +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/gen/SymbolSetAssignmentElement.kt @@ -6,7 +6,7 @@ import com.intellij.navigation.ItemPresentation import gay.pizza.pork.idea.psi.PorkElementHelpers import javax.swing.Icon -class SetAssignmentElement(node: ASTNode) : PorkElement(node) { +class SymbolSetAssignmentElement(node: ASTNode) : PorkElement(node) { override fun getIcon(flags: Int): Icon? = PorkElementHelpers.iconOf(this) diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt index 217b7f4..3a90f04 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/StandardOpHandlers.kt @@ -15,6 +15,7 @@ val StandardOpHandlers: List = listOf( ListSizeOpHandler, IndexOpHandler, + IndexSetOpHandler, AndOpHandler, OrOpHandler, diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/IndexSetOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/IndexSetOpHandler.kt new file mode 100644 index 0000000..b1c2b41 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/IndexSetOpHandler.kt @@ -0,0 +1,15 @@ +package gay.pizza.pork.vm.ops + +import gay.pizza.pork.bytecode.Op +import gay.pizza.pork.bytecode.Opcode +import gay.pizza.pork.vm.InternalMachine +import gay.pizza.pork.vm.OpHandler + +object IndexSetOpHandler : OpHandler(Opcode.IndexSet) { + override fun handle(machine: InternalMachine, op: Op) { + val list = machine.pop>() + val index = machine.pop().toInt() + val value = machine.pop() + list[index] = value + } +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/ListMakeOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/ListMakeOpHandler.kt index 0983429..2b6ab05 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/ListMakeOpHandler.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/ListMakeOpHandler.kt @@ -13,6 +13,6 @@ object ListMakeOpHandler : OpHandler(Opcode.ListMake) { val item = machine.popAnyValue() list.add(item) } - machine.push(list.reversed()) + machine.push(list.reversed().toMutableList()) } }