summaryrefslogtreecommitdiff
path: root/chapter27/src/main/java/com
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-25 09:51:44 -0700
committerCliff Click <cliffc@acm.org>2026-10-25 09:51:44 -0700
commit4051ce7cd26314f01dc8c0237899a742e0ab2084 (patch)
tree29cb9b47e0461c34be1797ac36dd31e8f0b10c09 /chapter27/src/main/java/com
parent5cfb046c8306a81ec40be82a59015f16f654fa93 (diff)
downloadSimple-4051ce7cd26314f01dc8c0237899a742e0ab2084.tar.gz
Simple-4051ce7cd26314f01dc8c0237899a742e0ab2084.zip
Fix ++x in methods
Fix ideaj setups
Diffstat (limited to 'chapter27/src/main/java/com')
-rw-r--r--chapter27/src/main/java/com/seaofnodes/simple/Parser.java76
1 files changed, 42 insertions, 34 deletions
diff --git a/chapter27/src/main/java/com/seaofnodes/simple/Parser.java b/chapter27/src/main/java/com/seaofnodes/simple/Parser.java
index 145feb15..93ad8f4e 100644
--- a/chapter27/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter27/src/main/java/com/seaofnodes/simple/Parser.java
@@ -1475,18 +1475,17 @@ public class Parser {
// Pre-dec/pre-inc
int old = pos();
if( match("--") || match("++") ) {
- int delta = _lexer.peek(-1)=='+' ? 1 : -1; // Pre vs post
+ int delta = _lexer.peek(-1)=='+' ? 1 : -1; // Inc vs Dec
+ int start = pos();
String name = _lexer.matchId();
- if( name!=null ) {
- Var n = _scope.lookup(name);
- if( n != null && !(n.type() instanceof TypeMemPtr) ) {
- if( n._final && !_scope.canInit(n) )
- throw error("Cannot reassign final '"+n._name+"'");
- checkSharedField(n);
- Node expr = liftExpr(peep(new AddNode(_scope.in(n),con(delta))),n.type(),true);
- _scope.update(n,expr);
- return expr;
- }
+ Var var = name==null ? null : _scope.lookup(name);
+ if( var!=null && !(var.type() instanceof TypeMemPtr) ) {
+ if( var._final && !_scope.canInit(var) )
+ throw error("Cannot reassign final '"+var._name+"'");
+ // Resolve fields just as a read or postfix update does. Updating
+ // their declaration's local slot would silently lose the Store.
+ pos(start);
+ return parsePrimary(delta);
}
// Reset, try again
pos(old);
@@ -1507,7 +1506,10 @@ public class Parser {
* </pre>
* @return a primary {@link Node}, never {@code null}
*/
- private Node parsePrimary() {
+ private Node parsePrimary() { return parsePrimary(0); }
+
+ // pre is +/-1 for a prefix update of a known name, zero otherwise.
+ private Node parsePrimary(int pre) {
if( _lexer.isNumber(_lexer.peek()) ) return parseLiteral();
if( _lexer.peek('"') ) return newString(parseString());
if( matchx("true" ) ) return con(1);
@@ -1555,7 +1557,7 @@ public class Parser {
if( instance(var) ) {
Var selfVar = _scope.lookup("self");
Node self = liftExpr(_scope.in(selfVar),selfVar.type(),true);
- return parsePostfixName(self,id);
+ return parsePostfixName(self,id,pre);
}
// Load local value
@@ -1570,7 +1572,7 @@ public class Parser {
else throw error("Cannot read uninitialized field '"+id+"'");
// Check for assign-update, x += e0;
- char ch = _lexer.matchOperAssign();
+ char ch = pre==0 ? _lexer.matchOperAssign() : (char)pre;
if( ch==0 ) // Normal primary, check for postfix updates
return parsePostfix(rvalue);
// Assign-update direct into Scope
@@ -1580,7 +1582,8 @@ public class Parser {
checkCaptureWrite(var);
Node op = opAssign(ch,rvalue, var.type() );
_scope.update(var,op);
- return postfix(ch) ? rvalue.unkeep() : op;
+ if( postfix(ch) ) rvalue.unkeep();
+ return pre==0 && postfix(ch) ? rvalue : op;
}
// true if instance variable lookup (var is in any number of nested blocks,
@@ -1877,8 +1880,10 @@ public class Parser {
* expr ('[' expr ']')* [ [op]= expr ] // Array reference
* </pre>
*/
- private Node parsePostfixName(Node expr, String name) {
- if( privateSelf(expr) ) return parsePrivateField(name);
+ private Node parsePostfixName(Node expr, String name) { return parsePostfixName(expr,name,0); }
+
+ private Node parsePostfixName(Node expr, String name, int pre) {
+ if( privateSelf(expr) ) return parsePrivateField(name,pre);
if( !privateSelf(expr) && mayBeSelf(expr,new java.util.BitSet()) )
throw error("Cannot access self through a merged alias during construction");
@@ -1887,7 +1892,7 @@ public class Parser {
// Sanity check expr for being a reference
if( !(expr._type instanceof TypeMemPtr ptr) )
- return parseUnknownField(expr,name);
+ return parseUnknownField(expr,name,pre);
// Find the field from the Type. Lookup in the base object field names.
TypeMemPtr ptr2 = (TypeMemPtr)TYPES.get(ptr._obj._name);
@@ -1895,7 +1900,7 @@ public class Parser {
ptr = ptr.makeFrom(ptr2._obj); // The declaration fixes the field shape; retain this view's access.
TypeStruct base = ptr._obj;
int fidx = base.find(name);
- if( fidx==-1 && base._open ) return parseUnknownField(expr,name);
+ if( fidx==-1 && base._open ) return parseUnknownField(expr,name,pre);
if( fidx == -1 )
throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
@@ -1918,7 +1923,7 @@ public class Parser {
: off(base,name)).keep();
// Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment
- if( matchOpx('=','=') ) {
+ if( pre==0 && matchOpx('=','=') ) {
Node val = parseAsgn().keep();
Node lift = liftExpr( val, tf, false );
@@ -1937,14 +1942,16 @@ public class Parser {
load = peep(load);
// Check for assign-update, "ptr.fld += expr" or "ary[idx]++"
- char ch = _lexer.matchOperAssign();
+ char ch = pre==0 ? _lexer.matchOperAssign() : (char)pre;
if( ch!=0 ) {
Node op = opAssign(ch,load,tf);
+ // A narrow Store may drop its conversion; prefix still returns it.
+ if( pre!=0 ) op.keep();
store(name,f._alias,tf,expr.unkeep(),off.unkeep(),op,false,base.isAry() ? ctrl() : null);
- load = postfix(ch) ? load.unkeep() : op;
- // And use the original loaded value as the result
- return load;
- //throw Utils.TODO(); // NO POSTFIX AFTER STORE, JUST RETURN
+ if( pre!=0 ) op.unkeep();
+ if( postfix(ch) ) load.unkeep();
+ // Prefix returns the new value; postfix returns the old load.
+ return pre==0 && postfix(ch) ? load : op;
} else {
off.unkill();
// Method call: Loaded a function from a named field, AND the base
@@ -1969,7 +1976,7 @@ public class Parser {
// Syntax fixes the access even when a forward definition or a loop
// leaves the receiver untyped. Resolve its alias and layout in the graph.
- private Node parseUnknownField(Node expr, String name) {
+ private Node parseUnknownField(Node expr, String name, int pre) {
expr.keep();
Node off = new FldOffNode(expr,name).peephole();
if( name.equals("[]") ) {
@@ -1978,7 +1985,7 @@ public class Parser {
off = peep(new AddNode(off,peep(new ShlNode(loc(),index,scale))));
}
off.keep();
- if( matchOpx('=','=') ) {
+ if( pre==0 && matchOpx('=','=') ) {
Node value = parseAsgn().keep();
unknownStore(name,expr,off,value);
expr.unkill();
@@ -1988,7 +1995,7 @@ public class Parser {
Node load = new LoadNode(loc(),name,1,mem(),expr,off);
load.setDef(0,ctrl());
load = peep(load);
- char ch = _lexer.matchOperAssign();
+ char ch = pre==0 ? _lexer.matchOperAssign() : (char)pre;
if( ch!=0 ) {
Node op = opAssign(ch,load,Type.BOTTOM).keep();
unknownStore(name,expr,off,op);
@@ -1996,7 +2003,7 @@ public class Parser {
// the stored value after conversion; postfix returns the old load.
// Reading our own Store folds once its alias and width are known.
if( postfix(ch) ) load.unkeep();
- else {
+ if( pre!=0 || !postfix(ch) ) {
load = new LoadNode(loc(),name,1,mem(),expr,off);
load.setDef(0,ctrl());
load = peep(load);
@@ -2010,7 +2017,7 @@ public class Parser {
} else load.keep();
expr.unkill();
off.unkill();
- return parsePostfix(load.unkeep());
+ return pre==0 ? parsePostfix(load.unkeep()) : load.unkeep();
}
private void unknownStore(String name, Node ptr, Node off, Node value) {
@@ -2022,12 +2029,12 @@ public class Parser {
// Explicit self.x and an unqualified field name use the same local slot.
// The map also keeps self.x distinct from a parameter/local named x.
- private Node parsePrivateField(String name) {
+ private Node parsePrivateField(String name, int pre) {
Var v=_fieldVars.get(name);
if( v==null ) throw error("Cannot resolve field '"+name+"'");
if( v.type() instanceof TypeFunPtr ctor && ctor.ret() instanceof TypeMem )
throw error("A constructor is only called by new");
- if( matchOpx('=','=') ) {
+ if( pre==0 && matchOpx('=','=') ) {
checkPrivateWrite(name);
Node value=parseAsgn().keep();
checkPublication(value);
@@ -2037,13 +2044,14 @@ public class Parser {
Node value=_scope.in(_scope.update(v,null));
if( value instanceof ConstantNode && (value._type==Type.BOTTOM || value._type==Type.TOP) )
throw error("Cannot read uninitialized field '"+name+"'");
- char ch=_lexer.matchOperAssign();
+ char ch=pre==0 ? _lexer.matchOperAssign() : (char)pre;
if( ch!=0 ) {
checkPrivateWrite(name);
Node op=opAssign(ch,value,v.type());
checkPublication(op);
_scope.update(v,op);
- return postfix(ch) ? value.unkeep() : op;
+ if( postfix(ch) ) value.unkeep();
+ return pre==0 && postfix(ch) ? value : op;
}
if( value._type instanceof TypeFunPtr && match("(") )
return parsePostfix(require(functionCall(value,self()),")"));