grammar Bosl # unicode generalized categories , according to regex ruby page rule lower /[[:lower:]]/ end # Lowercase alphabetical character rule upper /[[:upper:]]/ end # Uppercase alphabetical rule alnum /[[:alnum:]]/ end # Alphabetic and numeric character rule alpha /[[:alpha:]]/ end # Alphabetic character rule blank /[[:blank:]]/ end # Space or tab rule space /[[:space:]]/ end # Whitespace character ([:blank:], newline, carriage return, etc.) rule digit /[[:digit:]]/ end # Digit rule graph /[[:graph:]]/ end # Non-blank character (excludes spaces, control characters, and similar) rule print /[[:print:]]/ end # Like [:graph:], but includes the space character rule xdigit /[[:xdigit:]]/ end # Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F) rule linebreak (!blank space) end #define in regex terms for utf rule comment #don't include the newline (which ends the comment) "#" /.*/ end rule name_expression (name:([a-z_] [a-zA-Z0-9_]*) space*) { Ast::NameExpression.new(capture(:name).to_str)} end rule module_name_expression (name:([A-Z] [a-zA-Z0-9_]*) space*) { Ast::ModuleName.new(capture(:name).to_str)} end rule digits [0-9] [0-9]* end rule integer_expression (digits space*) { Ast::IntegerExpression.new(to_str.to_i) } end rule string_expression #"'" (/.*/ !"'") "'" ('"' str:(!'"' .)* '"') {Ast::StringExpression.new(capture(:str).to_str) } end rule basic_expression name_expression | integer_expression | module_name_expression | string_expression end 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_if 'if' end rule keyword_rescue 'rescue' space* end rule keyword_return 'return' space* end rule keyword_module 'module' space* end rule keyword_unless 'unless' space* end rule keyword_until 'until' space* end rule keyword_while 'while' space* end rule keyword_nil ('nil' space* ){ Ast::NilExpression.new } end rule keyword_false ('false' space*) { Ast::FalseExpression.new } 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 rule keyword_expression keyword_true | keyword_false | keyword_nil | basic_expression end # Tokens are single or double character combinations with "meaning" # braces, comman, point, questionmark , quotes, that kind of thing # operator symbols are separate in Opreators rule left_parenthesis '(' space* end rule right_parenthesis ')' space* end rule left_brace '{' space* end rule right_brace '}' space* end rule left_bracket '[' space* end rule right_bracket ']' space* end rule association "=>" space* end rule comma ',' space* end rule colon ':' space* end rule semicolon ';' space* end rule question_mark '?' space* end rule excamation_mark '!' space* end rule more_args (comma basic_expression )* { captures(:basic_expression).collect{|u| u.value } } end rule argument_list (left_parenthesis basic_expression? more_args right_parenthesis){ args = [ ] args << capture(:basic_expression).value if capture(:basic_expression) args += capture(:more_args).value if capture(:more_args) args } end rule call_site (basic_expression "." name_expression argument_list space?) { Ast::CallSiteExpression.new(capture(:name_expression).to_str , capture(:argument_list).value , capture(:basic_expression).value ) } end rule value_expression call_site | basic_expression end rule function_definition keyword_def name:function_name parameter_list newline expressions_end newline end rule parameter_list left_parenthesis parameter_list:( name:parameter? (comma name:parameter)* ) right_parenthesis end rule more_typed_args (comma typed_arg )* { captures(:typed_arg).collect{|u| u.value } } end rule typed_argument_list (left_parenthesis typed_arg? more_typed_args right_parenthesis){ args = [ ] args << capture(:typed_arg).value if capture(:typed_arg) args += capture(:more_typed_args).value if capture(:more_typed_args) args } end rule type (typ:("int" | "ref") space*) { capture(:typ).to_s } end rule typed_arg (type name_expression) { Ast::TypedName.new(capture(:type).value , capture(:name_expression).value.name) } end rule variable_definition (typed_arg ("=" space* value_expression)?) { type = capture(:typed_arg).value value = capture(:value_expression) ? capture(:value_expression).value : nil var = Ast::VariableDefinition.new(type.type , type.name , value) } end rule assignment (name_expression "=" space* value_expression){ Ast::AssignmentExpression.new( capture(:name_expression).value.name , capture(:value_expression).value) } end rule conditional (keyword_if left_parenthesis value_expression right_parenthesis body keyword_end) { Ast::IfExpression.new( capture(:value_expression).value , capture(:body).value , nil) } end rule while keyword_while left_parenthesis value_expression right_parenthesis keyword_do body keyword_end end rule return keyword_return value_expression newline end rule body (statement+){ captures(:statement).collect{|u| u.value } } end rule statement conditional | while | return | variable_definition | assignment end end