'use strict'

module.exports = function literal ($void) {
  var $ = $void.$
  var $Class = $.class
  var $Object = $.object
  var $Symbol = $.symbol
  var symbolOf = $Symbol.of
  var Tuple$ = $void.Tuple
  var Symbol$ = $void.Symbol
  var ClassType$ = $void.ClassType
  var thisCall = $void.thisCall
  var evaluate = $void.evaluate
  var arraySet = $.array.proto.set
  var staticOperator = $void.staticOperator

  var symbolPairing = $Symbol.pairing
  var symbolAll = $Symbol.all
  var symbolLiteral = $Symbol.literal
  var symbolArray = $Symbol.of('array')
  var symbolObject = $Symbol.of('object')
  var symbolClass = $Symbol.of('class')

  // (@ value ...)
  function arrayCreate (space, clist, offset) {
    var result = []
    var index, value
    while (offset < clist.length) {
      value = evaluate(clist[offset++], space)
      if (offset < clist.length && clist[offset] === symbolPairing) {
        offset += 1
        index = typeof value === 'number' ? value >> 0 : result.length
        arraySet.call(result, index, offset >= clist.length ? null
          : evaluate(clist[offset++], space)
        )
      } else {
        result.push(value)
      }
    }
    return result
  }

  // (@ symbol: value ...)
  function objectCreate (space, clist, type, offset) {
    var obj = type.empty()
    var length = clist.length
    while (offset < length) {
      var name = clist[offset++]
      if (name instanceof Symbol$) {
        name = name.key
      } else if (typeof name !== 'string') {
        if (name instanceof Tuple$) {
          name = evaluate(name, space)
        }
        if (name instanceof Symbol$) {
          name = name.key
        } else if (typeof name !== 'string') {
          name = thisCall(name, 'to-string')
        }
      }
      if (clist[offset] === symbolPairing) {
        obj[name] = ++offset < length ? evaluate(clist[offset++], space) : null
      } else {
        obj[name] = evaluate(symbolOf(name), space)
      }
    }
    // activate a typed object
    var activator = type.proto.activator
    if (typeof activator === 'function') {
      activator.call(obj, obj)
    }
    return obj
  }

  staticOperator('@', function (space, clause) {
    var clist = clause.$
    var length = clist.length
    if (length < 2) { // (@)
      return []
    }
    var indicator = clist[1]
    if (indicator !== symbolPairing) {
      return length <= 2 || clist[2] !== symbolPairing ||
          typeof indicator === 'number' || indicator instanceof Tuple$
        ? arrayCreate(space, clist, 1) // (@ ...) or (@ offset: value ...)
        : objectCreate(space, clist, $Object, 1) // (@ name: ...) or (@ "name": ...)
    }
    // (@: ...)
    if (length < 3) { // (@:)
      return Object.create($Object.proto)
    }
    // (@:a-type ...)
    var type = clist[2]
    return type === symbolClass
      ? $Class.of(objectCreate(space, clist, $Object, 3)) // (@:class ...)
      : type === symbolLiteral || type === symbolObject
        ? objectCreate(space, clist, $Object, 3) // (@:@ ...) (@:object ...)
        : type === symbolAll || type === symbolArray
          ? arrayCreate(space, clist, 3) // (@:* ...) (@:array ...)
          : objectCreate(space, clist,
            (type = evaluate(type, space)) instanceof ClassType$
              ? type // (@:a-class ...)
              : $Object, // ignore type and treat it as a common object.
            3)
  })
}

@@ -634,16 +634,137 @@
 lass')%0A%0A
+  // late binding%0A  var $warn = function warn () %7B%0A    $warn = $void.$warn%0A    return $warn.apply($void, arguments)%0A  %7D%0A%0A
   // (@ 
@@ -2256,16 +2256,322 @@
 bj%0A  %7D%0A%0A
+  function tryToCreateInstance (space, clist, type, offset) %7B%0A    if (!(type instanceof ClassType$)) %7B%0A      $warn('@-literal', 'invalid literal type', %5Btypeof type, type%5D)%0A      type = $Object // downgrade an unknown type to a common object.%0A    %7D%0A    return objectCreate(space, clist, type, offset)%0A  %7D%0A%0A
   static
@@ -2926,49 +2926,34 @@
     
-? arrayCreate(space, clist, 1) //
+// implicit array:
  (@ ...)
  or 
@@ -2944,27 +2944,44 @@
 ray: (@ ...)
+,
  or
+ discrete array:
  (@ offset: 
@@ -2995,32 +2995,31 @@
 ..)%0A        
-: object
+? array
 Create(space
@@ -3031,22 +3031,38 @@
 st, 
-$Object, 1) //
+1)%0A        // implicit object:
  (@ 
@@ -3087,24 +3087,73 @@
 name%22: ...)%0A
+        : objectCreate(space, clist, $Object, 1)%0A
     %7D%0A    //
@@ -3318,16 +3318,58 @@
 olClass%0A
+      // class declaration: (@:class ...)%0A
       ? 
@@ -3421,25 +3421,8 @@
  3))
- // (@:class ...)
 %0A   
@@ -3470,24 +3470,77 @@
 ymbolObject%0A
+        // explicit object: (@:@ ...) (@:object ...)%0A
         ? ob
@@ -3579,36 +3579,8 @@
 , 3)
- // (@:@ ...) (@:object ...)
 %0A   
@@ -3643,41 +3643,27 @@
     
-? arrayCreate(space, clist, 3) //
+// mandatory array:
  (@:
@@ -3689,32 +3689,31 @@
 )%0A          
-: object
+? array
 Create(space
@@ -3720,16 +3720,19 @@
 , clist,
+ 3)
 %0A       
@@ -3738,187 +3738,111 @@
     
-  (type = evaluate(type, space)) instanceof ClassType$%0A              ? type // (@:a-class ...)%0A              : $Object, // ignore type and treat it as a common object.%0A           
+// class instance: (@:a-class ...)%0A          : tryToCreateInstance(space, clist, evaluate(type, space),
  3)%0A

revise @-literal to add warning for invalid type identifier