changeset 650:d658eab7bf4c

finish compiling operators
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 31 Mar 2016 22:43:51 -0600
parents 37f0cf43f191
children 140cc5191b7a
files core/src/luan/impl/$Luan.java core/src/luan/impl/LuanJavaCompiler.java core/src/luan/impl/LuanParser.java
diffstat 3 files changed, 215 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
diff -r 37f0cf43f191 -r d658eab7bf4c core/src/luan/impl/$Luan.java
--- a/core/src/luan/impl/$Luan.java	Wed Mar 30 22:42:27 2016 -0600
+++ b/core/src/luan/impl/$Luan.java	Thu Mar 31 22:43:51 2016 -0600
@@ -1,5 +1,6 @@
 package luan.impl;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.ArrayList;
 import luan.Luan;
@@ -58,8 +59,120 @@
 		throw new LuanException("attempt to perform arithmetic on a "+Luan.type(o)+" value");
 	}
 
-	public static Boolean not(Object o) throws LuanException {
+	public static boolean not(Object o) throws LuanException {
 		return !Luan.checkBoolean(o);
 	}
 
+	private static Object arithmetic(LuanState luan,String op,Object o1,Object o2) throws LuanException {
+		LuanFunction fn = Luan.getBinHandler(op,o1,o2);
+		if( fn != null )
+			return Luan.first(fn.call(luan,new Object[]{o1,o2}));
+		String type = !(o1 instanceof Number) ? Luan.type(o1) : Luan.type(o2);
+		throw new LuanException("attempt to perform arithmetic on a "+type+" value");
+	}
+
+	public static Object pow(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number )
+			return Math.pow( ((Number)o1).doubleValue(), ((Number)o2).doubleValue() );
+		return arithmetic(luan,"__pow",o1,o2);
+	}
+
+	public static Object mul(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number )
+			return ((Number)o1).doubleValue() * ((Number)o2).doubleValue();
+		return arithmetic(luan,"__mul",o1,o2);
+	}
+
+	public static Object div(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number )
+			return ((Number)o1).doubleValue() / ((Number)o2).doubleValue();
+		return arithmetic(luan,"__div",o1,o2);
+	}
+
+	public static Object mod(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number ) {
+			double d1 = ((Number)o1).doubleValue();
+			double d2 = ((Number)o2).doubleValue();
+			return d1 - Math.floor(d1/d2)*d2;
+		}
+		return arithmetic(luan,"__mod",o1,o2);
+	}
+
+	public static Object add(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number )
+			return ((Number)o1).doubleValue() + ((Number)o2).doubleValue();
+		return arithmetic(luan,"__add",o1,o2);
+	}
+
+	public static Object sub(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number )
+			return ((Number)o1).doubleValue() - ((Number)o2).doubleValue();
+		return arithmetic(luan,"__sub",o1,o2);
+	}
+
+	public static Object concat(LuanState luan,Object o1,Object o2) throws LuanException {
+		LuanFunction fn = Luan.getBinHandler("__concat",o1,o2);
+		if( fn != null )
+			return Luan.first(fn.call(luan,new Object[]{o1,o2}));
+		String s1 = luan.toString(o1);
+		String s2 = luan.toString(o2);
+		return s1 + s2;
+	}
+
+	public static boolean eq(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 == o2 || o1 != null && o1.equals(o2) )
+			return true;
+		if( o1 instanceof Number && o2 instanceof Number ) {
+			Number n1 = (Number)o1;
+			Number n2 = (Number)o2;
+			return n1.doubleValue() == n2.doubleValue();
+		}
+		if( o1 instanceof byte[] && o2 instanceof byte[] ) {
+			byte[] b1 = (byte[])o1;
+			byte[] b2 = (byte[])o2;
+			return Arrays.equals(b1,b2);
+		}
+		if( !(o1 instanceof LuanTable && o2 instanceof LuanTable) )
+			return false;
+		LuanTable t1 = (LuanTable)o1;
+		LuanTable t2 = (LuanTable)o2;
+		LuanTable mt1 = t1.getMetatable();
+		LuanTable mt2 = t2.getMetatable();
+		if( mt1==null || mt2==null )
+			return false;
+		Object f = mt1.rawGet("__eq");
+		if( f == null || !f.equals(mt2.rawGet("__eq")) )
+			return false;
+		LuanFunction fn = Luan.checkFunction(f);
+		return Luan.checkBoolean( Luan.first(fn.call(luan,new Object[]{o1,o2})) );
+	}
+
+	public static boolean le(LuanState luan,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number ) {
+			Number n1 = (Number)o1;
+			Number n2 = (Number)o2;
+			return n1.doubleValue() <= n2.doubleValue();
+		}
+		if( o1 instanceof String && o2 instanceof String ) {
+			String s1 = (String)o1;
+			String s2 = (String)o2;
+			return s1.compareTo(s2) <= 0;
+		}
+		LuanFunction fn = Luan.getBinHandler("__le",o1,o2);
+		if( fn != null )
+			return Luan.checkBoolean( Luan.first(fn.call(luan,new Object[]{o1,o2})) );
+		fn = Luan.getBinHandler("__lt",o1,o2);
+		if( fn != null )
+			return !Luan.checkBoolean( Luan.first(fn.call(luan,new Object[]{o2,o1})) );
+		throw new LuanException( "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) );
+	}
+
+	public static boolean lt(LuanState luan,Object o1,Object o2) throws LuanException {
+		return Luan.isLessThan(luan,o1,o2);
+	}
+
+	public static boolean cnd(Object o) throws LuanException {
+		return !(o == null || Boolean.FALSE.equals(o));
+	}
+
 }
diff -r 37f0cf43f191 -r d658eab7bf4c core/src/luan/impl/LuanJavaCompiler.java
--- a/core/src/luan/impl/LuanJavaCompiler.java	Wed Mar 30 22:42:27 2016 -0600
+++ b/core/src/luan/impl/LuanJavaCompiler.java	Thu Mar 31 22:43:51 2016 -0600
@@ -57,8 +57,8 @@
 		outer:
 		for( int i=0; true; i++ ) {
 			if( i > max )
-				throw new RuntimeException();
-			if( byteCode[i]==1 && byteCode[i+1]*256 + byteCode[i+2] == len ) {
+				throw new RuntimeException("len="+len);
+			if( byteCode[i]==1 && (byteCode[i+1] << 8 | 0xFF & byteCode[i+2]) == len ) {
 				for( int j=i+3; j<i+3+len; j++ ) {
 					if( byteCode[j] != '$' )
 						continue outer;
diff -r 37f0cf43f191 -r d658eab7bf4c core/src/luan/impl/LuanParser.java
--- a/core/src/luan/impl/LuanParser.java	Wed Mar 30 22:42:27 2016 -0600
+++ b/core/src/luan/impl/LuanParser.java	Thu Mar 31 22:43:51 2016 -0600
@@ -181,7 +181,7 @@
 	FnDef Expression() throws ParseException {
 		Spaces(In.NOTHING);
 		int start = parser.begin();
-		Expressions expr = ExprZ(In.NOTHING);
+		Expressions expr = exp(ExprZ(In.NOTHING));
 		if( expr != null && parser.endOfInput() ) {
 			Stmt stmt = new ReturnStmt( expr );
 			return parser.success(newFnDef(start,stmt));
@@ -279,7 +279,7 @@
 		while(true) {
 			if( parser.match( "<%=" ) ) {
 				Spaces(inTemplate);
-				builder.add( RequiredExpr(inTemplate) );
+				builder.add( exp(RequiredExpr(inTemplate)) );
 				RequiredMatch( "%>" );
 			} else if( parser.match( "<%" ) ) {
 				Spaces(inTemplate);
@@ -355,7 +355,7 @@
 		List<String> names = RequiredNameList(In.NOTHING);
 		if( !Keyword("in",In.NOTHING) )
 			return parser.failure(null);
-		Expr expr = expr(RequiredExpr(In.NOTHING));
+		Expr expr = expr(exp(RequiredExpr(In.NOTHING)));
 		RequiredKeyword("do",In.NOTHING);
 		addSymbols(names);
 		Stmt loop = RequiredLoopBlock();
@@ -435,7 +435,7 @@
 		parser.begin();
 		if( !Keyword("while",In.NOTHING) )
 			return parser.failure(null);
-		Expr cnd = expr(RequiredExpr(In.NOTHING));
+		Expr cnd = expr(exp(RequiredExpr(In.NOTHING)));
 		RequiredKeyword("do",In.NOTHING);
 		Stmt loop = RequiredLoopBlock();
 		RequiredKeyword("end",In.NOTHING);
@@ -448,7 +448,7 @@
 			return parser.failure(null);
 		Stmt loop = RequiredLoopBlock();
 		RequiredKeyword("until",In.NOTHING);
-		Expr cnd = expr(RequiredExpr(In.NOTHING));
+		Expr cnd = expr(exp(RequiredExpr(In.NOTHING)));
 		return parser.success( new RepeatStmt(loop,cnd) );
 	}
 
@@ -468,7 +468,7 @@
 
 	private Stmt IfStmt2() throws ParseException {
 		parser.currentIndex();
-		Expr cnd = expr(RequiredExpr(In.NOTHING));
+		Expr cnd = expr(exp(RequiredExpr(In.NOTHING)));
 		RequiredKeyword("then",In.NOTHING);
 		Stmt thenBlock = RequiredBlock();
 		Stmt elseBlock;
@@ -507,7 +507,7 @@
 
 	private Stmt ExpressionsStmt() throws ParseException {
 		parser.begin();
-		Expressions exp = ExprZ(In.NOTHING);
+		Expressions exp = exp(ExprZ(In.NOTHING));
 		if( exp instanceof StmtExp )
 			return parser.success( new ExpressionsStmt(exp) );
 		return parser.failure(null);
@@ -521,102 +521,124 @@
 		return parser.success( var.settable() );
 	}
 
-	private Expressions RequiredExpr(In in) throws ParseException {
+	private ExpString RequiredExpr(In in) throws ParseException {
 		parser.begin();
 		return parser.success(required(ExprZ(in),"Bad expression"));
 	}
 
-	private Expressions ExprZ(In in) throws ParseException {
+	private ExpString ExprZ(In in) throws ParseException {
 		return OrExpr(in);
 	}
 
-	private Expressions OrExpr(In in) throws ParseException {
+	private ExpString OrExpr(In in) throws ParseException {
 		parser.begin();
-		Expressions exp = AndExpr(in);
+		ExpString exp = AndExpr(in);
 		if( exp==null )
 			return parser.failure(null);
 		while( Keyword("or",in) ) {
-			Expressions exp2 = AndExpr(in);
-			exp = new OrExpr( expr(exp), required(expr(exp2)) );
+			exp = exp.expr();
+			ExpString exp2 = required(RelExpr(in)).expr();
+			String code = "($Luan.cnd($cnd = " + exp.code + ") ? $cnd : (" + exp2.code + "))";
+			exp = new ExpString(code,true,true);
 		}
 		return parser.success(exp);
 	}
 
-	private Expressions AndExpr(In in) throws ParseException {
+	private ExpString AndExpr(In in) throws ParseException {
 		parser.begin();
-		Expressions exp = RelExpr(in);
+		ExpString exp = RelExpr(in);
 		if( exp==null )
 			return parser.failure(null);
 		while( Keyword("and",in) ) {
-			Expressions exp2 = RelExpr(in);
-			exp = new AndExpr( expr(exp), required(expr(exp2)) );
+			exp = exp.expr();
+			ExpString exp2 = required(RelExpr(in)).expr();
+			String code = "($Luan.cnd($cnd = " + exp.code + ") ? (" + exp2.code + ") : $cnd)";
+			exp = new ExpString(code,true,true);
 		}
 		return parser.success(exp);
 	}
 
-	private Expressions RelExpr(In in) throws ParseException {
+	private ExpString RelExpr(In in) throws ParseException {
 		parser.begin();
-		Expressions exp = ConcatExpr(in);
+		ExpString exp = ConcatExpr(in);
 		if( exp==null )
 			return parser.failure(null);
 		while(true) {
 			if( parser.match("==") ) {
 				Spaces(in);
-				Expressions exp2 = ConcatExpr(in);
-				exp = new EqExpr( expr(exp), required(expr(exp2)) );
+				exp = exp.expr();
+				ExpString exp2 = required(ConcatExpr(in)).expr();
+				String code = "$Luan.eq($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else if( parser.match("~=") ) {
 				Spaces(in);
-				Expressions exp2 = ConcatExpr(in);
-				exp = new NotExpr( new EqExpr( expr(exp), required(expr(exp2)) ) );
+				exp = exp.expr();
+				ExpString exp2 = required(ConcatExpr(in)).expr();
+				String code = "!$Luan.eq($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else if( parser.match("<=") ) {
 				Spaces(in);
-				Expressions exp2 = ConcatExpr(in);
-				exp = new LeExpr( expr(exp), required(expr(exp2)) );
+				exp = exp.expr();
+				ExpString exp2 = required(ConcatExpr(in)).expr();
+				String code = "$Luan.le($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else if( parser.match(">=") ) {
 				Spaces(in);
-				Expressions exp2 = ConcatExpr(in);
-				exp = new LeExpr( required(expr(exp2)), expr(exp) );
+				exp = exp.expr();
+				ExpString exp2 = required(ConcatExpr(in)).expr();
+				String code = "$Luan.le($luan," + exp2.code + "," + exp.code + ")";
+				exp = new ExpString(code,true,false);
 			} else if( parser.match("<") ) {
 				Spaces(in);
-				Expressions exp2 = ConcatExpr(in);
-				exp = new LtExpr( expr(exp), required(expr(exp2)) );
-			} else if( parser.match(">") ) {
+				exp = exp.expr();
+				ExpString exp2 = required(ConcatExpr(in)).expr();
+				String code = "$Luan.lt($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
+		} else if( parser.match(">") ) {
 				Spaces(in);
-				Expressions exp2 = ConcatExpr(in);
-				exp = new LtExpr( required(expr(exp2)), expr(exp) );
+				exp = exp.expr();
+				ExpString exp2 = required(ConcatExpr(in)).expr();
+				String code = "$Luan.lt($luan," + exp2.code + "," + exp.code + ")";
+				exp = new ExpString(code,true,false);
 			} else
 				break;
 		}
 		return parser.success(exp);
 	}
 
-	private Expressions ConcatExpr(In in) throws ParseException {
+	private ExpString ConcatExpr(In in) throws ParseException {
 		parser.begin();
-		Expressions exp = SumExpr(in);
+		ExpString exp = SumExpr(in);
 		if( exp==null )
 			return parser.failure(null);
 		if( parser.match("..") ) {
 			Spaces(in);
-			Expressions exp2 = ConcatExpr(in);
-			exp = new ConcatExpr( expr(exp), required(expr(exp2)) );
+			exp = exp.expr();
+			ExpString exp2 = required(ConcatExpr(in)).expr();
+			String code = "$Luan.concat($luan," + exp.code + "," + exp2.code + ")";
+			exp = new ExpString(code,true,false);
 		}
 		return parser.success(exp);
 	}
 
-	private Expressions SumExpr(In in) throws ParseException {
+	private ExpString SumExpr(In in) throws ParseException {
 		parser.begin();
-		Expressions exp = TermExpr(in);
+		ExpString exp = TermExpr(in);
 		if( exp==null )
 			return parser.failure(null);
 		while(true) {
 			if( parser.match('+') ) {
 				Spaces(in);
-				Expressions exp2 = TermExpr(in);
-				exp = new AddExpr( expr(exp), required(expr(exp2)) );
+				exp = exp.expr();
+				ExpString exp2 = required(TermExpr(in)).expr();
+				String code = "$Luan.add($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else if( Minus() ) {
 				Spaces(in);
-				Expressions exp2 = TermExpr(in);
-				exp = new SubExpr( expr(exp), required(expr(exp2)) );
+				exp = exp.expr();
+				ExpString exp2 = required(TermExpr(in)).expr();
+				String code = "$Luan.sub($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else
 				break;
 		}
@@ -628,25 +650,30 @@
 		return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure();
 	}
 
-	private Expressions TermExpr(In in) throws ParseException {
+	private ExpString TermExpr(In in) throws ParseException {
 		parser.begin();
-		ExpString expStr = UnaryExpr(in);
-		if( expStr==null )
+		ExpString exp = UnaryExpr(in);
+		if( exp==null )
 			return parser.failure(null);
-		Expressions exp = expStr.toExpressions();
 		while(true) {
 			if( parser.match('*') ) {
 				Spaces(in);
-				Expressions exp2 = required(UnaryExpr(in)).toExpressions();
-				exp = new MulExpr( expr(exp), expr(exp2) );
+				exp = exp.expr();
+				ExpString exp2 = required(UnaryExpr(in)).expr();
+				String code = "$Luan.mul($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else if( parser.match('/') ) {
 				Spaces(in);
-				Expressions exp2 = required(UnaryExpr(in)).toExpressions();
-				exp = new DivExpr( expr(exp), expr(exp2) );
+				exp = exp.expr();
+				ExpString exp2 = required(UnaryExpr(in)).expr();
+				String code = "$Luan.div($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else if( Mod() ) {
 				Spaces(in);
-				Expressions exp2 = required(UnaryExpr(in)).toExpressions();
-				exp = new ModExpr( expr(exp), expr(exp2) );
+				exp = exp.expr();
+				ExpString exp2 = required(UnaryExpr(in)).expr();
+				String code = "$Luan.mod($luan," + exp.code + "," + exp2.code + ")";
+				exp = new ExpString(code,true,false);
 			} else
 				break;
 		}
@@ -681,23 +708,25 @@
 			exp = new ExpString(code,true,false);
 			return parser.success(exp);
 		}
-		Expressions exp = PowExpr(in);
+		ExpString exp = PowExpr(in);
 		if( exp==null )
 			return parser.failure(null);
-		return parser.success(new ExpString(exp));
+		return parser.success(exp);
 	}
 
-	private Expressions PowExpr(In in) throws ParseException {
+	private ExpString PowExpr(In in) throws ParseException {
 		parser.begin();
 		Expressions exp = SingleExpr(in);
 		if( exp==null )
 			return parser.failure(null);
+		ExpString exp1 = new ExpString(exp);
 		if( parser.match('^') ) {
 			Spaces(in);
-			Expressions exp2 = PowExpr(in);
-			exp = new PowExpr( expr(exp), required(expr(exp2)) );
+			ExpString exp2 = required(PowExpr(in));
+			String code = "$Luan.pow($luan," + exp1.code + "," + exp2.code + ")";
+			exp1 = new ExpString(code,true,false);
 		}
-		return parser.success(exp);
+		return parser.success(exp1);
 	}
 
 	private Expressions SingleExpr(In in) throws ParseException {
@@ -790,11 +819,11 @@
 			exp = NameExpr(In.NOTHING);
 		if( exp!=null && parser.match('=') ) {
 			Spaces(In.NOTHING);
-			fields.add( new TableExpr.Field( exp, required(expr(ExprZ(In.NOTHING))) ) );
+			fields.add( new TableExpr.Field( exp, required(expr(exp(ExprZ(In.NOTHING)))) ) );
 			return parser.success();
 		}
 		parser.rollback();
-		Expressions exprs = ExprZ(In.NOTHING);
+		Expressions exprs = exp(ExprZ(In.NOTHING));
 		if( exprs != null ) {
 			builder.add(exprs);
 			return parser.success();
@@ -823,7 +852,7 @@
 		if( parser.match('(') ) {
 			In inParens = in.parens();
 			Spaces(inParens);
-			Expr exp = expr(RequiredExpr(inParens));
+			Expr exp = expr(exp(RequiredExpr(inParens)));
 			RequiredMatch(')');
 			Spaces(in);
 			return exprVar(exp);
@@ -983,7 +1012,7 @@
 			builder.add(exp);
 			return parser.success();
 		}
-		exp = ExprZ(in);
+		exp = exp(ExprZ(in));
 		if( exp==null )
 			return parser.failure();
 		builder.add(exp);
@@ -994,7 +1023,7 @@
 				builder.add(exp);
 				return parser.success();
 			}
-			builder.add( RequiredExpr(in) );
+			builder.add( exp(RequiredExpr(in)) );
 		}
 		return parser.success();
 	}
@@ -1004,7 +1033,7 @@
 		if( !parser.match('[') || parser.test("[") || parser.test("=") )
 			return parser.failure(null);
 		Spaces(In.NOTHING);
-		Expr exp = expr(RequiredExpr(In.NOTHING));
+		Expr exp = expr(exp(RequiredExpr(In.NOTHING)));
 		RequiredMatch(']');
 		Spaces(in);
 		return parser.success(exp);
@@ -1379,7 +1408,7 @@
 		}
 
 		ExpString expr() {
-			return isExpr ? this : new ExpString( "$Luan.first(" + code + ")", true, false );
+			return isExpr ? this : new ExpString( "$Luan.first(" + code + ")", true, isStmt );
 		}
 
 		Expressions toExpressions() {
@@ -1391,6 +1420,7 @@
 				+"\n"
 				+"public class " + className +" implements " + superClass + " {\n"
 				+"	@Override public Object eval(LuanStateImpl $luan) throws LuanException {\n"
+				+"		Object $cnd;\n"
 				+"		return " + code + ";\n"
 				+"	}\n"
 				+"}\n"
@@ -1409,4 +1439,8 @@
 		}
 	}
 
+	private static Expressions exp(ExpString expStr) {
+		return expStr==null ? null : expStr.toExpressions();
+	}
+
 }