Merge: grammar: add union and intersection types
authorJean Privat <jean@pryen.org>
Mon, 20 Mar 2017 20:09:00 +0000 (16:09 -0400)
committerJean Privat <jean@pryen.org>
Mon, 20 Mar 2017 20:09:00 +0000 (16:09 -0400)
This is a stub in the grammar to add intersection and union types.

* `var x: A and B`
* `var x: A or B and C or D or E`

Adding parenthesis `(A and B) or C` cause some nasty conflicts because the Nit grammar is very complex and organic (and sablecc is nowadays more a curse than a blessing).

all usage of types accept intersection and union except `new` and `isa` because LR1 conflicts with the boolean `or`.

* `x isa A or...`: shift type (`x isa A or B`) vs. reduce expr (`x isa A or true`)

This is not too much a problem because:

* intersection and union type are abstract (no `new`)
* `a isa A or B` should be the same than `a isa A or a isa B`

Note that this is only a stub: only the grammar is extended:
* there is no new AST node (`A or B` is parsed as `A`, the `B` is just dropped)
* there is no change in the metamodel of Nit

Pull-Request: #2389
Reviewed-by: Jean-Christophe Beaupré <jcbrinfo.public@gmail.com>

lib/core/environ.nit
lib/core/exec.nit
lib/core/file.nit
lib/core/kernel.nit
misc/docker/full/Dockerfile
src/compiler/abstract_compiler.nit
tests/MINGW64_NT.skip [new file with mode: 0644]
tests/sav/test_exec.res
tests/test_exec.nit
tests/tests.sh

index 941bd1c..4ef4c99 100644 (file)
@@ -46,10 +46,12 @@ redef class String
        # Search for the program `self` in all directories from `PATH`
        fun program_is_in_path: Bool
        do
+               var sep = if is_windows then ";" else ":"
                var full_path = "PATH".environ
-               var paths = full_path.split(":")
+               var paths = full_path.split(sep)
                for path in paths do if path.file_exists then
                        if path.join_path(self).file_exists then return true
+                       if is_windows and (path / self + ".exe").file_exists then return true
                end
 
                return false
index d5ab952..fedc5de 100644 (file)
@@ -164,7 +164,7 @@ class Process
                                return NULL;
                        }
                        start_info.hStdInput = in_fd[0];
-                       result->in_fd = _open_osfhandle((intptr_t)in_fd[1], _O_APPEND);
+                       result->in_fd = _open_osfhandle((intptr_t)in_fd[1], _O_WRONLY);
                        if ( !SetHandleInformation(in_fd[1], HANDLE_FLAG_INHERIT, 0) )
                                return NULL;
                } else {
@@ -214,6 +214,10 @@ class Process
                        &start_info,
                        &proc_info);
 
+               if (pipeflag & 1) CloseHandle(in_fd[0]);
+               if (pipeflag & 2) CloseHandle(out_fd[1]);
+               if (pipeflag & 3) CloseHandle(err_fd[1]);
+
                // Error?
                if (!created) {
                        result->running = 0;
index 6701588..09b20d9 100644 (file)
@@ -963,30 +963,28 @@ redef class String
        #     assert "path/to".basename(".ext")                 == "to"
        #     assert "path/to/".basename(".ext")                == "to"
        #     assert "path/to".basename                         == "to"
-       #     assert "path".basename("")                        == "path"
-       #     assert "/path".basename("")                       == "path"
-       #     assert "/".basename("")                           == "/"
-       #     assert "".basename("")                            == ""
+       #     assert "path".basename                            == "path"
+       #     assert "/path".basename                           == "path"
+       #     assert "/".basename                               == "/"
+       #     assert "".basename                                == ""
+       #
+       # On Windows, '\' are replaced by '/':
+       #
+       # ~~~nitish
+       # assert "C:\\path\\to\\a_file.ext".basename(".ext")    == "a_file"
+       # assert "C:\\".basename                                == "C:"
+       # ~~~
        fun basename(extension: nullable String): String
        do
                var n = self
-               if is_windows then
-                       var l = length - 1 # Index of the last char
-                       while l > 0 and (self.chars[l] == '/' or chars[l] == '\\') do l -= 1 # remove all trailing `/`
-                       if l == 0 then return "/"
-                       var pos = chars.last_index_of_from('/', l)
-                       pos = pos.max(last_index_of_from('\\', l))
-                       if pos >= 0 then
-                               n = substring(pos+1, l-pos)
-                       end
-               else
-                       var l = length - 1 # Index of the last char
-                       while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/`
-                       if l == 0 then return "/"
-                       var pos = chars.last_index_of_from('/', l)
-                       if pos >= 0 then
-                               n = substring(pos+1, l-pos)
-                       end
+               if is_windows then n = n.replace("\\", "/")
+
+               var l = length - 1 # Index of the last char
+               while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/`
+               if l == 0 then return "/"
+               var pos = chars.last_index_of_from('/', l)
+               if pos >= 0 then
+                       n = substring(pos+1, l-pos)
                end
 
                if extension != null then
@@ -1004,13 +1002,23 @@ redef class String
        #     assert "/path".dirname                       == "/"
        #     assert "/".dirname                           == "/"
        #     assert "".dirname                            == "."
+       #
+       # On Windows, '\' are replaced by '/':
+       #
+       # ~~~nitish
+       # assert "C:\\path\\to\\a_file.ext".dirname        == "C:/path/to"
+       # assert "C:\\file".dirname                        == "C:"
+       # ~~~
        fun dirname: String
        do
+               var s = self
+               if is_windows then s = s.replace("\\", "/")
+
                var l = length - 1 # Index of the last char
-               while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/`
-               var pos = chars.last_index_of_from('/', l)
+               while l > 0 and s.chars[l] == '/' do l -= 1 # remove all trailing `/`
+               var pos = s.chars.last_index_of_from('/', l)
                if pos > 0 then
-                       return substring(0, pos)
+                       return s.substring(0, pos)
                else if pos == 0 then
                        return "/"
                else
@@ -1055,10 +1063,18 @@ redef class String
        # assert "./../dir".simplify_path                  == "../dir"
        # assert "./dir".simplify_path                     == "dir"
        # ~~~
+       #
+       # On Windows, '\' are replaced by '/':
+       #
+       # ~~~nitish
+       # assert "C:\\some\\.\\complex\\../../path/to/a_file.ext".simplify_path == "C:/path/to/a_file.ext"
+       # assert "C:\\".simplify_path              == "C:"
+       # ~~~
        fun simplify_path: String
        do
-               var path_sep = if is_windows then "\\" else "/"
-               var a = self.split_with(path_sep)
+               var s = self
+               if is_windows then s = s.replace("\\", "/")
+               var a = s.split_with("/")
                var a2 = new Array[String]
                for x in a do
                        if x == "." and not a2.is_empty then continue # skip `././`
@@ -1183,6 +1199,7 @@ redef class String
        #     assert "/" + "/".relpath(".") == getcwd
        fun relpath(dest: String): String
        do
+               # TODO windows support
                var cwd = getcwd
                var from = (cwd/self).simplify_path.split("/")
                if from.last.is_empty then from.pop # case for the root directory
@@ -1215,8 +1232,10 @@ redef class String
        fun mkdir(mode: nullable Int): nullable Error
        do
                mode = mode or else 0o777
+               var s = self
+               if is_windows then s = s.replace("\\", "/")
 
-               var dirs = self.split_with("/")
+               var dirs = s.split_with("/")
                var path = new FlatBuffer
                if dirs.is_empty then return null
                if dirs[0].is_empty then
@@ -1235,7 +1254,7 @@ redef class String
                                error = new IOError("Cannot create directory `{path}`: {sys.errno.strerror}")
                        end
                end
-               var res = self.to_cstring.file_mkdir(mode)
+               var res = s.to_cstring.file_mkdir(mode)
                if not res and error == null then
                        error = new IOError("Cannot create directory `{path}`: {sys.errno.strerror}")
                end
@@ -1356,29 +1375,19 @@ redef class FlatString
        end
 
        redef fun basename(extension) do
+               var s = self
+               if is_windows then s = s.replace("\\", "/").as(FlatString)
+
                var bname
-               if is_windows then
-                       var l = last_byte
-                       var its = _items
-                       var min = _first_byte
-                       var sl = '/'.ascii
-                       var ls = '\\'.ascii
-                       while l > min and (its[l] == sl or its[l] == ls) do l -= 1
-                       if l == min then return "\\"
-                       var ns = l
-                       while ns >= min and its[ns] != sl and its[ns] != ls do ns -= 1
-                       bname = new FlatString.with_infos(its, l - ns, ns + 1)
-               else
-                       var l = last_byte
-                       var its = _items
-                       var min = _first_byte
-                       var sl = '/'.ascii
-                       while l > min and its[l] == sl do l -= 1
-                       if l == min then return "/"
-                       var ns = l
-                       while ns >= min and its[ns] != sl do ns -= 1
-                       bname = new FlatString.with_infos(its, l - ns, ns + 1)
-               end
+               var l = s.last_byte
+               var its = s._items
+               var min = s._first_byte
+               var sl = '/'.ascii
+               while l > min and its[l] == sl do l -= 1
+               if l == min then return "/"
+               var ns = l
+               while ns >= min and its[ns] != sl do ns -= 1
+               bname = new FlatString.with_infos(its, l - ns, ns + 1)
 
                return if extension != null then bname.strip_extension(extension) else bname
        end
index fa7b6f4..a821006 100644 (file)
@@ -1063,7 +1063,7 @@ extern class Pointer
        fun free `{ free(self); `}
 
        # Use the address value
-       redef fun hash `{ return (long)self; `}
+       redef fun hash `{ return (long)(intptr_t)self; `}
 
        # Is equal to any instance pointing to the same address
        redef fun ==(o) do return o isa Pointer and native_equals(o)
index 2efb5d3..10bb9f6 100644 (file)
@@ -20,6 +20,7 @@ RUN dpkg --add-architecture i386 \
                libsdl-ttf2.0-dev \
                libsdl1.2-dev \
                libsdl2-dev \
+               libsdl2-image-dev \
                libsqlite3-dev \
                libx11-dev \
                libxdg-basedir-dev \
index 11ff040..4ce8024 100644 (file)
@@ -349,14 +349,21 @@ class MakefileToolchain
                end
                var debug = toolcontext.opt_debug.value
 
-               makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g{ if not debug then " -O2 " else " "}-Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
+               makefile.write """
+CC ?= ccache cc
+CXX ?= ccache c++
+CFLAGS ?= -g {{{if not debug then "-O2" else ""}}} -Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs
+CINCL =
+LDFLAGS ?=
+LDLIBS  ?= -lm {{{linker_options.join(" ")}}}
+\n"""
 
                makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
                if platform.supports_libunwind then
                        if toolcontext.opt_no_stacktrace.value then
-                               makefile.write "NO_STACKTRACE=True"
+                               makefile.write "NO_STACKTRACE ?= True"
                        else
-                               makefile.write "NO_STACKTRACE= # Set to `True` to enable"
+                               makefile.write "NO_STACKTRACE ?= # Set to `True` to enable"
                        end
                end
 
diff --git a/tests/MINGW64_NT.skip b/tests/MINGW64_NT.skip
new file mode 100644 (file)
index 0000000..619b61b
--- /dev/null
@@ -0,0 +1,16 @@
+cocoa_extern_types
+cocoa_message_box
+hello_cocoa
+hello_ios
+test_platform_ios
+mnit
+shoot_linux
+dino_linux
+ballz_linux
+mpi
+emscripten
+neo_doxygen
+neo4j
+mongo
+pernicious_numbers
+frankuchredux
index 3647533..fcfb6f7 100644 (file)
@@ -1,7 +1,8 @@
 A hello world!
 0
 
-B hello world!0
+B hello world!true
+0
 
 C hello world!
 0
index efb94b7..58b6343 100644 (file)
@@ -24,6 +24,7 @@ print ""
 
 var ip = new ProcessReader("echo", "B hello world!")
 ip.read_line.output
+ip.eof.output
 ip.wait
 print ip.status
 
index 308ff84..2fbab89 100755 (executable)
@@ -154,6 +154,8 @@ else
        HOSTNAME="hostname -s"
 fi
 
+UNAME=`uname | sed s/-.*//`
+
 # $1 is the pattern of the test
 # $2 is the file to compare to
 # the result is:
@@ -373,7 +375,7 @@ need_skip()
        fi
 
        # Skip by OS
-       local os_skip_file=`uname`.skip
+       local os_skip_file=$UNAME.skip
        if test -e $os_skip_file && echo "$1" | grep -f "$os_skip_file" >/dev/null 2>&1; then
                echo "=> $2: [skip os]"
                echo >>$xml "<testcase classname='`xmlesc "$3"`' name='`xmlesc "$2"`' `timestamp`><skipped/></testcase>"
@@ -530,7 +532,7 @@ case $engine in
                ;;
 esac
 
-savdirs="sav/`$HOSTNAME` sav/`uname` sav/$engine $savdirs sav/"
+savdirs="sav/`$HOSTNAME` sav/$UNAME sav/$engine $savdirs sav/"
 
 # The default nitc compiler
 [ -z "$NITC" ] && find_nitc