From 2c8038c2da5420453419aff8084e25ee80c0fa5f Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 16 Jun 2012 18:20:06 +0200 Subject: [PATCH] WIP --- lib/stdlib/src/epp.erl | 155 ++++++++------ lib/stdlib/src/erl_parse.yrl | 386 +++++++++++++++++++++------------- lib/stdlib/src/escript.erl | 2 +- lib/stdlib/src/io.erl | 12 +- lib/stdlib/test/epp_SUITE.erl | 2 +- 5 files changed, 352 insertions(+), 205 deletions(-) diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index 418db3392b8d..1a6bcc537267 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -20,9 +20,9 @@ %% An Erlang code preprocessor. --export([open/2,open/3,open/4, open/5,close/1,format_error/1]). +-export([open/2,open/3,open/4, open/5, open/6,close/1,format_error/1]). -export([scan_erl_form/1,parse_erl_form/1,macro_defs/1]). --export([parse_file/1, parse_file/3, parse_file/4]). +-export([parse_file/1, parse_file/3, parse_file/4, parse_file/5]). -export([interpret_file_attribute/1]). -export([normalize_typed_record_fields/1,restore_typed_record_fields/1]). @@ -42,7 +42,8 @@ path=[], %Include-path macs = dict:new() :: dict(), %Macros (don't care locations) uses = dict:new() :: dict(), %Macro use structure - pre_opened = false :: boolean() + pre_opened = false :: boolean(), + range = false :: boolean() }). %%% Note on representation: as tokens, both {var, Location, Name} and @@ -95,13 +96,18 @@ open(Name, Path, Pdm) -> ErrorDescriptor :: term(). open(Name, StartLocation, Path, Pdm) -> + open(Name, StartLocation, Path, Pdm, []). + +open(Name, StartLocation, Path, Pdm, Opts) -> Self = self(), - Epp = spawn(fun() -> server(Self, Name, StartLocation, Path, Pdm) end), + Epp = spawn(fun() -> server(Self, Name, + StartLocation, Path, Pdm, Opts) end), epp_request(Epp). -open(Name, File, StartLocation, Path, Pdm) -> +open(Name, File, StartLocation, Path, Pdm, Opts) -> Self = self(), - Epp = spawn(fun() -> server(Self, Name, File, StartLocation,Path,Pdm) end), + Epp = spawn(fun() -> server(Self, Name, File, + StartLocation,Path,Pdm,Opts) end), epp_request(Epp). -spec close(Epp) -> 'ok' when @@ -206,7 +212,23 @@ parse_file(Ifile, Path, Predefs) -> OpenError :: file:posix() | badarg | system_limit. parse_file(Ifile, StartLocation, Path, Predefs) -> - case open(Ifile, StartLocation, Path, Predefs) of + parse_file(Ifile, StartLocation, Path, Predefs, []). + +-spec parse_file(FileName, StartLocation, IncludePath, PredefMacros, + ScanOptions) -> + {'ok', [Form]} | {error, OpenError} when + FileName :: file:name(), + StartLocation :: erl_scan:location(), + IncludePath :: [DirectoryName :: file:name()], + Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line}, + PredefMacros :: macros(), + ScanOptions :: erl_scan:options(), + Line :: erl_scan:line(), + ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(), + OpenError :: file:posix() | badarg | system_limit. + +parse_file(Ifile, StartLocation, Path, Predefs, ScanOptions) -> + case open(Ifile, StartLocation, Path, Predefs, ScanOptions) of {ok,Epp} -> Forms = parse_file(Epp), close(Epp), @@ -273,22 +295,22 @@ restore_typed_record_fields([{attribute,La,type,{{record,Record},Fields,[]}}| restore_typed_record_fields([Form|Forms]) -> [Form|restore_typed_record_fields(Forms)]. -%% server(StarterPid, FileName, Location, Path, PreDefMacros) -server(Pid, Name, AtLocation, Path, Pdm) -> +%% server(StarterPid, FileName, Location, Path, PreDefMacros, Opts) +server(Pid, Name, AtLocation, Path, Pdm, Opts) -> process_flag(trap_exit, true), case file:open(Name, [read]) of {ok,File} -> - init_server(Pid, Name, File, AtLocation, Path, Pdm, false); + init_server(Pid, Name, File, AtLocation, Path, Pdm, false, Opts); {error,E} -> epp_reply(Pid, {error,E}) end. -%% server(StarterPid, FileName, IoDevice, Location, Path, PreDefMacros) -server(Pid, Name, File, AtLocation, Path, Pdm) -> +%% server(StarterPid, FileName, IoDevice, Location, Path, PreDefMacros, Opts) +server(Pid, Name, File, AtLocation, Path, Pdm, Opts) -> process_flag(trap_exit, true), - init_server(Pid, Name, File, AtLocation, Path, Pdm, true). + init_server(Pid, Name, File, AtLocation, Path, Pdm, true, Opts). -init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre) -> +init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre, Opts) -> Ms0 = predef_macros(Name), case user_predef(Pdm, Ms0) of {ok,Ms1} -> @@ -296,7 +318,8 @@ init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre) -> %% ensure directory of current source file is first in path Path1 = [filename:dirname(Name) | Path], St = #epp{file=File, location=AtLocation, delta=0, name=Name, - name2=Name, path=Path1, macs=Ms1, pre_opened = Pre}, + name2=Name, path=Path1, macs=Ms1, pre_opened = Pre, + range = lists:member(range, Opts)}, From = wait_request(St), enter_file_reply(From, Name, AtLocation, AtLocation), wait_req_scan(St); @@ -352,6 +375,10 @@ user_predef([M|Pdm], Ms) when is_atom(M) -> user_predef([Md|_Pdm], _Ms) -> {error,{bad,Md}}; user_predef([], Ms) -> {ok,Ms}. +-spec scan_options(#epp{}) -> ['end']. +scan_options(#epp{range = Range}) -> + [ 'end' || Range ]. + %% wait_request(EppState) -> RequestFrom %% wait_req_scan(EppState) %% wait_req_skip(EppState, SkipIstack) @@ -362,7 +389,9 @@ wait_request(St) -> receive {epp_request,From,scan_erl_form} -> From; {epp_request,From,macro_defs} -> - epp_reply(From, dict:to_list(St#epp.macs)), + Macs = dict:to_list(St#epp.macs), + Macs2 = [ {Arity, Def} || {Arity, Def, _File} <- Macs ], + epp_reply(From, Macs2), wait_request(St); {epp_request,From,close} -> close_file(St), @@ -414,7 +443,8 @@ enter_file(NewName, Inc, From, St) -> enter_file2(NewF, Pname, From, St, AtLocation) -> Loc = start_loc(AtLocation), enter_file_reply(From, Pname, Loc, AtLocation), - Ms = dict:store({atom,'FILE'}, {none,[{string,Loc,Pname}]}, St#epp.macs), + Ms = dict:store({atom,'FILE'}, + {none,[{string,Loc,Pname}],nofile}, St#epp.macs), %% update the head of the include path to be the directory of the new %% source file, so that an included file can always include other files %% relative to its current location (this is also how C does it); note @@ -460,7 +490,7 @@ leave_file(From, St) -> name2=OldName2} = OldSt, CurrLoc = add_line(OldLoc, Delta), Ms = dict:store({atom,'FILE'}, - {none,[{string,CurrLoc,OldName2}]}, + {none,[{string,CurrLoc,OldName2}],nofile}, St#epp.macs), NextSt = OldSt#epp{sstk=Sts,macs=Ms}, enter_file_reply(From, OldName, CurrLoc, CurrLoc), @@ -483,7 +513,7 @@ leave_file(From, St) -> %% scan_toks(Tokens, From, EppState) scan_toks(From, St) -> - case io:scan_erl_form(St#epp.file, '', St#epp.location) of + case io:scan_erl_form(St#epp.file, '', St#epp.location, scan_options(St)) of {ok,Toks,Cl} -> scan_toks(Toks, From, St#epp{location=Cl}); {error,E,Cl} -> @@ -581,7 +611,8 @@ scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{',',Lc}|Toks], _Def, From, St) false -> scan_define_cont(From, St, {atom, M}, - {none, {none,Expansion}}) + {none, + {none,Expansion,St#epp.name2}}) end; {ok, _PreDef} -> %% Predefined macros: cannot be overloaded @@ -590,7 +621,7 @@ scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{',',Lc}|Toks], _Def, From, St) error -> scan_define_cont(From, St, {atom, M}, - {none, {none,Expansion}}) + {none, {none,Expansion,St#epp.name2}}) end; {error,ErrL,What} -> epp_reply(From, {error,{ErrL,epp,What}}), @@ -610,7 +641,7 @@ scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{'(',_Lc}|Toks], Def, From, St) wait_req_scan(St); false -> scan_define_cont(From, St, {atom, M}, - {Len, {As, Me}}) + {Len, {As, Me, St#epp.name2}}) end; {ok, _PreDef} -> %% Predefined macros: cannot be overloaded @@ -618,7 +649,8 @@ scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{'(',_Lc}|Toks], Def, From, St) epp_reply(From, {error,{loc(Mac),epp,{redefine_predef,M}}}), wait_req_scan(St); error -> - scan_define_cont(From, St, {atom, M}, {Len, {As, Me}}) + scan_define_cont(From, St, {atom, M}, + {Len, {As, Me, St#epp.name2}}) end; {error,ErrL,What} -> epp_reply(From, {error,{ErrL,epp,What}}), @@ -651,7 +683,7 @@ scan_define_cont(F, St, M, {Arity, Def}) -> wait_req_scan(St) end. -macro_uses({_Args, Tokens}) -> +macro_uses({_Args, Tokens, _File}) -> Uses0 = macro_ref(Tokens), lists:usort(Uses0). @@ -838,7 +870,8 @@ scan_endif(_Toks, Endif, From, St) -> scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp}, {dot,_Ld}], Tf, From, St) -> enter_file_reply(From, Name, Ln, neg_line(abs_loc(Tf))), - Ms = dict:store({atom,'FILE'}, {none,[{string,1,Name}]}, St#epp.macs), + Ms = dict:store({atom,'FILE'}, + {none,[{string,1,Name}],nofile}, St#epp.macs), Locf = loc(Tf), NewLoc = new_location(Ln, St#epp.location, Locf), {line, Line} = erl_scan:token_info(Tf, line), @@ -918,16 +951,20 @@ expand_macros(Type, MacT, M, Toks, Ms0) -> %% (Type will always be 'atom') {Ms, U} = Ms0, Lm = loc(MacT), - Tinfo = element(2, MacT), case expand_macro1(Type, Lm, M, Toks, Ms) of - {ok,{none,Exp}} -> + {ok,{none,Exp,File}} -> check_uses([{{Type,M}, none}], [], U, Lm), - Toks1 = expand_macros(expand_macro(Exp, Tinfo, [], dict:new()), Ms0), - expand_macros(Toks1++Toks, Ms0); - {ok,{As,Exp}} -> + Tinfo = element(2, MacT), + Toks1 = expand_macro(Exp, Tinfo, [], dict:new(), File), + io:format("~p~n", [Toks1]), + Toks2 = expand_macros(Toks1, Ms0), + expand_macros(Toks2++Toks, Ms0); + {ok,{As,Exp,File}} -> check_uses([{{Type,M}, length(As)}], [], U, Lm), - {Bs,Toks1} = bind_args(Toks, Lm, M, As, dict:new()), - expand_macros(expand_macro(Exp, Tinfo, Toks1, Bs), Ms0) + {Bs,Lrp,Toks1} = bind_args(Toks, Lm, M, As, dict:new()), + Tinfo = element(2, erl_parse:range_end(Lrp, MacT)), + io:format("~p~n", [expand_macro(Exp, Tinfo, Toks1, Bs, File)]), + expand_macros(expand_macro(Exp, Tinfo, Toks1, Bs, File), Ms0) end. expand_macro1(Type, Lm, M, Toks, Ms) -> @@ -973,14 +1010,14 @@ get_macro_uses({M,Arity}, U) -> %% Macro expansion %% Note: io:scan_erl_form() does not return comments or white spaces. -expand_macros([{'?',_Lq},{atom,_Lm,M}=MacT|Toks], Ms) -> - expand_macros(atom, MacT, M, Toks, Ms); +expand_macros([{'?',Lq},{atom,Lm,M}=MacT|Toks], Ms) -> + expand_macros(atom, erl_parse:range(Lq, Lm, MacT), M, Toks, Ms); %% Special macros -expand_macros([{'?',_Lq},{var,Lm,'LINE'}=Tok|Toks], Ms) -> +expand_macros([{'?',Lq},{var,Lm,'LINE'}=Tok|Toks], Ms) -> {line,Line} = erl_scan:token_info(Tok, line), - [{integer,Lm,Line}|expand_macros(Toks, Ms)]; -expand_macros([{'?',_Lq},{var,_Lm,M}=MacT|Toks], Ms) -> - expand_macros(atom, MacT, M, Toks, Ms); + [erl_parse:range(Lq, Lm, {integer,Lm,Line})|expand_macros(Toks, Ms)]; +expand_macros([{'?',Lq},{var,Lm,M}=MacT|Toks], Ms) -> + expand_macros(atom, erl_parse:range(Lq, Lm, MacT), M, Toks, Ms); %% Illegal macros expand_macros([{'?',_Lq},Token|_Toks], _Ms) -> T = case erl_scan:token_info(Token, text) of @@ -998,16 +1035,16 @@ expand_macros([], _Ms) -> []. %% bind_args(Tokens, MacroLocation, MacroName, ArgumentVars, Bindings) %% Collect the arguments to a macro call. -bind_args([{'(',_Llp},{')',_Lrp}|Toks], _Lm, _M, [], Bs) -> - {Bs,Toks}; +bind_args([{'(',_Llp},{')',Lrp}|Toks], _Lm, _M, [], Bs) -> + {Bs,Lrp,Toks}; bind_args([{'(',_Llp}|Toks0], Lm, M, [A|As], Bs) -> {Arg,Toks1} = macro_arg(Toks0, [], []), macro_args(Toks1, Lm, M, As, store_arg(Lm, M, A, Arg, Bs)); bind_args(_Toks, Lm, M, _As, _Bs) -> throw({error,Lm,{mismatch,M}}). % Cannot happen. -macro_args([{')',_Lrp}|Toks], _Lm, _M, [], Bs) -> - {Bs,Toks}; +macro_args([{')',Lrp}|Toks], _Lm, _M, [], Bs) -> + {Bs,Lrp,Toks}; macro_args([{',',_Lc}|Toks0], Lm, M, [A|As], Bs) -> {Arg,Toks1} = macro_arg(Toks0, [], []), macro_args(Toks1, Lm, M, As, store_arg(Lm, M, A, Arg, Bs)); @@ -1091,32 +1128,30 @@ macro_arg([], _E, Arg) -> %% argument values, inserting the location of first the macro call %% and then the macro arguments, i.e. simulate textual expansion. -expand_macro([{var,_Lv,V}|Ts], L, Rest, Bs) -> +expand_macro([{var,_Lv,V}|Ts], L, Rest, Bs, File) -> case dict:find(V, Bs) of {ok,Val} -> %% lists:append(Val, expand_macro(Ts, L, Rest, Bs)); - expand_arg(Val, Ts, L, Rest, Bs); + expand_arg(Val, Ts, L, Rest, Bs, File); error -> - [{var,L,V}|expand_macro(Ts, L, Rest, Bs)] + [{var,L,V}|expand_macro(Ts, L, Rest, Bs, File)] end; -expand_macro([{'?', _}, {'?', _}, {var,_Lv,V}|Ts], L, Rest, Bs) -> +expand_macro([{'?', _}, {'?', _}, {var,_Lv,V}|Ts], L, Rest, Bs, File) -> case dict:find(V, Bs) of {ok,Val} -> %% lists:append(Val, expand_macro(Ts, L, Rest, Bs)); - expand_arg(stringify(Val, L), Ts, L, Rest, Bs); + expand_arg(stringify(Val, L), Ts, L, Rest, Bs, File); error -> - [{var,L,V}|expand_macro(Ts, L, Rest, Bs)] + [{var,L,V}|expand_macro(Ts, L, Rest, Bs, File)] end; -expand_macro([T|Ts], L, Rest, Bs) -> - [setelement(2, T, L)|expand_macro(Ts, L, Rest, Bs)]; -expand_macro([], _L, Rest, _Bs) -> Rest. +expand_macro([T|Ts], L, Rest, Bs, File) -> + [setelement(2, T, L)|expand_macro(Ts, L, Rest, Bs, File)]; +expand_macro([], _L, Rest, _Bs, _File) -> Rest. -expand_arg([A|As], Ts, _L, Rest, Bs) -> - %% It is not obvious that the location of arguments should replace L. - NextL = element(2, A), - [A|expand_arg(As, Ts, NextL, Rest, Bs)]; -expand_arg([], Ts, L, Rest, Bs) -> - expand_macro(Ts, L, Rest, Bs). +expand_arg([A|As], Ts, L, Rest, Bs, File) -> + [A|expand_arg(As, Ts, L, Rest, Bs, File)]; +expand_arg([], Ts, L, Rest, Bs, File) -> + expand_macro(Ts, L, Rest, Bs, File). %%% stringify(Ts, L) returns a list of one token: a string which when %%% tokenized would yield the token list Ts. @@ -1140,9 +1175,11 @@ stringify1([]) -> stringify1([T | Tokens]) -> [io_lib:format(" ~s", [token_src(T)]) | stringify1(Tokens)]. -stringify(Ts, L) -> +stringify([T|_]=Ts, _L) -> [$\s | S] = lists:flatten(stringify1(Ts)), - [{string, L, S}]. + Lb = element(2, T), + Le = element(2, lists:last(Ts)), + [erl_parse:range_end(Le, {string, Lb, S})]. %% epp_request(Epp) %% epp_request(Epp, Request) diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 928c10f7f2cb..a19769dd40d0 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -69,64 +69,83 @@ Expect 2. Rootsymbol form. -form -> attribute dot : '$1'. -form -> function dot : '$1'. -form -> rule dot : '$1'. - -attribute -> '-' atom attr_val : build_attribute('$2', '$3'). -attribute -> '-' atom typed_attr_val : build_typed_attribute('$2','$3'). -attribute -> '-' atom '(' typed_attr_val ')' : build_typed_attribute('$2','$4'). -attribute -> '-' 'spec' type_spec : build_type_spec('$2', '$3'). -attribute -> '-' 'callback' type_spec : build_type_spec('$2', '$3'). - -type_spec -> spec_fun type_sigs : {'$1', '$2'}. -type_spec -> '(' spec_fun type_sigs ')' : {'$2', '$3'}. - -spec_fun -> atom : '$1'. -spec_fun -> atom ':' atom : {'$1', '$3'}. +form -> attribute dot : range_end(?line('$2'), '$1'). +form -> function dot : range_end(?line('$2'), '$1'). +form -> rule dot : range_end(?line('$2'), '$1'). + +attribute -> '-' atom attr_val : + range(?line('$1'), ?line('$3'), build_attribute('$2', element(1, '$3'))). +attribute -> '-' atom typed_attr_val : + range(?line('$1'), ?line('$3'), + build_typed_attribute('$2', element(1, '$3'))). +attribute -> '-' atom '(' typed_attr_val ')' : + range(?line('$1'), ?line('$5'), + build_typed_attribute('$2', element(1, '$4'))). +attribute -> '-' 'spec' type_spec : + range(?line('$1'), ?line('$3'), build_type_spec('$2', element(1, '$3'))). +attribute -> '-' 'callback' type_spec : + range(?line('$1'), ?line('$3'), build_type_spec('$2', element(1, '$3'))). + +type_spec -> spec_fun type_sigs : + range_end(?line(lists:last('$2')), {{element(1, '$1'), '$2'}, ?line('$1')}). +type_spec -> '(' spec_fun type_sigs ')' : + range_end(?line('$4'), {{element(1, '$2'), '$3'}, ?line('$1')}). + +spec_fun -> atom : + {'$1', ?line('$1')}. +spec_fun -> atom ':' atom : + range_end(?line('$3'), {{'$1', '$3'}, ?line('$1')}). %% The following two are retained only for backwards compatibility; %% they are not part of the EEP syntax and should be removed. -spec_fun -> atom '/' integer '::' : {'$1', '$3'}. -spec_fun -> atom ':' atom '/' integer '::' : {'$1', '$3', '$5'}. +spec_fun -> atom '/' integer '::' : + range_end(?line('$4'), {{'$1', '$3'}, ?line('$1')}). +spec_fun -> atom ':' atom '/' integer '::' : + range_end(?line('$6'), {{'$1', '$3', '$5'}, ?line('$1')}). -typed_attr_val -> expr ',' typed_record_fields : {typed_record, '$1', '$3'}. -typed_attr_val -> expr '::' top_type : {type_def, '$1', '$3'}. +typed_attr_val -> expr ',' typed_record_fields : + range_end(?line('$3'), {{typed_record, '$1', '$3'}, ?line('$1')}). +typed_attr_val -> expr '::' top_type : + range_end(?line('$3'), {{type_def, '$1', '$3'}, ?line('$1')}). -typed_record_fields -> '{' typed_exprs '}' : {tuple, ?line('$1'), '$2'}. +typed_record_fields -> '{' typed_exprs '}' : + range_end(?line('$3'), {tuple, ?line('$1'), '$2'}). typed_exprs -> typed_expr : ['$1']. typed_exprs -> typed_expr ',' typed_exprs : ['$1'|'$3']. typed_exprs -> expr ',' typed_exprs : ['$1'|'$3']. typed_exprs -> typed_expr ',' exprs : ['$1'|'$3']. -typed_expr -> expr '::' top_type : {typed,'$1','$3'}. +typed_expr -> expr '::' top_type : + range_end('$3', {typed,'$1','$3'}). type_sigs -> type_sig : ['$1']. type_sigs -> type_sig ';' type_sigs : ['$1'|'$3']. type_sig -> fun_type : '$1'. -type_sig -> fun_type 'when' type_guards : {type, ?line('$1'), bounded_fun, - ['$1','$3']}. +type_sig -> fun_type 'when' type_guards : + range_end(lists:last(?line('$3')), + {type, ?line('$1'), bounded_fun, ['$1','$3']}). type_guards -> type_guard : ['$1']. type_guards -> type_guard ',' type_guards : ['$1'|'$3']. -type_guard -> atom '(' top_types ')' : {type, ?line('$1'), constraint, - ['$1', '$3']}. +type_guard -> atom '(' top_types ')' : + range_end(?line('$4'), {type, ?line('$1'), constraint, ['$1', '$3']}). type_guard -> var '::' top_type : build_def('$1', '$3'). top_types -> top_type : ['$1']. top_types -> top_type ',' top_types : ['$1'|'$3']. -top_type -> var '::' top_type_100 : {ann_type, ?line('$1'), ['$1','$3']}. +top_type -> var '::' top_type_100 : + range_end(?line('$3'), {ann_type, ?line('$1'), ['$1','$3']}). top_type -> top_type_100 : '$1'. top_type_100 -> type_200 : '$1'. top_type_100 -> type_200 '|' top_type_100 : lift_unions('$1','$3'). -type_200 -> type_300 '..' type_300 : {type, ?line('$1'), range, - [skip_paren('$1'), - skip_paren('$3')]}. +type_200 -> type_300 '..' type_300 : + range_end(?line('$3'), {type, ?line('$1'), range, + [skip_paren('$1'), skip_paren('$3')]}). type_200 -> type_300 : '$1'. type_300 -> type_300 add_op type_400 : ?mkop2(skip_paren('$1'), @@ -140,64 +159,79 @@ type_400 -> type_500 : '$1'. type_500 -> prefix_op type : ?mkop1('$1', skip_paren('$2')). type_500 -> type : '$1'. -type -> '(' top_type ')' : {paren_type, ?line('$2'), ['$2']}. +type -> '(' top_type ')' : + {paren_type, ?line('$2'), [range(?line('$1'), ?line('$3'), '$2')]}. type -> var : '$1'. type -> atom : '$1'. -type -> atom '(' ')' : build_gen_type('$1'). -type -> atom '(' top_types ')' : {type, ?line('$1'), - normalise('$1'), '$3'}. -type -> atom ':' atom '(' ')' : {remote_type, ?line('$1'), - ['$1', '$3', []]}. -type -> atom ':' atom '(' top_types ')' : {remote_type, ?line('$1'), - ['$1', '$3', '$5']}. -type -> '[' ']' : {type, ?line('$1'), nil, []}. -type -> '[' top_type ']' : {type, ?line('$1'), list, ['$2']}. -type -> '[' top_type ',' '...' ']' : {type, ?line('$1'), - nonempty_list, ['$2']}. -type -> '{' '}' : {type, ?line('$1'), tuple, []}. -type -> '{' top_types '}' : {type, ?line('$1'), tuple, '$2'}. -type -> '#' atom '{' '}' : {type, ?line('$1'), record, ['$2']}. -type -> '#' atom '{' field_types '}' : {type, ?line('$1'), - record, ['$2'|'$4']}. +type -> atom '(' ')' : + range_end(?line('$3'), build_gen_type('$1')). +type -> atom '(' top_types ')' : + range_end(?line('$4'), {type, ?line('$1'), normalise('$1'), '$3'}). +type -> atom ':' atom '(' ')' : + range_end(?line('$5'), {remote_type, ?line('$1'), ['$1', '$3', []]}). +type -> atom ':' atom '(' top_types ')' : + range_end(?line('$6'), {remote_type, ?line('$1'), ['$1', '$3', '$5']}). +type -> '[' ']' : + range_end(?line('$2'), {type, ?line('$1'), nil, []}). +type -> '[' top_type ']' : + range_end(?line('$3'), {type, ?line('$1'), list, ['$2']}). +type -> '[' top_type ',' '...' ']' : + range_end(?line('$5'), {type, ?line('$1'), nonempty_list, ['$2']}). +type -> '{' '}' : + range_end(?line('$2'), {type, ?line('$1'), tuple, []}). +type -> '{' top_types '}' : + range_end(?line('$3'), {type, ?line('$1'), tuple, '$2'}). +type -> '#' atom '{' '}' : + range_end(?line('$3'), {type, ?line('$1'), record, ['$2']}). +type -> '#' atom '{' field_types '}' : + range_end(?line('$5'), {type, ?line('$1'), record, ['$2'|'$4']}). type -> binary_type : '$1'. type -> integer : '$1'. -type -> 'fun' '(' ')' : {type, ?line('$1'), 'fun', []}. +type -> 'fun' '(' ')' : + range_end(?line('$3'), {type, ?line('$1'), 'fun', []}). type -> 'fun' '(' fun_type_100 ')' : '$3'. - -fun_type_100 -> '(' '...' ')' '->' top_type - : {type, ?line('$1'), 'fun', - [{type, ?line('$1'), any}, '$5']}. +fun_type_100 -> '(' '...' ')' '->' top_type : + Any = range_end(?line('$3'), {type, ?line('$1'), any}), + range_end(?line('$5'), {type, ?line('$1'), 'fun', [Any, '$5']}). fun_type_100 -> fun_type : '$1'. -fun_type -> '(' ')' '->' top_type : {type, ?line('$1'), 'fun', - [{type, ?line('$1'), product, []}, '$4']}. -fun_type -> '(' top_types ')' '->' top_type - : {type, ?line('$1'), 'fun', - [{type, ?line('$1'), product, '$2'},'$5']}. +fun_type -> '(' ')' '->' top_type : + Product = range_end(?line('$2'), {type, ?line('$1'), product, []}), + range_end(?line('$4'), {type, ?line('$1'), 'fun', [Product, '$4']}). +fun_type -> '(' top_types ')' '->' top_type : + Product = range_end(?line('$3'), {type, ?line('$1'), product, '$2'}), + range_end(?line('$5'), {type, ?line('$1'), 'fun', [Product, '$5']}). field_types -> field_type : ['$1']. field_types -> field_type ',' field_types : ['$1'|'$3']. -field_type -> atom '::' top_type : {type, ?line('$1'), field_type, - ['$1', '$3']}. - -binary_type -> '<<' '>>' : {type, ?line('$1'),binary, - [abstract(0, ?line('$1')), - abstract(0, ?line('$1'))]}. -binary_type -> '<<' bin_base_type '>>' : {type, ?line('$1'),binary, - ['$2', abstract(0, ?line('$1'))]}. -binary_type -> '<<' bin_unit_type '>>' : {type, ?line('$1'),binary, - [abstract(0, ?line('$1')), '$2']}. -binary_type -> '<<' bin_base_type ',' bin_unit_type '>>' - : {type, ?line('$1'), binary, ['$2', '$4']}. - -bin_base_type -> var ':' type : build_bin_type(['$1'], '$3'). - -bin_unit_type -> var ':' var '*' type : build_bin_type(['$1', '$3'], '$5'). - -attr_val -> expr : ['$1']. -attr_val -> expr ',' exprs : ['$1' | '$3']. -attr_val -> '(' expr ',' exprs ')' : ['$2' | '$4']. +field_type -> atom '::' top_type : + range_end(?line('$3'),{type, ?line('$1'), field_type, ['$1', '$3']}). + +binary_type -> '<<' '>>' : + range_end(?line('$2'), {type, ?line('$1'), binary, + [abstract(0, ?line('$1')), abstract(0, ?line('$1'))]}). +binary_type -> '<<' bin_base_type '>>' : + range_end(?line('$3'), {type, ?line('$1'), binary, + ['$2', abstract(0, ?line('$1'))]}). +binary_type -> '<<' bin_unit_type '>>' : + range_end(?line('$3'), {type, ?line('$1'), binary, + [abstract(0, ?line('$1')), '$2']}). +binary_type -> '<<' bin_base_type ',' bin_unit_type '>>' : + range_end(?line('$5'), {type, ?line('$1'), binary, ['$2', '$4']}). + +bin_base_type -> var ':' type : + range(?line('$1'), ?line('$3'), build_bin_type(['$1'], '$3')). + +bin_unit_type -> var ':' var '*' type : + range(?line('$1'), ?line('$5'), build_bin_type(['$1', '$3'], '$5')). + +attr_val -> expr : + {['$1'], ?line('$1')}. +attr_val -> expr ',' exprs : + range_end(?line(lists:last('$3')), {['$1' | '$3'], ?line('$1')}). +attr_val -> '(' expr ',' exprs ')' : + range(?line('$1'), ?line('$5'), {['$2' | '$4'], ?line('$1')}). function -> function_clauses : build_function('$1'). @@ -205,7 +239,8 @@ function_clauses -> function_clause : ['$1']. function_clauses -> function_clause ';' function_clauses : ['$1'|'$3']. function_clause -> atom clause_args clause_guard clause_body : - {clause,?line('$1'),element(3, '$1'),'$2','$3','$4'}. + range_end(?line(lists:last('$4')), + {clause,?line('$1'),element(3, '$1'),'$2','$3','$4'}). clause_args -> argument_list : element(1, '$1'). @@ -216,10 +251,11 @@ clause_guard -> '$empty' : []. clause_body -> '->' exprs: '$2'. -expr -> 'catch' expr : {'catch',?line('$1'),'$2'}. +expr -> 'catch' expr : range_end(?line('$2'), {'catch',?line('$1'),'$2'}). expr -> expr_100 : '$1'. -expr_100 -> expr_150 '=' expr_100 : {match,?line('$2'),'$1','$3'}. +expr_100 -> expr_150 '=' expr_100 : + range(?line('$1'), ?line('$3'), {match,?line('$2'),'$1','$3'}). expr_100 -> expr_150 '!' expr_100 : ?mkop2('$1', '$2', '$3'). expr_100 -> expr_150 : '$1'. @@ -254,13 +290,13 @@ expr_700 -> record_expr : '$1'. expr_700 -> expr_800 : '$1'. expr_800 -> expr_900 ':' expr_max : - {remote,?line('$2'),'$1','$3'}. + range(?line('$1'), ?line('$3'), {remote,?line('$2'),'$1','$3'}). expr_800 -> expr_900 : '$1'. expr_900 -> '.' atom : - {record_field,?line('$1'),{atom,?line('$1'),''},'$2'}. + range_end(?line('$2'), {record_field,?line('$1'),{atom,?line('$1'),''},'$2'}). expr_900 -> expr_900 '.' atom : - {record_field,?line('$2'),'$1','$3'}. + range(?line('$1'), ?line('$3'), {record_field,?line('$2'),'$1','$3'}). expr_900 -> expr_max : '$1'. expr_max -> var : '$1'. @@ -271,8 +307,9 @@ expr_max -> list_comprehension : '$1'. expr_max -> binary_comprehension : '$1'. expr_max -> tuple : '$1'. %%expr_max -> struct : '$1'. -expr_max -> '(' expr ')' : '$2'. -expr_max -> 'begin' exprs 'end' : {block,?line('$1'),'$2'}. +expr_max -> '(' expr ')' : range(?line('$1'), ?line('$3'), '$2'). +expr_max -> 'begin' exprs 'end' : + range_end(?line('$3'), {block,?line('$1'),'$2'}). expr_max -> if_expr : '$1'. expr_max -> case_expr : '$1'. expr_max -> receive_expr : '$1'. @@ -281,22 +318,24 @@ expr_max -> try_expr : '$1'. expr_max -> query_expr : '$1'. -list -> '[' ']' : {nil,?line('$1')}. -list -> '[' expr tail : {cons,?line('$1'),'$2','$3'}. +list -> '[' ']' : range_end(?line('$2'), {nil,?line('$1')}). +list -> '[' expr tail : range_end(?line('$3'), {cons,?line('$1'),'$2','$3'}). tail -> ']' : {nil,?line('$1')}. tail -> '|' expr ']' : '$2'. -tail -> ',' expr tail : {cons,?line('$2'),'$2','$3'}. +tail -> ',' expr tail : + range(?line('$1'), ?line('$3'), {cons,?line('$2'),'$2','$3'}). -binary -> '<<' '>>' : {bin,?line('$1'),[]}. -binary -> '<<' bin_elements '>>' : {bin,?line('$1'),'$2'}. +binary -> '<<' '>>' : range_end(?line('$2'), {bin,?line('$1'),[]}). +binary -> '<<' bin_elements '>>' : + range_end(?line('$3'), {bin,?line('$1'),'$2'}). bin_elements -> bin_element : ['$1']. bin_elements -> bin_element ',' bin_elements : ['$1'|'$3']. bin_element -> bit_expr opt_bit_size_expr opt_bit_type_list : - {bin_element,?line('$1'),'$1','$2','$3'}. + range_end(?line('$3'), {bin_element,?line('$1'),'$1','$2','$3'}). bit_expr -> prefix_op expr_max : ?mkop1('$1', '$2'). bit_expr -> expr_max : '$1'. @@ -317,22 +356,24 @@ bit_size_expr -> expr_max : '$1'. list_comprehension -> '[' expr '||' lc_exprs ']' : - {lc,?line('$1'),'$2','$4'}. + range_end(?line('$5'), {lc,?line('$1'),'$2','$4'}). binary_comprehension -> '<<' binary '||' lc_exprs '>>' : - {bc,?line('$1'),'$2','$4'}. + range_end(?line('$5'), {bc,?line('$1'),'$2','$4'}). lc_exprs -> lc_expr : ['$1']. lc_exprs -> lc_expr ',' lc_exprs : ['$1'|'$3']. lc_expr -> expr : '$1'. -lc_expr -> expr '<-' expr : {generate,?line('$2'),'$1','$3'}. -lc_expr -> binary '<=' expr : {b_generate,?line('$2'),'$1','$3'}. +lc_expr -> expr '<-' expr : + range(?line('$1'), ?line('$3'), {generate,?line('$2'),'$1','$3'}). +lc_expr -> binary '<=' expr : + range(?line('$1'), ?line('$3'), {b_generate,?line('$2'),'$1','$3'}). -tuple -> '{' '}' : {tuple,?line('$1'),[]}. -tuple -> '{' exprs '}' : {tuple,?line('$1'),'$2'}. +tuple -> '{' '}' : range_end(?line('$2'), {tuple,?line('$1'),[]}). +tuple -> '{' exprs '}' : range_end(?line('$3'), {tuple,?line('$1'),'$2'}). %%struct -> atom tuple : -%% {struct,?line('$1'),element(3, '$1'),element(3, '$2')}. +%% range_end(?line('$2'), {struct,?line('$1'),element(3, '$1'),element(3, '$2')}). %% N.B. This is called from expr_700. @@ -340,65 +381,75 @@ tuple -> '{' exprs '}' : {tuple,?line('$1'),'$2'}. %% always atoms for the moment, this might change in the future. record_expr -> '#' atom '.' atom : - {record_index,?line('$1'),element(3, '$2'),'$4'}. + range_end(?line('$4'), {record_index,?line('$1'),element(3, '$2'),'$4'}). record_expr -> '#' atom record_tuple : - {record,?line('$1'),element(3, '$2'),'$3'}. + range_end(?line('$3'), {record,?line('$1'),element(3, '$2'),'$3'}). record_expr -> expr_max '#' atom '.' atom : - {record_field,?line('$2'),'$1',element(3, '$3'),'$5'}. + range(?line('$1'), ?line('$5'), {record_field,?line('$2'),'$1', + element(3, '$3'),'$5'}). record_expr -> expr_max '#' atom record_tuple : - {record,?line('$2'),'$1',element(3, '$3'),'$4'}. + range(?line('$1'), ?line('$4'), {record,?line('$2'),'$1', + element(3, '$3'),element(1, '$4')}). record_expr -> record_expr '#' atom '.' atom : - {record_field,?line('$2'),'$1',element(3, '$3'),'$5'}. + range(?line('$1'), ?line('$5'), {record_field,?line('$2'),'$1', + element(3, '$3'),'$5'}). record_expr -> record_expr '#' atom record_tuple : - {record,?line('$2'),'$1',element(3, '$3'),'$4'}. + range(?line('$1'), ?line('$4'), {record,?line('$2'),'$1', + element(3, '$3'),element(1, '$4')}). -record_tuple -> '{' '}' : []. -record_tuple -> '{' record_fields '}' : '$2'. +record_tuple -> '{' '}' : range_end(?line('$2'), {[],?line('$1')}). +record_tuple -> '{' record_fields '}' : + range_end(?line('$3'), {'$2',?line('$1')}). record_fields -> record_field : ['$1']. record_fields -> record_field ',' record_fields : ['$1' | '$3']. -record_field -> var '=' expr : {record_field,?line('$1'),'$1','$3'}. -record_field -> atom '=' expr : {record_field,?line('$1'),'$1','$3'}. +record_field -> var '=' expr : + range_end(?line('$3'), {record_field,?line('$1'),'$1','$3'}). +record_field -> atom '=' expr : + range_end(?line('$3'), {record_field,?line('$1'),'$1','$3'}). %% N.B. This is called from expr_700. function_call -> expr_800 argument_list : - {call,?line('$1'),'$1',element(1, '$2')}. + range_end(?line('$2'), {call,?line('$1'),'$1',element(1, '$2')}). -if_expr -> 'if' if_clauses 'end' : {'if',?line('$1'),'$2'}. +if_expr -> 'if' if_clauses 'end' : + range_end(?line('$3'), {'if',?line('$1'),'$2'}). if_clauses -> if_clause : ['$1']. if_clauses -> if_clause ';' if_clauses : ['$1' | '$3']. if_clause -> guard clause_body : - {clause,?line(hd(hd('$1'))),[],'$1','$2'}. + range_end(?line(lists:last('$2')), + {clause,?line(hd(hd('$1'))),[],'$1','$2'}). case_expr -> 'case' expr 'of' cr_clauses 'end' : - {'case',?line('$1'),'$2','$4'}. + range_end(?line('$5'), {'case',?line('$1'),'$2','$4'}). cr_clauses -> cr_clause : ['$1']. cr_clauses -> cr_clause ';' cr_clauses : ['$1' | '$3']. cr_clause -> expr clause_guard clause_body : - {clause,?line('$1'),['$1'],'$2','$3'}. + range_end(?line(lists:last('$3')), {clause,?line('$1'),['$1'],'$2','$3'}). receive_expr -> 'receive' cr_clauses 'end' : - {'receive',?line('$1'),'$2'}. + range_end(?line('$3'), {'receive',?line('$1'),'$2'}). receive_expr -> 'receive' 'after' expr clause_body 'end' : - {'receive',?line('$1'),[],'$3','$4'}. + range_end(?line('$5'), {'receive',?line('$1'),[],'$3','$4'}). receive_expr -> 'receive' cr_clauses 'after' expr clause_body 'end' : - {'receive',?line('$1'),'$2','$4','$5'}. + range_end(?line('$6'), {'receive',?line('$1'),'$2','$4','$5'}). fun_expr -> 'fun' atom '/' integer : - {'fun',?line('$1'),{function,element(3, '$2'),element(3, '$4')}}. + range_end(?line('$4'), {'fun',?line('$1'), + {function,element(3, '$2'),element(3, '$4')}}). fun_expr -> 'fun' atom_or_var ':' atom_or_var '/' integer_or_var : - {'fun',?line('$1'),{function,'$2','$4','$6'}}. + range_end(?line('$6'), {'fun',?line('$1'),{function,'$2','$4','$6'}}). fun_expr -> 'fun' fun_clauses 'end' : - build_fun(?line('$1'), '$2'). + range_end(?line('$3'), build_fun(?line('$1'), '$2')). atom_or_var -> atom : '$1'. atom_or_var -> var : '$1'. @@ -410,40 +461,43 @@ fun_clauses -> fun_clause : ['$1']. fun_clauses -> fun_clause ';' fun_clauses : ['$1' | '$3']. fun_clause -> argument_list clause_guard clause_body : - {Args,Pos} = '$1', - {clause,Pos,'fun',Args,'$2','$3'}. + {Args,Pos} = '$1', + range_end(?line(lists:last('$3')), {clause,Pos,'fun',Args,'$2','$3'}). try_expr -> 'try' exprs 'of' cr_clauses try_catch : - build_try(?line('$1'),'$2','$4','$5'). + range_end(?line('$5'), build_try(?line('$1'),'$2','$4','$5')). try_expr -> 'try' exprs try_catch : - build_try(?line('$1'),'$2',[],'$3'). + range_end(?line('$3'), build_try(?line('$1'),'$2',[],'$3')). try_catch -> 'catch' try_clauses 'end' : - {'$2',[]}. + range_end(?line('$3'), {{'$2',[]},?line('$1')}). try_catch -> 'catch' try_clauses 'after' exprs 'end' : - {'$2','$4'}. + range_end(?line('$5'), {{'$2','$4'},?line('$1')}). try_catch -> 'after' exprs 'end' : - {[],'$2'}. + range_end(?line('$3'), {{[],'$2'},?line('$1')}). try_clauses -> try_clause : ['$1']. try_clauses -> try_clause ';' try_clauses : ['$1' | '$3']. try_clause -> expr clause_guard clause_body : - L = ?line('$1'), - {clause,L,[{tuple,L,[{atom,L,throw},'$1',{var,L,'_'}]}],'$2','$3'}. + L = ?line('$1'), + Tuple = [{tuple,L,[{atom,L,throw},'$1',{var,L,'_'}]}], + range_end(?line(lists:last('$3')), {clause,L,Tuple,'$2','$3'}). try_clause -> atom ':' expr clause_guard clause_body : - L = ?line('$1'), - {clause,L,[{tuple,L,['$1','$3',{var,L,'_'}]}],'$4','$5'}. + L = ?line('$1'), + range_end(?line(lists:last('$5')), + {clause,L,[{tuple,L,['$1','$3',{var,L,'_'}]}],'$4','$5'}). try_clause -> var ':' expr clause_guard clause_body : - L = ?line('$1'), - {clause,L,[{tuple,L,['$1','$3',{var,L,'_'}]}],'$4','$5'}. + L = ?line('$1'), + range_end(?line(lists:last('$5')), + {clause,L,[{tuple,L,['$1','$3',{var,L,'_'}]}],'$4','$5'}). query_expr -> 'query' list_comprehension 'end' : - {'query',?line('$1'),'$2'}. + range_end(?line('$3'), {'query',?line('$1'),'$2'}). -argument_list -> '(' ')' : {[],?line('$1')}. -argument_list -> '(' exprs ')' : {'$2',?line('$1')}. +argument_list -> '(' ')' : range_end(?line('$2'), {[],?line('$1')}). +argument_list -> '(' exprs ')' : range_end(?line('$3'), {'$2',?line('$1')}). exprs -> expr : ['$1']. @@ -460,7 +514,8 @@ atomic -> strings : '$1'. strings -> string : '$1'. strings -> string strings : - {string,?line('$1'),element(3, '$1') ++ element(3, '$2')}. + range_end(?line('$2'), {string,?line('$1'), + element(3, '$1') ++ element(3, '$2')}). prefix_op -> '+' : '$1'. prefix_op -> '-' : '$1'. @@ -501,7 +556,8 @@ rule_clauses -> rule_clause : ['$1']. rule_clauses -> rule_clause ';' rule_clauses : ['$1'|'$3']. rule_clause -> atom clause_args clause_guard rule_body : - {clause,?line('$1'),element(3, '$1'),'$2','$3','$4'}. + range_end(?line(lists:last('$4')), + {clause,?line('$1'),element(3, '$1'),'$2','$3','$4'}). rule_body -> ':-' lc_exprs: '$2'. @@ -513,6 +569,7 @@ Erlang code. -export([abstract/2, package_segments/1]). -export([inop_prec/1,preop_prec/1,func_prec/0,max_prec/0]). -export([set_line/2,get_attribute/2,get_attributes/1]). +-export([range/3,range_end/2]). %% The following directive is needed for (significantly) faster compilation %% of the generated .erl file by the HiPE compiler. Please do not remove. @@ -534,13 +591,13 @@ Erlang code. -define(mkop2(L, OpPos, R), begin {Op,Pos} = OpPos, - {op,Pos,Op,L,R} + range(?line(L), ?line(R), {op,Pos,Op,L,R}) end). -define(mkop1(OpPos, A), begin {Op,Pos} = OpPos, - {op,Pos,Op,A} + range_end(?line(A), {op,Pos,Op,A}) end). %% keep track of line info in tokens @@ -640,13 +697,14 @@ find_arity_from_specs([Spec|_]) -> length(Args). build_def(LHS, Types) -> - IsSubType = {atom, ?line(LHS), is_subtype}, - {type, ?line(LHS), constraint, [IsSubType, [LHS, Types]]}. + L = ?line(LHS), + IsSubType = {atom, L, is_subtype}, + range_end(?line(Types), {type, L, constraint, [IsSubType, [LHS, Types]]}). -lift_unions(T1, {type, _La, union, List}) -> - {type, ?line(T1), union, [T1|List]}; +lift_unions(T1, {type, La, union, List}) -> + range_end(La, {type, ?line(T1), union, [T1|List]}); lift_unions(T1, T2) -> - {type, ?line(T1), union, [T1, T2]}. + range_end(?line(T2), {type, ?line(T1), union, [T1, T2]}). skip_paren({paren_type,_L,[Type]}) -> skip_paren(Type); @@ -1096,8 +1154,50 @@ max_prec() -> 1000. set_line(L, F) -> erl_scan:set_attribute(line, L, F). +get_attribute(L, 'begin') when not is_list(L) -> + undefined; +get_attribute(L, 'begin') -> + case lists:keyfind('begin', 1, L) of + false -> + case erl_scan:attributes_info(L, location) of + {location, Loc} when is_tuple(Loc) -> + {'begin', Loc}; + _ -> + undefined + end; + Attr -> + Attr + end; get_attribute(L, Name) -> erl_scan:attributes_info(L, Name). get_attributes(L) -> erl_scan:attributes_info(L). + + +range(L1, L2, N) when is_integer(L1); is_integer(L2) -> + N; +range(L1, L2, N) -> + Attrs = get_attributes(?line(N)), + case {get_attribute(L1, 'begin'), get_attribute(Attrs, 'begin')} of + {undefined, _} -> + N; + {Begin, OldBegin} when OldBegin =/= undefined, Begin > OldBegin -> + N; + {Begin, _OldBegin} -> + case {get_attribute(L2, 'end'), get_attribute(Attrs, 'end')} of + {undefined, _} -> + N; + {End, OldEnd} when OldEnd =/= undefined, End < OldEnd -> + N; + {End, _OldEnd} -> + NewAttrs = + lists:keystore('begin', 1, + lists:keystore('end', 1, Attrs, End), + Begin), + setelement(2, N, NewAttrs) + end + end. + +range_end(L, N) -> + range(?line(N), L, N). diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index 498d850df368..09f1a19afb47 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -603,7 +603,7 @@ parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) -> {PreDefMacros, Module} = pre_def_macros(File), IncludePath = [], {ok, _} = file:position(Fd, {bof, HeaderSz}), - case epp:open(File, Fd, StartLine, IncludePath, PreDefMacros) of + case epp:open(File, Fd, StartLine, IncludePath, PreDefMacros, []) of {ok, Epp} -> {ok, FileForm} = epp:parse_erl_form(Epp), OptModRes = epp:parse_erl_form(Epp), diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl index 9f65bbfa3a38..2c34e1f9c0a7 100644 --- a/lib/stdlib/src/io.erl +++ b/lib/stdlib/src/io.erl @@ -27,7 +27,7 @@ -export([fwrite/1,fwrite/2,fwrite/3,fread/2,fread/3, format/1,format/2,format/3]). -export([scan_erl_exprs/1,scan_erl_exprs/2,scan_erl_exprs/3, - scan_erl_form/1,scan_erl_form/2,scan_erl_form/3, + scan_erl_form/1,scan_erl_form/2,scan_erl_form/3,scan_erl_form/4, parse_erl_exprs/1,parse_erl_exprs/2,parse_erl_exprs/3, parse_erl_form/1,parse_erl_form/2,parse_erl_form/3]). -export([request/1,request/2,requests/1,requests/2]). @@ -394,6 +394,16 @@ scan_erl_form(Io, Prompt) -> scan_erl_form(Io, Prompt, Pos0) -> request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}). +-spec scan_erl_form(IoDevice, Prompt, StartLine, Options) -> Result when + IoDevice :: device(), + Prompt :: prompt(), + StartLine :: line(), + Options :: erl_scan:options(), + Result :: erl_scan:tokens_result() | request_error(). + +scan_erl_form(Io, Prompt, Pos0, Opts) -> + request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0,Opts]}). + %% Parsing Erlang code. -type parse_ret() :: {'ok', ExprList :: erl_parse:abstract_expr(), EndLine :: line()} diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 77c615d6d960..66b50bd4f841 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -483,7 +483,7 @@ skip_header(Config) when is_list(Config) -> ?line io:get_line(Fd, ''), ?line io:get_line(Fd, ''), ?line io:get_line(Fd, ''), - ?line {ok, Epp} = epp:open(list_to_atom(File), Fd, 4, [], []), + ?line {ok, Epp} = epp:open(list_to_atom(File), Fd, 4, [], [], []), ?line Forms = epp:parse_file(Epp), ?line [] = [Reason || {error, Reason} <- Forms],