dagon 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|