summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter17/README.md14
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/Parser.java49
-rw-r--r--chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java22
3 files changed, 64 insertions, 21 deletions
diff --git a/chapter17/README.md b/chapter17/README.md
index 1bac940b..d65ff879 100644
--- a/chapter17/README.md
+++ b/chapter17/README.md
@@ -12,6 +12,14 @@ Also allows `s.fld++` and `ary[idx]++`, and their `--` variants.
Allow pre-increment for identifiers only, for now: `--pc`.
+## Operator assignment
+
+Along the same lines as post-increment, we now allow `op=` assignment
+with semantics similar to other languages.
+
+`x += y`
+
+
## var & val
`var` can be used in the `type` position to indicate a "variable" (mutable
@@ -125,11 +133,5 @@ return i; // ERROR: Undefined name 'i'
-oper-assign +=, -=
TODO
switch
-
-
-
-
-
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/Parser.java b/chapter17/src/main/java/com/seaofnodes/simple/Parser.java
index 09ea21ac..47e7c3bb 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/Parser.java
@@ -889,13 +889,30 @@ public class Parser {
if( matchx("new" ) ) return alloc();
// Expect an identifier now
ScopeMinNode.Var n = requireLookupId("an identifier or expression");
- Node rvalue = _scope.in(n).keep();
- if( matchx("++") || matchx("--") ) {
- if( n._final )
- throw error("Cannot reassign final '"+n._name+"'");
- _scope.update(n,zsMask(peep(new AddNode(rvalue,con( _lexer.peek(-1)=='+' ? 1 : -1))),n.type()));
- }
- return rvalue.unkeep();
+ Node rvalue = _scope.in(n);
+ // Check for assign-update, x += e0;
+ char ch = _lexer.matchOperAssign();
+ if( ch==0 ) return rvalue;
+ if( n._final )
+ throw error("Cannot reassign final '"+n._name+"'");
+ Node op = switch(ch) {
+ case '+' -> new AddNode(rvalue,null);
+ case '-' -> new SubNode(rvalue,null);
+ case '*' -> new MulNode(rvalue,null);
+ case '/' -> new DivNode(rvalue,null);
+ case 1 -> new AddNode(rvalue,con( 1));
+ case (char)-1 -> new AddNode(rvalue,con(-1));
+ default -> throw Utils.TODO();
+ };
+ // Return pre-value (x+=1) or post-value (x++)
+ boolean pre = op.in(2)==null;
+ // Parse RHS argument as needed
+ if( pre )
+ { op.keep().setDef(2,parseExpression()); op.unkeep(); }
+ else rvalue.keep(); // Keep post-value across peeps
+ op = zsMask(peep(op),n.type());
+ _scope.update(n,op);
+ return pre ? op : rvalue.unkeep();
}
ScopeMinNode.Var requireLookupId(String msg) {
@@ -1344,12 +1361,28 @@ public class Parser {
//
private boolean isPunctuation(char ch) {
- return "=;[]<>()+-/*".indexOf(ch) != -1;
+ return "=;[]<>()+-/*&|^".indexOf(ch) != -1;
}
private String parsePunctuation() {
int start = _position;
return new String(_input, start, 1);
}
+
+ // Next oper= character, or 0.
+ // As a convenience, mark "++" as a char 1 and "--" as char -1 (65535)
+ public char matchOperAssign() {
+ skipWhiteSpace();
+ if( _position+2 >= _input.length ) return 0;
+ char ch0 = (char)_input[_position];
+ if( "+-/*&|^".indexOf(ch0) == -1 ) return 0;
+ char ch1 = (char)_input[_position+1];
+ if( ch1=='=' )
+ { _position += 2; return ch0; }
+ if( isIdLetter((char)_input[_position+2]) ) return 0; // Stop --x
+ if( ch0 == '+' && ch1 == '+' ) { _position += 2; return (char) 1; }
+ if( ch0 == '-' && ch1 == '-' ) { _position += 2; return (char)-1; }
+ return 0;
+ }
}
}
diff --git a/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java
index b1f7eb43..176a9236 100644
--- a/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java
+++ b/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java
@@ -105,6 +105,14 @@ return s.x;
assertEquals(255L, Evaluator.evaluate(stop, 0));
}
+ @Test
+ public void testInc8() {
+ Parser parser = new Parser("int x; x+=2; return x+=3;");
+ StopNode stop = parser.parse().iterate();
+ assertEquals("return 5;", stop.toString());
+ assertEquals(5L, Evaluator.evaluate(stop, 0));
+ }
+
// ---------------------------------------------------------------
@Test public void testVar0() {
Parser parser = new Parser("var d; return d;");
@@ -288,7 +296,7 @@ return b ? b.next ? b.next.x : b.x; // parses "b ? (b.next ? b.next.x : b.x) : 0
Parser parser = new Parser("""
int sum=0;
for( int i=0; i<arg; i++ )
- sum = sum + i;
+ sum += i;
return sum;
""");
StopNode stop = parser.parse().iterate();
@@ -301,7 +309,7 @@ return sum;
Parser parser = new Parser("""
int sum=0, i=0;
for( ; i<arg; i++ )
- sum = sum + i;
+ sum += i;
return sum;
""");
StopNode stop = parser.parse().iterate();
@@ -315,7 +323,7 @@ return sum;
int sum=0;
for( int i=0; ; i++ ) {
if( i>=arg ) break;
- sum = sum + i;
+ sum += i;
}
return sum;
""");
@@ -329,7 +337,7 @@ return sum;
Parser parser = new Parser("""
int sum=0;
for( int i=0; i<arg; )
- sum = sum + i++;
+ sum += i++;
return sum;
""");
StopNode stop = parser.parse().iterate();
@@ -342,7 +350,7 @@ return sum;
Parser parser = new Parser("""
int sum=0;
for( int i=0; i<arg; i++ )
- sum = sum + i;
+ sum += i;
return i;
""");
try { parser.parse().iterate(); fail(); }
@@ -361,7 +369,7 @@ while( arg-- )
int sum=0;
var ptr = head; // A read-only ptr, to be assigned from read-only next fields
for( ; ptr; ptr = ptr.next )
- sum = sum + ptr.i;
+ sum += ptr.i;
return sum;
""");
StopNode stop = parser.parse().iterate();
@@ -382,7 +390,7 @@ for( p=2; p*p < arg; p++ ) {
// p is now a prime
primes[nprimes++] = p;
// Mark out the rest non-primes
- for( int i = p + p; i < ary#; i = i + p )
+ for( int i = p + p; i < ary#; i += p )
ary[i] = true;
}
// Now just collect the remaining primes, no more marking