-- Evaluation of static expressions. -- Copyright (C) 2002, 2003, 2004, 2005 Tristan Gingold -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . with Types; use Types; with Vhdl.Nodes; use Vhdl.Nodes; package Vhdl.Evaluation is -- Evaluation is about compile-time computation of expressions, such as -- 2 + 1 --> 3. This is (of course) possible only with locally (and some -- globally) static expressions. Evaluation is required during semantic -- analysis at many places (in fact those where locally static expression -- are required by the language). For example, the type of O'Range (N) -- depends on N, so we need to evaluate N. -- -- The result of evaluation is a literal (integer, enumeration, real, -- physical), a string or a simple aggregate. For scalar types, the -- result is therefore normalized (there is only one kind of result), but -- for array types, the result isn't: in general it will be a string, but -- it may be a simple aggregate. Strings are preferred (because they are -- more compact), but aren't possible in some cases. For example, the -- evaluation of "Text" & NUL cannot be a string. -- -- Some functions (like Eval_Static_Expr) simply returns a result (which -- may be a node of the expression), others returns a result and set the -- origin (Literal_Origin or Range_Origin) to remember the original -- expression that was evaluation. The original expression is kept so that -- it is possible to print the original tree. -- Get the value of a physical integer literal or unit. May propagate -- Constraint_Error. function Get_Physical_Value (Expr : Iir) return Int64; -- Get the parameter of an attribute, or 1 if doesn't exist. function Eval_Attribute_Parameter_Or_1 (Attr : Iir) return Natural; -- Evaluate the locally static expression EXPR (without checking that EXPR -- is locally static). Return a literal or an aggregate, without setting -- the origin, and do not modify EXPR. This can be used only to get the -- value of an expression, without replacing it. function Eval_Static_Expr (Expr: Iir) return Iir; -- Evaluate (ie compute) expression EXPR. -- EXPR is required to be a locally static expression, otherwise an error -- message is generated. -- The result is a literal with the origin set. function Eval_Expr (Expr: Iir) return Iir; -- Same as Eval_Expr, but if EXPR is not locally static, the result is -- EXPR. Also, if EXPR is null_iir, then null_iir is returned. -- The purpose of this function is to evaluate an expression only if it -- is locally static. function Eval_Expr_If_Static (Expr : Iir) return Iir; -- Concatenate all the elements of OPERANDS. -- The first element of OPERANDS is the rightest one, the last the -- leftest one. All the elements are concatenation operators. -- All the elements are static. function Eval_Concatenation (Operands : Iir_Array) return Iir; -- Evaluate a physical literal and return a normalized literal (using -- the primary unit as unit). function Eval_Physical_Literal (Expr : Iir) return Iir; -- Return TRUE if literal EXPR is in SUB_TYPE bounds. -- OVERFLOW is the value returned for overflow_literal. The default is -- False because an overflow is never within the bounds (by definition). -- But if you use this function to report an error, you prefer to -- get True as you don't want to report a second error. function Eval_Is_In_Bound (Expr : Iir; Sub_Type : Iir; Overflow : Boolean := False) return Boolean; -- Emit an error if EXPR violates SUB_TYPE bounds. procedure Eval_Check_Bound (Expr : Iir; Sub_Type : Iir); -- Same as Eval_Expr, but a range check with SUB_TYPE is performed after -- computation. function Eval_Expr_Check (Expr : Iir; Sub_Type : Iir) return Iir; -- Call Eval_Expr_Check only if EXPR is static. function Eval_Expr_Check_If_Static (Expr : Iir; Atype : Iir) return Iir; -- For a locally static range RNG (a range expression, a range attribute -- or a name that denotes a type or a subtype) returns its corresponding -- locally static range_expression. The bounds of the results are also -- literals. -- Return a range_expression or NULL_IIR for a non locally static range. function Eval_Static_Range (Rng : Iir) return Iir; -- Return a locally static range expression with the origin set for ARANGE. function Eval_Range (Arange : Iir) return Iir; -- If ARANGE is a locally static range, return locally static range -- expression (with the origin set), else return ARANGE. function Eval_Range_If_Static (Arange : Iir) return Iir; -- Emit an error if A_RANGE is not included in SUB_TYPE. A_RANGE can be -- a range expression, a range attribute or a name that denotes a discrete -- type or subtype. A_RANGE must be a locally static range. procedure Eval_Check_Range (A_Range : Iir; Sub_Type : Iir; Any_Dir : Boolean); -- Return TRUE if A_RANGE is compatible with SUB_TYPE. Compatibility is -- defined in LRM: -- -- LRM08 5.2 Scalar types -- A range constraint is /compatible/ with a subtype if each bound of the -- range belongs to the subtype or if the range constraint defines a null -- range. function Eval_Is_Range_In_Bound (A_Range : Iir; Sub_Type : Iir; Any_Dir : Boolean) return Boolean; -- Return TRUE iff VAL belongs to BOUND. function Eval_Int_In_Range (Val : Int64; Bound : Iir) return Boolean; -- Return the length of the discrete range CONSTRAINT. function Eval_Discrete_Range_Length (Constraint : Iir) return Int64; -- Return the length of SUB_TYPE. function Eval_Discrete_Type_Length (Sub_Type : Iir) return Int64; -- Get the left bound of a range constraint. -- Note: the range constraint may be an attribute or a subtype. function Eval_Discrete_Range_Left (Constraint : Iir) return Iir; -- Return true iff RNG is a null range. function Eval_Is_Null_Discrete_Range (Rng : Iir) return Boolean; -- Return the position of EXPR, ie the result of sub_type'pos (EXPR), where -- sub_type is the type of expr. -- EXPR must be of a discrete subtype. function Eval_Pos (Expr : Iir) return Int64; -- Return True iff L and R (scalar literals) are equal. function Eval_Is_Eq (L, R : Iir) return Boolean; -- Replace ORIGIN (an overflow literal) with extreme positive value (if -- IS_POS is true) or extreme negative value. function Build_Extreme_Value (Is_Pos : Boolean; Origin : Iir) return Iir; -- Create a Iir_Kind_Overflow node of type EXPR_TYPE for ORIGIN. function Build_Overflow (Origin : Iir; Expr_Type : Iir) return Iir; -- Fill VECT with choices from CHOICES_CHAIN: each position of CHOICE_RANGE -- is associated with its corresponding choice from CHOICES_CHAIN. -- VECT bounds must be 0 .. Len - 1, where Len is the length of -- CHOICE_RANGE. procedure Build_Array_Choices_Vector (Vect : out Iir_Array; Choice_Range : Iir; Choices_Chain : Iir); -- Create an array subtype from LEN and BASE_TYPE, according to rules -- of LRM93 7.3.2.2. (which are the same as LRM93 7.2.4). function Create_Unidim_Array_By_Length (Base_Type : Iir; Len : Int64; Loc : Iir) return Iir_Array_Subtype_Definition; -- Create a subtype of A_TYPE whose length is LEN. -- This is used to create subtypes for strings or aggregates. function Create_Range_Subtype_By_Length (A_Type : Iir; Len : Int64; Loc : Location_Type) return Iir; -- Compute ATYPE'value (VALUE) using origin ORIG, but without checking -- bounds. function Eval_Value_Attribute (Value : String; Atype : Iir; Orig : Iir) return Iir; -- From one-dimensional array expression PREFIX extract element at -- offset OFF (from 0 to length -
/* Copyright 2017 Jack Humbert
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "process_ucis.h"

qk_ucis_state_t qk_ucis_state;

void qk_ucis_start(void) {
  qk_ucis_state.count = 0;
  qk_ucis_state.in_progress = true;

  qk_ucis_start_user();
}

__attribute__((weak))
void qk_ucis_start_user(void) {
  unicode_input_start();
  register_hex(0x2328);
  unicode_input_finish();
}

__attribute__((weak))
void qk_ucis_success(uint8_t symbol_index) {
}

static bool is_uni_seq(char *seq) {
  uint8_t i;

  for (i = 0; seq[i]; i++) {
    uint16_t code;
    if (('1' <= seq[i]) && (seq[i] <= '0'))
      code = seq[i] - '1' + KC_1;
    else
      code = seq[i] - 'a' + KC_A;

    if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code)
      return false;
  }

  return (qk_ucis_state.codes[i] == KC_ENT ||
          qk_ucis_state.codes[i] == KC_SPC);
}

__attribute__((weak))
void qk_ucis_symbol_fallback (void) {
  for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) {
    uint8_t code = qk_ucis_state.codes[i];
    register_code(code);
    unregister_code(code);
    wait_ms(UNICODE_TYPE_DELAY);
  }
}

__attribute__((weak))
void qk_ucis_cancel(void) {
}

void register_ucis(const char *hex) {
  for(int i = 0; hex[i]; i++) {
    uint8_t kc = 0;
    char c = hex[i];

    switch (c) {
    case '0':
      kc = KC_0;
      break;
    case '1' ... '9':
      kc = c - '1' + KC_1;
      break;
    case 'a' ... 'f':
      kc = c - 'a' + KC_A;
      break;
    case 'A' ... 'F':
      kc = c - 'A' + KC_A;
      break;
    }

    if (kc) {
      register_code (kc);
      unregister_code (kc);
      wait_ms (UNICODE_TYPE_DELAY);
    }
  }
}

bool process_ucis (uint16_t keycode, keyrecord_t *record) {
  uint8_t i;

  if (!qk_ucis_state.in_progress)
    return true;

  if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH &&
      !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) {
    return false;
  }

  if (!record->event.pressed)
    return true;

  qk_ucis_state.codes[qk_ucis_state.count] = keycode;
  qk_ucis_state.count++;

  if (keycode == KC_BSPC) {
    if (qk_ucis_state.count >= 2) {
      qk_ucis_state.count -= 2;
      return true;
    } else {
      qk_ucis_state.count--;
      return false;
    }
  }

  if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) {
    bool symbol_found = false;

    for (i = qk_ucis_state.count; i > 0; i--) {
      register_code (KC_BSPC);
      unregister_code (KC_BSPC);
      wait_ms(UNICODE_TYPE_DELAY);
    }

    if (keycode == KC_ESC) {
      qk_ucis_state.in_progress = false;
      qk_ucis_cancel();
      return false;
    }

    unicode_input_start();
    for (i = 0; ucis_symbol_table[i].symbol; i++) {
      if (is_uni_seq (ucis_symbol_table[i].symbol)) {
        symbol_found = true;
        register_ucis(ucis_symbol_table[i].code + 2);
        break;
      }
    }
    if (!symbol_found) {
      qk_ucis_symbol_fallback();
    }
    unicode_input_finish();

    if (symbol_found) {
      qk_ucis_success(i);
    }

    qk_ucis_state.in_progress = false;
    return false;
  }
  return true;
}