diff --git a/spec/zodiac/parser_spec.rb b/spec/zodiac/parser_spec.rb index 58885a3..8e466c3 100644 --- a/spec/zodiac/parser_spec.rb +++ b/spec/zodiac/parser_spec.rb @@ -15,5 +15,19 @@ expect(actual).to eq(expected) end end + + context 'when simple expression' do + xit 'returns simple expression' do + parser = described_class.new('1 + 2') + + actual = parser.parse + expected = { + kind: 'PROGRAM', + cmp_stmts: [] + } + + expect(actual).to eq(expected) + end + end end end diff --git a/src/zodiac/parser.rb b/src/zodiac/parser.rb index 2100957..e19f3ec 100644 --- a/src/zodiac/parser.rb +++ b/src/zodiac/parser.rb @@ -4,153 +4,6 @@ module Zodiac # Base parsing class for the Zodiac language. - - # Here is the syntax of Ruby in pseudo BNF. For more detail, see parse.y in Ruby distribution. - - # ARG : LHS `=' ARG - # | LHS OP_ASGN ARG - # | ARG `..' ARG - # | ARG `...' ARG - # | ARG `+' ARG - # | ARG `-' ARG - # | ARG `*' ARG - # | ARG `/' ARG - # | ARG `%' ARG - # | ARG `**' ARG - # | `+' ARG - # | `-' ARG - # | ARG `|' ARG - # | ARG `^' ARG - # | ARG `&' ARG - # | ARG `<=>' ARG - # | ARG `>' ARG - # | ARG `>=' ARG - # | ARG `<' ARG - # | ARG `<=' ARG - # | ARG `==' ARG - # | ARG `===' ARG - # | ARG `!=' ARG - # | ARG `=~' ARG - # | ARG `!~' ARG - # | `!' ARG - # | `~' ARG - # | ARG `<<' ARG - # | ARG `>>' ARG - # | ARG `&&' ARG - # | ARG `||' ARG - # | defined? ARG - # | PRIMARY - - # PRIMARY : `(' COMPSTMT `)' - # | LITERAL - # | VARIABLE - # | PRIMARY `::' IDENTIFIER - # | `::' IDENTIFIER - # | PRIMARY `[' [ARGS] `]' - # | `[' [ARGS [`,']] `]' - # | `{' [(ARGS|ASSOCS) [`,']] `}' - # | return [`(' [CALL_ARGS] `)'] - # | yield [`(' [CALL_ARGS] `)'] - # | defined? `(' ARG `)' - # | FUNCTION - # | FUNCTION `{' [`|' [BLOCK_VAR] `|'] COMPSTMT `}' - # | if EXPR THEN - # COMPSTMT - # (elsif EXPR THEN COMPSTMT)* - # [else COMPSTMT] - # end - # | unless EXPR THEN - # COMPSTMT - # [else COMPSTMT] - # end - # | while EXPR DO COMPSTMT end - # | until EXPR DO COMPSTMT end - # | case COMPSTMT - # (when WHEN_ARGS THEN COMPSTMT)+ - # [else COMPSTMT] - # end - # | for BLOCK_VAR in EXPR DO - # COMPSTMT - # end - # | begin - # COMPSTMT - # [rescue [ARGS] DO COMPSTMT]+ - # [else COMPSTMT] - # [ensure COMPSTMT] - # end - # | class IDENTIFIER [`<' IDENTIFIER] - # COMPSTMT - # end - # | module IDENTIFIER - # COMPSTMT - # end - # | def FNAME ARGDECL - # COMPSTMT - # end - # | def SINGLETON (`.'|`::') FNAME ARGDECL - # COMPSTMT - # end - - # WHEN_ARGS : ARGS [`,' `*' ARG] - # | `*' ARG - - # THEN : TERM - # | then - # | TERM then - - # DO : TERM - # | do - # | TERM do - - # BLOCK_VAR : LHS - # | MLHS - - # MLHS : MLHS_ITEM `,' [MLHS_ITEM (`,' MLHS_ITEM)*] [`*' [LHS]] - # | `*' LHS - - # MLHS_ITEM : LHS - # | '(' MLHS ')' - - # LHS : VARIABLE - # | PRIMARY `[' [ARGS] `]' - # | PRIMARY `.' IDENTIFIER - - # MRHS : ARGS [`,' `*' ARG] - # | `*' ARG - - # CALL_ARGS : ARGS - # | ARGS [`,' ASSOCS] [`,' `*' ARG] [`,' `&' ARG] - # | ASSOCS [`,' `*' ARG] [`,' `&' ARG] - # | `*' ARG [`,' `&' ARG] - # | `&' ARG - # | COMMAND - - # ARGS : ARG (`,' ARG)* - - # ARGDECL : `(' ARGLIST `)' - # | ARGLIST TERM - - # ARGLIST : IDENTIFIER(`,'IDENTIFIER)*[`,'`*'[IDENTIFIER]][`,'`&'IDENTIFIER] - # | `*'IDENTIFIER[`,'`&'IDENTIFIER] - # | [`&'IDENTIFIER] - - # SINGLETON : VARIABLE - # | `(' EXPR `)' - - # ASSOCS : ASSOC (`,' ASSOC)* - - # ASSOC : ARG `=>' ARG - - # VARIABLE : VARNAME - # | nil - # | self - - # LITERAL : numeric - # | SYMBOL - # | STRING - # | STRING2 - # | HERE_DOC - # | REGEXP class Parser def initialize(raw_string) @raw_string = raw_string @@ -178,6 +31,13 @@ def parse_program # COMPSTMT : STMT (TERM EXPR)* [TERM] def parse_compstmt + parse_stmt + + while @cur_index < @tokens.length + parse_term + parse_expr + end + { kind: 'COMPSTMT', value: nil } end @@ -246,5 +106,207 @@ def parse_command def parse_function { kind: 'FUNCTION', value: nil } end + + # THEN : TERM + # | then + # | TERM then + def parse_then + { kind: 'THEN', value: nil } + end + + # DO : TERM + # | do + # | TERM do + def parse_do + { kind: 'DO', value: nil } + end + + # BLOCK_VAR : LHS + # | MLHS + def parse_block_var + { kind: 'BLOCK_VAR', value: nil } + end + + # MLHS : MLHS_ITEM `,' [MLHS_ITEM (`,' MLHS_ITEM)*] [`*' [LHS]] + # | `*' LHS + def parse_mlhs + { kind: 'MLHS', value: nil } + end + + # ARG : LHS `=' ARG + # | LHS OP_ASGN ARG + # | ARG `..' ARG + # | ARG `...' ARG + # | ARG `+' ARG + # | ARG `-' ARG + # | ARG `*' ARG + # | ARG `/' ARG + # | ARG `%' ARG + # | ARG `**' ARG + # | `+' ARG + # | `-' ARG + # | ARG `|' ARG + # | ARG `^' ARG + # | ARG `&' ARG + # | ARG `<=>' ARG + # | ARG `>' ARG + # | ARG `>=' ARG + # | ARG `<' ARG + # | ARG `<=' ARG + # | ARG `==' ARG + # | ARG `===' ARG + # | ARG `!=' ARG + # | ARG `=~' ARG + # | ARG `!~' ARG + # | `!' ARG + # | `~' ARG + # | ARG `<<' ARG + # | ARG `>>' ARG + # | ARG `&&' ARG + # | ARG `||' ARG + # | defined? ARG + # | PRIMARY + def parse_arg + { kind: 'ARG', value: nil } + end + + # PRIMARY : `(' COMPSTMT `)' + # | LITERAL + # | VARIABLE + # | PRIMARY `::' IDENTIFIER + # | `::' IDENTIFIER + # | PRIMARY `[' [ARGS] `]' + # | `[' [ARGS [`,']] `]' + # | `{' [(ARGS|ASSOCS) [`,']] `}' + # | return [`(' [CALL_ARGS] `)'] + # | yield [`(' [CALL_ARGS] `)'] + # | defined? `(' ARG `)' + # | FUNCTION + # | FUNCTION `{' [`|' [BLOCK_VAR] `|'] COMPSTMT `}' + # | if EXPR THEN + # COMPSTMT + # (elsif EXPR THEN COMPSTMT)* + # [else COMPSTMT] + # end + # | unless EXPR THEN + # COMPSTMT + # [else COMPSTMT] + # end + # | while EXPR DO COMPSTMT end + # | until EXPR DO COMPSTMT end + # | case COMPSTMT + # (when WHEN_ARGS THEN COMPSTMT)+ + # [else COMPSTMT] + # end + # | for BLOCK_VAR in EXPR DO + # COMPSTMT + # end + # | begin + # COMPSTMT + # [rescue [ARGS] DO COMPSTMT]+ + # [else COMPSTMT] + # [ensure COMPSTMT] + # end + # | class IDENTIFIER [`<' IDENTIFIER] + # COMPSTMT + # end + # | module IDENTIFIER + # COMPSTMT + # end + # | def FNAME ARGDECL + # COMPSTMT + # end + # | def SINGLETON (`.'|`::') FNAME ARGDECL + # COMPSTMT + # end + def parse_primary + { kind: 'PRIMARY', value: nil } + end + + # WHEN_ARGS : ARGS [`,' `*' ARG] + # | `*' ARG + def parse_when_args + { kind: 'WHEN_ARGS', value: nil } + end + + # MLHS_ITEM : LHS + # | '(' MLHS ')' + def parse_mlhs_item + { kind: 'MLHS_ITEM', value: nil } + end + + # LHS : VARIABLE + # | PRIMARY `[' [ARGS] `]' + # | PRIMARY `.' IDENTIFIER + def parse_lhs + { kind: 'LHS', value: nil } + end + + # MRHS : ARGS [`,' `*' ARG] + # | `*' ARG + def parse_mrhs + { kind: 'MRHS', value: nil } + end + + # CALL_ARGS : ARGS + # | ARGS [`,' ASSOCS] [`,' `*' ARG] [`,' `&' ARG] + # | ASSOCS [`,' `*' ARG] [`,' `&' ARG] + # | `*' ARG [`,' `&' ARG] + # | `&' ARG + # | COMMAND + def parse_call_args + { kind: 'CALL_ARGS', value: nil } + end + + # ARGS : ARG (`,' ARG)* + def parse_args + { kind: 'ARGS', value: nil } + end + + # ARGDECL : `(' ARGLIST `)' + # | ARGLIST TERM + def parse_argdecl + { kind: 'ARGDECL', value: nil } + end + + # ARGLIST : IDENTIFIER(`,'IDENTIFIER)*[`,'`*'[IDENTIFIER]][`,'`&'IDENTIFIER] + # | `*'IDENTIFIER[`,'`&'IDENTIFIER] + # | [`&'IDENTIFIER] + def parse_arglist + { kind: 'ARGLIST', value: nil } + end + + # SINGLETON : VARIABLE + # | `(' EXPR `)' + def parse_singleton + { kind: 'SINGLETON', value: nil } + end + + # ASSOCS : ASSOC (`,' ASSOC)* + def parse_assocs + { kind: 'ASSOCS', value: nil } + end + + # ASSOC : ARG `=>' ARG + def parse_assoc + { kind: 'ASSOC', value: nil } + end + + # VARIABLE : VARNAME + # | nil + # | self + def parse_variable + { kind: 'VARIABLE', value: nil } + end + + # LITERAL : numeric + # | SYMBOL + # | STRING + # | STRING2 + # | HERE_DOC + # | REGEXP + def parse_literal + { kind: 'LITERAL', value: nil } + end end end