parse namespace

This commit is contained in:
z7zmey 2017-11-24 03:36:58 +02:00
parent c284df2e8c
commit b84c35f413
4 changed files with 2926 additions and 2831 deletions

5404
lexer.go

File diff suppressed because it is too large Load Diff

20
lexer.l
View File

@ -314,10 +314,10 @@ NEW_LINE (\r|\n|\r\n)
<PHP>[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] lval.token = string(l.TokenBytes(nil)); return T_COMMENT; // TODO: handle ?>
<PHP>[/][*][*][^*]*[*]+([^*/][^*]*[*]+)*[/] lval.token = string(l.TokenBytes(nil)); return T_DOC_COMMENT; // TODO: handle ?>
<PHP>'[^']*(\\')*' lval.token = string(l.TokenBytes(nil)); return T_CONSTANT_ENCAPSED_STRING
<PHP>{OPERATORS} lval.token = string(l.TokenBytes(nil)); return c
<PHP>{OPERATORS} lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<PHP>\{ pushState(PHP); lval.token = string(l.TokenBytes(nil)); return c
<PHP>\} popState(); lval.token = string(l.TokenBytes(nil)); return c
<PHP>\{ pushState(PHP); lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<PHP>\} popState(); lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<PHP>\${VAR_NAME} lval.token = string(l.TokenBytes(nil)); return T_VARIABLE
<PHP>{VAR_NAME} if c == -1 {fmt.Printf("%q\n", string(l.TokenBytes(nil)))};lval.token = string(l.TokenBytes(nil)); return T_STRING
@ -329,8 +329,8 @@ NEW_LINE (\r|\n|\r\n)
<PHP>[\']([^\\\']*([\\][\'])*)*[\'] lval.token = string(l.TokenBytes(nil)); return T_CONSTANT_ENCAPSED_STRING;
<PHP>` begin(BACKQUOTE); lval.token = string(l.TokenBytes(nil)); return c
<BACKQUOTE>` begin(PHP); lval.token = string(l.TokenBytes(nil)); return c
<PHP>` begin(BACKQUOTE); lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<BACKQUOTE>` begin(PHP); lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<PHP>[b]?\<\<\<[ \t]*({VAR_NAME}|([']{VAR_NAME}['])|(["]{VAR_NAME}["])){NEW_LINE}
tb := l.TokenBytes(nil)
@ -468,7 +468,7 @@ NEW_LINE (\r|\n|\r\n)
c = l.Next()
}
<STRING>\" popState(); lval.token = "\""; return c
<STRING>\" popState(); lval.token = "\""; return rune2Class(l.Prev.Rune)
<STRING,HEREDOC,BACKQUOTE>\{\$ lval.token = string(l.ungetN(1)); return T_CURLY_OPEN
<STRING,HEREDOC,BACKQUOTE>\$\{ pushState(STRING_VAR_NAME);lval.token = string(l.TokenBytes(nil)); return T_DOLLAR_OPEN_CURLY_BRACES
<STRING,HEREDOC,BACKQUOTE>\$ l.ungetN(1);pushState(STRING_VAR)
@ -602,16 +602,16 @@ NEW_LINE (\r|\n|\r\n)
<STRING_VAR>\${VAR_NAME} lval.token = string(l.TokenBytes(nil)); return T_VARIABLE
<STRING_VAR>->{VAR_NAME} lval.token = string(l.ungetN(len(l.TokenBytes(nil))-2)); return T_OBJECT_OPERATOR
<STRING_VAR>{VAR_NAME} popState();lval.token = string(l.TokenBytes(nil)); return T_STRING
<STRING_VAR>\[ pushState(STRING_VAR_INDEX);lval.token = string(l.TokenBytes(nil)); return c
<STRING_VAR>\[ pushState(STRING_VAR_INDEX);lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<STRING_VAR>.|[ \t\n\r] l.ungetN(1);popState()
<STRING_VAR_INDEX>{LNUM}|{HNUM}|{BNUM} lval.token = string(l.TokenBytes(nil)); return T_NUM_STRING
<STRING_VAR_INDEX>\${VAR_NAME} lval.token = string(l.TokenBytes(nil)); return T_VARIABLE
<STRING_VAR_INDEX>{VAR_NAME} lval.token = string(l.TokenBytes(nil)); return T_STRING
<STRING_VAR_INDEX>\] popState(); popState();lval.token = string(l.TokenBytes(nil)); return c
<STRING_VAR_INDEX>\] popState(); popState();lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<STRING_VAR_INDEX>[ \n\r\t\\'#] popState(); popState();lval.token = string(l.TokenBytes(nil)); return T_ENCAPSED_AND_WHITESPACE
<STRING_VAR_INDEX>{OPERATORS} lval.token = string(l.TokenBytes(nil)); return c
<STRING_VAR_INDEX>. lval.token = string(l.TokenBytes(nil)); return c
<STRING_VAR_INDEX>{OPERATORS} lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<STRING_VAR_INDEX>. lval.token = string(l.TokenBytes(nil)); return rune2Class(l.Prev.Rune)
<STRING_VAR_NAME>{VAR_NAME}[\[\}] popState();pushState(PHP);lval.token = string(l.ungetN(1)); return T_STRING_VARNAME
<STRING_VAR_NAME>. l.ungetN(1);popState();pushState(PHP)

146
parser.go
View File

@ -1,7 +1,9 @@
//line parser.y:2
package main
import __yyfmt__ "fmt"
//line parser.y:2
import (
"bytes"
"fmt"
@ -30,10 +32,12 @@ func (n node) print(out io.Writer, indent string) {
func Node(name string) node { return node{name: name} }
func (n node) append(nn ...node) node { n.children = append(n.children, nn...); return n }
//line parser.y:32
type yySymType struct {
yys int
node node
token string
value string
}
const T_INCLUDE = 57346
@ -330,6 +334,7 @@ var yyToknames = [...]string{
"T_DIR",
"T_NS_SEPARATOR",
"T_ELLIPSIS",
"';'",
}
var yyStatenames = [...]string{}
@ -337,8 +342,11 @@ const yyEofCode = 1
const yyErrCode = 2
const yyInitialStackSize = 16
//line parser.y:203
const src = `<?
class
namespace foo\bar\test;
include class;
namespace foo\bar\asdf;
`
func main() {
@ -348,6 +356,7 @@ func main() {
yyParse(l)
}
//line yacctab:1
var yyExca = [...]int{
-1, 1,
1, -1,
@ -356,52 +365,55 @@ var yyExca = [...]int{
const yyPrivate = 57344
const yyLast = 152
const yyLast = 162
var yyAct = [...]int{
12, 13, 14, 15, 16, 4, 17, 18, 19, 55,
56, 5, 1, 2, 0, 0, 0, 0, 0, 0,
16, 17, 18, 19, 20, 85, 21, 22, 23, 59,
60, 86, 4, 87, 88, 84, 8, 9, 1, 2,
83, 3, 6, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 20, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 21, 22, 25, 26,
27, 6, 7, 8, 9, 10, 11, 23, 24, 0,
0, 3, 0, 0, 0, 0, 0, 0, 0, 0,
28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 58, 59, 60, 61, 62, 50, 51, 52, 53,
54, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 0, 70, 68, 69, 65, 66, 0, 57,
63, 64, 71, 72, 74, 73, 75, 76, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 67,
78, 77,
0, 0, 24, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 25, 26, 29, 30,
31, 10, 11, 12, 13, 14, 15, 27, 28, 0,
0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 62, 63, 64, 65, 66, 54, 55, 56, 57,
58, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 0, 74, 72, 73, 69, 70, 0, 61,
67, 68, 75, 76, 78, 77, 79, 80, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 71,
82, 81, 0, 0, 0, 0, 0, 0, 0, 0,
0, 5,
}
var yyPact = [...]int{
-4, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, 8, -1000, -4, -70, -153, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -145, -1000, -1000, -71, -1000, -1000,
}
var yyPgo = [...]int{
0, 13, 12, 11, 5,
0, 22, 21, 20, 19, 18, 17, 16,
}
var yyR1 = [...]int{
0, 2, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
4, 4, 4, 4, 4, 4, 1, 1,
0, 5, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
7, 7, 7, 7, 7, 7, 1, 1, 3, 3,
4, 4, 2, 2,
}
var yyR2 = [...]int{
@ -412,29 +424,32 @@ var yyR2 = [...]int{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
2, 0, 3, 3,
}
var yyChk = [...]int{
-1000, -2, -1, 85, -4, -3, 75, 76, 77, 78,
79, 80, 4, 5, 6, 7, 8, 10, 11, 12,
56, 70, 71, 81, 82, 72, 73, 74, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 115,
116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
110, 111, 112, 113, 114, 13, 14, 133, 105, 106,
107, 108, 109, 134, 135, 130, 131, 153, 128, 129,
127, 136, 137, 139, 138, 140, 141, 155, 154,
-1000, -5, -4, -2, 4, 153, -1, 85, -7, -6,
75, 76, 77, 78, 79, 80, 4, 5, 6, 7,
8, 10, 11, 12, 56, 70, 71, 81, 82, 72,
73, 74, 94, 95, 96, 97, 98, 99, 100, 101,
102, 103, 104, 115, 116, 117, 118, 119, 120, 121,
122, 123, 124, 125, 110, 111, 112, 113, 114, 13,
14, 133, 105, 106, 107, 108, 109, 134, 135, 130,
131, 153, 128, 129, 127, 136, 137, 139, 138, 140,
141, 155, 154, -3, 85, 158, 156, 158, 85,
}
var yyDef = [...]int{
0, -2, 1, 76, 77, 69, 70, 71, 72, 73,
74, 75, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68,
81, -2, 1, 80, 0, 0, 0, 76, 77, 69,
70, 71, 72, 73, 74, 75, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
66, 67, 68, 0, 78, 82, 0, 83, 79,
}
var yyTok1 = [...]int{
@ -443,7 +458,7 @@ var yyTok1 = [...]int{
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 55, 3, 3, 3, 54, 37, 3,
3, 3, 52, 49, 9, 50, 51, 53, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 31, 3,
3, 3, 3, 3, 3, 3, 3, 3, 31, 158,
43, 17, 45, 30, 67, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
@ -479,6 +494,8 @@ var yyErrorMessages = [...]struct {
msg string
}{}
//line yaccpar:1
/* parser for yacc output */
var (
@ -810,19 +827,58 @@ yydefault:
case 1:
yyDollar = yyS[yypt-1 : yypt+1]
//line parser.y:163
{
fmt.Println(yyDollar[1].node)
}
case 76:
yyDollar = yyS[yypt-1 : yypt+1]
//line parser.y:182
{
yyVAL.node = Node("identifier")
}
case 77:
yyDollar = yyS[yypt-1 : yypt+1]
//line parser.y:183
{
yyVAL.node = Node("reserved")
}
case 78:
yyDollar = yyS[yypt-1 : yypt+1]
//line parser.y:187
{
yyVAL.node = Node("Namespace").append(Node(yyDollar[1].token))
}
case 79:
yyDollar = yyS[yypt-3 : yypt+1]
//line parser.y:188
{
yyVAL.node = yyDollar[1].node.append(Node(yyDollar[3].token))
}
case 80:
yyDollar = yyS[yypt-2 : yypt+1]
//line parser.y:192
{
yyVAL.node = yyDollar[1].node.append(yyDollar[2].node)
}
case 81:
yyDollar = yyS[yypt-0 : yypt+1]
//line parser.y:193
{
yyVAL.node = Node("Statements")
}
case 82:
yyDollar = yyS[yypt-3 : yypt+1]
//line parser.y:197
{
yyVAL.node = yyDollar[2].node /*TODO: identifier stub, refactor it*/
}
case 83:
yyDollar = yyS[yypt-3 : yypt+1]
//line parser.y:198
{
yyVAL.node = yyDollar[2].node
}
}
goto yystack /* stack new state and value */
}

187
parser.y
View File

@ -32,6 +32,7 @@ func (n node) append(nn...node) node { n.children = append(n.children, nn...); r
%union{
node node
token string
value string
}
%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
@ -67,98 +68,103 @@ func (n node) append(nn...node) node { n.children = append(n.children, nn...); r
%left T_ENDIF
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
%token T_EXIT
%token T_IF
%token T_LNUMBER
%token T_DNUMBER
%token T_STRING
%token T_STRING_VARNAME
%token T_VARIABLE
%token T_NUM_STRING
%token T_INLINE_HTML
%token T_CHARACTER
%token T_BAD_CHARACTER
%token T_ENCAPSED_AND_WHITESPACE
%token T_CONSTANT_ENCAPSED_STRING
%token T_ECHO
%token T_DO
%token T_WHILE
%token T_ENDWHILE
%token T_FOR
%token T_ENDFOR
%token T_FOREACH
%token T_ENDFOREACH
%token T_DECLARE
%token T_ENDDECLARE
%token T_AS
%token T_SWITCH
%token T_ENDSWITCH
%token T_CASE
%token T_DEFAULT
%token T_BREAK
%token T_CONTINUE
%token T_GOTO
%token T_FUNCTION
%token T_CONST
%token T_RETURN
%token T_TRY
%token T_CATCH
%token T_FINALLY
%token T_THROW
%token T_USE
%token T_INSTEADOF
%token T_GLOBAL
%token T_VAR
%token T_UNSET
%token T_ISSET
%token T_EMPTY
%token T_HALT_COMPILER
%token T_CLASS
%token T_TRAIT
%token T_INTERFACE
%token T_EXTENDS
%token T_IMPLEMENTS
%token T_OBJECT_OPERATOR
%token T_DOUBLE_ARROW
%token T_LIST
%token T_ARRAY
%token T_CALLABLE
%token T_CLASS_C
%token T_TRAIT_C
%token T_METHOD_C
%token T_FUNC_C
%token T_LINE
%token T_FILE
%token T_COMMENT
%token T_DOC_COMMENT
%token T_OPEN_TAG
%token T_OPEN_TAG_WITH_ECHO
%token T_CLOSE_TAG
%token T_WHITESPACE
%token T_START_HEREDOC
%token T_END_HEREDOC
%token T_DOLLAR_OPEN_CURLY_BRACES
%token T_CURLY_OPEN
%token T_PAAMAYIM_NEKUDOTAYIM
%token T_NAMESPACE
%token T_NS_C
%token T_DIR
%token T_NS_SEPARATOR
%token T_ELLIPSIS
%type <token> $unk
%token <token> T_INCLUDE
%token <token> T_INCLUDE_ONCE
%token <token> T_EXIT
%token <token> T_IF
%token <token> T_LNUMBER
%token <token> T_DNUMBER
%token <token> T_STRING
%token <token> T_STRING_VARNAME
%token <token> T_VARIABLE
%token <token> T_NUM_STRING
%token <token> T_INLINE_HTML
%token <token> T_CHARACTER
%token <token> T_BAD_CHARACTER
%token <token> T_ENCAPSED_AND_WHITESPACE
%token <token> T_CONSTANT_ENCAPSED_STRING
%token <token> T_ECHO
%token <token> T_DO
%token <token> T_WHILE
%token <token> T_ENDWHILE
%token <token> T_FOR
%token <token> T_ENDFOR
%token <token> T_FOREACH
%token <token> T_ENDFOREACH
%token <token> T_DECLARE
%token <token> T_ENDDECLARE
%token <token> T_AS
%token <token> T_SWITCH
%token <token> T_ENDSWITCH
%token <token> T_CASE
%token <token> T_DEFAULT
%token <token> T_BREAK
%token <token> T_CONTINUE
%token <token> T_GOTO
%token <token> T_FUNCTION
%token <token> T_CONST
%token <token> T_RETURN
%token <token> T_TRY
%token <token> T_CATCH
%token <token> T_FINALLY
%token <token> T_THROW
%token <token> T_USE
%token <token> T_INSTEADOF
%token <token> T_GLOBAL
%token <token> T_VAR
%token <token> T_UNSET
%token <token> T_ISSET
%token <token> T_EMPTY
%token <token> T_HALT_COMPILER
%token <token> T_CLASS
%token <token> T_TRAIT
%token <token> T_INTERFACE
%token <token> T_EXTENDS
%token <token> T_IMPLEMENTS
%token <token> T_OBJECT_OPERATOR
%token <token> T_DOUBLE_ARROW
%token <token> T_LIST
%token <token> T_ARRAY
%token <token> T_CALLABLE
%token <token> T_CLASS_C
%token <token> T_TRAIT_C
%token <token> T_METHOD_C
%token <token> T_FUNC_C
%token <token> T_LINE
%token <token> T_FILE
%token <token> T_COMMENT
%token <token> T_DOC_COMMENT
%token <token> T_OPEN_TAG
%token <token> T_OPEN_TAG_WITH_ECHO
%token <token> T_CLOSE_TAG
%token <token> T_WHITESPACE
%token <token> T_START_HEREDOC
%token <token> T_END_HEREDOC
%token <token> T_DOLLAR_OPEN_CURLY_BRACES
%token <token> T_CURLY_OPEN
%token <token> T_PAAMAYIM_NEKUDOTAYIM
%token <token> T_NAMESPACE
%token <token> T_NS_C
%token <token> T_DIR
%token <token> T_NS_SEPARATOR
%token <token> T_ELLIPSIS
%type <node> identifier
%type <node> top_statement
%type <node> namespace_name
%type <node> top_statement_list
%%
/////////////////////////////////////////////////////////////////////////
start:
identifier { fmt.Println($1) }
top_statement_list { fmt.Println($1) }
;
reserved_non_modifiers:
T_INCLUDE | T_INCLUDE_ONCE | T_EVAL | T_REQUIRE | T_REQUIRE_ONCE | T_LOGICAL_OR | T_LOGICAL_XOR | T_LOGICAL_AND
T_INCLUDE | T_INCLUDE_ONCE | T_EVAL | T_REQUIRE | T_REQUIRE_ONCE | T_LOGICAL_OR | T_LOGICAL_XOR | T_LOGICAL_AND
| T_INSTANCEOF | T_NEW | T_CLONE | T_EXIT | T_IF | T_ELSEIF | T_ELSE | T_ENDIF | T_ECHO | T_DO | T_WHILE | T_ENDWHILE
| T_FOR | T_ENDFOR | T_FOREACH | T_ENDFOREACH | T_DECLARE | T_ENDDECLARE | T_AS | T_TRY | T_CATCH | T_FINALLY
| T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO
@ -177,12 +183,29 @@ identifier:
| semi_reserved { $$ = Node("reserved") }
;
namespace_name:
T_STRING { $$ = Node("Namespace").append(Node($1)) }
| namespace_name T_NS_SEPARATOR T_STRING { $$ = $1.append(Node($3)) }
;
top_statement_list:
top_statement_list top_statement { $$ = $1.append($2); }
| /* empty */ { $$ = Node("Statements") }
;
top_statement:
T_INCLUDE identifier ';' { $$ = $2; /*TODO: identifier stub, refactor it*/ }
| T_NAMESPACE namespace_name ';' { $$ = $2; }
;
/////////////////////////////////////////////////////////////////////////
%%
const src = `<?
class
namespace foo\bar\test;
include class;
namespace foo\bar\asdf;
`
func main() {