
// // Copyright (c) 2006, Brian Frank and Andy Frank // Licensed under the Academic Free License version 3.0 // // History: // 23 Oct 06 Brian Frank Creation // ** ** ConstantFolder is used to implement constant folding optimizations ** where known literals and operations can be performed ahead of time ** by the compiler. ** class ConstantFolder : CompilerSupport { ////////////////////////////////////////////////////////////////////////// // Construction ////////////////////////////////////////////////////////////////////////// ** ** Constructor ** new make(Compiler compiler) : super(compiler) { } ////////////////////////////////////////////////////////////////////////// // Resolve ////////////////////////////////////////////////////////////////////////// ** ** Check shortcut expression for constant folding ** Expr fold(CallExpr call) { // there are certain methods we never optimize name := call.name if (never.containsKey(name)) return call // check if target is constant target := exprToConst(call.target) if (target == null) return call // check if all the parameters are constant Obj[] args := null for (i:=0; i<call.args.size; ++i) { arg := exprToConst(call.args[i]) if (arg == null) return call if (i === 0) args = [,] args.add(arg) } // everything is constant, so try to find an instance method method := target.type.method(name, false) if (method == null || method.isStatic) return call if (call.args.size != method.params.size) { if (call.args.size >= method.params.size || !method.params[call.args.size].hasDefault) return call } // try to invoke the method to get the result Obj result := null try { result = method.callOn(target, args) } catch { return call } // always skip constant folding on testSys if (compiler.pod.name == "testSys") return call // try to map result to literal return constToExpr(call, result) } private Obj exprToConst(Expr expr) { if (expr == null) return null switch (expr.id) { case ExprId.intLiteral: return ((LiteralExpr)expr).val case ExprId.floatLiteral: return ((LiteralExpr)expr).val case ExprId.decimalLiteral: return ((LiteralExpr)expr).val case ExprId.strLiteral: return ((LiteralExpr)expr).val case ExprId.durationLiteral: return ((LiteralExpr)expr).val default: return null } } private Expr constToExpr(Expr orig, Obj val) { if (val is Int) return LiteralExpr.make(orig.location, ExprId.intLiteral, ns.intType, val) if (val is Float) return LiteralExpr.make(orig.location, ExprId.floatLiteral, ns.floatType, val) if (val is Decimal) return LiteralExpr.make(orig.location, ExprId.decimalLiteral, ns.decimalType, val) if (val is Str) return LiteralExpr.make(orig.location, ExprId.strLiteral, ns.strType, val) if (val is Duration) return LiteralExpr.make(orig.location, ExprId.durationLiteral, ns.durationType, val) return orig } private const static Str:Int never := ["compare":1, "equal":1, "hash":1, "intern":1] }