summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/Parser.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/seaofnodes/simple/Parser.java')
-rw-r--r--src/main/java/com/seaofnodes/simple/Parser.java446
1 files changed, 273 insertions, 173 deletions
diff --git a/src/main/java/com/seaofnodes/simple/Parser.java b/src/main/java/com/seaofnodes/simple/Parser.java
index 4bb18d6b..a8064e17 100644
--- a/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/src/main/java/com/seaofnodes/simple/Parser.java
@@ -2,12 +2,13 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import static com.seaofnodes.simple.Utils.TODO;
import java.util.*;
/**
* The Parser converts a Simple source program to the Sea of Nodes intermediate
- * representation directly in one pass. There is no intermediate Abstract
+ * representation directly in one pass. There is no intermediate Abstract
* Syntax Tree structure.
* <p>
* This is a simple recursive descent parser. All lexical analysis is done here as well.
@@ -95,35 +96,26 @@ public class Parser {
// Mapping from a type name to a Type. The string name matches
// `type.str()` call. No TypeMemPtrs are in here, because Simple does not
// have C-style '*ptr' references.
- public static HashMap<String, Type> TYPES = new HashMap<>();
+ public final HashMap<String, Type> TYPES;
+
+ // Mapping from a type name to the constructor for a Type.
+ public final HashMap<String, StructNode> INITS;
+
public Parser(String source, TypeInteger arg) {
Node.reset();
IterPeeps.reset();
- TYPES.clear();
- TYPES.put("bool",TypeInteger.U1 );
- TYPES.put("byte",TypeInteger.U8 );
- TYPES.put("f32" ,TypeFloat .B32);
- TYPES.put("f64" ,TypeFloat .BOT);
- TYPES.put("flt" ,TypeFloat .BOT);
- TYPES.put("i16" ,TypeInteger.I16);
- TYPES.put("i32" ,TypeInteger.I32);
- TYPES.put("i64" ,TypeInteger.BOT);
- TYPES.put("i8" ,TypeInteger.I8 );
- TYPES.put("int" ,TypeInteger.BOT);
- TYPES.put("u1" ,TypeInteger.U1 );
- TYPES.put("u16" ,TypeInteger.U16);
- TYPES.put("u32" ,TypeInteger.U32);
- TYPES.put("u8" ,TypeInteger.U8 );
SCHEDULED = false;
_lexer = new Lexer(source);
_scope = new ScopeNode();
_continueScope = _breakScope = null;
- START = new StartNode(new Type[]{ Type.CONTROL, arg });
+ START = new StartNode(arg);
STOP = new StopNode(source);
ZERO = con(0).keep();
XCTRL= new XCtrlNode().peephole().keep();
ALIAS = 2; // alias 0 for the control, 1 for memory
+ TYPES = defaultTypes();
+ INITS = new HashMap<>();
}
public Parser(String source) {
@@ -133,13 +125,29 @@ public class Parser {
@Override
public String toString() { return _lexer.toString(); }
- String src() { return new String( _lexer._input ); }
+ public static HashMap<String, Type> defaultTypes() {
+ return new HashMap<>() {{
+ put("bool",TypeInteger.U1 );
+ put("byte",TypeInteger.U8 );
+ put("f32" ,TypeFloat .B32);
+ put("f64" ,TypeFloat .BOT);
+ put("flt" ,TypeFloat .BOT);
+ put("i16" ,TypeInteger.I16);
+ put("i32" ,TypeInteger.I32);
+ put("i64" ,TypeInteger.BOT);
+ put("i8" ,TypeInteger.I8 );
+ put("int" ,TypeInteger.BOT);
+ put("u1" ,TypeInteger.U1 );
+ put("u16" ,TypeInteger.U16);
+ put("u32" ,TypeInteger.U32);
+ put("u8" ,TypeInteger.U8 );
+ }};
+ }
// Debugging utility to find a Node by index
public static Node find(int nid) { return START.find(nid); }
private Node ctrl() { return _scope.ctrl(); }
-
private Node ctrl(Node n) { return _scope.ctrl(n); }
public StopNode parse() { return parse(false); }
@@ -147,8 +155,12 @@ public class Parser {
_xScopes.push(_scope);
// Enter a new scope for the initial control and arguments
_scope.push();
- _scope.define(ScopeNode.CTRL, Type.CONTROL , new CProjNode(START, 0, ScopeNode.CTRL).peephole());
- _scope.define(ScopeNode.ARG0, TypeInteger.BOT, new ProjNode(START, 1, ScopeNode.ARG0).peephole());
+ ScopeMinNode mem = new ScopeMinNode();
+ mem.addDef(null);
+ _scope.define(ScopeNode.CTRL, Type.CONTROL , false, new CProjNode(START, 0, ScopeNode.CTRL).peephole());
+ mem.addDef( new ProjNode(START, 1, ScopeNode.MEM0).peephole());
+ _scope.define(ScopeNode.MEM0, TypeMem.TOP , false, mem .peephole());
+ _scope.define(ScopeNode.ARG0, TypeInteger.BOT, false, new ProjNode(START, 2, ScopeNode.ARG0).peephole());
// Parse whole program
parseBlock();
@@ -157,6 +169,9 @@ public class Parser {
STOP.addReturn(new ReturnNode(ctrl(), ZERO, _scope).peephole());
_scope.pop();
_xScopes.pop();
+ for( StructNode init : INITS.values() )
+ init.unkeep().kill();
+ INITS.clear();
if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken());
STOP.peephole();
if( show ) showGraph();
@@ -205,49 +220,6 @@ public class Parser {
// to ambiguity
else return parseExpressionStatement();
}
-
- /**
- * Parse a struct field.
- * <pre>
- * type IDENTIFIER ;
- * </pre>
- */
- private Field parseField() {
- Type t = type();
- if( t==null )
- throw errorSyntax("Requires a field type, found '"+_lexer.getAnyNextToken()+"'");
- return require(Field.make(requireId().intern(),ALIAS++,t),";");
- }
-
- /**
- * Parse a struct declaration, and return the following statement.
- * Only allowed in top level scope.
- * Structs cannot be redefined.
- *
- * @return The statement following the struct
- */
- private Node parseStruct() {
- if (_xScopes.size() > 1) throw errorSyntax("struct declarations can only appear in top level scope");
- String typeName = requireId();
- Type t = TYPES.get(typeName);
- if( t!=null && !(t instanceof TypeMemPtr tmp && tmp._obj._fields==null) )
- throw errorSyntax("struct '" + typeName + "' cannot be redefined");
- // Parse a collection of fields
- ArrayList<Field> fields = new ArrayList<>();
- require("{");
- while (!peek('}') && !_lexer.isEOF()) {
- Field field = parseField();
- if (fields.contains(field)) throw errorSyntax("Field '" + field + "' already defined in struct '" + typeName + "'");
- fields.add(field);
- }
- require("}");
- // Build and install the TypeStruct
- TypeStruct ts = TypeStruct.make(typeName, fields.toArray(new Field[fields.size()]));
- TYPES.put(typeName, TypeMemPtr.make(ts));
- START.addMemProj(ts, _scope); // Insert memory edges
- return parseStatement();
- }
-
/**
* Parses a while statement
*
@@ -328,6 +300,8 @@ public class Parser {
// At exit the false control is the current control, and
// the scope is the exit scope after the exit test.
+ _xScopes.pop();
+ _xScopes.push(exit);
return _scope = exit;
}
@@ -336,15 +310,15 @@ public class Parser {
ctrl(XCTRL); // Kill current scope
// Prune nested lexical scopes that have depth > than the loop head
// We use _breakScope as a proxy for the loop head scope to obtain the depth
- while( cur._idxs.size() > _breakScope._idxs.size() )
+ while( cur._lexSize.size() > _breakScope._lexSize.size() )
cur.pop();
// If this is a continue then first time the target is null
// So we just use the pruned current scope as the base for the
// "continue"
- if (toScope == null)
+ if( toScope == null )
return cur;
// toScope is either the break scope, or a scope that was created here
- assert toScope._idxs.size() <= _breakScope._idxs.size();
+ assert toScope._lexSize.size() <= _breakScope._lexSize.size();
toScope.ctrl(toScope.mergeScopes(cur));
return toScope;
}
@@ -429,43 +403,44 @@ public class Parser {
return null;
}
- /**
- * Parses an expression statement or a declaration statement where type is a struct
- *
- * <pre>
- * name; // Error
- * type name; // Define name with default initial value
- * type name = expr; // Define name with given initial value
- * name = expr; // Reassign existing
- * expr // Something else
- * </pre>
- * @return an expression {@link Node}, never {@code null}
+ /** Parse: name [=expr]
*/
- private Node parseExpressionStatement() {
+ private Node parseAsgn(Type t, boolean xfinal) {
+ boolean isDecl = t!=null; // Having a type is a declaration, missing one is updating a prior name
int old = _lexer._position;
- Type t = type();
String name = requireId();
Node expr;
- if( match(";") ) { // Assign a default value
- // No type and no expr is an error
+ if( peek(';') || peek(',') ) {
+ // Bare "name" is not allowed
if( t==null ) throw errorSyntax("expression");
- expr = new ConstantNode(t.makeInit()).peephole();
- } else if( match("=") ) { // Assign "= expr;"
- expr = require(parseExpression(), ";");
- } else { // Neither, so just a normal expression parse
+ // Does this declaration need an initializer and not getting one?
+ Type init = xfinal || t instanceof TypeMemPtr tmp && !tmp._nil
+ // Must be initialized in the "new" constructor
+ ? Type.TOP
+ // Else takes the default
+ : t.makeInit();
+ expr = con(init);
+
+ } else if( !match("=") ) { // Something else
_lexer._position = old;
- return require(parseExpression(),";");
- }
+ return null;
+ } else
+ expr = parseExpression();
// Defining a new variable vs updating an old one
- if( t != null ) {
- if( _scope.define(name,t,expr) == null )
- throw error("Redefining name '" + name + "'");
- } else {
- if( _scope.lookup(name)==null )
+ if( !isDecl ) { // Assigning over an existing name
+ // Lookup
+ ScopeMinNode.Var def = _scope.lookup(name);
+ if( def==null )
throw error("Undefined name '" + name + "'");
- t = _scope.lookupDeclaredType(name);
+ // TOP fields are for late-initialized fields; these have never
+ // been written to, and this must be the final write. Other writes
+ // need to check the final bit.
+ if( _scope.in(def._idx)._type!=Type.TOP && def._final )
+ throw error("Cannot reassign final '"+name+"'");
+ t = def._type; // Declared field type
}
+
// Auto-widen int to float
if( expr._type instanceof TypeInteger && t instanceof TypeFloat )
expr = new ToFloatNode(expr).peephole();
@@ -478,9 +453,93 @@ public class Parser {
// Type is sane
if( !e.isa(t) )
throw error("Type " + e.str() + " is not of declared type " + t.str());
- return _scope.update(name,expr);
+
+ if( isDecl ) {
+ if( !_scope.define(name,t,xfinal,expr) )
+ throw error("Redefining name '" + name + "'");
+ } else
+ _scope.update(name,expr);
+ return expr;
+ }
+
+ /** Parse final: [!]asgn
+ */
+ private Node parseFinal(Type t) {
+ boolean xfinal = t!=null && match("!");
+ return parseAsgn(t,xfinal);
+ }
+
+ /**
+ * Parses an expression statement or a declaration statement where type is a struct
+ *
+ * <pre>
+ * type decl [, decl]*; // Define many names with the same type
+ * asgn; // Assign or load a variable
+ * expr; // Something else
+ * name; // Bare name is an error
+
+ * </pre>
+ * @return an expression {@link Node}, never {@code null}
+ */
+ private Node parseExpressionStatement() {
+ Node n;
+ Type t = type();
+ if( t != null ) {
+ // now parse final [, final]*
+ n = parseFinal(t);
+ while( match(",") )
+ n = parseFinal(t);
+
+ // Parse "asgn;" which is just "name = expr;"
+ } else if( ( n = parseAsgn(null,false)) == null ) {
+ // Something else
+ n = parseExpression();
+ }
+ return require(n,";");
}
+
+ /**
+ * Parse a struct declaration, and return the following statement.
+ * Only allowed in top level scope.
+ * Structs cannot be redefined.
+ *
+ * @return The statement following the struct
+ */
+ private Node parseStruct() {
+ if (_xScopes.size() > 1) throw errorSyntax("struct declarations can only appear in top level scope");
+ String typeName = requireId();
+ Type t = TYPES.get(typeName);
+ if( t!=null && !(t instanceof TypeMemPtr tmp && tmp._obj._fields==null) )
+ throw errorSyntax("struct '" + typeName + "' cannot be redefined");
+
+ // A Block scope parse, and inspect the scope afterward for fields.
+ _scope.push();
+ require("{");
+ while (!peek('}') && !_lexer.isEOF())
+ parseStatement();
+
+ // Grab the declarations and build fields and a Struct
+ int lexlen = _scope._lexSize.last();
+ int varlen = _scope._vars._len;
+ StructNode s = new StructNode();
+ Field[] fs = new Field[varlen-lexlen];
+ for( int i=lexlen; i<varlen; i++ ) {
+ s.addDef(_scope.in(i));
+ ScopeMinNode.Var v = _scope._vars.at(i);
+ fs[i-lexlen] = Field.make(v._name,v._type,ALIAS++,v._final);
+ }
+ TypeStruct ts = s._ts = TypeStruct.make(typeName, fs);
+ TYPES.put(typeName, TypeMemPtr.make(ts));
+ INITS.put(typeName,s.peephole().keep());
+ // Done with struct/block scope
+ require("}");
+ require(";");
+ _scope.pop();
+ return null;
+ }
+
+
// Parse and return a type or null. Valid types always are followed by an
// 'id' which the caller must parse. This lets us distinguish forward ref
// types (which ARE valid here) from local vars in an (optional) forward
@@ -529,14 +588,14 @@ public class Parser {
private TypeMemPtr typeAry( Type t ) {
if( t instanceof TypeMemPtr tmp && !tmp._nil )
throw error("Arrays of reference types must always be nullable");
- String tname = t.str()+"[]";
+ String tname = "["+t.str()+"]";
Type ta = TYPES.get(tname);
if( ta != null ) return (TypeMemPtr)ta;
// Need make an array type.
TypeStruct ts = TypeStruct.makeAry(TypeInteger.BOT,ALIAS++,t,ALIAS++);
+ assert ts.str().equals(tname);
TypeMemPtr tary = TypeMemPtr.make(ts);
TYPES.put(tname,tary);
- START.addMemProj(ts, _scope); // Insert memory alias edges
return tary;
}
@@ -694,67 +753,107 @@ public class Parser {
if( match("(") ) return require(parseExpression(), ")");
if( matchx("true" ) ) return con(1);
if( matchx("false") ) return ZERO;
- if( matchx("null" ) ) return new ConstantNode(TypeMemPtr.NULLPTR).peephole();
- if( matchx("new") ) {
- Type t = type();
- if( t==null ) throw error("Expected a type");
- if( match("[") ) {
- Node len = parseExpression().keep();
- if( !(len._type instanceof TypeInteger) )
- throw error("Cannot allocate an array with length "+len._type);
- require("]");
- TypeMemPtr tmp = typeAry(t);
- return newArray(tmp._obj,len);
- }
- if( t instanceof TypeMemPtr tmp ) {
- TypeStruct obj = tmp._obj;
- if( obj._fields==null )
- throw error("Unknown struct type '" + obj._name + "'");
- if( obj.isAry() )
- throw Utils.TODO(); // Missing array length
- return newStruct(obj,con(obj.offset(obj._fields.length)));
- }
- throw error("Cannot allocate a "+t.str());
- }
+ if( matchx("null" ) ) return con(TypeMemPtr.NULLPTR);
+ if( matchx("new" ) ) return alloc();
+ // Expect an identifier now
String name = _lexer.matchId();
if( name == null) throw errorSyntax("an identifier or expression");
- Node n = _scope.lookup(name);
- if( n!=null ) return n;
+ ScopeMinNode.Var n = _scope.lookup(name);
+ if( n!=null ) return _scope.in(n);
throw error("Undefined name '" + name + "'");
}
/**
- * Return a NewNode with pre-zeroed memory
+ Parse an allocation
+ */
+ private Node alloc() {
+ Type t = type();
+ if( t==null ) throw error("Expected a type");
+ // Parse ary[ length_expr ]
+ if( match("[") ) {
+ Node len = parseExpression().keep();
+ if( !(len._type instanceof TypeInteger) )
+ throw error("Cannot allocate an array with length "+len._type);
+ require("]");
+ TypeMemPtr tmp = typeAry(t);
+ return newArray(tmp._obj,len);
+ }
+
+ if( !(t instanceof TypeMemPtr tmp) )
+ throw error("Cannot allocate a "+t.str());
+
+ // Parse new struct { default_initialization }
+ StructNode s = INITS.get(tmp._obj._name);
+ if( s==null ) throw error("Unknown struct type '" + tmp._obj._name + "'");
+
+ Field[] fs = s._ts._fields;
+ // if the object is fully initialized, we can skip a block here.
+ // Check for constructor block:
+ boolean hasConstructor = match("{");
+ Ary<Node> init=s._inputs; int idx=0;
+ if( hasConstructor ) {
+ idx = _scope.nIns();
+ // Push a scope, and pre-assign all struct fields.
+ _scope.push();
+ for( int i=0; i<fs.length; i++ )
+ _scope.define(fs[i]._fname, fs[i]._type, fs[i]._final, s.in(i));
+ // Parse the constructor body
+ parseBlock();
+ require("}");
+ init = _scope._inputs;
+ }
+ // Check that all fields are initialized
+ for( int i=idx; i<init.size(); i++ )
+ if( init.get(i)._type == Type.TOP )
+ throw error("'"+tmp._obj._name+"' is not fully initialized, field '" + fs[i-idx]._fname + "' needs to be set in a constructor");
+ Node ptr = newStruct(tmp._obj, con(tmp._obj.offset(fs.length)), idx, init );
+ if( hasConstructor )
+ _scope.pop();
+ return ptr;
+ }
+
+
+ /**
+ * Return a NewNode initialized memory.
+ * @param obj is the declared type, with GLB fields
+ * @param init is a collection of initialized fields
*/
- private Node newStruct(TypeStruct obj, Node size) {
+ private Node newStruct( TypeStruct obj, Node size, int idx, Ary<Node> init ) {
Field[] fs = obj._fields;
- Node[] ns = new Node[2+fs.length];
- ns[0] = ctrl();
+ if( fs==null )
+ throw error("Unknown struct type '" + obj._name + "'");
+ int len = fs.length;
+ Node[] ns = new Node[2+len+len];
+ ns[0] = ctrl(); // Control in slot 0
+ // Total allocated length in bytes
ns[1] = size;
- for( int i = 0; i < fs.length; i++ )
- ns[i+2] = memAlias(fs[i]._alias);
+ // Memory aliases for every field
+ for( int i = 0; i < len; i++ )
+ ns[2 +i] = memAlias(fs[i]._alias);
+ // Initial values for every field
+ for( int i = 0; i < len; i++ )
+ ns[2+len+i] = init.get(i+idx);
Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole();
- for( int i = 0; i < fs.length; i++ )
+ for( int i = 0; i < len; i++ )
memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole());
return new ProjNode(nnn,1,obj._name).peephole();
}
+ private static final Ary<Node> ALTMP = new Ary<>(Node.class);
private Node newArray(TypeStruct ary, Node len) {
int base = ary.aryBase ();
int scale= ary.aryScale();
Node size = new AddNode(con(base),new ShlNode(len,con(scale)).peephole()).peephole();
- Node ptr = newStruct(ary,size);
- int alias = ary._fields[0]._alias; // Length alias
- memAlias(alias,new StoreNode("#",alias,TypeInteger.BOT,memAlias(alias),ptr,con( ary.offset(0) ), len.unkeep(), true ).peephole());
- return ptr;
+ ALTMP.clear(); ALTMP.add(len); ALTMP.add(con(ary._fields[1]._type.makeInit()));
+ return newStruct(ary,size,0,ALTMP);
}
// We set up memory aliases by inserting special vars in the scope these
// variables are prefixed by $ so they cannot be referenced in Simple code.
// Using vars has the benefit that all the existing machinery of scoping
// and phis work as expected
- private Node memAlias(int alias ) { return _scope.lookup(memName(alias) ); }
- private Node memAlias(int alias, Node st) { return _scope.update(memName(alias), st); }
+ private Node memAlias(int alias ) { return _scope.mem(alias ); }
+ private void memAlias(int alias, Node st) { _scope.mem(alias, st); }
public static String memName(int alias) { return ("$"+alias).intern(); }
/**
@@ -777,52 +876,49 @@ public class Parser {
// Sanity check expr for being a reference
if( !(expr._type instanceof TypeMemPtr ptr) )
throw error("Expected reference but got " + expr._type.str());
- if( ptr == TypeMemPtr.TOP ) throw error("Accessing field '" + name + "' from null");
- if( ptr._obj == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
+
+ // Happens when parsing known dead code, which often has other typing
+ // issues. Since the code is dead, possibly due to inlining, lets not
+ // spoil the user experience with error messages.
+ if( ctrl()._type==Type.XCONTROL )
+ // Exit out via parsing the trailing expression
+ return matchOpx('=','=') ? parseExpression() : parsePostfix(con(Type.TOP));
+
// Sanity check field name for existing
TypeMemPtr tmp = (TypeMemPtr)TYPES.get(ptr._obj._name);
if( tmp == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
TypeStruct base = tmp._obj;
int fidx = base.find(name);
if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
- expr.keep();
// Get field type and layout offset from base type and field index fidx
Field f = base._fields[fidx]; // Field from field index
- Node off;
- if( name.equals("[]") ) { // If field is an array body
- // Array index math
- Node idx = require(parseExpression(),"]");
- Node shl = new ShlNode(idx,con(base.aryScale())).peephole();
- off = new AddNode(con(base.aryBase()),shl).peephole();
- } else { // Else normal struct field
- // Hardwired field offset
- off = con(base.offset(fidx));
- }
- if( match("=") ) {
- // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment
- if( peek('=') ) _lexer._position--;
- else {
- off.keep();
- Node val = parseExpression();
- // Auto-truncate when storing to narrow fields
- val = zsMask(val,f._type).keep();
- Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr.unkeep(), off.unkeep(), val, false);
- // Arrays include control, as a proxy for a safety range check.
- // Structs don't need this; they only need a NPE check which is
- // done via the type system.
- if( base.isAry() ) st.setDef(0,ctrl());
- memAlias(f._alias, st.peephole());
- return val.unkeep(); // "obj.a = expr" returns the expression while updating memory
- }
+ Node off = name.equals("[]") // If field is an array body
+ // Array index math
+ ? new AddNode(con(base.aryBase()),new ShlNode(require(parseExpression(),"]"),con(base.aryScale())).peephole()).peephole()
+ // Struct field offsets are hardwired
+ : con(base.offset(fidx));
+
+ // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment
+ if( matchOpx('=','=') ) {
+ Node val = parseExpression();
+ // Auto-truncate when storing to narrow fields
+ val = zsMask(val,f._type);
+ Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off, val, false);
+ // Arrays include control, as a proxy for a safety range check.
+ // Structs don't need this; they only need a NPE check which is
+ // done via the type system.
+ if( base.isAry() ) st.setDef(0,ctrl());
+ memAlias(f._alias, st.peephole());
+ return val; // "obj.a = expr" returns the expression while updating memory
}
- Node load = new LoadNode(name, f._alias, f._type.glb(), memAlias(f._alias), expr.unkeep(), off);
+ Node load = new LoadNode(name, f._alias, f._type.glb(), memAlias(f._alias), expr, off);
// Arrays include control, as a proxy for a safety range check
// Structs don't need this; they only need a NPE check which is
// done via the type system.
- if( base.isAry() ) load.setDef(0,ctrl());
+ //if( base.isAry() ) load.setDef(0,ctrl());
return parsePostfix(load.peephole());
}
@@ -855,13 +951,9 @@ public class Parser {
* floatLiteral: [digits].[digits]?[e [digits]]?
* </pre>
*/
- private ConstantNode parseLiteral() {
- return (ConstantNode) new ConstantNode(_lexer.parseNumber()).peephole();
- }
-
- public static Node con( long con ) {
- return new ConstantNode(TypeInteger.constant(con)).peephole();
- }
+ private ConstantNode parseLiteral() { return con(_lexer.parseNumber()); }
+ public static Node con( long con ) { return con(TypeInteger.constant(con)); }
+ public static ConstantNode con( Type t ) { return (ConstantNode)new ConstantNode(t).peephole(); }
//////////////////////////////////
// Utilities for lexical analysis
@@ -870,6 +962,7 @@ public class Parser {
private boolean match (String syntax) { return _lexer.match (syntax); }
// Match must be "exact", not be followed by more id letters
private boolean matchx(String syntax) { return _lexer.matchx(syntax); }
+ private boolean matchOpx(char c0, char c1) { return _lexer.matchOpx(c0,c1); }
// Return true and do NOT skip if 'ch' is next
private boolean peek(char ch) { return _lexer.peek(ch); }
private boolean peekIsId() { return _lexer.peekIsId(); }
@@ -989,6 +1082,13 @@ public class Parser {
_position -= syntax.length();
return false;
}
+ boolean matchOpx(char c0, char c1) {
+ skipWhiteSpace();
+ if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c1 )
+ return false;
+ _position++;
+ return true;
+ }
private boolean peek(char ch) {
skipWhiteSpace();