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.
Files changed (80) hide show
  1. data/.gitignore +2 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +86 -0
  6. data/Rakefile +40 -0
  7. data/bin/dagon +44 -0
  8. data/bin/dspec +35 -0
  9. data/bin/idg +15 -0
  10. data/bin/idgr +16 -0
  11. data/build/parser.rb +1015 -0
  12. data/build/scanner.rb +686 -0
  13. data/core/array.rb +64 -0
  14. data/core/block.rb +38 -0
  15. data/core/class.rb +91 -0
  16. data/core/false.rb +38 -0
  17. data/core/float.rb +93 -0
  18. data/core/frame.rb +24 -0
  19. data/core/hash.rb +51 -0
  20. data/core/integer.rb +98 -0
  21. data/core/object.rb +50 -0
  22. data/core/string.rb +57 -0
  23. data/core/true.rb +37 -0
  24. data/core/vm.rb +125 -0
  25. data/core/void.rb +37 -0
  26. data/dagon.gemspec +19 -0
  27. data/dagon.vim +45 -0
  28. data/dagon/ast/array_node.rb +17 -0
  29. data/dagon/ast/assignment_node.rb +21 -0
  30. data/dagon/ast/block_node.rb +19 -0
  31. data/dagon/ast/class_definition_node.rb +24 -0
  32. data/dagon/ast/constant_ref_node.rb +15 -0
  33. data/dagon/ast/frame.rb +23 -0
  34. data/dagon/ast/function_call_node.rb +33 -0
  35. data/dagon/ast/function_definition_node.rb +15 -0
  36. data/dagon/ast/function_node.rb +23 -0
  37. data/dagon/ast/hash_node.rb +16 -0
  38. data/dagon/ast/if_node.rb +20 -0
  39. data/dagon/ast/instance_init_node.rb +28 -0
  40. data/dagon/ast/instance_var_ref_node.rb +21 -0
  41. data/dagon/ast/literal_node.rb +23 -0
  42. data/dagon/ast/node.rb +22 -0
  43. data/dagon/ast/root_node.rb +19 -0
  44. data/dagon/ast/string_node.rb +16 -0
  45. data/dagon/ast/unary_function_call_node.rb +17 -0
  46. data/dagon/ast/var_ref_node.rb +19 -0
  47. data/dagon/ast/while_node.rb +17 -0
  48. data/dagon/parser.y +151 -0
  49. data/dagon/scanner.rl +143 -0
  50. data/examples/assert.dg +8 -0
  51. data/examples/assignment.dg +2 -0
  52. data/examples/block.dg +8 -0
  53. data/examples/class.dg +6 -0
  54. data/examples/conditional.dg +3 -0
  55. data/examples/conditions.dg +6 -0
  56. data/examples/equality.dg +6 -0
  57. data/examples/error.dg +1 -0
  58. data/examples/eval.dg +1 -0
  59. data/examples/fibonacci.dg +15 -0
  60. data/examples/greeter.dg +6 -0
  61. data/examples/input.dg +3 -0
  62. data/examples/instance_variables.dg +11 -0
  63. data/examples/iterate.dg +2 -0
  64. data/examples/method_call.dg +9 -0
  65. data/examples/method_definition.dg +4 -0
  66. data/examples/operators.dg +6 -0
  67. data/examples/output.dg +1 -0
  68. data/examples/require.dg +1 -0
  69. data/spec/array_spec.dg +26 -0
  70. data/spec/assertions.dg +11 -0
  71. data/spec/boolean_spec.dg +48 -0
  72. data/spec/dspec.dg +16 -0
  73. data/spec/float_spec.dg +15 -0
  74. data/spec/hash_spec.dg +6 -0
  75. data/spec/number_spec.dg +18 -0
  76. data/spec/return_spec.dg +12 -0
  77. data/spec/string_spec.dg +18 -0
  78. data/spec/void_spec.dg +9 -0
  79. data/spec/while_spec.dg +7 -0
  80. metadata +180 -0
@@ -0,0 +1,50 @@
1
+ require "core/class"
2
+
3
+ module Dagon
4
+ module Core
5
+ class DG_Object
6
+ attr_reader :klass
7
+ def initialize klass = nil
8
+ @ivars = {}
9
+ @klass = klass || DG_Class.new
10
+ end
11
+
12
+ def dagon_define_class name, parent
13
+ name = name.to_sym
14
+ klass = DG_Class.new(name, parent)
15
+ @klass.dagon_const_set(name, klass)
16
+ klass
17
+ end
18
+
19
+ def dagon_const_set constant, value
20
+ @klass.dagon_const_set(constant, value)
21
+ end
22
+
23
+ def dagon_const_get constant
24
+ @klass.dagon_const_get(constant)
25
+ end
26
+
27
+ def dagon_send interpreter, name, *args
28
+ method = @klass.get_method(name)
29
+ if method
30
+ frame = Frame.new(self, self)
31
+ interpreter.push_frame frame
32
+ return_value = method.call(interpreter, self, *args) || Dvoid
33
+ interpreter.pop_frame
34
+ return_value
35
+ else
36
+ $stderr.puts "undefined method '#{name}' for #{self.inspect}:#{self.klass.name}"
37
+ exit(1)
38
+ end
39
+ end
40
+
41
+ def set_instance_variable name, value
42
+ @ivars[name.to_sym] = value
43
+ end
44
+
45
+ def get_instance_variable name
46
+ @ivars[name.to_sym]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,57 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_String < DG_Object
4
+ attr_reader :value
5
+ def initialize value, klass
6
+ @value = value
7
+ @klass = klass
8
+ end
9
+
10
+ def == other
11
+ value == other.value
12
+ end
13
+
14
+ def to_s
15
+ @value
16
+ end
17
+
18
+ def inspect
19
+ %{"#{@value}"}
20
+ end
21
+ end
22
+
23
+ class DG_StringClass < DG_Class
24
+ def initialize
25
+ super("String", Dagon::Core::DG_Class.new)
26
+ end
27
+
28
+ def boot
29
+ add_method "init", ->(vm, ref, value) {
30
+ ref.instance_variable_set("@value", value)
31
+ }
32
+ add_method "+", ->(vm, ref, other) {
33
+ dagon_new(vm, ref.value + other.value)
34
+ }
35
+ add_method "=", ->(vm, ref, other) {
36
+ ref.value == other.value ? Dtrue : Dfalse
37
+ }
38
+ add_method "!=", ->(vm, ref, other) {
39
+ ref.value != other.value ? Dtrue : Dfalse
40
+ }
41
+ add_method 'length', ->(vm, ref) {
42
+ vm.get_class("Integer").instance(ref.value.length)
43
+ }
44
+ add_method 'to-i', ->(vm, ref) {
45
+ vm.get_class("Integer").instance(ref.value.to_i)
46
+ }
47
+ add_method 'to-f', ->(vm, ref) {
48
+ vm.get_class("Float").instance(ref.value.to_f)
49
+ }
50
+ end
51
+
52
+ def dagon_new interpreter, string = ""
53
+ DG_String.new(string, self)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ require 'singleton'
2
+
3
+ module Dagon
4
+ module Core
5
+ class True < DG_Object
6
+ include Singleton
7
+ def initialize
8
+ @value = true
9
+ @klass = DG_TrueClass.new
10
+ end
11
+
12
+ def inspect
13
+ "true"
14
+ end
15
+ end
16
+
17
+ class DG_TrueClass < DG_Class
18
+ undef :dagon_new
19
+ def initialize
20
+ super("True", Dagon::Core::DG_Class.new)
21
+ end
22
+
23
+ def boot
24
+ add_method '!@', ->(vm, ref) {
25
+ Dfalse
26
+ }
27
+ add_method '=', ->(vm, ref, other) {
28
+ ref == other ? Dtrue : Dfalse
29
+ }
30
+ add_method '&&', ->(vm, ref, other) { other }
31
+ add_method '||', ->(vm, ref, other) { Dtrue }
32
+ add_method '^', ->(vm, ref, other) { other.dagon_send(vm, "!@") }
33
+ add_method 'to-s', ->(vm, ref) { vm.get_class("String").dagon_new(vm, "true") }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,125 @@
1
+ CORE = %w(object class array block false float frame integer string true void hash)
2
+ CORE.each do |klass|
3
+ require "core/#{klass}"
4
+ end
5
+
6
+ require "pry"
7
+
8
+ module Dagon
9
+ module Core
10
+ class VM
11
+ attr_reader :globals
12
+ def initialize main = nil
13
+ @load_paths = [File.expand_path(".")]
14
+ @required_files = []
15
+ @object = main || Dagon::Core::DG_Object.new
16
+ @stack = []
17
+ @stack.push Frame.new(@object, '(toplevel)')
18
+ @globals = {}
19
+ @classes = {}
20
+ boot_core
21
+ end
22
+
23
+ def boot_core
24
+ add_class("Array", DG_ArrayClass.new)
25
+ add_class("Block", DG_BlockClass.new)
26
+ add_class("False", DG_FalseClass.new)
27
+ add_class("Float", DG_FloatClass.new)
28
+ add_class("Hash", DG_HashClass.new)
29
+ add_class("Integer", DG_IntegerClass.new)
30
+ add_class("String", DG_StringClass.new)
31
+ add_class("True", DG_TrueClass.new)
32
+ add_class("Void", DG_VoidClass.new)
33
+
34
+ unless Kernel.const_defined?("Dtrue")
35
+ Kernel.const_set("Dtrue", Dagon::Core::True.instance)
36
+ end
37
+ unless Kernel.const_defined?("Dfalse")
38
+ Kernel.const_set("Dfalse", Dagon::Core::False.instance)
39
+ end
40
+ unless Kernel.const_defined?("Dvoid")
41
+ Kernel.const_set("Dvoid", Dagon::Core::Void.instance)
42
+ end
43
+ end
44
+
45
+ def current_object
46
+ @stack[0].object
47
+ end
48
+
49
+ def add_class name, klass
50
+ current_object.dagon_const_set(name, klass)
51
+ end
52
+
53
+ def get_class name
54
+ current_object.dagon_const_get(name)
55
+ end
56
+
57
+ def add_load_path path
58
+ unless @load_paths.include? path
59
+ @load_paths << path
60
+ end
61
+ end
62
+
63
+ def frame
64
+ @stack.last
65
+ end
66
+
67
+ def push_frame frame
68
+ @stack.push frame
69
+ @object = frame.object
70
+ end
71
+
72
+ def pop_frame
73
+ @stack.pop
74
+ @object = frame.object
75
+ end
76
+
77
+ def dagon_define_class name, parent
78
+ @object.dagon_define_class name, parent
79
+ end
80
+
81
+ def define_function name, block
82
+ if @object.respond_to? :add_method
83
+ @object.add_method name, block
84
+ else
85
+ @object.klass.add_method name, block
86
+ end
87
+ end
88
+
89
+ def find_file_path filename
90
+ @load_paths.each do |path|
91
+ if File.exists? File.join(path, "#{filename}.dg")
92
+ return File.join(path, "#{filename}.dg")
93
+ end
94
+ end
95
+ nil
96
+ end
97
+
98
+ def load_file filename
99
+ path = find_file_path(filename.value)
100
+ if path
101
+ @required_files << path
102
+ program = File.read(path)
103
+ tokens = Dagon::Scanner.tokenize(program, filename)
104
+ tree = Dagon::Parser.parse(tokens, filename, false)
105
+ tree.evaluate(self)
106
+ Dtrue
107
+ else
108
+ error "No such file or directory - #{filename.value}\n" +
109
+ "Searched: \n" +
110
+ @load_paths.map{ |path| " #{path}"}.join("\n")
111
+ end
112
+ end
113
+
114
+ def loaded? filename
115
+ @required_files.include? filename
116
+ end
117
+
118
+ def error message
119
+ $stderr.puts message
120
+ exit(1)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
@@ -0,0 +1,37 @@
1
+ require 'singleton'
2
+
3
+ module Dagon
4
+ module Core
5
+ class Void < DG_Object
6
+ include Singleton
7
+ def initialize
8
+ @klass = DG_VoidClass.new
9
+ end
10
+
11
+ def to_s
12
+ ""
13
+ end
14
+
15
+ def value # TODO: determine if there is a better way than this for checking equality
16
+ nil
17
+ end
18
+
19
+ def inspect
20
+ "void"
21
+ end
22
+ end
23
+
24
+ class DG_VoidClass < DG_Class
25
+ undef :dagon_new
26
+ def initialize
27
+ super("Void", Dagon::Core::DG_Class.new)
28
+ end
29
+
30
+ def boot
31
+ add_method "=", ->(vm, ref, other) {
32
+ ref == other ? Dtrue : Dfalse
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "dagon"
5
+ gem.version = "0.1.0"
6
+ gem.authors = ["Caleb Thompson", "Matt Mongeau"]
7
+ gem.email = ["cjaysson@gmail.com", "halogenandtoast@gmail.com"]
8
+ gem.description = "The Dagon programming language: whitespace, enumerators, blocks, One Way"
9
+ gem.summary = "The Esoteric Order of Dagon"
10
+ gem.homepage = "https://github.com/calebthompson/dagon"
11
+
12
+ gem.files = `git ls-files`.split($/)
13
+ gem.executables = gem.files.grep(%r{^bin/(dagon|dspec|idgr)}).map{ |f| File.basename(f) }
14
+ gem.require_paths = %w{core dagon}
15
+
16
+ gem.add_development_dependency 'rake'
17
+ gem.add_development_dependency 'racc'
18
+ gem.add_development_dependency 'pry'
19
+ end
@@ -0,0 +1,45 @@
1
+ " Vim syntax file
2
+ " Language: Dagon
3
+ " Maintainer: Caleb Thompson
4
+ " Latest Revision: 16 January 2013
5
+
6
+ au BufRead,BufNewFile *.dg set filetype=dagon
7
+
8
+ if exists("b:current_syntax")
9
+ finish
10
+ endif
11
+
12
+ syntax keyword dagonConditional if elseif else while break
13
+ syntax keyword dagonBoolean true false
14
+ syntax keyword dagonKeyword void
15
+ syntax keyword dagonFunction print puts
16
+ syntax match dagonNumber '\d'
17
+ syntax match dagonFloat '\d+\.\d+'
18
+ syntax region String start="'" end="'"
19
+ syntax region String start='"' end='"'
20
+ syntax region Array start="\[" end="\]"
21
+ syntax match dagonComment "\v#.*$"
22
+ syntax match dagonConstant "\v[A-Z][A-Za-z]*"
23
+ syntax match dagonIdentifier "\v-?[a-z][a-z0-9-]+"
24
+ syntax match dagonFunctionDefinition "\v-?[a-z][a-z0-9-]+:"
25
+ syntax region dagonFunctionDefinitionArgumentList start="\v-?[a-z][a-z0-9-]+\(" end="):"
26
+ syntax region dagonFunctionCall start="\v-?[a-z][a-z0-9-]+\(" end=")"
27
+ syntax match dagonOperator "\v \*\* "
28
+ syntax match dagonOperator "\v \* "
29
+ syntax match dagonOperator "\v / "
30
+ syntax match dagonOperator "\v \+ "
31
+ syntax match dagonOperator "\v - "
32
+ syntax match dagonAssignment ": "
33
+
34
+ highlight link dagonConditional Conditional
35
+ highlight link dagonKeyword Keyword
36
+ highlight link dagonBoolean Boolean
37
+ highlight link dagonIdentifier dagonFunction
38
+ highlight link dagonFunctionDefinition dagonFunction
39
+ highlight link dagonFunction Function
40
+
41
+ highlight link dagonComment Comment
42
+ highlight link dagonOperator Operator
43
+ highlight link dagonConstant Constant
44
+
45
+ let b:current_syntax = "dagon"
@@ -0,0 +1,17 @@
1
+ require 'core/array'
2
+
3
+ module Dagon
4
+ module AST
5
+ class ArrayNode < Node
6
+ def initialize filename, line_number, list
7
+ super filename, line_number
8
+ @list = list
9
+ end
10
+
11
+ def evaluate interpreter
12
+ evaluated_list = @list.map { |item| item.evaluate(interpreter) }
13
+ interpreter.get_class("Array").dagon_new(interpreter, evaluated_list)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Dagon
2
+ module AST
3
+ class AssignmentNode < Node
4
+ attr_reader :variable_name
5
+ attr_reader :variable_value
6
+ def initialize filename, line_number, variable_name, value
7
+ super filename, line_number
8
+ @variable_name = variable_name
9
+ @variable_value = value
10
+ end
11
+
12
+ def evaluate interpreter
13
+ if variable_name[0] == "@"
14
+ interpreter.frame.object.set_instance_variable(variable_name, value.evaluate(interpreter))
15
+ else
16
+ interpreter.frame[variable_name] = variable_value.evaluate(interpreter)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ require 'core/block'
2
+
3
+ module Dagon
4
+ module AST
5
+
6
+ class BlockNode < Node
7
+ def initialize filename, line_number, statements, arguments
8
+ super filename, line_number
9
+ @statements = statements
10
+ @arguments = arguments
11
+ end
12
+
13
+ def evaluate interpreter
14
+ arguments = @arguments.map(&:variable_name)
15
+ interpreter.get_class("Block").dagon_new(interpreter, @statements, interpreter.frame, arguments)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'core/frame'
2
+ require 'core/class'
3
+
4
+ module Dagon
5
+ module AST
6
+ class ClassDefinitionNode < Node
7
+ def initialize filename, line_number, class_name, statements
8
+ super filename, line_number
9
+ @class_name = class_name
10
+ @statements = statements
11
+ end
12
+
13
+ def evaluate interpreter
14
+ klass = interpreter.dagon_define_class @class_name, Dagon::Core::DG_Class.new
15
+ frame = Dagon::Core::Frame.new(klass, klass.name)
16
+ interpreter.push_frame frame
17
+ @statements.each do |statement|
18
+ statement.evaluate interpreter
19
+ end
20
+ interpreter.pop_frame
21
+ end
22
+ end
23
+ end
24
+ end