# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


==================================
Test a struct with constant fields
==================================

struct TestConstants {
  const voidConst      :Void    = void;
  const boolConst      :Bool    = true;
  const int8Const      :Int8    = -123;
  const int16Const     :Int16   = -12345;
  const int32Const     :Int32   = -12345678;
  const int64Const     :Int64   = -123456789012345;
  const uint8Const     :UInt8   = 234;
  const uint16Const    :UInt16  = 45678;
  const uint32Const    :UInt32  = 3456789012;
  const uint64Const    :UInt64  = 12345678901234567890;
  const float32Const   :Float32 = 1234.5;
  const float64Const   :Float64 = -123e45;
  const textConst      :Text    = "foo";
  const dataConst      :Data    = "bar";
  const structConst    :TestAllTypes = (
      voidField      = void,
      boolField      = true,
      int8Field      = -12,
      int16Field     = 3456,
      int32Field     = -78901234,
      int64Field     = 56789012345678,
      uInt8Field     = 90,
      uInt16Field    = 1234,
      uInt32Field    = 56789012,
      uInt64Field    = 345678901234567890,
      float32Field   = -1.25e-10,
      float64Field   = 345,
      textField      = "baz",
      dataField      = "qux",
      structField    = (
          textField = "nested",
          structField = (textField = "really nested")),
      enumField      = baz,
      # interfaceField can't have a default

      voidList      = [void, void, void],
      boolList      = [false, true, false, true, true],
      int8List      = [12, -34, -0x80, 0x7f],
      int16List     = [1234, -5678, -0x8000, 0x7fff],
      int32List     = [12345678, -90123456, -0x80000000, 0x7fffffff],
      int64List     = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff],
      uInt8List     = [12, 34, 0, 0xff],
      uInt16List    = [1234, 5678, 0, 0xffff],
      uInt32List    = [12345678, 90123456, 0, 0xffffffff],
      uInt64List    = [123456789012345, 678901234567890, 0, 0xffffffffffffffff],
      float32List   = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37],
      float64List   = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306],
      textList      = ["quux", "corge", "grault"],
      dataList      = ["garply", "waldo", "fred"],
      structList    = [
          (textField = "x " "structlist"
                       " 1"),
          (textField = "x structlist 2"),
          (textField = "x structlist 3")],
      enumList      = [qux, bar, grault]
      # interfaceList can't have a default
      );
  const enumConst      :TestEnum = corge;

  const voidListConst      :List(Void)    = [void, void, void, void, void, void];
  const boolListConst      :List(Bool)    = [true, false, false, true];
  const int8ListConst      :List(Int8)    = [111, -111];
  const int16ListConst     :List(Int16)   = [11111, -11111];
  const int32ListConst     :List(Int32)   = [111111111, -111111111];
  const int64ListConst     :List(Int64)   = [1111111111111111111, -1111111111111111111];
  const uint8ListConst     :List(UInt8)   = [111, 222] ;
  const uint16ListConst    :List(UInt16)  = [33333, 44444];
  const uint32ListConst    :List(UInt32)  = [3333333333];
  const uint64ListConst    :List(UInt64)  = [11111111111111111111];
  const float32ListConst   :List(Float32) = [5555.5, inf, -inf, nan];
  const float64ListConst   :List(Float64) = [7777.75, inf, -inf, nan];
  const textListConst      :List(Text)    = ["plugh", "xyzzy", "thud"];
  const dataListConst      :List(Data)    = ["oops", "exhausted", "rfc3092"];
  const structListConst    :List(TestAllTypes) = [
      (textField = "structlist 1"),
      (textField = "structlist 2"),
      (textField = "structlist 3")];
  const enumListConst      :List(TestEnum) = [foo, garply];
}

---

(message
      (statement
        (definition
          (struct
            (type_identifier)
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (void))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (boolean
                    (true)))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (number))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (float))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (float))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (string
                    (string_fragment)))))
            (field
              (const
                (const_identifier)
                (field_type
                  (primitive_type))
                (const_value
                  (string
                    (string_fragment)))))
            (field
              (const
                (const_identifier)
                (field_type
                  (custom_type
                    (type_identifier)))
                (const_value
                  (struct_shorthand
                    (property)
                    (const_value
                      (void))
                    (property)
                    (const_value
                      (boolean
                        (true)))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (float))
                    (property)
                    (const_value
                      (number))
                    (property)
                    (const_value
                      (string
                        (string_fragment)))
                    (property)
                    (const_value
                      (string
                        (string_fragment)))
                    (property)
                    (const_value
                      (struct_shorthand
                        (property)
                        (const_value
                          (string
                            (string_fragment)))
                        (property)
                        (const_value
                          (struct_shorthand
                            (property)
                            (const_value
                              (string
                                (string_fragment)))))))
                    (property)
                    (const_value
                      (const_identifier))
                    (comment)
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (void))
                        (const_value
                          (void))
                        (const_value
                          (void))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (boolean
                            (false)))
                        (const_value
                          (boolean
                            (true)))
                        (const_value
                          (boolean
                            (false)))
                        (const_value
                          (boolean
                            (true)))
                        (const_value
                          (boolean
                            (true)))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (number))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (float))
                        (const_value
                          (float))
                        (const_value
                          (float))
                        (const_value
                          (float))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (number))
                        (const_value
                          (number))
                        (const_value
                          (float))
                        (const_value
                          (float))
                        (const_value
                          (float))
                        (const_value
                          (float))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (string
                            (string_fragment)))
                        (const_value
                          (string
                            (string_fragment)))
                        (const_value
                          (string
                            (string_fragment)))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (string
                            (string_fragment)))
                        (const_value
                          (string
                            (string_fragment)))
                        (const_value
                          (string
                            (string_fragment)))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (struct_shorthand
                            (property)
                            (const_value
                              (concatenated_string
                                (string
                                  (string_fragment))
                                (string
                                  (string_fragment))
                                (string
                                  (string_fragment))))))
                        (const_value
                          (struct_shorthand
                            (property)
                            (const_value
                              (string
                                (string_fragment)))))
                        (const_value
                          (struct_shorthand
                            (property)
                            (const_value
                              (string
                                (string_fragment)))))))
                    (property)
                    (const_value
                      (const_list
                        (const_value
                          (const_identifier))
                        (const_value
                          (const_identifier))
                        (const_value
                          (const_identifier))))
                    (comment)))))
            (field
              (const
                (const_identifier)
                (field_type
                  (custom_type
                    (type_identifier)))
                (const_value
                  (const_identifier))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (void))
                    (const_value
                      (void))
                    (const_value
                      (void))
                    (const_value
                      (void))
                    (const_value
                      (void))
                    (const_value
                      (void))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (boolean
                        (true)))
                    (const_value
                      (boolean
                        (false)))
                    (const_value
                      (boolean
                        (false)))
                    (const_value
                      (boolean
                        (true)))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (float))
                    (const_value
                      (number))
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (float))
                    (const_value
                      (number))
                    (const_value
                      (number))
                    (const_value
                      (number))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (string
                        (string_fragment)))
                    (const_value
                      (string
                        (string_fragment)))
                    (const_value
                      (string
                        (string_fragment)))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (primitive_type))))
                (const_value
                  (const_list
                    (const_value
                      (string
                        (string_fragment)))
                    (const_value
                      (string
                        (string_fragment)))
                    (const_value
                      (string
                        (string_fragment)))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (custom_type
                        (type_identifier)))))
                (const_value
                  (const_list
                    (const_value
                      (struct_shorthand
                        (property)
                        (const_value
                          (string
                            (string_fragment)))))
                    (const_value
                      (struct_shorthand
                        (property)
                        (const_value
                          (string
                            (string_fragment)))))
                    (const_value
                      (struct_shorthand
                        (property)
                        (const_value
                          (string
                            (string_fragment)))))))))
            (field
              (const
                (const_identifier)
                (field_type
                  (list_type
                    (field_type
                      (custom_type
                        (type_identifier)))))
                (const_value
                  (const_list
                    (const_value
                      (const_identifier))
                    (const_value
                      (const_identifier))))))))))



====================================
Test constant used in the same scope
====================================

const globalInt :UInt32 = 12345;
const globalText :Text = "foobar";
const globalStruct :TestAllTypes = (int32Field = 54321);
const globalPrintableStruct :TestPrintInlineStructs = (someText = "foo");
const derivedConstant :TestAllTypes = (
    uInt32Field = .globalInt,
    textField = TestConstants.textConst,
    structField = TestConstants.structConst,
    int16List = TestConstants.int16ListConst,
    structList = TestConstants.structListConst);

---

(message
      (statement
        (definition
          (const
            (const_identifier)
            (field_type
              (primitive_type))
            (const_value
              (number)))))
      (statement
        (definition
          (const
            (const_identifier)
            (field_type
              (primitive_type))
            (const_value
              (string
                (string_fragment))))))
      (statement
        (definition
          (const
            (const_identifier)
            (field_type
              (custom_type
                (type_identifier)))
            (const_value
              (struct_shorthand
                (property)
                (const_value
                  (number)))))))
      (statement
        (definition
          (const
            (const_identifier)
            (field_type
              (custom_type
                (type_identifier)))
            (const_value
              (struct_shorthand
                (property)
                (const_value
                  (string
                    (string_fragment))))))))
      (statement
        (definition
          (const
            (const_identifier)
            (field_type
              (custom_type
                (type_identifier)))
            (const_value
              (struct_shorthand
                (property)
                (local_const
                  (const_identifier))
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))))))))



=======================================
Test a struct with AnyPointer constants
=======================================

struct TestAnyPointerConstants {
  anyKindAsStruct @0 :AnyPointer;
  anyStructAsStruct @1 :AnyStruct;
  anyKindAsList @2 :AnyPointer;
  anyListAsList @3 :AnyList;
}

const anyPointerConstants :TestAnyPointerConstants = (
  anyKindAsStruct = TestConstants.structConst,
  anyStructAsStruct = TestConstants.structConst,
  anyKindAsList = TestConstants.int32ListConst,
  anyListAsList = TestConstants.int32ListConst,
);

---

(message
      (statement
        (definition
          (struct
            (type_identifier)
            (field
              (field_identifier)
              (field_version)
              (field_type
                (primitive_type)))
            (field
              (field_identifier)
              (field_version)
              (field_type
                (custom_type
                  (type_identifier))))
            (field
              (field_identifier)
              (field_version)
              (field_type
                (primitive_type)))
            (field
              (field_identifier)
              (field_version)
              (field_type
                (custom_type
                  (type_identifier)))))))
      (statement
        (definition
          (const
            (const_identifier)
            (field_type
              (custom_type
                (type_identifier)))
            (const_value
              (struct_shorthand
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))
                (property)
                (const_value
                  (type_identifier)
                  (const_identifier))))))))
