Skip to content

Commit

Permalink
Handle XTC construct proper
Browse files Browse the repository at this point in the history
Requires a Java factory-style constructor.  So replace all my Java constructors with simple no-arg constructors, plus a set of factory methods.
Methods call "construct" will do a new before calling the "$construct" methods.
  • Loading branch information
cliffclick committed Feb 10, 2024
1 parent d7f03b5 commit c5e5d9b
Show file tree
Hide file tree
Showing 20 changed files with 169 additions and 88 deletions.
2 changes: 1 addition & 1 deletion javatools_backend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ MULTI = multiModule/Lib.x multiModule/Main.x
multi_x = $(patsubst %.x,$(MANUAL_DIR)/%.x,$(MULTI))
$(multi_x:x=xtc): $(MANUAL_DIR)/%.xtc: $(MANUAL_DIR)/%.x $(XDK)
@echo "compiling " $@ " because " $?
$(XTC) $(filter-out $(XDK),$^) -L $(MANUAL_DIR)/multiModule -o $(MANUAL_DIR)/multiModule
@$(XTC) $(filter-out $(XDK),$^) -L $(MANUAL_DIR)/multiModule -o $(MANUAL_DIR)/multiModule


multi_exe: $(XDK) $(classes) $(multi_x:x=xtc)
Expand Down
16 changes: 12 additions & 4 deletions javatools_backend/src/main/java/org/xvm/xec/XTC.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public XTC() {} // No arg constructor
// Assert is always-on runtime test
public static void xassert( boolean cond ) {
if( !cond )
throw new IllegalState();
throw new IllegalState("");
}
public static void xassert( boolean cond, String msg ) {
if( !cond )
Expand Down Expand Up @@ -112,15 +112,23 @@ and this means I might wrap (in Java) for every XTC {@code
So I am Once Again, asking for a language change: make the XTC assert
throw e.g. AssertionError instead of IllegalStateException.
*/

public static class Exception extends RuntimeException {
Exception(String msg) {super(msg); }
public static Exception construct(String s) { return new Exception(s); }
}


// XTC IllegalState mapped to Java
public static class IllegalState extends RuntimeException {
IllegalState() { }
public static class IllegalState extends Exception {
IllegalState(String msg) {super(msg); }
public static IllegalState construct(String s) { return new IllegalState(s); }
}

// XTC IllegalArgument mapped to Java
public static class IllegalArgument extends IllegalArgumentException {
public static class IllegalArgument extends Exception {
public IllegalArgument(String s) { super(s); }
public static IllegalArgument construct(String s) { return new IllegalArgument(s); }
}

// XTC ReadOnlyException mapped to Java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ public class RangeIE extends Range {
static final RangeIE GOLD = new RangeIE();
public RangeIE( ) { } // No arg constructor
public RangeIE( long lo, long hi ) { super(lo,hi,false,true); }
public static RangeIE construct(long lo, long hi) { return new RangeIE(lo,hi); }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ public class RangeII extends Range {
public static final RangeII GOLD = new RangeII();
public RangeII( ) { } // No arg constructor
public RangeII( long lo, long hi ) { super(lo,hi,false,false); }
public static RangeII construct(long lo, long hi) { return new RangeII(lo,hi); }
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public AryString( long len, LongFunction<String> fcn ) {
for( int i=0; i<_len; i++ )
_es[i] = fcn.apply(i);
}

public static AryString construct() { return new AryString(); }

// Add an element, doubling base array as needed
public AryString add( org.xvm.xec.ecstasy.text.String s ) { return add(s._i); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public class AryXTC<E extends XTC> extends Array<E> {
public AryXTC(E... es ) { this(es[0], Constant, Arrays.copyOfRange(es,1,es.length)); }
public AryXTC(E gold, Mutability mut, AryXTC<E> as) { this(gold,mut,as._es.clone()); }
public AryXTC(AryXTC<E> as) { this(as._gold,as._mut,as._es.clone()); }

public static <E extends XTC> AryXTC<E> construct(E gold) { return new AryXTC<>(gold); }


public AryXTC(E gold, long len, LongFunction<E> fcn ) {
this(gold,(int)len);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public Arychar( long len, LongUnaryOperator fcn ) {
public Arychar(String s) {
this(s.length(), i -> s.charAt((int)i));
}
public static Arychar construct( String s ) { return new Arychar(s); }

// Fetch element
public char at8(long idx) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ public class Arylong extends Array<Int64> {
public Arylong(double x, long... es) { this(Constant, es); }
public Arylong(Mutability mut, Arylong as) { this(mut,as._es.clone()); }
public Arylong(Arylong as) { this(as._mut,as); }

public Arylong( long len, LongUnaryOperator fcn ) {
this((int)len);
if( _len != len ) throw XEC.TODO(); // Too Big
for( int i=0; i<_len; i++ )
_es[i] = fcn.applyAsLong(i);
}
public static Arylong construct( long len, LongUnaryOperator fcn ) { return new Arylong(len,fcn); }


// Fetch element
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class Int128 extends IntNumber {
public Int128(long l0, long l1) { _i0=l0; _i1=l1; }
public Int128(long lo) { _i0=lo; _i1=0; }

public static Int128 construct(long lo) { return new Int128(lo); }

public Int128 add( long x ) { throw XEC.TODO(); }
public Int128 mul( long x ) { throw XEC.TODO(); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public static Int64 make(long x) {
public Int64(org.xvm.xec.ecstasy.text.String s) { this(s._i); }
public Int64( long i ) { _i = i; }

public static Int64 construct( String s ) { return new Int64(s); }
public static Int64 construct( long i ) { return new Int64(i); }

Array<Bit> toBitArray(Array.Mutability mut) { throw XEC.TODO(); }

// All the XTC types here are guaranteed to be Int64
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ public class IntLiteral extends Const {
public IntLiteral(String s) { _s=s; }
public IntLiteral(org.xvm.xec.ecstasy.text.String s) { this(s._i); }
public IntLiteral(long x) { _s=Long.toString(x); }

public static IntLiteral construct(String s) { return new IntLiteral(s); }
@Override public String toString() { return _s; }
}
146 changes: 95 additions & 51 deletions javatools_backend/src/main/java/org/xvm/xtc/ClzBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ private void jclass_body() {

_sb.ip("public ");
if( !_is_top ) _sb.p("static ");
_tclz.clz_def(_sb.p(jpart)).p(" ");
_tclz.clz_generic(_sb.p(jpart),true,true).p(" ");

// ... extends Const/XTC/etc
if( _clz._super != null ) _sb.p("extends ").p(_clz._super._name);
Expand All @@ -154,7 +154,7 @@ private void jclass_body() {
for( Contrib c : _clz._contribs )
if( c._comp==Part.Composition.Implements ) {
XClz iclz = c._tContrib instanceof ParamTCon ptc ? XClz.make(ptc) : XClz.make(((TermTCon)c._tContrib).clz());
iclz.clz_val(_sb.p((once++ == 0) ? (_clz._tclz._iface ? " extends " : " implements ") : ", "));
iclz.clz_generic(_sb.p((once++ == 0) ? (_clz._tclz._iface ? " extends " : " implements ") : ", "),true,false);
add_import(iclz);
}
}
Expand Down Expand Up @@ -195,28 +195,50 @@ private void jclass_body() {
// Interfaces in XTC can require a constructor with a particular signature.
// Interfaces in Java can NOT - so just do not emit the signature.
!is_iface ) {
// For all constructors
for( MethodPart construct = (MethodPart)mm.child(mm._name); construct != null; construct = construct._sibling ) {
// Empty constructor is specified, must be added now - BECAUSE I already
// added another constructor, so I do not get the default Java empty
// constructor "for free"

// This is an "empty" constructor: it takes required explicit type
// parameters but does no other work.
_sb.ifmt("public %0( ",java_class_name);
for( int i=0; i<_tclz.nTypeParms(); i++ )
_sb.fmt("$%0 %0,",_tclz._flds[i]);
_sb.unchar().p(" ) { // default XTC empty constructor\n").ii();
_sb.ip("super((Never)null);").nl();
for( int i=0; i<_tclz.nTypeParms(); i++ )
_sb.ifmt("this.%0 = %0;\n",_tclz._flds[i]);
_sb.di().ip("}\n");

// For all other constructors
for( MethodPart meth = (MethodPart)mm.child(mm._name); meth != null; meth = meth._sibling ) {
// To support XTC 'construct' I need a layer of indirection. The Java
// moral equivalent is calling 'this' in a constructor, but XTC allows
// calling 'this' anywhere.

// "public static Foo construct(typeargs,args) { return new Foo(typeargs).$construct(args); }"
_sb.nl();
// Skip common empty constructor
if( construct.is_empty_function() ) {
// Empty constructor is specified, must be added now - BECAUSE I
// already added another constructor, so I do not get the default
// Java empty constructor "for free"

// If the class has type parameters, we need to pass them in now.
_sb.ifmt("public %0( ",java_class_name);
for( int i=0; i<_tclz.nTypeParms(); i++ )
_sb.fmt("$%0 %0,",_tclz._flds[i]);
_sb.unchar().p(" ) { // default XTC empty constructor\n").ii();
_sb.ip("super((Never)null);").nl();
for( int i=0; i<_tclz.nTypeParms(); i++ )
_sb.ifmt("this.%0 = %0;\n",_tclz._flds[i]);
_sb.di().ip("}\n");
keywords(meth,false);
_tclz.clz_generic(_sb,false,true);
_sb.fmt("%0 construct( ",java_class_name); // Return type
for( int i=0; i<_tclz.nTypeParms(); i++ )
_sb.fmt("$%0 %0,",_tclz._flds[i]);
_sb.unchar();
args(meth,false);
_sb.p(") { return new ").p(java_class_name).p("( ");
for( int i=0; i<_tclz.nTypeParms(); i++ )
_sb.fmt("%0,",_tclz._flds[i]);
_sb.unchar().p(").$construct(");
arg_names(meth);
_sb.p("); }").nl();

// "private Foo $construct(args) { ..."
_sb.ip("private ").p(java_class_name).p(" ");
// Common empty constructor
if( meth.is_empty_function() ) {
_sb.p("$construct(){ return this; }").nl();
} else {

keywords(construct,true);
jmethod_body(construct,java_class_name,true);
jmethod_body(meth,"$construct",true);
}
}
}
Expand Down Expand Up @@ -345,9 +367,44 @@ private void keywords(MethodPart m, boolean is_constructor) {
m._xrets = XType.xtypes(m._rets);
}

// Argument with types "( int arg0, String arg1, ... )"
private void args(MethodPart m, boolean define_args) {
// Argument list
if( m._xargs!=null ) {
for( int i = 0; i < m._xargs.length; i++ ) {
// Unbox boxed args
m._xargs[i] = m._xargs[i].unbox();
// Parameter class, using local generic parameters
Parameter p = m._args[i];
if( p.tcon() instanceof TermTCon ttc && ttc.id() instanceof FormalCon )
_sb.p("$").p(ttc.name());
else if( p._special )
_sb.p("$").p(p._name);
else
m._xargs[i].clz(_sb,p.tcon() instanceof ParamTCon ptc ? ptc : null);

// Parameter name, and define it in scope
_sb.p(' ').p(p._name).p(", ");
if( define_args )
define(p._name,m._xargs[i]);
}
_sb.unchar(2);
}
}

// Argument names "arg0, arg1, ..."
private void arg_names(MethodPart m) {
if( m._args!=null ) {
for( Parameter p : m._args )
_sb.p(p._name).p(", ");
_sb.unchar(2);
}
}


// Emit a Java string for this MethodPart.
// Already _sb has the indent set.
// "public static <G extends Generic> Ary<G> " ... jmethod_body()
public void jmethod( MethodPart m, String mname ) {
assert _locals.isEmpty(); // No locals mapped yet

Expand Down Expand Up @@ -388,29 +445,12 @@ public void jmethod( MethodPart m, String mname ) {
//
// ...method_name( int arg0, String arg1, ...) {
// ...indented_body
// }
// }
public void jmethod_body( MethodPart m, String mname, boolean constructor ) {
// Argument list
// Argument list:
// ... method_name( int arg0, String, arg1, ... ) {
_sb.p(mname).p("( ");
if( m._xargs!=null ) {
for( int i = 0; i < m._xargs.length; i++ ) {
// Unbox boxed args
m._xargs[i] = m._xargs[i].unbox();
// Parameter class, using local generic parameters
Parameter p = m._args[i];
if( p.tcon() instanceof TermTCon ttc && ttc.id() instanceof FormalCon )
_sb.p("$").p(ttc.name());
else if( p._special )
_sb.p("$").p(p._name);
else
m._xargs[i].clz(_sb,p.tcon() instanceof ParamTCon ptc ? ptc : null);

// Parameter name, and define it in scope
_sb.p(' ').p(p._name).p(", ");
define(p._name,m._xargs[i]);
}
_sb.unchar(2);
}
args(m,true);
_sb.p(" ) ");

// Abstract method, no body
Expand All @@ -423,10 +463,14 @@ else if( p._special )
// If a constructor, move the super-call up front
if( constructor && _clz._super!=null && ast instanceof MultiAST multi )
do_super(multi);
// Wrap in required "{}"
if( !(ast instanceof BlockAST) )
ast = new BlockAST(ast);
ast.jcode(_sb);
// Wrap in required "{}" block
BlockAST blk = ast instanceof BlockAST blk0 ? blk0 : new BlockAST(ast);
// This is a XTC constructor, which in Java is implemented as a factory
// method - which has the normal no-arg Java constructor already called -
// but now the XTC constructor method needs to end in a Java return.
if( constructor )
blk = blk.add(new ReturnAST(null,m,null,new RegAST(-5/*A_THIS*/,"this",_tclz)));
blk.jcode(_sb);
_sb.nl();
}

Expand Down Expand Up @@ -454,16 +498,16 @@ else if( p._special )
}
}

// Constructors call other constructors via factory method $constructor,
// skipping the allocation step.
private void do_super( MultiAST ast ) {
for( int i=0; i<ast._kids.length; i++ ) {
AST kid = ast._kids[i];
if( kid instanceof CallAST call &&
call._kids[0] instanceof ConAST con &&
((MethodCon)con._tcon).name().equals("construct") ) {
// Move ith kid to the front; rename as "super"
System.arraycopy(ast._kids,0,ast._kids,1,i);
ast._kids[0] = kid;
con._con = "super";
kid._kids[0] = new RegAST(-13,"super",_tclz._super);
ast._kids[i] = new InvokeAST("$construct",new XType[]{XCons.VOID},kid._kids);
return;
}
}
Expand Down
Loading

0 comments on commit c5e5d9b

Please sign in to comment.