; G+ MACRO LANGUAGE

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

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

macro numeric p&
  local i
  i=0
  irp q, p
    match name==value, q
      i=value
      name=i
    else match name, q
      name=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 q, p
    match name==value, q
      label name at @base+$
      type value
    else match name, q
      label name at @base+$
      type 0
    end match
  end irp
end macro

macro byte p&
  variable db, p
end macro

macro int p&
  irp q, p
    match name[]==values, q
      match {v}, values
        label name at @base+$
        dd v
      else
        err 'Use: ={...}'
      end match
    else match name[size], q
      label name at @base+$
      dd size dup(0)
    else
      variable dd, q
    end match
  end irp
end macro

macro integer p&
  int p
end macro

macro void p&
  int p
end macro

macro text p&
  irp q, p
    match name==value, q
      label name at @base+$
      db value, 0
    else match name[size], q
      label name at @base+$
      db size dup(0)
    else
      err ''
    end match
  end irp
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 = int x, y
; class LINE  = POINT a, b
; class BOX   = int x, y, w, h
; class RECT  = int l, t, r, b

; class POINT3D   = int n, x, y, z
; class POLYGON   = POINT points[?]
; class POLYGON3D = POINT3D points[?]

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

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

; unfinished. replace asm '' with instructions

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 ;;;;;;;;;;;;;;;;;;;;

; unfinished. replace asm '' with instructions

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
    irp x, q            ; parameter
      x equ [ebp+%*4]   ; names
    end irp
  end if
  scope='f'
end macro

macro return v&
  match any, 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