2014-04-27 15:30:32 +02:00
|
|
|
require_relative "basic_types"
|
2014-04-27 17:13:10 +02:00
|
|
|
require_relative "tokens"
|
2014-04-27 20:12:42 +02:00
|
|
|
require_relative "keywords"
|
2014-04-24 14:43:20 +02:00
|
|
|
|
2014-04-27 14:44:34 +02:00
|
|
|
module Parser
|
2014-04-27 17:13:10 +02:00
|
|
|
|
2014-04-29 15:22:12 +02:00
|
|
|
# obviously a work in progress !!
|
2014-04-27 17:13:10 +02:00
|
|
|
# We "compose" the parser from bits, divide and hopefully conquer
|
|
|
|
|
2014-05-10 10:03:23 +02:00
|
|
|
class Crystal < Parslet::Parser
|
2014-04-27 15:30:32 +02:00
|
|
|
include BasicTypes
|
2014-04-27 17:13:10 +02:00
|
|
|
include Tokens
|
2014-04-27 20:12:42 +02:00
|
|
|
include Keywords
|
2014-04-27 17:13:10 +02:00
|
|
|
|
2014-04-29 15:22:12 +02:00
|
|
|
# a note about .maybe : .maybe is almost every respect the same as .repeat(0,1)
|
|
|
|
# so either 0, or 1, in other words maybe. Nice feature, but there are strings attached:
|
|
|
|
# a maybe removes the 0 a sequence (array) to a single (hash). Thus 2 transformations are needed
|
|
|
|
# More work than the prettiness is worth, so only use .maybe on something that does not need capturing
|
|
|
|
|
2014-04-27 20:12:42 +02:00
|
|
|
rule(:argument_list) {
|
2014-04-27 17:13:10 +02:00
|
|
|
left_parenthesis >>
|
2014-05-10 10:03:23 +02:00
|
|
|
( (simple_expression.as(:argument) >> space? >>
|
|
|
|
(comma >> space? >> simple_expression.as(:argument)).repeat(0)).repeat(0,1)).as(:argument_list) >>
|
|
|
|
space? >> right_parenthesis
|
2014-04-24 14:43:20 +02:00
|
|
|
}
|
|
|
|
|
2014-04-27 20:12:42 +02:00
|
|
|
rule(:function_call) { name.as(:function_call) >> argument_list }
|
2014-04-24 14:43:20 +02:00
|
|
|
|
2014-04-28 21:07:13 +02:00
|
|
|
rule(:assignment) { name.as(:asignee) >> equal_sign >> expression.as(:asigned) }
|
2014-05-08 17:42:24 +02:00
|
|
|
#| (name >> space? >> equal_sign.absent?)
|
2014-05-08 18:41:27 +02:00
|
|
|
|
|
|
|
rule(:simple_expression) { function_call | integer | string | name }
|
2014-05-08 18:49:15 +02:00
|
|
|
rule(:expression) { (conditional | simple_expression ) >> newline.maybe }
|
2014-04-24 14:43:20 +02:00
|
|
|
|
2014-04-28 14:46:57 +02:00
|
|
|
def delimited_expressions( delimit )
|
2014-05-08 18:49:15 +02:00
|
|
|
( (delimit.absent? >> (assignment | expression)).repeat(1)).as(:expressions) >> delimit >> newline.maybe
|
2014-04-28 14:46:57 +02:00
|
|
|
end
|
|
|
|
|
2014-04-27 20:41:38 +02:00
|
|
|
rule(:conditional) {
|
2014-05-08 18:49:15 +02:00
|
|
|
keyword_if >> left_parenthesis >> expression.as(:conditional) >> right_parenthesis >> newline >>
|
2014-04-28 14:46:57 +02:00
|
|
|
delimited_expressions(keyword_else).as(:if_true) >>
|
|
|
|
delimited_expressions(keyword_end).as(:if_false)
|
2014-04-24 14:43:20 +02:00
|
|
|
}
|
2014-04-28 20:21:12 +02:00
|
|
|
|
2014-04-28 14:46:57 +02:00
|
|
|
rule(:expressions_else) { delimited_expressions(keyword_else) }
|
|
|
|
rule(:expressions_end) { delimited_expressions(keyword_end) }
|
|
|
|
|
2014-04-27 20:12:42 +02:00
|
|
|
rule(:function_definition) {
|
2014-05-08 20:09:07 +02:00
|
|
|
keyword_def >> name.as(:function_definition) >> parmeter_list >> newline >> expressions_end
|
2014-04-24 14:43:20 +02:00
|
|
|
}
|
|
|
|
|
2014-04-27 20:41:38 +02:00
|
|
|
rule(:parmeter_list) {
|
2014-04-27 17:13:10 +02:00
|
|
|
left_parenthesis >>
|
2014-04-29 15:22:12 +02:00
|
|
|
((name.as(:parmeter) >> (comma >> name.as(:parmeter)).repeat(0)).repeat(0,1)).as(:parmeter_list) >>
|
2014-04-27 17:13:10 +02:00
|
|
|
right_parenthesis
|
2014-04-24 14:43:20 +02:00
|
|
|
}
|
2014-05-10 10:03:23 +02:00
|
|
|
rule(:root){ function_definition | expression | assignment | function_call }
|
2014-04-24 14:43:20 +02:00
|
|
|
end
|
|
|
|
end
|