How to use consume method of ast Package

Best Syzkaller code snippet using ast.consume

parser.go

Source:parser.go Github

copy

Full Screen

...159 if len(p.trivia) != 0 {160 tok.LeadingTriv = p.trivia161 p.trivia = nil162 }163 // Try consume trailing trivia164 line := p.file.Line(tok.End())165 for {166 trail := p.scanToken()167 if !p.isTrivia(trail) {168 p.unscanToken(trail)169 break170 }171 if line != p.file.Line(trail.Pos()) {172 p.trivia = append(p.trivia, asTrivia(trail))173 break174 }175 tok.TrailingTriv = append(tok.TrailingTriv, asTrivia(trail))176 }177 return tok178}179func (p *parser) isTrivia(tok ast.Token) bool {180 switch {181 case tok.Kind == token.COMMENT:182 return true183 case tok.Kind == token.PREPROC:184 return true185 default:186 if p.ppSkip && tok.Kind != token.EOF {187 return true188 }189 return false190 }191}192// Advance to the next token193func (p *parser) consume() ast.Token {194 tok := p.tokens[p.cursor]195 if p.trace {196 s := tok.Kind.String()197 switch {198 case tok.Kind.IsLiteral():199 p.printTrace(s, tok.Lit)200 case tok.Kind.IsOperator(), tok.Kind.IsKeyword():201 p.printTrace("\"" + s + "\"")202 default:203 p.printTrace(s)204 }205 }206 // Track curly braces for TTCN-3 semicolon rules207 p.seenBrace = false208 if p.tok == token.RBRACE {209 p.seenBrace = true210 }211 p.cursor++212 if p.cursor == len(p.tokens) && !p.speculating() {213 p.cursor = 0214 p.tokens = p.tokens[:0]215 }216 p.peek(1)217 p.tok = p.tokens[p.cursor].Kind218 return tok219}220// Append current token to trailing trivia and advance to next token.221func (p *parser) consumeTrivia(tok *ast.Token) {222 triv := p.consume()223 // TODO(5nord) Remove when parser is ready224 if tok == nil {225 return226 }227 var trivs []ast.Trivia228 copy(trivs, triv.LeadingTriv)229 trivs = append(trivs, asTrivia(triv))230 trivs = append(trivs, triv.TrailingTriv...)231 tok.TrailingTriv = append(tok.TrailingTriv, trivs...)232}233func (p *parser) peek(i int) ast.Token {234 idx := p.cursor + i - 1235 last := len(p.tokens) - 1236 if idx > last {237 n := idx - last238 for i := 0; i < n; i++ {239 p.tokens = append(p.tokens, p.scan())240 }241 }242 return p.tokens[idx]243}244func (p *parser) pos(i int) loc.Pos {245 tok := p.peek(i)246 return tok.Pos()247}248func (p *parser) lit(i int) string {249 return p.peek(i).Lit250}251func (p *parser) mark() {252 p.markers = append(p.markers, p.cursor)253}254func (p *parser) commit() {255 last := len(p.markers) - 1256 p.markers = p.markers[0:last]257}258func (p *parser) reset() {259 last := len(p.markers) - 1260 marker := p.markers[last]261 p.markers = p.markers[0:last]262 p.cursor = marker263 p.tok = p.tokens[p.cursor].Kind264}265func (p *parser) speculating() bool {266 return len(p.markers) > 0267}268// ----------------------------------------------------------------------------269// Tracing support270func (p *parser) printTrace(a ...interface{}) {271 const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "272 const n = len(dots)273 pos := p.file.Position(p.pos(1))274 fmt.Printf("%5d:%3d: ", pos.Line, pos.Column)275 i := 2 * p.indent276 for i > n {277 fmt.Print(dots)278 i -= n279 }280 // i <= n281 fmt.Print(dots[0:i])282 fmt.Println(a...)283}284func trace(p *parser, msg string) *parser {285 p.printTrace(msg, "(")286 p.indent++287 return p288}289// A bailout panic is raised to indicate early termination.290type bailout struct{}291func (p *parser) error(pos loc.Pos, msg string) {292 epos := p.file.Position(pos)293 // If AllErrors is not set, discard errors reported on the same line294 // as the last recorded error and stop parsing if there are more than295 // 10 errors.296 if p.mode&AllErrors == 0 {297 n := len(p.errors)298 if n > 0 && p.errors[n-1].Pos.Line == epos.Line {299 return // discard - likely a spurious error300 }301 if n > 10 {302 panic(bailout{})303 }304 }305 p.errors.Add(epos, msg)306}307func (p *parser) errorExpected(pos loc.Pos, msg string) {308 msg = "expected " + msg309 if pos == p.pos(1) {310 // the error happened at the current position;311 // make the error message more specific312 switch {313 case p.tok.IsLiteral():314 // print 123 rather than 'INT', etc.315 msg += ", found " + p.lit(1)316 default:317 msg += ", found '" + p.tok.String() + "'"318 }319 }320 p.error(pos, msg)321}322func (p *parser) expect(k token.Kind) ast.Token {323 if p.tok != k {324 tok := p.peek(1)325 p.errorExpected(tok.Pos(), "'"+k.String()+"'")326 }327 return p.consume() // make progress328}329func (p *parser) expectSemi(tok *ast.Token) {330 if p.tok == token.SEMICOLON {331 p.consumeTrivia(tok)332 return333 }334 // pedantic semicolon335 if p.semi {336 // semicolon is optional before a closing '}'337 if !p.seenBrace && p.tok == token.RBRACE && p.tok != token.EOF {338 p.errorExpected(p.pos(1), "';'")339 p.advance(stmtStart)340 }341 }342}343// advance consumes tokens until the current token p.tok344// is in the 'to' set, or EOF. For error recovery.345func (p *parser) advance(to map[token.Kind]bool) {346 for ; p.tok != token.EOF; p.consume() {347 if to[p.tok] {348 // Return only if parser made some progress since last349 // sync or if it has not reached 10 advance calls without350 // progress. Otherwise consume at least one token to351 // avoid an endless parser loop (it is possible that352 // both parseOperand and parseStmt call advance and353 // correctly do not advance, thus the need for the354 // invocation limit p.syncCnt).355 if p.pos(1) == p.syncPos && p.syncCnt < 10 {356 p.syncCnt++357 return358 }359 if p.pos(1) > p.syncPos {360 p.syncPos = p.pos(1)361 p.syncCnt = 0362 return363 }364 // Reaching here indicates a parser bug, likely an365 // incorrect token list in this function, but it only366 // leads to skipping of possibly correct code if a367 // previous error is present, and thus is preferred368 // over a non-terminating parse.369 }370 }371}372var stmtStart = map[token.Kind]bool{373 token.ALT: true,374 token.ALTSTEP: true,375 token.BREAK: true,376 token.CASE: true,377 token.CONST: true,378 token.CONTINUE: true,379 token.CONTROL: true,380 token.DISPLAY: true,381 token.DO: true,382 token.ELSE: true,383 token.ENCODE: true,384 token.EXTENSION: true,385 token.FOR: true,386 token.FRIEND: true,387 token.FUNCTION: true,388 token.GOTO: true,389 token.GROUP: true,390 token.IF: true,391 token.IMPORT: true,392 token.INTERLEAVE: true,393 token.LABEL: true,394 token.MAP: true,395 token.MODULE: true,396 token.MODULEPAR: true,397 token.PORT: true,398 token.PRIVATE: true,399 token.PUBLIC: true,400 token.RBRACE: true,401 token.REPEAT: true,402 token.RETURN: true,403 token.SELECT: true,404 token.SEMICOLON: true,405 token.SIGNATURE: true,406 token.TEMPLATE: true,407 token.TESTCASE: true,408 token.TIMER: true,409 token.TYPE: true,410 token.UNMAP: true,411 token.VAR: true,412 token.VARIANT: true,413 token.WHILE: true,414}415var operandStart = map[token.Kind]bool{416 token.ADDRESS: true,417 token.ALL: true,418 token.ANY: true,419 token.ANYKW: true,420 token.BSTRING: true,421 token.CHARSTRING: true,422 token.ERROR: true,423 token.FAIL: true,424 token.FALSE: true,425 token.FLOAT: true,426 //token.IDENT: true, TODO(5nord) fix conflict, see failing parser tests427 token.INCONC: true,428 token.INT: true,429 token.MAP: true,430 token.MTC: true,431 token.MUL: true,432 token.NAN: true,433 token.NONE: true,434 token.NULL: true,435 token.OMIT: true,436 token.PASS: true,437 token.STRING: true,438 token.SYSTEM: true,439 token.TESTCASE: true,440 token.TIMER: true,441 token.TRUE: true,442 token.UNIVERSAL: true,443 token.UNMAP: true,444}445var topLevelTokens = map[token.Kind]bool{446 token.COMMA: true,447 token.SEMICOLON: true,448 token.MODULE: true,449 token.CONTROL: true,450 token.EXTERNAL: true,451 token.FRIEND: true,452 token.FUNCTION: true,453 token.GROUP: true,454 token.IMPORT: true,455 token.MODULEPAR: true,456 token.SIGNATURE: true,457 token.TEMPLATE: true,458 token.TYPE: true,459 token.VAR: true,460 token.ALTSTEP: true,461 token.CONST: true,462 token.PRIVATE: true,463 token.PUBLIC: true,464 token.TIMER: true,465 token.PORT: true,466 token.REPEAT: true,467 token.BREAK: true,468 token.CONTINUE: true,469 token.LABEL: true,470 token.GOTO: true,471 token.RETURN: true,472 token.SELECT: true,473 token.ALT: true,474 token.INTERLEAVE: true,475 token.LBRACK: true,476 token.FOR: true,477 token.WHILE: true,478 token.DO: true,479 token.IF: true,480 token.LBRACE: true,481 token.IDENT: true,482 token.ANYKW: true,483 token.ALL: true,484 token.MAP: true,485 token.UNMAP: true,486 token.MTC: true,487 token.TESTCASE: true,488}489// parse is a generic entry point490func (p *parser) parse() ast.Node {491 switch p.tok {492 case token.MODULE:493 return p.parseModule()494 case token.CONTROL,495 token.EXTERNAL,496 token.FRIEND,497 token.FUNCTION,498 token.GROUP,499 token.IMPORT,500 token.MODULEPAR,501 token.SIGNATURE,502 token.TEMPLATE,503 token.TYPE,504 token.VAR,505 token.ALTSTEP,506 token.CONST,507 token.PRIVATE,508 token.PUBLIC:509 return p.parseModuleDef()510 case token.TIMER, token.PORT,511 token.REPEAT, token.BREAK, token.CONTINUE,512 token.LABEL,513 token.GOTO,514 token.RETURN,515 token.SELECT,516 token.ALT, token.INTERLEAVE,517 token.LBRACK,518 token.FOR,519 token.WHILE,520 token.DO,521 token.IF,522 token.LBRACE,523 token.IDENT, token.ANYKW, token.ALL, token.MAP, token.UNMAP, token.MTC:524 return p.parseStmt()525 case token.TESTCASE:526 if p.peek(1).Kind == token.DOT {527 return p.parseStmt()528 }529 return p.parseModuleDef()530 default:531 return p.parseExpr()532 }533}534/*************************************************************************535 * Expressions536 *************************************************************************/537// ExprList ::= ast.Expr { "," ast.Expr }538func (p *parser) parseExprList() (list []ast.Expr) {539 if p.trace {540 defer un(trace(p, "ExprList"))541 }542 list = append(list, p.parseExpr())543 for p.tok == token.COMMA {544 p.consumeTrivia(list[len(list)-1].LastTok())545 list = append(list, p.parseExpr())546 }547 return list548}549// ast.Expr ::= BinaryExpr550func (p *parser) parseExpr() ast.Expr {551 if p.trace {552 defer un(trace(p, "ast.Expr"))553 }554 return p.parseBinaryExpr(token.LowestPrec + 1)555}556// BinaryExpr ::= UnaryExpr557// | BinaryExpr OP BinaryExpr558//559func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {560 x := p.parseUnaryExpr()561 for {562 prec := p.tok.Precedence()563 if prec < prec1 {564 return x565 }566 op := p.consume()567 y := p.parseBinaryExpr(prec + 1)568 x = &ast.BinaryExpr{X: x, Op: op, Y: y}569 }570}571// UnaryExpr ::= "-"572// | ("-"|"+"|"!"|"not"|"not4b") UnaryExpr573// | PrimaryExpr574//575func (p *parser) parseUnaryExpr() ast.Expr {576 switch p.tok {577 case token.ADD, token.EXCL, token.NOT, token.NOT4B, token.SUB:578 tok := p.consume()579 // handle unused expr '-'580 if tok.Kind == token.SUB {581 switch p.tok {582 case token.COMMA, token.SEMICOLON, token.RBRACE, token.RBRACK, token.RPAREN, token.EOF:583 return &ast.ValueLiteral{Tok: tok}584 }585 }586 return &ast.UnaryExpr{Op: tok, X: p.parseUnaryExpr()}587 case token.COLONCOLON:588 tok := p.consume()589 return &ast.BinaryExpr{Op: tok, Y: p.parseExpr()}590 }591 return p.parsePrimaryExpr()592}593// PrimaryExpr ::= Operand [{ExtFieldRef}] [Stuff]594//595// ExtFieldRef ::= "." ID596// | "[" ast.Expr "]"597// | "(" ExprList ")"598//599// Stuff ::= ["length" "(" ExprList ")"]600// ["ifpresent" ]601// [("to"|"from") ast.Expr ]602// ["->" Redirect ]603// Redirect ::= ["value" ExprList ]604// ["param" ExprList ]605// ["sender" PrimaryExpr]606// ["@index" ["value"] PrimaryExpr]607// ["timestamp" PrimaryExpr]608//609func (p *parser) parsePrimaryExpr() ast.Expr {610 x := p.parseOperand()611L:612 for {613 switch p.tok {614 case token.DOT:615 x = p.parseSelectorExpr(x)616 case token.LBRACK:617 x = p.parseIndexExpr(x)618 case token.LPAREN:619 x = p.parseCallExpr(x)620 // Not supporting chained function calls like 'get().x'621 // eleminates conflicts with alt-guards.622 break623 default:624 break L625 }626 }627 if p.tok == token.LENGTH {628 x = p.parseLength(x)629 }630 if p.tok == token.IFPRESENT {631 x = &ast.UnaryExpr{Op: p.consume(), X: x}632 }633 if p.tok == token.TO || p.tok == token.FROM {634 x = &ast.BinaryExpr{X: x, Op: p.consume(), Y: p.parseExpr()}635 }636 if p.tok == token.REDIR {637 x = p.parseRedirect(x)638 }639 if p.tok == token.VALUE {640 x = &ast.ValueExpr{X: x, Tok: p.consume(), Y: p.parseExpr()}641 }642 if p.tok == token.PARAM {643 x = &ast.ParamExpr{X: x, Tok: p.consume(), Y: p.parseParenExpr()}644 }645 if p.tok == token.ALIVE {646 x = &ast.UnaryExpr{Op: p.consume(), X: x}647 }648 return x649}650// Operand ::= ("any"|"all") ("component"|"port"|"timer"|"from" PrimaryExpr)651// | Literal652// | Reference653//654// Literal ::= INT | STRING | BSTRING | FLOAT655// | "?" | "*"656// | "none" | "inconc" | "pass" | "fail" | "error"657// | "true" | "false"658// | "not_a_number"659//660// Reference ::= ID661// | "address" | ["unviersal"] "charstring" | "timer"662// | "null" | "omit"663// | "mtc" | "system" | "testcase"664// | "map" | "unmap"665//666func (p *parser) parseOperand() ast.Expr {667 etok := p.peek(1)668 switch p.tok {669 case token.ANYKW, token.ALL:670 tok := p.consume()671 switch p.tok {672 case token.COMPONENT, token.PORT, token.TIMER:673 return p.make_use(tok, p.consume())674 case token.FROM:675 return &ast.FromExpr{676 Kind: tok,677 FromTok: p.consume(),678 X: p.parsePrimaryExpr(),679 }680 }681 // Workaround for deprecated port-attribute 'all'682 if tok.Kind == token.ALL {683 return p.make_use(tok)684 }685 p.errorExpected(p.pos(1), "'component', 'port', 'timer' or 'from'")686 case token.UNIVERSAL:687 return p.parseUniversalCharstring()688 case token.ADDRESS,689 token.CHARSTRING,690 token.MAP,691 token.MTC,692 token.SYSTEM,693 token.TESTCASE,694 token.TIMER,695 token.UNMAP:696 return p.make_use(p.consume())697 case token.IDENT:698 return p.parseRef()699 case token.INT,700 token.ANY,701 token.BSTRING,702 token.ERROR,703 token.NULL,704 token.OMIT,705 token.FAIL,706 token.FALSE,707 token.FLOAT,708 token.INCONC,709 token.MUL,710 token.NAN,711 token.NONE,712 token.PASS,713 token.STRING,714 token.TRUE:715 return &ast.ValueLiteral{Tok: p.consume()}716 case token.LPAREN:717 // can be template `x := (1,2,3)`, but also artihmetic expression: `1*(2+3)`718 return p.parseParenExpr()719 case token.LBRACK:720 return p.parseIndexExpr(nil)721 case token.LBRACE:722 return p.parseCompositeLiteral()723 case token.MODIFIES:724 return &ast.ModifiesExpr{725 Tok: p.consume(),726 X: p.parsePrimaryExpr(),727 Assign: p.expect(token.ASSIGN),728 Y: p.parseExpr(),729 }730 case token.REGEXP:731 return p.parseCallRegexp()732 case token.PATTERN:733 return p.parseCallPattern()734 case token.DECMATCH:735 return p.parseCallDecmatch()736 case token.MODIF:737 return p.parseDecodedModifier()738 default:739 p.errorExpected(p.pos(1), "operand")740 }741 return &ast.ErrorNode{From: etok, To: p.peek(1)}742}743func (p *parser) parseRef() ast.Expr {744 id := p.parseIdent()745 if id == nil {746 return nil747 }748 if p.tok != token.LT {749 return id750 }751 p.mark()752 if x := p.tryTypeParameters(); x != nil && !operandStart[p.tok] {753 p.commit()754 return &ast.ParametrizedIdent{Ident: id, Params: x}755 }756 p.reset()757 return id758}759func (p *parser) parseParenExpr() *ast.ParenExpr {760 return &ast.ParenExpr{761 LParen: p.expect(token.LPAREN),762 List: p.parseExprList(),763 RParen: p.expect(token.RPAREN),764 }765}766func (p *parser) parseUniversalCharstring() *ast.Ident {767 return p.make_use(p.expect(token.UNIVERSAL), p.expect(token.CHARSTRING))768}769func (p *parser) parseCompositeLiteral() *ast.CompositeLiteral {770 c := new(ast.CompositeLiteral)771 c.LBrace = p.expect(token.LBRACE)772 if p.tok != token.RBRACE {773 c.List = p.parseExprList()774 }775 c.RBrace = p.expect(token.RBRACE)776 return c777}778func (p *parser) parseCallRegexp() *ast.RegexpExpr {779 c := new(ast.RegexpExpr)780 c.Tok = p.expect(token.REGEXP)781 if p.tok == token.MODIF {782 c.NoCase = p.consume()783 }784 c.X = p.parseParenExpr()785 return c786}787func (p *parser) parseCallPattern() *ast.PatternExpr {788 c := new(ast.PatternExpr)789 c.Tok = p.expect(token.PATTERN)790 if p.tok == token.MODIF {791 c.NoCase = p.consume()792 }793 c.X = p.parseExpr()794 return c795}796func (p *parser) parseCallDecmatch() *ast.DecmatchExpr {797 c := new(ast.DecmatchExpr)798 c.Tok = p.expect(token.DECMATCH)799 if p.tok == token.LPAREN {800 c.Params = p.parseParenExpr()801 }802 c.X = p.parseExpr()803 return c804}805func (p *parser) parseDecodedModifier() *ast.DecodedExpr {806 d := new(ast.DecodedExpr)807 d.Tok = p.expect(token.MODIF)808 if d.Tok.Lit != "@decoded" {809 p.errorExpected(d.Tok.Pos(), "@decoded")810 }811 if p.tok == token.LPAREN {812 d.Params = p.parseParenExpr()813 }814 d.X = p.parsePrimaryExpr()815 return d816}817func (p *parser) parseSelectorExpr(x ast.Expr) *ast.SelectorExpr {818 return &ast.SelectorExpr{X: x, Dot: p.consume(), Sel: p.parseRef()}819}820func (p *parser) parseIndexExpr(x ast.Expr) *ast.IndexExpr {821 return &ast.IndexExpr{822 X: x,823 LBrack: p.expect(token.LBRACK),824 Index: p.parseExpr(),825 RBrack: p.expect(token.RBRACK),826 }827}828func (p *parser) parseCallExpr(x ast.Expr) *ast.CallExpr {829 c := new(ast.CallExpr)830 c.Fun = x831 c.Args = new(ast.ParenExpr)832 c.Args.LParen = p.expect(token.LPAREN)833 if p.tok != token.RPAREN {834 switch p.tok {835 case token.TO, token.FROM, token.REDIR:836 var x ast.Expr837 if p.tok == token.TO || p.tok == token.FROM {838 // TODO: Shouldn't this be a FromExpr?839 x = &ast.BinaryExpr{X: x, Op: p.consume(), Y: p.parseExpr()}840 }841 if p.tok == token.REDIR {842 x = p.parseRedirect(x)843 }844 c.Args.List = []ast.Expr{x}845 default:846 c.Args.List = append(c.Args.List, p.parseExprList()...)847 }848 }849 c.Args.RParen = p.expect(token.RPAREN)850 return c851}852func (p *parser) parseLength(x ast.Expr) *ast.LengthExpr {853 return &ast.LengthExpr{854 X: x,855 Len: p.expect(token.LENGTH),856 Size: p.parseParenExpr(),857 }858}859func (p *parser) parseRedirect(x ast.Expr) *ast.RedirectExpr {860 r := &ast.RedirectExpr{861 X: x,862 Tok: p.expect(token.REDIR),863 }864 if p.tok == token.VALUE {865 r.ValueTok = p.expect(token.VALUE)866 r.Value = p.parseExprList()867 }868 if p.tok == token.PARAM {869 r.ParamTok = p.expect(token.PARAM)870 r.Param = p.parseExprList()871 }872 if p.tok == token.SENDER {873 r.SenderTok = p.expect(token.SENDER)874 r.Sender = p.parsePrimaryExpr()875 }876 if p.tok == token.MODIF {877 if p.lit(1) != "@index" {878 p.errorExpected(p.pos(1), "@index")879 }880 r.IndexTok = p.consume()881 if p.tok == token.VALUE {882 r.IndexValueTok = p.consume()883 }884 r.Index = p.parsePrimaryExpr()885 }886 if p.tok == token.TIMESTAMP {887 r.TimestampTok = p.expect(token.TIMESTAMP)888 r.Timestamp = p.parsePrimaryExpr()889 }890 return r891}892func (p *parser) parseName() *ast.Ident {893 switch p.tok {894 case token.IDENT, token.ADDRESS, token.CONTROL:895 id := &ast.Ident{Tok: p.consume(), IsName: true}896 p.names[id.String()] = true897 return id898 }899 p.expect(token.IDENT)900 return nil901}902func (p *parser) parseIdent() *ast.Ident {903 switch p.tok {904 case token.UNIVERSAL:905 return p.parseUniversalCharstring()906 case token.IDENT, token.ADDRESS, token.ALIVE, token.CHARSTRING, token.CONTROL:907 return p.make_use(p.consume())908 default:909 p.expect(token.IDENT) // use expect() error handling910 return nil911 }912}913func (p *parser) parseArrayDefs() []*ast.ParenExpr {914 var l []*ast.ParenExpr915 for p.tok == token.LBRACK {916 l = append(l, p.parseArrayDef())917 }918 return l919}920func (p *parser) parseArrayDef() *ast.ParenExpr {921 return &ast.ParenExpr{922 LParen: p.expect(token.LBRACK),923 List: p.parseExprList(),924 RParen: p.expect(token.RBRACK),925 }926}927func (p *parser) parseRefList() []ast.Expr {928 l := make([]ast.Expr, 0, 1)929 for {930 l = append(l, p.parseTypeRef())931 if p.tok != token.COMMA {932 break933 }934 p.consumeTrivia(l[len(l)-1].LastTok()) // consume ','935 }936 return l937}938func (p *parser) parseTypeRef() ast.Expr {939 if p.trace {940 defer un(trace(p, "TypeRef"))941 }942 return p.parsePrimaryExpr()943}944func (p *parser) tryTypeParameters() *ast.ParenExpr {945 if p.trace {946 defer un(trace(p, "tryTypeParameters"))947 }948 x := &ast.ParenExpr{949 LParen: p.consume(),950 }951 for p.tok != token.GT {952 y := p.tryTypeParameter()953 if y == nil {954 return nil955 }956 x.List = append(x.List, y)957 if p.tok != token.COMMA {958 break959 }960 p.consumeTrivia(x.List[len(x.List)-1].LastTok()) // consume ','961 }962 if p.tok != token.GT {963 return nil964 }965 x.RParen = p.consume()966 return x967}968func (p *parser) tryTypeParameter() ast.Expr {969 if p.trace {970 defer un(trace(p, "tryTypeParameter"))971 }972 x := p.tryTypeIdent()973L:974 for {975 switch p.tok {976 case token.DOT:977 x = &ast.SelectorExpr{978 X: x,979 Dot: p.consume(),980 Sel: p.tryTypeIdent(),981 }982 if x.(*ast.SelectorExpr).Sel == nil {983 return nil984 }985 case token.LBRACK:986 lbrack := p.consume()987 dash := p.consume()988 rbrack := p.consume()989 if dash.Kind != token.SUB || rbrack.Kind != token.RBRACK {990 return nil991 }992 x = &ast.IndexExpr{993 X: x,994 LBrack: lbrack,995 Index: &ast.ValueLiteral{Tok: dash},996 RBrack: rbrack,997 }998 default:999 break L1000 }1001 }1002 return x1003}1004func (p *parser) tryTypeIdent() ast.Expr {1005 if p.trace {1006 defer un(trace(p, "tryTypeIdent"))1007 }1008 var x *ast.Ident1009 switch p.tok {1010 case token.IDENT, token.ADDRESS, token.CHARSTRING:1011 x = p.make_use(p.consume())1012 case token.UNIVERSAL:1013 x = p.parseUniversalCharstring()1014 default:1015 return nil1016 }1017 if p.tok == token.LT {1018 if y := p.tryTypeParameters(); y == nil {1019 return &ast.ParametrizedIdent{1020 Ident: x,1021 Params: y,1022 }1023 }1024 }1025 return x1026}1027/*************************************************************************1028 * ast.Module1029 *************************************************************************/1030func (p *parser) parseModuleList() []*ast.Module {1031 var list []*ast.Module1032 if m := p.parseModule(); m != nil {1033 list = append(list, m)1034 p.expectSemi(m.LastTok())1035 }1036 for p.tok == token.MODULE {1037 if m := p.parseModule(); m != nil {1038 list = append(list, m)1039 p.expectSemi(m.LastTok())1040 }1041 }1042 p.expect(token.EOF)1043 return list1044}1045func (p *parser) parseModule() *ast.Module {1046 if p.trace {1047 defer un(trace(p, "ast.Module"))1048 }1049 m := new(ast.Module)1050 m.Tok = p.expect(token.MODULE)1051 m.Name = p.parseName()1052 if p.tok == token.LANGUAGE {1053 m.Language = p.parseLanguageSpec()1054 }1055 m.LBrace = p.expect(token.LBRACE)1056 for p.tok != token.RBRACE && p.tok != token.EOF {1057 m.Defs = append(m.Defs, p.parseModuleDef())1058 p.expectSemi(m.Defs[len(m.Defs)-1].LastTok())1059 }1060 m.RBrace = p.expect(token.RBRACE)1061 m.With = p.parseWith()1062 return m1063}1064func (p *parser) parseLanguageSpec() *ast.LanguageSpec {1065 l := new(ast.LanguageSpec)1066 l.Tok = p.consume()1067 for {1068 l.List = append(l.List, p.expect(token.STRING))1069 if p.tok != token.COMMA {1070 break1071 }1072 p.consumeTrivia(l.List[len(l.List)-1].LastTok()) // consume ','1073 }1074 return l1075}1076func (p *parser) parseModuleDef() *ast.ModuleDef {1077 m := new(ast.ModuleDef)1078 switch p.tok {1079 case token.PRIVATE, token.PUBLIC:1080 m.Visibility = p.consume()1081 case token.FRIEND:1082 if p.peek(2).Kind != token.MODULE {1083 m.Visibility = p.consume()1084 }1085 }1086 etok := p.peek(1)1087 switch p.tok {1088 case token.IMPORT:1089 m.Def = p.parseImport()1090 case token.GROUP:1091 m.Def = p.parseGroup()1092 case token.FRIEND:1093 m.Def = p.parseFriend()1094 case token.TYPE:1095 m.Def = p.parseTypeDecl()1096 case token.TEMPLATE:1097 m.Def = p.parseTemplateDecl()1098 case token.MODULEPAR:1099 m.Def = p.parseModulePar()1100 case token.VAR, token.CONST:1101 m.Def = p.parseValueDecl()1102 case token.SIGNATURE:1103 m.Def = p.parseSignatureDecl()1104 case token.FUNCTION, token.TESTCASE, token.ALTSTEP:1105 m.Def = p.parseFuncDecl()1106 case token.CONTROL:1107 m.Def = &ast.ControlPart{Name: p.parseIdent(), Body: p.parseBlockStmt(), With: p.parseWith()}1108 case token.EXTERNAL:1109 switch p.peek(2).Kind {1110 case token.FUNCTION:1111 m.Def = p.parseExtFuncDecl()1112 case token.CONST:1113 p.error(p.pos(1), "external constants not suppored")1114 p.consumeTrivia(nil)1115 m.Def = p.parseValueDecl()1116 default:1117 p.errorExpected(p.pos(1), "'function'")1118 p.advance(stmtStart)1119 m.Def = &ast.ErrorNode{From: etok, To: p.peek(1)}1120 }1121 default:1122 p.errorExpected(p.pos(1), "module definition")1123 p.advance(stmtStart)1124 m.Def = &ast.ErrorNode{From: etok, To: p.peek(1)}1125 }1126 if m.Def != nil {1127 p.addName(m.Def)1128 }1129 return m1130}1131func (p *parser) addName(n ast.Node) {1132 switch n := n.(type) {1133 case *ast.ValueDecl:1134 for _, n := range n.Decls {1135 p.addName(n)1136 }1137 default:1138 if name := ast.Name(n); name != "" {1139 p.names[name] = true1140 }1141 }1142}1143/*************************************************************************1144 * Import Definition1145 *************************************************************************/1146func (p *parser) make_use(toks ...ast.Token) *ast.Ident {1147 if len(toks) != 1 && len(toks) != 2 {1148 panic("No support for multi-token identifiers.")1149 }1150 id := &ast.Ident{Tok: toks[0]}1151 p.uses[toks[0].String()] = true1152 if len(toks) == 2 {1153 id.Tok2 = toks[1]1154 p.uses[toks[1].String()] = true1155 }1156 return id1157}1158func (p *parser) parseImport() *ast.ImportDecl {1159 if p.trace {1160 defer un(trace(p, "Import"))1161 }1162 x := new(ast.ImportDecl)1163 x.ImportTok = p.consume()1164 x.FromTok = p.expect(token.FROM)1165 x.Module = p.parseIdent()1166 if p.tok == token.LANGUAGE {1167 x.Language = p.parseLanguageSpec()1168 }1169 switch p.tok {1170 case token.ALL:1171 y := &ast.DefKindExpr{}1172 var z ast.Expr = p.make_use(p.consume())1173 if p.tok == token.EXCEPT {1174 z = &ast.ExceptExpr{1175 X: z,1176 ExceptTok: p.consume(),1177 LBrace: p.expect(token.LBRACE),1178 List: p.parseExceptStmts(),1179 RBrace: p.expect(token.RBRACE),1180 }1181 }1182 y.List = []ast.Expr{z}1183 x.List = append(x.List, y)1184 case token.LBRACE:1185 x.LBrace = p.expect(token.LBRACE)1186 for p.tok != token.RBRACE && p.tok != token.EOF {1187 x.List = append(x.List, p.parseImportStmt())1188 p.expectSemi(x.List[len(x.List)-1].LastTok())1189 }1190 x.RBrace = p.expect(token.RBRACE)1191 default:1192 p.errorExpected(p.pos(1), "'all' or import spec")1193 }1194 x.With = p.parseWith()1195 return x1196}1197func (p *parser) parseImportStmt() *ast.DefKindExpr {1198 x := new(ast.DefKindExpr)1199 switch p.tok {1200 case token.ALTSTEP, token.CONST, token.FUNCTION, token.MODULEPAR,1201 token.SIGNATURE, token.TEMPLATE, token.TESTCASE, token.TYPE:1202 x.Kind = p.consume()1203 if p.tok == token.ALL {1204 var y ast.Expr = p.make_use(p.consume())1205 if p.tok == token.EXCEPT {1206 y = &ast.ExceptExpr{1207 X: y,1208 ExceptTok: p.consume(),1209 List: p.parseRefList(),1210 }1211 }1212 x.List = []ast.Expr{y}1213 } else {1214 x.List = p.parseRefList()1215 }1216 case token.GROUP:1217 x.Kind = p.consume()1218 for {1219 y := p.parseTypeRef()1220 if p.tok == token.EXCEPT {1221 y = &ast.ExceptExpr{1222 X: y,1223 ExceptTok: p.consume(),1224 LBrace: p.expect(token.LBRACE),1225 List: p.parseExceptStmts(),1226 RBrace: p.expect(token.RBRACE),1227 }1228 }1229 x.List = append(x.List, y)1230 if p.tok != token.COMMA {1231 break1232 }1233 p.consumeTrivia(y.LastTok()) // consume ','1234 }1235 case token.IMPORT:1236 x.Kind = p.consume()1237 x.List = []ast.Expr{p.make_use(p.expect(token.ALL))}1238 default:1239 p.errorExpected(p.pos(1), "import definition qualifier")1240 p.advance(stmtStart)1241 }1242 return x1243}1244func (p *parser) parseExceptStmts() []ast.Expr {1245 var list []ast.Expr1246 for p.tok != token.RBRACE && p.tok != token.EOF {1247 x := p.parseExceptStmt()1248 p.expectSemi(x.LastTok())1249 list = append(list, x)1250 }1251 return list1252}1253func (p *parser) parseExceptStmt() *ast.DefKindExpr {1254 x := new(ast.DefKindExpr)1255 switch p.tok {1256 case token.ALTSTEP, token.CONST, token.FUNCTION, token.GROUP,1257 token.IMPORT, token.MODULEPAR, token.SIGNATURE, token.TEMPLATE,1258 token.TESTCASE, token.TYPE:1259 x.Kind = p.consume()1260 default:1261 p.errorExpected(p.pos(1), "definition qualifier")1262 }1263 if p.tok == token.ALL {1264 x.List = []ast.Expr{p.make_use(p.consume())}1265 } else {1266 x.List = p.parseRefList()1267 }1268 return x1269}1270/*************************************************************************1271 * Group Definition1272 *************************************************************************/1273func (p *parser) parseGroup() *ast.GroupDecl {1274 x := new(ast.GroupDecl)1275 x.Tok = p.consume()1276 x.Name = p.parseName()1277 x.LBrace = p.expect(token.LBRACE)1278 for p.tok != token.RBRACE && p.tok != token.EOF {1279 x.Defs = append(x.Defs, p.parseModuleDef())1280 p.expectSemi(x.Defs[len(x.Defs)-1].LastTok())1281 }1282 x.RBrace = p.expect(token.RBRACE)1283 x.With = p.parseWith()1284 return x1285}1286func (p *parser) parseFriend() *ast.FriendDecl {1287 return &ast.FriendDecl{1288 FriendTok: p.expect(token.FRIEND),1289 ModuleTok: p.expect(token.MODULE),1290 Module: p.parseIdent(),1291 With: p.parseWith(),1292 }1293}1294/*************************************************************************1295 * With Attributes1296 *************************************************************************/1297func (p *parser) parseWith() *ast.WithSpec {1298 if p.tok != token.WITH {1299 return nil1300 }1301 x := new(ast.WithSpec)1302 x.Tok = p.consume()1303 x.LBrace = p.expect(token.LBRACE)1304 for p.tok != token.RBRACE && p.tok != token.EOF {1305 x.List = append(x.List, p.parseWithStmt())1306 p.expectSemi(x.List[len(x.List)-1].LastTok())1307 }1308 x.RBrace = p.expect(token.RBRACE)1309 return x1310}1311func (p *parser) parseWithStmt() *ast.WithStmt {1312 if p.trace {1313 defer un(trace(p, "WithStmt"))1314 }1315 x := new(ast.WithStmt)1316 switch p.tok {1317 case token.ENCODE,1318 token.VARIANT,1319 token.DISPLAY,1320 token.EXTENSION,1321 token.OPTIONAL,1322 token.STEPSIZE,1323 token.OVERRIDE:1324 x.Kind = p.consume()1325 default:1326 p.errorExpected(p.pos(1), "with-attribute")1327 p.advance(stmtStart)1328 }1329 switch p.tok {1330 case token.OVERRIDE:1331 x.Override = p.consume()1332 case token.MODIF:1333 if p.lit(1) != "@local" {1334 p.errorExpected(p.pos(1), "@local")1335 }1336 x.Override = p.consume()1337 }1338 if p.tok == token.LPAREN {1339 x.LParen = p.consume()1340 for {1341 x.List = append(x.List, p.parseWithQualifier())1342 if p.tok != token.COMMA {1343 break1344 }1345 p.consumeTrivia(x.List[len(x.List)-1].LastTok())1346 }1347 x.RParen = p.expect(token.RPAREN)1348 }1349 var v ast.Expr = &ast.ValueLiteral{Tok: p.expect(token.STRING)}1350 if p.tok == token.DOT {1351 v = &ast.SelectorExpr{1352 X: v,1353 Dot: p.consume(),1354 Sel: &ast.ValueLiteral{Tok: p.expect(token.STRING)},1355 }1356 }1357 x.Value = v1358 return x1359}1360func (p *parser) parseWithQualifier() ast.Expr {1361 etok := p.peek(1)1362 switch p.tok {1363 case token.IDENT:1364 return p.parseTypeRef()1365 case token.LBRACK:1366 return p.parseIndexExpr(nil)1367 case token.TYPE, token.TEMPLATE, token.CONST, token.ALTSTEP, token.TESTCASE, token.FUNCTION, token.SIGNATURE, token.MODULEPAR, token.GROUP:1368 x := new(ast.DefKindExpr)1369 x.Kind = p.consume()1370 var y ast.Expr = p.make_use(p.expect(token.ALL))1371 if p.tok == token.EXCEPT {1372 y = &ast.ExceptExpr{1373 X: y,1374 ExceptTok: p.consume(),1375 LBrace: p.expect(token.LBRACE),1376 List: p.parseRefList(),1377 RBrace: p.expect(token.RBRACE),1378 }1379 }1380 x.List = []ast.Expr{y}1381 return x1382 default:1383 p.errorExpected(p.pos(1), "with-qualifier")1384 p.advance(stmtStart)1385 return &ast.ErrorNode{From: etok, To: p.peek(1)}1386 }1387}1388/*************************************************************************1389 * Type Definitions1390 *************************************************************************/1391func (p *parser) parseTypeDecl() ast.Decl {1392 etok := p.peek(1)1393 switch p.peek(2).Kind {1394 case token.IDENT, token.ADDRESS, token.CHARSTRING, token.NULL, token.UNIVERSAL:1395 return p.parseSubTypeDecl()1396 case token.PORT:1397 return p.parsePortTypeDecl()1398 case token.COMPONENT:1399 return p.parseComponentTypeDecl()1400 case token.UNION:1401 return p.parseStructTypeDecl()1402 case token.SET, token.RECORD:1403 if p.peek(3).Kind == token.IDENT || p.peek(3).Kind == token.ADDRESS {1404 return p.parseStructTypeDecl()1405 }1406 // lists are also parsed by parseSubTypeDecl1407 return p.parseSubTypeDecl()1408 case token.ENUMERATED:1409 return p.parseEnumTypeDecl()1410 case token.FUNCTION, token.ALTSTEP, token.TESTCASE:1411 return p.parseBehaviourTypeDecl()1412 default:1413 p.errorExpected(p.pos(1), "type definition")1414 p.advance(stmtStart)1415 return &ast.ErrorNode{From: etok, To: p.peek(1)}1416 }1417}1418/*************************************************************************1419 * Port Type1420 *************************************************************************/1421func (p *parser) parsePortTypeDecl() *ast.PortTypeDecl {1422 if p.trace {1423 defer un(trace(p, "ast.PortTypeDecl"))1424 }1425 x := new(ast.PortTypeDecl)1426 x.TypeTok = p.consume()1427 x.PortTok = p.consume()1428 x.Name = p.parseName()1429 if p.tok == token.LT {1430 x.TypePars = p.parseTypeFormalPars()1431 }1432 switch p.tok {1433 case token.MIXED, token.MESSAGE, token.PROCEDURE:1434 x.Kind = p.consume()1435 default:1436 p.errorExpected(p.pos(1), "'message' or 'procedure'")1437 }1438 if p.tok == token.REALTIME {1439 x.Realtime = p.consume()1440 }1441 x.LBrace = p.expect(token.LBRACE)1442 for p.tok != token.RBRACE && p.tok != token.EOF {1443 x.Attrs = append(x.Attrs, p.parsePortAttribute())1444 p.expectSemi(x.Attrs[len(x.Attrs)-1].LastTok())1445 }1446 x.RBrace = p.expect(token.RBRACE)1447 x.With = p.parseWith()1448 return x1449}1450func (p *parser) parsePortAttribute() ast.Node {1451 if p.trace {1452 defer un(trace(p, "ast.PortAttribute"))1453 }1454 etok := p.peek(1)1455 switch p.tok {1456 case token.IN, token.OUT, token.INOUT, token.ADDRESS:1457 return &ast.PortAttribute{1458 Kind: p.consume(),1459 Types: p.parseRefList(),1460 }1461 case token.MAP, token.UNMAP:1462 return &ast.PortMapAttribute{1463 MapTok: p.consume(),1464 ParamTok: p.expect(token.PARAM),1465 Params: p.parseFormalPars(),1466 }1467 default:1468 p.errorExpected(p.pos(1), "port attribute")1469 p.advance(stmtStart)1470 return &ast.ErrorNode{From: etok, To: p.peek(1)}1471 }1472}1473/*************************************************************************1474 * Component Type1475 *************************************************************************/1476func (p *parser) parseComponentTypeDecl() *ast.ComponentTypeDecl {1477 if p.trace {1478 defer un(trace(p, "ast.ComponentTypeDecl"))1479 }1480 x := new(ast.ComponentTypeDecl)1481 x.TypeTok = p.consume()1482 x.CompTok = p.consume()1483 x.Name = p.parseName()1484 if p.tok == token.LT {1485 x.TypePars = p.parseTypeFormalPars()1486 }1487 if p.tok == token.EXTENDS {1488 x.ExtendsTok = p.consume()1489 x.Extends = p.parseRefList()1490 }1491 x.Body = p.parseBlockStmt()1492 x.With = p.parseWith()1493 return x1494}1495/*************************************************************************1496 * Struct Type Declaration1497 *************************************************************************/1498func (p *parser) parseStructTypeDecl() *ast.StructTypeDecl {1499 if p.trace {1500 defer un(trace(p, "ast.StructTypeDecl"))1501 }1502 x := new(ast.StructTypeDecl)1503 x.TypeTok = p.consume()1504 x.Kind = p.consume()1505 x.Name = p.parseName()1506 if p.tok == token.LT {1507 x.TypePars = p.parseTypeFormalPars()1508 }1509 x.LBrace = p.expect(token.LBRACE)1510 for p.tok != token.RBRACE && p.tok != token.EOF {1511 x.Fields = append(x.Fields, p.parseField())1512 if p.tok != token.COMMA {1513 break1514 }1515 p.consumeTrivia(x.Fields[len(x.Fields)-1].LastTok())1516 }1517 x.RBrace = p.expect(token.RBRACE)1518 x.With = p.parseWith()1519 return x1520}1521/*************************************************************************1522 * Enumeration Type Declaration1523 *************************************************************************/1524func (p *parser) parseEnumTypeDecl() *ast.EnumTypeDecl {1525 if p.trace {1526 defer un(trace(p, "ast.EnumTypeDecl"))1527 }1528 x := new(ast.EnumTypeDecl)1529 x.TypeTok = p.consume()1530 x.EnumTok = p.consume()1531 x.Name = p.parseName()1532 if p.tok == token.LT {1533 x.TypePars = p.parseTypeFormalPars()1534 }1535 x.LBrace = p.expect(token.LBRACE)1536 for p.tok != token.RBRACE && p.tok != token.EOF {1537 x.Enums = append(x.Enums, p.parseEnum())1538 if p.tok != token.COMMA {1539 break1540 }1541 p.consumeTrivia(x.Enums[len(x.Enums)-1].LastTok())1542 }1543 x.RBrace = p.expect(token.RBRACE)1544 x.With = p.parseWith()1545 return x1546}1547func (p *parser) parseEnum() ast.Expr {1548 var firstIdent func(n ast.Expr) *ast.Ident1549 firstIdent = func(n ast.Expr) *ast.Ident {1550 switch n := n.(type) {1551 case *ast.CallExpr:1552 return firstIdent(n.Fun)1553 case *ast.SelectorExpr:1554 return firstIdent(n.X)1555 case *ast.Ident:1556 return n1557 default:1558 return nil1559 }1560 }1561 x := p.parseExpr()1562 if id := firstIdent(x); id != nil {1563 p.names[id.String()] = true1564 id.IsName = true1565 }1566 return x1567}1568/*************************************************************************1569 * Behaviour Type Declaration1570 *************************************************************************/1571func (p *parser) parseBehaviourTypeDecl() *ast.BehaviourTypeDecl {1572 if p.trace {1573 defer un(trace(p, "ast.BehaviourTypeDecl"))1574 }1575 x := new(ast.BehaviourTypeDecl)1576 x.TypeTok = p.consume()1577 x.Kind = p.consume()1578 x.Name = p.parseName()1579 if p.tok == token.LT {1580 x.TypePars = p.parseTypeFormalPars()1581 }1582 x.Params = p.parseFormalPars()1583 if p.tok == token.RUNS {1584 x.RunsOn = p.parseRunsOn()1585 }1586 if p.tok == token.SYSTEM {1587 x.System = p.parseSystem()1588 }1589 if p.tok == token.RETURN {1590 x.Return = p.parseReturn()1591 }1592 x.With = p.parseWith()1593 return x1594}1595/*************************************************************************1596 * Subtype1597 *************************************************************************/1598func (p *parser) parseSubTypeDecl() *ast.SubTypeDecl {1599 if p.trace {1600 defer un(trace(p, "ast.SubTypeDecl"))1601 }1602 x := new(ast.SubTypeDecl)1603 x.TypeTok = p.consume()1604 x.Field = p.parseField()1605 x.With = p.parseWith()1606 return x1607}1608func (p *parser) parseField() *ast.Field {1609 if p.trace {1610 defer un(trace(p, "Field"))1611 }1612 x := new(ast.Field)1613 if p.tok == token.MODIF {1614 if p.lit(1) != "@default" {1615 p.errorExpected(p.pos(1), "@default")1616 }1617 x.DefaultTok = p.consume()1618 }1619 x.Type = p.parseTypeSpec()1620 x.Name = p.parseName()1621 if p.tok == token.LT {1622 x.TypePars = p.parseTypeFormalPars()1623 }1624 if p.tok == token.LBRACK {1625 x.ArrayDef = p.parseArrayDefs()1626 }1627 if p.tok == token.LPAREN {1628 x.ValueConstraint = p.parseParenExpr()1629 }1630 if p.tok == token.LENGTH {1631 x.LengthConstraint = p.parseLength(nil)1632 }1633 if p.tok == token.OPTIONAL {1634 x.Optional = p.consume()1635 }1636 return x1637}1638func (p *parser) parseTypeSpec() ast.TypeSpec {1639 if p.trace {1640 defer un(trace(p, "TypeSpec"))1641 }1642 etok := p.peek(1)1643 switch p.tok {1644 case token.ADDRESS, token.CHARSTRING, token.IDENT, token.NULL, token.UNIVERSAL:1645 return &ast.RefSpec{X: p.parseTypeRef()}1646 case token.UNION:1647 return p.parseStructSpec()1648 case token.SET, token.RECORD:1649 if p.peek(2).Kind == token.LBRACE {1650 return p.parseStructSpec()1651 }1652 return p.parseListSpec()1653 case token.ENUMERATED:1654 return p.parseEnumSpec()1655 case token.FUNCTION, token.ALTSTEP, token.TESTCASE:1656 return p.parseBehaviourSpec()1657 default:1658 p.errorExpected(p.pos(1), "type definition")1659 return &ast.ErrorNode{From: etok, To: p.peek(1)}1660 }1661}1662func (p *parser) parseStructSpec() *ast.StructSpec {1663 if p.trace {1664 defer un(trace(p, "StructSpec"))1665 }1666 x := new(ast.StructSpec)1667 x.Kind = p.consume()1668 x.LBrace = p.expect(token.LBRACE)1669 for p.tok != token.RBRACE && p.tok != token.EOF {1670 x.Fields = append(x.Fields, p.parseField())1671 if p.tok != token.COMMA {1672 break1673 }1674 p.consumeTrivia(x.Fields[len(x.Fields)-1].LastTok())1675 }1676 x.RBrace = p.expect(token.RBRACE)1677 return x1678}1679func (p *parser) parseEnumSpec() *ast.EnumSpec {1680 if p.trace {1681 defer un(trace(p, "ListSpec"))1682 }1683 x := new(ast.EnumSpec)1684 x.Tok = p.consume()1685 x.LBrace = p.expect(token.LBRACE)1686 for p.tok != token.RBRACE && p.tok != token.EOF {1687 x.Enums = append(x.Enums, p.parseEnum())1688 if p.tok != token.COMMA {1689 break1690 }1691 p.consumeTrivia(x.Enums[len(x.Enums)-1].LastTok())1692 }1693 x.RBrace = p.expect(token.RBRACE)1694 return x1695}1696func (p *parser) parseListSpec() *ast.ListSpec {1697 if p.trace {1698 defer un(trace(p, "ListSpec"))1699 }1700 x := new(ast.ListSpec)1701 x.Kind = p.consume()1702 if p.tok == token.LENGTH {1703 x.Length = p.parseLength(nil)1704 }1705 x.OfTok = p.expect(token.OF)1706 x.ElemType = p.parseTypeSpec()1707 return x1708}1709func (p *parser) parseBehaviourSpec() *ast.BehaviourSpec {1710 if p.trace {1711 defer un(trace(p, "BehaviourSpec"))1712 }1713 x := new(ast.BehaviourSpec)1714 x.Kind = p.consume()1715 x.Params = p.parseFormalPars()1716 if p.tok == token.RUNS {1717 x.RunsOn = p.parseRunsOn()1718 }1719 if p.tok == token.SYSTEM {1720 x.System = p.parseSystem()1721 }1722 if p.tok == token.RETURN {1723 x.Return = p.parseReturn()1724 }1725 return x1726}1727/*************************************************************************1728 * Template Declaration1729 *************************************************************************/1730func (p *parser) parseTemplateDecl() *ast.TemplateDecl {1731 if p.trace {1732 defer un(trace(p, "TemplateDecl"))1733 }1734 x := &ast.TemplateDecl{}1735 x.TemplateTok = p.consume()1736 if p.tok == token.LPAREN {1737 x.LParen = p.consume() // consume '('1738 x.Tok = p.consume() // consume omit/value/...1739 x.RParen = p.expect(token.RPAREN)1740 }1741 if p.tok == token.MODIF {1742 x.Modif = p.consume()1743 }1744 x.Type = p.parseTypeRef()1745 if _, ok := x.Type.(*ast.ErrorNode); ok {1746 return x1747 }1748 x.Name = p.parseName()1749 if p.tok == token.LT {1750 x.TypePars = p.parseTypeFormalPars()1751 }1752 if p.tok == token.LPAREN {1753 x.Params = p.parseFormalPars()1754 }1755 if p.tok == token.MODIFIES {1756 x.ModifiesTok = p.consume()1757 x.Base = p.parsePrimaryExpr()1758 }1759 x.AssignTok = p.expect(token.ASSIGN)1760 x.Value = p.parseExpr()1761 x.With = p.parseWith()1762 return x1763}1764/*************************************************************************1765 * ast.Module ast.FormalPar1766 *************************************************************************/1767func (p *parser) parseModulePar() ast.Decl {1768 if p.trace {1769 defer un(trace(p, "ModulePar"))1770 }1771 tok := p.consume()1772 // parse deprecated module parameter group1773 if p.tok == token.LBRACE {1774 x := &ast.ModuleParameterGroup{Tok: tok}1775 x.LBrace = p.consume()1776 for p.tok != token.RBRACE && p.tok != token.EOF {1777 d := new(ast.ValueDecl)1778 d.TemplateRestriction = p.parseRestrictionSpec()1779 d.Type = p.parseTypeRef()1780 d.Decls = p.parseDeclList()1781 p.expectSemi(d.Decls[len(d.Decls)-1].LastTok())1782 x.Decls = append(x.Decls, d)1783 }1784 x.RBrace = p.expect(token.RBRACE)1785 x.With = p.parseWith()1786 return x1787 }1788 x := &ast.ValueDecl{Kind: tok}1789 x.TemplateRestriction = p.parseRestrictionSpec()1790 x.Type = p.parseTypeRef()1791 x.Decls = p.parseDeclList()1792 x.With = p.parseWith()1793 return x1794}1795/*************************************************************************1796 * Value Declaration1797 *************************************************************************/1798func (p *parser) parseValueDecl() *ast.ValueDecl {1799 if p.trace {1800 defer un(trace(p, "ValueDecl"))1801 }1802 x := &ast.ValueDecl{Kind: p.consume()}1803 x.TemplateRestriction = p.parseRestrictionSpec()1804 if p.tok == token.MODIF {1805 x.Modif = p.consume()1806 }1807 if x.Kind.Kind != token.TIMER {1808 x.Type = p.parseTypeRef()1809 }1810 x.Decls = p.parseDeclList()1811 x.With = p.parseWith()1812 return x1813}1814func (p *parser) parseRestrictionSpec() *ast.RestrictionSpec {1815 switch p.tok {1816 case token.TEMPLATE:1817 x := new(ast.RestrictionSpec)1818 x.TemplateTok = p.consume()1819 if p.tok == token.LPAREN {1820 x.LParen = p.consume()1821 x.Tok = p.consume()1822 x.RParen = p.expect(token.RPAREN)1823 }1824 return x1825 case token.OMIT, token.VALUE, token.PRESENT:1826 x := new(ast.RestrictionSpec)1827 x.Tok = p.consume()1828 return x1829 default:1830 return nil1831 }1832}1833func (p *parser) parseDeclList() (list []*ast.Declarator) {1834 if p.trace {1835 defer un(trace(p, "DeclList"))1836 }1837 list = append(list, p.parseDeclarator())1838 for p.tok == token.COMMA {1839 p.consumeTrivia(list[len(list)-1].LastTok())1840 list = append(list, p.parseDeclarator())1841 }1842 return1843}1844func (p *parser) parseDeclarator() *ast.Declarator {1845 x := &ast.Declarator{}1846 x.Name = p.parseName()1847 if p.tok == token.LBRACK {1848 x.ArrayDef = p.parseArrayDefs()1849 }1850 if p.tok == token.ASSIGN {1851 x.AssignTok = p.consume()1852 x.Value = p.parseExpr()1853 }1854 return x1855}1856/*************************************************************************1857 * Behaviour Declaration1858 *************************************************************************/1859func (p *parser) parseFuncDecl() *ast.FuncDecl {1860 if p.trace {1861 defer un(trace(p, "FuncDecl"))1862 }1863 x := new(ast.FuncDecl)1864 x.Kind = p.consume()1865 if p.tok == token.MODIF {1866 x.Modif = p.consume()1867 }1868 x.Name = p.parseName()1869 if p.tok == token.LT {1870 x.TypePars = p.parseTypeFormalPars()1871 }1872 x.Params = p.parseFormalPars()1873 if p.tok == token.RUNS {1874 x.RunsOn = p.parseRunsOn()1875 }1876 if p.tok == token.MTC {1877 x.Mtc = p.parseMtc()1878 }1879 if p.tok == token.SYSTEM {1880 x.System = p.parseSystem()1881 }1882 if p.tok == token.RETURN {1883 x.Return = p.parseReturn()1884 }1885 if p.tok == token.LBRACE {1886 x.Body = p.parseBlockStmt()1887 }1888 x.With = p.parseWith()1889 return x1890}1891/*************************************************************************1892 * External Function Declaration1893 *************************************************************************/1894func (p *parser) parseExtFuncDecl() *ast.FuncDecl {1895 if p.trace {1896 defer un(trace(p, "ExtFuncDecl"))1897 }1898 x := new(ast.FuncDecl)1899 x.External = p.consume()1900 x.Kind = p.consume()1901 if p.tok == token.MODIF {1902 x.Modif = p.consume()1903 }1904 x.Name = p.parseName()1905 x.Params = p.parseFormalPars()1906 if p.tok == token.RUNS {1907 x.RunsOn = p.parseRunsOn()1908 }1909 if p.tok == token.MTC {1910 x.Mtc = p.parseMtc()1911 }1912 if p.tok == token.SYSTEM {1913 x.System = p.parseSystem()1914 }1915 if p.tok == token.RETURN {1916 x.Return = p.parseReturn()1917 }1918 x.With = p.parseWith()1919 return x1920}1921/*************************************************************************1922 * Signature Declaration1923 *************************************************************************/1924func (p *parser) parseSignatureDecl() *ast.SignatureDecl {1925 if p.trace {1926 defer un(trace(p, "SignatureDecl"))1927 }1928 x := new(ast.SignatureDecl)1929 x.Tok = p.consume()1930 x.Name = p.parseName()1931 if p.tok == token.LT {1932 x.TypePars = p.parseTypeFormalPars()1933 }1934 x.Params = p.parseFormalPars()1935 if p.tok == token.NOBLOCK {1936 x.NoBlock = p.consume()1937 }1938 if p.tok == token.RETURN {1939 x.Return = p.parseReturn()1940 }1941 if p.tok == token.EXCEPTION {1942 x.ExceptionTok = p.consume()1943 x.Exception = p.parseParenExpr()1944 }1945 x.With = p.parseWith()1946 return x1947}1948func (p *parser) parseRunsOn() *ast.RunsOnSpec {1949 return &ast.RunsOnSpec{1950 RunsTok: p.expect(token.RUNS),1951 OnTok: p.expect(token.ON),1952 Comp: p.parseTypeRef(),1953 }1954}1955func (p *parser) parseSystem() *ast.SystemSpec {1956 return &ast.SystemSpec{1957 Tok: p.expect(token.SYSTEM),1958 Comp: p.parseTypeRef(),1959 }1960}1961func (p *parser) parseMtc() *ast.MtcSpec {1962 return &ast.MtcSpec{1963 Tok: p.expect(token.MTC),1964 Comp: p.parseTypeRef(),1965 }1966}1967func (p *parser) parseReturn() *ast.ReturnSpec {1968 x := new(ast.ReturnSpec)1969 x.Tok = p.consume()1970 x.Restriction = p.parseRestrictionSpec()1971 if p.tok == token.MODIF {1972 x.Modif = p.consume()1973 }1974 x.Type = p.parseTypeRef()1975 return x1976}1977func (p *parser) parseFormalPars() *ast.FormalPars {1978 if p.trace {1979 defer un(trace(p, "FormalPars"))1980 }1981 x := new(ast.FormalPars)1982 x.LParen = p.expect(token.LPAREN)1983 for p.tok != token.RPAREN {1984 x.List = append(x.List, p.parseFormalPar())1985 if p.tok != token.COMMA {1986 break1987 }1988 p.consumeTrivia(x.List[len(x.List)-1].LastTok())1989 }1990 x.RParen = p.expect(token.RPAREN)1991 return x1992}1993func (p *parser) parseFormalPar() *ast.FormalPar {1994 if p.trace {1995 defer un(trace(p, "ast.FormalPar"))1996 }1997 x := new(ast.FormalPar)1998 switch p.tok {1999 case token.IN:2000 x.Direction = p.consume()2001 case token.OUT:2002 x.Direction = p.consume()2003 case token.INOUT:2004 x.Direction = p.consume()2005 }2006 x.TemplateRestriction = p.parseRestrictionSpec()2007 if p.tok == token.MODIF {2008 x.Modif = p.consume()2009 }2010 x.Type = p.parseTypeRef()2011 x.Name = p.parseName()2012 if p.tok == token.LBRACK {2013 x.ArrayDef = p.parseArrayDefs()2014 }2015 if p.tok == token.ASSIGN {2016 x.AssignTok = p.consume()2017 x.Value = p.parseExpr()2018 }2019 return x2020}2021func (p *parser) parseTypeFormalPars() *ast.FormalPars {2022 if p.trace {2023 defer un(trace(p, "TypeFormalPars"))2024 }2025 x := new(ast.FormalPars)2026 x.LParen = p.expect(token.LT)2027 for p.tok != token.GT {2028 x.List = append(x.List, p.parseTypeFormalPar())2029 if p.tok != token.COMMA {2030 break2031 }2032 p.consumeTrivia(x.List[len(x.List)-1].LastTok())2033 }2034 x.RParen = p.expect(token.GT)2035 return x2036}2037func (p *parser) parseTypeFormalPar() *ast.FormalPar {2038 if p.trace {2039 defer un(trace(p, "TypeFormalPar"))2040 }2041 x := new(ast.FormalPar)2042 if p.tok == token.IN {2043 x.Direction = p.consume()2044 }2045 switch p.tok {2046 case token.TYPE:2047 x.Type = p.make_use(p.consume())2048 case token.SIGNATURE:2049 x.Type = p.make_use(p.consume())2050 default:2051 x.Type = p.parseTypeRef()2052 }2053 x.Name = p.make_use(p.expect(token.IDENT))2054 x.Name.IsName = true2055 if p.tok == token.ASSIGN {2056 x.AssignTok = p.consume()2057 x.Value = p.parseTypeRef()2058 }2059 return x2060}2061/*************************************************************************2062 * Statements2063 *************************************************************************/2064func (p *parser) parseBlockStmt() *ast.BlockStmt {2065 if p.trace {2066 defer un(trace(p, "BlockStmt"))2067 }2068 x := &ast.BlockStmt{LBrace: p.expect(token.LBRACE)}2069 for p.tok != token.RBRACE && p.tok != token.EOF {2070 x.Stmts = append(x.Stmts, p.parseStmt())2071 p.expectSemi(x.Stmts[len(x.Stmts)-1].LastTok())2072 }2073 x.RBrace = p.expect(token.RBRACE)2074 return x2075}2076func (p *parser) parseStmt() ast.Stmt {2077 if p.trace {2078 defer un(trace(p, "ast.Stmt"))2079 }2080 etok := p.peek(1)2081 switch p.tok {2082 case token.TEMPLATE:2083 return &ast.DeclStmt{Decl: p.parseTemplateDecl()}2084 case token.VAR, token.CONST, token.TIMER, token.PORT:2085 return &ast.DeclStmt{Decl: p.parseValueDecl()}2086 case token.REPEAT, token.BREAK, token.CONTINUE:2087 return &ast.BranchStmt{Tok: p.consume()}2088 case token.LABEL:2089 return &ast.BranchStmt{Tok: p.consume(), Label: p.make_use(p.expect(token.IDENT))}2090 case token.GOTO:2091 return &ast.BranchStmt{Tok: p.consume(), Label: p.make_use(p.expect(token.IDENT))}2092 case token.RETURN:2093 x := &ast.ReturnStmt{Tok: p.consume()}2094 if !stmtStart[p.tok] && p.tok != token.SEMICOLON && p.tok != token.RBRACE {2095 x.Result = p.parseExpr()2096 }2097 return x2098 case token.SELECT:2099 return p.parseSelect()2100 case token.ALT, token.INTERLEAVE:2101 return &ast.AltStmt{Tok: p.consume(), Body: p.parseBlockStmt()}2102 case token.LBRACK:2103 return p.parseAltGuard()2104 case token.FOR:2105 return p.parseForLoop()2106 case token.WHILE:2107 return p.parseWhileLoop()2108 case token.DO:2109 return p.parseDoWhileLoop()2110 case token.IF:2111 return p.parseIfStmt()2112 case token.LBRACE:2113 return p.parseBlockStmt()2114 case token.IDENT, token.TESTCASE, token.ANYKW, token.ALL, token.MAP, token.UNMAP, token.MTC:2115 x := p.parseSimpleStmt()2116 // try call-statement block2117 if p.tok == token.LBRACE {2118 c, ok := x.Expr.(*ast.CallExpr)2119 if !ok {2120 return x2121 }2122 s, ok := c.Fun.(*ast.SelectorExpr)2123 if !ok {2124 return x2125 }2126 id, ok := s.Sel.(*ast.Ident)2127 if !ok {2128 return x2129 }2130 if id.Tok.Lit != "call" {2131 return x2132 }2133 call := new(ast.CallStmt)2134 call.Stmt = x2135 call.Body = p.parseBlockStmt()2136 return call2137 }2138 return x2139 // Interpret simple literal expressions like integers or strings as statement.2140 // This exception was added to help implementing ast-evaluator code like this:2141 //2142 // if (1 > 2) { 10 } else { 20 }2143 //2144 case token.INT, token.FLOAT, token.STRING, token.BSTRING, token.TRUE, token.FALSE, token.PASS, token.FAIL, token.NONE, token.INCONC, token.ERROR:2145 return p.parseSimpleStmt()2146 default:2147 p.errorExpected(p.pos(1), "statement")2148 p.advance(stmtStart)2149 return &ast.ErrorNode{From: etok, To: p.peek(1)}2150 }2151}2152func (p *parser) parseForLoop() *ast.ForStmt {2153 x := new(ast.ForStmt)2154 x.Tok = p.consume()2155 x.LParen = p.expect(token.LPAREN)2156 if p.tok == token.VAR {2157 x.Init = &ast.DeclStmt{Decl: p.parseValueDecl()}2158 } else {2159 x.Init = &ast.ExprStmt{Expr: p.parseExpr()}2160 }2161 x.InitSemi = p.expect(token.SEMICOLON)2162 x.Cond = p.parseExpr()2163 x.CondSemi = p.expect(token.SEMICOLON)2164 x.Post = p.parseSimpleStmt()2165 x.LParen = p.expect(token.RPAREN)2166 x.Body = p.parseBlockStmt()2167 return x2168}2169func (p *parser) parseWhileLoop() *ast.WhileStmt {2170 return &ast.WhileStmt{2171 Tok: p.consume(),2172 Cond: p.parseParenExpr(),2173 Body: p.parseBlockStmt(),2174 }2175}2176func (p *parser) parseDoWhileLoop() *ast.DoWhileStmt {2177 return &ast.DoWhileStmt{2178 DoTok: p.consume(),2179 Body: p.parseBlockStmt(),2180 WhileTok: p.expect(token.WHILE),2181 Cond: p.parseParenExpr(),2182 }2183}2184func (p *parser) parseIfStmt() *ast.IfStmt {2185 x := &ast.IfStmt{2186 Tok: p.consume(),2187 Cond: p.parseParenExpr(),2188 Then: p.parseBlockStmt(),2189 }2190 if p.tok == token.ELSE {2191 x.ElseTok = p.consume()2192 if p.tok == token.IF {2193 x.Else = p.parseIfStmt()2194 } else {2195 x.Else = p.parseBlockStmt()2196 }2197 }2198 return x2199}2200func (p *parser) parseSelect() *ast.SelectStmt {2201 x := new(ast.SelectStmt)2202 x.Tok = p.expect(token.SELECT)2203 if p.tok == token.UNION {2204 x.Union = p.consume()2205 }2206 x.Tag = p.parseParenExpr()2207 x.LBrace = p.expect(token.LBRACE)2208 for p.tok == token.CASE {2209 x.Body = append(x.Body, p.parseCaseStmt())2210 }2211 x.RBrace = p.expect(token.RBRACE)2212 return x2213}2214func (p *parser) parseCaseStmt() *ast.CaseClause {2215 x := new(ast.CaseClause)2216 x.Tok = p.expect(token.CASE)2217 if p.tok == token.ELSE {2218 p.consume() // TODO(5nord) move token into AST2219 } else {2220 x.Case = p.parseParenExpr()2221 }2222 x.Body = p.parseBlockStmt()2223 return x2224}2225func (p *parser) parseAltGuard() *ast.CommClause {2226 x := new(ast.CommClause)2227 x.LBrack = p.expect(token.LBRACK)2228 if p.tok == token.ELSE {2229 x.Else = p.consume()2230 x.RBrack = p.expect(token.RBRACK)2231 x.Body = p.parseBlockStmt()2232 return x2233 }2234 if p.tok != token.RBRACK {2235 x.X = p.parseExpr()2236 }2237 x.RBrack = p.expect(token.RBRACK)2238 x.Comm = p.parseSimpleStmt()2239 if p.tok == token.LBRACE {2240 x.Body = p.parseBlockStmt()2241 }2242 return x2243}...

Full Screen

Full Screen

parse.go

Source:parse.go Github

copy

Full Screen

...159 p.curFnName = fnName160 fn := ast.NewFnNode((sc&static) != 0, fnName, ty)161 p.spawnScope()162 p.readFnParams(fn)163 if p.consume(";") {164 p.rewindScope()165 p.curScope.addGVar((sc&static) != 0, fnName, types.NewFn(ty, false), nil)166 return nil167 }168 p.expect("{")169 for !p.consume("}") {170 fn.Body = append(fn.Body, p.stmt())171 }172 p.setFnLVars(fn)173 p.rewindScope()174 p.curScope.addGVar((sc&static) != 0, fnName, types.NewFn(ty, true), nil)175 // TODO: align176 fn.StackSize = p.curScope.curOffset177 return fn178}179type storageClass int180const (181 static storageClass = 0b01182 extern storageClass = 0b10183)184func (p *Parser) decl() (t types.Type, id string, rhs ast.Node, sc storageClass) {185 t, isTypeDef, sc := p.baseType()186 if p.consume(";") {187 return188 }189 id, t = p.tyDecl(t)190 if isTypeDef {191 p.expect(";")192 p.curScope.addTypeDef(id, t)193 // returned t is nil when it is types.Typepedef (no need to add to scope.vars)194 return nil, "", nil, sc195 }196 t = p.tySuffix(t)197 if p.consume(";") {198 return199 }200 if (sc & extern) != 0 {201 p.expect(";")202 return203 }204 p.expect("=")205 rhs = p.initializer(t, sc)206 p.expect(";")207 return208}209func (p *Parser) initializer(t types.Type, sc storageClass) ast.Node {210 switch t := t.(type) {211 case *types.Arr:212 var nodes []ast.Node213 if strTok, ok := p.consumeStr(); ok {214 init := vars.NewGVarInitStr(strTok.Str())215 s := vars.NewGVar((sc&static) != 0, newGVarLabel(), types.NewArr(types.NewChar(), strTok.Len()), init)216 p.Ast.GVars = append(p.Ast.GVars, s)217 return ast.NewVarNode(s)218 }219 p.expect("{")220 for !p.consume("}") {221 nodes = append(nodes, p.initializer(t.Of, sc))222 if !p.consume(",") {223 p.expect("}")224 break225 }226 }227 return ast.NewBlkNode(nodes)228 case *types.Struct:229 nodes := make([]ast.Node, len(t.Members))230 if strTok, ok := p.consumeStr(); ok {231 init := vars.NewGVarInitStr(strTok.Str())232 s := vars.NewGVar((sc&static) != 0, newGVarLabel(), types.NewArr(types.NewChar(), strTok.Len()), init)233 p.Ast.GVars = append(p.Ast.GVars, s)234 return ast.NewVarNode(s)235 }236 p.expect("{")237 idx := 0238 for !p.consume("}") {239 if p.consume(".") {240 id := p.expectID().Str()241 p.expect("=")242 for i, mem := range t.Members[idx:] {243 if id == mem.Name {244 idx += i245 break246 }247 }248 }249 nodes[idx] = p.initializer(t.Members[idx].Type, sc)250 if !p.consume(",") {251 p.expect("}")252 break253 }254 idx++255 }256 return ast.NewBlkNode(nodes)257 default:258 return p.assign()259 }260}261func (p *Parser) baseType() (t types.Type, isTypeDef bool, sc storageClass) {262 if p.consume("typedef") {263 isTypeDef = true264 }265 if p.consume("static") {266 sc |= static267 }268 if p.consume("extern") {269 sc |= extern270 }271 if isTypeDef && (sc != 0) || (sc == 0b11) {272 log.Fatal("typedef, static and extern should not be used together.")273 }274 switch tok := p.Toks[0].(type) {275 case *tokenizer.IDTok:276 if typeDef, ok := p.searchVar(tok.Str()).(*vars.TypeDef); ok {277 p.popToks()278 return typeDef.Type(), isTypeDef, sc279 }280 case *tokenizer.ReservedTok:281 if p.beginsWith("struct") {282 return p.structDecl(), isTypeDef, sc283 }284 if p.beginsWith("enum") {285 return p.enumDecl(), isTypeDef, sc286 }287 if p.consume("void") {288 return types.NewVoid(), isTypeDef, sc289 }290 if p.consume("_Bool") {291 return types.NewBool(), isTypeDef, sc292 }293 // just skip `volatile` keyword since there is no optimisation yet.294 p.consume("volatile")295 // TODO: handle unsigned properly296 p.consume("unsigned")297 p.consume("signed")298 if p.consume("char") {299 return types.NewChar(), isTypeDef, sc300 }301 if p.consume("short") {302 p.consume("int")303 return types.NewShort(), isTypeDef, sc304 }305 if p.consume("int") {306 return types.NewInt(), isTypeDef, sc307 }308 if p.consume("long") {309 p.consume("long")310 p.consume("int")311 return types.NewLong(), isTypeDef, sc312 }313 return types.NewInt(), isTypeDef, sc314 }315 log.Fatalf("Type expected but got %T: %s", p.Toks[0], p.Toks[0].Str())316 return317}318func (p *Parser) tyDecl(baseTy types.Type) (id string, ty types.Type) {319 for p.consume("*") {320 baseTy = types.NewPtr(baseTy)321 }322 if p.consume("(") {323 id, ty = p.tyDecl(nil)324 p.expect(")")325 baseTy = p.tySuffix(baseTy)326 switch ty := ty.(type) {327 case *types.Arr:328 ty.Of = baseTy329 case *types.Ptr:330 ty.To = baseTy331 default:332 ty = baseTy333 }334 return335 }336 return p.expectID().Str(), p.tySuffix(baseTy)337}338func (p *Parser) tySuffix(t types.Type) types.Type {339 if !p.consume("[") {340 return t341 }342 l := -1343 if !p.consume("]") {344 l = int(p.constExpr())345 p.expect("]")346 }347 t = p.tySuffix(t)348 return types.NewArr(t, l)349}350func (p *Parser) constExpr() int64 {351 return ast.Eval(p.ternary())352}353func (p *Parser) readFnParams(fn *ast.FnNode) {354 p.expect("(")355 isFirstArg := true356 orig := p.Toks357 if p.consume("void") && p.consume(")") {358 return359 }360 p.Toks = orig361 for !p.consume(")") {362 if !isFirstArg {363 p.expect(",")364 }365 isFirstArg = false366 ty, _, _ := p.baseType()367 id, ty := p.tyDecl(ty)368 if arr, ok := ty.(*types.Arr); ok {369 ty = types.NewPtr(arr.Of)370 }371 lv := p.curScope.addLVar(id, ty)372 fn.Params = append(fn.Params, lv)373 }374}375func (p *Parser) setFnLVars(fn *ast.FnNode) {376 offset := 0377 for _, sv := range p.curScope.vars {378 switch v := sv.(type) {379 case *vars.LVar:380 offset = types.AlignTo(offset, v.Type().Alignment())381 offset += v.Type().Size()382 v.Offset = offset383 fn.LVars = append(fn.LVars, v)384 }385 }386}387func (p *Parser) structDecl() types.Type {388 p.expect("struct")389 tag, tagExists := p.consumeID()390 if tagExists && !p.beginsWith("{") {391 if tag := p.searchStructTag(tag.Str()); tag != nil {392 return tag.ty393 }394 log.Fatalf("No such struct tag %s", tag.Str())395 }396 p.expect("{")397 var members []*types.Member398 offset, align := 0, 0399 for !p.consume("}") {400 // TODO: handle when rhs is not null401 ty, tag, _, _ := p.decl()402 offset = types.AlignTo(offset, ty.Alignment())403 members = append(members, types.NewMember(tag, offset, ty))404 offset += ty.Size()405 if align < ty.Size() {406 align = ty.Size()407 }408 }409 ty := types.NewStruct(align, members, types.AlignTo(offset, align))410 if tagExists {411 p.curScope.addStructTag(newStructTag(tag.Str(), ty))412 }413 return ty414}415func (p *Parser) enumDecl() types.Type {416 p.expect("enum")417 tag, tagExists := p.consumeID()418 if tagExists && !p.beginsWith("{") {419 if tag := p.searchEnumTag(tag.Str()); tag != nil {420 return tag.ty421 }422 log.Fatalf("No such enum tag %s", tag.Str())423 }424 t := types.NewEnum()425 p.expect("{")426 c := 0427 for {428 id := p.expectID()429 if p.consume("=") {430 c = int(p.constExpr())431 }432 p.curScope.addEnum(id.Str(), t, c)433 c++434 orig := p.Toks435 if p.consume("}") || p.consume(",") && p.consume("}") {436 break437 }438 p.Toks = orig439 p.expect(",")440 }441 if tagExists {442 p.curScope.addEnumTag(newEnumTag(tag.Str(), t))443 }444 return t445}446func (p *Parser) stmt() ast.Node {447 // handle block448 if p.consume("{") {449 var blkStmts []ast.Node450 p.spawnScope()451 for !p.consume("}") {452 blkStmts = append(blkStmts, p.stmt())453 }454 p.rewindScope()455 return ast.NewBlkNode(blkStmts)456 }457 // handle return458 if p.consume("return") {459 if p.consume(";") {460 return ast.NewRetNode(nil, p.curFnName)461 }462 node := ast.NewRetNode(p.expr(), p.curFnName)463 p.expect(";")464 return node465 }466 // handle break467 if p.consume("break") {468 p.expect(";")469 return ast.NewBreakNode()470 }471 // handle continue472 if p.consume("continue") {473 p.expect(";")474 return ast.NewContinueNode()475 }476 // handle if statement477 if p.consume("if") {478 p.expect("(")479 cond := p.expr()480 p.expect(")")481 then := p.stmt()482 var els ast.Node483 if p.consume("else") {484 els = p.stmt()485 }486 return ast.NewIfNode(cond, then, els)487 }488 // handle while statement489 if p.consume("while") {490 p.expect("(")491 cond := p.expr()492 p.expect(")")493 then := p.stmt()494 return ast.NewWhileNode(cond, then)495 }496 // handle do-while statement497 if p.consume("do") {498 then := p.stmt()499 p.expect("while")500 p.expect("(")501 cond := p.expr()502 p.expect(")")503 p.expect(";")504 return ast.NewDoWhileNode(cond, then)505 }506 // handle for statement507 if p.consume("for") {508 p.expect("(")509 var init, cond, inc, then ast.Node510 p.spawnScope()511 if !p.consume(";") {512 if p.isType() {513 t, id, rhs, _ := p.decl()514 p.curScope.addLVar(id, t)515 if rhs == nil {516 init = ast.NewNullNode()517 } else {518 a := ast.NewAssignNode(ast.NewVarNode(p.findVar(id)), rhs)519 init = ast.NewExprNode(a)520 }521 } else {522 init = ast.NewExprNode(p.expr())523 p.expect(";")524 }525 }526 if !p.consume(";") {527 cond = p.expr()528 p.expect(";")529 }530 if !p.consume(")") {531 inc = ast.NewExprNode(p.expr())532 p.expect(")")533 }534 then = p.stmt()535 p.rewindScope()536 return ast.NewForNode(init, cond, inc, then)537 }538 // handle switch statement539 if p.consume("switch") {540 p.expect("(")541 e := p.expr()542 p.expect(")")543 p.expect("{")544 var cases []*ast.CaseNode545 var dflt *ast.CaseNode546 for idx := 0; ; idx++ {547 if node, isDefault := p.switchCase(idx); node == nil {548 break549 } else {550 cases = append(cases, node)551 if isDefault {552 if dflt != nil {553 log.Fatal("Multiple definition of default clause.")554 }555 dflt = node556 }557 }558 }559 p.expect("}")560 return ast.NewSwitchNode(e, cases, dflt)561 }562 // handle variable definition563 if p.isType() {564 t, id, rhs, sc := p.decl()565 if id == "" {566 return ast.NewNullNode()567 }568 if (sc & static) != 0 {569 init := buildGVarInit(t, rhs)570 p.curScope.addGVar(true, id, t, init)571 return ast.NewNullNode()572 }573 p.curScope.addLVar(id, t)574 if rhs == nil {575 return ast.NewNullNode()576 }577 return storeInit(t, ast.NewVarNode(p.findVar(id)), rhs)578 }579 node := p.expr()580 p.expect(";")581 return ast.NewExprNode(node)582}583func storeInit(t types.Type, dst ast.AddressableNode, rhs ast.Node) ast.Node {584 switch t := t.(type) {585 case *types.Arr:586 // TODO: clean up587 var body []ast.Node588 var ln, idx int589 _, isChar := t.Base().(*types.Char)590 isString, str := isStrNode(rhs)591 // string literal592 if isChar && isString {593 for i, r := range str {594 idx++595 addr := ast.NewDerefNode(ast.NewAddNode(dst, ast.NewNumNode(int64(i))))596 body = append(body, ast.NewExprNode(ast.NewAssignNode(addr, ast.NewNumNode(int64(r)))))597 }598 ln = len(str)599 } else {600 blkBody := rhs.(*ast.BlkNode).Body601 for i, mem := range blkBody {602 idx++603 addr := ast.NewDerefNode(ast.NewAddNode(dst, ast.NewNumNode(int64(i))))604 body = append(body, storeInit(t.Base(), addr, mem))605 }606 ln = len(blkBody)607 }608 if t.Len < 0 {609 t.Len = ln610 }611 if t, ok := t.Base().(*types.Arr); !ok {612 // zero out on initialization613 for i := idx; i < ln; i++ {614 addr := ast.NewDerefNode(ast.NewAddNode(dst, ast.NewNumNode(int64(i))))615 body = append(body, zeroOut(t.Base(), addr))616 }617 }618 return ast.NewBlkNode(body)619 case *types.Struct:620 var body []ast.Node621 idx := 0622 for i, mem := range rhs.(*ast.BlkNode).Body {623 idx++624 member := t.Members[i]625 node := ast.NewMemberNode(dst, member)626 if mem == nil {627 body = append(body, zeroOut(member.Type, node))628 } else {629 body = append(body, ast.NewExprNode(ast.NewAssignNode(node, mem)))630 }631 }632 return ast.NewBlkNode(body)633 default:634 return ast.NewExprNode(ast.NewAssignNode(dst, rhs))635 }636}637func zeroOut(t types.Type, dst ast.AddressableNode) ast.Node {638 switch t := t.(type) {639 case *types.Arr:640 var body []ast.Node641 for i := 0; i < t.Len; i++ {642 addr := ast.NewAddNode(dst, ast.NewNumNode(int64(i)))643 body = append(body, zeroOut(t.Base(), ast.NewDerefNode(addr)))644 }645 return ast.NewBlkNode(body)646 case *types.Struct:647 var body []ast.Node648 for _, mem := range t.Members {649 addr := ast.NewAddNode(dst, ast.NewNumNode(int64(mem.Offset)))650 body = append(body, zeroOut(mem.Type, ast.NewDerefNode(addr)))651 }652 return ast.NewBlkNode(body)653 default:654 return ast.NewExprNode(ast.NewAssignNode(dst, ast.NewNumNode(0)))655 }656}657func isStrNode(n ast.Node) (bool, string) {658 if v, ok := n.(*ast.VarNode); !ok {659 return false, ""660 } else if g, ok := v.Var.(*vars.GVar); !ok {661 return false, ""662 } else if t, ok := g.Type().(*types.Arr); !ok {663 return false, ""664 } else if _, ok := t.Base().(*types.Char); !ok {665 return false, ""666 } else {667 return true, g.Init.(*vars.GVarInitStr).Content668 }669}670func (p *Parser) switchCase(idx int) (node *ast.CaseNode, isDefault bool) {671 if p.consume("case") {672 n := p.constExpr()673 p.expect(":")674 var body []ast.Node675 for !p.beginsWith("case") && !p.beginsWith("default") && !p.beginsWith("}") {676 body = append(body, p.stmt())677 }678 node = ast.NewCaseNode(int(n), body, idx)679 } else if p.consume("default") {680 isDefault = true681 p.expect(":")682 var body []ast.Node683 for !p.beginsWith("case") && !p.beginsWith("default") && !p.beginsWith("}") {684 body = append(body, p.stmt())685 }686 node = ast.NewCaseNode(-1, body, idx)687 }688 return689}690func (p *Parser) expr() ast.Node {691 return p.assign()692}693func (p *Parser) assign() ast.Node {694 node := p.ternary()695 if p.consume("=") {696 node = ast.NewAssignNode(node.(ast.AddressableNode), p.assign())697 } else if p.consume("+=") {698 if _, ok := node.LoadType().(types.Pointing); ok {699 node = ast.NewBinaryNode(ast.NdPtrAddEq, node.(ast.AddressableNode), p.assign())700 } else {701 node = ast.NewBinaryNode(ast.NdAddEq, node.(ast.AddressableNode), p.assign())702 }703 } else if p.consume("-=") {704 if _, ok := node.LoadType().(types.Pointing); ok {705 node = ast.NewBinaryNode(ast.NdPtrSubEq, node.(ast.AddressableNode), p.assign())706 } else {707 node = ast.NewBinaryNode(ast.NdSubEq, node.(ast.AddressableNode), p.assign())708 }709 } else if p.consume("*=") {710 node = ast.NewBinaryNode(ast.NdMulEq, node.(ast.AddressableNode), p.assign())711 } else if p.consume("/=") {712 node = ast.NewBinaryNode(ast.NdDivEq, node.(ast.AddressableNode), p.assign())713 }714 return node715}716func (p *Parser) ternary() ast.Node {717 node := p.logOr()718 if !p.consume("?") {719 return node720 }721 l := p.expr()722 p.expect(":")723 r := p.ternary()724 return ast.NewTernaryNode(node, l, r)725}726func (p *Parser) logOr() ast.Node {727 node := p.logAnd()728 for p.consume("||") {729 node = ast.NewBinaryNode(ast.NdLogOr, node, p.logAnd())730 }731 return node732}733func (p *Parser) logAnd() ast.Node {734 node := p.bitOr()735 for p.consume("&&") {736 node = ast.NewBinaryNode(ast.NdLogAnd, node, p.bitOr())737 }738 return node739}740func (p *Parser) bitOr() ast.Node {741 node := p.bitXor()742 for p.consume("|") {743 node = ast.NewBinaryNode(ast.NdBitOr, node, p.bitXor())744 }745 return node746}747func (p *Parser) bitXor() ast.Node {748 node := p.bitAnd()749 for p.consume("^") {750 node = ast.NewBinaryNode(ast.NdBitXor, node, p.bitXor())751 }752 return node753}754func (p *Parser) bitAnd() ast.Node {755 node := p.equality()756 for p.consume("&") {757 node = ast.NewBinaryNode(ast.NdBitAnd, node, p.equality())758 }759 return node760}761func (p *Parser) equality() ast.Node {762 node := p.relational()763 for {764 if p.consume("==") {765 node = ast.NewBinaryNode(ast.NdEq, node, p.relational())766 } else if p.consume("!=") {767 node = ast.NewBinaryNode(ast.NdNeq, node, p.relational())768 } else {769 return node770 }771 }772}773func (p *Parser) relational() ast.Node {774 node := p.shift()775 for {776 if p.consume("<=") {777 node = ast.NewBinaryNode(ast.NdLeq, node, p.shift())778 } else if p.consume(">=") {779 node = ast.NewBinaryNode(ast.NdGeq, node, p.shift())780 } else if p.consume("<") {781 node = ast.NewBinaryNode(ast.NdLt, node, p.shift())782 } else if p.consume(">") {783 node = ast.NewBinaryNode(ast.NdGt, node, p.shift())784 } else {785 return node786 }787 }788}789func (p *Parser) shift() ast.Node {790 node := p.addSub()791 for {792 if p.consume("<<") {793 node = ast.NewBinaryNode(ast.NdShl, node, p.shift())794 } else if p.consume(">>") {795 node = ast.NewBinaryNode(ast.NdShr, node, p.shift())796 } else if p.consume("<<=") {797 node = ast.NewBinaryNode(ast.NdShlEq, node, p.shift())798 } else if p.consume(">>=") {799 node = ast.NewBinaryNode(ast.NdShrEq, node, p.shift())800 } else {801 return node802 }803 }804}805func (p *Parser) addSub() ast.Node {806 node := p.mulDiv()807 for {808 if p.consume("+") {809 node = ast.NewAddNode(node, p.mulDiv())810 } else if p.consume("-") {811 node = ast.NewSubNode(node, p.mulDiv())812 } else {813 return node814 }815 }816}817func (p *Parser) mulDiv() ast.Node {818 node := p.cast()819 for {820 if p.consume("*") {821 node = ast.NewBinaryNode(ast.NdMul, node, p.cast())822 } else if p.consume("/") {823 node = ast.NewBinaryNode(ast.NdDiv, node, p.cast())824 } else {825 return node826 }827 }828}829func (p *Parser) cast() ast.Node {830 orig := p.Toks831 if p.consume("(") {832 if p.isType() {833 t, _, _ := p.baseType()834 for p.consume("*") {835 t = types.NewPtr(t)836 }837 p.expect(")")838 return ast.NewCastNode(p.cast(), t)839 }840 p.Toks = orig841 }842 return p.unary()843}844func (p *Parser) unary() ast.Node {845 if p.consume("+") {846 return p.cast()847 }848 if p.consume("-") {849 return ast.NewSubNode(ast.NewNumNode(0), p.cast())850 }851 if p.consume("*") {852 return ast.NewDerefNode(p.cast())853 }854 if p.consume("&") {855 return ast.NewAddrNode(p.cast().(ast.AddressableNode))856 }857 if p.consume("!") {858 return ast.NewNotNode(p.cast())859 }860 if p.consume("~") {861 return ast.NewBitNotNode(p.cast())862 }863 if p.consume("++") {864 return ast.NewIncNode(p.unary().(ast.AddressableNode), true)865 }866 if p.consume("--") {867 return ast.NewDecNode(p.unary().(ast.AddressableNode), true)868 }869 return p.postfix()870}871func (p *Parser) postfix() ast.Node {872 node := p.primary()873 for {874 if p.consume("[") {875 add := ast.NewAddNode(node, p.expr())876 node = ast.NewDerefNode(add)877 p.expect("]")878 continue879 }880 if p.consume(".") {881 if s, ok := node.LoadType().(*types.Struct); ok {882 mem := s.FindMember(p.expectID().Str())883 node = ast.NewMemberNode(node.(ast.AddressableNode), mem)884 continue885 }886 log.Fatalf("Expected struct but got %T", node.LoadType())887 }888 if p.consume("->") {889 if t, ok := node.LoadType().(*types.Ptr); ok {890 mem := t.Base().(*types.Struct).FindMember(p.expectID().Str())891 node = ast.NewMemberNode(ast.NewDerefNode(node.(ast.AddressableNode)), mem)892 continue893 }894 log.Fatalf("Expected pointer but got %T", node.LoadType())895 }896 if p.consume("++") {897 node = ast.NewIncNode(node.(ast.AddressableNode), false)898 continue899 }900 if p.consume("--") {901 node = ast.NewDecNode(node.(ast.AddressableNode), false)902 continue903 }904 return node905 }906}907func (p *Parser) stmtExpr() ast.Node {908 // "(" and "{" is already read.909 p.spawnScope()910 body := make([]ast.Node, 0)911 body = append(body, p.stmt())912 for !p.consume("}") {913 body = append(body, p.stmt())914 }915 p.expect(")")916 if ex, ok := body[len(body)-1].(*ast.ExprNode); !ok {917 log.Fatal("Statement expression returning void is not supported")918 } else {919 body[len(body)-1] = ex.Body920 }921 p.rewindScope()922 return ast.NewStmtExprNode(body)923}924func (p *Parser) primary() ast.Node {925 if p.consume("(") {926 if p.consume("{") {927 return p.stmtExpr()928 }929 node := p.expr()930 p.expect(")")931 return node932 }933 if p.consume("sizeof") {934 orig := p.Toks935 if p.consume("(") {936 if p.isType() {937 base, _, _ := p.baseType()938 n := base.Size()939 p.expect(")")940 return ast.NewNumNode(int64(n))941 }942 p.Toks = orig943 }944 return ast.NewNumNode(int64(p.unary().LoadType().Size()))945 }946 if id, isID := p.consumeID(); isID {947 id := id.Str()948 if p.consume("(") {949 var t types.Type950 if fn, ok := p.searchVar(id).(*vars.GVar); ok {951 t = fn.Type().(*types.Fn).RetTy952 } else {953 t = types.NewInt()954 }955 var params []ast.Node956 if p.consume(")") {957 return ast.NewFnCallNode(id, params, t)958 }959 params = append(params, p.expr())960 for p.consume(",") {961 params = append(params, p.expr())962 }963 p.expect(")")964 return ast.NewFnCallNode(id, params, t)965 }966 switch v := p.findVar(id).(type) {967 case *vars.Enum:968 return ast.NewNumNode(int64(v.Val))969 case *vars.LVar, *vars.GVar:970 return ast.NewVarNode(v)971 default:972 log.Fatalf("Unhandled case of vars.Var in primary: %T", p.findVar(id))973 }974 }975 if strTok, isStr := p.consumeStr(); isStr {976 init := vars.NewGVarInitStr(strTok.Str())977 s := vars.NewGVar(true, newGVarLabel(), types.NewArr(types.NewChar(), strTok.Len()), init)978 p.Ast.GVars = append(p.Ast.GVars, s)979 return ast.NewVarNode(s)980 }981 return ast.NewNumNode(int64(p.expectNum().Val))982}...

Full Screen

Full Screen

consume

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 f, err := parser.ParseFile(fset, "2.go", nil, parser.ParseComments)4 if err != nil {5 fmt.Println(err)6 }7 ast.Print(fset, f)8}

Full Screen

Full Screen

consume

Using AI Code Generation

copy

Full Screen

1import (2type ast struct{3}4func newast(renderer *sdl.Renderer, x int32, y int32, w int32, h int32) *ast{5 texture, err := img.LoadTexture(renderer, "images/ast1.png")6 if err != nil{7 panic(err)8 }9 return &ast{10 }11}12func (a *ast) consume(renderer *sdl.Renderer, x int32, y int32, w int32, h int32){13 texture, err := img.LoadTexture(renderer, "images/ast1.png")14 if err != nil{15 panic(err)16 }17}18func (a *ast) destroy(){19 a.texture.Destroy()20}21func (a *ast) draw(renderer *sdl.Renderer){22 renderer.Copy(a.texture, nil, &sdl.Rect{X: a.x, Y: a.y, W: a.w, H: a.h})23}24func (a *ast) update(){25}26func (a *ast) hit(b *bullet) bool{27 if a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.h + a.y > b.y{28 }29}30func (a *ast) hit2(b *bullet) bool{

Full Screen

Full Screen

consume

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 import "fmt"4 func main() {5 fmt.Println("Hello, 世界")6 }`7 f, err := parser.ParseFile(fset, "hello.go", src, 0)8 if err != nil {9 log.Fatal(err)10 }11 ast.Print(fset, f)12}13import (14func main() {15 import "fmt"16 func main() {17 fmt.Println("Hello, 世界")18 }`19 f, err := parser.ParseFile(fset, "hello.go", src, 0)20 if err != nil {21 log.Fatal(err)22 }23 ast.Print(fset, f)24}25import (26func main() {

Full Screen

Full Screen

consume

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 g := graph.New(4)4 g.Set(0, 1, 1)5 g.Set(1, 2, 1)6 g.Set(2, 3, 1)7 g.Set(3, 0, 1)8 g.Set(0, 2, 1)9 g.Set(1, 3, 1)10 fmt.Println(g.String())11}12import (13func main() {14 g := graph.New(4)15 g.Set(0, 1, 1)16 g.Set(1, 2, 1)17 g.Set(2, 3, 1)18 g.Set(3, 0, 1)19 g.Set(0, 2, 1)20 g.Set(1, 3, 1)21 fmt.Println(g.DOT())22}23digraph {24}

Full Screen

Full Screen

consume

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 fmt.Println("Hello World!")4 a := ast.NewAst()5 a.Consume()6}7import (8type Ast struct {9}10func NewAst() *Ast {11 return &Ast{}12}13func (a *Ast) Consume() {14 fmt.Println("Consume method called")15}

Full Screen

Full Screen

consume

Using AI Code Generation

copy

Full Screen

1import (2type ast struct {3}4func (a *ast) ExitEveryRule(ctx antlr.ParserRuleContext) {5 fmt.Println(ctx.GetText())6}7func main() {8 is := antlr.NewInputStream("2+2")9 lexer := parser.NewCalcLexer(is)10 stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)11 p := parser.NewCalcParser(stream)12 antlr.ParseTreeWalkerDefault.Walk(&ast{}, p.Start())13}

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful