compound-ex4
Version:
Compound-ex4 - MVC framework for NodeJS (ExpressJs 4 version), fork compoundjs(https://github.com/1602/compound)
513 lines (461 loc) • 18.6 kB
text/coffeescript
events = require './events'
{MarkedYAMLError} = require './errors'
tokens = require './tokens'
class extends MarkedYAMLError
class
DEFAULT_TAGS =
'!' : '!',
'!!': 'tag:yaml.org,2002:'
constructor: ->
= null
= null
= {}
= []
= []
= 'parse_stream_start'
###
Reset the state attributes.
###
dispose: ->
= []
= null
###
Check the type of the next event.
###
check_event: (choices...) ->
if is null
= @[]() if ?
if isnt null
return true if choices.length is 0
for choice in choices
return true if instanceof choice
return false
###
Get the next event.
###
peek_event: ->
= @[]() if is null and ?
return
###
Get the event and proceed further.
###
get_event: ->
= @[]() if is null and ?
event =
= null
return event
# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
# implicit_document ::= block_node DOCUMENT-END*
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
###
Parse the stream start.
###
parse_stream_start: ->
token =
event = new events.StreamStartEvent token.start_mark, token.end_mark
# Prepare the next state,
= 'parse_implicit_document_start'
return event
###
Parse an implicit document.
###
parse_implicit_document_start: ->
if not tokens.DirectiveToken, tokens.DocumentStartToken, \
tokens.StreamEndToken
= DEFAULT_TAGS
token =
start_mark = end_mark = token.start_mark
event = new events.DocumentStartEvent start_mark, end_mark, false
# Prepare the next state
.push 'parse_document_end'
= 'parse_block_node'
return event
else
return
###
Parse an explicit document.
###
parse_document_start: ->
# Parse any extra document end indicators
while tokens.DocumentEndToken
if not tokens.StreamEndToken
start_mark = .start_mark
[version, tags] =
throw new exports.ParserError \
"expected '<document start>', but found #{@peek_token().id}", \
.start_mark unless tokens.DocumentStartToken
token =
end_mark = token.end_mark
event = new events.DocumentStartEvent start_mark, end_mark, true,
version, tags
.push 'parse_document_end'
= 'parse_document_content'
else
# Parse the end of the stream.
token =
event = new events.StreamEndEvent token.start_mark, token.end_mark
throw new Error 'assertion error, states should be empty' \
unless .length is 0
throw new Error 'assertion error, marks should be empty' \
unless .length is 0
= null
return event
###
Parse the document end.
###
parse_document_end: ->
token =
start_mark = end_mark = token.start_mark
explicit = no
if tokens.DocumentEndToken
token =
end_mark = token.end_mark
explicit = yes
event = new events.DocumentEndEvent start_mark, end_mark, explicit
# Prepare next state.
= 'parse_document_start'
return event
parse_document_content: ->
if tokens.DirectiveToken, tokens.DocumentStartToken, \
tokens.DocumentEndToken, tokens.StreamEndToken
event = .start_mark
= .pop()
return event
else
return
process_directives: ->
= null
= {}
while tokens.DirectiveToken
token =
if token.name is 'YAML'
throw new exports.ParserError null, null, \
'found duplicate YAML directive', token.start_mark \
if isnt null
[major, minor] = token.value
throw new exports.ParserError null, null, \
'found incompatible YAML document (version 1.* is required)',
token.start_mark if major isnt 1
= token.value
else if token.name is 'TAG'
[handle, prefix] =
throw new exports.ParserError null, null, \
"duplicate tag handle #{handle}", token.start_mark \
if handle of
[handle] = prefix
tag_handles_copy = null
for own handle, prefix of
tag_handles_copy ?= {}
tag_handles_copy[handle] = prefix
value = [, tag_handles_copy]
for own handle, prefix of DEFAULT_TAGS
[handle] = prefix if prefix not of
return value
# block_node_or_indentless_sequence ::= ALIAS
# | properties (block_content | indentless_sequence)?
# | block_content
# | indentless_block_sequence
# block_node ::= ALIAS
# | properties block_content?
# | block_content
# flow_node ::= ALIAS
# | properties flow_content?
# | flow_content
# properties ::= TAG ANCHOR? | ANCHOR TAG?
# block_content ::= block_collection | flow_collection | SCALAR
# flow_content ::= flow_collection | SCALAR
# block_collection ::= block_sequence | block_mapping
# flow_collection ::= flow_sequence | flow_mapping
parse_block_node: -> true
parse_flow_node: ->
parse_block_node_or_indentless_sequence: ->
true, true
parse_node: (block = false, indentless_sequence = false) ->
if tokens.AliasToken
token =
event = new events.AliasEvent token.value, token.start_mark,
token.end_mark
= .pop()
else
anchor = null
tag = null
start_mark = end_mark = tag_mark = null
if tokens.AnchorToken
token =
start_mark = token.start_mark
end_mark = token.end_mark
anchor = token.value
if tokens.TagToken
token =
tag_mark = token.start_mark
end_mark = token.end_mark
tag = token.value
else if tokens.TagToken
token =
start_mark = tag_mark = token.start_mark
end_mark = token.end_mark
tag = token.value
if tokens.AnchorToken
token =
end_mark = token.end_mark
anchor = token.value
if tag isnt null
[handle, suffix] = tag
if handle isnt null
throw new exports.ParserError 'while parsing a node', start_mark, \
"found undefined tag handle #{handle}", tag_mark \
if handle not of
tag = [handle] + suffix
else
tag = suffix
start_mark = end_mark = .start_mark if start_mark is null
event = null
implicit = tag is null or tag is '!'
if indentless_sequence and tokens.BlockEntryToken
end_mark = .end_mark
event = new events.SequenceStartEvent anchor, tag, implicit,
start_mark, end_mark
= 'parse_indentless_sequence_entry'
else
if tokens.ScalarToken
token =
end_mark = token.end_mark
if (token.plain and tag is null) or tag is '!'
implicit = [true, false]
else if tag is null
implicit = [false, true]
else
implicit = [false, false]
event = new events.ScalarEvent anchor, tag, implicit, token.value,
start_mark, end_mark, token.style
= .pop()
else if tokens.FlowSequenceStartToken
end_mark = .end_mark
event = new events.SequenceStartEvent anchor, tag, implicit,
start_mark, end_mark, true
= 'parse_flow_sequence_first_entry'
else if tokens.FlowMappingStartToken
end_mark = .end_mark
event = new events.MappingStartEvent anchor, tag, implicit,
start_mark, end_mark, true
= 'parse_flow_mapping_first_key'
else if block and tokens.BlockSequenceStartToken
end_mark = .end_mark
event = new events.SequenceStartEvent anchor, tag, implicit,
start_mark, end_mark, false
= 'parse_block_sequence_first_entry'
else if block and tokens.BlockMappingStartToken
end_mark = .end_mark
event = new events.MappingStartEvent anchor, tag, implicit,
start_mark, end_mark, false
= 'parse_block_mapping_first_key'
else if anchor isnt null or tag isnt null
# Empty scalars are allowed even if a tag or an anchor is specified.
event = new events.ScalarEvent anchor, tag, [implicit, false], '',
start_mark, end_mark
= .pop()
else
if block
node = 'block'
else
node = 'flow'
token =
throw new exports.ParserError "while parsing a #{node} node",
start_mark, "expected the node content, but found #{token.id}",
token.start_mark
return event
# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
# BLOCK-END
parse_block_sequence_first_entry: ->
token =
.push token.start_mark
return
parse_block_sequence_entry: ->
if tokens.BlockEntryToken
token =
if not tokens.BlockEntryToken, tokens.BlockEndToken
.push 'parse_block_sequence_entry'
return
else
= 'parse_block_sequence_entry'
return token.end_mark
if not tokens.BlockEndToken
token =
throw new exports.ParserError 'while parsing a block collection',
.slice(-1)[0], "expected <block end>, but found #{token.id}",
token.start_mark
token =
event = new events.SequenceEndEvent token.start_mark, token.end_mark
= .pop()
.pop()
return event
# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
parse_indentless_sequence_entry: ->
if tokens.BlockEntryToken
token =
if not tokens.BlockEntryToken, tokens.KeyToken, \
tokens.ValueToken, tokens.BlockEndToken
.push 'parse_indentless_sequence_entry'
return
else
= 'parse_indentless_sequence_entry'
return token.end_mark
token =
event = new events.SequenceEndEvent token.start_mark, token.start_mark
= .pop()
return event
# block_mapping ::= BLOCK-MAPPING-START
# ((KEY block_node_or_indentless_sequence?)?
# (VALUE block_node_or_indentless_sequence?)?)* BLOCK-END
parse_block_mapping_first_key: ->
token =
.push token.start_mark
return
parse_block_mapping_key: ->
if tokens.KeyToken
token =
if not tokens.KeyToken, tokens.ValueToken, \
tokens.BlockEndToken
.push 'parse_block_mapping_value'
return
else
= 'parse_block_mapping_value'
return token.end_mark
if not tokens.BlockEndToken
token =
throw new exports.ParserError 'while parsing a block mapping',
.slice(-1)[0], "expected <block end>, but found #{token.id}",
token.start_mark
token =
event = new events.MappingEndEvent token.start_mark, token.end_mark
= .pop()
.pop()
return event
parse_block_mapping_value: ->
if tokens.ValueToken
token =
if not tokens.KeyToken, tokens.ValueToken, \
tokens.BlockEndToken
.push 'parse_block_mapping_key'
return
else
= 'parse_block_mapping_key'
return token.end_mark
else
= 'parse_block_mapping_key'
token =
return token.start_mark
# flow_sequence ::= FLOW-SEQUENCE-START
# (flow_sequence_entry FLOW-ENTRY)* flow_sequence_entry? FLOW-SEQUENCE-END
# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
#
# Note that while production rules for both flow_sequence_entry and
# flow_mapping_entry are equal, their interpretations are different. For
# `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
# generate an inline mapping (set syntax).
parse_flow_sequence_first_entry: ->
token =
.push token.start_mark
return yes
parse_flow_sequence_entry: (first = no) ->
if not tokens.FlowSequenceEndToken
if not first
if tokens.FlowEntryToken
else
token =
throw new exports.ParserError 'while parsing a flow sequence',
.slice(-1)[0], "expected ',' or ']', but got #{token.id}",
token.start_mark
if tokens.KeyToken
token =
event = new events.MappingStartEvent null, null, true,
token.start_mark, token.end_mark, true
= 'parse_flow_sequence_entry_mapping_key'
return event
else if not tokens.FlowSequenceEndToken
.push 'parse_flow_sequence_entry'
return
token =
event = new events.SequenceEndEvent token.start_mark, token.end_mark
= .pop()
.pop()
return event
parse_flow_sequence_entry_mapping_key: ->
token =
if not tokens.ValueToken, tokens.FlowEntryToken, \
tokens.FlowSequenceEndToken
.push 'parse_flow_sequence_entry_mapping_value'
return
else
= 'parse_flow_sequence_entry_mapping_value'
return token.end_mark
parse_flow_sequence_entry_mapping_value: ->
if tokens.ValueToken
token =
if not tokens.FlowEntryToken, tokens.FlowSequenceEndToken
.push 'parse_flow_sequence_entry_mapping_end'
return
else
= 'parse_flow_sequence_entry_mapping_end'
return token.end_mark
else
= 'parse_flow_sequence_entry_mapping_end'
token =
return token.start_mark
parse_flow_sequence_entry_mapping_end: ->
= 'parse_flow_sequence_entry'
token =
return new events.MappingEndEvent token.start_mark, token.start_mark
# flow_mapping ::= FLOW-MAPPING-START (flow_mapping_entry FLOW-ENTRY)*
# flow_mapping_entry? FLOW-MAPPING-END
# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
parse_flow_mapping_first_key: ->
token =
.push token.start_mark
return yes
parse_flow_mapping_key: (first = no) ->
if not tokens.FlowMappingEndToken
if not first
if tokens.FlowEntryToken
else
token =
throw new exports.ParserError 'while parsing a flow mapping',
.slice(-1)[0], "expected ',' or '}', but got #{token.id}",
token.start_mark
if tokens.KeyToken
token =
if not tokens.ValueToken, tokens.FlowEntryToken, \
tokens.FlowMappingEndToken
.push 'parse_flow_mapping_value'
return
else
= 'parse_flow_mapping_value'
return token.end_mark
else if not tokens.FlowMappingEndToken
.push 'parse_flow_mapping_empty_value'
return
token =
event = new events.MappingEndEvent token.start_mark, token.end_mark
= .pop()
.pop()
return event
parse_flow_mapping_value: ->
if tokens.ValueToken
token =
if not tokens.FlowEntryToken, tokens.FlowMappingEndToken
.push 'parse_flow_mapping_key'
return
else
= 'parse_flow_mapping_key'
return token.end_mark
else
= 'parse_flow_mapping_key'
token =
return token.start_mark
parse_flow_mapping_empty_value: ->
= 'parse_flow_mapping_key'
return .start_mark
process_empty_scalar: (mark) ->
return new events.ScalarEvent null, null, [true, false], '', mark, mark