├── 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 | ![Demo](https://github.com/haskellcamargo/advpl-debugger/blob/master/demo.png) 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 | } --------------------------------------------------------------------------------