; TOY MACRO LANGUAGE FOR FASMG

RET equ $D, $A

macro asm p&
  db p, RET
end macro

;;;;;;;;;;;;;;;;;;; ESSENTIALS ;;;;;;;;;;;;;;;;;;;

; is x in list? return is=1/0

macro is_in is, x, list
  is=0
  irp x, list
    match =x, r
      is=1
      break
    end match
  end irp
end macro

;;;;;;;;;;;;;;;;;;; CONSTANTS ;;;;;;;;;;;;;;;;;;;;

; numeric BLACK, WHITE=1, RED, GREEN, BLUE

macro numeric p&
  local i
  i=0
  irp q, p
    match a==b, q
      i=b
      a=i
    else match a, q
      a=i
    end match
    i=i+1
  end irp
end macro

;;;;;;;;;;;;;;;;;;;; VARIABLE ;;;;;;;;;;;;;;;;;;;;

; int i=7, n='Z', j=$CAFEBABE

scope=0

macro variable type, p&
  irp x, p
    match name==value, x
      if scope=0
        asm `name, ' ', `type, ' ', `value, ' '
      end if
    else match name, x
      if scope=0
        asm `name, ' ', `type, ' 0'
      end if
    end match
  end irp
end macro

macro byte p&
  variable db, p
end macro

macro int p&
  variable dd, p
end macro

macro int p&
  match a[]==vs, p
    match {z}, vs
      asm `a, ': dd ', `z
    end match
  else match a[n], p
    asm `a, ': rd ', `n
  else
    int p
  end match
end macro

;;;;;;;;;;;;;;;;;;;;; CLASS ;;;;;;;;;;;;;;;;;;;;;;

macro class type
  esc macro type name
    scope='c'
    name:
    namespace name
      ; ...
end macro

macro endc!
      ; ...
    end namespace
    scope=0
  esc end macro
end macro

; EXAMPLE:

; class POINT
;   int x, y
; endc

; POINT point

; 2-DO: single-line classes:

; class RGB     = byte a, r, g, b
; class POINT   = integer x, y
; class LINE    = POINT a, b
; class BOX     = integer x, y, w, h
; class RECT    = integer l, t, r, b
; class POINT3D = integer n, x, y, z
; class POLYGON = POINT3D points[?]

; 2-DO: memory manager (CPU portable),
; dynamic arrays: IMAGE images[?]

;;;;;;;;;;;;;;;;;;;; OPERATION ;;;;;;;;;;;;;;;;;;;

macro let p&
  match a==&b, p
    asm 'lea ', `a, ', ', '[', `b, ']'
  else match a==b, p
    asm 'mov ', `a, ', ', `b
  else match a>>>b, p
    asm 'sar ', `a, ', ', `b
  else match a<<b, p
    asm 'shl ', `a, ', ', `b
  else match a>>b, p
    asm 'shr ', `a, ', ', `b
  else match a&b, p
    asm 'and ', `a, ', ', `b
  else match a|b, p
    asm 'or ', `a, ', ', `b
  else match a+b, p
    match =1, b
      asm 'inc ', `a
    else
      asm 'add ', `a, ', ', `b
    end match
  else match a-b, p
    match =1, b
      asm 'dec ', `a
    else
      asm 'sub ', `a, ', ', `b
    end match
  else match a*b, p
    match =2, b
      asm 'shl ', `a, ', 1'
    else match =4, b
      asm 'shl ', `a, ', 2'
    else match =8, b
      asm 'shl ', `a, ', 3'
    else
      asm 'imul ', `a, ', ', `b
    end match
  else match a/b, p
    match =2, b
      asm 'sar ', `a, ', 1'
    else match =4, b
      asm 'sar ', `a, ', 2'
    else match =8, b
      asm 'sar ', `a, ', 3'
    else
      match =eax, a
        asm 'push edx'
        asm 'cdq'
        asm 'idiv ', `b
        asm 'pop edx'
      else
        err 'Destiny must be eax'
      end match
    end match
  else
    display 'Invalid:', RET
    display 'let ', `p
    err ''
  end match
end macro

macro let p&
  irp x, p
    let x
  end irp
end macro

;;;;;;;;;;;;;;;;;;;; FUNCTION ;;;;;;;;;;;;;;;;;;;;

its_name equ 0
its_parameters equ 0
its_locals equ 0

n_parameters=0
parameters_size=0
n_locals=0
locals_size=0

macro function name, p&
  local n
  n=0
  match =0, its_name
    its_name equ name
    its_parameters equ p
  else
    err 'endf expected'
  end match
  n=0
  match any, p
    irp x, p
      n=n+1
    end irp
  end match
  n_parameters=n
  parameters_size=n*4
  @#name:
  asm `name, ':'
  macro name q&
    n=0
    irp x, q
      n=n+1
    end irp
    if n>1
      if n<>n_parameters
        display `name, ': '
        display 'Invalid # parameters', RET
        err ''
      end if
      irp x, q          ; pushr...
        indx 1+%%-%     ; x=q[#]
        asm 'push ', `x
      end irp
    end if
    asm 'call ', `name  ; call f
  end macro
  if n_parameters
    asm 'push ebp'      ; db $55
    asm 'mov ebp, esp'  ; db $89, $E5
    n=8
    irp x, q            ; parameter
      x equ [ebp+n]     ; names
      n=n+4
    end irp
  end if
  scope='f'
end macro

macro return v&
  match x, v
    asm 'mov eax, ' `v
  end match
  if n_parameters \
    | n_locals
    asm 'mov esp, ebp' ; db $89, $EC
    asm 'pop ebp'      ; db $5D
  end if
  if n_parameters
    asm 'ret n'        ; db $C2, dw n
  else
    asm 'ret'          ; db $C3
  end if
end macro

macro endf! v&
  return v
  restore its_name
  irp x, its_parameters
    restore x
  end irp
  scope=0
end macro