You've already forked templates-parser
mirror of
https://github.com/AdaCore/templates-parser.git
synced 2026-02-12 12:29:55 -08:00
272 lines
9.5 KiB
Ada
272 lines
9.5 KiB
Ada
------------------------------------------------------------------------------
|
|
-- Templates Parser --
|
|
-- --
|
|
-- Copyright (C) 2010-2024, AdaCore --
|
|
-- --
|
|
-- This library is free software; you can redistribute it and/or modify --
|
|
-- it under terms of the GNU General Public License as published by the --
|
|
-- Free Software Foundation; either version 3, or (at your option) any --
|
|
-- later version. This library is distributed in the hope that it will be --
|
|
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of --
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
|
|
-- --
|
|
-- As a special exception under Section 7 of GPL version 3, you are --
|
|
-- granted additional permissions described in the GCC Runtime Library --
|
|
-- Exception, version 3.1, as published by the Free Software Foundation. --
|
|
-- --
|
|
-- You should have received a copy of the GNU General Public License and --
|
|
-- a copy of the GCC Runtime Library Exception along with this program; --
|
|
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
|
-- <http://www.gnu.org/licenses/>. --
|
|
-- --
|
|
-- As a special exception, if other files instantiate generics from this --
|
|
-- unit, or you link this unit with other files to produce an executable, --
|
|
-- this unit does not by itself cause the resulting executable to be --
|
|
-- covered by the GNU General Public License. This exception does not --
|
|
-- however invalidate any other reasons why the executable file might be --
|
|
-- covered by the GNU Public License. --
|
|
------------------------------------------------------------------------------
|
|
|
|
separate (Templates_Parser)
|
|
|
|
package body Simplifier is
|
|
|
|
procedure Run (T : in out Tree) is
|
|
|
|
procedure Rewrite (T : in out Data.Tree);
|
|
-- Optimize data tree T
|
|
|
|
procedure Link_End (T, To : Tree; Link : out Tree);
|
|
-- Link To at end of tree T, Link is the pointer to the last node
|
|
|
|
--------------
|
|
-- Link_End --
|
|
--------------
|
|
|
|
procedure Link_End (T, To : Tree; Link : out Tree) is
|
|
N : Tree := T;
|
|
begin
|
|
while N.Next /= null loop
|
|
N := N.Next;
|
|
end loop;
|
|
|
|
N.Next := To;
|
|
Link := N;
|
|
end Link_End;
|
|
|
|
-------------
|
|
-- Rewrite --
|
|
-------------
|
|
|
|
procedure Rewrite (T : in out Data.Tree) is
|
|
use type Data.NKind;
|
|
use type Data.Tree;
|
|
|
|
D, Prev : Data.Tree;
|
|
Moved : Boolean := False;
|
|
Old : Data.Tree;
|
|
begin
|
|
D := T;
|
|
|
|
while D /= null loop
|
|
case D.Kind is
|
|
when Data.Text =>
|
|
if Prev = null
|
|
and then T.Kind = Data.Text
|
|
and then D /= T
|
|
then
|
|
Append (T.Value, D.Value);
|
|
|
|
Old := T.Next;
|
|
T.Next := D.Next;
|
|
D := D.Next;
|
|
Moved := True;
|
|
|
|
Data.Release (Old, Single => True);
|
|
|
|
elsif Prev /= null and then Prev.Kind = Data.Text then
|
|
Append (Prev.Value, D.Value);
|
|
|
|
Old := Prev.Next;
|
|
Prev.Next := D.Next;
|
|
D := D.Next;
|
|
Moved := True;
|
|
|
|
Data.Release (Old, Single => True);
|
|
end if;
|
|
|
|
when Data.Var =>
|
|
-- Rewrite also the macro if any
|
|
|
|
if D.Var.Is_Macro then
|
|
Run (D.Var.Def);
|
|
|
|
-- Check if we have a single resulting TEXT node
|
|
|
|
if D.Var.Def /= null
|
|
and then D.Var.Def.Kind = Text
|
|
and then D.Var.Def.Text.Kind = Data.Text
|
|
and then D.Var.Def.Text.Next = null
|
|
and then D.Var.Def.Next = null
|
|
then
|
|
declare
|
|
C : aliased Filter.Filter_Context (P_Size => 0);
|
|
begin
|
|
if Prev = null then
|
|
-- First node is a variable (line starting with
|
|
-- a tag variable), replace it by the
|
|
-- corresponding text node.
|
|
Old := T;
|
|
T := new Data.Node'
|
|
(Kind => Data.Text,
|
|
Line => D.Var.Def.Text.Line,
|
|
Col => D.Var.Def.Text.Col,
|
|
Next => D.Var.Def.Text.Next,
|
|
Value => To_Unbounded_String
|
|
(Data.Translate
|
|
(D.Var,
|
|
To_String (D.Var.Def.Text.Value),
|
|
C'Access)));
|
|
|
|
D := D.Next;
|
|
Moved := True;
|
|
|
|
Data.Release (Old, Single => True);
|
|
|
|
elsif Prev.Kind = Data.Text then
|
|
-- First node was a text, merge the values
|
|
Append (Prev.Value, D.Var.Def.Text.Value);
|
|
|
|
Old := Prev.Next;
|
|
Prev.Next := D.Next;
|
|
D := D.Next;
|
|
Moved := True;
|
|
|
|
Data.Release (Old, Single => True);
|
|
end if;
|
|
end;
|
|
end if;
|
|
end if;
|
|
end case;
|
|
|
|
if not Moved then
|
|
Prev := D;
|
|
D := D.Next;
|
|
else
|
|
Moved := False;
|
|
end if;
|
|
end loop;
|
|
end Rewrite;
|
|
|
|
N : Tree := T;
|
|
Prev, P : Tree;
|
|
Moved : Boolean := False;
|
|
|
|
begin
|
|
T := N;
|
|
|
|
while N /= null loop
|
|
case N.Kind is
|
|
when Text =>
|
|
Rewrite (N.Text);
|
|
|
|
when Table_Stmt =>
|
|
Run (N.Blocks);
|
|
|
|
when Section_Block =>
|
|
Run (N.Common);
|
|
Run (N.Sections);
|
|
|
|
when Section_Stmt =>
|
|
Run (N.N_Section);
|
|
|
|
when If_Stmt =>
|
|
declare
|
|
V : constant String := Expr.Analyze (N.Cond);
|
|
begin
|
|
if V = Expr.Unknown then
|
|
Run (N.N_True);
|
|
Run (N.N_False);
|
|
|
|
elsif (Expr.Is_True (V) and then N.N_True = null)
|
|
or else (not Expr.Is_True (V) and then N.N_False = null)
|
|
then
|
|
-- The corresponding branch does not exist, skip IF
|
|
Expr.Release (N.Cond);
|
|
Release (N.N_True);
|
|
Release (N.N_False);
|
|
|
|
declare
|
|
Old : Tree;
|
|
begin
|
|
if Prev = null then
|
|
Old := T;
|
|
T := T.Next;
|
|
else
|
|
Old := Prev.Next;
|
|
Prev.Next := N.Next;
|
|
end if;
|
|
|
|
N := N.Next;
|
|
Unchecked_Free (Old);
|
|
end;
|
|
|
|
Moved := True;
|
|
|
|
elsif Expr.Is_True (V) then
|
|
Expr.Release (N.Cond);
|
|
Release (N.N_False);
|
|
|
|
Run (N.N_True);
|
|
|
|
if Prev = null then
|
|
Link_End (N.N_True, T.Next, Link => P);
|
|
Unchecked_Free (T);
|
|
T := N.N_True;
|
|
else
|
|
Link_End (N.N_True, N.Next, Link => P);
|
|
Unchecked_Free (Prev.Next);
|
|
Prev.Next := N.N_True;
|
|
end if;
|
|
|
|
Prev := P;
|
|
N := N.Next;
|
|
Moved := True;
|
|
|
|
else
|
|
Expr.Release (N.Cond);
|
|
Release (N.N_True);
|
|
|
|
Run (N.N_False);
|
|
|
|
if Prev = null then
|
|
Link_End (N.N_False, T.Next, Link => P);
|
|
Unchecked_Free (T);
|
|
T := N.N_False;
|
|
else
|
|
Link_End (N.N_False, N.Next, Link => P);
|
|
Unchecked_Free (Prev.Next);
|
|
Prev.Next := N.N_False;
|
|
end if;
|
|
|
|
Prev := P;
|
|
N := N.Next;
|
|
Moved := True;
|
|
end if;
|
|
end;
|
|
|
|
when others =>
|
|
null;
|
|
end case;
|
|
|
|
if Moved then
|
|
Moved := False;
|
|
else
|
|
Prev := N;
|
|
N := N.Next;
|
|
end if;
|
|
end loop;
|
|
end Run;
|
|
|
|
end Simplifier;
|