From 619780a913c1a0e894b08c129ed7d4f78673673a Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Thu, 27 Aug 2015 21:00:30 +0300 Subject: [PATCH] transform first couple of grammar files --- lib/parser/basic.citrus | 92 ++++++++++++++++++++++++++++++++++++++ lib/parser/keywords.citrus | 31 +++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 lib/parser/basic.citrus create mode 100644 lib/parser/keywords.citrus diff --git a/lib/parser/basic.citrus b/lib/parser/basic.citrus new file mode 100644 index 0000000..57ac710 --- /dev/null +++ b/lib/parser/basic.citrus @@ -0,0 +1,92 @@ + +grammar BasicTypes + + # space really is just space. ruby is newline sensitive, so there is more whitespace footwork + # rule of thumb is that anything eats space behind it, but only space, no newlines + rule space [ \t]* end + + rule linebreak "\n" end + + rule comment + "#" (/.*/ !linebreak) linebreak + end + + rule dot '.' end + + ## Lexical syntax + + rule number + float | integer + end + + rule float + (digits '.' digits space*) { to_str.to_f } + end + + rule integer + (digits space*) { to_str.to_i } + end + + rule digits + [0-9]+ ('_' [0-9]+)* # Numbers may contain underscores. + end + + rule lparen '(' space* end + rule rparen ')' space* end + + + # Hierarchical syntax + + rule term + additive | factor + end + + rule additive + (factor operator:('+' | '-') space* term) { + capture(:factor).value.send(capture(:operator).to_s, capture(:term).value) + } + end + + rule factor + multiplicative | prefix + end + + rule multiplicative + (prefix operator:('*' | '/' | '%') space* factor) { + capture(:prefix).value.send(capture(:operator).to_s, capture(:factor).value) + } + end + + rule prefix + prefixed | exponent + end + + rule prefixed + (operator:('-' | '+' | '~') space* prefix) { + s = capture(:operator).to_s + s += '@' unless s == '~' # Unary + and - require an @. + capture(:prefix).value.send(s) + } + end + + rule exponent + exponential | primary + end + + rule exponential + (primary operator:'**' space* prefix) { + capture(:primary).value.send(capture(:operator).to_s, capture(:prefix).value) + } + end + + rule primary + group | number + end + + rule group + (lparen term rparen) { + capture(:term).value + } + end + +end diff --git a/lib/parser/keywords.citrus b/lib/parser/keywords.citrus new file mode 100644 index 0000000..372ad0e --- /dev/null +++ b/lib/parser/keywords.citrus @@ -0,0 +1,31 @@ +grammar Keywords + include BasicTypes + + rule keyword_begin 'begin' space? end + rule keyword_class 'class' space? end + rule keyword_def 'def' space? end + rule keyword_do 'do' space? end + rule keyword_else 'else' space? end + rule keyword_end 'end' space? end + rule keyword_false 'false' space? end + rule keyword_if 'if' space? end + rule keyword_rescue 'rescue' space? end + rule keyword_return 'return' space? end + rule keyword_module 'module' space? end + rule keyword_nil 'nil' space? end + rule keyword_unless 'unless' space? end + rule keyword_until 'until' space? end + rule keyword_while 'while' space? end + + rule keyword_true + ('true' space?) { Ast::TrueExpression.new } + end + + # this rule is just to make sure identifiers can't be keywords. Kind of duplication here, but we need the + # space in above rules, so just make sure to add any here too. + rule keyword ('begin' | 'def' | 'do' | 'else' | 'end' | + 'false' | 'if' | 'rescue' | 'true' | 'nil' | + 'unless' | 'until' | 'while') space? + end + +end