-- JaMTypeImpl.mesa
-- Last edit by Doug Wyatt,  8-Oct-81  0:16:49

DIRECTORY
  JaMBasic USING [Object, ObType],
  JaMInternal USING [Frame, Stack],
  JaMOps USING [DictLength, Equality, Error, Install, InstallReason, limitchk,
    MakeName, NameToString, Pop, Push, PushBoolean, PushInteger, PushReal,
    rangechk, RegisterExplicit, StringCompare, StringToken, Top, typechk],
  Inline USING [LowHalf],
  Real USING [Fix];

JaMTypeImpl: PROGRAM
IMPORTS JaMOps, Inline, Real
EXPORTS JaMOps = {
OPEN JaMOps, JaMInternal, JaMBasic;

-- Globals

typeName: ARRAY ObType OF name Object;

-- Procedures

Length: PUBLIC PROC[ob: Object] RETURNS[CARDINAL] = {
  len: CARDINAL ← 1; -- default length is 1
  WITH ob:ob SELECT FROM
    string => len ← ob.length;
    array => len ← ob.length;
    dict => len ← DictLength[ob];
    name => len ← NameToString[ob].length;
    ENDCASE;
  RETURN[len];
  };

Compare: PUBLIC PROC[a,b: Object] RETURNS[Equality] = {
  -- Checks for equality of values of objects
  WITH a:a SELECT FROM
    null => WITH b:b SELECT FROM
      null => RETURN[T];
      ENDCASE;
    integer => WITH b:b SELECT FROM
      integer => RETURN[IF a.ivalue=b.ivalue THEN T ELSE F];
      real => RETURN[IF a.ivalue=b.rvalue THEN T ELSE F];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[IF a.rvalue=b.ivalue THEN T ELSE F];
      real => RETURN[IF a.rvalue=b.rvalue THEN T ELSE F];
      ENDCASE;
    boolean => WITH b:b SELECT FROM
      boolean => RETURN[IF a.bvalue=b.bvalue THEN T ELSE F];
      ENDCASE;
    name => WITH b:b SELECT FROM
      name => RETURN[IF a.id=b.id THEN T ELSE F];
      string => RETURN[IF StringMatch[NameToString[a],b] THEN T ELSE F];
      ENDCASE;
    string => WITH b:b SELECT FROM
      name => RETURN[IF StringMatch[a,NameToString[b]] THEN T ELSE F];
      string => RETURN[IF StringMatch[a,b] THEN T ELSE F];
      ENDCASE;
    stream => WITH b:b SELECT FROM
      stream => RETURN[IF a.index=b.index AND a.stamp=b.stamp THEN T ELSE F];
      ENDCASE;
    command => WITH b:b SELECT FROM
      command => RETURN[IF a.index=b.index THEN T ELSE F];
      ENDCASE;
    dict => WITH b:b SELECT FROM
      dict => RETURN[IF a.dict=b.dict THEN T ELSE F];
      ENDCASE;
    array => WITH b:b SELECT FROM
      array => RETURN[IF a.length=b.length AND a.base=b.base THEN T ELSE F];
      ENDCASE;
    mark => WITH b:b SELECT FROM
      mark => RETURN[T];
      ENDCASE;
    user => WITH b:b SELECT FROM
      user => RETURN[IF a.data=b.data AND a.stamp=b.stamp THEN T ELSE F];
      ENDCASE;
    exec => WITH b:b SELECT FROM
      exec => RETURN[T];
      ENDCASE;
    loop => WITH b:b SELECT FROM
      loop => RETURN[T];
      ENDCASE;
    scope => WITH b:b SELECT FROM
      scope => RETURN[IF a.top=b.top AND a.id=b.id THEN T ELSE F];
      ENDCASE;
    ENDCASE;
  RETURN[nil];
  };

StringMatch: PROC[a,b: string Object] RETURNS[BOOLEAN] = INLINE {
  IF a.length=b.length THEN RETURN[StringCompare[a,b]=0]
  ELSE RETURN[FALSE] };

-- Type-specific stack operations

PopInteger: PUBLIC PROC[stack: Stack] RETURNS[LONG INTEGER] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    integer => RETURN[ob.ivalue];
    ENDCASE => ERROR Error[typechk] };

PopCardinal: PUBLIC PROC[stack: Stack, limit: CARDINAL ← 0]
  RETURNS[CARDINAL] = {
  ob: Object ← Pop[stack];
  max: CARDINAL ← limit;
  IF max=0 THEN max ← LAST[CARDINAL];
  WITH ob:ob SELECT FROM
    integer => { i: LONG INTEGER ← ob.ivalue;
      IF i<0 THEN ERROR Error[rangechk];
      IF i>max THEN ERROR Error[IF limit=0 THEN rangechk ELSE limitchk];
      RETURN[Inline.LowHalf[i]] };
    ENDCASE => ERROR Error[typechk] };

PopReal: PUBLIC PROC[stack: Stack] RETURNS[REAL] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    integer => RETURN[ob.ivalue];
    real => RETURN[ob.rvalue];
    ENDCASE => ERROR Error[typechk] };

PopBoolean: PUBLIC PROC[stack: Stack] RETURNS[BOOLEAN] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    boolean => RETURN[ob.bvalue];
    ENDCASE => ERROR Error[typechk] };

PopString: PUBLIC PROC[stack: Stack] RETURNS[string Object] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    string => RETURN[ob];
    ENDCASE => ERROR Error[typechk] };

PopArray: PUBLIC PROC[stack: Stack] RETURNS[array Object] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    array => RETURN[ob];
    ENDCASE => ERROR Error[typechk] };

PopDict: PUBLIC PROC[stack: Stack] RETURNS[dict Object] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    dict => RETURN[ob];
    ENDCASE => ERROR Error[typechk] };

PopCommand: PUBLIC PROC[stack: Stack] RETURNS[command Object] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    command => RETURN[ob];
    ENDCASE => ERROR Error[typechk] };

PopStream: PUBLIC PROC[stack: Stack] RETURNS[stream Object] = {
  ob: Object ← Pop[stack];
  WITH ob:ob SELECT FROM
    stream => RETURN[ob];
    ENDCASE => ERROR Error[typechk] };

TopInteger: PUBLIC PROC[stack: Stack] RETURNS[LONG INTEGER] = {
  ob: Object ← Top[stack];
  WITH ob:ob SELECT FROM
    integer => RETURN[ob.ivalue];
    ENDCASE => ERROR Error[typechk] };

TopDict: PUBLIC PROC[stack: Stack] RETURNS[dict Object] = {
  ob: Object ← Top[stack];
  WITH ob:ob SELECT FROM
    dict => RETURN[ob];
    ENDCASE => ERROR Error[typechk] };

-- Intrinsics

JLength: PUBLIC PROC[frame: Frame] = {
  ob: Object ← Pop[frame.opstk];
  PushInteger[frame.opstk,Length[ob]];
  };

JLitChk: PUBLIC PROC[frame: Frame] = {
  ob: Object ← Pop[frame.opstk];
  PushBoolean[frame.opstk,(ob.tag=L)];
  };

JType: PUBLIC PROC[frame: Frame] = {
  ob: Object ← Pop[frame.opstk];
  name: name Object ← typeName[ob.type];
  Push[frame.opstk,name];
  };

JCvLit: PUBLIC PROC[frame: Frame] = {
  ob: Object ← Pop[frame.opstk];
  ob.tag ← L; Push[frame.opstk,ob];
  };

JCvX: PUBLIC PROC[frame: Frame] = {
  ob: Object ← Pop[frame.opstk];
  ob.tag ← X; Push[frame.opstk,ob];
  };

StringToInteger: PROC[frame: Frame, string: string Object]
  RETURNS[LONG INTEGER] = {
  found: BOOLEAN; token: Object;
  [found: found, token: token] ← StringToken[frame,string];
  IF found THEN WITH tok:token SELECT FROM
    integer => RETURN[tok.ivalue];
    ENDCASE;
  ERROR Error[typechk];
  };

StringToReal: PROC[frame: Frame, string: string Object]
  RETURNS[REAL] = {
  found: BOOLEAN; token: Object;
  [found: found, token: token] ← StringToken[frame,string];
  IF found THEN WITH tok:token SELECT FROM
    integer => RETURN[tok.ivalue];
    real => RETURN[tok.rvalue];
    ENDCASE;
  ERROR Error[typechk];
  };

JCvI: PUBLIC PROC[frame: Frame] = {
  ob: Object ← Pop[frame.opstk];
  i: LONG INTEGER;
  WITH ob:ob SELECT FROM
    integer => i ← ob.ivalue;
    real => IF ob.rvalue IN[FIRST[LONG INTEGER]..LAST[LONG INTEGER]]
      THEN i ← Real.Fix[ob.rvalue] ELSE ERROR Error[rangechk];
    string => i ← StringToInteger[frame,ob];
    ENDCASE => ERROR Error[typechk];
  PushInteger[frame.opstk,i];
  };

JCvR: PUBLIC PROC[frame: Frame] = {
  ob: Object ← Pop[frame.opstk];
  r: REAL;
  WITH ob:ob SELECT FROM
    integer => r ← ob.ivalue;
    real => r ← ob.rvalue;
    string => r ← StringToReal[frame,ob];
    ENDCASE => ERROR Error[typechk];
  PushReal[frame.opstk,r];
  };

-- Initialization

InstallType: PROC[why: InstallReason, frame: Frame] = { SELECT why FROM
  register => {
    typeName ← [
      null: MakeName[".nulltype"L],
      integer: MakeName[".integertype"L],
      real: MakeName[".realtype"L],
      boolean: MakeName[".booleantype"L],
      name: MakeName[".nametype"L],
      string: MakeName[".stringtype"L],
      stream: MakeName[".streamtype"L],
      command: MakeName[".commandtype"L],
      dict: MakeName[".dicttype"L],
      array: MakeName[".arraytype"L],
      mark: MakeName[".marktype"L],
      exec: MakeName[".exectype"L],
      loop: MakeName[".looptype"L],
      scope: MakeName[".scopetype"L]
      ];
    RegisterExplicit[frame, ".length"L, JLength];
    RegisterExplicit[frame, ".litchk"L, JLitChk];
    RegisterExplicit[frame, ".type"L, JType];
    RegisterExplicit[frame, ".cvlit"L, JCvLit];
    RegisterExplicit[frame, ".cvi"L, JCvI];
    RegisterExplicit[frame, ".cvli"L, JCvI]; -- just in case
    RegisterExplicit[frame, ".cvr"L, JCvR];
    RegisterExplicit[frame, ".cvx"L, JCvX];
    };
  ENDCASE;
  };

Install[InstallType];

}.