lib/hotcell/parser.y in hotcell-0.1.0 vs lib/hotcell/parser.y in hotcell-0.2.0
- old
+ new
@@ -43,10 +43,11 @@
left PLUS MINUS
left GT GTE LT LTE
nonassoc EQUAL INEQUAL
left AND
left OR
+ nonassoc RANGE
right TERNARY
right ASSIGN
nonassoc COMMA COLON
left SEMICOLON NEWLINE
preclow
@@ -55,13 +56,20 @@
document: document document_unit { pospoppush(2); val[0].children.push(val[1]) }
| document_unit { result = build Joiner, :JOINER, val[0], position: pospoppush(1) }
document_unit: template | tag | block_tag | command_tag
template: TEMPLATE { result = val[0] }
- tag: TOPEN TCLOSE { result = build Tag, :TAG, mode: TAG_MODES[val[0]], position: pospoppush(2) }
+ tag: TOPEN TCLOSE {
+ result = build Tag, :TAG,
+ mode: tag_modes(val[0], @escape_tags ? :escape : :normal),
+ position: pospoppush(2)
+ }
| TOPEN sequence TCLOSE {
- result = build Tag, :TAG, *Array.wrap(val[1]).flatten, mode: TAG_MODES[val[0]], position: pospoppush(3)
+ result = build Tag, :TAG,
+ *Array.wrap(val[1]).flatten,
+ mode: tag_modes(val[0], @escape_tags ? :escape : :normal),
+ position: pospoppush(3)
}
command_body: COMMAND { result = build @commands[val[0]] || Command, val[0], position: pospoppush(1) }
| COMMAND arguments {
result = build @commands[val[0]] || Command, val[0], *val[1], position: pospoppush(2)
@@ -71,11 +79,11 @@
result = build Assigner, val[0], val[2], position: pospoppush(3)
}
command_tag: TOPEN command TCLOSE {
command = val[1].is_a?(Command) ? val[1] : val[1].children[0]
command.validate!
- result = build Tag, :TAG, val[1], mode: TAG_MODES[val[0]], position: pospoppush(3)
+ result = build Tag, :TAG, val[1], mode: tag_modes(val[0]), position: pospoppush(3)
}
subcommand: SUBCOMMAND { result = build @substack.last[val[0]], val[0], position: pospoppush(1) }
| SUBCOMMAND arguments {
result = build @substack.last[val[0]], val[0], *val[1], position: pospoppush(2)
@@ -92,11 +100,11 @@
}
block_close: ENDBLOCK
| END BLOCK { pospoppush(2) }
| END
block_open_tag: TOPEN block_open TCLOSE {
- result = build Tag, :TAG, val[1], mode: TAG_MODES[val[0]], position: pospoppush(3)
+ result = build Tag, :TAG, val[1], mode: tag_modes(val[0]), position: pospoppush(3)
}
block_close_tag: TOPEN block_close TCLOSE { pospoppush(3) }
block_subnodes: block_subnodes document_unit {
pospoppush(2)
val[0][-1].is_a?(Joiner) ?
@@ -128,31 +136,31 @@
| sequence NEWLINE { pospoppush(2) }
| NEWLINE sequence { pospoppush(2, 1); result = val[1] }
| NEWLINE { result = [] }
| expr { result = [val[0]] }
- expr: expr MULTIPLY expr { result = build Calculator, :MULTIPLY, val[0], val[2], position: pospoppush(3) }
- | expr POWER expr { result = build Calculator, :POWER, val[0], val[2], position: pospoppush(3) }
- | expr DIVIDE expr { result = build Calculator, :DIVIDE, val[0], val[2], position: pospoppush(3) }
- | expr PLUS expr { result = build Calculator, :PLUS, val[0], val[2], position: pospoppush(3) }
- | expr MINUS expr { result = build Calculator, :MINUS, val[0], val[2], position: pospoppush(3) }
- | expr MODULO expr { result = build Calculator, :MODULO, val[0], val[2], position: pospoppush(3) }
- | MINUS expr =UMINUS { result = build Calculator, :UMINUS, val[1], position: pospoppush(2) }
- | PLUS expr =UPLUS { result = build Calculator, :UPLUS, val[1], position: pospoppush(2) }
- | expr AND expr { result = build Calculator, :AND, val[0], val[2], position: pospoppush(3) }
- | expr OR expr { result = build Calculator, :OR, val[0], val[2], position: pospoppush(3) }
- | expr GT expr { result = build Calculator, :GT, val[0], val[2], position: pospoppush(3) }
- | expr GTE expr { result = build Calculator, :GTE, val[0], val[2], position: pospoppush(3) }
- | expr LT expr { result = build Calculator, :LT, val[0], val[2], position: pospoppush(3) }
- | expr LTE expr { result = build Calculator, :LTE, val[0], val[2], position: pospoppush(3) }
- | expr EQUAL expr { result = build Calculator, :EQUAL, val[0], val[2], position: pospoppush(3) }
- | expr INEQUAL expr { result = build Calculator, :INEQUAL, val[0], val[2], position: pospoppush(3) }
- | NOT expr { result = build Calculator, :NOT, val[1], position: pospoppush(2) }
+ expr: expr MULTIPLY expr { result = build Expression, :MULTIPLY, val[0], val[2], position: pospoppush(3) }
+ | expr POWER expr { result = build Expression, :POWER, val[0], val[2], position: pospoppush(3) }
+ | expr DIVIDE expr { result = build Expression, :DIVIDE, val[0], val[2], position: pospoppush(3) }
+ | expr PLUS expr { result = build Expression, :PLUS, val[0], val[2], position: pospoppush(3) }
+ | expr MINUS expr { result = build Expression, :MINUS, val[0], val[2], position: pospoppush(3) }
+ | expr MODULO expr { result = build Expression, :MODULO, val[0], val[2], position: pospoppush(3) }
+ | MINUS expr =UMINUS { result = build Expression, :UMINUS, val[1], position: pospoppush(2) }
+ | PLUS expr =UPLUS { result = build Expression, :UPLUS, val[1], position: pospoppush(2) }
+ | expr AND expr { result = build Expression, :AND, val[0], val[2], position: pospoppush(3) }
+ | expr OR expr { result = build Expression, :OR, val[0], val[2], position: pospoppush(3) }
+ | expr GT expr { result = build Expression, :GT, val[0], val[2], position: pospoppush(3) }
+ | expr GTE expr { result = build Expression, :GTE, val[0], val[2], position: pospoppush(3) }
+ | expr LT expr { result = build Expression, :LT, val[0], val[2], position: pospoppush(3) }
+ | expr LTE expr { result = build Expression, :LTE, val[0], val[2], position: pospoppush(3) }
+ | expr EQUAL expr { result = build Expression, :EQUAL, val[0], val[2], position: pospoppush(3) }
+ | expr INEQUAL expr { result = build Expression, :INEQUAL, val[0], val[2], position: pospoppush(3) }
+ | NOT expr { result = build Expression, :NOT, val[1], position: pospoppush(2) }
| IDENTIFER ASSIGN expr { result = build Assigner, val[0], val[2], position: pospoppush(3) }
| expr PERIOD method { pospoppush(3); val[2].children[0] = val[0]; result = val[2] }
| expr AOPEN arguments ACLOSE {
- result = build Summoner, 'manipulator_brackets', val[0], *val[2], position: pospoppush(4)
+ result = build Summoner, '[]', val[0], *val[2], position: pospoppush(4)
}
| POPEN PCLOSE { pospoppush(2); result = nil }
| POPEN sequence PCLOSE {
position = pospoppush(3)
result = case val[1].size
@@ -162,16 +170,21 @@
build Sequencer, :SEQUENCE, *val[1].flatten, position: position
end
}
| value
- value: const | number | string | array | hash | method
+ value: const | number | string | range | array | hash | method
const: NIL | TRUE | FALSE
number: INTEGER | FLOAT
string: STRING | REGEXP
+ range: expr RANGE expr {
+ result = build Expression, val[1] == '..' ? :RANGE : :ERANGE,
+ val[0], val[2], position: pospoppush(3)
+ }
+
array: AOPEN ACLOSE { result = build Arrayer, :ARRAY, position: pospoppush(2) }
| AOPEN params ACLOSE { result = build Arrayer, :ARRAY, *val[1], position: pospoppush(3) }
params: params COMMA expr { pospoppush(3); val[0].push(val[2]) }
| expr { result = [val[0]] }
@@ -205,21 +218,25 @@
BCLOSE = { ']' => :ACLOSE, '}' => :HCLOSE, ')' => :PCLOSE }
NEWLINE_PRED = Set.new(BOPEN.values + OPERATIONS.values)
NEWLINE_NEXT = Set.new(BCLOSE.values + [:NEWLINE])
- TAG_MODES = { '{{' => :normal, '{{!' => :silence }
+ TAG_MODES = {
+ '!' => :silence, '^' => :escape, 'e' => :escape,
+ '~' => :normal, 'r' => :normal
+ }
def initialize source, options = {}
@source = Source.wrap(source)
@lexer = Lexer.new(source)
@tokens = @lexer.tokens
@position = -1
@commands = options[:commands] || {}
@blocks = options[:blocks] || {}
@endblocks = Set.new(@blocks.keys.map { |identifer| "end#{identifer}" })
+ @escape_tags = !!options[:escape_tags]
@substack = []
@posstack = []
end
@@ -233,9 +250,14 @@
# because fuck the brains, that's why!
last = @posstack.pop
reduced = @posstack.push(@posstack.pop(pop)[push])[-1]
@posstack.push last
reduced
+ end
+
+ def tag_modes tag, default = :normal
+ mode = tag.gsub(/^{{/, '').first
+ TAG_MODES[mode] || default
end
def parse
if @tokens.size == 0
build Joiner, :JOINER, position: 0