From 295a44f67d8739d25e8cbcb8a4321b04efcd7df8 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Fri, 16 Aug 2019 19:06:21 +0200 Subject: [PATCH] as: convert to module-tagged errors, format_error/1, and error:format/1; improve specs --- erlang/apps/as/src/as.erl | 4 ++-- erlang/apps/as/src/assemble.erl | 10 +++++++- erlang/apps/as/src/input.erl | 10 +++++--- erlang/apps/as/src/output.erl | 10 +++++++- erlang/apps/as/src/parse.erl | 12 +++++++--- erlang/apps/as/src/scan.erl | 12 +++++++--- erlang/apps/as/src/scan_state.erl | 38 ++++++++++++++++++++++--------- erlang/apps/as/src/token.erl | 6 ++--- 8 files changed, 75 insertions(+), 27 deletions(-) diff --git a/erlang/apps/as/src/as.erl b/erlang/apps/as/src/as.erl index 88b3742..9c20dc3 100644 --- a/erlang/apps/as/src/as.erl +++ b/erlang/apps/as/src/as.erl @@ -36,8 +36,8 @@ main_(Argv) -> ok -> halt(0); {error, _Reason} = Error -> escript_runtime:fatal("~p\n", [Error]) end; - {error, ErrMsg} -> - escript_runtime:errmsg("~s\n", [ErrMsg]), + {error, Reason} -> + escript_runtime:errmsg("~s\n", [error:format(Reason)]), usage() end. diff --git a/erlang/apps/as/src/assemble.erl b/erlang/apps/as/src/assemble.erl index d7f2bb9..6f6c0c7 100644 --- a/erlang/apps/as/src/assemble.erl +++ b/erlang/apps/as/src/assemble.erl @@ -21,11 +21,13 @@ -module(assemble). -export([ tunit/1 + , format_error/1 ]). -include("tunit.hrl"). -include_lib("lib/include/pdp10_elf36.hrl"). +-spec tunit(#tunit{}) -> {ok, #tunit{}} | {error, {module(), term()}}. tunit(Tunit) -> sections(maps:values(Tunit#tunit.sections), Tunit). @@ -47,7 +49,7 @@ section(Section, Tunit) -> , sh_flags = ?SHF_MERGE bor ?SHF_STRINGS } -> comment(Section, Tunit); #section{ name = Name } -> - {error, io_lib:format("don't know how to assemble section ~s", [Name])} + {error, {?MODULE, {cannot_assemble, Name}}} end. %% Assemble .comment ----------------------------------------------------------- @@ -100,3 +102,9 @@ insn_image(Insn) -> (Word bsr 18) band 511, (Word bsr 9) band 511, Word band 511]. + +%% Error reporting ------------------------------------------------------------- + +-spec format_error(term()) -> io_lib:chars(). +format_error({cannot_assemble, Name}) -> + io_lib:format("don't know how to assemble section ~s", [Name]). diff --git a/erlang/apps/as/src/input.erl b/erlang/apps/as/src/input.erl index a3ba055..5279044 100644 --- a/erlang/apps/as/src/input.erl +++ b/erlang/apps/as/src/input.erl @@ -21,11 +21,13 @@ -module(input). -export([ files/1 + , format_error/1 ]). -include("tunit.hrl"). -include_lib("lib/include/pdp10_elf36.hrl"). +-spec files([string()]) -> {ok, #tunit{}} | {error, {module(), term()}}. files(Files) -> NewFiles = case Files of @@ -235,9 +237,11 @@ section_dot_text() -> % ".text" %% Error reporting ------------------------------------------------------------- -%% FIXME: this is duplicated a few times, move it to scan_state.erl fmterr(ScanState, Fmt, Args) -> {ok, FileName} = scan_state:filename(ScanState), {ok, LineNr} = scan_state:linenr(ScanState), - {error, lists:flatten(io_lib:format("file ~s line ~p: " ++ Fmt, - [FileName, LineNr | Args]))}. + {error, {?MODULE, {FileName, LineNr, Fmt, Args}}}. + +-spec format_error(term()) -> io_lib:chars(). +format_error({FileName, LineNr, Fmt, Args}) -> + io_lib:format("file ~s line ~p: " ++ Fmt, [FileName, LineNr | Args]). diff --git a/erlang/apps/as/src/output.erl b/erlang/apps/as/src/output.erl index 3279914..bf1b930 100644 --- a/erlang/apps/as/src/output.erl +++ b/erlang/apps/as/src/output.erl @@ -46,6 +46,7 @@ -module(output). -export([ tunit/2 + , format_error/1 ]). -include("tunit.hrl"). @@ -64,6 +65,7 @@ , strtab :: #strtab{} }). +-spec tunit(#tunit{}, string()) -> ok | {error, {module(), term()}}. tunit(Tunit, File) -> emit(layout(Tunit), File). @@ -330,7 +332,7 @@ emit(Context, File) -> emit(Funs, Context, FP, 0) after pdp10_stdio:fclose(FP) end; - {error, Reason} -> {error, io_lib:format("opening ~s: ~p", [File, Reason])} + {error, Reason} -> {error, {?MODULE, {cannot_open, File, Reason}}} end. emit([], _Context, _FP, _Offset) -> ok; @@ -558,3 +560,9 @@ image_write([H | T], FP) -> image_write([], _FP) -> ok; image_write(TByte, FP) when is_integer(TByte), 0 =< TByte, TByte =< 511 -> pdp10_stdio:fputc(TByte, FP). + +%% Error reporting ------------------------------------------------------------- + +-spec format_error(term()) -> io_lib:chars(). +format_error({cannot_open, File, Reason}) -> + io_lib:format("opening ~s: ~s", [File, error:format(Reason)]). diff --git a/erlang/apps/as/src/parse.erl b/erlang/apps/as/src/parse.erl index 7eeda67..94a5ff5 100644 --- a/erlang/apps/as/src/parse.erl +++ b/erlang/apps/as/src/parse.erl @@ -21,12 +21,15 @@ -module(parse). -export([ stmt/1 + , format_error/1 ]). -include("token.hrl"). -include("tunit.hrl"). -include_lib("lib/include/pdp10_opcodes.hrl"). +-spec stmt(scan_state:scan_state()) + -> {ok, stmt()} | eof | {error, {module(), term()}}. stmt(ScanState) -> case scan:token(ScanState) of {ok, ?T_DOT_FILE} -> dot_file(ScanState); @@ -303,10 +306,13 @@ dot_type(ScanState) -> badtok(_ScanState, _ErrMsg, {error, _Reason} = Error) -> Error; badtok(ScanState, ErrMsg, {ok, Token}) -> - fmterr(ScanState, ErrMsg ++ "; current token is ~s", [token:to_string(Token)]). + fmterr(ScanState, ErrMsg ++ "; current token is ~s", [token:format(Token)]). fmterr(ScanState, Fmt, Args) -> {ok, FileName} = scan_state:filename(ScanState), {ok, LineNr} = scan_state:linenr(ScanState), - {error, lists:flatten(io_lib:format("file ~s line ~p: " ++ Fmt, - [FileName, LineNr | Args]))}. + {error, {?MODULE, {FileName, LineNr, Fmt, Args}}}. + +-spec format_error(term()) -> io_lib:chars(). +format_error({FileName, LineNr, Fmt, Args}) -> + io_lib:format("file ~s line ~p: " ++ Fmt, [FileName, LineNr | Args]). diff --git a/erlang/apps/as/src/scan.erl b/erlang/apps/as/src/scan.erl index 72c564d..a38507c 100644 --- a/erlang/apps/as/src/scan.erl +++ b/erlang/apps/as/src/scan.erl @@ -21,10 +21,13 @@ -module(scan). -export([ token/1 + , format_error/1 ]). -include("token.hrl"). +-spec token(scan_state:scan_state()) + -> {ok, token()} | {error, {module(), term()}}. token(ScanState) -> case scan_state:fgetc(ScanState) of {error, _Reason} = Error -> Error; @@ -220,11 +223,14 @@ chval(Ch) -> end. badchar(ScanState, Ch, Context) -> - ChStr = char_to_string(Ch), {ok, FileName} = scan_state:filename(ScanState), {ok, LineNr} = scan_state:linenr(ScanState), - {error, lists:flatten(io_lib:format("~s line ~p: invalid character '~s' ~s", - [FileName, LineNr, ChStr, Context]))}. + {error, {?MODULE, {FileName, LineNr, Ch, Context}}}. + +-spec format_error(term()) -> io_lib:chars(). +format_error({FileName, LineNr, Ch, Context}) -> + io_lib:format("~s line ~p: invalid character '~s' ~s", + [FileName, LineNr, char_to_string(Ch), Context]). char_to_string(eof) -> ""; char_to_string(Ch) when $\s =< Ch, Ch =< $~ -> [$', Ch, $']; diff --git a/erlang/apps/as/src/scan_state.erl b/erlang/apps/as/src/scan_state.erl index d1bf583..64e77a6 100644 --- a/erlang/apps/as/src/scan_state.erl +++ b/erlang/apps/as/src/scan_state.erl @@ -31,6 +31,7 @@ % meta-data accessors , filename/1 , linenr/1 + , format_error/1 ]). %% gen_server callbacks @@ -52,39 +53,54 @@ , linenr :: pos_integer() }). +-type scan_state() :: pid(). + +-export_type([scan_state/0]). + %% API ------------------------------------------------------------------------- --spec fclose(pid()) -> ok | {error, any()}. +-spec fclose(scan_state()) -> ok | {error, {module(), term()}}. fclose(Pid) -> gen_server:call(Pid, fclose, infinity). --spec fgetc(pid()) -> {ok, byte()} | eof | {error, any()}. +-spec fgetc(scan_state()) -> {ok, byte()} | eof | {error, {module(), term()}}. fgetc(Pid) -> gen_server:call(Pid, fgetc, infinity). --spec fopen(string()) -> {ok, pid()} | {error, any()}. +-spec fopen(string()) -> {ok, scan_state()} | {error, {module(), term()}}. fopen(File) -> do_fopen(File). --spec stdin() -> {ok, pid()}. +-spec stdin() -> {ok, scan_state()}. stdin() -> do_fopen(stdin). do_fopen(File) -> gen_server:start(?MODULE, File, []). --spec ungetc(byte(), pid()) -> ok | {error, any()}. +-spec ungetc(byte(), scan_state()) -> ok | {error, {module(), term()}}. ungetc(Ch, Pid) -> gen_server:call(Pid, {ungetc, Ch}, infinity). --spec filename(pid()) -> {ok, string()}. +-spec filename(scan_state()) -> {ok, string()}. filename(Pid) -> gen_server:call(Pid, filename, infinity). --spec linenr(pid()) -> {ok, pos_integer()}. +-spec linenr(scan_state()) -> {ok, pos_integer()}. linenr(Pid) -> gen_server:call(Pid, linenr, infinity). +-spec format_error(term()) -> io_lib:chars(). +format_error(Reason) -> + case Reason of + {bad_request, Req} -> + io_lib:format("internal error: bad request: ~p", [Req]); + ungetc -> + "internal error: invalid ungetc"; + _ -> + io_lib:format("~p", [Reason]) + end. + %% gen_server callbacks -------------------------------------------------------- init(stdin) -> @@ -92,7 +108,7 @@ init(stdin) -> init(File) -> case file:open(File, [raw, read, read_ahead]) of {ok, IoDev} -> do_init(File, IoDev); - {error, Reason} -> {stop, Reason} + {error, Reason} -> {stop, {file, Reason}} end. do_init(FileName, IoDev) -> @@ -115,7 +131,7 @@ handle_call(Req, _From, State) -> linenr -> {reply, {ok, State#state.linenr}, State}; _ -> - {reply, {error, {bad_request, Req}}, State} + {reply, {error, {?MODULE, {bad_request, Req}}}, State} end. handle_cast(_Req, State) -> @@ -155,7 +171,7 @@ handle_fgetc(State) -> _ -> State end}; eof -> {eof, State}; - {error, _Reason} = Error -> {Error, State} + {error, Reason} -> {{error, {file, Reason}}, State} end, {reply, Result, NewState}; Ch -> @@ -167,5 +183,5 @@ handle_fgetc(State) -> handle_ungetc(State, Ch) -> case State#state.ungetc of [] -> {reply, ok, State#state{ungetc = Ch}}; - _ -> {reply, {error, ungetc}, State} + _ -> {reply, {error, {?MODULE, ungetc}}, State} end. diff --git a/erlang/apps/as/src/token.erl b/erlang/apps/as/src/token.erl index 50591cf..ec4e9d9 100644 --- a/erlang/apps/as/src/token.erl +++ b/erlang/apps/as/src/token.erl @@ -21,7 +21,7 @@ -module(token). -export([ from_symbol/1 - , to_string/1 + , format/1 ]). -include("token.hrl"). @@ -38,8 +38,8 @@ from_symbol(Name) -> _ -> {?T_SYMBOL, Name} end. --spec to_string(token()) -> string(). -to_string(Token) -> +-spec format(token()) -> io_lib:chars(). +format(Token) -> case Token of ?T_DOT_FILE -> ".file"; ?T_DOT_GLOBL -> ".globl";