dagon 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +86 -0
- data/Rakefile +40 -0
- data/bin/dagon +44 -0
- data/bin/dspec +35 -0
- data/bin/idg +15 -0
- data/bin/idgr +16 -0
- data/build/parser.rb +1015 -0
- data/build/scanner.rb +686 -0
- data/core/array.rb +64 -0
- data/core/block.rb +38 -0
- data/core/class.rb +91 -0
- data/core/false.rb +38 -0
- data/core/float.rb +93 -0
- data/core/frame.rb +24 -0
- data/core/hash.rb +51 -0
- data/core/integer.rb +98 -0
- data/core/object.rb +50 -0
- data/core/string.rb +57 -0
- data/core/true.rb +37 -0
- data/core/vm.rb +125 -0
- data/core/void.rb +37 -0
- data/dagon.gemspec +19 -0
- data/dagon.vim +45 -0
- data/dagon/ast/array_node.rb +17 -0
- data/dagon/ast/assignment_node.rb +21 -0
- data/dagon/ast/block_node.rb +19 -0
- data/dagon/ast/class_definition_node.rb +24 -0
- data/dagon/ast/constant_ref_node.rb +15 -0
- data/dagon/ast/frame.rb +23 -0
- data/dagon/ast/function_call_node.rb +33 -0
- data/dagon/ast/function_definition_node.rb +15 -0
- data/dagon/ast/function_node.rb +23 -0
- data/dagon/ast/hash_node.rb +16 -0
- data/dagon/ast/if_node.rb +20 -0
- data/dagon/ast/instance_init_node.rb +28 -0
- data/dagon/ast/instance_var_ref_node.rb +21 -0
- data/dagon/ast/literal_node.rb +23 -0
- data/dagon/ast/node.rb +22 -0
- data/dagon/ast/root_node.rb +19 -0
- data/dagon/ast/string_node.rb +16 -0
- data/dagon/ast/unary_function_call_node.rb +17 -0
- data/dagon/ast/var_ref_node.rb +19 -0
- data/dagon/ast/while_node.rb +17 -0
- data/dagon/parser.y +151 -0
- data/dagon/scanner.rl +143 -0
- data/examples/assert.dg +8 -0
- data/examples/assignment.dg +2 -0
- data/examples/block.dg +8 -0
- data/examples/class.dg +6 -0
- data/examples/conditional.dg +3 -0
- data/examples/conditions.dg +6 -0
- data/examples/equality.dg +6 -0
- data/examples/error.dg +1 -0
- data/examples/eval.dg +1 -0
- data/examples/fibonacci.dg +15 -0
- data/examples/greeter.dg +6 -0
- data/examples/input.dg +3 -0
- data/examples/instance_variables.dg +11 -0
- data/examples/iterate.dg +2 -0
- data/examples/method_call.dg +9 -0
- data/examples/method_definition.dg +4 -0
- data/examples/operators.dg +6 -0
- data/examples/output.dg +1 -0
- data/examples/require.dg +1 -0
- data/spec/array_spec.dg +26 -0
- data/spec/assertions.dg +11 -0
- data/spec/boolean_spec.dg +48 -0
- data/spec/dspec.dg +16 -0
- data/spec/float_spec.dg +15 -0
- data/spec/hash_spec.dg +6 -0
- data/spec/number_spec.dg +18 -0
- data/spec/return_spec.dg +12 -0
- data/spec/string_spec.dg +18 -0
- data/spec/void_spec.dg +9 -0
- data/spec/while_spec.dg +7 -0
- metadata +180 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class ConstantRefNode < Node
|
4
|
+
attr_reader :variable_name
|
5
|
+
def initialize filename, line_number, variable_name
|
6
|
+
super filename, line_number
|
7
|
+
@constant_name = variable_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate interpreter
|
11
|
+
interpreter.current_object.dagon_const_get(@constant_name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/dagon/ast/frame.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class Frame
|
4
|
+
attr_reader :frame_name
|
5
|
+
def initialize frame_name
|
6
|
+
@frame_name = frame_name
|
7
|
+
@local_variables = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def local_variable? name
|
11
|
+
@local_variables.key? name
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](key)
|
15
|
+
@local_variables[key]
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
@local_variables[key] = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class DagonError < StandardError; end
|
4
|
+
class DagonArgumentError < DagonError; end
|
5
|
+
|
6
|
+
class FunctionCallNode < Node
|
7
|
+
def initialize filename, line_number, object, function_name, arguments, block
|
8
|
+
super filename, line_number
|
9
|
+
@function_name = function_name
|
10
|
+
@arguments = arguments
|
11
|
+
@block = block
|
12
|
+
@object = object
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate interpreter
|
16
|
+
arguments = @arguments.map { |argument| argument.evaluate interpreter }
|
17
|
+
if @block
|
18
|
+
arguments << @block.evaluate(interpreter)
|
19
|
+
end
|
20
|
+
object = if @object
|
21
|
+
@object.evaluate interpreter
|
22
|
+
else
|
23
|
+
interpreter.frame.object
|
24
|
+
end
|
25
|
+
frame = Dagon::Core::Frame.new(object, @function_name)
|
26
|
+
interpreter.push_frame frame
|
27
|
+
result = object.dagon_send interpreter, @function_name, *arguments
|
28
|
+
interpreter.pop_frame
|
29
|
+
result
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class FunctionDefinitionNode < Node
|
4
|
+
def initialize filename, line_number, function_name, function_object
|
5
|
+
super filename, line_number
|
6
|
+
@function_name = function_name
|
7
|
+
@function_object = function_object
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate interpreter
|
11
|
+
interpreter.define_function @function_name, @function_object
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class Function < Node
|
4
|
+
def initialize filename, line_number, params, body
|
5
|
+
super filename, line_number
|
6
|
+
@params = params.map(&:variable_name) # params must be unwrapped
|
7
|
+
@body = body
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(interpreter, object, *args)
|
11
|
+
unless args.size == @params.size
|
12
|
+
$stderr.puts "Wrong"
|
13
|
+
exit(1)
|
14
|
+
end
|
15
|
+
frame = interpreter.frame
|
16
|
+
args.each_with_index do |arg, index|
|
17
|
+
frame[@params[index]] = arg
|
18
|
+
end
|
19
|
+
execute_list interpreter, @body
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'core/hash'
|
2
|
+
|
3
|
+
module Dagon
|
4
|
+
module AST
|
5
|
+
class HashNode < Node
|
6
|
+
def initialize(filename, line_number, assignments)
|
7
|
+
super(filename, line_number)
|
8
|
+
@assignments = assignments
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate(interpreter)
|
12
|
+
interpreter.get_class("Hash").dagon_new(interpreter, @assignments)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class IfNode < Node
|
4
|
+
def initialize filename, line_number, condition, true_statements, false_statements
|
5
|
+
super filename, line_number
|
6
|
+
@condition = condition
|
7
|
+
@true_statements = true_statements
|
8
|
+
@false_statements = false_statements
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate interpreter
|
12
|
+
if @condition.evaluate(interpreter) == Dtrue
|
13
|
+
execute_list interpreter, @true_statements
|
14
|
+
else
|
15
|
+
execute_list interpreter, @false_statements if @false_statements
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class InstanceInitNode < Node
|
4
|
+
def initialize filename, line_number, klass_name, arguments, block
|
5
|
+
super filename, line_number
|
6
|
+
@klass_name = klass_name
|
7
|
+
@arguments = arguments
|
8
|
+
@block = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate interpreter
|
12
|
+
arguments = @arguments.map { |argument| argument.evaluate interpreter }
|
13
|
+
if @block
|
14
|
+
arguments << BlockNode.new(@filename, @line_number, @block, interpreter.frame)
|
15
|
+
end
|
16
|
+
|
17
|
+
object = interpreter.frame.object
|
18
|
+
klass = object.dagon_const_get(@klass_name)
|
19
|
+
if klass.respond_to? :dagon_new
|
20
|
+
klass.dagon_new(interpreter, *arguments)
|
21
|
+
else
|
22
|
+
$stderr.puts "Cannot initialize object of type #{@klass_name}"
|
23
|
+
exit(1)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class InstanceVarRefNode < Node
|
4
|
+
attr_reader :variable_name
|
5
|
+
def initialize filename, line_number, instance_variable_name
|
6
|
+
super filename, line_number
|
7
|
+
@instance_variable_name = instance_variable_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate interpreter
|
11
|
+
current = interpreter.frame.object.get_instance_variable(@instance_variable_name)
|
12
|
+
if current
|
13
|
+
current
|
14
|
+
else
|
15
|
+
interpreter.frame.object.set_instance_variable(@instance_variable_name, Dvoid)
|
16
|
+
Dvoid
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'core/integer'
|
2
|
+
require 'core/float'
|
3
|
+
|
4
|
+
module Dagon
|
5
|
+
module AST
|
6
|
+
class LiteralNode < Node
|
7
|
+
def initialize filename, line_number, literal
|
8
|
+
super filename, line_number
|
9
|
+
@value = literal
|
10
|
+
end
|
11
|
+
|
12
|
+
def evaluate interpreter
|
13
|
+
case @value.class.name
|
14
|
+
when "Fixnum" then interpreter.get_class("Integer").instance(@value)
|
15
|
+
when "Float" then interpreter.get_class("Float").instance(@value)
|
16
|
+
when "TrueClass" then Dtrue
|
17
|
+
when "FalseClass" then Dfalse
|
18
|
+
when "NilClass" then Dvoid
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/dagon/ast/node.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class Node
|
4
|
+
attr_reader :filename, :line_number
|
5
|
+
def initialize filename, line_number
|
6
|
+
@filename = filename
|
7
|
+
@line_number = line_number
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute_list interpreter, nodes
|
11
|
+
nodes.map do |node|
|
12
|
+
node.evaluate(interpreter)
|
13
|
+
end.last
|
14
|
+
end
|
15
|
+
|
16
|
+
def dagon_error! string
|
17
|
+
raise DagonError, "Problem? #{string}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "core/vm"
|
2
|
+
|
3
|
+
module Dagon
|
4
|
+
module AST
|
5
|
+
class RootNode < Node
|
6
|
+
attr_accessor :vm
|
7
|
+
def initialize tree
|
8
|
+
super nil, nil
|
9
|
+
@tree = tree
|
10
|
+
@vm = Dagon::Core::VM.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate vm = nil
|
14
|
+
actual_vm = vm || @vm
|
15
|
+
execute_list actual_vm, @tree
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'core/string'
|
2
|
+
|
3
|
+
module Dagon
|
4
|
+
module AST
|
5
|
+
class StringNode < Node
|
6
|
+
def initialize filename, line_number, string
|
7
|
+
super filename, line_number
|
8
|
+
@value = string
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate interpreter
|
12
|
+
interpreter.get_class("String").dagon_new(interpreter, @value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
|
4
|
+
class UnaryFunctionCallNode < Node
|
5
|
+
def initialize filename, line_number, object, function_name
|
6
|
+
super filename, line_number
|
7
|
+
@object = object
|
8
|
+
@function_name = function_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate interpreter
|
12
|
+
object = @object.evaluate interpreter
|
13
|
+
object.dagon_send interpreter, "#{@function_name}@"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class VarRefNode < Node
|
4
|
+
attr_reader :variable_name
|
5
|
+
def initialize filename, line_number, variable_name
|
6
|
+
super filename, line_number
|
7
|
+
@variable_name = variable_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate interpreter
|
11
|
+
if interpreter.frame.local_variable? @variable_name
|
12
|
+
interpreter.frame[@variable_name]
|
13
|
+
else
|
14
|
+
interpreter.frame.object.dagon_send(interpreter, @variable_name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Dagon
|
2
|
+
module AST
|
3
|
+
class WhileNode < Node
|
4
|
+
def initialize filename, line_number, condition, statements
|
5
|
+
super filename, line_number
|
6
|
+
@condition = condition
|
7
|
+
@statements = statements
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate interpreter
|
11
|
+
while @condition.evaluate(interpreter) == Dtrue
|
12
|
+
execute_list interpreter, @statements
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/dagon/parser.y
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
class Dagon::Parser
|
2
|
+
prechigh
|
3
|
+
right EXPONENT
|
4
|
+
left '!'
|
5
|
+
left '&&' '||' '^'
|
6
|
+
left '*' '/'
|
7
|
+
left '+' '-'
|
8
|
+
left ':'
|
9
|
+
nonassoc '>' '<' '>=' '<=' '=' '!='
|
10
|
+
preclow
|
11
|
+
rule
|
12
|
+
program: { result = [] }
|
13
|
+
| statements { result = AST::RootNode.new(val[0]) }
|
14
|
+
|
15
|
+
block: INDENT statements DEDENT { result = val[1] }
|
16
|
+
|
17
|
+
statements: statements statement { result.push val[1] }
|
18
|
+
| statement { result = [val[0]] }
|
19
|
+
|
20
|
+
statement: class_definition
|
21
|
+
| method_definition
|
22
|
+
| assignment
|
23
|
+
| expression
|
24
|
+
| conditional_statement
|
25
|
+
| while_statement
|
26
|
+
|
27
|
+
while_statement: WHILE condition block { result = AST::WhileNode.new(@filename, nil, val[1], val[2]) }
|
28
|
+
|
29
|
+
conditional_statement: IF condition block else_stmt { result = AST::IfNode.new(@filename, nil, val[1], val[2], val[3]) }
|
30
|
+
else_stmt: { result = nil }
|
31
|
+
| ELSEIF condition block else_stmt{ result = [AST::IfNode.new(@filename, nil, val[1], val[2], val[3])] }
|
32
|
+
| ELSE block { result = val[1] }
|
33
|
+
|
34
|
+
class_definition: CONSTANT ':' block { result = AST::ClassDefinitionNode.new(@filename, nil, val[0].data, val[2]) }
|
35
|
+
|
36
|
+
|
37
|
+
assignment: method_name ASSIGNMENT expression { result = AST::AssignmentNode.new(@filename, nil, val[0].variable_name, val[2]) }
|
38
|
+
| '@' method_name ASSIGNMENT expression { result = AST::AssignmentNode.new(@filename, nil, "@#{val[1].variable_name}", val[3]) }
|
39
|
+
|
40
|
+
expression: expression '-' expression { result = call_on_object(val[0], '-', val[2]) }
|
41
|
+
| expression '+' expression { result = call_on_object(val[0], '+', val[2]) }
|
42
|
+
| expression '*' expression { result = call_on_object(val[0], '*', val[2]) }
|
43
|
+
| expression '/' expression { result = call_on_object(val[0], '/', val[2]) }
|
44
|
+
| expression '&&' expression { result = call_on_object(val[0], '&&', val[2]) }
|
45
|
+
| expression '||' expression { result = call_on_object(val[0], '||', val[2]) }
|
46
|
+
| expression '^' expression { result = call_on_object(val[0], '^', val[2]) }
|
47
|
+
| expression EXPONENT expression { result = call_on_object(val[0], '**', val[2]) }
|
48
|
+
| condition
|
49
|
+
|
50
|
+
unary_expression: '!' expression { result = AST::UnaryFunctionCallNode.new(@filename, nil, val[1], "!") }
|
51
|
+
|
52
|
+
condition: expression '>' expression { result = call_on_object(val[0], '>', val[2]) }
|
53
|
+
| expression '<' expression { result = call_on_object(val[0], '<', val[2]) }
|
54
|
+
| expression '<=' expression { result = call_on_object(val[0], '<=', val[2]) }
|
55
|
+
| expression '>=' expression { result = call_on_object(val[0], '>=', val[2]) }
|
56
|
+
| expression '=' expression { result = call_on_object(val[0], '=', val[2]) }
|
57
|
+
| expression '!=' expression { result = call_on_object(val[0], '!=', val[2]) }
|
58
|
+
| unary_expression
|
59
|
+
| term
|
60
|
+
|
61
|
+
hash: LBRACE hash_list RBRACE { result = AST::HashNode.new(@filename, nil, val[1]) }
|
62
|
+
hash_list: { result = [] }
|
63
|
+
| hash_member { result = val }
|
64
|
+
| hash_list COMMA hash_member { result << val }
|
65
|
+
hash_member: assignment { result = val[0] }
|
66
|
+
|
67
|
+
array: LBRACKET list RBRACKET { result = AST::ArrayNode.new(@filename, nil, val[1]) }
|
68
|
+
list: { result = [] }
|
69
|
+
| list_member { result = val }
|
70
|
+
| list COMMA list_member { result.push val[2] }
|
71
|
+
list_member: expression { result = val[0] }
|
72
|
+
| assignment { result = val[0] }
|
73
|
+
|
74
|
+
|
75
|
+
method_name: IDENTIFIER { result = AST::VarRefNode.new(@filename, nil, val[0].data) }
|
76
|
+
|
77
|
+
term: '@' IDENTIFIER { result = AST::InstanceVarRefNode.new(@filename, nil, "@#{val[1].data}") }
|
78
|
+
| IDENTIFIER { result = AST::VarRefNode.new(@filename, nil, val[0].data) }
|
79
|
+
| CONSTANT { result = AST::ConstantRefNode.new(@filename, nil, val[0].data) }
|
80
|
+
| literal
|
81
|
+
| array
|
82
|
+
| hash
|
83
|
+
| method_call
|
84
|
+
| object_call
|
85
|
+
|
86
|
+
literal: FLOAT { result = AST::LiteralNode.new(@filename, nil, val[0].data.to_f) }
|
87
|
+
| INTEGER { result = AST::LiteralNode.new(@filename, nil, val[0].data.to_i) }
|
88
|
+
| STRING { result = AST::StringNode.new(@filename, nil, val[0].data) }
|
89
|
+
| TRUE { result = AST::LiteralNode.new(@filename, nil, true) }
|
90
|
+
| FALSE { result = AST::LiteralNode.new(@filename, nil, false) }
|
91
|
+
| VOID { result = AST::LiteralNode.new(@filename, nil, nil) }
|
92
|
+
|
93
|
+
|
94
|
+
method_definition: method_name ':' block { result = AST::FunctionDefinitionNode.new(@filename, nil, val[0].variable_name, AST::Function.new(@filename, nil, [], val[2])) }
|
95
|
+
| method_name LPAREN list RPAREN ':' block { result = AST::FunctionDefinitionNode.new(@filename, nil, val[0].variable_name, AST::Function.new(@filename, nil, val[2], val[5])) }
|
96
|
+
|
97
|
+
method_call: term DOT method_name lambda { result = AST::FunctionCallNode.new(@filename, nil, val[0], val[2].variable_name, [], val[3]) }
|
98
|
+
| term DOT method_name LPAREN list RPAREN lambda { result = AST::FunctionCallNode.new(@filename, nil, val[0], val[2].variable_name, val[4], val[6]) }
|
99
|
+
| method_name LPAREN list RPAREN lambda { result = AST::FunctionCallNode.new(@filename, nil, nil, val[0].variable_name, val[2], val[4]) }
|
100
|
+
| term '[' expression RBRACKET { result = AST::FunctionCallNode.new(@filename, nil, val[0], '[]', [val[2]], nil) }
|
101
|
+
|
102
|
+
object_call: CONSTANT LPAREN list RPAREN lambda { result = AST::InstanceInitNode.new(@filename, nil, val[0].data, val[2], val[4]) }
|
103
|
+
|
104
|
+
multiline_lambda: ARROW LPAREN list RPAREN block { result = AST::BlockNode.new(@filename, nil, val[4], val[2]) }
|
105
|
+
| ARROW block { result = AST::BlockNode.new(@filename, nil, val[1], []) }
|
106
|
+
|
107
|
+
singleline_lambda: ARROW LPAREN list RPAREN LBRACE statement RBRACE { result = AST::BlockNode.new(@filename, nil, [val[5]], val[2]) }
|
108
|
+
| ARROW LBRACE statement RBRACE { result = AST::BlockNode.new(@filename, nil, [val[2]], []) }
|
109
|
+
lambda: { result = nil }
|
110
|
+
| multiline_lambda { result = val[0] }
|
111
|
+
| singleline_lambda { result = val[0] }
|
112
|
+
|
113
|
+
---- header
|
114
|
+
%w(
|
115
|
+
node root_node function_call_node function_definition_node function_node
|
116
|
+
string_node literal_node var_ref_node if_node assignment_node while_node
|
117
|
+
class_definition_node instance_init_node block_node hash_node array_node
|
118
|
+
unary_function_call_node constant_ref_node instance_var_ref_node
|
119
|
+
).each { |node| require_relative "../dagon/ast/#{node}" }
|
120
|
+
|
121
|
+
---- inner
|
122
|
+
|
123
|
+
def initialize(tokens, filename, debug = false)
|
124
|
+
@yydebug = debug
|
125
|
+
@filename = filename
|
126
|
+
@tokens = tokens
|
127
|
+
@line = 0
|
128
|
+
end
|
129
|
+
|
130
|
+
def parse
|
131
|
+
do_parse
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.parse(tokens, filename, debug = false)
|
135
|
+
new(tokens, filename, debug).parse
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
attr_accessor :tokens
|
140
|
+
def next_token
|
141
|
+
tokens.shift
|
142
|
+
end
|
143
|
+
|
144
|
+
def on_error error_token_id, error_value, value_stack
|
145
|
+
$stderr.puts "#{@filename}:#{error_value.line}: syntax error, unexpected #{error_value.data.inspect}", value_stack.inspect
|
146
|
+
exit
|
147
|
+
end
|
148
|
+
|
149
|
+
def call_on_object(object, method, *args)
|
150
|
+
AST::FunctionCallNode.new(@filename, nil, object, method, args, nil)
|
151
|
+
end
|