├── Debug.prg
├── Debugger.prg
├── ExprTest.prg
├── LICENSE
├── README.md
├── demo.png
├── fold_minus.png
├── fold_plus.png
├── folding.js
├── index.html
└── syntax.css
/Debug.prg:
--------------------------------------------------------------------------------
1 | #include "protheus.ch"
2 |
3 | Function Console( xVar )
4 | Local aParser := { ;
5 | /* Keyword */ { |Keyword| Keyword }, ;
6 | /* Number */ { |Number | Number }, ;
7 | /* String */ { |String | '"' + String + '"' }, ;
8 | /* Indent */ { |Scope | Replicate( " ", Scope * 2 ) }, ;
9 | /* Symbol */ { |Symbol | Symbol }, ;
10 | /* Newline */ { | | Chr( 13 ) + Chr( 10 ) }, ;
11 | /* Date */ { |D | D }, ;
12 | /* True */ { |T | T }, ;
13 | /* False */ { |F | F }, ;
14 | /* Nil */ { |N | N }, ;
15 | /* Block */ { |B | B }, ;
16 | /* Propert */ { |P | P }, ;
17 | /* Object */ { |O | O }, ;
18 | /* Unknown */ { |U | U }, ;
19 | /* Name */ { |Nm | Nm }, ;
20 | /* Dedent */ { |Scope | Replicate( " ", ( Scope * 2 ) - 2 ) }, ;
21 | /* Folder */ { | | "" }, ;
22 | /* BeginClos */ { | | "" }, ;
23 | /* EndClos */ { | | "" } }
24 | Return Debugger( xVar, aParser )
25 |
26 | Function Debug( xVar )
27 | Local aParser := { ;
28 | /* Keyword */ { |Keyword| '' + Keyword + "" }, ;
29 | /* Number */ { |Number | '' + Number + "" }, ;
30 | /* String */ { |String | '"' + String + '"' }, ;
31 | /* Indent */ { |Scope | Replicate( " ", Scope * 2 ) }, ;
32 | /* Symbol */ { |Symbol | '' + Symbol + "" }, ;
33 | /* Newline */ { | | "
" }, ;
34 | /* Date */ { |D | '' + D + "" }, ;
35 | /* True */ { |T | '' + T + "" }, ;
36 | /* False */ { |F | '' + F + "" }, ;
37 | /* Nil */ { |N | '' + N + "" }, ;
38 | /* Block */ { |B | '' + B + "" }, ;
39 | /* Property */ { |P | '' + P + "" }, ;
40 | /* Object */ { |O | '' + O + "" }, ;
41 | /* Unknown */ { |U | '' + U + "" }, ;
42 | /* Name */ { |Nm | '' + Nm + "" }, ;
43 | /* Dedent */ { |Scope | Replicate( " ", ( Scope * 2 ) - 2 ) }, ;
44 | /* Folder */ { | | '' }, ;
45 | /* BeginClos */ { | | '' }, ;
46 | /* EndClos */ { | | '' } }
47 | Local cHTML := Debugger( xVar, aParser )
48 | RegisterHTML( cHTML )
49 | DEFINE DIALOG oDlg TITLE "NG - Debugger de Expressoes" FROM 180, 180 TO 550, 700 PIXEL
50 | TIBrowser():New( 0, 0, 260, 180, "C:\ng_debugger\result.html", oDlg )
51 | ACTIVATE MSDIALOG oDlg CENTERED
52 | Return Console( xVar )
53 |
54 | Static Function RegisterHTML( cHTML )
55 | Local nHandle := fCreate( "C:\ng_debugger\result.html" )
56 | fWrite( nHandle, MountPage( cHTML ) )
57 | fClose( nHandle )
58 | Return
59 |
60 | Static Function MountPage( cHTML )
61 | Return '
' ;
63 | + cHTML + '
'
65 |
--------------------------------------------------------------------------------
/Debugger.prg:
--------------------------------------------------------------------------------
1 | #include "protheus.ch"
2 | #define TOKEN ""
3 | #xtranslate @Token { } => Eval( T_, )
4 | #xtranslate @Instance => T_ :=
5 | #xtranslate @Next => Context++
6 | #xtranslate @Previous => Context--
7 |
8 | Function Debugger( xVar, aParser )
9 | Local cExprResult
10 | Static Context := 0
11 |
12 | @Instance KEYWORD aParser[ 1 ]
13 | @Instance NUMBER aParser[ 2 ]
14 | @Instance STRING aParser[ 3 ]
15 | @Instance INDENT aParser[ 4 ]
16 | @Instance SYMBOL aParser[ 5 ]
17 | @Instance NEWLINE aParser[ 6 ]
18 | @Instance DATE aParser[ 7 ]
19 | @Instance TRUE aParser[ 8 ]
20 | @Instance FALSE aParser[ 9 ]
21 | @Instance NIL aParser[ 10 ]
22 | @Instance BLOCK aParser[ 11 ]
23 | @Instance PROPERTY aParser[ 12 ]
24 | @Instance OBJECT aParser[ 13 ]
25 | @Instance UNKNOWN aParser[ 14 ]
26 | @Instance NAME aParser[ 15 ]
27 | @Instance DEDENT aParser[ 16 ]
28 | @Instance FOLDER aParser[ 17 ]
29 | @Instance BEGIN_CLOS aParser[ 18 ]
30 | @Instance END_CLOS aParser[ 19 ]
31 |
32 | cExprResult := ParseExpr( xVar )
33 | ConOut( cExprResult )
34 | Return cExprResult
35 |
36 | Static Function ParseExpr( xVar )
37 | Local cType := ValType( xVar )
38 |
39 | Do Case
40 | Case cType == "C" // String
41 | Return ParseString( xVar )
42 | Case cType == "N" // Number
43 | Return ParseNumber( xVar )
44 | Case cType == "A" // Array
45 | Return ParseArray( xVar )
46 | Case cType == "U" // Nil
47 | Return ParseNil( xVar )
48 | Case cType == "D" // Date
49 | Return ParseDate( xVar )
50 | Case cType == "B" // Block
51 | Return ParseBlock( xVar )
52 | Case cType == "O" // Object
53 | Return ParseObject( xVar )
54 | Case cType == "L" // Logic
55 | If xVar
56 | Return ParseTrue()
57 | Else
58 | Return ParseFalse()
59 | EndIf
60 | Otherwise
61 | Return ParseUnknown( xVar )
62 | EndCase
63 | Return
64 |
65 | Static Function ParseString( cData )
66 | Return @Token { KEYWORD "string" } ;
67 | + @Token { SYMBOL "<" } ;
68 | + @Token { NUMBER AllTrim( Str( Len( cData ) ) ) } ;
69 | + @Token { SYMBOL ">" } ;
70 | + @Token { SYMBOL "(" } ;
71 | + @Token { STRING cData } ;
72 | + @Token { SYMBOL ")" } ;
73 | + @Token { NEWLINE TOKEN }
74 |
75 | Static Function ParseNumber( nData )
76 | Return @Token { KEYWORD "number" } ;
77 | + @Token { SYMBOL "(" } ;
78 | + @Token { NUMBER AllTrim( Str( nData ) ) } ;
79 | + @Token { SYMBOL ")" } ;
80 | + @Token { NEWLINE TOKEN }
81 |
82 | Static Function ParseTrue
83 | Return @Token { KEYWORD "logic" } ;
84 | + @Token { SYMBOL "(" } ;
85 | + @Token { TRUE ".T." } ;
86 | + @Token { SYMBOL ")" } ;
87 | + @Token { NEWLINE TOKEN }
88 |
89 | Static Function ParseFalse
90 | Return @Token { KEYWORD "logic" } ;
91 | + @Token { SYMBOL "(" } ;
92 | + @Token { FALSE ".F." } ;
93 | + @Token { SYMBOL ")" } ;
94 | + @Token { NEWLINE TOKEN }
95 |
96 | Static Function ParseUnknown( xData )
97 | Return @Token { KEYWORD "unknown" } ;
98 | + @Token { SYMBOL "(" } ;
99 | + @Token { UNKNOWN ValType( xData ) } ;
100 | + @Token { SYMBOL ")" } ;
101 | + @Token { NEWLINE TOKEN }
102 |
103 | Static Function ParseNil
104 | Return @Token { NIL "nil" } ;
105 | + @Token { NEWLINE TOKEN }
106 |
107 | Static Function ParseBlock( bData )
108 | Return @Token { KEYWORD "block" } ;
109 | + @Token { SYMBOL "(" } ;
110 | + @Token { BLOCK GetCBSource( bData ) } ;
111 | + @Token { SYMBOL ")" } ;
112 | + @Token { NEWLINE TOKEN }
113 |
114 | Static Function ParseDate( dData )
115 | Return @Token { KEYWORD "date" } ;
116 | + @Token { SYMBOL "(" } ;
117 | + @Token { DATE DtoC( dData ) } ;
118 | + @Token { SYMBOL ")" } ;
119 | + @Token { NEWLINE TOKEN }
120 |
121 | Static Function ParseObject( oData )
122 | Local cTemplate := ""
123 | Local aChildren := ClassDataArr( oData )
124 | Local nContext := 0
125 | @Next
126 | nContext := Context
127 | cTemplate += @Token { KEYWORD "object" } ;
128 | + @Token { SYMBOL "<" } ;
129 | + @Token { NAME GetClassName( oData ) } ;
130 | + @Token { SYMBOL ">" } ;
131 | + @Token { SYMBOL "(" }
132 |
133 | If Len( aChildren ) > 0
134 | cTemplate += @Token { FOLDER TOKEN } ;
135 | + @Token { BEGIN_CLOS TOKEN } ;
136 | + @Token { NEWLINE TOKEN }
137 | Else
138 | cTemplate += @Token { SYMBOL ")" } ;
139 | + @Token { NEWLINE TOKEN }
140 | @Previous
141 | Return cTemplate
142 | EndIf
143 |
144 | cTemplate += ParseProperty( aChildren ) ;
145 | + @Token { DEDENT nContext } ;
146 | + @Token { SYMBOL ")" } ;
147 | + @Token { END_CLOS TOKEN } ;
148 | + @Token { NEWLINE TOKEN }
149 |
150 | @Previous
151 | Return cTemplate
152 |
153 | Static Function ParseProperty( aProp )
154 | Local nI
155 | Local cTemplate := ""
156 | For nI := 1 To Len( aProp )
157 | cTemplate += @Token { INDENT Context } ;
158 | + @Token { KEYWORD "Property" } ;
159 | + @Token { SYMBOL "<" } ;
160 | + @Token { PROPERTY aProp[ nI ][ 1 ] } ;
161 | + @Token { SYMBOL ">" } ;
162 | + @Token { SYMBOL ": " } ;
163 | + ParseExpr( aProp[ nI ][ 2 ] )
164 | Next nI
165 | Return cTemplate
166 |
167 | Static Function ParseArray( aData )
168 | Local nI
169 | Local cTemplate := ""
170 | Local nContext
171 | @Next
172 | nContext := Context
173 | cTemplate += @Token { KEYWORD "array" } ;
174 | + @Token { SYMBOL "<" } ;
175 | + @Token { NUMBER AllTrim( Str( Len( aData ) ) ) } ;
176 | + @Token { SYMBOL ">" } ;
177 | + @Token { SYMBOL "(" } ;
178 | + @Token { FOLDER TOKEN } ;
179 | + @Token { BEGIN_CLOS TOKEN } ;
180 | + @Token { NEWLINE TOKEN }
181 |
182 | For nI := 1 To Len( aData )
183 | cTemplate += @Token { INDENT Context } ;
184 | + @Token { SYMBOL "[" } ;
185 | + @Token { NUMBER AllTrim( Str( nI ) ) } ;
186 | + @Token { SYMBOL "]" } ;
187 | + @Token { SYMBOL " => " } ;
188 | + ParseExpr( aData[ nI ] )
189 | Next nI
190 |
191 | cTemplate += @Token { DEDENT nContext } ;
192 | + @Token { SYMBOL ")" } ;
193 | + @Token { END_CLOS TOKEN } ;
194 | + @Token { NEWLINE TOKEN }
195 | @Previous
196 | Return cTemplate
197 |
--------------------------------------------------------------------------------
/ExprTest.prg:
--------------------------------------------------------------------------------
1 | /**
2 | * Teste do analisador de expressões.
3 | * @author Marcelo Camargo
4 | */
5 | Function ExprTest
6 | Debug( { { { |X| X * X }, "Lorem ipsum dolor sit amet consectetur", nil }, ;
7 | .T., .F., 1.39, { 12 }, Person:Create( "Bar", 10 ) } )
8 | Return
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Marcelo Camargo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AdvPL Debugger
2 |
3 | An expressions analyzer for AdvPL in AdvPL!
4 |
5 | 
6 |
7 | Written by [Marcelo Haskell Camargo](https://github.com/haskellcamargo)
8 |
--------------------------------------------------------------------------------
/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nginformatica/advpl-debugger/08ca3448812bd0b4d7173a8902f4f75cc52654f6/demo.png
--------------------------------------------------------------------------------
/fold_minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nginformatica/advpl-debugger/08ca3448812bd0b4d7173a8902f4f75cc52654f6/fold_minus.png
--------------------------------------------------------------------------------
/fold_plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nginformatica/advpl-debugger/08ca3448812bd0b4d7173a8902f4f75cc52654f6/fold_plus.png
--------------------------------------------------------------------------------
/folding.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Folding da árvore sintática gerada.
3 | * @author Marcelo Camargo
4 | */
5 | (function(syntax) {
6 |
7 | // Aplicar folding nos elementos definidos como foldables pelo parser
8 | var folders = syntax.getElementsByClassName("folder");
9 |
10 | for (var i = 0, len = folders.length; i < len; i++) {
11 | folders[i].appendChild((function() {
12 | var image = document.createElement("img");
13 | image.src = "fold_minus.png";
14 | return image;
15 | })());
16 |
17 | folders[i].onclick = function(e) {
18 | if (this.nextSibling.style.display === "none") {
19 | this.nextSibling.style.display = "inline";
20 | this.firstChild.src = "fold_minus.png";
21 | } else {
22 | this.nextSibling.style.display = "none";
23 | this.firstChild.src = "fold_plus.png";
24 | }
25 | };
26 | }
27 | })(window.document);
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | array<6>(
8 | [1] => array<3>(
9 | [1] => block({|X| X * X})
10 | [2] => string<38>("Lorem ipsum dolor sit amet consectetur")
11 | [3] => nil
12 | )
13 | [2] => logic(.T.)
14 | [3] => logic(.F.)
15 | [4] => number(1.39)
16 | [5] => array<1>(
17 | [1] => number(12)
18 | )
19 | [6] => object<Person>(
20 | Property<cName> => string("Bar")
21 | Property<cAge> => number(10)
22 | )
23 | )
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/syntax.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Arquivo de definição sintática para o analisador de expressões AdvPL.
3 | * @author Marcelo Camargo
4 | */
5 | html, body {
6 | padding: 0;
7 | margin: 0;
8 | background: gainsboro;
9 | }
10 |
11 | #codegen {
12 | font-family: monospace;
13 | line-height: 20px;
14 | padding: 20px;
15 | }
16 |
17 | .keyword {
18 | color: #0077C0;
19 | font-weight: bold;
20 | }
21 |
22 | .symbol {
23 | color: #34495E;
24 | }
25 |
26 | .number {
27 | color: #AA0C48;
28 | }
29 |
30 | .block {
31 | border: 1px solid #333;
32 | color: #6E248D;
33 | background: white;
34 | padding: 2px;
35 | }
36 |
37 | .nil {
38 | color: #6E3C1B;
39 | }
40 |
41 | .string {
42 | border: 1px solid #333;
43 | color: #B71C0C;
44 | background: white;
45 | padding: 2px;
46 | }
47 |
48 | .true {
49 | font-weight: bold;
50 | color: #009C41;
51 | }
52 |
53 | .false {
54 | font-weight: bold;
55 | color: #A70C00;
56 | }
57 |
58 | .name {
59 | text-decoration: underline;
60 | color: #E67E22;
61 | }
62 |
63 | .property {
64 | color: #004790;
65 | }
66 |
67 | .folder img {
68 | width: 16px;
69 | height: 16px;
70 | line-height: 20px;
71 | margin-bottom: -3px;
72 | cursor: pointer;
73 | }
74 |
75 | .string .extender {
76 | cursor: pointer;
77 | border: 1px solid silver;
78 | padding: 0 3px;
79 | background: #009C41;
80 | color: white;
81 | }
--------------------------------------------------------------------------------