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

Add support for pow (^) #16

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong license header.

package com.oracle.truffle.sl.nodes.expression;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.sl.nodes.SLBinaryNode;
import java.math.BigDecimal;
import java.math.BigInteger;

/**
* Performs the "^" operation - returns the value of the first argument
* raised to the power of the second argument.
*/
@NodeInfo(shortName = "^")
public abstract class SLPowNode extends SLBinaryNode {

private final BranchProfile bigNumbers = BranchProfile.create();


@Specialization(rewriteOn = ArithmeticException.class)
protected long pow(long left, long right) {
double pow = Math.pow(left, right);
if (pow > Long.MAX_VALUE) {
bigNumbers.enter();
throw new ArithmeticException();
}
return (long) pow;
}

@Specialization
@CompilerDirectives.TruffleBoundary
protected BigInteger pow(BigInteger left, BigInteger right) {
return new BigDecimal(Math.pow(left.doubleValue(), right.doubleValue())).toBigIntegerExact();
}

}
51 changes: 27 additions & 24 deletions src/main/java/com/oracle/truffle/sl/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class Parser {
public static final int _identifier = 1;
public static final int _stringLiteral = 2;
public static final int _numericLiteral = 3;
public static final int maxT = 34;
public static final int maxT = 35;

static final boolean _T = true;
static final boolean _x = false;
Expand Down Expand Up @@ -227,7 +227,7 @@ SLStatementNode Statement(boolean inLoop) {
Expect(11);
break;
}
default: SynErr(35); break;
default: SynErr(36); break;
}
return result;
}
Expand Down Expand Up @@ -354,9 +354,11 @@ SLExpressionNode Arithmetic() {
SLExpressionNode Term() {
SLExpressionNode result;
result = Factor();
while (la.kind == 28 || la.kind == 29) {
while (la.kind == 28 || la.kind == 29 || la.kind == 30) {
if (la.kind == 28) {
Get();
} else if (la.kind == 29) {
Get();
} else {
Get();
}
Expand All @@ -377,7 +379,7 @@ SLExpressionNode Factor() {
result = MemberExpression(null, null, assignmentName);
} else if (StartOf(5)) {
result = factory.createRead(assignmentName);
} else SynErr(36);
} else SynErr(37);
} else if (la.kind == 2) {
Get();
result = factory.createStringLiteral(t, true);
Expand All @@ -392,7 +394,7 @@ SLExpressionNode Factor() {
Expect(7);
int length = (t.charPos + t.val.length()) - start;
result = factory.createParenExpression(expr, start, length);
} else SynErr(37);
} else SynErr(38);
return result;
}

Expand Down Expand Up @@ -420,7 +422,7 @@ SLExpressionNode MemberExpression(SLExpressionNode r, SLExpressionNode assignme
Expect(7);
Token finalToken = t;
result = factory.createCall(receiver, parameters, finalToken);
} else if (la.kind == 30) {
} else if (la.kind == 31) {
Get();
SLExpressionNode value = Expression();
if (assignmentName == null) {
Expand All @@ -430,23 +432,23 @@ SLExpressionNode MemberExpression(SLExpressionNode r, SLExpressionNode assignme
} else {
result = factory.createWriteProperty(assignmentReceiver, assignmentName, value);
}
} else if (la.kind == 31) {
} else if (la.kind == 32) {
Get();
if (receiver == null) {
receiver = factory.createRead(assignmentName);
}
Expect(1);
nestedAssignmentName = factory.createStringLiteral(t, false);
result = factory.createReadProperty(receiver, nestedAssignmentName);
} else if (la.kind == 32) {
} else if (la.kind == 33) {
Get();
if (receiver == null) {
receiver = factory.createRead(assignmentName);
}
nestedAssignmentName = Expression();
result = factory.createReadProperty(receiver, nestedAssignmentName);
Expect(33);
} else SynErr(38);
Expect(34);
} else SynErr(39);
if (StartOf(4)) {
result = MemberExpression(result, receiver, nestedAssignmentName);
}
Expand All @@ -465,12 +467,12 @@ public void Parse() {
}

private static final boolean[][] set = {
{_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x},
{_x,_T,_T,_T, _x,_T,_x,_x, _x,_x,_T,_x, _T,_T,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x},
{_x,_T,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x},
{_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x},
{_x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_x,_x,_x},
{_x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x,_x}
{_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x},
{_x,_T,_T,_T, _x,_T,_x,_x, _x,_x,_T,_x, _T,_T,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x},
{_x,_T,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x},
{_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x},
{_x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x},
{_x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x}

};

Expand Down Expand Up @@ -544,15 +546,16 @@ public void SynErr(int line, int col, int n) {
case 27: s = "\"-\" expected"; break;
case 28: s = "\"*\" expected"; break;
case 29: s = "\"/\" expected"; break;
case 30: s = "\"=\" expected"; break;
case 31: s = "\".\" expected"; break;
case 32: s = "\"[\" expected"; break;
case 33: s = "\"]\" expected"; break;
case 34: s = "??? expected"; break;
case 35: s = "invalid Statement"; break;
case 36: s = "invalid Factor"; break;
case 30: s = "\"^\" expected"; break;
case 31: s = "\"=\" expected"; break;
case 32: s = "\".\" expected"; break;
case 33: s = "\"[\" expected"; break;
case 34: s = "\"]\" expected"; break;
case 35: s = "??? expected"; break;
case 36: s = "invalid Statement"; break;
case 37: s = "invalid Factor"; break;
case 38: s = "invalid MemberExpression"; break;
case 38: s = "invalid Factor"; break;
case 39: s = "invalid MemberExpression"; break;
default:
s = "error " + n;
break;
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/oracle/truffle/sl/parser/SLNodeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import com.oracle.truffle.sl.nodes.expression.SLLongLiteralNode;
import com.oracle.truffle.sl.nodes.expression.SLMulNodeGen;
import com.oracle.truffle.sl.nodes.expression.SLParenExpressionNode;
import com.oracle.truffle.sl.nodes.expression.SLPowNodeGen;
import com.oracle.truffle.sl.nodes.expression.SLStringLiteralNode;
import com.oracle.truffle.sl.nodes.expression.SLSubNodeGen;
import com.oracle.truffle.sl.nodes.local.SLReadArgumentNode;
Expand Down Expand Up @@ -351,6 +352,9 @@ public SLExpressionNode createBinary(Token opToken, SLExpressionNode leftNode, S
case "||":
result = SLLogicalOrNodeGen.create(leftNode, rightNode);
break;
case "^":
result = SLPowNodeGen.create(leftNode, rightNode);
break;
default:
throw new RuntimeException("unexpected operation: " + opToken.val);
}
Expand Down
29 changes: 16 additions & 13 deletions src/main/java/com/oracle/truffle/sl/parser/Scanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ public class Scanner {

static final char EOL = '\n';
static final int eofSym = 0;
static final int maxT = 34;
static final int noSym = 34;
static final int maxT = 35;
static final int noSym = 35;


public Buffer buffer; // scanner buffer
Expand Down Expand Up @@ -366,17 +366,18 @@ public class Scanner {
start.set(59, 11);
start.set(124, 12);
start.set(38, 14);
start.set(60, 28);
start.set(62, 29);
start.set(61, 30);
start.set(60, 29);
start.set(62, 30);
start.set(61, 31);
start.set(33, 19);
start.set(43, 21);
start.set(45, 22);
start.set(42, 23);
start.set(47, 24);
start.set(46, 25);
start.set(91, 26);
start.set(93, 27);
start.set(94, 25);
start.set(46, 26);
start.set(91, 27);
start.set(93, 28);
start.set(Buffer.EOF, -1);
literals.put("function", new Integer(4));
literals.put("break", new Integer(10));
Expand Down Expand Up @@ -597,23 +598,25 @@ Token NextToken() {
case 24:
{t.kind = 29; break loop;}
case 25:
{t.kind = 31; break loop;}
{t.kind = 30; break loop;}
case 26:
{t.kind = 32; break loop;}
case 27:
{t.kind = 33; break loop;}
case 28:
{t.kind = 34; break loop;}
case 29:
recEnd = pos; recKind = 20;
if (ch == '=') {AddCh(); state = 16; break;}
else {t.kind = 20; break loop;}
case 29:
case 30:
recEnd = pos; recKind = 22;
if (ch == '=') {AddCh(); state = 17; break;}
else {t.kind = 22; break loop;}
case 30:
recEnd = pos; recKind = 30;
case 31:
recEnd = pos; recKind = 31;
if (ch == '=') {AddCh(); state = 18; break;}
else {t.kind = 30; break loop;}
else {t.kind = 31; break loop;}

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ Term<out SLExpressionNode result>
=
Factor<out result>
{
("*" | "/") (. Token op = t; .)
("*" | "/" | "^") (. Token op = t; .)
Factor<out SLExpressionNode right> (. result = factory.createBinary(op, result, right); .)
}
.
Expand Down
76 changes: 76 additions & 0 deletions src/test/java/com/oracle/truffle/sl/test/SLPowTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.oracle.truffle.sl.test;

import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.vm.PolyglotEngine;
import java.math.BigDecimal;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class SLPowTest {

private PolyglotEngine engine;
private PolyglotEngine.Value pow;

@Before
public void initEngine() throws Exception {
engine = PolyglotEngine.newBuilder().build();
engine.eval(
Source.newBuilder("\n"
+ "function pow(a, b) {\n"
+ " return a ^ b;\n"
+ "}\n").
name("pow.sl").
mimeType("application/x-sl").
build()
);
pow = engine.findGlobalSymbol("pow");
}

@After
public void dispose() {
engine.dispose();
}

@Test
public void powOf2And2() throws Exception {
Number ret = pow.execute(2, 2).as(Number.class);
assertEquals(4, ret.intValue());
}

@Test
public void pow2And3() throws Exception {
Number ret = pow.execute(2, 3).as(Number.class);
assertEquals(8, ret.intValue());
}

@Test
public void powBigIntegers() throws Exception {
Number ret = pow.execute(Long.MAX_VALUE, 2).as(Number.class);
assertEquals(new BigDecimal(Math.pow(Long.MAX_VALUE, 2)).toBigIntegerExact(), ret);
}

@Test
public void pow2AndString() throws Exception {
Exception exc = null;
try {
pow.execute(2, "test");
Assert.fail("should not get here");
} catch (RuntimeException ex) {
Throwable cause = ex.getCause();
Assert.assertTrue(cause.getClass().getName(), cause instanceof UnsupportedTypeException);
exc = ex;
}
Assert.assertNotNull(exc);
}

}
9 changes: 9 additions & 0 deletions tests/Pow.sl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function main() {
println(2 ^ 2);
println(2 ^ 3);
println(2 ^ 2 ^ 2);
println(3 + 2 ^ 2);
println(6465467984651316454646 ^ 4);
//println(2 ^ "test");
//println(6465467984651316454646 ^ "test");
}