Browse Source

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

From 23625dd8e080cf3bdd8f49934b755e0d3d45e1cd Mon Sep 17 00:00:00 2001
From: Dmitry Boyarintsev <[email protected]>
Date: Wed, 20 Nov 2019 12:28:43 -0500

git-svn-id: branches/wasm@46037 -
nickysn 5 years ago
parent
commit
fddbd834df
1 changed files with 174 additions and 66 deletions
  1. 174 66
      utils/wasmbin/watparser.pas

+ 174 - 66
utils/wasmbin/watparser.pas

@@ -5,23 +5,79 @@ unit watparser;
 interface
 interface
 
 
 uses
 uses
-  SysUtils, Classes, parseutils, wasmtext, wasmmodule, wasmbin, watscanner;
+  SysUtils, Classes, wasmtext, wasmmodule, wasmbin, watscanner;
 
 
 type
 type
   TParseResult = record
   TParseResult = record
-    error : string;
+    error  : string;
+    line   : integer;
+    pos    : integer;
+    offset : integer;
   end;
   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 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
 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;
 procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken;
-  out hadOpenBrace: Boolean);
+  out hadOpenBrace: Boolean); overload;
 begin
 begin
   sc.Next;
   sc.Next;
   hadOpenBrace := sc.token = weOpenBrace;
   hadOpenBrace := sc.token = weOpenBrace;
@@ -29,6 +85,15 @@ begin
   tk:=sc.token;
   tk:=sc.token;
 end;
 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;
 function ConsumeOpenToken(sc: TWatScanner; tk: TWatToken): Boolean;
 begin
 begin
   sc.Next;
   sc.Next;
@@ -39,22 +104,22 @@ begin
   end;
   end;
 end;
 end;
 
 
-function ConsumeToken(sc: TWatScanner; tk: TWatToken; var res: TParseResult): Boolean;
+function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
 begin
 begin
   Result:=sc.token =tk;
   Result:=sc.token =tk;
   if not Result then
   if not Result then
-    ErrorExpectButFound(res, 'some token','?')
+    ErrorExpectButFound(sc,TokenStr[tk])
   else
   else
     sc.Next;
     sc.Next;
 end;
 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
 begin
   num:=-1;
   num:=-1;
   id:='';
   id:='';
   Result := sc.Next;
   Result := sc.Next;
   if not Result then begin
   if not Result then begin
-    ErrorUnexpectedEof(res);
+    ErrorUnexpectedEof(sc);
     Exit;
     Exit;
   end;
   end;
 
 
@@ -62,7 +127,7 @@ begin
     weNumber: num:=sc.GetInt32;
     weNumber: num:=sc.GetInt32;
     weIdent: id:=sc.resText;
     weIdent: id:=sc.resText;
   else
   else
-    ErrorExpectButFound(res, 'index');
+    ErrorExpectButFound(sc, 'index', TokenStr[sc.token]);
     Result := false;
     Result := false;
   end;
   end;
   Result := true;
   Result := true;
@@ -83,34 +148,31 @@ begin
   end;
   end;
 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
 begin
   tp:=0;
   tp:=0;
   id:='';
   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;
     id:=sc.resText;
     sc.Next;
     sc.Next;
   end;
   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;
   sc.Next;
-  Result := sc.token=weCloseBrace;
-  if Result then sc.Next
-  else ErrorExpectButFound(res, ')');
+
+  if consumeClose then
+    ConsumeToken(sc, weCloseBrace);
 end;
 end;
 
 
-function ParseFunc(sc: TWatScanner; dst: TWasmFunc; var res: TParseResult): Boolean;
+procedure ParseFunc(sc: TWatScanner; dst: TWasmFunc);
 var
 var
   nm : integer;
   nm : integer;
   id : string;
   id : string;
   p  : TWasmParam;
   p  : TWasmParam;
+  tk  : TWatToken;
 begin
 begin
   if sc.token=weFunc then sc.Next;
   if sc.token=weFunc then sc.Next;
   repeat
   repeat
@@ -119,45 +181,51 @@ begin
       sc.Next;
       sc.Next;
     end;
     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;
       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;
     end;
 
 
   until sc.token=weCloseBrace;
   until sc.token=weCloseBrace;
   sc.Next;
   sc.Next;
 end;
 end;
 
 
-function ParseModule(sc: TWatScanner; dst: TWasmModule; var res: TParseResult): Boolean;
+function ParseModuleInt(sc: TWatScanner; dst: TWasmModule): Boolean;
 begin
 begin
   if not ConsumeOpenToken(sc, weModule) then begin
   if not ConsumeOpenToken(sc, weModule) then begin
-    Result := false;
+    ErrorExpectButFound(sc, 'module');
     Exit;
     Exit;
   end;
   end;
 
 
@@ -167,12 +235,11 @@ begin
       sc.Next;
       sc.Next;
 
 
       if sc.token = weFunc then begin
       if sc.token = weFunc then begin
-        Result := ParseFunc(sc, dst.AddFunc, res);
-        if not Result then Exit;
+        ParseFunc(sc, dst.AddFunc);
       end;
       end;
 
 
     end else if sc.token<>weCloseBrace then begin
     end else if sc.token<>weCloseBrace then begin
-      ErrorUnexpected(res);
+      ErrorUnexpected(sc, TokenStr[sc.token]);
       Result := false;
       Result := false;
       exit;
       exit;
     end;
     end;
@@ -181,21 +248,62 @@ begin
   Result := true;
   Result := true;
 end;
 end;
 
 
-procedure ErrorUnexpected(var res: TParseResult; const tokenstr: string);
+function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean;
+var
+  res : TParseResult;
 begin
 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;
 end;
 
 
-procedure ErrorUnexpectedEof(var res: TParseResult);
+procedure GetLineAndPos(const buf: string; ofs: integer; out line, pos: integer);
+var
+  i: integer;
+  ll: integer;
 begin
 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;
 end;
 
 
-procedure ErrorExpectButFound(var res: TParseResult; const expected, butfound: string);
+function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean;
+begin
+  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
 begin
-  res.error:=expected +' is expected';
-  if butfound<>'' then
-    res.error:=res.error+', but '+butfound+ ' found';
+  inherited Create(amsg);
+  offset:=aofs;
 end;
 end;
 
 
 end.
 end.