Skip to content
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 @@ -91,7 +91,7 @@ multiplicationExpression
;

unaryExpression
: ('-' | '!') unaryExpression
: ('-' | '!' | '#') unaryExpression
| postfixExpression
;

Expand Down Expand Up @@ -183,4 +183,4 @@ LINE_COMMENT
;


ANY: . ;
ANY: . ;
1 change: 1 addition & 0 deletions docs/ez-lang.rst
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ Following table describes the available operators by their precedence (low to hi
| ``%`` | | |
+------------+-----------------+----------+
| ``-`` | negate | Unary |
| ``#`` | array length | Unary |
| ``!`` | | |
+------------+-----------------+----------+
| ``(...)``, | function call, | Postfix |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ public Token scan() {
case ',':
case '.':
case '%':
case '#':
case '+':
case '*':
case ';':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class TestLexer {
public void testLexer() {
String src = """
// A comment
Ident=,>=<>>=!=!1.5{0}11()[]+-*/ //Another comment
Ident=,>=<>>=!=!1.5{0}11()[]+-*/# //Another comment
""";
Lexer lexer = new Lexer(src);
Token[] expected = new Token[]{
Expand All @@ -37,7 +37,8 @@ public void testLexer() {
Token.newPunct("+", 0),
Token.newPunct("-", 0),
Token.newPunct("*", 0),
Token.newPunct("/", 0)
Token.newPunct("/", 0),
Token.newPunct("#", 0)
};

List<Token> tokens = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,11 @@ private static EZType operandType(Operand operand) {
}

private static boolean evalUnary(LatticeElement cell, LatticeElement input, String unOp, EZType resultType) {
if (unOp.equals("#")) {
if (input.kind == F_TOP || input.kind == F_REF_TOP)
return false;
return cell.meetWithTypeBottom(resultType);
}
if (input.isIntegerConstant()) {
long value = input.kind == F_INT_ZERO ? 0 : input.intValue;
if (unOp.equals("-"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ else if (arg instanceof Operand.NullConstantOperand) {
else if (unaryValue instanceof Value.FloatValue floatValue && unaryInst.unop.equals("-")) {
execStack.stack[base + unaryInst.result().frameSlot()] = new Value.FloatValue(-floatValue.value);
}
else if (unaryValue instanceof Value.ArrayValue arrayValue && unaryInst.unop.equals("#")) {
execStack.stack[base + unaryInst.result().frameSlot()] = new Value.IntegerValue(arrayValue.values.size());
}
else
throw new IllegalStateException("Unexpected unary operand: " + unaryOperand);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1031,4 +1031,18 @@ func main()->Int
integerValue.value == 1);
}

@Test
public void testArrayLengthUnaryOperator() {
String src = """
func foo()->Int {
var a = new [Int] {1,2,3,4}
var b = new [Int] {len=0,value=0}
return #a + #b
}
""";
var value = compileAndRun(src, "foo");
Assert.assertNotNull(value);
Assert.assertTrue(value instanceof Value.IntegerValue integerValue
&& integerValue.value == 4);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@ private AST.Expr parseMultiplication(Lexer lexer) {

private AST.Expr parseUnary(Lexer lexer) {
if (isToken(currentToken, "-")
|| isToken(currentToken, "!")) {
|| isToken(currentToken, "!")
|| isToken(currentToken, "#")) {
var tok = currentToken;
nextToken(lexer);
return new AST.UnaryExpr(tok, parseUnary(lexer), tok.lineNumber);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ else if (arg instanceof Operand.NullConstantOperand) {
else if (unaryValue instanceof Value.FloatValue floatValue && unaryInst.unop.equals("-")) {
execStack.stack[base + unaryInst.result().frameSlot()] = new Value.FloatValue(-floatValue.value);
}
else if (unaryValue instanceof Value.ArrayValue arrayValue && unaryInst.unop.equals("#")) {
execStack.stack[base + unaryInst.result().frameSlot()] = new Value.IntegerValue(arrayValue.values.size());
}
else
throw new IllegalStateException("Unexpected unary operand: " + unaryOperand);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,4 +558,18 @@ func foo()->Float {
Assert.assertTrue(value instanceof Value.FloatValue floatValue
&& Math.abs(floatValue.value - 3.5) < 0.000001);
}
@Test
public void testArrayLengthUnaryOperator() {
String src = """
func foo()->Int {
var a = new [Int] {1,2,3}
var b = new [Int] {len=0,value=0}
return #a + #b
}
""";
var value = compileAndRun(src, "foo");
Assert.assertNotNull(value);
Assert.assertTrue(value instanceof Value.IntegerValue integerValue
&& integerValue.value == 3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,25 @@ private Node compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) {
return objPtr;
}

// # operator
private Node compileArrayLengthExpr(AST.Expr arrayExpr, int lineNumber) {
Node objPtr = compileExpr(arrayExpr).keep();
if( !(objPtr._type instanceof TypeMemPtr ptr) ) {
throw new CompilerException("Unexpected type " + objPtr._type.str(), lineNumber);
}
String name = "#";
TypeStruct base = ptr._obj;
int fidx = base.find(name);
if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'", lineNumber);
Field f = base._fields[fidx];
Node off = con(base.offset(fidx)).keep();
Node load = new LoadNode(name, f._alias, f._type, memAlias(f._alias), objPtr, off);
load = peep(load);
objPtr.unkeep();
off.unkeep();
return load;
}

private Node compileArrayIndexExpr(AST.ArrayLoadExpr arrayLoadExpr) {
Node objPtr = compileExpr(arrayLoadExpr.array).keep();
// Sanity check expr for being a reference
Expand Down Expand Up @@ -531,12 +550,23 @@ private Node compileInitExpr(AST.InitExpr initExpr) {
return objPtr.unkeep();
}

private Node newArray(TypeStruct ary, Node len) {
private Node newArray(TypeStruct ary, Node arrayLen) {
int base = ary.aryBase ();
int scale= ary.aryScale();
Node size = peep(new AddNode(con(base),peep(new ShlNode(len.keep(),con(scale)))));
return newStruct(ary,size);
int scale = ary.aryScale();
// array size = base + len << scale
Node size = peep(new AddNode(con(base),peep(new ShlNode(arrayLen.keep(),con(scale)))));
Node ptr = newStruct(ary,size).keep();
// arrays are structs with two fields
// first field is length
// second field is [] data
Field[] fs = ary._fields;
// store length as int32
Node mem = memAlias(fs[0]._alias);
Node st = new StoreNode(fs[0]._fname,fs[0]._alias,fs[0]._type,mem,ptr,con(ary.offset(0)),arrayLen.unkeep(),true).peephole();
memAlias(fs[0]._alias,st);
return ptr.unkeep();
}

/**
* Return a NewNode initialized memory.
* @param obj is the declared type, with GLB fields
Expand Down Expand Up @@ -586,6 +616,7 @@ private Node compileUnaryExpr(AST.UnaryExpr unaryExpr) {
}
// Maybe below we should explicitly set Int
case "!": return peep(new NotNode(compileExpr(unaryExpr.expr)));
case "#": return compileArrayLengthExpr(unaryExpr.expr, unaryExpr.lineNumber);
default: throw new CompilerException("Invalid unary op", unaryExpr.lineNumber);
}
}
Expand Down
3 changes: 3 additions & 0 deletions seaofnodes/src/test/cases/array/array.ez
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func foo()->Int {
return #new [Int]{42,84}
}
21 changes: 21 additions & 0 deletions seaofnodes/src/test/cases/array/array.ez_ir
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
START: [[ ]]
4 Start ____ ____ ____ [[ 7 18 3 ]] [ Ctrl, #TOP, int]

L3: [[ START ]]
3 foo ____ 4 [[ 6 17 11 10 14 8 13 5 16 2 ]] Ctrl
6 $mem 3 7 [[ 5 10 10 ]] #BOT
17 $rpc 3 18 [[ 2 ]] $[ALL]
11 #24 3 [[ 10 ]] 24
10 new_ary 3 11 6 6 [[ 9 12 15 ]] [ Ctrl, *![int], #2:u32, #3:int]
9 $2 10 [[ 8 ]] #2:u32
12 [int] 10 [[ 8 14 13 ]] *[int]
15 $3 10 [[ 14 ]] #3:int
14 st8 3 15 12 ____ ____ [[ 13 ]] #3:int
13 st8 3 14 12 ____ ____ [[ 5 ]] #3:int
8 st4 3 9 12 ____ ____ [[ 5 ]] #2:u32
16 #2 3 [[ 2 ]] 2
5 ALLMEM 3 6 8 13 [[ 2 ]] #BOT
2 Return 3 5 16 17 [[ 1 ]] [ Ctrl, #BOT, 2]

L1: [[ ]]
1 Stop 2 [[ ]] Bot
15 changes: 15 additions & 0 deletions seaofnodes/src/test/cases/array/array.ez_out
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---foo { -> int #0}---------------------------
0000 4883EC08 subi rsp -= #8
0004 BE18000000 ldi rsi = #24
0009 BF01000000 alloc ldi rcx = #1
000E E800000000 call #calloc
0013 48C740082A st8 [rax+8],#42
0018 000000
001B C700020000 st4 [rax],#2
0020 00
0021 48C7401054 st8 [rax+16],#84
0026 000000
0029 B802000000 ldi rax = #2
002E 4883C408C3 addi rsp += #8
0033 ret
---{ -> int #0}---------------------------
6 changes: 6 additions & 0 deletions seaofnodes/src/test/cases/array/array.smp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var foo = {->
var a = new int[2];
a[0] = 42;
a[1] = 84;
return a#;
};
21 changes: 21 additions & 0 deletions seaofnodes/src/test/cases/array/array.smp_ir
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
START: [[ ]]
4 Start ____ ____ ____ [[ 7 18 3 ]] [ Ctrl, #TOP, int]

L3: [[ START ]]
3 foo ____ 4 [[ 6 17 11 10 14 8 13 5 16 2 ]] Ctrl
6 $mem 3 7 [[ 5 10 10 ]] #BOT
17 $rpc 3 18 [[ 2 ]] $[ALL]
11 #24 3 [[ 10 ]] 24
10 new_ary 3 11 6 6 [[ 9 12 15 ]] [ Ctrl, *![int], #2:u32, #3:int]
9 $2 10 [[ 8 ]] #2:u32
12 [int] 10 [[ 8 14 13 ]] *[int]
15 $3 10 [[ 14 ]] #3:int
14 st8 3 15 12 ____ ____ [[ 13 ]] #3:int
13 st8 3 14 12 ____ ____ [[ 5 ]] #3:int
8 st4 3 9 12 ____ ____ [[ 5 ]] #2:u32
16 #2 3 [[ 2 ]] 2
5 ALLMEM 3 6 8 13 [[ 2 ]] #BOT
2 Return 3 5 16 17 [[ 1 ]] [ Ctrl, #BOT, 2]

L1: [[ ]]
1 Stop 2 [[ ]] Bot
15 changes: 15 additions & 0 deletions seaofnodes/src/test/cases/array/array.smp_out
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---foo { -> 2 #0}---------------------------
0000 4883EC08 subi rsp -= #8
0004 BE18000000 ldi rsi = #24
0009 BF01000000 alloc ldi rcx = #1
000E E800000000 call #calloc
0013 48C740082A st8 [rax+8],#42
0018 000000
001B C700020000 st4 [rax],#2
0020 00
0021 48C7401054 st8 [rax+16],#84
0026 000000
0029 B802000000 ldi rax = #2
002E 4883C408C3 addi rsp += #8
0033 ret
---{ -> 2 #0}---------------------------
6 changes: 6 additions & 0 deletions seaofnodes/src/test/cases/array2/array.ez
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
func foo()->[Float] {
return new [Float]{4.2,8.4}
}
func bar()->Int {
return #foo()
}
38 changes: 38 additions & 0 deletions seaofnodes/src/test/cases/array2/array.ez_ir
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
START: [[ ]]
4 Start ____ ____ ____ [[ 7 19 24 3 ]] [ Ctrl, #TOP, int]

L3: [[ START ]]
3 foo ____ 4 [[ 6 18 11 16 17 10 14 13 8 5 2 ]] Ctrl
6 $mem 3 7 [[ 5 10 10 ]] #BOT
18 $rpc 3 19 [[ 2 ]] $[ALL]
16 #4.2 3 [[ 14 ]] 4.2
11 #24 3 [[ 10 ]] 24
17 #8.4 3 [[ 13 ]] 8.4
14 st8 3 15 12 ____ 16 [[ 13 ]] #5:flt
13 st8 3 14 12 ____ 17 [[ 5 ]] #5:flt
10 new_ary 3 11 6 6 [[ 9 12 15 ]] [ Ctrl, *![flt], #4:u32, #5:flt]
9 $4 10 [[ 8 ]] #4:u32
12 [flt] 10 [[ 8 14 13 2 ]] *[flt]
15 $5 10 [[ 14 ]] #5:flt
8 st4 3 9 12 ____ ____ [[ 5 ]] #4:u32
5 ALLMEM 3 6 ____ ____ 8 13 [[ 2 ]] #BOT
2 Return 3 5 12 18 [[ 1 ]] [ Ctrl, #BOT, *![flt]]

L24: [[ START ]]
24 bar ____ 4 [[ 25 29 23 ]] Ctrl
25 $mem 24 7 [[ 23 ]] #BOT
29 $rpc 24 19 [[ 20 ]] $[ALL]
23 call 24 25 [[ 22 ]] Ctrl

L22: [[ L24 ]]
22 CallEnd 23 [[ 21 26 28 ]] [ Ctrl, #BOT, *![flt]]
28 #2 22 [[ 27 ]] *[flt]
26 $mem 22 [[ 20 27 ]] #BOT

L21: [[ L22 ]]
21 $ctrl 22 [[ 27 20 ]] Ctrl
27 ld4 21 26 28 ____ [[ 20 ]] u32
20 Return 21 26 27 29 [[ 1 ]] [ Ctrl, #BOT, u32]

L1: [[ ]]
1 Stop 2 20 [[ ]] Bot
24 changes: 24 additions & 0 deletions seaofnodes/src/test/cases/array2/array.ez_out
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---foo { -> *![flt] #0}---------------------------
0000 4883EC08 subi rsp -= #8
0004 BE18000000 ldi rsi = #24
0009 BF01000000 alloc ldi rcx = #1
000E E800000000 call #calloc
0013 F20F100500 ld8 xmm0 = #4.2
0018 000000
001B F20F114008 st8 [rax+8],xmm0
0020 F20F100500 ld8 xmm0 = #8.4
0025 000000
0028 F20F114010 st8 [rax+16],xmm0
002D C700020000 st4 [rax],#2
0032 00
0033 4883C408C3 addi rsp += #8
0038 ret
---{ -> *![flt] #0}---------------------------

---bar { -> int #1}---------------------------
0040 4883EC08 subi rsp -= #8
0044 E8B7FFFFFF call foo
0049 8B00 ld4 rax,[rax]
004B 4883C408C3 addi rsp += #8
0050 ret
---{ -> int #1}---------------------------
9 changes: 9 additions & 0 deletions seaofnodes/src/test/cases/array2/array.smp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
val foo = {->
var a = new flt[2];
a[0] = 4.2;
a[1] = 8.4;
return a;
};
val bar = { ->
return foo()#;
};
Loading
Loading