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