Best Atoum code snippet using parser
scannerc.go
Source:scannerc.go
...13// The process of transforming a YAML stream into a sequence of events is14// divided on two steps: Scanning and Parsing.15//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{1112 typ: yaml_BLOCK_ENTRY_TOKEN,1113 start_mark: start_mark,1114 end_mark: end_mark,1115 }1116 yaml_insert_token(parser, -1, &token)1117 return true1118}1119// Produce the KEY token.1120func yaml_parser_fetch_key(parser *yaml_parser_t) bool {1121 // In the block context, additional checks are required.1122 if parser.flow_level == 0 {1123 // Check if we are allowed to start a new key (not nessesary simple).1124 if !parser.simple_key_allowed {1125 return yaml_parser_set_scanner_error(parser, "", parser.mark,1126 "mapping keys are not allowed in this context")1127 }1128 // Add the BLOCK-MAPPING-START token if needed.1129 if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {1130 return false1131 }1132 }1133 // Reset any potential simple keys on the current flow level.1134 if !yaml_parser_remove_simple_key(parser) {1135 return false1136 }1137 // Simple keys are allowed after '?' in the block context.1138 parser.simple_key_allowed = parser.flow_level == 01139 // Consume the token.1140 start_mark := parser.mark1141 skip(parser)1142 end_mark := parser.mark1143 // Create the KEY token and append it to the queue.1144 token := yaml_token_t{1145 typ: yaml_KEY_TOKEN,1146 start_mark: start_mark,1147 end_mark: end_mark,1148 }1149 yaml_insert_token(parser, -1, &token)1150 return true1151}1152// Produce the VALUE token.1153func yaml_parser_fetch_value(parser *yaml_parser_t) bool {1154 simple_key := &parser.simple_keys[len(parser.simple_keys)-1]1155 // Have we found a simple key?1156 if simple_key.possible {1157 // Create the KEY token and insert it into the queue.1158 token := yaml_token_t{1159 typ: yaml_KEY_TOKEN,1160 start_mark: simple_key.mark,1161 end_mark: simple_key.mark,1162 }1163 yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)1164 // In the block context, we may need to add the BLOCK-MAPPING-START token.1165 if !yaml_parser_roll_indent(parser, simple_key.mark.column,1166 simple_key.token_number,1167 yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {1168 return false1169 }1170 // Remove the simple key.1171 simple_key.possible = false1172 // A simple key cannot follow another simple key.1173 parser.simple_key_allowed = false1174 } else {1175 // The ':' indicator follows a complex key.1176 // In the block context, extra checks are required.1177 if parser.flow_level == 0 {1178 // Check if we are allowed to start a complex value.1179 if !parser.simple_key_allowed {1180 return yaml_parser_set_scanner_error(parser, "", parser.mark,1181 "mapping values are not allowed in this context")1182 }1183 // Add the BLOCK-MAPPING-START token if needed.1184 if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {1185 return false1186 }1187 }1188 // Simple keys after ':' are allowed in the block context.1189 parser.simple_key_allowed = parser.flow_level == 01190 }1191 // Consume the token.1192 start_mark := parser.mark1193 skip(parser)1194 end_mark := parser.mark1195 // Create the VALUE token and append it to the queue.1196 token := yaml_token_t{1197 typ: yaml_VALUE_TOKEN,1198 start_mark: start_mark,1199 end_mark: end_mark,1200 }1201 yaml_insert_token(parser, -1, &token)1202 return true1203}1204// Produce the ALIAS or ANCHOR token.1205func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {1206 // An anchor or an alias could be a simple key.1207 if !yaml_parser_save_simple_key(parser) {1208 return false1209 }1210 // A simple key cannot follow an anchor or an alias.1211 parser.simple_key_allowed = false1212 // Create the ALIAS or ANCHOR token and append it to the queue.1213 var token yaml_token_t1214 if !yaml_parser_scan_anchor(parser, &token, typ) {1215 return false1216 }1217 yaml_insert_token(parser, -1, &token)1218 return true1219}1220// Produce the TAG token.1221func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {1222 // A tag could be a simple key.1223 if !yaml_parser_save_simple_key(parser) {1224 return false1225 }1226 // A simple key cannot follow a tag.1227 parser.simple_key_allowed = false1228 // Create the TAG token and append it to the queue.1229 var token yaml_token_t1230 if !yaml_parser_scan_tag(parser, &token) {1231 return false1232 }1233 yaml_insert_token(parser, -1, &token)1234 return true1235}1236// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.1237func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {1238 // Remove any potential simple keys.1239 if !yaml_parser_remove_simple_key(parser) {1240 return false1241 }1242 // A simple key may follow a block scalar.1243 parser.simple_key_allowed = true1244 // Create the SCALAR token and append it to the queue.1245 var token yaml_token_t1246 if !yaml_parser_scan_block_scalar(parser, &token, literal) {1247 return false1248 }1249 yaml_insert_token(parser, -1, &token)1250 return true1251}1252// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.1253func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {1254 // A plain scalar could be a simple key.1255 if !yaml_parser_save_simple_key(parser) {1256 return false1257 }1258 // A simple key cannot follow a flow scalar.1259 parser.simple_key_allowed = false1260 // Create the SCALAR token and append it to the queue.1261 var token yaml_token_t1262 if !yaml_parser_scan_flow_scalar(parser, &token, single) {1263 return false1264 }1265 yaml_insert_token(parser, -1, &token)1266 return true1267}1268// Produce the SCALAR(...,plain) token.1269func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {1270 // A plain scalar could be a simple key.1271 if !yaml_parser_save_simple_key(parser) {1272 return false1273 }1274 // A simple key cannot follow a flow scalar.1275 parser.simple_key_allowed = false1276 // Create the SCALAR token and append it to the queue.1277 var token yaml_token_t1278 if !yaml_parser_scan_plain_scalar(parser, &token) {1279 return false1280 }1281 yaml_insert_token(parser, -1, &token)1282 return true1283}1284// Eat whitespaces and comments until the next token is found.1285func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {1286 // Until the next token is not found.1287 for {1288 // Allow the BOM mark to start a line.1289 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1290 return false1291 }1292 if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {1293 skip(parser)1294 }1295 // Eat whitespaces.1296 // Tabs are allowed:1297 // - in the flow context1298 // - in the block context, but not at the beginning of the line or1299 // after '-', '?', or ':' (complex value).1300 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1301 return false1302 }1303 for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {1304 skip(parser)1305 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1306 return false1307 }1308 }1309 // Eat a comment until a line break.1310 if parser.buffer[parser.buffer_pos] == '#' {1311 for !is_breakz(parser.buffer, parser.buffer_pos) {1312 skip(parser)1313 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1314 return false1315 }1316 }1317 }1318 // If it is a line break, eat it.1319 if is_break(parser.buffer, parser.buffer_pos) {1320 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {1321 return false1322 }1323 skip_line(parser)1324 // In the block context, a new line may start a simple key.1325 if parser.flow_level == 0 {1326 parser.simple_key_allowed = true1327 }1328 } else {1329 break // We have found a token.1330 }1331 }1332 return true1333}1334// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.1335//1336// Scope:1337// %YAML 1.1 # a comment \n1338// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1339// %TAG !yaml! tag:yaml.org,2002: \n1340// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1341//1342func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {1343 // Eat '%'.1344 start_mark := parser.mark1345 skip(parser)1346 // Scan the directive name.1347 var name []byte1348 if !yaml_parser_scan_directive_name(parser, start_mark, &name) {1349 return false1350 }1351 // Is it a YAML directive?1352 if bytes.Equal(name, []byte("YAML")) {1353 // Scan the VERSION directive value.1354 var major, minor int81355 if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {1356 return false1357 }1358 end_mark := parser.mark1359 // Create a VERSION-DIRECTIVE token.1360 *token = yaml_token_t{1361 typ: yaml_VERSION_DIRECTIVE_TOKEN,1362 start_mark: start_mark,1363 end_mark: end_mark,1364 major: major,1365 minor: minor,1366 }1367 // Is it a TAG directive?1368 } else if bytes.Equal(name, []byte("TAG")) {1369 // Scan the TAG directive value.1370 var handle, prefix []byte1371 if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {1372 return false1373 }1374 end_mark := parser.mark1375 // Create a TAG-DIRECTIVE token.1376 *token = yaml_token_t{1377 typ: yaml_TAG_DIRECTIVE_TOKEN,1378 start_mark: start_mark,1379 end_mark: end_mark,1380 value: handle,1381 prefix: prefix,1382 }1383 // Unknown directive.1384 } else {1385 yaml_parser_set_scanner_error(parser, "while scanning a directive",1386 start_mark, "found unknown directive name")1387 return false1388 }1389 // Eat the rest of the line including any comments.1390 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1391 return false1392 }1393 for is_blank(parser.buffer, parser.buffer_pos) {1394 skip(parser)1395 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1396 return false1397 }1398 }1399 if parser.buffer[parser.buffer_pos] == '#' {1400 for !is_breakz(parser.buffer, parser.buffer_pos) {1401 skip(parser)1402 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1403 return false1404 }1405 }1406 }1407 // Check if we are at the end of the line.1408 if !is_breakz(parser.buffer, parser.buffer_pos) {1409 yaml_parser_set_scanner_error(parser, "while scanning a directive",1410 start_mark, "did not find expected comment or line break")1411 return false1412 }1413 // Eat a line break.1414 if is_break(parser.buffer, parser.buffer_pos) {1415 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {1416 return false1417 }1418 skip_line(parser)1419 }1420 return true1421}1422// Scan the directive name.1423//1424// Scope:1425// %YAML 1.1 # a comment \n1426// ^^^^1427// %TAG !yaml! tag:yaml.org,2002: \n1428// ^^^1429//1430func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {1431 // Consume the directive name.1432 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1433 return false1434 }1435 var s []byte1436 for is_alpha(parser.buffer, parser.buffer_pos) {1437 s = read(parser, s)1438 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1439 return false1440 }1441 }1442 // Check if the name is empty.1443 if len(s) == 0 {1444 yaml_parser_set_scanner_error(parser, "while scanning a directive",1445 start_mark, "could not find expected directive name")1446 return false1447 }1448 // Check for an blank character after the name.1449 if !is_blankz(parser.buffer, parser.buffer_pos) {1450 yaml_parser_set_scanner_error(parser, "while scanning a directive",1451 start_mark, "found unexpected non-alphabetical character")1452 return false1453 }1454 *name = s1455 return true1456}1457// Scan the value of VERSION-DIRECTIVE.1458//1459// Scope:1460// %YAML 1.1 # a comment \n1461// ^^^^^^1462func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {1463 // Eat whitespaces.1464 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1465 return false1466 }1467 for is_blank(parser.buffer, parser.buffer_pos) {1468 skip(parser)1469 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1470 return false1471 }1472 }1473 // Consume the major version number.1474 if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {1475 return false1476 }1477 // Eat '.'.1478 if parser.buffer[parser.buffer_pos] != '.' {1479 return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",1480 start_mark, "did not find expected digit or '.' character")1481 }1482 skip(parser)1483 // Consume the minor version number.1484 if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {1485 return false1486 }1487 return true1488}1489const max_number_length = 21490// Scan the version number of VERSION-DIRECTIVE.1491//1492// Scope:1493// %YAML 1.1 # a comment \n1494// ^1495// %YAML 1.1 # a comment \n1496// ^1497func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {1498 // Repeat while the next character is digit.1499 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1500 return false1501 }1502 var value, length int81503 for is_digit(parser.buffer, parser.buffer_pos) {1504 // Check if the number is too long.1505 length++1506 if length > max_number_length {1507 return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",1508 start_mark, "found extremely long version number")1509 }1510 value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))1511 skip(parser)1512 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1513 return false1514 }1515 }1516 // Check if the number was present.1517 if length == 0 {1518 return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",1519 start_mark, "did not find expected version number")1520 }1521 *number = value1522 return true1523}1524// Scan the value of a TAG-DIRECTIVE token.1525//1526// Scope:1527// %TAG !yaml! tag:yaml.org,2002: \n1528// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1529//1530func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {1531 var handle_value, prefix_value []byte1532 // Eat whitespaces.1533 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1534 return false1535 }1536 for is_blank(parser.buffer, parser.buffer_pos) {1537 skip(parser)1538 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1539 return false1540 }1541 }1542 // Scan a handle.1543 if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {1544 return false1545 }1546 // Expect a whitespace.1547 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1548 return false1549 }1550 if !is_blank(parser.buffer, parser.buffer_pos) {1551 yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",1552 start_mark, "did not find expected whitespace")1553 return false1554 }1555 // Eat whitespaces.1556 for is_blank(parser.buffer, parser.buffer_pos) {1557 skip(parser)1558 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1559 return false1560 }1561 }1562 // Scan a prefix.1563 if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {1564 return false1565 }1566 // Expect a whitespace or line break.1567 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1568 return false1569 }1570 if !is_blankz(parser.buffer, parser.buffer_pos) {1571 yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",1572 start_mark, "did not find expected whitespace or line break")1573 return false1574 }1575 *handle = handle_value1576 *prefix = prefix_value1577 return true1578}1579func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {1580 var s []byte1581 // Eat the indicator character.1582 start_mark := parser.mark1583 skip(parser)1584 // Consume the value.1585 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1586 return false1587 }1588 for is_alpha(parser.buffer, parser.buffer_pos) {1589 s = read(parser, s)1590 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1591 return false1592 }1593 }1594 end_mark := parser.mark1595 /*1596 * Check if length of the anchor is greater than 0 and it is followed by1597 * a whitespace character or one of the indicators:1598 *1599 * '?', ':', ',', ']', '}', '%', '@', '`'.1600 */1601 if len(s) == 0 ||1602 !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||1603 parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||1604 parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||1605 parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||1606 parser.buffer[parser.buffer_pos] == '`') {1607 context := "while scanning an alias"1608 if typ == yaml_ANCHOR_TOKEN {1609 context = "while scanning an anchor"1610 }1611 yaml_parser_set_scanner_error(parser, context, start_mark,1612 "did not find expected alphabetic or numeric character")1613 return false1614 }1615 // Create a token.1616 *token = yaml_token_t{1617 typ: typ,1618 start_mark: start_mark,1619 end_mark: end_mark,1620 value: s,1621 }1622 return true1623}1624/*1625 * Scan a TAG token.1626 */1627func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {1628 var handle, suffix []byte1629 start_mark := parser.mark1630 // Check if the tag is in the canonical form.1631 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {1632 return false1633 }1634 if parser.buffer[parser.buffer_pos+1] == '<' {1635 // Keep the handle as ''1636 // Eat '!<'1637 skip(parser)1638 skip(parser)1639 // Consume the tag value.1640 if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {1641 return false1642 }1643 // Check for '>' and eat it.1644 if parser.buffer[parser.buffer_pos] != '>' {1645 yaml_parser_set_scanner_error(parser, "while scanning a tag",1646 start_mark, "did not find the expected '>'")1647 return false1648 }1649 skip(parser)1650 } else {1651 // The tag has either the '!suffix' or the '!handle!suffix' form.1652 // First, try to scan a handle.1653 if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {1654 return false1655 }1656 // Check if it is, indeed, handle.1657 if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {1658 // Scan the suffix now.1659 if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {1660 return false1661 }1662 } else {1663 // It wasn't a handle after all. Scan the rest of the tag.1664 if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {1665 return false1666 }1667 // Set the handle to '!'.1668 handle = []byte{'!'}1669 // A special case: the '!' tag. Set the handle to '' and the1670 // suffix to '!'.1671 if len(suffix) == 0 {1672 handle, suffix = suffix, handle1673 }1674 }1675 }1676 // Check the character which ends the tag.1677 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1678 return false1679 }1680 if !is_blankz(parser.buffer, parser.buffer_pos) {1681 yaml_parser_set_scanner_error(parser, "while scanning a tag",1682 start_mark, "did not find expected whitespace or line break")1683 return false1684 }1685 end_mark := parser.mark1686 // Create a token.1687 *token = yaml_token_t{1688 typ: yaml_TAG_TOKEN,1689 start_mark: start_mark,1690 end_mark: end_mark,1691 value: handle,1692 suffix: suffix,1693 }1694 return true1695}1696// Scan a tag handle.1697func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {1698 // Check the initial '!' character.1699 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1700 return false1701 }1702 if parser.buffer[parser.buffer_pos] != '!' {1703 yaml_parser_set_scanner_tag_error(parser, directive,1704 start_mark, "did not find expected '!'")1705 return false1706 }1707 var s []byte1708 // Copy the '!' character.1709 s = read(parser, s)1710 // Copy all subsequent alphabetical and numerical characters.1711 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1712 return false1713 }1714 for is_alpha(parser.buffer, parser.buffer_pos) {1715 s = read(parser, s)1716 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1717 return false1718 }1719 }1720 // Check if the trailing character is '!' and copy it.1721 if parser.buffer[parser.buffer_pos] == '!' {1722 s = read(parser, s)1723 } else {1724 // It's either the '!' tag or not really a tag handle. If it's a %TAG1725 // directive, it's an error. If it's a tag token, it must be a part of URI.1726 if directive && string(s) != "!" {1727 yaml_parser_set_scanner_tag_error(parser, directive,1728 start_mark, "did not find expected '!'")1729 return false1730 }1731 }1732 *handle = s1733 return true1734}1735// Scan a tag.1736func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {1737 //size_t length = head ? strlen((char *)head) : 01738 var s []byte1739 hasTag := len(head) > 01740 // Copy the head if needed.1741 //1742 // Note that we don't copy the leading '!' character.1743 if len(head) > 1 {1744 s = append(s, head[1:]...)1745 }1746 // Scan the tag.1747 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1748 return false1749 }1750 // The set of characters that may appear in URI is as follows:1751 //1752 // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',1753 // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',1754 // '%'.1755 // [Go] Convert this into more reasonable logic.1756 for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||1757 parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||1758 parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||1759 parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||1760 parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||1761 parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||1762 parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||1763 parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||1764 parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||1765 parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||1766 parser.buffer[parser.buffer_pos] == '%' {1767 // Check if it is a URI-escape sequence.1768 if parser.buffer[parser.buffer_pos] == '%' {1769 if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {1770 return false1771 }1772 } else {1773 s = read(parser, s)1774 }1775 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1776 return false1777 }1778 hasTag = true1779 }1780 if !hasTag {1781 yaml_parser_set_scanner_tag_error(parser, directive,1782 start_mark, "did not find expected tag URI")1783 return false1784 }1785 *uri = s1786 return true1787}1788// Decode an URI-escape sequence corresponding to a single UTF-8 character.1789func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {1790 // Decode the required number of characters.1791 w := 10241792 for w > 0 {1793 // Check for a URI-escaped octet.1794 if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {1795 return false1796 }1797 if !(parser.buffer[parser.buffer_pos] == '%' &&1798 is_hex(parser.buffer, parser.buffer_pos+1) &&1799 is_hex(parser.buffer, parser.buffer_pos+2)) {1800 return yaml_parser_set_scanner_tag_error(parser, directive,1801 start_mark, "did not find URI escaped octet")1802 }1803 // Get the octet.1804 octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))1805 // If it is the leading octet, determine the length of the UTF-8 sequence.1806 if w == 1024 {1807 w = width(octet)1808 if w == 0 {1809 return yaml_parser_set_scanner_tag_error(parser, directive,1810 start_mark, "found an incorrect leading UTF-8 octet")1811 }1812 } else {1813 // Check if the trailing octet is correct.1814 if octet&0xC0 != 0x80 {1815 return yaml_parser_set_scanner_tag_error(parser, directive,1816 start_mark, "found an incorrect trailing UTF-8 octet")1817 }1818 }1819 // Copy the octet and move the pointers.1820 *s = append(*s, octet)1821 skip(parser)1822 skip(parser)1823 skip(parser)1824 w--1825 }1826 return true1827}1828// Scan a block scalar.1829func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {1830 // Eat the indicator '|' or '>'.1831 start_mark := parser.mark1832 skip(parser)1833 // Scan the additional block scalar indicators.1834 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1835 return false1836 }1837 // Check for a chomping indicator.1838 var chomping, increment int1839 if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {1840 // Set the chomping method and eat the indicator.1841 if parser.buffer[parser.buffer_pos] == '+' {1842 chomping = +11843 } else {1844 chomping = -11845 }1846 skip(parser)1847 // Check for an indentation indicator.1848 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1849 return false1850 }1851 if is_digit(parser.buffer, parser.buffer_pos) {1852 // Check that the indentation is greater than 0.1853 if parser.buffer[parser.buffer_pos] == '0' {1854 yaml_parser_set_scanner_error(parser, "while scanning a block scalar",1855 start_mark, "found an indentation indicator equal to 0")1856 return false1857 }1858 // Get the indentation level and eat the indicator.1859 increment = as_digit(parser.buffer, parser.buffer_pos)1860 skip(parser)1861 }1862 } else if is_digit(parser.buffer, parser.buffer_pos) {1863 // Do the same as above, but in the opposite order.1864 if parser.buffer[parser.buffer_pos] == '0' {1865 yaml_parser_set_scanner_error(parser, "while scanning a block scalar",1866 start_mark, "found an indentation indicator equal to 0")1867 return false1868 }1869 increment = as_digit(parser.buffer, parser.buffer_pos)1870 skip(parser)1871 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1872 return false1873 }1874 if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {1875 if parser.buffer[parser.buffer_pos] == '+' {1876 chomping = +11877 } else {1878 chomping = -11879 }1880 skip(parser)1881 }1882 }1883 // Eat whitespaces and comments to the end of the line.1884 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1885 return false1886 }1887 for is_blank(parser.buffer, parser.buffer_pos) {1888 skip(parser)1889 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1890 return false1891 }1892 }1893 if parser.buffer[parser.buffer_pos] == '#' {1894 for !is_breakz(parser.buffer, parser.buffer_pos) {1895 skip(parser)1896 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1897 return false1898 }1899 }1900 }1901 // Check if we are at the end of the line.1902 if !is_breakz(parser.buffer, parser.buffer_pos) {1903 yaml_parser_set_scanner_error(parser, "while scanning a block scalar",1904 start_mark, "did not find expected comment or line break")1905 return false1906 }1907 // Eat a line break.1908 if is_break(parser.buffer, parser.buffer_pos) {1909 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {1910 return false1911 }1912 skip_line(parser)1913 }1914 end_mark := parser.mark1915 // Set the indentation level if it was specified.1916 var indent int1917 if increment > 0 {1918 if parser.indent >= 0 {1919 indent = parser.indent + increment1920 } else {1921 indent = increment1922 }1923 }1924 // Scan the leading line breaks and determine the indentation level if needed.1925 var s, leading_break, trailing_breaks []byte1926 if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {1927 return false1928 }1929 // Scan the block scalar content.1930 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1931 return false1932 }1933 var leading_blank, trailing_blank bool1934 for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {1935 // We are at the beginning of a non-empty line.1936 // Is it a trailing whitespace?1937 trailing_blank = is_blank(parser.buffer, parser.buffer_pos)1938 // Check if we need to fold the leading line break.1939 if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {1940 // Do we need to join the lines by space?1941 if len(trailing_breaks) == 0 {1942 s = append(s, ' ')1943 }1944 } else {1945 s = append(s, leading_break...)1946 }1947 leading_break = leading_break[:0]1948 // Append the remaining line breaks.1949 s = append(s, trailing_breaks...)1950 trailing_breaks = trailing_breaks[:0]1951 // Is it a leading whitespace?1952 leading_blank = is_blank(parser.buffer, parser.buffer_pos)1953 // Consume the current line.1954 for !is_breakz(parser.buffer, parser.buffer_pos) {1955 s = read(parser, s)1956 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1957 return false1958 }1959 }1960 // Consume the line break.1961 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {1962 return false1963 }1964 leading_break = read_line(parser, leading_break)1965 // Eat the following indentation spaces and line breaks.1966 if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {1967 return false1968 }1969 }1970 // Chomp the tail.1971 if chomping != -1 {1972 s = append(s, leading_break...)1973 }1974 if chomping == 1 {1975 s = append(s, trailing_breaks...)1976 }1977 // Create a token.1978 *token = yaml_token_t{1979 typ: yaml_SCALAR_TOKEN,1980 start_mark: start_mark,1981 end_mark: end_mark,1982 value: s,1983 style: yaml_LITERAL_SCALAR_STYLE,1984 }1985 if !literal {1986 token.style = yaml_FOLDED_SCALAR_STYLE1987 }1988 return true1989}1990// Scan indentation spaces and line breaks for a block scalar. Determine the1991// indentation level if needed.1992func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {1993 *end_mark = parser.mark1994 // Eat the indentation spaces and line breaks.1995 max_indent := 01996 for {1997 // Eat the indentation spaces.1998 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {1999 return false2000 }2001 for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {2002 skip(parser)2003 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {2004 return false2005 }2006 }2007 if parser.mark.column > max_indent {2008 max_indent = parser.mark.column2009 }2010 // Check for a tab character messing the indentation.2011 if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {2012 return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",2013 start_mark, "found a tab character where an indentation space is expected")2014 }2015 // Have we found a non-empty line?2016 if !is_break(parser.buffer, parser.buffer_pos) {2017 break2018 }2019 // Consume the line break.2020 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {2021 return false2022 }2023 // [Go] Should really be returning breaks instead.2024 *breaks = read_line(parser, *breaks)2025 *end_mark = parser.mark2026 }2027 // Determine the indentation level if needed.2028 if *indent == 0 {2029 *indent = max_indent2030 if *indent < parser.indent+1 {2031 *indent = parser.indent + 12032 }2033 if *indent < 1 {2034 *indent = 12035 }2036 }2037 return true2038}2039// Scan a quoted scalar.2040func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {2041 // Eat the left quote.2042 start_mark := parser.mark2043 skip(parser)2044 // Consume the content of the quoted scalar.2045 var s, leading_break, trailing_breaks, whitespaces []byte2046 for {2047 // Check that there are no document indicators at the beginning of the line.2048 if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {2049 return false2050 }2051 if parser.mark.column == 0 &&2052 ((parser.buffer[parser.buffer_pos+0] == '-' &&2053 parser.buffer[parser.buffer_pos+1] == '-' &&2054 parser.buffer[parser.buffer_pos+2] == '-') ||2055 (parser.buffer[parser.buffer_pos+0] == '.' &&2056 parser.buffer[parser.buffer_pos+1] == '.' &&2057 parser.buffer[parser.buffer_pos+2] == '.')) &&2058 is_blankz(parser.buffer, parser.buffer_pos+3) {2059 yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",2060 start_mark, "found unexpected document indicator")2061 return false2062 }2063 // Check for EOF.2064 if is_z(parser.buffer, parser.buffer_pos) {2065 yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",2066 start_mark, "found unexpected end of stream")2067 return false2068 }2069 // Consume non-blank characters.2070 leading_blanks := false2071 for !is_blankz(parser.buffer, parser.buffer_pos) {2072 if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {2073 // Is is an escaped single quote.2074 s = append(s, '\'')2075 skip(parser)2076 skip(parser)2077 } else if single && parser.buffer[parser.buffer_pos] == '\'' {2078 // It is a right single quote.2079 break2080 } else if !single && parser.buffer[parser.buffer_pos] == '"' {2081 // It is a right double quote.2082 break2083 } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {2084 // It is an escaped line break.2085 if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {2086 return false2087 }2088 skip(parser)2089 skip_line(parser)2090 leading_blanks = true2091 break2092 } else if !single && parser.buffer[parser.buffer_pos] == '\\' {2093 // It is an escape sequence.2094 code_length := 02095 // Check the escape character.2096 switch parser.buffer[parser.buffer_pos+1] {2097 case '0':2098 s = append(s, 0)2099 case 'a':2100 s = append(s, '\x07')2101 case 'b':2102 s = append(s, '\x08')2103 case 't', '\t':2104 s = append(s, '\x09')2105 case 'n':2106 s = append(s, '\x0A')2107 case 'v':2108 s = append(s, '\x0B')2109 case 'f':2110 s = append(s, '\x0C')2111 case 'r':2112 s = append(s, '\x0D')2113 case 'e':2114 s = append(s, '\x1B')2115 case ' ':2116 s = append(s, '\x20')2117 case '"':2118 s = append(s, '"')2119 case '\'':2120 s = append(s, '\'')2121 case '\\':2122 s = append(s, '\\')2123 case 'N': // NEL (#x85)2124 s = append(s, '\xC2')2125 s = append(s, '\x85')2126 case '_': // #xA02127 s = append(s, '\xC2')2128 s = append(s, '\xA0')2129 case 'L': // LS (#x2028)2130 s = append(s, '\xE2')2131 s = append(s, '\x80')2132 s = append(s, '\xA8')2133 case 'P': // PS (#x2029)2134 s = append(s, '\xE2')2135 s = append(s, '\x80')2136 s = append(s, '\xA9')2137 case 'x':2138 code_length = 22139 case 'u':2140 code_length = 42141 case 'U':2142 code_length = 82143 default:2144 yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",2145 start_mark, "found unknown escape character")2146 return false2147 }2148 skip(parser)2149 skip(parser)2150 // Consume an arbitrary escape code.2151 if code_length > 0 {2152 var value int2153 // Scan the character value.2154 if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {2155 return false2156 }2157 for k := 0; k < code_length; k++ {2158 if !is_hex(parser.buffer, parser.buffer_pos+k) {2159 yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",2160 start_mark, "did not find expected hexdecimal number")2161 return false2162 }2163 value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)2164 }2165 // Check the value and write the character.2166 if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {2167 yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",2168 start_mark, "found invalid Unicode character escape code")2169 return false2170 }2171 if value <= 0x7F {2172 s = append(s, byte(value))2173 } else if value <= 0x7FF {2174 s = append(s, byte(0xC0+(value>>6)))2175 s = append(s, byte(0x80+(value&0x3F)))2176 } else if value <= 0xFFFF {2177 s = append(s, byte(0xE0+(value>>12)))2178 s = append(s, byte(0x80+((value>>6)&0x3F)))2179 s = append(s, byte(0x80+(value&0x3F)))2180 } else {2181 s = append(s, byte(0xF0+(value>>18)))2182 s = append(s, byte(0x80+((value>>12)&0x3F)))2183 s = append(s, byte(0x80+((value>>6)&0x3F)))2184 s = append(s, byte(0x80+(value&0x3F)))2185 }2186 // Advance the pointer.2187 for k := 0; k < code_length; k++ {2188 skip(parser)2189 }2190 }2191 } else {2192 // It is a non-escaped non-blank character.2193 s = read(parser, s)2194 }2195 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {2196 return false2197 }2198 }2199 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {2200 return false2201 }2202 // Check if we are at the end of the scalar.2203 if single {2204 if parser.buffer[parser.buffer_pos] == '\'' {2205 break2206 }2207 } else {2208 if parser.buffer[parser.buffer_pos] == '"' {2209 break2210 }2211 }2212 // Consume blank characters.2213 for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {2214 if is_blank(parser.buffer, parser.buffer_pos) {2215 // Consume a space or a tab character.2216 if !leading_blanks {2217 whitespaces = read(parser, whitespaces)2218 } else {2219 skip(parser)2220 }2221 } else {2222 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {2223 return false2224 }2225 // Check if it is a first line break.2226 if !leading_blanks {2227 whitespaces = whitespaces[:0]2228 leading_break = read_line(parser, leading_break)2229 leading_blanks = true2230 } else {2231 trailing_breaks = read_line(parser, trailing_breaks)2232 }2233 }2234 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {2235 return false2236 }2237 }2238 // Join the whitespaces or fold line breaks.2239 if leading_blanks {2240 // Do we need to fold line breaks?2241 if len(leading_break) > 0 && leading_break[0] == '\n' {2242 if len(trailing_breaks) == 0 {2243 s = append(s, ' ')2244 } else {2245 s = append(s, trailing_breaks...)2246 }2247 } else {2248 s = append(s, leading_break...)2249 s = append(s, trailing_breaks...)2250 }2251 trailing_breaks = trailing_breaks[:0]2252 leading_break = leading_break[:0]2253 } else {2254 s = append(s, whitespaces...)2255 whitespaces = whitespaces[:0]2256 }2257 }2258 // Eat the right quote.2259 skip(parser)2260 end_mark := parser.mark2261 // Create a token.2262 *token = yaml_token_t{2263 typ: yaml_SCALAR_TOKEN,2264 start_mark: start_mark,2265 end_mark: end_mark,2266 value: s,2267 style: yaml_SINGLE_QUOTED_SCALAR_STYLE,2268 }2269 if !single {2270 token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE2271 }2272 return true2273}2274// Scan a plain scalar.2275func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {2276 var s, leading_break, trailing_breaks, whitespaces []byte2277 var leading_blanks bool2278 var indent = parser.indent + 12279 start_mark := parser.mark2280 end_mark := parser.mark2281 // Consume the content of the plain scalar.2282 for {2283 // Check for a document indicator.2284 if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {2285 return false2286 }2287 if parser.mark.column == 0 &&2288 ((parser.buffer[parser.buffer_pos+0] == '-' &&2289 parser.buffer[parser.buffer_pos+1] == '-' &&2290 parser.buffer[parser.buffer_pos+2] == '-') ||2291 (parser.buffer[parser.buffer_pos+0] == '.' &&2292 parser.buffer[parser.buffer_pos+1] == '.' &&2293 parser.buffer[parser.buffer_pos+2] == '.')) &&2294 is_blankz(parser.buffer, parser.buffer_pos+3) {2295 break2296 }2297 // Check for a comment.2298 if parser.buffer[parser.buffer_pos] == '#' {2299 break2300 }2301 // Consume non-blank characters.2302 for !is_blankz(parser.buffer, parser.buffer_pos) {2303 // Check for indicators that may end a plain scalar.2304 if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||2305 (parser.flow_level > 0 &&2306 (parser.buffer[parser.buffer_pos] == ',' ||2307 parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||2308 parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||2309 parser.buffer[parser.buffer_pos] == '}')) {2310 break2311 }2312 // Check if we need to join whitespaces and breaks.2313 if leading_blanks || len(whitespaces) > 0 {2314 if leading_blanks {2315 // Do we need to fold line breaks?2316 if leading_break[0] == '\n' {2317 if len(trailing_breaks) == 0 {2318 s = append(s, ' ')2319 } else {2320 s = append(s, trailing_breaks...)2321 }2322 } else {2323 s = append(s, leading_break...)2324 s = append(s, trailing_breaks...)2325 }2326 trailing_breaks = trailing_breaks[:0]2327 leading_break = leading_break[:0]2328 leading_blanks = false2329 } else {2330 s = append(s, whitespaces...)2331 whitespaces = whitespaces[:0]2332 }2333 }2334 // Copy the character.2335 s = read(parser, s)2336 end_mark = parser.mark2337 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {2338 return false2339 }2340 }2341 // Is it the end?2342 if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {2343 break2344 }2345 // Consume blank characters.2346 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {2347 return false2348 }2349 for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {2350 if is_blank(parser.buffer, parser.buffer_pos) {2351 // Check for tab characters that abuse indentation.2352 if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {2353 yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",2354 start_mark, "found a tab character that violates indentation")2355 return false2356 }2357 // Consume a space or a tab character.2358 if !leading_blanks {2359 whitespaces = read(parser, whitespaces)2360 } else {2361 skip(parser)2362 }2363 } else {2364 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {2365 return false2366 }2367 // Check if it is a first line break.2368 if !leading_blanks {2369 whitespaces = whitespaces[:0]2370 leading_break = read_line(parser, leading_break)2371 leading_blanks = true2372 } else {2373 trailing_breaks = read_line(parser, trailing_breaks)2374 }2375 }2376 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {2377 return false2378 }2379 }2380 // Check indentation level.2381 if parser.flow_level == 0 && parser.mark.column < indent {2382 break2383 }2384 }2385 // Create a token.2386 *token = yaml_token_t{2387 typ: yaml_SCALAR_TOKEN,2388 start_mark: start_mark,2389 end_mark: end_mark,2390 value: s,2391 style: yaml_PLAIN_SCALAR_STYLE,2392 }2393 // Note that we change the 'simple_key_allowed' flag.2394 if leading_blanks {2395 parser.simple_key_allowed = true2396 }2397 return true2398}...
parserc.go
Source:parserc.go
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}...
ConsoleOptionParserTest.php
Source:ConsoleOptionParserTest.php
...27 *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 ));559 $result = $parser->parse(array('--secondary', '--fourth', '4', 'c'), 'sub');560 $expected = array(array(561 'secondary' => true,562 'fourth' => '4',563 'help' => false,564 'verbose' => false,565 'quiet' => false), array('c'));566 $this->assertEquals($expected, $result, 'Sub parser did not parse request.');567 }568}...
JavaScriptSymbol.php
Source:JavaScriptSymbol.php
...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}...
Autoloader.php
Source:Autoloader.php
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');...
xml_test.php
Source:xml_test.php
2// $Id: xml_test.php 1787 2008-04-26 20:35:39Z pp11 $3require_once(dirname(__FILE__) . '/../autorun.php');4require_once(dirname(__FILE__) . '/../xml.php');5Mock::generate('SimpleScorer');6if (! function_exists('xml_parser_create')) {7 SimpleTest::ignore('TestOfXmlStructureParsing');8 SimpleTest::ignore('TestOfXmlResultsParsing');9}10class TestOfNestingTags extends UnitTestCase {11 function testGroupSize() {12 $nesting = new NestingGroupTag(array('SIZE' => 2));13 $this->assertEqual($nesting->getSize(), 2);14 }15}16class TestOfXmlStructureParsing extends UnitTestCase {17 function testValidXml() {18 $listener = new MockSimpleScorer();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?>...
combinator.php
Source:combinator.php
...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 }...
TokenParserBroker.php
Source:TokenParserBroker.php
...8 * For the full copyright and license information, please view the LICENSE9 * file that was distributed with this source code.10 */11/**12 * Default implementation of a token parser broker.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