Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions effekt/shared/src/main/scala/effekt/Lexer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,23 @@ enum TokenKind {
case `-`
case `*`

case `>>`
case `<<`
case `~`
case `--`
case `~>`
case `<~`
case `<|`
case `|>`
case `+=`
case `-=`
case `*=`
case `/=`
case `..`
case `...`
case `^^`
case `^`

// keywords
case `let`
case `true`
Expand Down Expand Up @@ -398,11 +415,17 @@ class Lexer(source: Source) extends Iterator[Token] {
// Comments
case ('/', '*') => advance2With(multilineComment())
case ('/', '/') => advance2With(singlelineComment())
case ('/', '=') => advance2With(TokenKind.`/=`)
case ('/', _) => advanceWith(TokenKind.`/`)

// Shebang
case ('#', '!') => advance2With(shebang())


case ('.', '.') if peekAhead(2) == '.' => advance3With(TokenKind.`...`)
case ('.', '.') => advance2With(TokenKind.`..`)
case ('.', _) => advanceWith(TokenKind.`.`)

// Two-character operators
case ('=', '=') => advance2With(TokenKind.`===`)
case ('=', '>') => advance2With(TokenKind.`=>`)
Expand All @@ -411,29 +434,45 @@ class Lexer(source: Source) extends Iterator[Token] {
case ('!', '=') => advance2With(TokenKind.`!==`)
case ('!', _) => advanceWith(TokenKind.`!`)

case ('^', '^') => advance2With(TokenKind.`^^`)
case ('^', _) => advanceWith(TokenKind.`^`)

case ('~', '>') => advance2With(TokenKind.`~>`)
case ('~', _) => advanceWith(TokenKind.`~`)

case ('<', '<') => advance2With(TokenKind.`<<`)
case ('<', '=') => advance2With(TokenKind.`<=`)
case ('<', '>') => advance2With(TokenKind.`<>`)
case ('<', '{') => advance2With(TokenKind.`<{`)
case ('<', '~') => advance2With(TokenKind.`<~`)
case ('<', '|') => advance2With(TokenKind.`<|`)
case ('<', _) => advanceWith(TokenKind.`<`)

case ('>', '>') => advance2With(TokenKind.`>>`)
case ('>', '=') => advance2With(TokenKind.`>=`)
case ('>', _) => advanceWith(TokenKind.`>`)

case (':', ':') => advance2With(TokenKind.`::`)
case (':', _) => advanceWith(TokenKind.`:`)

case ('|', '|') => advance2With(TokenKind.`||`)
case ('|', '>') => advance2With(TokenKind.`|>`)
case ('|', _) => advanceWith(TokenKind.`|`)

case ('&', '&') => advance2With(TokenKind.`&&`)
case ('&', _) => advanceWith(TokenKind.`&`)

case ('+', '+') => advance2With(TokenKind.`++`)
case ('+', '=') => advance2With(TokenKind.`+=`)
case ('+', _) => advanceWith(TokenKind.`+`)

case ('-', c) if c.isDigit => advanceWith(number(negative = true))
case ('-', '=') => advance2With(TokenKind.`-=`)
case ('-', _) => advanceWith(TokenKind.`-`)

case ('*', '=') => advanceWith(TokenKind.`*=`)
case ('*', _) => advanceWith(TokenKind.`*`)

case ('$', '{') =>
interpolationDepths.push(depthTracker.braces + 1)
depthTracker.braces += 1
Expand Down Expand Up @@ -470,8 +509,6 @@ class Lexer(source: Source) extends Iterator[Token] {
depthTracker.brackets -= 1
advanceWith(TokenKind.`]`)
case (',', _) => advanceWith(TokenKind.`,`)
case ('.', _) => advanceWith(TokenKind.`.`)
case ('*', _) => advanceWith(TokenKind.`*`)

case ('\u0000', _) =>
// EOF reached - provide context about unclosed constructs
Expand Down
91 changes: 71 additions & 20 deletions effekt/shared/src/main/scala/effekt/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -975,10 +975,13 @@ class Parser(positions: Positions, tokens: Seq[Token], source: Source) {
}

def orExpr(): Term = infix(andExpr, `||`)
def andExpr(): Term = infix(eqExpr, `&&`)
def eqExpr(): Term = infix(relExpr, `===`, `!==`)
def relExpr(): Term = infix(addExpr, `<=`, `>=`, `<`, `>`)
def addExpr(): Term = infix(mulExpr, `++`, `+`, `-`)
def andExpr(): Term = infix(pipeExpr, `&&`)
def pipeExpr(): Term = infix(bitOrExpr, `<|`, `|>`)
def bitOrExpr(): Term = infix(bitAndExpr, TokenKind.`|`)
def bitAndExpr(): Term = infix(eqExpr, `&`)
def eqExpr(): Term = infix(rangeExpr, `===`, `!==`, `<=`, `>=`, `<`, `>`)
def rangeExpr(): Term = infix(addExpr, `..`, `...`, TokenKind.`~`, TokenKind.`~>`, TokenKind.`<~`)
def addExpr(): Term = infix(mulExpr, `++`, `--`, `+`, `-`, `<<`, `>>`, `^`, `^^`)
def mulExpr(): Term = infix(callExpr, `*`, `/`)

inline def infix(nonTerminal: () => Term, ops: TokenKind*): Term =
Expand Down Expand Up @@ -1022,15 +1025,36 @@ class Parser(positions: Positions, tokens: Seq[Token], source: Source) {
case `&&` => "infixAnd"
case `===` => "infixEq"
case `!==` => "infixNeq"
case `<` => "infixLt"
case `>` => "infixGt"
case `<` => "infixLt"
case `>` => "infixGt"
case `<=` => "infixLte"
case `>=` => "infixGte"
case `+` => "infixAdd"
case `-` => "infixSub"
case `*` => "infixMul"
case `/` => "infixDiv"
case `+` => "infixAdd"
case `+=` => "infixAdd"
case `-` => "infixSub"
case `-=` => "infixSub"
case `*` => "infixMul"
case `*=` => "infixMul"
case `/` => "infixDiv"
case `/=` => "infixDiv"
case `++` => "infixConcat"
case `>>` => "infixShr"
case `<<` => "infixShl"
case `--` => "infixRemove"

case TokenKind.`~` => "infixTilde"
case TokenKind.`~>` => "infixTildeRight"
case TokenKind.`<~` => "infixTildeLeft"
case TokenKind.`|` => "infixPipe"
case TokenKind.`&` => "infixAmp"

case `<|` => "infixPipeLeft"
case `|>` => "infixPipeRight"
case `..` => "infixDotDot"
case `...` => "infixDotDotDot"
case `^^` => "infixHatHat"
case `^` => "infixHat"

case _ => sys.error(s"Internal compiler error: not a valid operator ${op}")
}

Expand All @@ -1052,18 +1076,32 @@ class Parser(positions: Positions, tokens: Seq[Token], source: Source) {

while (peek(`.`) || isArguments)
peek.kind match {
// member selection (or method call)
// member selection, postfix acess, or method call
// <EXPR>.<NAME>
// | <EXPR>.<NAME>( ... )
case `.` =>
val dot = peek
consume(`.`)
val member = idRef()
// method call
if (isArguments) {
val (targs, vargs, bargs) = arguments()
e = Term.MethodCall(e, member, targs, vargs, bargs, span())
} else {
e = Term.MethodCall(e, member, Nil, Nil, Nil, span())
peek.kind match {
// <EXPR>.[<EXPR>, ...]
case `[` =>
val bracket = peek
val arguments = some(expr, `[`, `,`, `]`)
e = MethodCall(e,
IdRef(Nil, "postfixAccess", Span(source, dot.start, bracket.end, Synthesized)),
Nil, arguments.unspan.map(a => ValueArg.Unnamed(a)), Nil,
Span(source, e.span.from, arguments.span.to, Synthesized)
)

case _ =>
val member = idRef()
// method call
if (isArguments) {
val (targs, vargs, bargs) = arguments()
e = Term.MethodCall(e, member, targs, vargs, bargs, span())
} else {
e = Term.MethodCall(e, member, Nil, Nil, Nil, span())
}
}

// function call
Expand Down Expand Up @@ -1168,7 +1206,20 @@ class Parser(positions: Positions, tokens: Seq[Token], source: Source) {
case _ if isVariable =>
peek(1).kind match {
case _: Str => templateString()
case _ => variable()
case _ =>
val lhs = variable()
peek.kind match {
case `+=` | `-=` | `*=` | `/=` =>
val op = next()
val operand = expr()
val rhs = Call(
IdTarget(IdRef(Nil, opName(op.kind), op.span(source).synthesized)),
Nil, List(ValueArg.Unnamed(lhs), ValueArg.Unnamed(operand)), Nil,
Span(source, lhs.span.from, operand.span.to, Synthesized)
)
Assign(lhs.id, rhs, span())
case _ => lhs
}
}
case _ if isHole => hole()
case _ if isTupleOrGroup => tupleOrGroup()
Expand Down Expand Up @@ -1295,7 +1346,7 @@ class Parser(positions: Positions, tokens: Seq[Token], source: Source) {
private def isUnitLiteral: Boolean = peek(`(`) && peek(1, `)`)

def isVariable: Boolean = isIdRef
def variable(): Term =
def variable(): Term.Var =
nonterminal:
Var(idRef(), span())

Expand Down
2 changes: 2 additions & 0 deletions examples/pos/array_operators.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1
2
29 changes: 29 additions & 0 deletions examples/pos/array_operators.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

def postfixAccess[T](arr: Array[T], index: Int): T = unsafeGet(arr, index)

// access as a function
def example1() = {
val arr = array[Int](10, 1)
println(arr.[2])
}

// access on a capability / object
interface MyRef[T] {
def postfixAccess(index: Int): T
}

def example2() = {
def arr = new MyRef[Int] {
def postfixAccess(index) = 1
};
println(arr.[0] + arr.[1])
}

// multi dimensional access
def example3(arr: Array[Array[Int]]) =
println(arr.[0].[1] + arr.[1].[0])

def main() = {
example1()
example2()
}
2 changes: 2 additions & 0 deletions examples/pos/assign_operators.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
3
1
9 changes: 9 additions & 0 deletions examples/pos/assign_operators.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
def main() = {
var x = 1
var y = 2

x += y
println(x) // 3
y -= 1
println(y) // 1
}
Loading