aboutsummaryrefslogtreecommitdiffstats
path: root/test/racc/assets/huia.y
diff options
context:
space:
mode:
Diffstat (limited to 'test/racc/assets/huia.y')
-rw-r--r--test/racc/assets/huia.y318
1 files changed, 318 insertions, 0 deletions
diff --git a/test/racc/assets/huia.y b/test/racc/assets/huia.y
new file mode 100644
index 0000000000..de9d45150c
--- /dev/null
+++ b/test/racc/assets/huia.y
@@ -0,0 +1,318 @@
+# Copyright (c) 2014 James Harton
+#
+# MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+class Huia::Parser
+
+ token
+ IDENTIFIER EQUAL PLUS MINUS ASTERISK FWD_SLASH COLON FLOAT INTEGER STRING
+ EXPO INDENT OUTDENT OPAREN CPAREN DOT SIGNATURE NL EOF PIPE COMMA NIL TRUE
+ FALSE EQUALITY CALL SELF CONSTANT CHAR DOUBLE_TICK_STRING
+ DOUBLE_TICK_STRING_END INTERPOLATE_START INTERPOLATE_END BOX LSQUARE
+ RSQUARE FACES LFACE RFACE BANG TILDE RETURN NOT_EQUALITY OR AND GT LT
+ GTE LTE AT
+
+ prechigh
+ left EXPO
+ left BANG TILDE
+ left ASTERISK FWD_SLASH PERCENT
+ left PLUS MINUS
+
+ right EQUAL
+ preclow
+
+ rule
+ statements: statement
+ | statements statement { return scope }
+
+ statement: expr eol { return scope.append val[0] }
+ | expr { return scope.append val[0] }
+ | eol { return scope }
+
+ eol: NL | EOF
+ nlq: NL |
+
+ expr: literal
+ | grouped_expr
+ | binary_op
+ | unary_op
+ | method_call
+ | constant
+ | variable
+ | array
+ | hash
+ | return
+
+ return: return_expr
+ | return_nil
+ return_expr: RETURN expr { return n(:Return, val[1]) }
+ return_nil: RETURN { return n(:Return, n(:Nil)) }
+
+ array: empty_array
+ | array_list
+
+ empty_array: BOX { return n :Array }
+
+ array_list: LSQUARE array_items RSQUARE { return val[1] }
+ array_items: expr { return n :Array, [val[0]] }
+ | array_items COMMA expr { val[0].append(val[2]); return val[0] }
+
+ hash: empty_hash
+ | hash_list
+ empty_hash: FACES { return n :Hash }
+ hash_list: LFACE hash_items RFACE { return val[1] }
+ hash_items: hash_item { return n :Hash, val[0] }
+ | hash_items COMMA hash_item { val[0].append(val[2]); return val[0] }
+ hash_item: expr COLON expr { return n :HashItem, val[0], val[2] }
+
+ constant: CONSTANT { return constant val[0] }
+
+ indented: indented_w_stmts
+ | indented_w_expr
+ | indented_wo_stmts
+ indented_w_stmts: indent statements outdent { return val[0] }
+ indented_w_expr: indent expr outdent { return val[0].append(val[1]) }
+ indented_wo_stmts: indent outdent { return val[0] }
+ outdent: OUTDENT { return pop_scope }
+
+
+ indent_w_args: indent_pipe indent_args PIPE nlq INDENT { return val[0] }
+ indent_pipe: PIPE { return push_scope }
+ indent_wo_args: INDENT { return push_scope }
+ indent: indent_w_args
+ | indent_wo_args
+
+ indent_args: indent_arg
+ | indent_args COMMA indent_arg
+ indent_arg: arg_var { return scope.add_argument val[0] }
+ | arg_var EQUAL expr { return n :Assignment, val[0], val[2] }
+ arg_var: IDENTIFIER { return n :Variable, val[0] }
+
+ method_call: method_call_on_object
+ | method_call_on_self
+ | method_call_on_closure
+ method_call_on_object: expr DOT call_signature { return n :MethodCall, val[0], val[2] }
+ | expr DOT IDENTIFIER { return n :MethodCall, val[0], n(:CallSignature, val[2]) }
+ method_call_on_self: call_signature { return n :MethodCall, scope_instance, val[0] }
+
+ method_call_on_closure: AT call_signature { return n :MethodCall, this_closure, val[1] }
+ | AT IDENTIFIER { return n :MethodCall, this_closure, n(:CallSignature, val[1]) }
+
+ call_signature: call_arguments
+ | call_simple_name
+ call_simple_name: CALL { return n :CallSignature, val[0] }
+ call_argument: SIGNATURE call_passed_arg { return n :CallSignature, val[0], [val[1]] }
+ call_passed_arg: call_passed_simple
+ | call_passed_indented
+ call_passed_simple: expr
+ | expr NL
+ call_passed_indented: indented
+ | indented NL
+ call_arguments: call_argument { return val[0] }
+ | call_arguments call_argument { return val[0].concat_signature val[1] }
+
+ grouped_expr: OPAREN expr CPAREN { return n :Expression, val[1] }
+
+ variable: IDENTIFIER { return allocate_local val[0] }
+
+ binary_op: assignment
+ | addition
+ | subtraction
+ | multiplication
+ | division
+ | exponentiation
+ | modulo
+ | equality
+ | not_equality
+ | logical_or
+ | logical_and
+ | greater_than
+ | less_than
+ | greater_or_eq
+ | less_or_eq
+
+ assignment: IDENTIFIER EQUAL expr { return allocate_local_assignment val[0], val[2] }
+ addition: expr PLUS expr { return binary val[0], val[2], 'plus:' }
+ subtraction: expr MINUS expr { return binary val[0], val[2], 'minus:' }
+ multiplication: expr ASTERISK expr { return binary val[0], val[2], 'multiplyBy:' }
+ division: expr FWD_SLASH expr { return binary val[0], val[2], 'divideBy:' }
+ exponentiation: expr EXPO expr { return binary val[0], val[2], 'toThePowerOf:' }
+ modulo: expr PERCENT expr { return binary val[0], val[2], 'moduloOf:' }
+ equality: expr EQUALITY expr { return binary val[0], val[2], 'isEqualTo:' }
+ not_equality: expr NOT_EQUALITY expr { return binary val[0], val[2], 'isNotEqualTo:' }
+ logical_or: expr OR expr { return binary val[0], val[2], 'logicalOr:' }
+ logical_and: expr AND expr { return binary val[0], val[2], 'logicalAnd:' }
+ greater_than: expr GT expr { return binary val[0], val[2], 'isGreaterThan:' }
+ less_than: expr LT expr { return binary val[0], val[2], 'isLessThan:' }
+ greater_or_eq: expr GTE expr { return binary val[0], val[2], 'isGreaterOrEqualTo:' }
+ less_or_eq: expr LTE expr { return binary val[0], val[2], 'isLessOrEqualTo:' }
+
+ unary_op: unary_not
+ | unary_plus
+ | unary_minus
+ | unary_complement
+
+ unary_not: BANG expr { return unary val[1], 'unaryNot' }
+ unary_plus: PLUS expr { return unary val[1], 'unaryPlus' }
+ unary_minus: MINUS expr { return unary val[1], 'unaryMinus' }
+ unary_complement: TILDE expr { return unary val[1], 'unaryComplement' }
+
+ literal: integer
+ | float
+ | string
+ | nil
+ | true
+ | false
+ | self
+
+ float: FLOAT { return n :Float, val[0] }
+ integer: INTEGER { return n :Integer, val[0] }
+ nil: NIL { return n :Nil }
+ true: TRUE { return n :True }
+ false: FALSE { return n :False }
+ self: SELF { return n :Self }
+
+ string: STRING { return n :String, val[0] }
+ | interpolated_string
+ | empty_string
+
+ interpolated_string: DOUBLE_TICK_STRING interpolated_string_contents DOUBLE_TICK_STRING_END { return val[1] }
+ interpolation: INTERPOLATE_START expr INTERPOLATE_END { return val[1] }
+ interpolated_string_contents: interpolated_string_chunk { return n :InterpolatedString, val[0] }
+ | interpolated_string_contents interpolated_string_chunk { val[0].append(val[1]); return val[0] }
+ interpolated_string_chunk: chars { return val[0] }
+ | interpolation { return to_string(val[0]) }
+ empty_string: DOUBLE_TICK_STRING DOUBLE_TICK_STRING_END { return n :String, '' }
+
+ chars: CHAR { return n :String, val[0] }
+ | chars CHAR { val[0].append(val[1]); return val[0] }
+end
+
+---- inner
+
+attr_accessor :lexer, :scopes, :state
+
+def initialize lexer
+ @lexer = lexer
+ @state = []
+ @scopes = []
+ push_scope
+end
+
+def ast
+ @ast ||= do_parse
+ @scopes.first
+end
+
+def on_error t, val, vstack
+ line = lexer.line
+ col = lexer.column
+ message = "Unexpected #{token_to_str t} at #{lexer.filename} line #{line}:#{col}:\n\n"
+
+ start = line - 5 > 0 ? line - 5 : 0
+ i_size = line.to_s.size
+ (start..(start + 5)).each do |i|
+ message << sprintf("\t%#{i_size}d: %s\n", i, lexer.get_line(i))
+ message << "\t#{' ' * i_size} #{'-' * (col - 1)}^\n" if i == line
+ end
+
+ raise SyntaxError, message
+end
+
+def next_token
+ nt = lexer.next_computed_token
+ # just use a state stack for now, we'll have to do something
+ # more sophisticated soon.
+ if nt && nt.first == :state
+ if nt.last
+ state.push << nt.last
+ else
+ state.pop
+ end
+ next_token
+ else
+ nt
+ end
+end
+
+def push_scope
+ new_scope = Huia::AST::Scope.new scope
+ new_scope.file = lexer.filename
+ new_scope.line = lexer.line
+ new_scope.column = lexer.column
+ scopes.push new_scope
+ new_scope
+end
+
+def pop_scope
+ scopes.pop
+end
+
+def scope
+ scopes.last
+end
+
+def binary left, right, method
+ node(:MethodCall, left, node(:CallSignature, method, [right]))
+end
+
+def unary left, method
+ node(:MethodCall, left, node(:CallSignature, method))
+end
+
+def node type, *args
+ Huia::AST.const_get(type).new(*args).tap do |n|
+ n.file = lexer.filename
+ n.line = lexer.line
+ n.column = lexer.column
+ end
+end
+alias n node
+
+def allocate_local name
+ node(:Variable, name).tap do |n|
+ scope.allocate_local n
+ end
+end
+
+def allocate_local_assignment name, value
+ node(:Assignment, name, value).tap do |n|
+ scope.allocate_local n
+ end
+end
+
+def this_closure
+ allocate_local('@')
+end
+
+def scope_instance
+ node(:ScopeInstance, scope)
+end
+
+def constant name
+ return scope_instance if name == 'self'
+ node(:Constant, name)
+end
+
+def to_string expr
+ node(:MethodCall, expr, node(:CallSignature, 'toString'))
+end