[PATCH 041/188] refactoring the parser to use exceptions

From 23625dd8e080cf3bdd8f49934b755e0d3d45e1cd Mon Sep 17 00:00:00 2001
From: Dmitry Boyarintsev <skalogryz.lists@gmail.com>
Date: Wed, 20 Nov 2019 12:28:43 -0500

git-svn-id: branches/wasm@46037 -
This commit is contained in:
nickysn 2020-08-03 12:59:28 +00:00
parent 18c78e1465
commit fddbd834df

View File

@ -5,23 +5,79 @@ unit watparser;
interface
uses
SysUtils, Classes, parseutils, wasmtext, wasmmodule, wasmbin, watscanner;
SysUtils, Classes, wasmtext, wasmmodule, wasmbin, watscanner;
type
TParseResult = record
error : string;
error : string;
line : integer;
pos : integer;
offset : integer;
end;
const
TokenStr : array[TWatToken] of string = (
'uknown', 'end of file', 'error',
'index',
'string', 'number', '(', ')',
'linksymbol',
'instruction',
'func',
'param', 'result',
'module', 'mut', 'funcref',
'i32', 'i64',
'f32', 'f64',
'type',
'import', 'global', 'table', 'memory', 'local', 'export',
'elem', 'data', 'offset'
);
//function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
function ParseModule(sc: TWatScanner; dst: TWasmModule; var res: TParseResult): Boolean;
procedure ErrorUnexpected(var res: TParseResult; const tokenstr: string = '');
procedure ErrorExpectButFound(var res: TParseResult; const expected: string; const butfound: string = '');
procedure ErrorUnexpectedEof(var res: TParseResult);
function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean; overload;
function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean; overload;
type
// used to stop the recursive parsing
{ EParserError }
EParserError = class(Exception)
offset : integer;
constructor Create(const amsg: string; aofs: integer);
end;
implementation
const
WAT_DEFTYPES='iN or fN';
procedure ParseError(sc: TWatScanner; const errMsg: string);
begin
raise EParserError.Create(errMsg, sc.ofs);
end;
procedure ErrorUnexpected(sc: TWatScanner; const tokenstr: string = '');
begin
ParseError(sc, 'unexpected '+tokenstr);
end;
procedure ErrorExpectButFound(sc: TWatScanner; const expected: string; const butfound: string =''); overload;
var
r : string;
begin
if butfound = '' then r := sc.resText
else r := butfound;
ParseError(sc, 'expected "'+expected+'", but "'+r+'" found');
end;
procedure ErrorUnexpectedEof(sc: TWatScanner);
begin
ParseError(sc, 'unexpected end of file');
end;
procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken;
out hadOpenBrace: Boolean);
out hadOpenBrace: Boolean); overload;
begin
sc.Next;
hadOpenBrace := sc.token = weOpenBrace;
@ -29,6 +85,15 @@ begin
tk:=sc.token;
end;
procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken); overload;
var
op: Boolean;
begin
ConsumeAnyOpenToken(sc, tk, op);
end;
function ConsumeOpenToken(sc: TWatScanner; tk: TWatToken): Boolean;
begin
sc.Next;
@ -39,22 +104,22 @@ begin
end;
end;
function ConsumeToken(sc: TWatScanner; tk: TWatToken; var res: TParseResult): Boolean;
function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
begin
Result:=sc.token =tk;
if not Result then
ErrorExpectButFound(res, 'some token','?')
ErrorExpectButFound(sc,TokenStr[tk])
else
sc.Next;
end;
function ParseNumOfId(sc: TWatScanner; out num: integer; out id: string; var res: TParseResult): Boolean;
function ParseNumOfId(sc: TWatScanner; out num: integer; out id: string): Boolean;
begin
num:=-1;
id:='';
Result := sc.Next;
if not Result then begin
ErrorUnexpectedEof(res);
ErrorUnexpectedEof(sc);
Exit;
end;
@ -62,7 +127,7 @@ begin
weNumber: num:=sc.GetInt32;
weIdent: id:=sc.resText;
else
ErrorExpectButFound(res, 'index');
ErrorExpectButFound(sc, 'index', TokenStr[sc.token]);
Result := false;
end;
Result := true;
@ -83,34 +148,31 @@ begin
end;
end;
function ParseParam(sc: TWatScanner; out id: string; out tp: byte; var res: TParseResult): Boolean;
procedure ParseParam(sc: TWatScanner; out id: string; out tp: byte; allowIdent: Boolean = true; consumeClose: Boolean = true);
begin
tp:=0;
id:='';
if sc.token=weParam then sc.Next;
if sc.token=weIdent then begin
if allowIdent and (sc.token=weIdent) then begin
id:=sc.resText;
sc.Next;
end;
if not TokenTypeToValType(sc.token, tp) then begin
ErrorExpectButFound(res, 'type');
Result:=false;
Exit;
end else
Result:=true;
if not TokenTypeToValType(sc.token, tp) then
ErrorExpectButFound(sc, WAT_DEFTYPES, TokenStr[sc.token]);
sc.Next;
Result := sc.token=weCloseBrace;
if Result then sc.Next
else ErrorExpectButFound(res, ')');
if consumeClose then
ConsumeToken(sc, weCloseBrace);
end;
function ParseFunc(sc: TWatScanner; dst: TWasmFunc; var res: TParseResult): Boolean;
procedure ParseFunc(sc: TWatScanner; dst: TWasmFunc);
var
nm : integer;
id : string;
p : TWasmParam;
tk : TWatToken;
begin
if sc.token=weFunc then sc.Next;
repeat
@ -119,45 +181,51 @@ begin
sc.Next;
end;
Result:=false;
if sc.token=weOpenBrace then begin
ConsumeAnyOpenToken(sc, tk);
if tk = weType then begin
if not ParseNumOfId(sc, nm, id) then Exit;
if nm>=0 then dst.typeIdx:=nm
else dst.typeId:=id;
ConsumeAnyOpenToken(sc, tk);
end;
while tk = weParam do begin
p:=dst.GetInlineType.AddParam;
sc.Next;
case sc.token of
weType: begin
if not ParseNumOfId(sc, nm, id, res) then Exit;
if nm>=0 then dst.typeIdx:=nm
else dst.typeId:=id;
end;
weParam: begin
sc.Next;
p:=dst.GetInlineType.AddParam;
if not ParseParam(sc, p.id, p.tp, res) then Exit;
end;
weResult: begin
sc.Next;
p:=dst.GetInlineType.AddResult;
if not ParseParam(sc, p.id, p.tp, res) then Exit;
end;
weLocal: begin
sc.Next;
p:=dst.AddLocal;
if not ParseParam(sc, p.id, p.tp, res) then Exit;
end;
else
ErrorUnexpected(res, 'booh');
Exit;
end;
if not ConsumeToken(sc, weCloseBrace, res) then Exit;
ParseParam(sc, p.id, p.tp);
ConsumeAnyOpenToken(sc, tk);
end;
while tk = weResult do begin
p:=dst.GetInlineType.AddResult;
sc.Next;
ParseParam(sc, p.id, p.tp, false);
ConsumeAnyOpenToken(sc, tk);
end;
while tk = weLocal do begin
p:=dst.AddLocal;
sc.Next;
ParseParam(sc, p.id, p.tp);
ConsumeAnyOpenToken(sc, tk);
end;
if not (tk in [weInstr, weCloseBrace]) then
ErrorExpectButFound(sc, 'identifier');
while tk<>weCloseBrace do begin
ConsumeToken(sc, weInstr);
end;
until sc.token=weCloseBrace;
sc.Next;
end;
function ParseModule(sc: TWatScanner; dst: TWasmModule; var res: TParseResult): Boolean;
function ParseModuleInt(sc: TWatScanner; dst: TWasmModule): Boolean;
begin
if not ConsumeOpenToken(sc, weModule) then begin
Result := false;
ErrorExpectButFound(sc, 'module');
Exit;
end;
@ -167,12 +235,11 @@ begin
sc.Next;
if sc.token = weFunc then begin
Result := ParseFunc(sc, dst.AddFunc, res);
if not Result then Exit;
ParseFunc(sc, dst.AddFunc);
end;
end else if sc.token<>weCloseBrace then begin
ErrorUnexpected(res);
ErrorUnexpected(sc, TokenStr[sc.token]);
Result := false;
exit;
end;
@ -181,21 +248,62 @@ begin
Result := true;
end;
procedure ErrorUnexpected(var res: TParseResult; const tokenstr: string);
function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean;
var
res : TParseResult;
begin
res.error:='unexpected token '+tokenstr;
Result := ParseModule(sc, dst, res);
if not Result then begin
errMsg:=Format('line: %d, pos: %d, %s', [res.line, res.pos, res.error]);
end else
errMsg:='';
end;
procedure ErrorUnexpectedEof(var res: TParseResult);
procedure GetLineAndPos(const buf: string; ofs: integer; out line, pos: integer);
var
i: integer;
ll: integer;
begin
res.error:='unexpected end of file';
i:=1;
line:=1;
ll:=1;
while (i<=length(buf)) and (i<ofs) do begin
if (buf[i]=#13) or (buf[i]=#10) then begin
inc(line);
if (i<=length(buf)) and (i<ofs) and ((buf[i]=#13) or (buf[i]=#10)) and (buf[i] <> buf[i-1]) then
inc(i);
ll:=i;
end;
inc(i);
end;
pos:=ofs - ll;
end;
procedure ErrorExpectButFound(var res: TParseResult; const expected, butfound: string);
function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean;
begin
res.error:=expected +' is expected';
if butfound<>'' then
res.error:=res.error+', but '+butfound+ ' found';
try
err.error:='';
err.pos:=0;
err.line:=0;
err.offset:=0;
ParseModuleInt(sc, dst);
Result:=true;
except
on x: EParserError do begin
err.error := x.Message;
err.offset := x.offset;
GetLineAndPos(sc.buf, x.offset, err.line, err.pos);
Result:=false;
end;
end;
end;
{ EParserError }
constructor EParserError.Create(const amsg: string; aofs: integer);
begin
inherited Create(amsg);
offset:=aofs;
end;
end.