Skip to content

Commit

Permalink
fix(compiler): Fix math ops for u64 [fixes LNG-204] (#811)
Browse files Browse the repository at this point in the history
  • Loading branch information
InversionSpaces authored Jul 25, 2023
1 parent cb539f1 commit 50ba194
Show file tree
Hide file tree
Showing 24 changed files with 617 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers {

val const = ctx.allValues.get("X")
const.nonEmpty should be(true)
const.get should be(LiteralModel("5", LiteralType.number))
const.get should be(LiteralModel.number(5))

}

Expand Down
71 changes: 71 additions & 0 deletions integration-tests/aqua/examples/math.aqua
Original file line number Diff line number Diff line change
@@ -1,8 +1,79 @@
aqua Math

export test1, test2, testI16, testI32, testI64, testU64

func test1() -> u64:
res = 1 + 2 - 3 * 5 - 2 * 3 / 2 + 5
<- res

func test2() -> u64:
res = 2 ** 2 ** (2 * 2 - 2) + 2 - 3 * 5 - 2 * 3 / 2 + 5 + (4 % 2 - 2)
<- res

func getI8() -> i8:
<- -8

func getI16() -> i16:
<- -16

func getI32() -> i32:
<- -32

func getI64() -> i64:
<- -64

func getU8() -> u8:
<- 8

func getU16() -> u16:
<- 16

func getU32() -> u32:
<- 32

func getU64() -> u64:
<- 64

func testI16(peer: string) -> []i16:
res: *i16

on peer:
res <<- getI16() + getI16()
res <<- getI8() * getU8()
res <<- getI8() % getI16()
res <<- getI16() - getI8()

<- res

func testI32(peer: string) -> []i32:
res: *i32

on peer:
res <<- getI32() + getU16()
res <<- getI16() * getU16()
res <<- getI8() % getU16()
res <<- getI16() - getI32()

<- res

func testI64(peer: string) -> []i64:
res: *i64

on peer:
res <<- getI32() + getU32()
res <<- getI16() * getU32()
res <<- getI64() % getI64()
res <<- getU8() - getI64()

<- res

func testU64(peer: string) -> []u64:
res: *u64

on peer:
res <<- getU32() + getU64()
res <<- getU64() * getU64()
res <<- getU64() % getU16()
res <<- getU8() - getU64()

<- res
26 changes: 25 additions & 1 deletion integration-tests/src/__test__/examples.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
} from '../examples/collectionSugarCall.js';
import {funcsCall} from '../examples/funcsCall.js';
import {nestedDataCall} from '../examples/nestedDataCall.js';
import {mathTest1Call, mathTest2Call} from '../examples/mathCall.js';
import {mathTest1Call, mathTest2Call, mathTestI16Call, mathTestI32Call, mathTestI64Call, mathTestU64Call} from '../examples/mathCall.js';
import {lng58Bug} from '../compiled/examples/closures.js';
import {config, isEphemeral} from '../config.js';
import {bugLng79Call} from "../examples/canonCall.js";
Expand Down Expand Up @@ -275,6 +275,30 @@ describe('Testing examples', () => {
expect(res).toEqual(3);
});

it('math.aqua test I16', async () => {
let res = await mathTestI16Call(relay1.peerId);

expect(res).toEqual([-32, -64, -8, -8]);
});

it('math.aqua test I32', async () => {
let res = await mathTestI32Call(relay1.peerId);

expect(res).toEqual([-16, -256, -8, 16]);
});

it('math.aqua test I64', async () => {
let res = await mathTestI64Call(relay1.peerId);

expect(res).toEqual([0, -512, 0, 72]);
});

it('math.aqua test U64', async () => {
let res = await mathTestU64Call(relay1.peerId);

expect(res).toEqual([96, 4096, 0, -56]);
});

it('multiReturn.aqua', async () => {
let multiReturnResult = await multiReturnCall();
expect(multiReturnResult).toEqual([['some-str', 'random-str', 'some-str'], 5, 'some-str', [1, 2], null, 10]);
Expand Down
18 changes: 17 additions & 1 deletion integration-tests/src/examples/mathCall.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import {test1, test2} from '../compiled/examples/math.js';
import {test1, test2, testI16, testI32, testI64, testU64} from '../compiled/examples/math.js';

export async function mathTest1Call(): Promise<number> {
return await test1();
}

export async function mathTest2Call(): Promise<number> {
return await test2();
}

export async function mathTestI16Call(peer: string): Promise<number[]> {
return await testI16(peer);
}

export async function mathTestI32Call(peer: string): Promise<number[]> {
return await testI32(peer);
}

export async function mathTestI64Call(peer: string): Promise<number[]> {
return await testI64(peer);
}

export async function mathTestU64Call(peer: string): Promise<number[]> {
return await testU64(peer);
}
11 changes: 7 additions & 4 deletions model/raw/src/main/scala/aqua/raw/value/ValueRaw.scala
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ case class LiteralRaw(value: String, baseType: Type) extends ValueRaw {
object LiteralRaw {
def quote(value: String): LiteralRaw = LiteralRaw("\"" + value + "\"", LiteralType.string)

def number(value: Int): LiteralRaw = LiteralRaw(value.toString, LiteralType.number)
def number(value: Int): LiteralRaw = LiteralRaw(value.toString, LiteralType.forInt(value))

val Zero: LiteralRaw = LiteralRaw("0", LiteralType.number)
val Zero: LiteralRaw = number(0)

val True: LiteralRaw = LiteralRaw("true", LiteralType.bool)
val False: LiteralRaw = LiteralRaw("false", LiteralType.bool)
Expand Down Expand Up @@ -162,11 +162,14 @@ case class MakeStructRaw(fields: NonEmptyMap[String, ValueRaw], structType: Stru
copy(fields = fields.map(_.renameVars(map)))
}

case class AbilityRaw(fieldsAndArrows: NonEmptyMap[String, ValueRaw], abilityType: AbilityType) extends ValueRaw {
case class AbilityRaw(fieldsAndArrows: NonEmptyMap[String, ValueRaw], abilityType: AbilityType)
extends ValueRaw {

override def baseType: Type = abilityType

override def map(f: ValueRaw => ValueRaw): ValueRaw = f(copy(fieldsAndArrows = fieldsAndArrows.map(f)))
override def map(f: ValueRaw => ValueRaw): ValueRaw = f(
copy(fieldsAndArrows = fieldsAndArrows.map(f))
)

override def varNames: Set[String] = {
fieldsAndArrows.toSortedMap.values.flatMap(_.varNames).toSet
Expand Down
2 changes: 1 addition & 1 deletion model/src/main/scala/aqua/model/ValueModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ object LiteralModel {

def quote(str: String): LiteralModel = LiteralModel(s"\"$str\"", LiteralType.string)

def number(n: Int): LiteralModel = LiteralModel(n.toString, LiteralType.number)
def number(n: Int): LiteralModel = LiteralModel(n.toString, LiteralType.forInt(n))
}

sealed trait PropertyModel {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,7 @@ object ModelBuilder {
ValueModel.fromRaw(bc.errorHandlingSrvId),
bc.errorFuncName,
CallRes(
ValueModel.lastError :: LiteralModel(
i.toString,
LiteralType.number
) :: Nil,
ValueModel.lastError :: LiteralModel.number(i) :: Nil,
None
),
on
Expand Down
12 changes: 9 additions & 3 deletions parser/src/main/scala/aqua/parser/lexer/ValueToken.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ case class LiteralToken[F[_]: Comonad](valueToken: F[String], ts: LiteralType)

def value: String = valueToken.extract

override def toString: String = s"$value"
override def toString: String = s"$value:$ts"
}

case class CollectionToken[F[_]: Comonad](
Expand Down Expand Up @@ -96,7 +96,8 @@ object CallArrowToken {
Name.p
~ abilities().? ~ comma0(ValueToken.`value`.surroundedBy(`/s*`))
.between(` `.?.with1 *> `(` <* `/s*`, `/s*` *> `)`)
).map { case ((n, ab), args) =>
)
.map { case ((n, ab), args) =>
CallBraces(n, ab.map(_.toList).getOrElse(Nil), args)
}
.withContext(
Expand Down Expand Up @@ -171,6 +172,11 @@ object InfixToken {

def p: P[Unit] = P.string(symbol)

object Op {
val math: List[Op] = List(Pow, Mul, Div, Rem, Add, Sub)
val compare: List[Op] = List(Gt, Gte, Lt, Lte)
}

private def opsParser(ops: List[Op]): P[(Span, Op)] =
P.oneOf(ops.map(op => op.p.lift.map(s => s.as(op))))

Expand Down Expand Up @@ -351,7 +357,7 @@ object ValueToken {
(minus.?.with1 ~ Numbers.nonNegativeIntString).lift.map(fu =>
fu.extract match {
case (Some(_), n) LiteralToken(fu.as(s"-$n"), LiteralType.signed)
case (None, n) LiteralToken(fu.as(n), LiteralType.number)
case (None, n) LiteralToken(fu.as(n), LiteralType.unsigned)
}
)

Expand Down
6 changes: 4 additions & 2 deletions parser/src/test/scala/aqua/AquaSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import aqua.parser.head.{FromExpr, UseFromExpr}
import aqua.parser.lexer.*
import aqua.parser.lexer.Token.LiftToken
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
import aqua.types.LiteralType.{bool, number, string}
import aqua.types.LiteralType.{bool, number, signed, string, unsigned}
import aqua.types.{LiteralType, ScalarType}
import cats.{~>, Id}
import org.scalatest.EitherValues
Expand Down Expand Up @@ -60,7 +60,9 @@ object AquaSpec {
implicit def toVarIndex(name: String, idx: Int): VarToken[Id] =
VarToken[Id](toName(name), IntoIndex[Id](toNumber(idx).unit, Some(toNumber(idx))) :: Nil)
implicit def toLiteral(name: String, t: LiteralType): LiteralToken[Id] = LiteralToken[Id](name, t)
implicit def toNumber(n: Int): LiteralToken[Id] = LiteralToken[Id](n.toString, number)

implicit def toNumber(n: Int): LiteralToken[Id] =
LiteralToken[Id](n.toString, LiteralType.forInt(n))
implicit def toBool(n: Boolean): LiteralToken[Id] = LiteralToken[Id](n.toString, bool)
implicit def toStr(n: String): LiteralToken[Id] = LiteralToken[Id]("\"" + n + "\"", string)

Expand Down
2 changes: 1 addition & 1 deletion parser/src/test/scala/aqua/parser/AbilityIdExprSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class AbilityIdExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
)

parseAbId("Ab 1") should be(
AbilityIdExpr[Id](toNamedType("Ab"), LiteralToken[Id]("1", LiteralType.number))
AbilityIdExpr[Id](toNamedType("Ab"), toNumber(1))
)

parseAbId("Ab a.id") should be(
Expand Down
7 changes: 2 additions & 5 deletions parser/src/test/scala/aqua/parser/AbilityValueExprSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ class AbilityValueExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
import AquaSpec.*

private def parseAndCheckAbility(str: String) = {
val one = LiteralToken[Id]("1", LiteralType.number)

parseData(
str
) should be(
NamedValueToken(
NamedTypeToken[Id]("AbilityA"),
NonEmptyMap.of(
"v1" -> one,
"v1" -> toNumber(1),
"f1" -> VarToken(Name[Id]("input"), IntoField[Id]("arrow") :: Nil)
)
)
Expand All @@ -36,8 +34,7 @@ class AbilityValueExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
}

"multiline line struct value" should "be parsed" in {
parseAndCheckAbility(
"""AbilityA(v1 = 1, f1 = input.arrow)""".stripMargin)
parseAndCheckAbility("""AbilityA(v1 = 1, f1 = input.arrow)""".stripMargin)
}

}
2 changes: 1 addition & 1 deletion parser/src/test/scala/aqua/parser/InfixTokenSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class InfixTokenSpec extends AnyFlatSpec with Matchers with AquaSpec {

import AquaSpec._

private def literal(n: Int): ValueToken[Id] = LiteralToken[Id](n.toString, LiteralType.number)
private def literal(n: Int): ValueToken[Id] = toNumber(n)

private def infixToken(left: ValueToken[Id], right: ValueToken[Id], op: Op) =
InfixToken[Id](left, right, op)
Expand Down
Loading

0 comments on commit 50ba194

Please sign in to comment.