summaryrefslogtreecommitdiffstats
path: root/idlc/source/astexpression.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'idlc/source/astexpression.cxx')
-rw-r--r--idlc/source/astexpression.cxx1327
1 files changed, 1327 insertions, 0 deletions
diff --git a/idlc/source/astexpression.cxx b/idlc/source/astexpression.cxx
new file mode 100644
index 000000000..1afa91dbf
--- /dev/null
+++ b/idlc/source/astexpression.cxx
@@ -0,0 +1,1327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <astexpression.hxx>
+#include <astconstant.hxx>
+#include <astscope.hxx>
+#include <errorhandler.hxx>
+
+#include <o3tl/float_int_conversion.hxx>
+#include <osl/diagnose.h>
+
+#include <limits.h>
+#include <float.h>
+#include <memory>
+
+AstExpression::AstExpression(ExprComb c, AstExpression* pExpr1, AstExpression* pExpr2)
+ : m_combOperator(c)
+ , m_subExpr1(pExpr1)
+ , m_subExpr2(pExpr2)
+{
+}
+
+AstExpression::AstExpression(sal_Int32 l)
+ : m_combOperator(ExprComb::NONE)
+{
+ m_exprValue.reset(new AstExprValue);
+ m_exprValue->et = ET_long;
+ m_exprValue->u.lval = l;
+}
+
+AstExpression::AstExpression(sal_Int32 l, ExprType et)
+ : m_combOperator(ExprComb::NONE)
+{
+ m_exprValue.reset(new AstExprValue);
+ m_exprValue->et = et;
+ m_exprValue->u.lval = l;
+}
+
+AstExpression::AstExpression(sal_Int64 h)
+ : m_combOperator(ExprComb::NONE)
+{
+ m_exprValue.reset(new AstExprValue);
+ m_exprValue->et = ET_hyper;
+ m_exprValue->u.hval = h;
+}
+
+AstExpression::AstExpression(sal_uInt64 uh)
+ : m_combOperator(ExprComb::NONE)
+{
+ m_exprValue.reset(new AstExprValue);
+ m_exprValue->et = ET_uhyper;
+ m_exprValue->u.uhval = uh;
+}
+
+AstExpression::AstExpression(double d)
+ : m_combOperator(ExprComb::NONE)
+{
+ m_exprValue.reset(new AstExprValue);
+ m_exprValue->et = ET_double;
+ m_exprValue->u.dval = d;
+}
+
+AstExpression::AstExpression(OString* scopedName)
+ : m_combOperator(ExprComb::Symbol)
+{
+ if (scopedName)
+ m_xSymbolicName = *scopedName;
+}
+
+AstExpression::~AstExpression() {}
+
+/*
+ * Perform the coercion from the given AstExprValue to the requested
+ * ExprType. Return an AstExprValue if successful, NULL if failed.
+ * must be done for hyper, uhyper
+ */
+static bool coerce_value(AstExprValue* ev, ExprType t)
+{
+ if (ev == nullptr)
+ return false;
+
+ switch (t)
+ {
+ case ET_short:
+ switch (ev->et)
+ {
+ case ET_short:
+ return true;
+ case ET_ushort:
+ {
+ if (ev->u.usval > SAL_MAX_INT16)
+ return false;
+ auto tmp = static_cast<sal_Int16>(ev->u.usval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_long:
+ {
+ if (ev->u.lval < SAL_MIN_INT16 || ev->u.lval > SAL_MAX_INT16)
+ return false;
+ auto tmp = static_cast<sal_Int16>(ev->u.lval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_ulong:
+ {
+ if (ev->u.ulval > SAL_MAX_INT16)
+ return false;
+ auto tmp = static_cast<sal_Int16>(ev->u.ulval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_hyper:
+ {
+ if (ev->u.hval < SAL_MIN_INT16 || ev->u.hval > SAL_MAX_INT16)
+ return false;
+ auto tmp = static_cast<sal_Int16>(ev->u.hval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_uhyper:
+ {
+ if (ev->u.uhval > SAL_MAX_INT16)
+ return false;
+ auto tmp = static_cast<sal_Int16>(ev->u.uhval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_boolean:
+ {
+ auto tmp = static_cast<sal_Int16>(ev->u.bval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_float:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT16)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_INT16)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_Int16>(ev->u.fval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_double:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT16)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_INT16)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_Int16>(ev->u.dval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_byte:
+ {
+ auto tmp = static_cast<sal_Int16>(ev->u.byval);
+ ev->u.sval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_ushort:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ if (ev->u.sval < 0)
+ return false;
+ auto tmp = static_cast<sal_uInt16>(ev->u.sval);
+ ev->u.usval = tmp;
+ ev->et = ET_ushort;
+ return true;
+ }
+ case ET_ushort:
+ return true;
+ case ET_long:
+ {
+ if (ev->u.lval < 0 || ev->u.lval > SAL_MAX_UINT16)
+ return false;
+ auto tmp = static_cast<sal_uInt16>(ev->u.lval);
+ ev->u.usval = tmp;
+ ev->et = ET_ushort;
+ return true;
+ }
+ case ET_ulong:
+ {
+ if (ev->u.ulval > SAL_MAX_UINT16)
+ return false;
+ auto tmp = static_cast<sal_uInt16>(ev->u.ulval);
+ ev->u.usval = tmp;
+ ev->et = ET_ushort;
+ return true;
+ }
+ case ET_hyper:
+ {
+ if (ev->u.hval < 0 || ev->u.hval > SAL_MAX_UINT16)
+ return false;
+ auto tmp = static_cast<sal_uInt16>(ev->u.hval);
+ ev->u.usval = tmp;
+ ev->et = ET_ushort;
+ return true;
+ }
+ case ET_uhyper:
+ {
+ if (ev->u.uhval > SAL_MAX_UINT16)
+ return false;
+ auto tmp = static_cast<sal_uInt16>(ev->u.uhval);
+ ev->u.usval = tmp;
+ ev->et = ET_ushort;
+ return true;
+ }
+ case ET_boolean:
+ {
+ auto tmp = static_cast<sal_uInt16>(ev->u.bval);
+ ev->u.usval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_float:
+ {
+ if (ev->u.fval < 0.0
+ || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT16))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_uInt16>(ev->u.fval);
+ ev->u.usval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_double:
+ {
+ if (ev->u.dval < 0.0
+ || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT16))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_uInt16>(ev->u.dval);
+ ev->u.usval = tmp;
+ ev->et = ET_short;
+ return true;
+ }
+ case ET_byte:
+ {
+ auto tmp = static_cast<sal_uInt16>(ev->u.byval);
+ ev->u.usval = tmp;
+ ev->et = ET_ushort;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_long:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ auto tmp = static_cast<sal_Int32>(ev->u.sval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_ushort:
+ {
+ auto tmp = static_cast<sal_Int32>(ev->u.usval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_long:
+ return true;
+ case ET_ulong:
+ {
+ if (ev->u.ulval > SAL_MAX_INT32)
+ return false;
+ auto tmp = static_cast<sal_Int32>(ev->u.ulval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_hyper:
+ {
+ if (ev->u.hval < SAL_MIN_INT32 || ev->u.hval > SAL_MAX_INT32)
+ return false;
+ auto tmp = static_cast<sal_Int32>(ev->u.hval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_uhyper:
+ {
+ if (ev->u.uhval > SAL_MAX_INT32)
+ return false;
+ auto tmp = static_cast<sal_Int32>(ev->u.uhval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_boolean:
+ {
+ auto tmp = static_cast<sal_Int32>(ev->u.bval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_float:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT32)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_INT32)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_Int32>(ev->u.fval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_double:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT32)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_INT32)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_Int32>(ev->u.dval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_byte:
+ {
+ auto tmp = static_cast<sal_Int32>(ev->u.byval);
+ ev->u.lval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_ulong:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ if (ev->u.sval < 0)
+ return false;
+ auto tmp = static_cast<sal_uInt32>(ev->u.sval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_ushort:
+ {
+ auto tmp = static_cast<sal_uInt32>(ev->u.usval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_long:
+ {
+ if (ev->u.lval < 0)
+ return false;
+ auto tmp = static_cast<sal_uInt32>(ev->u.lval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_ulong:
+ return true;
+ case ET_hyper:
+ {
+ if (ev->u.hval < 0 || ev->u.hval > SAL_MAX_UINT32)
+ return false;
+ auto tmp = static_cast<sal_uInt32>(ev->u.hval);
+ ev->u.lval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_uhyper:
+ {
+ if (ev->u.uhval > SAL_MAX_UINT32)
+ return false;
+ auto tmp = static_cast<sal_uInt32>(ev->u.uhval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_boolean:
+ {
+ auto tmp = static_cast<sal_uInt32>(ev->u.bval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_float:
+ {
+ if (ev->u.fval < 0.0
+ || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT32))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_uInt32>(ev->u.fval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_double:
+ {
+ if (ev->u.dval < 0.0
+ || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT32))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_uInt32>(ev->u.dval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ case ET_byte:
+ {
+ auto tmp = static_cast<sal_uInt32>(ev->u.byval);
+ ev->u.ulval = tmp;
+ ev->et = ET_ulong;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_hyper:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ auto tmp = static_cast<sal_Int64>(ev->u.sval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ case ET_ushort:
+ {
+ auto tmp = static_cast<sal_Int64>(ev->u.usval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ case ET_long:
+ {
+ auto tmp = static_cast<sal_Int64>(ev->u.lval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ case ET_ulong:
+ {
+ auto tmp = static_cast<sal_Int64>(ev->u.ulval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ case ET_hyper:
+ return true;
+ case ET_uhyper:
+ {
+ if (ev->u.uhval > SAL_MAX_INT64)
+ return false;
+ auto tmp = static_cast<sal_Int64>(ev->u.uhval);
+ ev->u.hval = tmp;
+ ev->et = ET_long;
+ return true;
+ }
+ case ET_boolean:
+ {
+ auto tmp = static_cast<sal_Int64>(ev->u.bval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ case ET_float:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT64)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_INT64)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_Int64>(ev->u.fval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ case ET_double:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT64)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_INT64)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_Int64>(ev->u.dval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ case ET_byte:
+ {
+ auto tmp = static_cast<sal_Int64>(ev->u.byval);
+ ev->u.hval = tmp;
+ ev->et = ET_hyper;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_uhyper:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ if (ev->u.sval < 0)
+ return false;
+ auto tmp = static_cast<sal_uInt64>(ev->u.sval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_ushort:
+ {
+ auto tmp = static_cast<sal_uInt64>(ev->u.usval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_long:
+ {
+ if (ev->u.lval < 0)
+ return false;
+ auto tmp = static_cast<sal_uInt64>(ev->u.lval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_ulong:
+ {
+ auto tmp = static_cast<sal_uInt64>(ev->u.ulval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_hyper:
+ {
+ if (ev->u.hval < 0)
+ return false;
+ auto tmp = static_cast<sal_uInt64>(ev->u.hval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_uhyper:
+ return true;
+ case ET_boolean:
+ {
+ auto tmp = static_cast<sal_uInt64>(ev->u.bval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_float:
+ {
+ if (ev->u.fval < 0.0
+ || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT64))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_uInt64>(ev->u.fval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_double:
+ {
+ if (ev->u.dval < 0.0
+ || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT64))
+ {
+ return false;
+ }
+ auto tmp = static_cast<sal_uInt64>(ev->u.dval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ case ET_byte:
+ {
+ auto tmp = static_cast<sal_uInt64>(ev->u.byval);
+ ev->u.uhval = tmp;
+ ev->et = ET_uhyper;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_boolean:
+ switch (ev->et)
+ {
+ case ET_short:
+ ev->u.bval = ev->u.sval != 0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_ushort:
+ ev->u.bval = ev->u.usval != 0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_long:
+ ev->u.bval = ev->u.lval != 0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_ulong:
+ ev->u.bval = ev->u.ulval != 0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_hyper:
+ ev->u.bval = ev->u.hval != 0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_uhyper:
+ ev->u.bval = ev->u.uhval != 0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_boolean:
+ return true;
+ case ET_float:
+ ev->u.bval = ev->u.fval != 0.0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_double:
+ ev->u.bval = ev->u.dval != 0.0;
+ ev->et = ET_boolean;
+ return true;
+ case ET_byte:
+ ev->u.bval = ev->u.byval != 0;
+ ev->et = ET_boolean;
+ return true;
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_float:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ auto tmp = static_cast<float>(ev->u.sval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ case ET_ushort:
+ {
+ auto tmp = static_cast<float>(ev->u.usval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ case ET_long:
+ {
+ auto tmp = static_cast<float>(ev->u.lval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ case ET_ulong:
+ {
+ auto tmp = static_cast<float>(ev->u.ulval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ case ET_hyper:
+ {
+ auto tmp = static_cast<float>(ev->u.hval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ case ET_uhyper:
+ {
+ if (static_cast<float>(ev->u.ulval) > FLT_MAX)
+ return false;
+ auto tmp = static_cast<float>(ev->u.ulval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ case ET_boolean:
+ ev->u.fval = ev->u.bval ? 1.0f : 0.0f;
+ ev->et = ET_float;
+ return true;
+ case ET_float:
+ return true;
+ case ET_double:
+ {
+ if (static_cast<float>(ev->u.dval) > FLT_MAX
+ || static_cast<float>(ev->u.dval) < -FLT_MAX)
+ return false;
+ auto tmp = static_cast<float>(ev->u.dval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ case ET_byte:
+ {
+ auto tmp = static_cast<float>(ev->u.byval);
+ ev->u.fval = tmp;
+ ev->et = ET_float;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_double:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ auto tmp = static_cast<double>(ev->u.sval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ case ET_ushort:
+ {
+ auto tmp = static_cast<double>(ev->u.usval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ case ET_long:
+ {
+ auto tmp = static_cast<double>(ev->u.lval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ case ET_ulong:
+ {
+ auto tmp = static_cast<double>(ev->u.ulval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ case ET_hyper:
+ {
+ auto tmp = static_cast<double>(ev->u.hval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ case ET_uhyper:
+ {
+ if (ev->u.dval > FLT_MAX || ev->u.dval < -FLT_MAX)
+ return false;
+ auto tmp = static_cast<double>(ev->u.ulval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ case ET_boolean:
+ ev->u.dval = ev->u.bval ? 1.0 : 0.0;
+ ev->et = ET_double;
+ return true;
+ case ET_float:
+ {
+ auto tmp = static_cast<double>(ev->u.fval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ case ET_double:
+ return true;
+ case ET_byte:
+ {
+ auto tmp = static_cast<double>(ev->u.byval);
+ ev->u.dval = tmp;
+ ev->et = ET_double;
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ case ET_byte:
+ switch (ev->et)
+ {
+ case ET_short:
+ {
+ if (ev->u.sval < SAL_MIN_INT8 || ev->u.sval > SAL_MAX_UINT8)
+ return false;
+ auto tmp = static_cast<unsigned char>(ev->u.sval);
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_ushort:
+ {
+ if (ev->u.usval > SAL_MAX_UINT8)
+ return false;
+ auto tmp = static_cast<unsigned char>(ev->u.usval);
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_long:
+ {
+ if (ev->u.lval < SAL_MIN_INT8 || ev->u.lval > SAL_MAX_UINT8)
+ return false;
+ auto tmp = static_cast<unsigned char>(ev->u.lval);
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_ulong:
+ {
+ if (ev->u.ulval > SAL_MAX_UINT8)
+ return false;
+ auto tmp = static_cast<unsigned char>(ev->u.ulval);
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_hyper:
+ {
+ if (ev->u.hval < SAL_MIN_INT8 || ev->u.hval > SAL_MAX_UINT8)
+ return false;
+ auto tmp = static_cast<unsigned char>(ev->u.hval);
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_uhyper:
+ {
+ if (ev->u.uhval > SAL_MAX_UINT8)
+ return false;
+ auto tmp = static_cast<unsigned char>(ev->u.uhval);
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_boolean:
+ ev->u.byval = ev->u.bval ? 1 : 0;
+ ev->et = ET_byte;
+ return true;
+ case ET_float:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT8)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT8)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<unsigned char>(static_cast<sal_Int32>(ev->u.fval));
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_double:
+ {
+ if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT8)
+ && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT8)))
+ {
+ return false;
+ }
+ auto tmp = static_cast<unsigned char>(static_cast<sal_Int32>(ev->u.dval));
+ ev->u.byval = tmp;
+ ev->et = ET_byte;
+ return true;
+ }
+ case ET_byte:
+ return true;
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+}
+
+bool AstExpression::coerce(ExprType t)
+{
+ /*
+ * Is it already of the right type?
+ */
+ if (m_exprValue != nullptr && m_exprValue->et == t)
+ return true;
+ /*
+ * OK, must coerce
+ *
+ * First, evaluate it, then try to coerce result type
+ * If already evaluated, return the result
+ */
+ evaluate();
+ if (m_exprValue == nullptr)
+ return false;
+
+ if (!coerce_value(m_exprValue.get(), t))
+ m_exprValue.reset();
+
+ return m_exprValue != nullptr;
+}
+
+bool AstExpression::compareLong(AstExpression* pExpr)
+{
+ bool bRet = false;
+ if (m_combOperator != pExpr->m_combOperator)
+ return bRet;
+ evaluate();
+ pExpr->evaluate();
+ if (m_exprValue == nullptr || pExpr->getExprValue() == nullptr)
+ return bRet;
+ if (m_exprValue->et != pExpr->getExprValue()->et)
+ return bRet;
+ switch (m_exprValue->et)
+ {
+ case ET_long:
+ bRet = m_exprValue->u.lval == pExpr->getExprValue()->u.lval;
+ break;
+ default:
+ OSL_ASSERT(false);
+ bRet = false;
+ break;
+ }
+ return bRet;
+}
+
+void AstExpression::evaluate()
+{
+ /*
+ * Already evaluated?
+ */
+ if (m_exprValue != nullptr)
+ return;
+ /*
+ * OK, must evaluate operator
+ */
+ switch (m_combOperator)
+ {
+ case ExprComb::Add:
+ case ExprComb::Minus:
+ case ExprComb::Mul:
+ case ExprComb::Div:
+ case ExprComb::Mod:
+ m_exprValue = eval_bin_op();
+ break;
+ case ExprComb::Or:
+ case ExprComb::Xor:
+ case ExprComb::And:
+ case ExprComb::Left:
+ case ExprComb::Right:
+ m_exprValue = eval_bit_op();
+ break;
+ case ExprComb::UPlus:
+ case ExprComb::UMinus:
+ m_exprValue = eval_un_op();
+ break;
+ case ExprComb::Symbol:
+ m_exprValue = eval_symbol();
+ break;
+ case ExprComb::NONE:
+ break;
+ }
+}
+
+std::unique_ptr<AstExprValue> AstExpression::eval_bin_op()
+{
+ ExprType eType = ET_double;
+
+ if (m_combOperator == ExprComb::Mod)
+ eType = ET_hyper;
+
+ if (m_subExpr1 == nullptr || m_subExpr2 == nullptr)
+ return nullptr;
+ m_subExpr1->evaluate();
+ if (m_subExpr1->getExprValue() == nullptr)
+ return nullptr;
+ if (!m_subExpr1->coerce(eType))
+ return nullptr;
+ m_subExpr2->evaluate();
+ if (m_subExpr2->getExprValue() == nullptr)
+ return nullptr;
+ if (!m_subExpr2->coerce(eType))
+ return nullptr;
+
+ std::unique_ptr<AstExprValue> retval(new AstExprValue);
+ retval->et = eType;
+
+ switch (m_combOperator)
+ {
+ case ExprComb::Mod:
+ if (m_subExpr2->getExprValue()->u.hval == 0)
+ return nullptr;
+ retval->u.hval
+ = m_subExpr1->getExprValue()->u.hval % m_subExpr2->getExprValue()->u.hval;
+ break;
+ case ExprComb::Add:
+ retval->u.dval
+ = m_subExpr1->getExprValue()->u.dval + m_subExpr2->getExprValue()->u.dval;
+ break;
+ case ExprComb::Minus:
+ retval->u.dval
+ = m_subExpr1->getExprValue()->u.dval - m_subExpr2->getExprValue()->u.dval;
+ break;
+ case ExprComb::Mul:
+ retval->u.dval
+ = m_subExpr1->getExprValue()->u.dval * m_subExpr2->getExprValue()->u.dval;
+ break;
+ case ExprComb::Div:
+ if (m_subExpr2->getExprValue()->u.dval == 0.0)
+ return nullptr;
+ retval->u.dval
+ = m_subExpr1->getExprValue()->u.dval / m_subExpr2->getExprValue()->u.dval;
+ break;
+ default:
+ return nullptr;
+ }
+
+ return retval;
+}
+
+std::unique_ptr<AstExprValue> AstExpression::eval_bit_op()
+{
+ if (m_subExpr1 == nullptr || m_subExpr2 == nullptr)
+ return nullptr;
+ m_subExpr1->evaluate();
+ if (m_subExpr1->getExprValue() == nullptr)
+ return nullptr;
+ if (!m_subExpr1->coerce(ET_long))
+ return nullptr;
+ m_subExpr2->evaluate();
+ if (m_subExpr2->getExprValue() == nullptr)
+ return nullptr;
+ if (!m_subExpr2->coerce(ET_long))
+ return nullptr;
+
+ std::unique_ptr<AstExprValue> retval(new AstExprValue);
+ retval->et = ET_long;
+
+ switch (m_combOperator)
+ {
+ case ExprComb::Or:
+ retval->u.lval
+ = m_subExpr1->getExprValue()->u.lval | m_subExpr2->getExprValue()->u.lval;
+ break;
+ case ExprComb::Xor:
+ retval->u.lval
+ = m_subExpr1->getExprValue()->u.lval ^ m_subExpr2->getExprValue()->u.lval;
+ break;
+ case ExprComb::And:
+ retval->u.lval
+ = m_subExpr1->getExprValue()->u.lval & m_subExpr2->getExprValue()->u.lval;
+ break;
+ case ExprComb::Left:
+ retval->u.lval = m_subExpr1->getExprValue()->u.lval
+ << m_subExpr2->getExprValue()->u.lval;
+ break;
+ case ExprComb::Right:
+ retval->u.lval
+ = m_subExpr1->getExprValue()->u.lval >> m_subExpr2->getExprValue()->u.lval;
+ break;
+ default:
+ return nullptr;
+ }
+
+ return retval;
+}
+
+std::unique_ptr<AstExprValue> AstExpression::eval_un_op()
+{
+ if (m_subExpr1 == nullptr)
+ return nullptr;
+ m_subExpr1->evaluate();
+ if (m_subExpr1->getExprValue() == nullptr)
+ return nullptr;
+ if (!m_subExpr1->coerce(ET_double))
+ return nullptr;
+
+ std::unique_ptr<AstExprValue> retval(new AstExprValue);
+ retval->et = ET_double;
+
+ switch (m_combOperator)
+ {
+ case ExprComb::UPlus:
+ retval->u.lval = m_subExpr1->getExprValue()->u.lval;
+ break;
+ case ExprComb::UMinus:
+ retval->u.lval = -(m_subExpr1->getExprValue()->u.lval);
+ break;
+ default:
+ return nullptr;
+ }
+
+ return retval;
+}
+
+std::unique_ptr<AstExprValue> AstExpression::eval_symbol()
+{
+ AstScope* pScope = nullptr;
+ AstDeclaration* pDecl;
+ AstConstant* pConst;
+
+ /*
+ * Is there a symbol stored?
+ */
+ if (!m_xSymbolicName)
+ {
+ ErrorHandler::evalError(this);
+ return nullptr;
+ }
+ /*
+ * Get current scope for lookup
+ */
+ if (idlc()->scopes()->depth() > 0)
+ pScope = idlc()->scopes()->topNonNull();
+ if (!pScope)
+ {
+ ErrorHandler::lookupError(*m_xSymbolicName);
+ return nullptr;
+ }
+ /*
+ * Do lookup
+ */
+ pDecl = pScope->lookupByName(*m_xSymbolicName);
+ if (pDecl == nullptr)
+ {
+ ErrorHandler::lookupError(*m_xSymbolicName);
+ return nullptr;
+ }
+ /*
+ * Is it a constant?
+ */
+ if (pDecl->getNodeType() != NT_const && pDecl->getNodeType() != NT_enum_val)
+ {
+ ErrorHandler::constantExpected(pDecl, *m_xSymbolicName);
+ return nullptr;
+ }
+ if (!ErrorHandler::checkPublished(pDecl))
+ {
+ return nullptr;
+ }
+ /*
+ * OK, now evaluate the constant we just got, to produce its value
+ */
+ pConst = static_cast<AstConstant*>(pDecl);
+ pConst->getConstValue()->evaluate();
+ auto const val = pConst->getConstValue()->getExprValue();
+ return val == nullptr ? nullptr : std::make_unique<AstExprValue>(*val);
+}
+
+OString AstExpression::toString()
+{
+ OString exprStr;
+ if (m_combOperator == ExprComb::Symbol)
+ return m_xSymbolicName ? *m_xSymbolicName : OString("<Undefined Name>");
+
+ if (m_exprValue)
+ {
+ switch (m_exprValue->et)
+ {
+ case ET_short:
+ return OString::number(m_exprValue->u.sval);
+ case ET_ushort:
+ return OString::number(m_exprValue->u.usval);
+ case ET_long:
+ return OString::number(m_exprValue->u.lval);
+ case ET_ulong:
+ return OString::number(m_exprValue->u.ulval);
+ case ET_hyper:
+ return OString::number(m_exprValue->u.hval);
+ case ET_uhyper:
+ return OString::number(m_exprValue->u.uhval);
+ case ET_float:
+ return OString::number(m_exprValue->u.fval);
+ case ET_double:
+ return OString::number(m_exprValue->u.dval);
+ case ET_byte:
+ return OString::number(m_exprValue->u.byval);
+ case ET_boolean:
+ if (m_exprValue->u.lval == 0)
+ return "FALSE";
+ else
+ return "TRUE";
+ default:
+ OSL_ASSERT(false);
+ return OString();
+ }
+ }
+
+ switch (m_combOperator)
+ {
+ case ExprComb::UPlus:
+ exprStr += "+";
+ break;
+ case ExprComb::UMinus:
+ exprStr += "-";
+ break;
+ default:
+ break;
+ }
+ if (m_subExpr1)
+ exprStr += m_subExpr1->toString();
+ switch (m_combOperator)
+ {
+ case ExprComb::Add:
+ exprStr += " + ";
+ break;
+ case ExprComb::Minus:
+ exprStr += " - ";
+ break;
+ case ExprComb::Mul:
+ exprStr += " * ";
+ break;
+ case ExprComb::Div:
+ exprStr += " / ";
+ break;
+ case ExprComb::Mod:
+ exprStr += " % ";
+ break;
+ case ExprComb::Or:
+ exprStr += " | ";
+ break;
+ case ExprComb::Xor:
+ exprStr += " ^ ";
+ break;
+ case ExprComb::And:
+ exprStr += " & ";
+ break;
+ case ExprComb::Left:
+ exprStr += " << ";
+ break;
+ case ExprComb::Right:
+ exprStr += " >> ";
+ break;
+ default:
+ break;
+ }
+
+ if (m_subExpr2)
+ exprStr += m_subExpr2->toString();
+
+ return exprStr;
+}
+
+// Convert the type of an AST_Expression to a char *
+const char* exprTypeToString(ExprType t)
+{
+ switch (t)
+ {
+ case ET_short:
+ return "short";
+ case ET_ushort:
+ return "unsigned short";
+ case ET_long:
+ return "long";
+ case ET_ulong:
+ return "unsigned long";
+ case ET_hyper:
+ return "hyper";
+ case ET_uhyper:
+ return "unsigned hyper";
+ case ET_float:
+ return "float";
+ case ET_double:
+ return "double";
+ case ET_char:
+ return "char";
+ case ET_byte:
+ return "byte";
+ case ET_boolean:
+ return "boolean";
+ case ET_string:
+ return "string";
+ case ET_any:
+ return "any";
+ case ET_type:
+ return "type";
+ case ET_void:
+ return "void";
+ case ET_none:
+ return "none";
+ }
+
+ return "unknown";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */