Skip to content

Commit

Permalink
Merge pull request #353 from alephium/mut_binding
Browse files Browse the repository at this point in the history
Mutable binding
  • Loading branch information
simerplaha authored Jan 14, 2025
2 parents c3ccf99 + b0f8717 commit d4ae8a6
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ object Demo extends App {
| while(cache.getValue() == objectB.read().value) {
| // do something
| }
|
| // mutable binding
| let (a, mut b, _) = (1, 2, 3)
| }
|
| 🚀
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ private object ExpressionParser {
ForLoopParser.parseOrFail |
WhileLoopParser.parseOrFail |
VariableDeclarationParser.parseOrFail |
MutableBindingParser.parseOrFail |
TypeAssignmentParser.parseOrFail |
BlockParser.clause(required = false) |
ReferenceCallParser.parseOrFail |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.alephium.ralph.lsp.access.compiler.parser.soft

import fastparse._
import fastparse.NoWhitespace.noWhitespaceImplicit
import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range
import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token}

private object MutableBindingParser {

/** Syntax: mut [identifier] */
def parseOrFail[Unknown: P]: P[SoftAST.MutableBinding] =
P {
Index ~
TokenParser.parseOrFail(Token.Mut) ~
SpaceParser.parseOrFail ~
IdentifierParser.parseOrFail ~
Index
} map {
case (from, mut, space, identifier, to) =>
SoftAST.MutableBinding(
index = range(from, to),
mut = mut,
space = space,
identifier = identifier
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,14 @@ object SoftAST {
assignment: Assignment)
extends ExpressionAST

/** Syntax: mut [identifier] */
case class MutableBinding(
index: SourceIndex,
mut: TokenDocumented[Token.Mut.type],
space: Space,
identifier: Identifier)
extends ExpressionAST

case class Annotation(
index: SourceIndex,
at: TokenDocumented[Token.At.type],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2024 The Alephium Authors
// This file is part of the alephium project.
//
// The library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the library. If not, see http://www.gnu.org/licenses/.

package org.alephium.ralph.lsp.access.compiler.parser.soft

import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._
import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST
import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._
import org.alephium.ralph.lsp.access.util.TestCodeUtil._
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.OptionValues._

class MutableBindingSpec extends AnyWordSpec with Matchers {

"succeed" when {
"an identifier is set a mut" in {
val annotation =
parseMutableBinding("mut variable")

annotation shouldBe
SoftAST.MutableBinding(
index = indexOf(">>mut variable<<"),
mut = Mut(indexOf(">>mut<< variable")),
space = SpaceOne(indexOf("mut>> <<variable")),
identifier = Identifier(indexOf("mut >>variable<<"), "variable")
)
}

"an identifier in a tuple is set a mut" in {
val body =
parseSoft("(a, b, mut variable)")

body.parts should have size 1
val tuple = body.parts.head.part.asInstanceOf[SoftAST.Tuple]

tuple.headExpression shouldBe defined
tuple.tailExpressions should have size 2 // there are two tail expressions
val lastExpression = tuple.tailExpressions.last.expression.asInstanceOf[SoftAST.MutableBinding] // test the last expression i.e. `mut variable`

lastExpression shouldBe
SoftAST.MutableBinding(
index = indexOf("(a, b, >>mut variable<<)"),
mut = Mut(indexOf("(a, b, >>mut<< variable)")),
space = SpaceOne(indexOf("(a, b, mut>> <<variable)")),
identifier = Identifier(indexOf("(a, b, mut >>variable<<)"), "variable")
)
}

"the binding is documented" when {
"tuple" in {
val body =
parseSoft {
"""(
|a,
|b,
|// documentation line 1
|// documentation line 2
|mut variable
|)
|""".stripMargin
}

body.parts should have size 1
val tuple = body.parts.head.part.asInstanceOf[SoftAST.Tuple]

tuple.headExpression shouldBe defined
tuple.tailExpressions should have size 2 // there are two tail expressions
val lastExpression = tuple.tailExpressions.last.expression.asInstanceOf[SoftAST.MutableBinding] // test the last expression i.e. `mut variable`

lastExpression.mut.documentation.value.toCode() shouldBe
"""// documentation line 1
|// documentation line 2
|""".stripMargin
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ object TestParser {
def parseAssignment(code: String): SoftAST.Assignment =
runSoftParser(AssignmentParser.parseOrFail(_))(code)

def parseMutableBinding(code: String): SoftAST.MutableBinding =
runSoftParser(MutableBindingParser.parseOrFail(_))(code)

def parseTemplate(code: String): SoftAST.Template =
runSoftParser(TemplateParser.parseOrFail(_))(code)

Expand Down

0 comments on commit d4ae8a6

Please sign in to comment.