Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compiler): Fix math ops for u64 [fixes LNG-204] #811

Merged
merged 4 commits into from
Jul 25, 2023
Merged
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
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
Loading