How to use Parser class

Best Cucumber Common Library code snippet using Parser

scannerc.go

Source:scannerc.go Github

copy

Full Screen

...16// The Scanner transforms the input stream into a sequence of tokens, while the17// parser transform the sequence of tokens produced by the Scanner into a18// sequence of parsing events.19//20// The Scanner is rather clever and complicated. The Parser, on the contrary,21// is a straightforward implementation of a recursive-descendant parser (or,22// LL(1) parser, as it is usually called).23//24// Actually there are two issues of Scanning that might be called "clever", the25// rest is quite straightforward. The issues are "block collection start" and26// "simple keys". Both issues are explained below in details.27//28// Here the Scanning step is explained and implemented. We start with the list29// of all the tokens produced by the Scanner together with short descriptions.30//31// Now, tokens:32//33// STREAM-START(encoding) # The stream start.34// STREAM-END # The stream end.35// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.36// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.37// DOCUMENT-START # '---'38// DOCUMENT-END # '...'39// BLOCK-SEQUENCE-START # Indentation increase denoting a block40// BLOCK-MAPPING-START # sequence or a block mapping.41// BLOCK-END # Indentation decrease.42// FLOW-SEQUENCE-START # '['43// FLOW-SEQUENCE-END # ']'44// BLOCK-SEQUENCE-START # '{'45// BLOCK-SEQUENCE-END # '}'46// BLOCK-ENTRY # '-'47// FLOW-ENTRY # ','48// KEY # '?' or nothing (simple keys).49// VALUE # ':'50// ALIAS(anchor) # '*anchor'51// ANCHOR(anchor) # '&anchor'52// TAG(handle,suffix) # '!handle!suffix'53// SCALAR(value,style) # A scalar.54//55// The following two tokens are "virtual" tokens denoting the beginning and the56// end of the stream:57//58// STREAM-START(encoding)59// STREAM-END60//61// We pass the information about the input stream encoding with the62// STREAM-START token.63//64// The next two tokens are responsible for tags:65//66// VERSION-DIRECTIVE(major,minor)67// TAG-DIRECTIVE(handle,prefix)68//69// Example:70//71// %YAML 1.172// %TAG ! !foo73// %TAG !yaml! tag:yaml.org,2002:74// ---75//76// The correspoding sequence of tokens:77//78// STREAM-START(utf-8)79// VERSION-DIRECTIVE(1,1)80// TAG-DIRECTIVE("!","!foo")81// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")82// DOCUMENT-START83// STREAM-END84//85// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole86// line.87//88// The document start and end indicators are represented by:89//90// DOCUMENT-START91// DOCUMENT-END92//93// Note that if a YAML stream contains an implicit document (without '---'94// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be95// produced.96//97// In the following examples, we present whole documents together with the98// produced tokens.99//100// 1. An implicit document:101//102// 'a scalar'103//104// Tokens:105//106// STREAM-START(utf-8)107// SCALAR("a scalar",single-quoted)108// STREAM-END109//110// 2. An explicit document:111//112// ---113// 'a scalar'114// ...115//116// Tokens:117//118// STREAM-START(utf-8)119// DOCUMENT-START120// SCALAR("a scalar",single-quoted)121// DOCUMENT-END122// STREAM-END123//124// 3. Several documents in a stream:125//126// 'a scalar'127// ---128// 'another scalar'129// ---130// 'yet another scalar'131//132// Tokens:133//134// STREAM-START(utf-8)135// SCALAR("a scalar",single-quoted)136// DOCUMENT-START137// SCALAR("another scalar",single-quoted)138// DOCUMENT-START139// SCALAR("yet another scalar",single-quoted)140// STREAM-END141//142// We have already introduced the SCALAR token above. The following tokens are143// used to describe aliases, anchors, tag, and scalars:144//145// ALIAS(anchor)146// ANCHOR(anchor)147// TAG(handle,suffix)148// SCALAR(value,style)149//150// The following series of examples illustrate the usage of these tokens:151//152// 1. A recursive sequence:153//154// &A [ *A ]155//156// Tokens:157//158// STREAM-START(utf-8)159// ANCHOR("A")160// FLOW-SEQUENCE-START161// ALIAS("A")162// FLOW-SEQUENCE-END163// STREAM-END164//165// 2. A tagged scalar:166//167// !!float "3.14" # A good approximation.168//169// Tokens:170//171// STREAM-START(utf-8)172// TAG("!!","float")173// SCALAR("3.14",double-quoted)174// STREAM-END175//176// 3. Various scalar styles:177//178// --- # Implicit empty plain scalars do not produce tokens.179// --- a plain scalar180// --- 'a single-quoted scalar'181// --- "a double-quoted scalar"182// --- |-183// a literal scalar184// --- >-185// a folded186// scalar187//188// Tokens:189//190// STREAM-START(utf-8)191// DOCUMENT-START192// DOCUMENT-START193// SCALAR("a plain scalar",plain)194// DOCUMENT-START195// SCALAR("a single-quoted scalar",single-quoted)196// DOCUMENT-START197// SCALAR("a double-quoted scalar",double-quoted)198// DOCUMENT-START199// SCALAR("a literal scalar",literal)200// DOCUMENT-START201// SCALAR("a folded scalar",folded)202// STREAM-END203//204// Now it's time to review collection-related tokens. We will start with205// flow collections:206//207// FLOW-SEQUENCE-START208// FLOW-SEQUENCE-END209// FLOW-MAPPING-START210// FLOW-MAPPING-END211// FLOW-ENTRY212// KEY213// VALUE214//215// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and216// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'217// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the218// indicators '?' and ':', which are used for denoting mapping keys and values,219// are represented by the KEY and VALUE tokens.220//221// The following examples show flow collections:222//223// 1. A flow sequence:224//225// [item 1, item 2, item 3]226//227// Tokens:228//229// STREAM-START(utf-8)230// FLOW-SEQUENCE-START231// SCALAR("item 1",plain)232// FLOW-ENTRY233// SCALAR("item 2",plain)234// FLOW-ENTRY235// SCALAR("item 3",plain)236// FLOW-SEQUENCE-END237// STREAM-END238//239// 2. A flow mapping:240//241// {242// a simple key: a value, # Note that the KEY token is produced.243// ? a complex key: another value,244// }245//246// Tokens:247//248// STREAM-START(utf-8)249// FLOW-MAPPING-START250// KEY251// SCALAR("a simple key",plain)252// VALUE253// SCALAR("a value",plain)254// FLOW-ENTRY255// KEY256// SCALAR("a complex key",plain)257// VALUE258// SCALAR("another value",plain)259// FLOW-ENTRY260// FLOW-MAPPING-END261// STREAM-END262//263// A simple key is a key which is not denoted by the '?' indicator. Note that264// the Scanner still produce the KEY token whenever it encounters a simple key.265//266// For scanning block collections, the following tokens are used (note that we267// repeat KEY and VALUE here):268//269// BLOCK-SEQUENCE-START270// BLOCK-MAPPING-START271// BLOCK-END272// BLOCK-ENTRY273// KEY274// VALUE275//276// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation277// increase that precedes a block collection (cf. the INDENT token in Python).278// The token BLOCK-END denote indentation decrease that ends a block collection279// (cf. the DEDENT token in Python). However YAML has some syntax pecularities280// that makes detections of these tokens more complex.281//282// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators283// '-', '?', and ':' correspondingly.284//285// The following examples show how the tokens BLOCK-SEQUENCE-START,286// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:287//288// 1. Block sequences:289//290// - item 1291// - item 2292// -293// - item 3.1294// - item 3.2295// -296// key 1: value 1297// key 2: value 2298//299// Tokens:300//301// STREAM-START(utf-8)302// BLOCK-SEQUENCE-START303// BLOCK-ENTRY304// SCALAR("item 1",plain)305// BLOCK-ENTRY306// SCALAR("item 2",plain)307// BLOCK-ENTRY308// BLOCK-SEQUENCE-START309// BLOCK-ENTRY310// SCALAR("item 3.1",plain)311// BLOCK-ENTRY312// SCALAR("item 3.2",plain)313// BLOCK-END314// BLOCK-ENTRY315// BLOCK-MAPPING-START316// KEY317// SCALAR("key 1",plain)318// VALUE319// SCALAR("value 1",plain)320// KEY321// SCALAR("key 2",plain)322// VALUE323// SCALAR("value 2",plain)324// BLOCK-END325// BLOCK-END326// STREAM-END327//328// 2. Block mappings:329//330// a simple key: a value # The KEY token is produced here.331// ? a complex key332// : another value333// a mapping:334// key 1: value 1335// key 2: value 2336// a sequence:337// - item 1338// - item 2339//340// Tokens:341//342// STREAM-START(utf-8)343// BLOCK-MAPPING-START344// KEY345// SCALAR("a simple key",plain)346// VALUE347// SCALAR("a value",plain)348// KEY349// SCALAR("a complex key",plain)350// VALUE351// SCALAR("another value",plain)352// KEY353// SCALAR("a mapping",plain)354// BLOCK-MAPPING-START355// KEY356// SCALAR("key 1",plain)357// VALUE358// SCALAR("value 1",plain)359// KEY360// SCALAR("key 2",plain)361// VALUE362// SCALAR("value 2",plain)363// BLOCK-END364// KEY365// SCALAR("a sequence",plain)366// VALUE367// BLOCK-SEQUENCE-START368// BLOCK-ENTRY369// SCALAR("item 1",plain)370// BLOCK-ENTRY371// SCALAR("item 2",plain)372// BLOCK-END373// BLOCK-END374// STREAM-END375//376// YAML does not always require to start a new block collection from a new377// line. If the current line contains only '-', '?', and ':' indicators, a new378// block collection may start at the current line. The following examples379// illustrate this case:380//381// 1. Collections in a sequence:382//383// - - item 1384// - item 2385// - key 1: value 1386// key 2: value 2387// - ? complex key388// : complex value389//390// Tokens:391//392// STREAM-START(utf-8)393// BLOCK-SEQUENCE-START394// BLOCK-ENTRY395// BLOCK-SEQUENCE-START396// BLOCK-ENTRY397// SCALAR("item 1",plain)398// BLOCK-ENTRY399// SCALAR("item 2",plain)400// BLOCK-END401// BLOCK-ENTRY402// BLOCK-MAPPING-START403// KEY404// SCALAR("key 1",plain)405// VALUE406// SCALAR("value 1",plain)407// KEY408// SCALAR("key 2",plain)409// VALUE410// SCALAR("value 2",plain)411// BLOCK-END412// BLOCK-ENTRY413// BLOCK-MAPPING-START414// KEY415// SCALAR("complex key")416// VALUE417// SCALAR("complex value")418// BLOCK-END419// BLOCK-END420// STREAM-END421//422// 2. Collections in a mapping:423//424// ? a sequence425// : - item 1426// - item 2427// ? a mapping428// : key 1: value 1429// key 2: value 2430//431// Tokens:432//433// STREAM-START(utf-8)434// BLOCK-MAPPING-START435// KEY436// SCALAR("a sequence",plain)437// VALUE438// BLOCK-SEQUENCE-START439// BLOCK-ENTRY440// SCALAR("item 1",plain)441// BLOCK-ENTRY442// SCALAR("item 2",plain)443// BLOCK-END444// KEY445// SCALAR("a mapping",plain)446// VALUE447// BLOCK-MAPPING-START448// KEY449// SCALAR("key 1",plain)450// VALUE451// SCALAR("value 1",plain)452// KEY453// SCALAR("key 2",plain)454// VALUE455// SCALAR("value 2",plain)456// BLOCK-END457// BLOCK-END458// STREAM-END459//460// YAML also permits non-indented sequences if they are included into a block461// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced:462//463// key:464// - item 1 # BLOCK-SEQUENCE-START is NOT produced here.465// - item 2466//467// Tokens:468//469// STREAM-START(utf-8)470// BLOCK-MAPPING-START471// KEY472// SCALAR("key",plain)473// VALUE474// BLOCK-ENTRY475// SCALAR("item 1",plain)476// BLOCK-ENTRY477// SCALAR("item 2",plain)478// BLOCK-END479//480// Ensure that the buffer contains the required number of characters.481// Return true on success, false on failure (reader error or memory error).482func cache(parser *yaml_parser_t, length int) bool {483 // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)484 return parser.unread >= length || yaml_parser_update_buffer(parser, length)485}486// Advance the buffer pointer.487func skip(parser *yaml_parser_t) {488 parser.mark.index++489 parser.mark.column++490 parser.unread--491 parser.buffer_pos += width(parser.buffer[parser.buffer_pos])492}493func skip_line(parser *yaml_parser_t) {494 if is_crlf(parser.buffer, parser.buffer_pos) {495 parser.mark.index += 2496 parser.mark.column = 0497 parser.mark.line++498 parser.unread -= 2499 parser.buffer_pos += 2500 } else if is_break(parser.buffer, parser.buffer_pos) {501 parser.mark.index++502 parser.mark.column = 0503 parser.mark.line++504 parser.unread--505 parser.buffer_pos += width(parser.buffer[parser.buffer_pos])506 }507}508// Copy a character to a string buffer and advance pointers.509func read(parser *yaml_parser_t, s []byte) []byte {510 w := width(parser.buffer[parser.buffer_pos])511 if w == 0 {512 panic("invalid character sequence")513 }514 if len(s) == 0 {515 s = make([]byte, 0, 32)516 }517 if w == 1 && len(s)+w <= cap(s) {518 s = s[:len(s)+1]519 s[len(s)-1] = parser.buffer[parser.buffer_pos]520 parser.buffer_pos++521 } else {522 s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)523 parser.buffer_pos += w524 }525 parser.mark.index++526 parser.mark.column++527 parser.unread--528 return s529}530// Copy a line break character to a string buffer and advance pointers.531func read_line(parser *yaml_parser_t, s []byte) []byte {532 buf := parser.buffer533 pos := parser.buffer_pos534 switch {535 case buf[pos] == '\r' && buf[pos+1] == '\n':536 // CR LF . LF537 s = append(s, '\n')538 parser.buffer_pos += 2539 parser.mark.index++540 parser.unread--541 case buf[pos] == '\r' || buf[pos] == '\n':542 // CR|LF . LF543 s = append(s, '\n')544 parser.buffer_pos += 1545 case buf[pos] == '\xC2' && buf[pos+1] == '\x85':546 // NEL . LF547 s = append(s, '\n')548 parser.buffer_pos += 2549 case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):550 // LS|PS . LS|PS551 s = append(s, buf[parser.buffer_pos:pos+3]...)552 parser.buffer_pos += 3553 default:554 return s555 }556 parser.mark.index++557 parser.mark.column = 0558 parser.mark.line++559 parser.unread--560 return s561}562// Get the next token.563func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {564 // Erase the token object.565 *token = yaml_token_t{} // [Go] Is this necessary?566 // No tokens after STREAM-END or error.567 if parser.stream_end_produced || parser.error != yaml_NO_ERROR {568 return true569 }570 // Ensure that the tokens queue contains enough tokens.571 if !parser.token_available {572 if !yaml_parser_fetch_more_tokens(parser) {573 return false574 }575 }576 // Fetch the next token from the queue.577 *token = parser.tokens[parser.tokens_head]578 parser.tokens_head++579 parser.tokens_parsed++580 parser.token_available = false581 if token.typ == yaml_STREAM_END_TOKEN {582 parser.stream_end_produced = true583 }584 return true585}586// Set the scanner error and return false.587func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {588 parser.error = yaml_SCANNER_ERROR589 parser.context = context590 parser.context_mark = context_mark591 parser.problem = problem592 parser.problem_mark = parser.mark593 return false594}595func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {596 context := "while parsing a tag"597 if directive {598 context = "while parsing a %TAG directive"599 }600 return yaml_parser_set_scanner_error(parser, context, context_mark, problem)601}602func trace(args ...interface{}) func() {603 pargs := append([]interface{}{"+++"}, args...)604 fmt.Println(pargs...)605 pargs = append([]interface{}{"---"}, args...)606 return func() { fmt.Println(pargs...) }607}608// Ensure that the tokens queue contains at least one token which can be609// returned to the Parser.610func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {611 // While we need more tokens to fetch, do it.612 for {613 // Check if we really need to fetch more tokens.614 need_more_tokens := false615 if parser.tokens_head == len(parser.tokens) {616 // Queue is empty.617 need_more_tokens = true618 } else {619 // Check if any potential simple key may occupy the head position.620 if !yaml_parser_stale_simple_keys(parser) {621 return false622 }623 for i := range parser.simple_keys {624 simple_key := &parser.simple_keys[i]625 if simple_key.possible && simple_key.token_number == parser.tokens_parsed {626 need_more_tokens = true627 break628 }629 }630 }631 // We are finished.632 if !need_more_tokens {633 break634 }635 // Fetch the next token.636 if !yaml_parser_fetch_next_token(parser) {637 return false638 }639 }640 parser.token_available = true641 return true642}643// The dispatcher for token fetchers.644func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {645 // Ensure that the buffer is initialized.646 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {647 return false648 }649 // Check if we just started scanning. Fetch STREAM-START then.650 if !parser.stream_start_produced {651 return yaml_parser_fetch_stream_start(parser)652 }653 // Eat whitespaces and comments until we reach the next token.654 if !yaml_parser_scan_to_next_token(parser) {655 return false656 }657 // Remove obsolete potential simple keys.658 if !yaml_parser_stale_simple_keys(parser) {659 return false660 }661 // Check the indentation level against the current column.662 if !yaml_parser_unroll_indent(parser, parser.mark.column) {663 return false664 }665 // Ensure that the buffer contains at least 4 characters. 4 is the length666 // of the longest indicators ('--- ' and '... ').667 if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {668 return false669 }670 // Is it the end of the stream?671 if is_z(parser.buffer, parser.buffer_pos) {672 return yaml_parser_fetch_stream_end(parser)673 }674 // Is it a directive?675 if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {676 return yaml_parser_fetch_directive(parser)677 }678 buf := parser.buffer679 pos := parser.buffer_pos680 // Is it the document start indicator?681 if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {682 return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)683 }684 // Is it the document end indicator?685 if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {686 return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)687 }688 // Is it the flow sequence start indicator?689 if buf[pos] == '[' {690 return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)691 }692 // Is it the flow mapping start indicator?693 if parser.buffer[parser.buffer_pos] == '{' {694 return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)695 }696 // Is it the flow sequence end indicator?697 if parser.buffer[parser.buffer_pos] == ']' {698 return yaml_parser_fetch_flow_collection_end(parser,699 yaml_FLOW_SEQUENCE_END_TOKEN)700 }701 // Is it the flow mapping end indicator?702 if parser.buffer[parser.buffer_pos] == '}' {703 return yaml_parser_fetch_flow_collection_end(parser,704 yaml_FLOW_MAPPING_END_TOKEN)705 }706 // Is it the flow entry indicator?707 if parser.buffer[parser.buffer_pos] == ',' {708 return yaml_parser_fetch_flow_entry(parser)709 }710 // Is it the block entry indicator?711 if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {712 return yaml_parser_fetch_block_entry(parser)713 }714 // Is it the key indicator?715 if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {716 return yaml_parser_fetch_key(parser)717 }718 // Is it the value indicator?719 if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {720 return yaml_parser_fetch_value(parser)721 }722 // Is it an alias?723 if parser.buffer[parser.buffer_pos] == '*' {724 return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)725 }726 // Is it an anchor?727 if parser.buffer[parser.buffer_pos] == '&' {728 return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)729 }730 // Is it a tag?731 if parser.buffer[parser.buffer_pos] == '!' {732 return yaml_parser_fetch_tag(parser)733 }734 // Is it a literal scalar?735 if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {736 return yaml_parser_fetch_block_scalar(parser, true)737 }738 // Is it a folded scalar?739 if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {740 return yaml_parser_fetch_block_scalar(parser, false)741 }742 // Is it a single-quoted scalar?743 if parser.buffer[parser.buffer_pos] == '\'' {744 return yaml_parser_fetch_flow_scalar(parser, true)745 }746 // Is it a double-quoted scalar?747 if parser.buffer[parser.buffer_pos] == '"' {748 return yaml_parser_fetch_flow_scalar(parser, false)749 }750 // Is it a plain scalar?751 //752 // A plain scalar may start with any non-blank characters except753 //754 // '-', '?', ':', ',', '[', ']', '{', '}',755 // '#', '&', '*', '!', '|', '>', '\'', '\"',756 // '%', '@', '`'.757 //758 // In the block context (and, for the '-' indicator, in the flow context759 // too), it may also start with the characters760 //761 // '-', '?', ':'762 //763 // if it is followed by a non-space character.764 //765 // The last rule is more restrictive than the specification requires.766 // [Go] Make this logic more reasonable.767 //switch parser.buffer[parser.buffer_pos] {768 //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':769 //}770 if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||771 parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||772 parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||773 parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||774 parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||775 parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||776 parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||777 parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||778 parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||779 parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||780 (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||781 (parser.flow_level == 0 &&782 (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&783 !is_blankz(parser.buffer, parser.buffer_pos+1)) {784 return yaml_parser_fetch_plain_scalar(parser)785 }786 // If we don't determine the token type so far, it is an error.787 return yaml_parser_set_scanner_error(parser,788 "while scanning for the next token", parser.mark,789 "found character that cannot start any token")790}791// Check the list of potential simple keys and remove the positions that792// cannot contain simple keys anymore.793func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {794 // Check for a potential simple key for each flow level.795 for i := range parser.simple_keys {796 simple_key := &parser.simple_keys[i]797 // The specification requires that a simple key798 //799 // - is limited to a single line,800 // - is shorter than 1024 characters.801 if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {802 // Check if the potential simple key to be removed is required.803 if simple_key.required {804 return yaml_parser_set_scanner_error(parser,805 "while scanning a simple key", simple_key.mark,806 "could not find expected ':'")807 }808 simple_key.possible = false809 }810 }811 return true812}813// Check if a simple key may start at the current position and add it if814// needed.815func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {816 // A simple key is required at the current position if the scanner is in817 // the block context and the current column coincides with the indentation818 // level.819 required := parser.flow_level == 0 && parser.indent == parser.mark.column820 //821 // If the current position may start a simple key, save it.822 //823 if parser.simple_key_allowed {824 simple_key := yaml_simple_key_t{825 possible: true,826 required: required,827 token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),828 }829 simple_key.mark = parser.mark830 if !yaml_parser_remove_simple_key(parser) {831 return false832 }833 parser.simple_keys[len(parser.simple_keys)-1] = simple_key834 }835 return true836}837// Remove a potential simple key at the current flow level.838func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {839 i := len(parser.simple_keys) - 1840 if parser.simple_keys[i].possible {841 // If the key is required, it is an error.842 if parser.simple_keys[i].required {843 return yaml_parser_set_scanner_error(parser,844 "while scanning a simple key", parser.simple_keys[i].mark,845 "could not find expected ':'")846 }847 }848 // Remove the key from the stack.849 parser.simple_keys[i].possible = false850 return true851}852// Increase the flow level and resize the simple key list if needed.853func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {854 // Reset the simple key on the next level.855 parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})856 // Increase the flow level.857 parser.flow_level++858 return true859}860// Decrease the flow level.861func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {862 if parser.flow_level > 0 {863 parser.flow_level--864 parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]865 }866 return true867}868// Push the current indentation level to the stack and set the new level869// the current column is greater than the indentation level. In this case,870// append or insert the specified token into the token queue.871func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {872 // In the flow context, do nothing.873 if parser.flow_level > 0 {874 return true875 }876 if parser.indent < column {877 // Push the current indentation level to the stack and set the new878 // indentation level.879 parser.indents = append(parser.indents, parser.indent)880 parser.indent = column881 // Create a token and insert it into the queue.882 token := yaml_token_t{883 typ: typ,884 start_mark: mark,885 end_mark: mark,886 }887 if number > -1 {888 number -= parser.tokens_parsed889 }890 yaml_insert_token(parser, number, &token)891 }892 return true893}894// Pop indentation levels from the indents stack until the current level895// becomes less or equal to the column. For each indentation level, append896// the BLOCK-END token.897func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool {898 // In the flow context, do nothing.899 if parser.flow_level > 0 {900 return true901 }902 // Loop through the indentation levels in the stack.903 for parser.indent > column {904 // Create a token and append it to the queue.905 token := yaml_token_t{906 typ: yaml_BLOCK_END_TOKEN,907 start_mark: parser.mark,908 end_mark: parser.mark,909 }910 yaml_insert_token(parser, -1, &token)911 // Pop the indentation level.912 parser.indent = parser.indents[len(parser.indents)-1]913 parser.indents = parser.indents[:len(parser.indents)-1]914 }915 return true916}917// Initialize the scanner and produce the STREAM-START token.918func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {919 // Set the initial indentation.920 parser.indent = -1921 // Initialize the simple key stack.922 parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})923 // A simple key is allowed at the beginning of the stream.924 parser.simple_key_allowed = true925 // We have started.926 parser.stream_start_produced = true927 // Create the STREAM-START token and append it to the queue.928 token := yaml_token_t{929 typ: yaml_STREAM_START_TOKEN,930 start_mark: parser.mark,931 end_mark: parser.mark,932 encoding: parser.encoding,933 }934 yaml_insert_token(parser, -1, &token)935 return true936}937// Produce the STREAM-END token and shut down the scanner.938func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {939 // Force new line.940 if parser.mark.column != 0 {941 parser.mark.column = 0942 parser.mark.line++943 }944 // Reset the indentation level.945 if !yaml_parser_unroll_indent(parser, -1) {946 return false947 }948 // Reset simple keys.949 if !yaml_parser_remove_simple_key(parser) {950 return false951 }952 parser.simple_key_allowed = false953 // Create the STREAM-END token and append it to the queue.954 token := yaml_token_t{955 typ: yaml_STREAM_END_TOKEN,956 start_mark: parser.mark,957 end_mark: parser.mark,958 }959 yaml_insert_token(parser, -1, &token)960 return true961}962// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.963func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {964 // Reset the indentation level.965 if !yaml_parser_unroll_indent(parser, -1) {966 return false967 }968 // Reset simple keys.969 if !yaml_parser_remove_simple_key(parser) {970 return false971 }972 parser.simple_key_allowed = false973 // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.974 token := yaml_token_t{}975 if !yaml_parser_scan_directive(parser, &token) {976 return false977 }978 // Append the token to the queue.979 yaml_insert_token(parser, -1, &token)980 return true981}982// Produce the DOCUMENT-START or DOCUMENT-END token.983func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {984 // Reset the indentation level.985 if !yaml_parser_unroll_indent(parser, -1) {986 return false987 }988 // Reset simple keys.989 if !yaml_parser_remove_simple_key(parser) {990 return false991 }992 parser.simple_key_allowed = false993 // Consume the token.994 start_mark := parser.mark995 skip(parser)996 skip(parser)997 skip(parser)998 end_mark := parser.mark999 // Create the DOCUMENT-START or DOCUMENT-END token.1000 token := yaml_token_t{1001 typ: typ,1002 start_mark: start_mark,1003 end_mark: end_mark,1004 }1005 // Append the token to the queue.1006 yaml_insert_token(parser, -1, &token)1007 return true1008}1009// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.1010func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {1011 // The indicators '[' and '{' may start a simple key.1012 if !yaml_parser_save_simple_key(parser) {1013 return false1014 }1015 // Increase the flow level.1016 if !yaml_parser_increase_flow_level(parser) {1017 return false1018 }1019 // A simple key may follow the indicators '[' and '{'.1020 parser.simple_key_allowed = true1021 // Consume the token.1022 start_mark := parser.mark1023 skip(parser)1024 end_mark := parser.mark1025 // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.1026 token := yaml_token_t{1027 typ: typ,1028 start_mark: start_mark,1029 end_mark: end_mark,1030 }1031 // Append the token to the queue.1032 yaml_insert_token(parser, -1, &token)1033 return true1034}1035// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.1036func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {1037 // Reset any potential simple key on the current flow level.1038 if !yaml_parser_remove_simple_key(parser) {1039 return false1040 }1041 // Decrease the flow level.1042 if !yaml_parser_decrease_flow_level(parser) {1043 return false1044 }1045 // No simple keys after the indicators ']' and '}'.1046 parser.simple_key_allowed = false1047 // Consume the token.1048 start_mark := parser.mark1049 skip(parser)1050 end_mark := parser.mark1051 // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.1052 token := yaml_token_t{1053 typ: typ,1054 start_mark: start_mark,1055 end_mark: end_mark,1056 }1057 // Append the token to the queue.1058 yaml_insert_token(parser, -1, &token)1059 return true1060}1061// Produce the FLOW-ENTRY token.1062func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {1063 // Reset any potential simple keys on the current flow level.1064 if !yaml_parser_remove_simple_key(parser) {1065 return false1066 }1067 // Simple keys are allowed after ','.1068 parser.simple_key_allowed = true1069 // Consume the token.1070 start_mark := parser.mark1071 skip(parser)1072 end_mark := parser.mark1073 // Create the FLOW-ENTRY token and append it to the queue.1074 token := yaml_token_t{1075 typ: yaml_FLOW_ENTRY_TOKEN,1076 start_mark: start_mark,1077 end_mark: end_mark,1078 }1079 yaml_insert_token(parser, -1, &token)1080 return true1081}1082// Produce the BLOCK-ENTRY token.1083func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {1084 // Check if the scanner is in the block context.1085 if parser.flow_level == 0 {1086 // Check if we are allowed to start a new entry.1087 if !parser.simple_key_allowed {1088 return yaml_parser_set_scanner_error(parser, "", parser.mark,1089 "block sequence entries are not allowed in this context")1090 }1091 // Add the BLOCK-SEQUENCE-START token if needed.1092 if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {1093 return false1094 }1095 } else {1096 // It is an error for the '-' indicator to occur in the flow context,1097 // but we let the Parser detect and report about it because the Parser1098 // is able to point to the context.1099 }1100 // Reset any potential simple keys on the current flow level.1101 if !yaml_parser_remove_simple_key(parser) {1102 return false1103 }1104 // Simple keys are allowed after '-'.1105 parser.simple_key_allowed = true1106 // Consume the token.1107 start_mark := parser.mark1108 skip(parser)1109 end_mark := parser.mark1110 // Create the BLOCK-ENTRY token and append it to the queue.1111 token := yaml_token_t{...

Full Screen

Full Screen

parserc.go

Source:parserc.go Github

copy

Full Screen

1package yaml2import (3 "bytes"4)5// The parser implements the following grammar:6//7// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END8// implicit_document ::= block_node DOCUMENT-END*9// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*10// block_node_or_indentless_sequence ::=11// ALIAS12// | properties (block_content | indentless_block_sequence)?13// | block_content14// | indentless_block_sequence15// block_node ::= ALIAS16// | properties block_content?17// | block_content18// flow_node ::= ALIAS19// | properties flow_content?20// | flow_content21// properties ::= TAG ANCHOR? | ANCHOR TAG?22// block_content ::= block_collection | flow_collection | SCALAR23// flow_content ::= flow_collection | SCALAR24// block_collection ::= block_sequence | block_mapping25// flow_collection ::= flow_sequence | flow_mapping26// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END27// indentless_sequence ::= (BLOCK-ENTRY block_node?)+28// block_mapping ::= BLOCK-MAPPING_START29// ((KEY block_node_or_indentless_sequence?)?30// (VALUE block_node_or_indentless_sequence?)?)*31// BLOCK-END32// flow_sequence ::= FLOW-SEQUENCE-START33// (flow_sequence_entry FLOW-ENTRY)*34// flow_sequence_entry?35// FLOW-SEQUENCE-END36// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?37// flow_mapping ::= FLOW-MAPPING-START38// (flow_mapping_entry FLOW-ENTRY)*39// flow_mapping_entry?40// FLOW-MAPPING-END41// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?42// Peek the next token in the token queue.43func peek_token(parser *yaml_parser_t) *yaml_token_t {44 if parser.token_available || yaml_parser_fetch_more_tokens(parser) {45 return &parser.tokens[parser.tokens_head]46 }47 return nil48}49// Remove the next token from the queue (must be called after peek_token).50func skip_token(parser *yaml_parser_t) {51 parser.token_available = false52 parser.tokens_parsed++53 parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN54 parser.tokens_head++55}56// Get the next event.57func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {58 // Erase the event object.59 *event = yaml_event_t{}60 // No events after the end of the stream or error.61 if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {62 return true63 }64 // Generate the next event.65 return yaml_parser_state_machine(parser, event)66}67// Set parser error.68func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {69 parser.error = yaml_PARSER_ERROR70 parser.problem = problem71 parser.problem_mark = problem_mark72 return false73}74func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {75 parser.error = yaml_PARSER_ERROR76 parser.context = context77 parser.context_mark = context_mark78 parser.problem = problem79 parser.problem_mark = problem_mark80 return false81}82// State dispatcher.83func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {84 //trace("yaml_parser_state_machine", "state:", parser.state.String())85 switch parser.state {86 case yaml_PARSE_STREAM_START_STATE:87 return yaml_parser_parse_stream_start(parser, event)88 case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:89 return yaml_parser_parse_document_start(parser, event, true)90 case yaml_PARSE_DOCUMENT_START_STATE:91 return yaml_parser_parse_document_start(parser, event, false)92 case yaml_PARSE_DOCUMENT_CONTENT_STATE:93 return yaml_parser_parse_document_content(parser, event)94 case yaml_PARSE_DOCUMENT_END_STATE:95 return yaml_parser_parse_document_end(parser, event)96 case yaml_PARSE_BLOCK_NODE_STATE:97 return yaml_parser_parse_node(parser, event, true, false)98 case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:99 return yaml_parser_parse_node(parser, event, true, true)100 case yaml_PARSE_FLOW_NODE_STATE:101 return yaml_parser_parse_node(parser, event, false, false)102 case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:103 return yaml_parser_parse_block_sequence_entry(parser, event, true)104 case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:105 return yaml_parser_parse_block_sequence_entry(parser, event, false)106 case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:107 return yaml_parser_parse_indentless_sequence_entry(parser, event)108 case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:109 return yaml_parser_parse_block_mapping_key(parser, event, true)110 case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:111 return yaml_parser_parse_block_mapping_key(parser, event, false)112 case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:113 return yaml_parser_parse_block_mapping_value(parser, event)114 case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:115 return yaml_parser_parse_flow_sequence_entry(parser, event, true)116 case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:117 return yaml_parser_parse_flow_sequence_entry(parser, event, false)118 case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:119 return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)120 case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:121 return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)122 case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:123 return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)124 case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:125 return yaml_parser_parse_flow_mapping_key(parser, event, true)126 case yaml_PARSE_FLOW_MAPPING_KEY_STATE:127 return yaml_parser_parse_flow_mapping_key(parser, event, false)128 case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:129 return yaml_parser_parse_flow_mapping_value(parser, event, false)130 case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:131 return yaml_parser_parse_flow_mapping_value(parser, event, true)132 default:133 panic("invalid parser state")134 }135}136// Parse the production:137// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END138// ************139func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {140 token := peek_token(parser)141 if token == nil {142 return false143 }144 if token.typ != yaml_STREAM_START_TOKEN {145 return yaml_parser_set_parser_error(parser, "did not find expected <stream-start>", token.start_mark)146 }147 parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE148 *event = yaml_event_t{149 typ: yaml_STREAM_START_EVENT,150 start_mark: token.start_mark,151 end_mark: token.end_mark,152 encoding: token.encoding,153 }154 skip_token(parser)155 return true156}157// Parse the productions:158// implicit_document ::= block_node DOCUMENT-END*159// *160// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*161// *************************162func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {163 token := peek_token(parser)164 if token == nil {165 return false166 }167 // Parse extra document end indicators.168 if !implicit {169 for token.typ == yaml_DOCUMENT_END_TOKEN {170 skip_token(parser)171 token = peek_token(parser)172 if token == nil {173 return false174 }175 }176 }177 if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&178 token.typ != yaml_TAG_DIRECTIVE_TOKEN &&179 token.typ != yaml_DOCUMENT_START_TOKEN &&180 token.typ != yaml_STREAM_END_TOKEN {181 // Parse an implicit document.182 if !yaml_parser_process_directives(parser, nil, nil) {183 return false184 }185 parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)186 parser.state = yaml_PARSE_BLOCK_NODE_STATE187 *event = yaml_event_t{188 typ: yaml_DOCUMENT_START_EVENT,189 start_mark: token.start_mark,190 end_mark: token.end_mark,191 }192 } else if token.typ != yaml_STREAM_END_TOKEN {193 // Parse an explicit document.194 var version_directive *yaml_version_directive_t195 var tag_directives []yaml_tag_directive_t196 start_mark := token.start_mark197 if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {198 return false199 }200 token = peek_token(parser)201 if token == nil {202 return false203 }204 if token.typ != yaml_DOCUMENT_START_TOKEN {205 yaml_parser_set_parser_error(parser,206 "did not find expected <document start>", token.start_mark)207 return false208 }209 parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)210 parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE211 end_mark := token.end_mark212 *event = yaml_event_t{213 typ: yaml_DOCUMENT_START_EVENT,214 start_mark: start_mark,215 end_mark: end_mark,216 version_directive: version_directive,217 tag_directives: tag_directives,218 implicit: false,219 }220 skip_token(parser)221 } else {222 // Parse the stream end.223 parser.state = yaml_PARSE_END_STATE224 *event = yaml_event_t{225 typ: yaml_STREAM_END_EVENT,226 start_mark: token.start_mark,227 end_mark: token.end_mark,228 }229 skip_token(parser)230 }231 return true232}233// Parse the productions:234// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*235// ***********236//237func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {238 token := peek_token(parser)239 if token == nil {240 return false241 }242 if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||243 token.typ == yaml_TAG_DIRECTIVE_TOKEN ||244 token.typ == yaml_DOCUMENT_START_TOKEN ||245 token.typ == yaml_DOCUMENT_END_TOKEN ||246 token.typ == yaml_STREAM_END_TOKEN {247 parser.state = parser.states[len(parser.states)-1]248 parser.states = parser.states[:len(parser.states)-1]249 return yaml_parser_process_empty_scalar(parser, event,250 token.start_mark)251 }252 return yaml_parser_parse_node(parser, event, true, false)253}254// Parse the productions:255// implicit_document ::= block_node DOCUMENT-END*256// *************257// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*258//259func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {260 token := peek_token(parser)261 if token == nil {262 return false263 }264 start_mark := token.start_mark265 end_mark := token.start_mark266 implicit := true267 if token.typ == yaml_DOCUMENT_END_TOKEN {268 end_mark = token.end_mark269 skip_token(parser)270 implicit = false271 }272 parser.tag_directives = parser.tag_directives[:0]273 parser.state = yaml_PARSE_DOCUMENT_START_STATE274 *event = yaml_event_t{275 typ: yaml_DOCUMENT_END_EVENT,276 start_mark: start_mark,277 end_mark: end_mark,278 implicit: implicit,279 }280 return true281}282// Parse the productions:283// block_node_or_indentless_sequence ::=284// ALIAS285// *****286// | properties (block_content | indentless_block_sequence)?287// ********** *288// | block_content | indentless_block_sequence289// *290// block_node ::= ALIAS291// *****292// | properties block_content?293// ********** *294// | block_content295// *296// flow_node ::= ALIAS297// *****298// | properties flow_content?299// ********** *300// | flow_content301// *302// properties ::= TAG ANCHOR? | ANCHOR TAG?303// *************************304// block_content ::= block_collection | flow_collection | SCALAR305// ******306// flow_content ::= flow_collection | SCALAR307// ******308func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {309 //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()310 token := peek_token(parser)311 if token == nil {312 return false313 }314 if token.typ == yaml_ALIAS_TOKEN {315 parser.state = parser.states[len(parser.states)-1]316 parser.states = parser.states[:len(parser.states)-1]317 *event = yaml_event_t{318 typ: yaml_ALIAS_EVENT,319 start_mark: token.start_mark,320 end_mark: token.end_mark,321 anchor: token.value,322 }323 skip_token(parser)324 return true325 }326 start_mark := token.start_mark327 end_mark := token.start_mark328 var tag_token bool329 var tag_handle, tag_suffix, anchor []byte330 var tag_mark yaml_mark_t331 if token.typ == yaml_ANCHOR_TOKEN {332 anchor = token.value333 start_mark = token.start_mark334 end_mark = token.end_mark335 skip_token(parser)336 token = peek_token(parser)337 if token == nil {338 return false339 }340 if token.typ == yaml_TAG_TOKEN {341 tag_token = true342 tag_handle = token.value343 tag_suffix = token.suffix344 tag_mark = token.start_mark345 end_mark = token.end_mark346 skip_token(parser)347 token = peek_token(parser)348 if token == nil {349 return false350 }351 }352 } else if token.typ == yaml_TAG_TOKEN {353 tag_token = true354 tag_handle = token.value355 tag_suffix = token.suffix356 start_mark = token.start_mark357 tag_mark = token.start_mark358 end_mark = token.end_mark359 skip_token(parser)360 token = peek_token(parser)361 if token == nil {362 return false363 }364 if token.typ == yaml_ANCHOR_TOKEN {365 anchor = token.value366 end_mark = token.end_mark367 skip_token(parser)368 token = peek_token(parser)369 if token == nil {370 return false371 }372 }373 }374 var tag []byte375 if tag_token {376 if len(tag_handle) == 0 {377 tag = tag_suffix378 tag_suffix = nil379 } else {380 for i := range parser.tag_directives {381 if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {382 tag = append([]byte(nil), parser.tag_directives[i].prefix...)383 tag = append(tag, tag_suffix...)384 break385 }386 }387 if len(tag) == 0 {388 yaml_parser_set_parser_error_context(parser,389 "while parsing a node", start_mark,390 "found undefined tag handle", tag_mark)391 return false392 }393 }394 }395 implicit := len(tag) == 0396 if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {397 end_mark = token.end_mark398 parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE399 *event = yaml_event_t{400 typ: yaml_SEQUENCE_START_EVENT,401 start_mark: start_mark,402 end_mark: end_mark,403 anchor: anchor,404 tag: tag,405 implicit: implicit,406 style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),407 }408 return true409 }410 if token.typ == yaml_SCALAR_TOKEN {411 var plain_implicit, quoted_implicit bool412 end_mark = token.end_mark413 if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {414 plain_implicit = true415 } else if len(tag) == 0 {416 quoted_implicit = true417 }418 parser.state = parser.states[len(parser.states)-1]419 parser.states = parser.states[:len(parser.states)-1]420 *event = yaml_event_t{421 typ: yaml_SCALAR_EVENT,422 start_mark: start_mark,423 end_mark: end_mark,424 anchor: anchor,425 tag: tag,426 value: token.value,427 implicit: plain_implicit,428 quoted_implicit: quoted_implicit,429 style: yaml_style_t(token.style),430 }431 skip_token(parser)432 return true433 }434 if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {435 // [Go] Some of the events below can be merged as they differ only on style.436 end_mark = token.end_mark437 parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE438 *event = yaml_event_t{439 typ: yaml_SEQUENCE_START_EVENT,440 start_mark: start_mark,441 end_mark: end_mark,442 anchor: anchor,443 tag: tag,444 implicit: implicit,445 style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),446 }447 return true448 }449 if token.typ == yaml_FLOW_MAPPING_START_TOKEN {450 end_mark = token.end_mark451 parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE452 *event = yaml_event_t{453 typ: yaml_MAPPING_START_EVENT,454 start_mark: start_mark,455 end_mark: end_mark,456 anchor: anchor,457 tag: tag,458 implicit: implicit,459 style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),460 }461 return true462 }463 if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {464 end_mark = token.end_mark465 parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE466 *event = yaml_event_t{467 typ: yaml_SEQUENCE_START_EVENT,468 start_mark: start_mark,469 end_mark: end_mark,470 anchor: anchor,471 tag: tag,472 implicit: implicit,473 style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),474 }475 return true476 }477 if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {478 end_mark = token.end_mark479 parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE480 *event = yaml_event_t{481 typ: yaml_MAPPING_START_EVENT,482 start_mark: start_mark,483 end_mark: end_mark,484 anchor: anchor,485 tag: tag,486 implicit: implicit,487 style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE),488 }489 return true490 }491 if len(anchor) > 0 || len(tag) > 0 {492 parser.state = parser.states[len(parser.states)-1]493 parser.states = parser.states[:len(parser.states)-1]494 *event = yaml_event_t{495 typ: yaml_SCALAR_EVENT,496 start_mark: start_mark,497 end_mark: end_mark,498 anchor: anchor,499 tag: tag,500 implicit: implicit,501 quoted_implicit: false,502 style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),503 }504 return true505 }506 context := "while parsing a flow node"507 if block {508 context = "while parsing a block node"509 }510 yaml_parser_set_parser_error_context(parser, context, start_mark,511 "did not find expected node content", token.start_mark)512 return false513}514// Parse the productions:515// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END516// ******************** *********** * *********517//518func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {519 if first {520 token := peek_token(parser)521 parser.marks = append(parser.marks, token.start_mark)522 skip_token(parser)523 }524 token := peek_token(parser)525 if token == nil {526 return false527 }528 if token.typ == yaml_BLOCK_ENTRY_TOKEN {529 mark := token.end_mark530 skip_token(parser)531 token = peek_token(parser)532 if token == nil {533 return false534 }535 if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {536 parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)537 return yaml_parser_parse_node(parser, event, true, false)538 } else {539 parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE540 return yaml_parser_process_empty_scalar(parser, event, mark)541 }542 }543 if token.typ == yaml_BLOCK_END_TOKEN {544 parser.state = parser.states[len(parser.states)-1]545 parser.states = parser.states[:len(parser.states)-1]546 parser.marks = parser.marks[:len(parser.marks)-1]547 *event = yaml_event_t{548 typ: yaml_SEQUENCE_END_EVENT,549 start_mark: token.start_mark,550 end_mark: token.end_mark,551 }552 skip_token(parser)553 return true554 }555 context_mark := parser.marks[len(parser.marks)-1]556 parser.marks = parser.marks[:len(parser.marks)-1]557 return yaml_parser_set_parser_error_context(parser,558 "while parsing a block collection", context_mark,559 "did not find expected '-' indicator", token.start_mark)560}561// Parse the productions:562// indentless_sequence ::= (BLOCK-ENTRY block_node?)+563// *********** *564func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {565 token := peek_token(parser)566 if token == nil {567 return false568 }569 if token.typ == yaml_BLOCK_ENTRY_TOKEN {570 mark := token.end_mark571 skip_token(parser)572 token = peek_token(parser)573 if token == nil {574 return false575 }576 if token.typ != yaml_BLOCK_ENTRY_TOKEN &&577 token.typ != yaml_KEY_TOKEN &&578 token.typ != yaml_VALUE_TOKEN &&579 token.typ != yaml_BLOCK_END_TOKEN {580 parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)581 return yaml_parser_parse_node(parser, event, true, false)582 }583 parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE584 return yaml_parser_process_empty_scalar(parser, event, mark)585 }586 parser.state = parser.states[len(parser.states)-1]587 parser.states = parser.states[:len(parser.states)-1]588 *event = yaml_event_t{589 typ: yaml_SEQUENCE_END_EVENT,590 start_mark: token.start_mark,591 end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark?592 }593 return true594}595// Parse the productions:596// block_mapping ::= BLOCK-MAPPING_START597// *******************598// ((KEY block_node_or_indentless_sequence?)?599// *** *600// (VALUE block_node_or_indentless_sequence?)?)*601//602// BLOCK-END603// *********604//605func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {606 if first {607 token := peek_token(parser)608 parser.marks = append(parser.marks, token.start_mark)609 skip_token(parser)610 }611 token := peek_token(parser)612 if token == nil {613 return false614 }615 if token.typ == yaml_KEY_TOKEN {616 mark := token.end_mark617 skip_token(parser)618 token = peek_token(parser)619 if token == nil {620 return false621 }622 if token.typ != yaml_KEY_TOKEN &&623 token.typ != yaml_VALUE_TOKEN &&624 token.typ != yaml_BLOCK_END_TOKEN {625 parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)626 return yaml_parser_parse_node(parser, event, true, true)627 } else {628 parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE629 return yaml_parser_process_empty_scalar(parser, event, mark)630 }631 } else if token.typ == yaml_BLOCK_END_TOKEN {632 parser.state = parser.states[len(parser.states)-1]633 parser.states = parser.states[:len(parser.states)-1]634 parser.marks = parser.marks[:len(parser.marks)-1]635 *event = yaml_event_t{636 typ: yaml_MAPPING_END_EVENT,637 start_mark: token.start_mark,638 end_mark: token.end_mark,639 }640 skip_token(parser)641 return true642 }643 context_mark := parser.marks[len(parser.marks)-1]644 parser.marks = parser.marks[:len(parser.marks)-1]645 return yaml_parser_set_parser_error_context(parser,646 "while parsing a block mapping", context_mark,647 "did not find expected key", token.start_mark)648}649// Parse the productions:650// block_mapping ::= BLOCK-MAPPING_START651//652// ((KEY block_node_or_indentless_sequence?)?653//654// (VALUE block_node_or_indentless_sequence?)?)*655// ***** *656// BLOCK-END657//658//659func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {660 token := peek_token(parser)661 if token == nil {662 return false663 }664 if token.typ == yaml_VALUE_TOKEN {665 mark := token.end_mark666 skip_token(parser)667 token = peek_token(parser)668 if token == nil {669 return false670 }671 if token.typ != yaml_KEY_TOKEN &&672 token.typ != yaml_VALUE_TOKEN &&673 token.typ != yaml_BLOCK_END_TOKEN {674 parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)675 return yaml_parser_parse_node(parser, event, true, true)676 }677 parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE678 return yaml_parser_process_empty_scalar(parser, event, mark)679 }680 parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE681 return yaml_parser_process_empty_scalar(parser, event, token.start_mark)682}683// Parse the productions:684// flow_sequence ::= FLOW-SEQUENCE-START685// *******************686// (flow_sequence_entry FLOW-ENTRY)*687// * **********688// flow_sequence_entry?689// *690// FLOW-SEQUENCE-END691// *****************692// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?693// *694//695func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {696 if first {697 token := peek_token(parser)698 parser.marks = append(parser.marks, token.start_mark)699 skip_token(parser)700 }701 token := peek_token(parser)702 if token == nil {703 return false704 }705 if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {706 if !first {707 if token.typ == yaml_FLOW_ENTRY_TOKEN {708 skip_token(parser)709 token = peek_token(parser)710 if token == nil {711 return false712 }713 } else {714 context_mark := parser.marks[len(parser.marks)-1]715 parser.marks = parser.marks[:len(parser.marks)-1]716 return yaml_parser_set_parser_error_context(parser,717 "while parsing a flow sequence", context_mark,718 "did not find expected ',' or ']'", token.start_mark)719 }720 }721 if token.typ == yaml_KEY_TOKEN {722 parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE723 *event = yaml_event_t{724 typ: yaml_MAPPING_START_EVENT,725 start_mark: token.start_mark,726 end_mark: token.end_mark,727 implicit: true,728 style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),729 }730 skip_token(parser)731 return true732 } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {733 parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)734 return yaml_parser_parse_node(parser, event, false, false)735 }736 }737 parser.state = parser.states[len(parser.states)-1]738 parser.states = parser.states[:len(parser.states)-1]739 parser.marks = parser.marks[:len(parser.marks)-1]740 *event = yaml_event_t{741 typ: yaml_SEQUENCE_END_EVENT,742 start_mark: token.start_mark,743 end_mark: token.end_mark,744 }745 skip_token(parser)746 return true747}748//749// Parse the productions:750// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?751// *** *752//753func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {754 token := peek_token(parser)755 if token == nil {756 return false757 }758 if token.typ != yaml_VALUE_TOKEN &&759 token.typ != yaml_FLOW_ENTRY_TOKEN &&760 token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {761 parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)762 return yaml_parser_parse_node(parser, event, false, false)763 }764 mark := token.end_mark765 skip_token(parser)766 parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE767 return yaml_parser_process_empty_scalar(parser, event, mark)768}769// Parse the productions:770// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?771// ***** *772//773func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {774 token := peek_token(parser)775 if token == nil {776 return false777 }778 if token.typ == yaml_VALUE_TOKEN {779 skip_token(parser)780 token := peek_token(parser)781 if token == nil {782 return false783 }784 if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {785 parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)786 return yaml_parser_parse_node(parser, event, false, false)787 }788 }789 parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE790 return yaml_parser_process_empty_scalar(parser, event, token.start_mark)791}792// Parse the productions:793// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?794// *795//796func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {797 token := peek_token(parser)798 if token == nil {799 return false800 }801 parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE802 *event = yaml_event_t{803 typ: yaml_MAPPING_END_EVENT,804 start_mark: token.start_mark,805 end_mark: token.start_mark, // [Go] Shouldn't this be end_mark?806 }807 return true808}809// Parse the productions:810// flow_mapping ::= FLOW-MAPPING-START811// ******************812// (flow_mapping_entry FLOW-ENTRY)*813// * **********814// flow_mapping_entry?815// ******************816// FLOW-MAPPING-END817// ****************818// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?819// * *** *820//821func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {822 if first {823 token := peek_token(parser)824 parser.marks = append(parser.marks, token.start_mark)825 skip_token(parser)826 }827 token := peek_token(parser)828 if token == nil {829 return false830 }831 if token.typ != yaml_FLOW_MAPPING_END_TOKEN {832 if !first {833 if token.typ == yaml_FLOW_ENTRY_TOKEN {834 skip_token(parser)835 token = peek_token(parser)836 if token == nil {837 return false838 }839 } else {840 context_mark := parser.marks[len(parser.marks)-1]841 parser.marks = parser.marks[:len(parser.marks)-1]842 return yaml_parser_set_parser_error_context(parser,843 "while parsing a flow mapping", context_mark,844 "did not find expected ',' or '}'", token.start_mark)845 }846 }847 if token.typ == yaml_KEY_TOKEN {848 skip_token(parser)849 token = peek_token(parser)850 if token == nil {851 return false852 }853 if token.typ != yaml_VALUE_TOKEN &&854 token.typ != yaml_FLOW_ENTRY_TOKEN &&855 token.typ != yaml_FLOW_MAPPING_END_TOKEN {856 parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)857 return yaml_parser_parse_node(parser, event, false, false)858 } else {859 parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE860 return yaml_parser_process_empty_scalar(parser, event, token.start_mark)861 }862 } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {863 parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)864 return yaml_parser_parse_node(parser, event, false, false)865 }866 }867 parser.state = parser.states[len(parser.states)-1]868 parser.states = parser.states[:len(parser.states)-1]869 parser.marks = parser.marks[:len(parser.marks)-1]870 *event = yaml_event_t{871 typ: yaml_MAPPING_END_EVENT,872 start_mark: token.start_mark,873 end_mark: token.end_mark,874 }875 skip_token(parser)876 return true877}878// Parse the productions:879// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?880// * ***** *881//882func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {883 token := peek_token(parser)884 if token == nil {885 return false886 }887 if empty {888 parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE889 return yaml_parser_process_empty_scalar(parser, event, token.start_mark)890 }891 if token.typ == yaml_VALUE_TOKEN {892 skip_token(parser)893 token = peek_token(parser)894 if token == nil {895 return false896 }897 if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {898 parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)899 return yaml_parser_parse_node(parser, event, false, false)900 }901 }902 parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE903 return yaml_parser_process_empty_scalar(parser, event, token.start_mark)904}905// Generate an empty scalar event.906func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {907 *event = yaml_event_t{908 typ: yaml_SCALAR_EVENT,909 start_mark: mark,910 end_mark: mark,911 value: nil, // Empty912 implicit: true,913 style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),914 }915 return true916}917var default_tag_directives = []yaml_tag_directive_t{918 {[]byte("!"), []byte("!")},919 {[]byte("!!"), []byte("tag:yaml.org,2002:")},920}921// Parse directives.922func yaml_parser_process_directives(parser *yaml_parser_t,923 version_directive_ref **yaml_version_directive_t,924 tag_directives_ref *[]yaml_tag_directive_t) bool {925 var version_directive *yaml_version_directive_t926 var tag_directives []yaml_tag_directive_t927 token := peek_token(parser)928 if token == nil {929 return false930 }931 for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {932 if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {933 if version_directive != nil {934 yaml_parser_set_parser_error(parser,935 "found duplicate %YAML directive", token.start_mark)936 return false937 }938 if token.major != 1 || token.minor != 1 {939 yaml_parser_set_parser_error(parser,940 "found incompatible YAML document", token.start_mark)941 return false942 }943 version_directive = &yaml_version_directive_t{944 major: token.major,945 minor: token.minor,946 }947 } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {948 value := yaml_tag_directive_t{949 handle: token.value,950 prefix: token.prefix,951 }952 if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {953 return false954 }955 tag_directives = append(tag_directives, value)956 }957 skip_token(parser)958 token = peek_token(parser)959 if token == nil {960 return false961 }962 }963 for i := range default_tag_directives {964 if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {965 return false966 }967 }968 if version_directive_ref != nil {969 *version_directive_ref = version_directive970 }971 if tag_directives_ref != nil {972 *tag_directives_ref = tag_directives973 }974 return true975}976// Append a tag directive to the directives stack.977func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {978 for i := range parser.tag_directives {979 if bytes.Equal(value.handle, parser.tag_directives[i].handle) {980 if allow_duplicates {981 return true982 }983 return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)984 }985 }986 // [Go] I suspect the copy is unnecessary. This was likely done987 // because there was no way to track ownership of the data.988 value_copy := yaml_tag_directive_t{989 handle: make([]byte, len(value.handle)),990 prefix: make([]byte, len(value.prefix)),991 }992 copy(value_copy.handle, value.handle)993 copy(value_copy.prefix, value.prefix)994 parser.tag_directives = append(parser.tag_directives, value_copy)995 return true996}...

Full Screen

Full Screen

ConsoleOptionParserTest.php

Source:ConsoleOptionParserTest.php Github

copy

Full Screen

1<?php2/**3 * ConsoleOptionParserTest file4 *5 * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>6 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)7 *8 * Licensed under The MIT License9 * For full copyright and license information, please see the LICENSE.txt10 * Redistributions of files must retain the above copyright notice11 *12 * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)13 * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests14 * @package Cake.Test.Case.Console15 * @since CakePHP(tm) v 2.016 * @license http://www.opensource.org/licenses/mit-license.php MIT License17 */18App::uses('ConsoleOptionParser', 'Console');19/**20 * ConsoleOptionParserTest21 *22 * @package Cake.Test.Case.Console23 */24class ConsoleOptionParserTest extends CakeTestCase {25/**26 * test setting the console description27 *28 * @return void29 */30 public function testDescription() {31 $parser = new ConsoleOptionParser('test', false);32 $result = $parser->description('A test');33 $this->assertEquals($parser, $result, 'Setting description is not chainable');34 $this->assertEquals('A test', $parser->description(), 'getting value is wrong.');35 $parser->description(array('A test', 'something'));36 $this->assertEquals("A test\nsomething", $parser->description(), 'getting value is wrong.');37 }38/**39 * test setting the console epilog40 *41 * @return void42 */43 public function testEpilog() {44 $parser = new ConsoleOptionParser('test', false);45 $result = $parser->epilog('A test');46 $this->assertEquals($parser, $result, 'Setting epilog is not chainable');47 $this->assertEquals('A test', $parser->epilog(), 'getting value is wrong.');48 $parser->epilog(array('A test', 'something'));49 $this->assertEquals("A test\nsomething", $parser->epilog(), 'getting value is wrong.');50 }51/**52 * test adding an option returns self.53 *54 * @return void55 */56 public function testAddOptionReturnSelf() {57 $parser = new ConsoleOptionParser('test', false);58 $result = $parser->addOption('test');59 $this->assertEquals($parser, $result, 'Did not return $this from addOption');60 }61/**62 * test adding an option and using the long value for parsing.63 *64 * @return void65 */66 public function testAddOptionLong() {67 $parser = new ConsoleOptionParser('test', false);68 $parser->addOption('test', array(69 'short' => 't'70 ));71 $result = $parser->parse(array('--test', 'value'));72 $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');73 }74/**75 * test adding an option with a zero value76 *77 * @return void78 */79 public function testAddOptionZero() {80 $parser = new ConsoleOptionParser('test', false);81 $parser->addOption('count', array());82 $result = $parser->parse(array('--count', '0'));83 $this->assertEquals(array('count' => '0', 'help' => false), $result[0], 'Zero parameter did not parse out');84 }85/**86 * test addOption with an object.87 *88 * @return void89 */90 public function testAddOptionObject() {91 $parser = new ConsoleOptionParser('test', false);92 $parser->addOption(new ConsoleInputOption('test', 't'));93 $result = $parser->parse(array('--test=value'));94 $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');95 }96/**97 * test adding an option and using the long value for parsing.98 *99 * @return void100 */101 public function testAddOptionLongEquals() {102 $parser = new ConsoleOptionParser('test', false);103 $parser->addOption('test', array(104 'short' => 't'105 ));106 $result = $parser->parse(array('--test=value'));107 $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');108 }109/**110 * test adding an option and using the default.111 *112 * @return void113 */114 public function testAddOptionDefault() {115 $parser = new ConsoleOptionParser('test', false);116 $parser->addOption('test', array(117 'default' => 'default value',118 ));119 $result = $parser->parse(array('--test'));120 $this->assertEquals(array('test' => 'default value', 'help' => false), $result[0], 'Default value did not parse out');121 $parser = new ConsoleOptionParser('test', false);122 $parser->addOption('test', array(123 'default' => 'default value',124 ));125 $result = $parser->parse(array());126 $this->assertEquals(array('test' => 'default value', 'help' => false), $result[0], 'Default value did not parse out');127 }128/**129 * test adding an option and using the short value for parsing.130 *131 * @return void132 */133 public function testAddOptionShort() {134 $parser = new ConsoleOptionParser('test', false);135 $parser->addOption('test', array(136 'short' => 't'137 ));138 $result = $parser->parse(array('-t', 'value'));139 $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Short parameter did not parse out');140 }141/**142 * Test that adding an option using a two letter short value causes an exception.143 * As they will not parse correctly.144 *145 * @expectedException ConsoleException146 * @return void147 */148 public function testAddOptionShortOneLetter() {149 $parser = new ConsoleOptionParser('test', false);150 $parser->addOption('test', array('short' => 'te'));151 }152/**153 * test adding and using boolean options.154 *155 * @return void156 */157 public function testAddOptionBoolean() {158 $parser = new ConsoleOptionParser('test', false);159 $parser->addOption('test', array(160 'boolean' => true,161 ));162 $result = $parser->parse(array('--test', 'value'));163 $expected = array(array('test' => true, 'help' => false), array('value'));164 $this->assertEquals($expected, $result);165 $result = $parser->parse(array('value'));166 $expected = array(array('test' => false, 'help' => false), array('value'));167 $this->assertEquals($expected, $result);168 }169/**170 * test adding an multiple shorts.171 *172 * @return void173 */174 public function testAddOptionMultipleShort() {175 $parser = new ConsoleOptionParser('test', false);176 $parser->addOption('test', array('short' => 't', 'boolean' => true))177 ->addOption('file', array('short' => 'f', 'boolean' => true))178 ->addOption('output', array('short' => 'o', 'boolean' => true));179 $result = $parser->parse(array('-o', '-t', '-f'));180 $expected = array('file' => true, 'test' => true, 'output' => true, 'help' => false);181 $this->assertEquals($expected, $result[0], 'Short parameter did not parse out');182 $result = $parser->parse(array('-otf'));183 $this->assertEquals($expected, $result[0], 'Short parameter did not parse out');184 }185/**186 * test multiple options at once.187 *188 * @return void189 */190 public function testMultipleOptions() {191 $parser = new ConsoleOptionParser('test', false);192 $parser->addOption('test')193 ->addOption('connection')194 ->addOption('table', array('short' => 't', 'default' => true));195 $result = $parser->parse(array('--test', 'value', '-t', '--connection', 'postgres'));196 $expected = array('test' => 'value', 'table' => true, 'connection' => 'postgres', 'help' => false);197 $this->assertEquals($expected, $result[0], 'multiple options did not parse');198 }199/**200 * Test adding multiple options.201 *202 * @return void203 */204 public function testAddOptions() {205 $parser = new ConsoleOptionParser('something', false);206 $result = $parser->addOptions(array(207 'name' => array('help' => 'The name'),208 'other' => array('help' => 'The other arg')209 ));210 $this->assertEquals($parser, $result, 'addOptions is not chainable.');211 $result = $parser->options();212 $this->assertEquals(3, count($result), 'Not enough options');213 }214/**215 * test that boolean options work216 *217 * @return void218 */219 public function testOptionWithBooleanParam() {220 $parser = new ConsoleOptionParser('test', false);221 $parser->addOption('no-commit', array('boolean' => true))222 ->addOption('table', array('short' => 't'));223 $result = $parser->parse(array('--table', 'posts', '--no-commit', 'arg1', 'arg2'));224 $expected = array(array('table' => 'posts', 'no-commit' => true, 'help' => false), array('arg1', 'arg2'));225 $this->assertEquals($expected, $result, 'Boolean option did not parse correctly.');226 }227/**228 * test parsing options that do not exist.229 *230 * @expectedException ConsoleException231 * @return void232 */233 public function testOptionThatDoesNotExist() {234 $parser = new ConsoleOptionParser('test', false);235 $parser->addOption('no-commit', array('boolean' => true));236 $parser->parse(array('--fail', 'other'));237 }238/**239 * test parsing short options that do not exist.240 *241 * @expectedException ConsoleException242 * @return void243 */244 public function testShortOptionThatDoesNotExist() {245 $parser = new ConsoleOptionParser('test', false);246 $parser->addOption('no-commit', array('boolean' => true));247 $parser->parse(array('-f'));248 }249/**250 * test that options with choices enforce them.251 *252 * @expectedException ConsoleException253 * @return void254 */255 public function testOptionWithChoices() {256 $parser = new ConsoleOptionParser('test', false);257 $parser->addOption('name', array('choices' => array('mark', 'jose')));258 $result = $parser->parse(array('--name', 'mark'));259 $expected = array('name' => 'mark', 'help' => false);260 $this->assertEquals($expected, $result[0], 'Got the correct value.');261 $parser->parse(array('--name', 'jimmy'));262 }263/**264 * Ensure that option values can start with -265 *266 * @return void267 */268 public function testOptionWithValueStartingWithMinus() {269 $parser = new ConsoleOptionParser('test', false);270 $parser->addOption('name')271 ->addOption('age');272 $result = $parser->parse(array('--name', '-foo', '--age', 'old'));273 $expected = array('name' => '-foo', 'age' => 'old', 'help' => false);274 $this->assertEquals($expected, $result[0], 'Option values starting with "-" are broken.');275 }276/**277 * test positional argument parsing.278 *279 * @return void280 */281 public function testPositionalArgument() {282 $parser = new ConsoleOptionParser('test', false);283 $result = $parser->addArgument('name', array('help' => 'An argument'));284 $this->assertEquals($parser, $result, 'Should return this');285 }286/**287 * test addOption with an object.288 *289 * @return void290 */291 public function testAddArgumentObject() {292 $parser = new ConsoleOptionParser('test', false);293 $parser->addArgument(new ConsoleInputArgument('test'));294 $result = $parser->arguments();295 $this->assertCount(1, $result);296 $this->assertEquals('test', $result[0]->name());297 }298/**299 * Test adding arguments out of order.300 *301 * @return void302 */303 public function testAddArgumentOutOfOrder() {304 $parser = new ConsoleOptionParser('test', false);305 $parser->addArgument('name', array('index' => 1, 'help' => 'first argument'))306 ->addArgument('bag', array('index' => 2, 'help' => 'second argument'))307 ->addArgument('other', array('index' => 0, 'help' => 'Zeroth argument'));308 $result = $parser->arguments();309 $this->assertCount(3, $result);310 $this->assertEquals('other', $result[0]->name());311 $this->assertEquals('name', $result[1]->name());312 $this->assertEquals('bag', $result[2]->name());313 $this->assertSame(array(0, 1, 2), array_keys($result));314 }315/**316 * test overwriting positional arguments.317 *318 * @return void319 */320 public function testPositionalArgOverwrite() {321 $parser = new ConsoleOptionParser('test', false);322 $parser->addArgument('name', array('help' => 'An argument'))323 ->addArgument('other', array('index' => 0));324 $result = $parser->arguments();325 $this->assertEquals(1, count($result), 'Overwrite did not occur');326 }327/**328 * test parsing arguments.329 *330 * @expectedException ConsoleException331 * @return void332 */333 public function testParseArgumentTooMany() {334 $parser = new ConsoleOptionParser('test', false);335 $parser->addArgument('name', array('help' => 'An argument'))336 ->addArgument('other');337 $expected = array('one', 'two');338 $result = $parser->parse($expected);339 $this->assertEquals($expected, $result[1], 'Arguments are not as expected');340 $parser->parse(array('one', 'two', 'three'));341 }342/**343 * test parsing arguments with 0 value.344 *345 * @return void346 */347 public function testParseArgumentZero() {348 $parser = new ConsoleOptionParser('test', false);349 $expected = array('one', 'two', 0, 'after', 'zero');350 $result = $parser->parse($expected);351 $this->assertEquals($expected, $result[1], 'Arguments are not as expected');352 }353/**354 * test that when there are not enough arguments an exception is raised355 *356 * @expectedException ConsoleException357 * @return void358 */359 public function testPositionalArgNotEnough() {360 $parser = new ConsoleOptionParser('test', false);361 $parser->addArgument('name', array('required' => true))362 ->addArgument('other', array('required' => true));363 $parser->parse(array('one'));364 }365/**366 * test that arguments with choices enforce them.367 *368 * @expectedException ConsoleException369 * @return void370 */371 public function testPositionalArgWithChoices() {372 $parser = new ConsoleOptionParser('test', false);373 $parser->addArgument('name', array('choices' => array('mark', 'jose')))374 ->addArgument('alias', array('choices' => array('cowboy', 'samurai')))375 ->addArgument('weapon', array('choices' => array('gun', 'sword')));376 $result = $parser->parse(array('mark', 'samurai', 'sword'));377 $expected = array('mark', 'samurai', 'sword');378 $this->assertEquals($expected, $result[1], 'Got the correct value.');379 $parser->parse(array('jose', 'coder'));380 }381/**382 * Test adding multiple arguments.383 *384 * @return void385 */386 public function testAddArguments() {387 $parser = new ConsoleOptionParser('test', false);388 $result = $parser->addArguments(array(389 'name' => array('help' => 'The name'),390 'other' => array('help' => 'The other arg')391 ));392 $this->assertEquals($parser, $result, 'addArguments is not chainable.');393 $result = $parser->arguments();394 $this->assertEquals(2, count($result), 'Not enough arguments');395 }396/**397 * test setting a subcommand up.398 *399 * @return void400 */401 public function testSubcommand() {402 $parser = new ConsoleOptionParser('test', false);403 $result = $parser->addSubcommand('initdb', array(404 'help' => 'Initialize the database'405 ));406 $this->assertEquals($parser, $result, 'Adding a subcommand is not chainable');407 }408/**409 * test addSubcommand with an object.410 *411 * @return void412 */413 public function testAddSubcommandObject() {414 $parser = new ConsoleOptionParser('test', false);415 $parser->addSubcommand(new ConsoleInputSubcommand('test'));416 $result = $parser->subcommands();417 $this->assertEquals(1, count($result));418 $this->assertEquals('test', $result['test']->name());419 }420/**421 * test removeSubcommand with an object.422 *423 * @return void424 */425 public function testRemoveSubcommand() {426 $parser = new ConsoleOptionParser('test', false);427 $parser->addSubcommand(new ConsoleInputSubcommand('test'));428 $result = $parser->subcommands();429 $this->assertEquals(1, count($result));430 $parser->removeSubcommand('test');431 $result = $parser->subcommands();432 $this->assertEquals(0, count($result), 'Remove a subcommand does not work');433 }434/**435 * test adding multiple subcommands436 *437 * @return void438 */439 public function testAddSubcommands() {440 $parser = new ConsoleOptionParser('test', false);441 $result = $parser->addSubcommands(array(442 'initdb' => array('help' => 'Initialize the database'),443 'create' => array('help' => 'Create something')444 ));445 $this->assertEquals($parser, $result, 'Adding a subcommands is not chainable');446 $result = $parser->subcommands();447 $this->assertEquals(2, count($result), 'Not enough subcommands');448 }449/**450 * test that no exception is triggered when help is being generated451 *452 * @return void453 */454 public function testHelpNoExceptionWhenGettingHelp() {455 $parser = new ConsoleOptionParser('mycommand', false);456 $parser->addOption('test', array('help' => 'A test option.'))457 ->addArgument('model', array('help' => 'The model to make.', 'required' => true));458 $result = $parser->parse(array('--help'));459 $this->assertTrue($result[0]['help']);460 }461/**462 * test that help() with a command param shows the help for a subcommand463 *464 * @return void465 */466 public function testHelpSubcommandHelp() {467 $subParser = new ConsoleOptionParser('method', false);468 $subParser->addOption('connection', array('help' => 'Db connection.'));469 $parser = new ConsoleOptionParser('mycommand', false);470 $parser->addSubcommand('method', array(471 'help' => 'This is another command',472 'parser' => $subParser473 ))474 ->addOption('test', array('help' => 'A test option.'));475 $result = $parser->help('method');476 $expected = <<<TEXT477<info>Usage:</info>478cake mycommand method [-h] [--connection]479<info>Options:</info>480--help, -h Display this help.481--connection Db connection.482TEXT;483 $this->assertTextEquals($expected, $result, 'Help is not correct.');484 }485/**486 * test building a parser from an array.487 *488 * @return void489 */490 public function testBuildFromArray() {491 $spec = array(492 'command' => 'test',493 'arguments' => array(494 'name' => array('help' => 'The name'),495 'other' => array('help' => 'The other arg')496 ),497 'options' => array(498 'name' => array('help' => 'The name'),499 'other' => array('help' => 'The other arg')500 ),501 'subcommands' => array(502 'initdb' => array('help' => 'make database')503 ),504 'description' => 'description text',505 'epilog' => 'epilog text'506 );507 $parser = ConsoleOptionParser::buildFromArray($spec);508 $this->assertEquals($spec['description'], $parser->description());509 $this->assertEquals($spec['epilog'], $parser->epilog());510 $options = $parser->options();511 $this->assertTrue(isset($options['name']));512 $this->assertTrue(isset($options['other']));513 $args = $parser->arguments();514 $this->assertEquals(2, count($args));515 $commands = $parser->subcommands();516 $this->assertEquals(1, count($commands));517 }518/**519 * test that create() returns instances520 *521 * @return void522 */523 public function testCreateFactory() {524 $parser = ConsoleOptionParser::create('factory', false);525 $this->assertInstanceOf('ConsoleOptionParser', $parser);526 $this->assertEquals('factory', $parser->command());527 }528/**529 * test that command() inflects the command name.530 *531 * @return void532 */533 public function testCommandInflection() {534 $parser = new ConsoleOptionParser('CommandLine');535 $this->assertEquals('command_line', $parser->command());536 }537/**538 * test that parse() takes a subcommand argument, and that the subcommand parser539 * is used.540 *541 * @return void542 */543 public function testParsingWithSubParser() {544 $parser = new ConsoleOptionParser('test', false);545 $parser->addOption('primary')546 ->addArgument('one', array('required' => true, 'choices' => array('a', 'b')))547 ->addArgument('two', array('required' => true))548 ->addSubcommand('sub', array(549 'parser' => array(550 'options' => array(551 'secondary' => array('boolean' => true),552 'fourth' => array('help' => 'fourth option')553 ),554 'arguments' => array(555 'sub_arg' => array('choices' => array('c', 'd'))556 )557 )558 ));...

Full Screen

Full Screen

JavaScriptSymbol.php

Source:JavaScriptSymbol.php Github

copy

Full Screen

1<?php2require_once('Symbol.php');3require_once('JavaScriptFunctionCall.php');4require_once('JavaScriptLiteral.php');5require_once('JavaScriptString.php');6require_once('JavaScriptNumber.php');7require_once('JavaScriptRegExp.php');8require_once('JavaScriptFunction.php');9require_once('JavaScriptTernary.php');10require_once('JavaScriptObject.php');11require_once('JavaScriptArray.php');12require_once('JavaScriptVariable.php');13require_once('JavaScriptAssignment.php');14require_once('JavaScriptOr.php');15class JavaScriptSymbol extends Symbol {16 /**17 * Guesses the type of the current symbol18 */19 public function type() {20 switch($this->id){21 case '{':22 return 'Object';23 case '[':24 return 'Array';25 case 'function':26 return 'Function';27 }28 }29 public function convert($recursing = FALSE) {30 if ($this->arity == 'literal') {31 switch($this->type){32 case 'string':33 return new JavaScriptString($this->value);34 case 'number':35 return new JavaScriptNumber($this->value);36 case 'regex':37 return new JavaScriptRegExp($this->value);38 default:39 return new JavaScriptLiteral($this->value);40 }41 }42 else {43 switch($this->id){44 case '?':45 return new JavaScriptTernary($this->first, $this->second, $this->third);46 case '(':47 return new JavaScriptFunctionCall($this->first, $this->second);48 case 'function':49 return new JavaScriptFunction($this);50 case '{':51 return new JavaScriptObject($this);52 case '[':53 case '.':54 if ($this->arity == 'unary') {55 return new JavaScriptArray($this->first);56 }else{57 return new JavaScriptVariable($this);58 }59 case '=':60 return new JavaScriptAssignment($this->first, $this->second);61 case '||':62 $output = array();63 $first = $this->first;64 if (is_array($first) && count($first == 1)) {65 $first = $first[0];66 }67 $first = $first->convert(TRUE);68 if (is_array($first)) {69 $output = array_merge($output, $first);70 }71 else {72 $output[] = $first;73 }74 $seconds = $this->second;75 if (!is_array($seconds)) {76 $seconds = array($seconds);77 }78 foreach ($seconds as $second) {79 $second = $second->convert(TRUE);80 if (is_array($second)) {81 $output = array_merge($output, $second);82 }83 else {84 $output[] = $second;85 }86 }87 return $recursing ? $output : new JavaScriptOr($output);88 }89 switch ($this->arity) {90 case 'name':91 if ($this->value == 'new') {92 // TODO: Make new matter93 if ($this->first->id == 'function') {94 return new JavaScriptFunction($this->first, true);95 }96 elseif ($this->first->id == '(') {97 return new JavaScriptFunctionCall($this->first, $this->second, true);98 }99 elseif ($this->first->id == '.' || $this->first->id == '[') {100 return new JavaScriptVariable($this->first, true);101 }102 else {103 throw new Exception("Line {$this->first->line_number}, char {$this->first->char_pos}: New statement preceeds unknown");104 }105 }106 return new JavaScriptVariable($this);107 case 'literal':108 case 'operator':109 case 'this':110 case 'unary':111 return new JavaScriptLiteral($this);112 }113 }114 throw new Exception("No class for {$this->id}:{$this->arity}");115 }116 // led/nud/lbp functions117 public function led_bracket($parser, $left) {118 $this->first = $left;119 $this->second = $parser->expression();120 $this->arity = 'binary';121 $parser->advance(']');122 return $this;123 }124 public function nud_bracket($parser) {125 $items = array();126 if (!$parser->peek(']')) {127 while (1) {128 $items[] = $parser->expression();129 if (!$parser->peek(',')) {130 break;131 }132 $parser->advance(',');133 if ($parser->peek(']')) {134 // Be lenient about trailing commas135 break;136 }137 }138 }139 $parser->advance(']');140 $this->first = $items;141 $this->arity = 'unary';142 return $this;143 }144 public function std_break($parser) {145 $parser->skip_terminators();146 $this->arity = 'statement';147 return $this;148 }149 public function lbp_colon($parser, $left) {150 if ($left->arity == 'name' && $parser->peek2(array('for', 'while', 'do'))) {151 return 100;152 }153 return 0;154 }155 public function led_colon($parser, $left) {156 $this->first = $left;157 if ($parser->token->arity != 'name') {158 throw new Exception("Line {$left->line_number}, char {$left->char_pos}: Expected a property name");159 }160 $parser->token->arity = 'literal';161 $this->second = $parser->expression();162 $this->arity = 'binary';163 $parser->skip_terminators();164 return $this;165 }166 public function lbp_crement($parser, $left) {167 if ($left->id == '.' || $left->id == '[' || $left->arity == 'name') {168 return 100;169 }170 return 0;171 }172 public function led_crement($parser, $left) {173 // Show that the in/decrementer is on the right174 $this->first = $left;175 $this->arity = 'unary';176 return $this;177 }178 public function nud_crement($parser) {179 // Show that the in/decrement is before the expression180 $this->first = NULL;181 $this->second = $parser->expression(75);182 return $this;183 }184 public function nud_curly($parser) {185 $values = array();186 $this->comments = array();187 if (!$parser->peek('}')) {188 while (1) {189 $token = $parser->token;190 if ($token->arity != 'name' && $token->arity != 'literal') {191 throw new Exception("Line {$token->line_number}, char {$token->char_pos}: Bad key: {$token->id}");192 }193 $comments = $parser->comments_before($token);194 if (!empty($comments)) {195 if (!empty($this->comments)) {196 $this->comments[] = "\n";197 }198 $this->comments = array_merge($this->comments, $comments);199 }200 $parser->advance();201 $parser->advance(':');202 $expression = $parser->expression();203 if (is_array($expression)) {204 $expression = $expression[0];205 }206 $expression->key = $token->value;207 $values[] = $expression;208 if (!$parser->peek(',')) {209 break;210 }211 $token = $parser->token;212 $parser->advance(',');213 if ($parser->peek('}')) {214 // Be lenient about trailing commas215 break;216 }217 }218 }219 if ($parser->peek('}')) {220 $this->comments = array_merge($this->comments, $parser->comments_before($parser->token));221 }222 $parser->advance('}');223 $this->first = $values;224 $this->arity = 'unary';225 return $this;226 }227 public function std_curly($parser) {228 $statements = $parser->statements(array('}'));229 $parser->advance('}');230 return $statements;231 }232 public function std_do($parser) {233 if ($parser->peek('{')) {234 $this->first = $this->block($parser);235 }236 else {237 $this->first = $parser->expression($parser);238 $parser->skip_terminators();239 }240 $parser->advance('while');241 $parser->advance('(');242 $this->second = $parser->expression();243 $parser->advance(')');244 $parser->skip_terminators();245 return $this;246 }247 public function led_equals($parser, $left) {248 $this->first = $left;249 $this->second = $parser->expression(9);250 $parser->scope->assignment($this->first, $this->second);251 return $this;252 }253 public function std_for($parser) {254 $parser->advance('(');255 if($parser->peek('var')) {256 $token = $parser->token;257 $parser->advance('var');258 $this->first = $token->std($parser);259 if ($parser->peek('in')) {260 $parser->advance('in');261 $this->second = $parser->expression();262 }263 }264 else {265 // Don't forget that expressionless for(;;) loops are valid266 $this->first = $parser->peek(';') ? NULL : $parser->statements(array(')', ';'));267 }268 if (!$parser->peek(')')) {269 // var can possibly swallow the ;270 if ($parser->peek(';')) {271 $parser->advance(';');272 }273 $this->second = $parser->peek(';') ? NULL : $parser->statements(array(';'));274 $parser->advance(';');275 $this->thid = $parser->peek(')') ? NULL : $parser->statements(array(')'));276 }277 $parser->advance(')');278 if ($parser->peek('{')) {279 $this->block = $this->block($parser);280 }281 elseif (!$parser->peek(';')) {282 $this->block = $parser->expression();283 }284 $parser->skip_terminators();285 $this->arity = 'statement';286 return $this;287 }288 public function nud_function($parser) {289 $arguments = array();290 $parser->new_scope();291 $this->scope = $parser->scope;292 if ($parser->token->arity == 'name') {293 $parser->scope->define($parser->token);294 $this->name = $parser->token->value;295 $parser->advance();296 }297 $parser->advance('(');298 if (!$parser->peek(')')) {299 while (1) {300 if ($parser->token->arity != 'name') {301 throw new Exception('Expected a parameter name');302 }303 $parser->scope->define($parser->token);304 $argument = $parser->token;305 $parser->advance();306 $argument->comments = array_merge($parser->comments_before($argument), $parser->comments_after($argument));307 $arguments[] = $argument;308 if (!$parser->peek(',')) {309 break;310 }311 $parser->advance(',');312 }313 }314 $this->first = $arguments;315 $parser->advance(')');316 $parser->peek('{');317 $this->comments = $parser->comments_after($parser->token);318 $parser->advance('{');319 $this->second = $parser->statements(array('}'));320 $parser->advance('}');321 $this->arity = 'function';322 $parser->scope_pop();323 return $this;324 }325 public function std_if($parser) {326 $parser->advance('(');327 $this->first = $parser->expression();328 $parser->advance(')');329 if ($parser->peek('{')) {330 $this->second = $this->block($parser);331 }332 elseif (!$parser->peek(';')) {333 $this->second = $parser->expression();334 }335 $parser->skip_terminators();336 337 if ($parser->peek('else')) {338 $parser->advance('else');339 if ($parser->peek('if')) {340 $this->third = $parser->statement;341 }342 elseif ($parser->peek('{')) {343 $this->third = $this->block($parser);344 }345 elseif (!$parser->peek(';')) {346 $this->third = $parser->expression();347 }348 $parser->skip_terminators();349 }350 else {351 $this->third = NULL;352 }353 $this->arity = 'statement';354 return $this;355 }356 public function executed_function($function, $parser) {357 // The function gets executed358 if ($parser->peek('(')) {359 // led_parenthesis might have already swallowed it360 $parser->advance('(');361 }362 $arguments = array();363 if (!$parser->peek(')')) {364 while (1) {365 $arguments[] = $parser->expression();366 if (!$parser->peek(',')) {367 break;368 }369 $parser->advance(',');370 }371 }372 $parser->advance(')');373 $parser->skip_terminators();374 // Make assignments within the function scope (in $function)375 // between the arguments in the expression and the passed arguments376 foreach ($function->first as $i => $parameter) {377 if ($arguments[$i]) {378 // The passed argument is assigned immediately to the matching parameter379 $function->scope->assignment($parameter, $arguments[$i]);380 }381 }382 $this->first = $function;383 $this->second = $arguments;384 $this->arity = 'execution';385 return $this;386 }387 public function led_parenthesis($parser, $left) {388 if ($left->id == 'function') {389 return $this->executed_function($left, $parser);390 }391 if ($left->id == '{') {392 $expression = $parser->expression();393 $parser->advance(')');394 return $expression;395 }396 if (!$parser->peek(')')) {397 while (1) {398 $arguments[] = $parser->expression();399 if (!$parser->peek(',')) {400 break;401 }402 $parser->advance(',');403 }404 }405 if ($left->arity == 'operator' && $left->id != '.' && $left->id != '[' && count($arguments) == 1) {406 $arguments = $arguments[0];407 }408 // e.g. foo(bar) has a foo first, [bar] second409 $this->arity = 'binary';410 $this->first = $left;411 $this->second = $arguments;412 $parser->advance(')');413 return $this;414 }415 public function nud_parenthesis($parser) {416 // '(' can mean function call, or executed function417 $is_function = $parser->peek('function');418 $expressions = array();419 while (1) {420 $expressions[] = $parser->expression();421 if ($parser->peek(')')) {422 break;423 }424 $parser->advance(',');425 }426 $parser->advance(')');427 if ($is_function && $parser->peek('(')) {428 return $this->executed_function($expressions[0], $parser);429 }430 return $expressions;431 }432 public function led_period($parser, $left) {433 $this->first = $left;434 if ($parser->token->arity != 'name') {435 throw new Exception('Expected a property name');436 }437 $parser->token->arity = 'literal';438 $this->second = $parser->token;439 $this->arity ='binary';440 $parser->advance();441 return $this;442 }443 public function led_questionmark($parser, $left) {444 $this->first = $left;445 $this->second = $parser->expression();446 $parser->advance(':');447 $this->third = $parser->expression();448 $this->arity = 'ternary';449 return $this;450 }451 public function nud_this($parser) {452 $parser->scope->reserve($this);453 $this->arity = 'this';454 return $this;455 }456 public function std_try($parser) {457 $this->first = $this->block($parser);458 if ($parser->peek('catch')) {459 $parser->advance('catch');460 $catch = $parser->new_symbol('catch');461 $parser->advance('(');462 $catch->first = $parser->expression();463 $parser->advance(')');464 $catch->second = $this->block($parser);465 $this->second = $catch;466 }467 if ($parser->peek('finally')) {468 $parser->advance('finally');469 $this->third = $this->block($parser);470 }471 $parser->skip_terminators();472 $this->arity = 'statement';473 return $this;474 }475 public function std_return($parser) {476 if (!$parser->peek("\n") && !$parser->peek(';') && !$parser->peek('}')) {477 $this->first = $parser->expression();478 }479 $parser->skip_terminators();480 $this->arity = 'statement';481 return $this;482 }483 public function std_switch($parser) {484 // switch statements can have multiple485 // levels of passthrough and expressions486 // need to be aggregated for each current487 // case statement until a break is reached488 $branches = array();489 $parser->advance('(');490 $this->first = $parser->expression();491 $parser->advance(')');492 $parser->advance('{');493 $this->second = array();494 $cases = array();495 while (1) {496 if ($parser->peek('}')) {497 break;498 }499 if ($parser->peek('default')) {500 $cases[] = $parser->token;501 $switch = 'default';502 $parser->advance('default');503 }504 else {505 $cases[] = $parser->token;506 $parser->advance('case');507 $switch = 'case';508 $cases[] = $parser->expression();509 }510 $parser->advance(':');511 $statements = $parser->statements(array('default', 'case', '}'));512 if ($switch == 'default') {513 $default = $parser->new_symbol('default');514 $default->first = $statements;515 $cases[] = $default;516 }517 elseif ($switch == 'case' && !empty($statements)) {518 $case = $parser->new_symbol('case');519 $case->first = $statements;520 $cases[] = $case;521 }522 }523 $this->second = $cases;524 $parser->advance('}');525 $this->arity = 'statement';526 return $this;527 }528 public function std_var($parser) {529 $assignments = array();530 while (1) {531 $parser->peek();532 $token = $parser->token;533 if ($token->arity != 'name') {534 throw new Exception("Line {$token->line_number}, char {$token->char_pos}: Expected a new variable name");535 }536 $parser->scope->define($token);537 $parser->advance();538 if ($parser->peek('=')) {539 $t = $parser->token;540 $parser->advance('=');541 $t->first = $token;542 $t->second = $parser->expression();543 $parser->scope->assignment($t->first, $t->second);544 $t->arity = 'binary';545 $assignments[] = $t;546 }547 else {548 $t = $parser->new_symbol('=');549 $t->first = $token;550 $t->second = NULL;551 $assignments[] = $t;552 }553 if (!$parser->peek(',')) {554 break;555 }556 $parser->advance(',');557 }558 $parser->skip_terminators();559 return $assignments;560 }561 public function std_while($parser) {562 $parser->advance('(');563 $this->first = $parser->statements(array(')'));564 $parser->advance(')');565 if ($parser->peek('{')) {566 $this->second = $this->block($parser);567 }568 else {569 $this->second = $parser->expression();570 }571 $parser->skip_terminators();572 $this->arity = 'statement';573 return $this;574 }575}...

Full Screen

Full Screen

Autoloader.php

Source:Autoloader.php Github

copy

Full Screen

1<?php2namespace PhpParser;3/**4 * @codeCoverageIgnore5 */6class Autoloader7{8 /** @var bool Whether the autoloader has been registered. */9 private static $registered = false;10 /** @var bool Whether we're running on PHP 7. */11 private static $runningOnPhp7;12 /**13 * Registers PhpParser\Autoloader as an SPL autoloader.14 *15 * @param bool $prepend Whether to prepend the autoloader instead of appending16 */17 static public function register($prepend = false) {18 if (self::$registered === true) {19 return;20 }21 spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);22 self::$registered = true;23 self::$runningOnPhp7 = version_compare(PHP_VERSION, '7.0-dev', '>=');24 }25 /**26 * Handles autoloading of classes.27 *28 * @param string $class A class name.29 */30 static public function autoload($class) {31 if (0 === strpos($class, 'PhpParser\\')) {32 if (isset(self::$php7AliasesOldToNew[$class])) {33 if (self::$runningOnPhp7) {34 return;35 }36 // Load the new class, alias will be registered afterwards37 $class = self::$php7AliasesOldToNew[$class];38 }39 $fileName = dirname(__DIR__) . '/' . strtr($class, '\\', '/') . '.php';40 if (file_exists($fileName)) {41 require $fileName;42 }43 if (isset(self::$php7AliasesNewToOld[$class])) {44 // New class name was used, register alias for old one, otherwise45 // it won't be usable in "instanceof" and other non-autoloading places.46 if (!self::$runningOnPhp7) {47 class_alias($class, self::$php7AliasesNewToOld[$class]);48 }49 }50 } else if (0 === strpos($class, 'PHPParser_')) {51 if (isset(self::$nonNamespacedAliases[$class])) {52 // Register all aliases at once to avoid dependency issues53 self::registerNonNamespacedAliases();54 }55 }56 }57 private static function registerNonNamespacedAliases() {58 foreach (self::$nonNamespacedAliases as $old => $new) {59 class_alias($new, $old);60 }61 }62 private static $php7AliasesOldToNew = array(63 'PhpParser\Node\Expr\Cast\Bool' => 'PhpParser\Node\Expr\Cast\Bool_',64 'PhpParser\Node\Expr\Cast\Int' => 'PhpParser\Node\Expr\Cast\Int_',65 'PhpParser\Node\Expr\Cast\Object' => 'PhpParser\Node\Expr\Cast\Object_',66 'PhpParser\Node\Expr\Cast\String' => 'PhpParser\Node\Expr\Cast\String_',67 'PhpParser\Node\Scalar\String' => 'PhpParser\Node\Scalar\String_',68 );69 private static $php7AliasesNewToOld = array(70 'PhpParser\Node\Expr\Cast\Bool_' => 'PhpParser\Node\Expr\Cast\Bool',71 'PhpParser\Node\Expr\Cast\Int_' => 'PhpParser\Node\Expr\Cast\Int',72 'PhpParser\Node\Expr\Cast\Object_' => 'PhpParser\Node\Expr\Cast\Object',73 'PhpParser\Node\Expr\Cast\String_' => 'PhpParser\Node\Expr\Cast\String',74 'PhpParser\Node\Scalar\String_' => 'PhpParser\Node\Scalar\String',75 );76 private static $nonNamespacedAliases = array(77 'PHPParser_Builder' => 'PhpParser\Builder',78 'PHPParser_BuilderAbstract' => 'PhpParser\BuilderAbstract',79 'PHPParser_BuilderFactory' => 'PhpParser\BuilderFactory',80 'PHPParser_Comment' => 'PhpParser\Comment',81 'PHPParser_Comment_Doc' => 'PhpParser\Comment\Doc',82 'PHPParser_Error' => 'PhpParser\Error',83 'PHPParser_Lexer' => 'PhpParser\Lexer',84 'PHPParser_Lexer_Emulative' => 'PhpParser\Lexer\Emulative',85 'PHPParser_Node' => 'PhpParser\Node',86 'PHPParser_NodeAbstract' => 'PhpParser\NodeAbstract',87 'PHPParser_NodeDumper' => 'PhpParser\NodeDumper',88 'PHPParser_NodeTraverser' => 'PhpParser\NodeTraverser',89 'PHPParser_NodeTraverserInterface' => 'PhpParser\NodeTraverserInterface',90 'PHPParser_NodeVisitor' => 'PhpParser\NodeVisitor',91 'PHPParser_NodeVisitor_NameResolver' => 'PhpParser\NodeVisitor\NameResolver',92 'PHPParser_NodeVisitorAbstract' => 'PhpParser\NodeVisitorAbstract',93 'PHPParser_Parser' => 'PhpParser\Parser',94 'PHPParser_PrettyPrinterAbstract' => 'PhpParser\PrettyPrinterAbstract',95 'PHPParser_PrettyPrinter_Default' => 'PhpParser\PrettyPrinter\Standard',96 'PHPParser_PrettyPrinter_Zend' => 'PhpParser\PrettyPrinter\Standard',97 'PHPParser_Serializer' => 'PhpParser\Serializer',98 'PHPParser_Serializer_XML' => 'PhpParser\Serializer\XML',99 'PHPParser_Unserializer' => 'PhpParser\Unserializer',100 'PHPParser_Unserializer_XML' => 'PhpParser\Unserializer\XML',101 'PHPParser_Builder_Class' => 'PhpParser\Builder\Class_',102 'PHPParser_Builder_Function' => 'PhpParser\Builder\Function_',103 'PHPParser_Builder_Interface' => 'PhpParser\Builder\Interface_',104 'PHPParser_Builder_Method' => 'PhpParser\Builder\Method',105 'PHPParser_Builder_Param' => 'PhpParser\Builder\Param',106 'PHPParser_Builder_Property' => 'PhpParser\Builder\Property',107 'PHPParser_Node_Arg' => 'PhpParser\Node\Arg',108 'PHPParser_Node_Const' => 'PhpParser\Node\Const_',109 'PHPParser_Node_Expr' => 'PhpParser\Node\Expr',110 'PHPParser_Node_Name' => 'PhpParser\Node\Name',111 'PHPParser_Node_Name_FullyQualified' => 'PhpParser\Node\Name\FullyQualified',112 'PHPParser_Node_Name_Relative' => 'PhpParser\Node\Name\Relative',113 'PHPParser_Node_Param' => 'PhpParser\Node\Param',114 'PHPParser_Node_Scalar' => 'PhpParser\Node\Scalar',115 'PHPParser_Node_Stmt' => 'PhpParser\Node\Stmt',116 'PHPParser_Node_Stmt_Break' => 'PhpParser\Node\Stmt\Break_',117 'PHPParser_Node_Stmt_Case' => 'PhpParser\Node\Stmt\Case_',118 'PHPParser_Node_Stmt_Catch' => 'PhpParser\Node\Stmt\Catch_',119 'PHPParser_Node_Stmt_Class' => 'PhpParser\Node\Stmt\Class_',120 'PHPParser_Node_Stmt_ClassConst' => 'PhpParser\Node\Stmt\ClassConst',121 'PHPParser_Node_Stmt_ClassMethod' => 'PhpParser\Node\Stmt\ClassMethod',122 'PHPParser_Node_Stmt_Const' => 'PhpParser\Node\Stmt\Const_',123 'PHPParser_Node_Stmt_Continue' => 'PhpParser\Node\Stmt\Continue_',124 'PHPParser_Node_Stmt_Declare' => 'PhpParser\Node\Stmt\Declare_',125 'PHPParser_Node_Stmt_DeclareDeclare' => 'PhpParser\Node\Stmt\DeclareDeclare',126 'PHPParser_Node_Stmt_Do' => 'PhpParser\Node\Stmt\Do_',127 'PHPParser_Node_Stmt_Echo' => 'PhpParser\Node\Stmt\Echo_',128 'PHPParser_Node_Stmt_Else' => 'PhpParser\Node\Stmt\Else_',129 'PHPParser_Node_Stmt_ElseIf' => 'PhpParser\Node\Stmt\ElseIf_',130 'PHPParser_Node_Stmt_For' => 'PhpParser\Node\Stmt\For_',131 'PHPParser_Node_Stmt_Foreach' => 'PhpParser\Node\Stmt\Foreach_',132 'PHPParser_Node_Stmt_Function' => 'PhpParser\Node\Stmt\Function_',133 'PHPParser_Node_Stmt_Global' => 'PhpParser\Node\Stmt\Global_',134 'PHPParser_Node_Stmt_Goto' => 'PhpParser\Node\Stmt\Goto_',135 'PHPParser_Node_Stmt_HaltCompiler' => 'PhpParser\Node\Stmt\HaltCompiler',136 'PHPParser_Node_Stmt_If' => 'PhpParser\Node\Stmt\If_',137 'PHPParser_Node_Stmt_InlineHTML' => 'PhpParser\Node\Stmt\InlineHTML',138 'PHPParser_Node_Stmt_Interface' => 'PhpParser\Node\Stmt\Interface_',139 'PHPParser_Node_Stmt_Label' => 'PhpParser\Node\Stmt\Label',140 'PHPParser_Node_Stmt_Namespace' => 'PhpParser\Node\Stmt\Namespace_',141 'PHPParser_Node_Stmt_Property' => 'PhpParser\Node\Stmt\Property',142 'PHPParser_Node_Stmt_PropertyProperty' => 'PhpParser\Node\Stmt\PropertyProperty',143 'PHPParser_Node_Stmt_Return' => 'PhpParser\Node\Stmt\Return_',144 'PHPParser_Node_Stmt_Static' => 'PhpParser\Node\Stmt\Static_',145 'PHPParser_Node_Stmt_StaticVar' => 'PhpParser\Node\Stmt\StaticVar',146 'PHPParser_Node_Stmt_Switch' => 'PhpParser\Node\Stmt\Switch_',147 'PHPParser_Node_Stmt_Throw' => 'PhpParser\Node\Stmt\Throw_',148 'PHPParser_Node_Stmt_Trait' => 'PhpParser\Node\Stmt\Trait_',149 'PHPParser_Node_Stmt_TraitUse' => 'PhpParser\Node\Stmt\TraitUse',150 'PHPParser_Node_Stmt_TraitUseAdaptation' => 'PhpParser\Node\Stmt\TraitUseAdaptation',151 'PHPParser_Node_Stmt_TraitUseAdaptation_Alias' => 'PhpParser\Node\Stmt\TraitUseAdaptation\Alias',152 'PHPParser_Node_Stmt_TraitUseAdaptation_Precedence' => 'PhpParser\Node\Stmt\TraitUseAdaptation\Precedence',153 'PHPParser_Node_Stmt_TryCatch' => 'PhpParser\Node\Stmt\TryCatch',154 'PHPParser_Node_Stmt_Unset' => 'PhpParser\Node\Stmt\Unset_',155 'PHPParser_Node_Stmt_UseUse' => 'PhpParser\Node\Stmt\UseUse',156 'PHPParser_Node_Stmt_Use' => 'PhpParser\Node\Stmt\Use_',157 'PHPParser_Node_Stmt_While' => 'PhpParser\Node\Stmt\While_',158 'PHPParser_Node_Expr_AssignBitwiseAnd' => 'PhpParser\Node\Expr\AssignOp\BitwiseAnd',159 'PHPParser_Node_Expr_AssignBitwiseOr' => 'PhpParser\Node\Expr\AssignOp\BitwiseOr',160 'PHPParser_Node_Expr_AssignBitwiseXor' => 'PhpParser\Node\Expr\AssignOp\BitwiseXor',161 'PHPParser_Node_Expr_AssignConcat' => 'PhpParser\Node\Expr\AssignOp\Concat',162 'PHPParser_Node_Expr_AssignDiv' => 'PhpParser\Node\Expr\AssignOp\Div',163 'PHPParser_Node_Expr_AssignMinus' => 'PhpParser\Node\Expr\AssignOp\Minus',164 'PHPParser_Node_Expr_AssignMod' => 'PhpParser\Node\Expr\AssignOp\Mod',165 'PHPParser_Node_Expr_AssignMul' => 'PhpParser\Node\Expr\AssignOp\Mul',166 'PHPParser_Node_Expr_AssignPlus' => 'PhpParser\Node\Expr\AssignOp\Plus',167 'PHPParser_Node_Expr_AssignShiftLeft' => 'PhpParser\Node\Expr\AssignOp\ShiftLeft',168 'PHPParser_Node_Expr_AssignShiftRight' => 'PhpParser\Node\Expr\AssignOp\ShiftRight',169 'PHPParser_Node_Expr_Cast' => 'PhpParser\Node\Expr\Cast',170 'PHPParser_Node_Expr_Cast_Array' => 'PhpParser\Node\Expr\Cast\Array_',171 'PHPParser_Node_Expr_Cast_Bool' => 'PhpParser\Node\Expr\Cast\Bool_',172 'PHPParser_Node_Expr_Cast_Double' => 'PhpParser\Node\Expr\Cast\Double',173 'PHPParser_Node_Expr_Cast_Int' => 'PhpParser\Node\Expr\Cast\Int_',174 'PHPParser_Node_Expr_Cast_Object' => 'PhpParser\Node\Expr\Cast\Object_',175 'PHPParser_Node_Expr_Cast_String' => 'PhpParser\Node\Expr\Cast\String_',176 'PHPParser_Node_Expr_Cast_Unset' => 'PhpParser\Node\Expr\Cast\Unset_',177 'PHPParser_Node_Expr_BitwiseAnd' => 'PhpParser\Node\Expr\BinaryOp\BitwiseAnd',178 'PHPParser_Node_Expr_BitwiseOr' => 'PhpParser\Node\Expr\BinaryOp\BitwiseOr',179 'PHPParser_Node_Expr_BitwiseXor' => 'PhpParser\Node\Expr\BinaryOp\BitwiseXor',180 'PHPParser_Node_Expr_BooleanAnd' => 'PhpParser\Node\Expr\BinaryOp\BooleanAnd',181 'PHPParser_Node_Expr_BooleanOr' => 'PhpParser\Node\Expr\BinaryOp\BooleanOr',182 'PHPParser_Node_Expr_Concat' => 'PhpParser\Node\Expr\BinaryOp\Concat',183 'PHPParser_Node_Expr_Div' => 'PhpParser\Node\Expr\BinaryOp\Div',184 'PHPParser_Node_Expr_Equal' => 'PhpParser\Node\Expr\BinaryOp\Equal',185 'PHPParser_Node_Expr_Greater' => 'PhpParser\Node\Expr\BinaryOp\Greater',186 'PHPParser_Node_Expr_GreaterOrEqual' => 'PhpParser\Node\Expr\BinaryOp\GreaterOrEqual',187 'PHPParser_Node_Expr_Identical' => 'PhpParser\Node\Expr\BinaryOp\Identical',188 'PHPParser_Node_Expr_LogicalAnd' => 'PhpParser\Node\Expr\BinaryOp\LogicalAnd',189 'PHPParser_Node_Expr_LogicalOr' => 'PhpParser\Node\Expr\BinaryOp\LogicalOr',190 'PHPParser_Node_Expr_LogicalXor' => 'PhpParser\Node\Expr\BinaryOp\LogicalXor',191 'PHPParser_Node_Expr_Minus' => 'PhpParser\Node\Expr\BinaryOp\Minus',192 'PHPParser_Node_Expr_Mod' => 'PhpParser\Node\Expr\BinaryOp\Mod',193 'PHPParser_Node_Expr_Mul' => 'PhpParser\Node\Expr\BinaryOp\Mul',194 'PHPParser_Node_Expr_NotEqual' => 'PhpParser\Node\Expr\BinaryOp\NotEqual',195 'PHPParser_Node_Expr_NotIdentical' => 'PhpParser\Node\Expr\BinaryOp\NotIdentical',196 'PHPParser_Node_Expr_Plus' => 'PhpParser\Node\Expr\BinaryOp\Plus',197 'PHPParser_Node_Expr_ShiftLeft' => 'PhpParser\Node\Expr\BinaryOp\ShiftLeft',198 'PHPParser_Node_Expr_ShiftRight' => 'PhpParser\Node\Expr\BinaryOp\ShiftRight',199 'PHPParser_Node_Expr_Smaller' => 'PhpParser\Node\Expr\BinaryOp\Smaller',200 'PHPParser_Node_Expr_SmallerOrEqual' => 'PhpParser\Node\Expr\BinaryOp\SmallerOrEqual',201 'PHPParser_Node_Expr_Array' => 'PhpParser\Node\Expr\Array_',202 'PHPParser_Node_Expr_ArrayDimFetch' => 'PhpParser\Node\Expr\ArrayDimFetch',203 'PHPParser_Node_Expr_ArrayItem' => 'PhpParser\Node\Expr\ArrayItem',204 'PHPParser_Node_Expr_Assign' => 'PhpParser\Node\Expr\Assign',205 'PHPParser_Node_Expr_AssignRef' => 'PhpParser\Node\Expr\AssignRef',206 'PHPParser_Node_Expr_BitwiseNot' => 'PhpParser\Node\Expr\BitwiseNot',207 'PHPParser_Node_Expr_BooleanNot' => 'PhpParser\Node\Expr\BooleanNot',208 'PHPParser_Node_Expr_ClassConstFetch' => 'PhpParser\Node\Expr\ClassConstFetch',209 'PHPParser_Node_Expr_Clone' => 'PhpParser\Node\Expr\Clone_',210 'PHPParser_Node_Expr_Closure' => 'PhpParser\Node\Expr\Closure',211 'PHPParser_Node_Expr_ClosureUse' => 'PhpParser\Node\Expr\ClosureUse',212 'PHPParser_Node_Expr_ConstFetch' => 'PhpParser\Node\Expr\ConstFetch',213 'PHPParser_Node_Expr_Empty' => 'PhpParser\Node\Expr\Empty_',214 'PHPParser_Node_Expr_ErrorSuppress' => 'PhpParser\Node\Expr\ErrorSuppress',215 'PHPParser_Node_Expr_Eval' => 'PhpParser\Node\Expr\Eval_',216 'PHPParser_Node_Expr_Exit' => 'PhpParser\Node\Expr\Exit_',217 'PHPParser_Node_Expr_FuncCall' => 'PhpParser\Node\Expr\FuncCall',218 'PHPParser_Node_Expr_Include' => 'PhpParser\Node\Expr\Include_',219 'PHPParser_Node_Expr_Instanceof' => 'PhpParser\Node\Expr\Instanceof_',220 'PHPParser_Node_Expr_Isset' => 'PhpParser\Node\Expr\Isset_',221 'PHPParser_Node_Expr_List' => 'PhpParser\Node\Expr\List_',222 'PHPParser_Node_Expr_MethodCall' => 'PhpParser\Node\Expr\MethodCall',223 'PHPParser_Node_Expr_New' => 'PhpParser\Node\Expr\New_',224 'PHPParser_Node_Expr_PostDec' => 'PhpParser\Node\Expr\PostDec',225 'PHPParser_Node_Expr_PostInc' => 'PhpParser\Node\Expr\PostInc',226 'PHPParser_Node_Expr_PreDec' => 'PhpParser\Node\Expr\PreDec',227 'PHPParser_Node_Expr_PreInc' => 'PhpParser\Node\Expr\PreInc',228 'PHPParser_Node_Expr_Print' => 'PhpParser\Node\Expr\Print_',229 'PHPParser_Node_Expr_PropertyFetch' => 'PhpParser\Node\Expr\PropertyFetch',230 'PHPParser_Node_Expr_ShellExec' => 'PhpParser\Node\Expr\ShellExec',231 'PHPParser_Node_Expr_StaticCall' => 'PhpParser\Node\Expr\StaticCall',232 'PHPParser_Node_Expr_StaticPropertyFetch' => 'PhpParser\Node\Expr\StaticPropertyFetch',233 'PHPParser_Node_Expr_Ternary' => 'PhpParser\Node\Expr\Ternary',234 'PHPParser_Node_Expr_UnaryMinus' => 'PhpParser\Node\Expr\UnaryMinus',235 'PHPParser_Node_Expr_UnaryPlus' => 'PhpParser\Node\Expr\UnaryPlus',236 'PHPParser_Node_Expr_Variable' => 'PhpParser\Node\Expr\Variable',237 'PHPParser_Node_Expr_Yield' => 'PhpParser\Node\Expr\Yield_',238 'PHPParser_Node_Scalar_ClassConst' => 'PhpParser\Node\Scalar\MagicConst\Class_',239 'PHPParser_Node_Scalar_DirConst' => 'PhpParser\Node\Scalar\MagicConst\Dir',240 'PHPParser_Node_Scalar_FileConst' => 'PhpParser\Node\Scalar\MagicConst\File',241 'PHPParser_Node_Scalar_FuncConst' => 'PhpParser\Node\Scalar\MagicConst\Function_',242 'PHPParser_Node_Scalar_LineConst' => 'PhpParser\Node\Scalar\MagicConst\Line',243 'PHPParser_Node_Scalar_MethodConst' => 'PhpParser\Node\Scalar\MagicConst\Method',244 'PHPParser_Node_Scalar_NSConst' => 'PhpParser\Node\Scalar\MagicConst\Namespace_',245 'PHPParser_Node_Scalar_TraitConst' => 'PhpParser\Node\Scalar\MagicConst\Trait_',246 'PHPParser_Node_Scalar_DNumber' => 'PhpParser\Node\Scalar\DNumber',247 'PHPParser_Node_Scalar_Encapsed' => 'PhpParser\Node\Scalar\Encapsed',248 'PHPParser_Node_Scalar_LNumber' => 'PhpParser\Node\Scalar\LNumber',249 'PHPParser_Node_Scalar_String' => 'PhpParser\Node\Scalar\String_',250 );251}252class_alias('PhpParser\Autoloader', 'PHPParser_Autoloader');...

Full Screen

Full Screen

xml_test.php

Source:xml_test.php Github

copy

Full Screen

...19 $listener->expectNever('paintGroupStart');20 $listener->expectNever('paintGroupEnd');21 $listener->expectNever('paintCaseStart');22 $listener->expectNever('paintCaseEnd');23 $parser = new SimpleTestXmlParser($listener);24 $this->assertTrue($parser->parse("<?xml version=\"1.0\"?>\n"));25 $this->assertTrue($parser->parse("<run>\n"));26 $this->assertTrue($parser->parse("</run>\n"));27 }28 function testEmptyGroup() {29 $listener = new MockSimpleScorer();30 $listener->expectOnce('paintGroupStart', array('a_group', 7));31 $listener->expectOnce('paintGroupEnd', array('a_group'));32 $parser = new SimpleTestXmlParser($listener);33 $parser->parse("<?xml version=\"1.0\"?>\n");34 $parser->parse("<run>\n");35 $this->assertTrue($parser->parse("<group size=\"7\">\n"));36 $this->assertTrue($parser->parse("<name>a_group</name>\n"));37 $this->assertTrue($parser->parse("</group>\n"));38 $parser->parse("</run>\n");39 }40 function testEmptyCase() {41 $listener = new MockSimpleScorer();42 $listener->expectOnce('paintCaseStart', array('a_case'));43 $listener->expectOnce('paintCaseEnd', array('a_case'));44 $parser = new SimpleTestXmlParser($listener);45 $parser->parse("<?xml version=\"1.0\"?>\n");46 $parser->parse("<run>\n");47 $this->assertTrue($parser->parse("<case>\n"));48 $this->assertTrue($parser->parse("<name>a_case</name>\n"));49 $this->assertTrue($parser->parse("</case>\n"));50 $parser->parse("</run>\n");51 }52 function testEmptyMethod() {53 $listener = new MockSimpleScorer();54 $listener->expectOnce('paintCaseStart', array('a_case'));55 $listener->expectOnce('paintCaseEnd', array('a_case'));56 $listener->expectOnce('paintMethodStart', array('a_method'));57 $listener->expectOnce('paintMethodEnd', array('a_method'));58 $parser = new SimpleTestXmlParser($listener);59 $parser->parse("<?xml version=\"1.0\"?>\n");60 $parser->parse("<run>\n");61 $parser->parse("<case>\n");62 $parser->parse("<name>a_case</name>\n");63 $this->assertTrue($parser->parse("<test>\n"));64 $this->assertTrue($parser->parse("<name>a_method</name>\n"));65 $this->assertTrue($parser->parse("</test>\n"));66 $parser->parse("</case>\n");67 $parser->parse("</run>\n");68 }69 function testNestedGroup() {70 $listener = new MockSimpleScorer();71 $listener->expectAt(0, 'paintGroupStart', array('a_group', 7));72 $listener->expectAt(1, 'paintGroupStart', array('b_group', 3));73 $listener->expectCallCount('paintGroupStart', 2);74 $listener->expectAt(0, 'paintGroupEnd', array('b_group'));75 $listener->expectAt(1, 'paintGroupEnd', array('a_group'));76 $listener->expectCallCount('paintGroupEnd', 2);77 $parser = new SimpleTestXmlParser($listener);78 $parser->parse("<?xml version=\"1.0\"?>\n");79 $parser->parse("<run>\n");80 $this->assertTrue($parser->parse("<group size=\"7\">\n"));81 $this->assertTrue($parser->parse("<name>a_group</name>\n"));82 $this->assertTrue($parser->parse("<group size=\"3\">\n"));83 $this->assertTrue($parser->parse("<name>b_group</name>\n"));84 $this->assertTrue($parser->parse("</group>\n"));85 $this->assertTrue($parser->parse("</group>\n"));86 $parser->parse("</run>\n");87 }88}89class AnyOldSignal {90 public $stuff = true;91}92class TestOfXmlResultsParsing extends UnitTestCase {93 function sendValidStart(&$parser) {94 $parser->parse("<?xml version=\"1.0\"?>\n");95 $parser->parse("<run>\n");96 $parser->parse("<case>\n");97 $parser->parse("<name>a_case</name>\n");98 $parser->parse("<test>\n");99 $parser->parse("<name>a_method</name>\n");100 }101 function sendValidEnd(&$parser) {102 $parser->parse("</test>\n");103 $parser->parse("</case>\n");104 $parser->parse("</run>\n");105 }106 function testPass() {107 $listener = new MockSimpleScorer();108 $listener->expectOnce('paintPass', array('a_message'));109 $parser = new SimpleTestXmlParser($listener);110 $this->sendValidStart($parser);111 $this->assertTrue($parser->parse("<pass>a_message</pass>\n"));112 $this->sendValidEnd($parser);113 }114 function testFail() {115 $listener = new MockSimpleScorer();116 $listener->expectOnce('paintFail', array('a_message'));117 $parser = new SimpleTestXmlParser($listener);118 $this->sendValidStart($parser);119 $this->assertTrue($parser->parse("<fail>a_message</fail>\n"));120 $this->sendValidEnd($parser);121 }122 function testException() {123 $listener = new MockSimpleScorer();124 $listener->expectOnce('paintError', array('a_message'));125 $parser = new SimpleTestXmlParser($listener);126 $this->sendValidStart($parser);127 $this->assertTrue($parser->parse("<exception>a_message</exception>\n"));128 $this->sendValidEnd($parser);129 }130 function testSkip() {131 $listener = new MockSimpleScorer();132 $listener->expectOnce('paintSkip', array('a_message'));133 $parser = new SimpleTestXmlParser($listener);134 $this->sendValidStart($parser);135 $this->assertTrue($parser->parse("<skip>a_message</skip>\n"));136 $this->sendValidEnd($parser);137 }138 function testSignal() {139 $signal = new AnyOldSignal();140 $signal->stuff = "Hello";141 $listener = new MockSimpleScorer();142 $listener->expectOnce('paintSignal', array('a_signal', $signal));143 $parser = new SimpleTestXmlParser($listener);144 $this->sendValidStart($parser);145 $this->assertTrue($parser->parse(146 "<signal type=\"a_signal\"><![CDATA[" .147 serialize($signal) . "]]></signal>\n"));148 $this->sendValidEnd($parser);149 }150 function testMessage() {151 $listener = new MockSimpleScorer();152 $listener->expectOnce('paintMessage', array('a_message'));153 $parser = new SimpleTestXmlParser($listener);154 $this->sendValidStart($parser);155 $this->assertTrue($parser->parse("<message>a_message</message>\n"));156 $this->sendValidEnd($parser);157 }158 function testFormattedMessage() {159 $listener = new MockSimpleScorer();160 $listener->expectOnce('paintFormattedMessage', array("\na\tmessage\n"));161 $parser = new SimpleTestXmlParser($listener);162 $this->sendValidStart($parser);163 $this->assertTrue($parser->parse("<formatted><![CDATA[\na\tmessage\n]]></formatted>\n"));164 $this->sendValidEnd($parser);165 }166}167?>...

Full Screen

Full Screen

combinator.php

Source:combinator.php Github

copy

Full Screen

1<?php2 declare( strict_types = 1 );3 namespace verfriemelt\pp\Parser\functions;4 use \Closure;5 use \verfriemelt\pp\Parser\Parser;6 use \verfriemelt\pp\Parser\ParserInput;7 use \verfriemelt\pp\Parser\ParserInputInterface;8 use \verfriemelt\pp\Parser\ParserState;9 function choice( Parser ... $parsers ): Parser {10 return new Parser( 'choice', static function ( ParserInputInterface $input, ParserState $state ) use ( &$parsers ): ParserState {11 foreach ( $parsers as $parser ) {12 $newState = $parser->run( $input, $state );13 if ( !$newState->isError() && $newState->getIndex() > $state->getIndex() ) {14 return $newState;15 }16 }17 return $state->error( "chould not match with any parser at position {$state->getIndex()}" );18 } );19 }20 function sequenceOf( Parser ... $parsers ): Parser {21 return new Parser( 'choice', static function ( ParserInputInterface $input, ParserState $state ) use ( &$parsers ): ParserState {22 if ( $state->isError() ) {23 return $state;24 }25 $currentState = $state;26 $results = [];27 foreach ( $parsers as $parser ) {28 $currentState = $parser->run( $input, $currentState );29 $results[] = $currentState->getResult();30 }31 return $currentState->result( $results );32 } );33 }34 function many( Parser $parser ): Parser {35 return new Parser( 'many', static function ( ParserInputInterface $input, ParserState $currentState ) use ( &$parser ): ParserState {36 $results = [];37 $isDone = false;38 while ( !$isDone ) {39 $nextState = $parser->run( $input, $currentState );40 if ( !$nextState->isError() && $nextState->getIndex() > $currentState->getIndex() ) {41 $results[] = $nextState->getResult();42 $currentState = $nextState;43 } else {44 $isDone = true;45 }46 }47 return $currentState->result( $results );48 } );49 }50 function manyOne( Parser $parser ): Parser {51 return new Parser( 'many', static function ( ParserInputInterface $input, ParserState $currentState ) use ( &$parser ): ParserState {52 $results = [];53 $isDone = false;54 while ( !$isDone ) {55 $nextState = $parser->run( $input, $currentState );56 if ( !$nextState->isError() && $nextState->getIndex() > $currentState->getIndex() ) {57 $results[] = $nextState->getResult();58 $currentState = $nextState;59 } else {60 $isDone = true;61 }62 }63 if ( count( $results ) === 0 ) {64 return $currentState->error( 'must at least match one parser at index ' . $currentState->getIndex() );65 }66 return $currentState->result( $results );67 } );68 }69 function seperatedBy( Parser $seperator ): Closure {70 return static fn( Parser $value ) => new Parser( 'seperatered', static function ( ParserInputInterface $input, ParserState $state ) use ( &$value, &$seperator ): ParserState {71 $results = [];72 $currentState = $state;73 while ( true ) {74 $nextState = $value->run( $input, $currentState );75 if ( !$nextState->isError() && $nextState->getIndex() > $currentState->getIndex() ) {76 $results[] = $nextState->getResult();77 $currentState = $nextState;78 } else {79 break;80 }81 $nextState = $seperator->run( $input, $currentState );82 if ( !$nextState->isError() && $nextState->getIndex() > $currentState->getIndex() ) {83 $currentState = $nextState;84 } else {85 break;86 }87 }88 return $currentState->result( $results );89 } );90 }91 function between( Parser $left, Parser $right ): Closure {92 return static fn( Parser $between ) => sequenceOf(93 $left,94 $between,95 $right,96 )->map( fn( $r ) => $r[1] );97 }98 function lazy( \Closure $lazy ): Parser {99 return new Parser( 'lazy', static function ( ParserInputInterface $input, ParserState $state ) use ( &$lazy ): ParserState {100 return $lazy()->run( $input, $state );101 } );102 }103 function succeed( mixed $value ): Parser {104 return new Parser( 'succeed', static fn( ParserInput $input, ParserState $state ): ParserState => $state->result( $value ) );105 }106 function fail( string $msg ): Parser {107 return new Parser( 'succeed', static fn( ParserInput $input, ParserState $state ): ParserState => $state->error( $msg ) );108 }109 function contextual( \Closure $generator ): Closure {110 return static fn() => succeed( null )->chain( static function () use ( $generator ) {111 $iterator = null;112 $step = static function ( $nextValue = null ) use ( &$step, &$iterator, &$generator ) {113 if ( $iterator === null ) {114 $iterator = $generator();115 $parser = $iterator->current();116 } else {117 $parser = $iterator->send( $nextValue );118 }119 if ( !$iterator->valid() ) {120 return succeed( $nextValue );121 }122 return $parser->chain( $step );123 };124 return $step();125 } );126 }127 function optional( Parser $parser ): Parser {128 $opt = new Parser( 'optional', static function ( ParserInputInterface $input, ParserState $currentState ) use ( &$parser ): ParserState {129 $nextState = $parser->run( $input, $currentState );130 if ( !$nextState->isError() ) {131 return $nextState;132 }133 return $currentState;134 } );135 return succeed( null )->chain( contextual( function () use ( $opt ) {136 return succeed( yield $opt );137 } ) );138 }139 function not( Parser $parser ): Parser {140 return new Parser( 'not', static function ( ParserInputInterface $input, ParserState $currentState ) use ( &$parser ): ParserState {141 $nextState = $parser->run( $input, $currentState );142 if ( $nextState->isError() ) {143 return $currentState;144 }145 return $currentState->error( 'should have not matched parser' );146 } );147 }...

Full Screen

Full Screen

TokenParserBroker.php

Source:TokenParserBroker.php Github

copy

Full Screen

...13 *14 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>15 * @deprecated since 1.12 (to be removed in 2.0)16 */17class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface18{19 protected $parser;20 protected $parsers = array();21 protected $brokers = array();22 /**23 * Constructor.24 *25 * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances26 * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances27 */28 public function __construct($parsers = array(), $brokers = array())29 {30 foreach ($parsers as $parser) {31 if (!$parser instanceof Twig_TokenParserInterface) {32 throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');33 }34 $this->parsers[$parser->getTag()] = $parser;35 }36 foreach ($brokers as $broker) {37 if (!$broker instanceof Twig_TokenParserBrokerInterface) {38 throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');39 }40 $this->brokers[] = $broker;41 }42 }43 /**44 * Adds a TokenParser.45 *46 * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance47 */48 public function addTokenParser(Twig_TokenParserInterface $parser)49 {50 $this->parsers[$parser->getTag()] = $parser;51 }52 /**53 * Removes a TokenParser.54 *55 * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance56 */57 public function removeTokenParser(Twig_TokenParserInterface $parser)58 {59 $name = $parser->getTag();60 if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) {61 unset($this->parsers[$name]);62 }63 }64 /**65 * Adds a TokenParserBroker.66 *67 * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance68 */69 public function addTokenParserBroker(Twig_TokenParserBroker $broker)70 {71 $this->brokers[] = $broker;72 }73 /**74 * Removes a TokenParserBroker.75 *76 * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance77 */78 public function removeTokenParserBroker(Twig_TokenParserBroker $broker)79 {80 if (false !== $pos = array_search($broker, $this->brokers)) {81 unset($this->brokers[$pos]);82 }83 }84 /**85 * Gets a suitable TokenParser for a tag.86 *87 * First looks in parsers, then in brokers.88 *89 * @param string $tag A tag name90 *91 * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found92 */93 public function getTokenParser($tag)94 {95 if (isset($this->parsers[$tag])) {96 return $this->parsers[$tag];97 }98 $broker = end($this->brokers);99 while (false !== $broker) {100 $parser = $broker->getTokenParser($tag);101 if (null !== $parser) {102 return $parser;103 }104 $broker = prev($this->brokers);105 }106 }107 public function getParsers()108 {109 return $this->parsers;110 }111 public function getParser()112 {113 return $this->parser;114 }115 public function setParser(Twig_ParserInterface $parser)116 {117 $this->parser = $parser;118 foreach ($this->parsers as $tokenParser) {119 $tokenParser->setParser($parser);120 }121 foreach ($this->brokers as $broker) {122 $broker->setParser($parser);123 }124 }125}...

Full Screen

Full Screen

Parser

Using AI Code Generation

copy

Full Screen

1use Cucumber\Parser;2use Cucumber\Parser\ParserException;3use Cucumber\Parser\ParserNotFoundException;4{5 $parser = new Parser('1.feature');6 $parser->parse();7}8catch (ParserException $e)9{10}11catch (ParserNotFoundException $e)12{13}14use Cucumber\Parser;15use Cucumber\Parser\ParserException;16use Cucumber\Parser\ParserNotFoundException;17{18 $parser = new Parser('2.feature');19 $parser->parse();20}21catch (ParserException $e)22{23}24catch (ParserNotFoundException $e)25{26}27use Cucumber\Parser;28use Cucumber\Parser\ParserException;29use Cucumber\Parser\ParserNotFoundException;30{31 $parser = new Parser('3.feature');32 $parser->parse();33}34catch (ParserException $e)35{36}37catch (ParserNotFoundException $e)38{39}

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