[m-rev.] for review: speed up lexer.m

Peter Wang novalazy at gmail.com
Wed May 14 14:28:54 AEST 2008


Estimated hours taken: 1
Branches: main

Speed up the lexer.

library/io.m:
	Add a version of `io.read_char' with an interface that doesn't imply
	memory allocation in the usual case.

library/lexer.m:
	Use the new predicate to read characters.

	Thread the input stream through the lexer instead of looking up the
	"current" input stream for each character.  (Looking up the stream
	is not so trivial after it was made thread-local.)

Index: library/io.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/io.m,v
retrieving revision 1.408
diff -u -r1.408 io.m
--- library/io.m	28 Apr 2008 05:13:05 -0000	1.408
+++ library/io.m	14 May 2008 03:00:18 -0000
@@ -226,6 +226,12 @@
 :- pred io.read_char(io.input_stream::in, io.result(char)::out,
     io::di, io::uo) is det.
 
+    % Reads a character from the specified stream.
+    % This interface avoids memory allocation when there is no error.
+    %
+:- pred io.read_char_unboxed(io.input_stream::in, io.result::out, char::out,
+    io::di, io::uo) is det.
+
     % Reads a whitespace delimited word from specified stream.
     %
 :- pred io.read_word(io.input_stream::in, io.result(list(char))::out,
@@ -1882,6 +1888,22 @@
         Result = error(io_error(Msg))
     ).
 
+:- pragma inline(io.read_char_unboxed/5).
+
+io.read_char_unboxed(Stream, Result, Char, !IO) :-
+    io.read_char_code(Stream, Code, !IO),
+    ( Code = -1 ->
+        Result = eof,
+        Char = char.det_from_int(0)
+    ; char.to_int(Char0, Code) ->
+        Result = ok,
+        Char = Char0
+    ;
+        io.make_err_msg("read failed: ", Msg, !IO),
+        Result = error(io_error(Msg)),
+        Char = char.det_from_int(0)
+    ).
+
 % We want to inline these, to allow deforestation.
 :- pragma inline(io.read_byte/3).
 :- pragma inline(io.read_byte/4).
Index: library/lexer.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/lexer.m,v
retrieving revision 1.56
diff -u -r1.56 lexer.m
--- library/lexer.m	3 Apr 2008 05:26:47 -0000	1.56
+++ library/lexer.m	14 May 2008 03:00:18 -0000
@@ -202,25 +202,26 @@
     % past the `bar', so now we need to match with a `baz'.
 
 get_token_list(Tokens, !IO) :-
-    get_token(Token, Context, !IO),
-    get_token_list_2(Token, Context, Tokens, !IO).
+    io.input_stream(Stream, !IO),
+    get_token(Stream, Token, Context, !IO),
+    get_token_list_2(Stream, Token, Context, Tokens, !IO).
 
-:- pred get_token_list_2(token::in, token_context::in, token_list::out,
-    io::di, io::uo) is det.
+:- pred get_token_list_2(io.input_stream::in, token::in, token_context::in,
+    token_list::out, io::di, io::uo) is det.
 
-get_token_list_2(Token0, Context0, Tokens, !IO) :-
+get_token_list_2(Stream, Token0, Context0, Tokens, !IO) :-
     ( Token0 = eof ->
         Tokens = token_nil
     ; ( Token0 = end ; Token0 = error(_) ; Token0 = io_error(_) ) ->
         Tokens = token_cons(Token0, Context0, token_nil)
     ; Token0 = integer_dot(Int) ->
-        get_context(Context1, !IO),
-        get_dot(Token1, !IO),
-        get_token_list_2(Token1, Context1, Tokens1, !IO),
+        get_context(Stream, Context1, !IO),
+        get_dot(Stream, Token1, !IO),
+        get_token_list_2(Stream, Token1, Context1, Tokens1, !IO),
         Tokens = token_cons(integer(Int), Context0, Tokens1)
     ;
-        get_token(Token1, Context1, !IO),
-        get_token_list_2(Token1, Context1, Tokens1, !IO),
+        get_token(Stream, Token1, Context1, !IO),
+        get_token_list_2(Stream, Token1, Context1, Tokens1, !IO),
         Tokens = token_cons(Token0, Context0, Tokens1)
     ).
 
@@ -243,10 +244,11 @@
 %
 % Some low-level routines.
 
-:- pred get_context(token_context::out, io::di, io::uo) is det.
+:- pred get_context(io.input_stream::in, token_context::out, io::di, io::uo)
+    is det.
 
-get_context(Context, !IO) :-
-    io.get_line_number(Context, !IO).
+get_context(Stream, Context, !IO) :-
+    io.get_line_number(Stream, Context, !IO).
 
 :- type string_token_context == token_context.
 
@@ -310,64 +312,65 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred get_token(token::out, token_context::out, io::di, io::uo) is det.
+:- pred get_token(io.input_stream::in, token::out, token_context::out,
+    io::di, io::uo) is det.
 
-get_token(Token, Context, !IO) :-
-    io.read_char(Result, !IO),
+get_token(Stream, Token, Context, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = io_error(Error)
     ;
         Result = eof,
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = eof
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_whitespace(Char) ->
-            get_token_2(Token, Context, !IO)
+            get_token_2(Stream, Token, Context, !IO)
         ; ( char.is_upper(Char) ; Char = '_' ) ->
-            get_context(Context, !IO),
-            get_variable([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_variable(Stream, [Char], Token, !IO)
         ; char.is_lower(Char) ->
-            get_context(Context, !IO),
-            get_name([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_name(Stream, [Char], Token, !IO)
         ; Char = '0' ->
-            get_context(Context, !IO),
-            get_zero(Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_zero(Stream, Token, !IO)
         ; char.is_digit(Char) ->
-            get_context(Context, !IO),
-            get_number([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_number(Stream, [Char], Token, !IO)
         ; special_token(Char, SpecialToken) ->
-            get_context(Context, !IO),
+            get_context(Stream, Context, !IO),
             ( SpecialToken = open ->
                 Token = open_ct
             ;
                 Token = SpecialToken
             )
         ; Char = ('.') ->
-            get_context(Context, !IO),
-            get_dot(Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_dot(Stream, Token, !IO)
         ; Char = ('%') ->
-            skip_to_eol(Token, Context, !IO)
+            skip_to_eol(Stream, Token, Context, !IO)
         ; ( Char = '"' ; Char = '''' ) ->
-            get_context(Context, !IO),
-            start_quoted_name(Char, [], Token, !IO)
+            get_context(Stream, Context, !IO),
+            start_quoted_name(Stream, Char, [], Token, !IO)
         ; Char = ('/') ->
-            get_slash(Token, Context, !IO)
+            get_slash(Stream, Token, Context, !IO)
         ; Char = ('#') ->
-            get_source_line_number([], Token, Context, !IO)
+            get_source_line_number(Stream, [], Token, Context, !IO)
         ; Char = ('`') ->
-            get_context(Context, !IO),
+            get_context(Stream, Context, !IO),
             Token = name("`")
         ; Char = '$' ->
-            get_context(Context, !IO),
-            get_implementation_defined_literal_rest(Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_implementation_defined_literal_rest(Stream, Token, !IO)
         ; graphic_token_char(Char) ->
-            get_context(Context, !IO),
-            get_graphic([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_graphic(Stream, [Char], Token, !IO)
         ;
-            get_context(Context, !IO),
+            get_context(Stream, Context, !IO),
             Token = junk(Char)
         )
     ).
@@ -429,61 +432,61 @@
     % This is just like get_token, except that we have already scanned past
     % some whitespace, so '(' gets scanned as `open' rather than `open_ct'.
     %
-:- pred get_token_2(token::out, token_context::out, io::di, io::uo)
-    is det.
+:- pred get_token_2(io.input_stream::in, token::out, token_context::out,
+    io::di, io::uo) is det.
 
-get_token_2(Token, Context, !IO) :-
-    io.read_char(Result, !IO),
+get_token_2(Stream, Token, Context, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = io_error(Error)
     ;
         Result = eof,
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = eof
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_whitespace(Char) ->
-            get_token_2(Token, Context, !IO)
+            get_token_2(Stream, Token, Context, !IO)
         ; ( char.is_upper(Char) ; Char = '_' ) ->
-            get_context(Context, !IO),
-            get_variable([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_variable(Stream, [Char], Token, !IO)
         ; char.is_lower(Char) ->
-            get_context(Context, !IO),
-            get_name([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_name(Stream, [Char], Token, !IO)
         ; Char = '0' ->
-            get_context(Context, !IO),
-            get_zero(Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_zero(Stream, Token, !IO)
         ; char.is_digit(Char) ->
-            get_context(Context, !IO),
-            get_number([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_number(Stream, [Char], Token, !IO)
         ; special_token(Char, SpecialToken) ->
-            get_context(Context, !IO),
+            get_context(Stream, Context, !IO),
             Token = SpecialToken
         ; Char = ('.') ->
-            get_context(Context, !IO),
-            get_dot(Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_dot(Stream, Token, !IO)
         ; Char = ('%') ->
-            skip_to_eol(Token, Context, !IO)
+            skip_to_eol(Stream, Token, Context, !IO)
         ; ( Char = '"' ; Char = '''' ) ->
-            get_context(Context, !IO),
-            start_quoted_name(Char, [], Token, !IO)
+            get_context(Stream, Context, !IO),
+            start_quoted_name(Stream, Char, [], Token, !IO)
         ; Char = ('/') ->
-            get_slash(Token, Context, !IO)
+            get_slash(Stream, Token, Context, !IO)
         ; Char = ('#') ->
-            get_source_line_number([], Token, Context, !IO)
+            get_source_line_number(Stream, [], Token, Context, !IO)
         ; Char = ('`') ->
-            get_context(Context, !IO),
+            get_context(Stream, Context, !IO),
             Token = name("`")
         ; Char = '$' ->
-            get_context(Context, !IO),
-            get_implementation_defined_literal_rest(Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_implementation_defined_literal_rest(Stream, Token, !IO)
         ; graphic_token_char(Char) ->
-            get_context(Context, !IO),
-            get_graphic([Char], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_graphic(Stream, [Char], Token, !IO)
         ;
-            get_context(Context, !IO),
+            get_context(Stream, Context, !IO),
             Token = junk(Char)
         )
     ).
@@ -571,10 +574,10 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred get_dot(token::out, io::di, io::uo) is det.
+:- pred get_dot(io.input_stream::in, token::out, io::di, io::uo) is det.
 
-get_dot(Token, !IO) :-
-    io.read_char(Result, !IO),
+get_dot(Stream, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -582,14 +585,14 @@
         Result = eof,
         Token = end
     ;
-        Result = ok(Char),
+        Result = ok,
         ( whitespace_after_dot(Char) ->
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = end
         ; graphic_token_char(Char) ->
-            get_graphic([Char, '.'], Token, !IO)
+            get_graphic(Stream, [Char, '.'], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = name(".")
         )
     ).
@@ -626,25 +629,25 @@
 %
 % Comments.
 
-:- pred skip_to_eol(token::out, token_context::out, io::di, io::uo)
-    is det.
+:- pred skip_to_eol(io.input_stream::in, token::out, token_context::out,
+    io::di, io::uo) is det.
 
-skip_to_eol(Token, Context, !IO) :-
-    io.read_char(Result, !IO),
+skip_to_eol(Stream, Token, Context, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = io_error(Error)
     ;
         Result = eof,
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = eof
     ;
-        Result = ok(Char),
+        Result = ok,
         ( Char = '\n' ->
-            get_token_2(Token, Context, !IO)
+            get_token_2(Stream, Token, Context, !IO)
         ;
-            skip_to_eol(Token, Context, !IO)
+            skip_to_eol(Stream, Token, Context, !IO)
         )
     ).
 
@@ -663,28 +666,29 @@
         Token = eof
     ).
 
-:- pred get_slash(token::out, token_context::out, io::di, io::uo) is det.
+:- pred get_slash(io.input_stream::in, token::out, token_context::out,
+    io::di, io::uo) is det.
 
-get_slash(Token, Context, !IO) :-
-    io.read_char(Result, !IO),
+get_slash(Stream, Token, Context, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = io_error(Error)
     ;
         Result = eof,
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = name("/")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( Char = ('*') ->
-            get_comment(Token, Context, !IO)
+            get_comment(Stream, Token, Context, !IO)
         ; graphic_token_char(Char) ->
-            get_context(Context, !IO),
-            get_graphic([Char, '/'], Token, !IO)
+            get_context(Stream, Context, !IO),
+            get_graphic(Stream, [Char, '/'], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
-            get_context(Context, !IO),
+            io.putback_char(Stream, Char, !IO),
+            get_context(Stream, Context, !IO),
             Token = name("/")
         )
     ).
@@ -708,25 +712,25 @@
         Token = name("/")
     ).
 
-:- pred get_comment(token::out, token_context::out,
+:- pred get_comment(io.input_stream::in, token::out, token_context::out,
     io::di, io::uo) is det.
 
-get_comment(Token, Context, !IO) :-
-    io.read_char(Result, !IO),
+get_comment(Stream, Token, Context, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = io_error(Error)
     ;
         Result = eof,
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = error("unterminated '/*' comment")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( Char = ('*') ->
-            get_comment_2(Token, Context, !IO)
+            get_comment_2(Stream, Token, Context, !IO)
         ;
-            get_comment(Token, Context, !IO)
+            get_comment(Stream, Token, Context, !IO)
         )
     ).
 
@@ -745,27 +749,28 @@
         Token = error("unterminated '/*' comment")
     ).
 
-:- pred get_comment_2(token::out, token_context::out, io::di, io::uo) is det.
+:- pred get_comment_2(io.input_stream::in, token::out, token_context::out,
+    io::di, io::uo) is det.
 
-get_comment_2(Token, Context, !IO) :-
-    io.read_char(Result, !IO),
+get_comment_2(Stream, Token, Context, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = io_error(Error)
     ;
         Result = eof,
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = error("unterminated '/*' comment")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( Char = ('/') ->
             % end of /* ... */ comment, so get next token
-            get_token_2(Token, Context, !IO)
+            get_token_2(Stream, Token, Context, !IO)
         ; Char = ('*') ->
-            get_comment_2(Token, Context, !IO)
+            get_comment_2(Stream, Token, Context, !IO)
         ;
-            get_comment(Token, Context, !IO)
+            get_comment(Stream, Token, Context, !IO)
         )
     ).
 
@@ -791,14 +796,14 @@
 %
 % Quoted names and quoted strings.
 
-:- pred start_quoted_name(char::in, list(char)::in, token::out,
-    io::di, io::uo) is det.
+:- pred start_quoted_name(io.input_stream::in, char::in, list(char)::in,
+    token::out, io::di, io::uo) is det.
 
-start_quoted_name(QuoteChar, Chars, Token, !IO) :-
-    get_quoted_name(QuoteChar, Chars, Token0, !IO),
+start_quoted_name(Stream, QuoteChar, Chars, Token, !IO) :-
+    get_quoted_name(Stream, QuoteChar, Chars, Token0, !IO),
     ( Token0 = error(_) ->
         % Skip to the end of the string or name.
-        start_quoted_name(QuoteChar, Chars, _, !IO),
+        start_quoted_name(Stream, QuoteChar, Chars, _, !IO),
         Token = Token0
     ; Token0 = eof ->
         Token = error("unterminated quote")
@@ -825,11 +830,11 @@
         Token = Token0
     ).
 
-:- pred get_quoted_name(char::in, list(char)::in, token::out,
-    io::di, io::uo) is det.
+:- pred get_quoted_name(io.input_stream::in, char::in, list(char)::in,
+    token::out, io::di, io::uo) is det.
 
-get_quoted_name(QuoteChar, Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_quoted_name(Stream, QuoteChar, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -837,13 +842,13 @@
         Result = eof,
         Token = eof
     ;
-        Result = ok(Char),
+        Result = ok,
         ( Char = QuoteChar ->
-            get_quoted_name_quote(QuoteChar, Chars, Token, !IO)
+            get_quoted_name_quote(Stream, QuoteChar, Chars, Token, !IO)
         ; Char = ('\\') ->
-            get_quoted_name_escape(QuoteChar, Chars, Token, !IO)
+            get_quoted_name_escape(Stream, QuoteChar, Chars, Token, !IO)
         ;
-            get_quoted_name(QuoteChar, [Char | Chars], Token, !IO)
+            get_quoted_name(Stream, QuoteChar, [Char | Chars], Token, !IO)
         )
     ).
 
@@ -869,11 +874,11 @@
         Token = eof
     ).
 
-:- pred get_quoted_name_quote(char::in, list(char)::in, token::out,
-    io::di, io::uo) is det.
+:- pred get_quoted_name_quote(io.input_stream::in, char::in, list(char)::in,
+    token::out, io::di, io::uo) is det.
 
-get_quoted_name_quote(QuoteChar, Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_quoted_name_quote(Stream, QuoteChar, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -881,11 +886,11 @@
         Result = eof,
         finish_quoted_name(QuoteChar, Chars, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( Char = QuoteChar ->
-            get_quoted_name(QuoteChar, [Char | Chars], Token, !IO)
+            get_quoted_name(Stream, QuoteChar, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             finish_quoted_name(QuoteChar, Chars, Token)
         )
     ).
@@ -925,11 +930,11 @@
         Token = error("invalid character in quoted name")
     ).
 
-:- pred get_quoted_name_escape(char::in, list(char)::in, token::out,
-    io::di, io::uo) is det.
+:- pred get_quoted_name_escape(io.input_stream::in, char::in, list(char)::in,
+    token::out, io::di, io::uo) is det.
 
-get_quoted_name_escape(QuoteChar, Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_quoted_name_escape(Stream, QuoteChar, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -937,23 +942,23 @@
         Result = eof,
         Token = eof
     ;
-        Result = ok(Char),
+        Result = ok,
         ( Char = '\n' ->
-            get_quoted_name(QuoteChar, Chars, Token, !IO)
+            get_quoted_name(Stream, QuoteChar, Chars, Token, !IO)
         ; Char = '\r' ->
             % Files created on Windows may have an extra return character.
-            get_quoted_name_escape(QuoteChar, Chars, Token, !IO)
+            get_quoted_name_escape(Stream, QuoteChar, Chars, Token, !IO)
         ; escape_char(Char, EscapedChar) ->
             Chars1 = [EscapedChar | Chars],
-            get_quoted_name(QuoteChar, Chars1, Token, !IO)
+            get_quoted_name(Stream, QuoteChar, Chars1, Token, !IO)
         ; Char = 'x' ->
-            get_hex_escape(QuoteChar, Chars, [], Token, !IO)
+            get_hex_escape(Stream, QuoteChar, Chars, [], Token, !IO)
         ; Char = 'u' ->
-            get_unicode_escape(4, QuoteChar, Chars, [], Token, !IO)
+            get_unicode_escape(Stream, 4, QuoteChar, Chars, [], Token, !IO)
         ; Char = 'U' ->
-            get_unicode_escape(8, QuoteChar, Chars, [], Token, !IO)
+            get_unicode_escape(Stream, 8, QuoteChar, Chars, [], Token, !IO)
         ; char.is_octal_digit(Char) ->
-            get_octal_escape(QuoteChar, Chars, [Char], Token, !IO)
+            get_octal_escape(Stream, QuoteChar, Chars, [Char], Token, !IO)
         ;
             Token = error("invalid escape character")
         )
@@ -1012,10 +1017,11 @@
 escape_char('"', '"').
 escape_char('`', '`').
 
-:- pred get_unicode_escape(int::in, char::in, list(char)::in, list(char)::in,
-    token::out, io::di, io::uo) is det.
+:- pred get_unicode_escape(io.input_stream::in, int::in, char::in,
+    list(char)::in, list(char)::in, token::out, io::di, io::uo) is det.
 
-get_unicode_escape(NumHexChars, QuoteChar, Chars, HexChars, Token, !IO) :-
+get_unicode_escape(Stream, NumHexChars, QuoteChar, Chars, HexChars, Token,
+        !IO) :-
     ( if NumHexChars = list.length(HexChars) then
         ( if
             rev_char_list_to_string(HexChars, HexString),
@@ -1025,14 +1031,14 @@
             ( if UnicodeCharCode = 0 then
                 Token = null_character_error
             else
-                get_quoted_name(QuoteChar, list.reverse(UTFChars) ++ Chars,
-                    Token, !IO)
+                get_quoted_name(Stream, QuoteChar,
+                    list.reverse(UTFChars) ++ Chars, Token, !IO)
             )
         else
             Token = error("invalid Unicode character code")
         )
     else
-        io.read_char(Result, !IO),
+        io.read_char_unboxed(Stream, Result, Char, !IO),
         (
             Result = error(Error),
             Token = io_error(Error)
@@ -1040,9 +1046,9 @@
             Result = eof,
             Token = eof
         ;
-            Result = ok(Char),
+            Result = ok,
             ( if char.is_hex_digit(Char) then
-                get_unicode_escape(NumHexChars, QuoteChar, Chars,
+                get_unicode_escape(Stream, NumHexChars, QuoteChar, Chars,
                     [Char | HexChars], Token, !IO)
             else
                 Token = error("invalid hex character in Unicode escape")
@@ -1240,11 +1246,11 @@
     EncodingInt = 0
 ").
 
-:- pred get_hex_escape(char::in, list(char)::in, list(char)::in,
-    token::out, io::di, io::uo) is det.
+:- pred get_hex_escape(io.input_stream::in, char::in, list(char)::in,
+    list(char)::in, token::out, io::di, io::uo) is det.
 
-get_hex_escape(QuoteChar, Chars, HexChars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_hex_escape(Stream, QuoteChar, Chars, HexChars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1252,11 +1258,12 @@
         Result = eof,
         Token = eof
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_hex_digit(Char) ->
-            get_hex_escape(QuoteChar, Chars, [Char | HexChars], Token, !IO)
+            get_hex_escape(Stream, QuoteChar, Chars, [Char | HexChars], Token,
+                !IO)
         ; Char = ('\\') ->
-            finish_hex_escape(QuoteChar, Chars, HexChars, Token, !IO)
+            finish_hex_escape(Stream, QuoteChar, Chars, HexChars, Token, !IO)
         ;
             Token = error("unterminated hex escape")
         )
@@ -1284,10 +1291,10 @@
         Token = eof
     ).
 
-:- pred finish_hex_escape(char::in, list(char)::in, list(char)::in,
-    token::out, io::di, io::uo) is det.
+:- pred finish_hex_escape(io.input_stream::in, char::in, list(char)::in,
+    list(char)::in, token::out, io::di, io::uo) is det.
 
-finish_hex_escape(QuoteChar, Chars, HexChars, Token, !IO) :-
+finish_hex_escape(Stream, QuoteChar, Chars, HexChars, Token, !IO) :-
     (
         HexChars = [],
         Token = error("empty hex escape")
@@ -1301,7 +1308,7 @@
             ( Int = 0 ->
                 Token = null_character_error
             ;
-                get_quoted_name(QuoteChar, [Char|Chars], Token, !IO)
+                get_quoted_name(Stream, QuoteChar, [Char|Chars], Token, !IO)
             )
         ;
             Token = error("invalid hex escape")
@@ -1338,11 +1345,11 @@
         )
     ).
 
-:- pred get_octal_escape(char::in, list(char)::in, list(char)::in,
-    token::out, io::di, io::uo) is det.
+:- pred get_octal_escape(io.input_stream::in, char::in, list(char)::in,
+    list(char)::in, token::out, io::di, io::uo) is det.
 
-get_octal_escape(QuoteChar, Chars, OctalChars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_octal_escape(Stream, QuoteChar, Chars, OctalChars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1350,18 +1357,20 @@
         Result = eof,
         Token = eof
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_octal_digit(Char) ->
-            get_octal_escape(QuoteChar, Chars, [Char | OctalChars], Token, !IO)
+            get_octal_escape(Stream, QuoteChar, Chars, [Char | OctalChars],
+                Token, !IO)
         ; Char = ('\\') ->
-            finish_octal_escape(QuoteChar, Chars,
+            finish_octal_escape(Stream, QuoteChar, Chars,
                 OctalChars, Token, !IO)
         ;
             % XXX We don't report this as an error since we need bug-for-bug
             % compatibility with NU-Prolog.
             % Token = error("unterminated octal escape")
-            io.putback_char(Char, !IO),
-            finish_octal_escape(QuoteChar, Chars, OctalChars, Token, !IO)
+            io.putback_char(Stream, Char, !IO),
+            finish_octal_escape(Stream, QuoteChar, Chars, OctalChars, Token,
+                !IO)
         )
     ).
 
@@ -1391,10 +1400,10 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred finish_octal_escape(char::in, list(char)::in, list(char)::in,
-    token::out, io::di, io::uo) is det.
+:- pred finish_octal_escape(io.input_stream::in, char::in, list(char)::in,
+    list(char)::in, token::out, io::di, io::uo) is det.
 
-finish_octal_escape(QuoteChar, Chars, OctalChars, Token, !IO) :-
+finish_octal_escape(Stream, QuoteChar, Chars, OctalChars, Token, !IO) :-
     (
         OctalChars = [],
         Token = error("empty octal escape")
@@ -1408,7 +1417,7 @@
             ( Int = 0 ->
                 Token = null_character_error
             ;
-                get_quoted_name(QuoteChar, [Char | Chars], Token, !IO)
+                get_quoted_name(Stream, QuoteChar, [Char | Chars], Token, !IO)
             )
         ;
             Token = error("invalid octal escape")
@@ -1449,10 +1458,11 @@
 %
 % Names and variables.
 
-:- pred get_name(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_name(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_name(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_name(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1464,11 +1474,11 @@
             Token = error("invalid character in name")
         )
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_alnum_or_underscore(Char) ->
-            get_name([Char | Chars], Token, !IO)
+            get_name(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             ( rev_char_list_to_string(Chars, Name) ->
                 Token = name(Name)
             ;
@@ -1496,11 +1506,11 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_implementation_defined_literal_rest(token::out, io::di, io::uo)
-    is det.
+:- pred get_implementation_defined_literal_rest(io.input_stream::in,
+    token::out, io::di, io::uo) is det.
 
-get_implementation_defined_literal_rest(Token, !IO) :-
-    io.read_char(Result, !IO),
+get_implementation_defined_literal_rest(Stream, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1508,18 +1518,18 @@
         Result = eof,
         Token = name("$")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_lower(Char) ->
-            get_name([Char], Token0, !IO),
+            get_name(Stream, [Char], Token0, !IO),
             ( Token0 = name(S) ->
                 Token = implementation_defined(S)
             ;
                 Token = Token0
             )
         ; graphic_token_char(Char) ->
-            get_graphic([Char, '$'], Token, !IO)
+            get_graphic(Stream, [Char, '$'], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = name("$")
         )
     ).
@@ -1560,23 +1570,23 @@
     % (The source file name can be set with a `:- pragma source_file'
     % declaration.)
     %
-:- pred get_source_line_number(list(char)::in, token::out,
+:- pred get_source_line_number(io.input_stream::in, list(char)::in, token::out,
     token_context::out, io::di, io::uo) is det.
 
-get_source_line_number(Chars, Token, Context, !IO) :-
-    io.read_char(Result, !IO),
+get_source_line_number(Stream, Chars, Token, Context, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = io_error(Error)
     ;
         Result = eof,
-        get_context(Context, !IO),
+        get_context(Stream, Context, !IO),
         Token = error("unexpected end-of-file in `#' line number directive")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_digit(Char) ->
-            get_source_line_number([Char | Chars], Token, Context, !IO)
+            get_source_line_number(Stream, [Char | Chars], Token, Context, !IO)
         ; Char = '\n' ->
             (
                 rev_char_list_to_string(Chars, String)
@@ -1585,20 +1595,20 @@
                     string.base_string_to_int(10, String, Int),
                     Int > 0
                 ->
-                    io.set_line_number(Int, !IO),
-                    get_token(Token, Context, !IO)
+                    io.set_line_number(Stream, Int, !IO),
+                    get_token(Stream, Token, Context, !IO)
                 ;
-                    get_context(Context, !IO),
+                    get_context(Stream, Context, !IO),
                     string.append_list(["invalid line number `", String,
                         "' in `#' line number directive"], Message),
                     Token = error(Message)
                 )
             ;
-                get_context(Context, !IO),
+                get_context(Stream, Context, !IO),
                 Token = error("invalid character in `#' line number directive")
             )
         ;
-            get_context(Context, !IO),
+            get_context(Stream, Context, !IO),
             ( char.to_int(Char, 0) ->
                 String = "NUL"
             ;
@@ -1648,10 +1658,11 @@
         Token = error("unexpected end-of-file in `#' line number directive")
     ).
 
-:- pred get_graphic(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_graphic(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_graphic(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_graphic(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1663,11 +1674,11 @@
             Token = error("invalid character in graphic token")
         )
     ;
-        Result = ok(Char),
+        Result = ok,
         ( graphic_token_char(Char) ->
-            get_graphic([Char | Chars], Token, !IO)
+            get_graphic(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             ( rev_char_list_to_string(Chars, Name) ->
                 Token = name(Name)
             ;
@@ -1695,10 +1706,11 @@
         Token = name(Name)
     ).
 
-:- pred get_variable(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_variable(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_variable(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_variable(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1710,11 +1722,11 @@
             Token = error("invalid character in variable")
         )
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_alnum_or_underscore(Char) ->
-            get_variable([Char | Chars], Token, !IO)
+            get_variable(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             ( rev_char_list_to_string(Chars, VariableName) ->
                 Token = variable(VariableName)
             ;
@@ -1746,10 +1758,10 @@
 %
 % Integer and float literals.
 
-:- pred get_zero(token::out, io::di, io::uo) is det.
+:- pred get_zero(io.input_stream::in, token::out, io::di, io::uo) is det.
 
-get_zero(Token, !IO) :-
-    io.read_char(Result, !IO),
+get_zero(Stream, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1757,23 +1769,23 @@
         Result = eof,
         Token = integer(0)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_digit(Char) ->
-            get_number([Char], Token, !IO)
+            get_number(Stream, [Char], Token, !IO)
         ; Char = '''' ->
-            get_char_code(Token, !IO)
+            get_char_code(Stream, Token, !IO)
         ; Char = 'b' ->
-            get_binary(Token, !IO)
+            get_binary(Stream, Token, !IO)
         ; Char = 'o' ->
-            get_octal(Token, !IO)
+            get_octal(Stream, Token, !IO)
         ; Char = 'x' ->
-            get_hex(Token, !IO)
+            get_hex(Stream, Token, !IO)
         ; Char = ('.') ->
-            get_int_dot(['0'], Token, !IO)
+            get_int_dot(Stream, ['0'], Token, !IO)
         ; ( Char = 'e' ; Char = 'E' ) ->
-            get_float_exponent([Char, '0'], Token, !IO)
+            get_float_exponent(Stream, [Char, '0'], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = integer(0)
         )
     ).
@@ -1808,10 +1820,10 @@
         Token = integer(0)
     ).
 
-:- pred get_char_code(token::out, io::di, io::uo) is det.
+:- pred get_char_code(io.input_stream::in, token::out, io::di, io::uo) is det.
 
-get_char_code(Token, !IO) :-
-    io.read_char(Result, !IO),
+get_char_code(Stream, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1819,7 +1831,7 @@
         Result = eof,
         Token = error("unterminated char code constant")
     ;
-        Result = ok(Char),
+        Result = ok,
         char.to_int(Char, CharCode),
         Token = integer(CharCode)
     ).
@@ -1837,10 +1849,10 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_binary(token::out, io::di, io::uo) is det.
+:- pred get_binary(io.input_stream::in, token::out, io::di, io::uo) is det.
 
-get_binary(Token, !IO) :-
-    io.read_char(Result, !IO),
+get_binary(Stream, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1848,11 +1860,11 @@
         Result = eof,
         Token = error("unterminated binary constant")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_binary_digit(Char) ->
-            get_binary_2([Char], Token, !IO)
+            get_binary_2(Stream, [Char], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = error("unterminated binary constant")
         )
     ).
@@ -1874,10 +1886,11 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_binary_2(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_binary_2(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_binary_2(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_binary_2(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1885,11 +1898,11 @@
         Result = eof,
         rev_char_list_to_int(Chars, 2, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_binary_digit(Char) ->
-            get_binary_2([Char | Chars], Token, !IO)
+            get_binary_2(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             rev_char_list_to_int(Chars, 2, Token)
         )
     ).
@@ -1913,10 +1926,10 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_octal(token::out, io::di, io::uo) is det.
+:- pred get_octal(io.input_stream::in, token::out, io::di, io::uo) is det.
 
-get_octal(Token, !IO) :-
-    io.read_char(Result, !IO),
+get_octal(Stream, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1924,11 +1937,11 @@
         Result = eof,
         Token = error("unterminated octal constant")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_octal_digit(Char) ->
-            get_octal_2([Char], Token, !IO)
+            get_octal_2(Stream, [Char], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = error("unterminated octal constant")
         )
     ).
@@ -1951,10 +1964,11 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_octal_2(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_octal_2(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_octal_2(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_octal_2(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -1962,11 +1976,11 @@
         Result = eof,
         rev_char_list_to_int(Chars, 8, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_octal_digit(Char) ->
-            get_octal_2([Char | Chars], Token, !IO)
+            get_octal_2(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             rev_char_list_to_int(Chars, 8, Token)
         )
     ).
@@ -1990,10 +2004,10 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_hex(token::out, io::di, io::uo) is det.
+:- pred get_hex(io.input_stream::in, token::out, io::di, io::uo) is det.
 
-get_hex(Token, !IO) :-
-    io.read_char(Result, !IO),
+get_hex(Stream, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -2001,11 +2015,11 @@
         Result = eof,
         Token = error("unterminated hex constant")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_hex_digit(Char) ->
-            get_hex_2([Char], Token, !IO)
+            get_hex_2(Stream, [Char], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = error("unterminated hex constant")
         )
     ).
@@ -2028,10 +2042,11 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_hex_2(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_hex_2(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_hex_2(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_hex_2(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -2039,11 +2054,11 @@
         Result = eof,
         rev_char_list_to_int(Chars, 16, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_hex_digit(Char) ->
-            get_hex_2([Char | Chars], Token, !IO)
+            get_hex_2(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             rev_char_list_to_int(Chars, 16, Token)
         )
     ).
@@ -2067,10 +2082,11 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_number(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_number(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_number(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_number(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -2078,15 +2094,15 @@
         Result = eof,
         rev_char_list_to_int(Chars, 10, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_digit(Char) ->
-            get_number([Char | Chars], Token, !IO)
+            get_number(Stream, [Char | Chars], Token, !IO)
         ; Char = ('.') ->
-            get_int_dot(Chars, Token, !IO)
+            get_int_dot(Stream, Chars, Token, !IO)
         ; ( Char = 'e' ; Char = 'E' ) ->
-            get_float_exponent([Char | Chars], Token, !IO)
+            get_float_exponent(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             rev_char_list_to_int(Chars, 10, Token)
         )
     ).
@@ -2115,24 +2131,25 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_int_dot(list(char)::in, token::out, io::di, io::uo) is det.
+:- pred get_int_dot(io.input_stream::in, list(char)::in, token::out,
+    io::di, io::uo) is det.
 
-get_int_dot(Chars, Token, !IO) :-
+get_int_dot(Stream, Chars, Token, !IO) :-
     % XXX The float literal syntax doesn't match ISO Prolog.
-    io.read_char(Result, !IO),
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
     ;
         Result = eof,
-        io.putback_char('.', !IO),
+        io.putback_char(Stream, '.', !IO),
         rev_char_list_to_int(Chars, 10, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_digit(Char) ->
-            get_float_decimals([Char, '.' | Chars], Token, !IO)
+            get_float_decimals(Stream, [Char, '.' | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             % We can't putback the ".", because io.putback_char only
             % guarantees one character of pushback. So instead, we return
             % an `integer_dot' token; the main loop of get_token_list_2 will
@@ -2168,13 +2185,13 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_float_decimals(list(char)::in, token::out,
+:- pred get_float_decimals(io.input_stream::in, list(char)::in, token::out,
     io::di, io::uo) is det.
 
     % We've read past the decimal point, so now get the decimals.
     %
-get_float_decimals(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_float_decimals(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -2182,13 +2199,13 @@
         Result = eof,
         rev_char_list_to_float(Chars, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_digit(Char) ->
-            get_float_decimals([Char | Chars], Token, !IO)
+            get_float_decimals(Stream, [Char | Chars], Token, !IO)
         ; ( Char = 'e' ; Char = 'E' ) ->
-            get_float_exponent([Char | Chars], Token, !IO)
+            get_float_exponent(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             rev_char_list_to_float(Chars, Token)
         )
     ).
@@ -2216,11 +2233,11 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_float_exponent(list(char)::in, token::out,
+:- pred get_float_exponent(io.input_stream::in, list(char)::in, token::out,
     io::di, io::uo) is det.
 
-get_float_exponent(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_float_exponent(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -2228,13 +2245,13 @@
         Result = eof,
         rev_char_list_to_float(Chars, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( ( Char = ('+') ; Char = ('-') ) ->
-            get_float_exponent_2([Char | Chars], Token, !IO)
+            get_float_exponent_2(Stream, [Char | Chars], Token, !IO)
         ; char.is_digit(Char) ->
-            get_float_exponent_3([Char | Chars], Token, !IO)
+            get_float_exponent_3(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = error("unterminated exponent in float token")
         )
     ).
@@ -2261,15 +2278,15 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_float_exponent_2(list(char)::in, token::out,
+:- pred get_float_exponent_2(io.input_stream::in, list(char)::in, token::out,
     io::di, io::uo) is det.
 
     % We've read past the E signalling the start of the exponent -
     % make sure that there's at least one digit following,
     % and then get the remaining digits.
     %
-get_float_exponent_2(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_float_exponent_2(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -2277,11 +2294,11 @@
         Result = eof,
         Token = error("unterminated exponent in float token")
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_digit(Char) ->
-            get_float_exponent_3([Char | Chars], Token, !IO)
+            get_float_exponent_3(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             Token = error("unterminated exponent in float token")
         )
     ).
@@ -2308,14 +2325,14 @@
         string_get_context(Posn0, Context, !Posn)
     ).
 
-:- pred get_float_exponent_3(list(char)::in, token::out,
+:- pred get_float_exponent_3(io.input_stream::in, list(char)::in, token::out,
     io::di, io::uo) is det.
 
     % We've read past the first digit of the exponent -
     % now get the remaining digits.
     %
-get_float_exponent_3(Chars, Token, !IO) :-
-    io.read_char(Result, !IO),
+get_float_exponent_3(Stream, Chars, Token, !IO) :-
+    io.read_char_unboxed(Stream, Result, Char, !IO),
     (
         Result = error(Error),
         Token = io_error(Error)
@@ -2323,11 +2340,11 @@
         Result = eof,
         rev_char_list_to_float(Chars, Token)
     ;
-        Result = ok(Char),
+        Result = ok,
         ( char.is_digit(Char) ->
-            get_float_exponent_3([Char | Chars], Token, !IO)
+            get_float_exponent_3(Stream, [Char | Chars], Token, !IO)
         ;
-            io.putback_char(Char, !IO),
+            io.putback_char(Stream, Char, !IO),
             rev_char_list_to_float(Chars, Token)
         )
     ).


--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list