@@ -191,6 +191,16 @@ extern int main(int, char**);
191
191
192
192
static const char * restrict function_stack_start ;
193
193
194
+ const SYMBOL SYMstart = "start" ;
195
+ const SYMBOL SYMend = "end" ;
196
+ const SYMBOL SYMcurrent = "current" ;
197
+ const SYMBOL SYMread = "read" ;
198
+ const SYMBOL SYMwrite = "write" ;
199
+ const SYMBOL SYMappend = "append" ;
200
+ const SYMBOL SYMreadHwrite = "read-write" ;
201
+ const SYMBOL SYMreadHappend = "read-append" ;
202
+ const SYMBOL SYMreadHwriteHexisting = "read-write-existing" ;
203
+
194
204
// Variables and needed by functions.c defined in runtime.c
195
205
static void init_stack (void );
196
206
static STRING show_object (const ANY object , const _Bool , char * );
@@ -287,7 +297,7 @@ static STRING ___join(STRING, STRING);
287
297
static NUMBER ___stringHlength (STRING );
288
298
static STRING ___substring (NUMBER , NUMBER , STRING );
289
299
static STRING ___input (void );
290
- static IO ___open (STRING , STRING );
300
+ static IO ___open (SYMBOL , STRING );
291
301
static void ___close (IO );
292
302
static NUMBER ___number (STRING );
293
303
static STRING ___path (void );
@@ -1697,7 +1707,7 @@ static STRING ___show(ANY o)
1697
1707
1698
1708
static LIST ___split (STRING sep , STRING str )
1699
1709
{
1700
- if (!* sep ) throw_error ("Empty separator " );
1710
+ if (!* sep ) throw_error ("Seperator cannot be empty " );
1701
1711
LIST lst = NULL ;
1702
1712
size_t len = strlen (sep );
1703
1713
char * found ;
@@ -1961,12 +1971,19 @@ static NUMBER ___tanh(NUMBER a)
1961
1971
return tanh (a );
1962
1972
}
1963
1973
1964
- static IO ___open (STRING path , STRING mode )
1974
+ static IO ___open (SYMBOL m , STRING path )
1965
1975
{
1966
1976
assert_impure ();
1967
- // TODO mode should definitely be a symbol.
1977
+ char * mode ;
1978
+ if (m == SYMread ) mode = "r" ;
1979
+ else if (m == SYMwrite ) mode = "w" ;
1980
+ else if (m == SYMappend ) mode = "a" ;
1981
+ else if (m == SYMreadHappend ) mode = "a+" ;
1982
+ else if (m == SYMreadHwrite ) mode = "w+" ;
1983
+ else if (m == SYMreadHwriteHexisting ) mode = "r+" ;
1984
+ else throw_error ("Expected one of \\read, \\write, \\append, \\read-write, \\read-append, \\read-write-existing" );
1968
1985
FILE * fp = fopen (path , mode );
1969
- if unlikely (!fp ) throw_error_fmt ("cannot open file '%s'" , path );
1986
+ if unlikely (!fp ) throw_error_fmt ("Cannot open file '%s'" , path );
1970
1987
IO io = gc_malloc (sizeof * io );
1971
1988
io -> path = path ;
1972
1989
io -> mode = mode ;
@@ -1979,6 +1996,7 @@ static STRING ___readHfile(IO io)
1979
1996
assert_impure ();
1980
1997
// Read a file to a string.
1981
1998
FILE * fp = io -> file ;
1999
+ fseek (fp , 0 , SEEK_SET ); // seek to beginning
1982
2000
if unlikely (!io -> mode ) throw_error_fmt ("File '%s' is not open" , io -> path );
1983
2001
if unlikely (fp == NULL ) throw_error_fmt ("Cannot open file '%s'" , io -> path );
1984
2002
struct stat st ;
@@ -1988,7 +2006,14 @@ static STRING ___readHfile(IO io)
1988
2006
throw_error_fmt ("Error reading file '%s'" , io -> path );
1989
2007
text [st .st_size ] = '\0' ; // Remove trailing eof.
1990
2008
return text ;
1991
- // TODO: single line (or delimited) file read function for better IO performance
2009
+ }
2010
+
2011
+ static STRING ___readHline (IO io )
2012
+ {
2013
+ assert_impure ();
2014
+ char * buf = (char * )(space [z ] + alloc [z ]); // use the top of memory as a buffer like Show does
2015
+ fgets (buf , INT_MAX , io -> file );
2016
+ return gc_strdup (buf ); // this can only GC once so won't overwrite the buffer.
1992
2017
}
1993
2018
1994
2019
static void ___close (IO io )
@@ -2018,16 +2043,21 @@ static void ___write(STRING s, IO io)
2018
2043
fputs (s , io -> file );
2019
2044
}
2020
2045
2021
- static void ___seek (NUMBER n , IO io )
2046
+ static void ___seek (SYMBOL ref , NUMBER n , IO io )
2022
2047
{
2023
- size_t p = n ;
2024
- if unlikely (p != n ) throw_error_fmt ("cannot seek to position %.14g" , n );
2025
- fseek (io -> file , p , SEEK_CUR );
2048
+ int pos ;
2049
+ if (ref == SYMstart ) pos = SEEK_SET ;
2050
+ else if (ref == SYMend ) pos = SEEK_END ;
2051
+ else if (ref == SYMcurrent ) pos = SEEK_CUR ;
2052
+ else throw_error_fmt ("Expected one of \\start, \\end, \\current" );
2053
+ long offset = n ;
2054
+ if unlikely (offset != n || fseek (io -> file , offset , pos ))
2055
+ throw_error_fmt ("Can't seek to position %.14g relative to %s" , n , ref );
2026
2056
}
2027
2057
2028
2058
static void invalid_jump (uint8_t * env )
2029
2059
{
2030
- throw_error ("cannot resume expired continuation" );
2060
+ throw_error ("Cannot resume expired continuation" );
2031
2061
}
2032
2062
2033
2063
static void oh_no (uint8_t * env )
@@ -2062,7 +2092,7 @@ static TABLE ___table (BLOCK expr)
2062
2092
// Move to a list.
2063
2093
TABLE d = NULL ;
2064
2094
size_t len = stack_length ();
2065
- if (len % 2 != 0 ) throw_error ("table initialiser must be key-value pairs" );
2095
+ if (len % 2 != 0 ) throw_error ("Table initialiser must be key-value pairs" );
2066
2096
for (size_t i = 0 ; i < len ; i += 2 )
2067
2097
{
2068
2098
ANY key = stack .start [i + 1 ];
@@ -2074,7 +2104,7 @@ static TABLE ___table (BLOCK expr)
2074
2104
ptrdiff_t diff = compare_objects (ptr -> key , key );
2075
2105
if (diff > 0 ) { assign = (cognate_table * * )& ptr -> child1 ; ptr = ptr -> child1 ; }
2076
2106
else if (diff < 0 ) { assign = (cognate_table * * )& ptr -> child2 ; ptr = ptr -> child2 ; }
2077
- else throw_error ("duplicate keys in table initialiser" );
2107
+ else throw_error ("Duplicate keys in table initialiser" );
2078
2108
}
2079
2109
2080
2110
* assign = gc_malloc (sizeof (* * assign ));
0 commit comments